Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

[ENV-B0] First-class sandboxed credentials for Claude Code, OpenCode 2.x and Pi (no Codex)

Open
#290 0 comments 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 1 day

Nobody has claimed this yet.

Assessment

Difficulty
5/5
Estimated time
Over a week
Newbie friendliness
15/100
Issue type
Feature
Clarity
Mostly clear
Activity status
Active
Tech stack
docker, github, python

Research direction

Start with src/autoforge/sandbox_policy.py and src/autoforge/providers.py, then read ADR 0005 and the linked Pi and OpenCode provider guidance to understand the existing auth contracts. Verify each supported CLI’s current authentication behavior and map it to the acceptance matrix. Done means each advertised route has isolated, typed credential handling, passes the listed security and failure checks, and has compatibility documentation; unsupported routes fail with actionable diagnostics.

Written by the indexing model from the issue text.

Description

enhancement

Artifact: implementation-ready provider-auth workstream of EPIC #266. Wave: B (credential bridge / pre-Docker). Size: L. Scope explicitly restricted to AutoForge's current CLI agent providers: Claude Code, OpenCode 2.x, and Pi. Codex is OUT OF SCOPE, including Codex OAuth-file mounting, Codex SDK and Codex-specific login UX.

Objective

Implement a typed, provider-scoped, least-privilege credential projection that can supply the model authentication AutoForge's existing Claude Code / OpenCode 2.x / Pi adapters actually use in an isolated Docker/Podman environment without giving the agent any GitHub mutation credential, copying the operator's HOME, assuming legacy authentication formats, or putting token values in Docker CLI argv, docker inspect metadata, images, logs, or durable AutoForge state. Preserve existing host/Bubblewrap behavior. The Docker backend in #271 consumes this contract; #270 owns general container capabilities/policy, while this task owns provider-specific auth compatibility and refresh.

Hard dependencies

  • #267 ENV-A1: execution backend ADR
  • #268 ENV-A2: backend launch interface
  • #270 ENV-A4: enforceable container policy
  • #286 (LAUNCH-E M5+R6, outside this EPIC): separate environment allow-lists per execution class. Without it, "the model key reaches only agent launches" cannot hold, because today's single execution.env_allowlist also feeds repository commands. Added as a native blocked_by edge on 2026-10-23.
  • #271 (Docker runtime), #274 (E2E) consume this issue; no dependency on #147's entire SDK EPIC or #126's human interaction rollout.

Existing facts to inspect (do not assume newer/older releases have equivalent behavior)

  • AutoForge sandbox_policy.py: typed AuthMode.NONE/ENV/FILE_RO/DIR_RW/KEYRING, ProviderRequirements.auth, operator roots forbidden, environment rewriting. ADR 0005 D7/D8; #165 credential boundary.
  • AutoForge providers.py: actual CLI argv, current environment allowlists and provider-specific installation/config requirements, opencode run --standalone, Pi RPC & preflight.
  • Pi operator guide, Pi policy: dedicated PI_CODING_AGENT_DIR, pi auth check --model ... --json --no-refresh, Pi's own OAuth refresh; separate require_oauth from DeepSeek API-key route.
  • OpenCode 2.x provider login documentation: saved OAuth/API credentials reside in server-side SQLite (typically ~/.local/share/opencode/opencode.db, discover using opencode debug paths db); legacy auth.json may be imported, but must NOT be assumed the current source of truth. The selected --standalone server must use the same isolated XDG/data/runtime roots, with no fallback to shared host background service. Stored account may take precedence over environment key.
  • Claude Code env docs: support explicit CLAUDE_CODE_OAUTH_TOKEN generated by claude setup-token, or ANTHROPIC_API_KEY, plus dedicated config/state path when supported; do not assume host keychain credentials are readable, portable or safe to copy. Subscription eligibility/terms and token expiry must be documented and checked with actual CLI.

Provider acceptance matrix

Claude Code CLI
  • Document/test ANTHROPIC_API_KEY and CLAUDE_CODE_OAUTH_TOKEN as separate auth choices. The latter may be generated through an operator-controlled claude setup-token; never automate token extraction from macOS Keychain, OS secret service or ~/.claude. Respect explicit provider auth precedence and no ambient fallback.
  • Inject using safe ephemeral staging (no token value in Docker create/env metadata or host argv), with a private in-container config/HOME; if agent CLI needs an env variable, populate it only inside the confined agent process, not the Docker API container configuration. State precisely what remains readable by the agent/process itself.
  • Test absent/expired/revoked token as typed actionable failures; no implicit subscription → paid API-key fallback. SDK provider claude-sdk (#147/#149) is NOT silently broadened to use subscription auth.
OpenCode 2.x CLI
  • Support provider API-key env-route via explicit scoped credentials for the selected OpenCode integration; never forward global OPENCODE_* or OPENAI_* wholesale.
  • Design and prove managed dedicated OpenCode 2.x account store for accounts established by its supported auth login / /connect flow, avoiding sharing/copying a live operator database or editing SQLite schema directly. Discover and verify actual opencode debug paths db; account DB updates/refresh and optional SQLite WAL/SHM sidecars must be handled by the provider's supported mechanisms and safely owned persistence, not ad-hoc file-copy races.
  • Ensure opencode run --standalone (or existing pinned v2 CLI command) resolves the same private data/config directories as auth login; no background daemon/service, wrong user home, global plugins, arbitrary external tools, or fallback to host account. Distinguish currently supported auth methods from assumptions about third-party subscriptions.
Pi RPC
  • Support dedicated PI_CODING_AGENT_DIR with private auth.json/model state, not ~/.pi/agent from operator HOME, and never mount operator's full Pi directory. Preserve --no-approve --no-extensions --no-skills --no-prompt-templates --no-themes --offline and explicit tools/context policy.
  • Verify require_oauth: true → Pi's own read-only auth preflight, OAuth refresh only within the authorized private store; require_oauth: false → DeepSeek/provider API key from a provider-scoped credential store or opt-in env. No provider key globally forwarded to every agent.
  • When multiple issue workers share one Pi OAuth identity, define a single-writer/serialized refresh, isolated per-worker managed copies, or documented fail-closed policy; do not let token-rotation races silently corrupt credentials. Persist only private provider auth state, never transcripts as credentials.

Cross-provider security and delivery contract

  • Threat-model tokens in docker run -e KEY=value, Podman CLI arguments, Docker inspect, container logs, entrypoint shell argv, mounted paths, /proc, snapshots, state.json, errors and backups. Pass secrets via runtime-only confined channels/private ephemeral file projections, not container creation metadata; mandatory cleanup and no leaking to sibling containers.
  • Never inject GH_TOKEN, GITHUB_TOKEN, Git/SSH credentials or controller Github auth into an agent; controller-owned external effects remain intact.
  • Shared typed auth plan includes provider name, credential kind, scope, source identity without value, writable vs read-only refresh policy, path mapping, audit-safe failure and capability refusal; no general-purpose host mounts.
  • No provider code reads/copies/prints operator credential files; if importing an existing login is supported, it is an explicit operator-owned one-time provisioning step with source access minimization and precise disclosure. Otherwise require isolated login in a dedicated auth directory.
  • Config, doctor and dry-run reveal credential presence/type/capability only, not values. Revoke/rotate procedures, multi-worker contention, canceled launch and forced-stop cleanup documented and tested.
  • Fake credentials + fake CLIs prove all routes and rejection paths. Real supported-host Docker probes verify key absence from Docker metadata and operator HOME; optional live provider smoke runs require explicit operator creds and report separately whether OAuth/auth refresh actually succeeded.
  • Changes preserve bwrap baseline; if persistence schema is necessary, first coordinate protocol number on #23. Update docs with a provider-auth compatibility matrix, and mark unsupported routes as such.

Non-goals

No Codex-specific adapter, auth.json copying or ChatGPT-to-Codex workaround; no new OAuth implementation in AutoForge; no cross-provider token broker; no SDK subscription changes; no guarantees that any provider supports a subscription plan when that provider or terms do not authorize it. No release-blocking dependency on Public Alpha #255.

Completion

This is not complete merely because a token reaches a running container. Each advertised provider route must be safe, reproducible and independently tested; explicitly unsupported routes must fail closed with a concrete diagnostic.

Dev Containers-derived principle: preserve authentication identity across ephemeral containers

Design target: “身份留在宿主机、执行环境可以重建” — canonical provider login and refresh state is operator-owned and persistent outside the disposable sandbox, while each Claude Code/OpenCode 2.x/Pi execution gets only a narrowly scoped, auditable credential projection. Do not use the container filesystem as the only copy of a login, and do not assume a Dev Container secrets declaration or credential forwarding API performs OAuth refresh.

  • Provider-by-provider decision table: Claude Code CLI (CLAUDE_CODE_OAUTH_TOKEN / ANTHROPIC_API_KEY), OpenCode 2.x (managed account store / provider API key), Pi (managed PI_CODING_AGENT_DIR, OAuth versus DeepSeek API key). State the canonical auth location, provisioning mechanism, refresh writer, worker-concurrency behavior, projection, clean removal and rehydration of a new container. No Codex.
  • With a valid canonical identity, destroy container A and launch container B: verify that auth still works without re-login, copying the host HOME, or introducing a Docker metadata/argv secret. Expired/revoked/rotated credentials produce explicit failures, and reprovisioning never occurs silently.
  • Shared-store refresh must have an explicit single-writer/transactional mechanism or fail-closed, rather than concurrent writable copies; the durable identity store survives the sandbox, while run-only secret projections and mounts are removed. Coordinate orphan/crash windows with #272.
  • Confirm no GitHub credential helper, GH_TOKEN/GITHUB_TOKEN, or host SSH agent is inherited, notwithstanding the convenience of VS Code Git credential forwarding. The current agent only receives its model authentication.

Context: Dev Containers spec; first-class secrets design. Dev Containers is architectural inspiration, not a security dependency or drop-in OAuth implementation.

Host-to-container model credential injection, not GitHub delegation (2026-10-23)

  • Implement the model-credential projection used by #292/#271: the host/controller-side launcher selects only the current Claude Code/OpenCode 2.x/Pi identity and projects a limited credential lease into the container's own process/config path. Do not bundle model credentials into /source or /workspace snapshot/image/build output.
  • Keep model authentication distinct from Controller gh/hardened git; agents receive zero GitHub credential/helper/SSH socket and have no direct GitHub-write authority.
  • Test container/image rebuild and private workspace recreation with retained host-managed login state; revoke on cancellation, clean per-run projections, preserve carefully coordinated refresh state.
  • Inject without credential values in Docker create/exec argv, inspect metadata, container logs or state; document residual fact that the Agent process can access its own model auth.

Planning reconciliation (2026-10-23)

Artifact: planning update from the 2026-10-23 reconciliation of EPIC #266 with its architecture review (#266 comment). Baseline re-read: main 388ecb3. Planning only: nothing here implements a feature or checks off a criterion. The earlier sections stay authoritative where this one does not change them.

Retained without change
  • The scope is Claude Code CLI, OpenCode 2.x and Pi RPC. Codex stays out of scope.
  • The canonical login stays operator-owned on the host. Each launch gets a disposable, run-scoped projection.
  • Nothing GitHub-related is forwarded to the coding agent. That covers GH_TOKEN/GITHUB_TOKEN, the gh configuration and credential helper, the SSH agent, the host HOME, and the Git common dir.
  • Model credentials stay separate from the controller's gh and hardened git.
Added by this reconciliation
  • Native prerequisite #286. It is in the hard dependencies above.
  • Which redaction work each logging guarantee needs:
    • #281 (step-outcome JSON escaping) and #284 (a credential directly after an ANSI escape) are prerequisites of #274's "no credential in logs" assertion. They are native edges on #274.
    • #282 and #285 widen the recognised credential shapes (Google AIza…, AWS, PEM, gsk_, xai- and others). They are not prerequisites. Until they land, the provider-auth compatibility matrix must name each OpenCode route whose key shape redaction does not recognise, and must not claim that route's key is redacted.
  • Never in the image. Credentials are never written into an image layer, a build argument or an image label. #271's image contract enforces this, and a test inspects the built image.
  • Never in recorded configuration or state. No credential or credential-derived value enters configuration fingerprints (src/autoforge/config_fingerprint.py), state.json, the lifecycle journal (#272) or diagnostics. Only kind, scope and presence may be recorded.
  • Lifetime. The projection lives exactly as long as #267's decision 3 says a launch's credential projection lives. #272's lifecycle journal records it, and #272 removes it on every exit path and during reconciliation.
  • Residual R3, stated plainly. An agent that holds its model credential and has general outbound access can exfiltrate that credential (#257, maintainer residual R3). The Docker MVP does not prevent this. #294 (post-MVP egress mediation) narrows the channel but cannot close it. The docs say so.
Additional acceptance criteria (planning reconciliation)
  • With #286 in place, a test proves the model credential reaches agent launches only and never a validation or pre-merge (EXPORT_COMMAND) launch
  • A built image and its history contain no credential, build argument or label carrying one (checked on real Docker in #274)
  • No credential value appears in a configuration fingerprint, state.json, the lifecycle journal or doctor output; a test seeds dummy secrets and searches every persisted artifact
  • The provider-auth compatibility matrix lists which routes' key shapes redaction recognises at release time, and states residual R3
Dominant language
Python
Stars
0
Forks
0
Avg merge
5h 51m
Merged PRs (30d)
66

Getting set up

This project ships no dev container, Dockerfile or contributing guide, so setting up is up to you: start from its README, and see our first-contribution guide for the general steps.

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from iceboundrock/AutoForge

All issues in iceboundrock/AutoForge

Similar issues

More Python issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.