docs: explain Codex and Claude credential ownership
Squash-merges the adapter credential ownership doc PR. - Documents codex_local host-owns-auth topology and CODEX_HOME auth precedence - Documents claude_local snapshot-owns-auth topology (sandbox targets only) - Adds API-key vs ChatGPT-subscription guidance for high-concurrency fleets - Adds deferred config-validation warning spec for sandbox credential mismatches - Fixes: SSH scope mismatch (Greptile P1) and codex auth.json materialization note (Greptile P2) Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
parent
3288ec4f47
commit
187a929d97
|
|
@ -8,7 +8,8 @@ The `claude_local` adapter runs Anthropic's Claude Code CLI locally. It supports
|
|||
## Prerequisites
|
||||
|
||||
- Claude Code CLI installed (`claude` command available)
|
||||
- `ANTHROPIC_API_KEY` set in the environment or agent config
|
||||
- Either `ANTHROPIC_API_KEY` in adapter env/host env, or a Claude Code
|
||||
subscription login available to the execution target
|
||||
|
||||
## Configuration Fields
|
||||
|
||||
|
|
@ -69,6 +70,33 @@ On-call checklist if you see this in production:
|
|||
|
||||
The adapter creates a temporary directory with symlinks to Paperclip skills and passes it via `--add-dir`. This makes skills discoverable without polluting the agent's working directory.
|
||||
|
||||
## Remote credential ownership
|
||||
|
||||
`claude_local` uses a snapshot-owns-auth topology for managed sandbox execution
|
||||
targets. When the run uses a sandbox execution target and no explicit
|
||||
`CLAUDE_CONFIG_DIR` is configured, Paperclip creates a remote
|
||||
`CLAUDE_CONFIG_DIR` under the run's Claude runtime directory. It uploads
|
||||
sanitized host-side settings such as `settings.json` and `CLAUDE.md`, but the
|
||||
managed seed does not upload host Claude credential files.
|
||||
|
||||
After the seed is copied, the remote materialization command checks the
|
||||
execution target's own `$HOME/.claude` directory. For each missing credential
|
||||
file, it copies `.credentials.json` or `credentials.json` from that remote home
|
||||
into the managed `CLAUDE_CONFIG_DIR`. That means credentials baked into the
|
||||
sandbox image win for managed remote Claude runs.
|
||||
|
||||
Worked example: a sandbox image contains `$HOME/.claude/.credentials.json` from
|
||||
its own Claude Code login. Paperclip starts a managed remote `claude_local` run,
|
||||
uploads only the sanitized config seed, and sets `CLAUDE_CONFIG_DIR` to the
|
||||
remote runtime config path. Because the managed config has no credential file,
|
||||
the adapter copies the sandbox image's `$HOME/.claude/.credentials.json` into
|
||||
that path before invoking Claude. The sandbox snapshot owns the credential for
|
||||
the run.
|
||||
|
||||
This differs from [`codex_local`](/adapters/codex-local), where a
|
||||
Paperclip-managed sandbox run uploads a host-owned `CODEX_HOME/auth.json` and
|
||||
therefore shadows any Codex login already present inside the sandbox image.
|
||||
|
||||
For manual local CLI usage outside heartbeat runs (for example running as `claudecoder` directly), use:
|
||||
|
||||
```sh
|
||||
|
|
|
|||
|
|
@ -8,7 +8,11 @@ The `codex_local` adapter runs OpenAI's Codex CLI locally. It supports session p
|
|||
## Prerequisites
|
||||
|
||||
- Codex CLI installed (`codex` command available)
|
||||
- `OPENAI_API_KEY` set in the environment or agent config
|
||||
- Either a host Codex login with `~/.codex/auth.json`, or a per-agent
|
||||
`OPENAI_API_KEY` configured in adapter env (Paperclip materializes this into
|
||||
`$CODEX_HOME/auth.json` for managed homes; Codex CLI reads credentials from
|
||||
`auth.json`, not directly from the process environment — for a self-managed
|
||||
external `CODEX_HOME`, write `auth.json` there directly instead)
|
||||
|
||||
## Configuration Fields
|
||||
|
||||
|
|
@ -55,6 +59,83 @@ A managed home is created empty, so the adapter must provision auth into it befo
|
|||
- **Genuine external overrides** (a `CODEX_HOME` outside the Paperclip-managed company tree) are treated as self-managed and are never seeded or overwritten.
|
||||
- **Fail-fast guard:** if a managed home ends up with no usable `auth.json` and no configured API key, the run fails with an explicit `adapter_failed` ("no Codex credentials provisioned for managed home …") rather than emitting an unauthenticated request.
|
||||
|
||||
### Auth ownership and precedence
|
||||
|
||||
`codex_local` is host-owns-auth when Paperclip owns the effective
|
||||
`CODEX_HOME`. The winning credential file is:
|
||||
|
||||
1. **Per-agent API key:** when adapter env contains a non-empty
|
||||
`OPENAI_API_KEY`, Paperclip writes `$CODEX_HOME/auth.json` with only
|
||||
`{ "OPENAI_API_KEY": "..." }`. This overwrites any existing file or symlink
|
||||
at that path. Codex CLI versions that Paperclip supports read the key from
|
||||
`auth.json`, not directly from the process environment.
|
||||
2. **Host ChatGPT-subscription login:** when no per-agent key is configured,
|
||||
Paperclip symlinks `auth.json` from the shared host Codex home into the
|
||||
managed home. The symlink keeps rotating/single-use refresh tokens live
|
||||
instead of copying a stale token into the managed home.
|
||||
3. **External `CODEX_HOME`:** if adapter env points `CODEX_HOME` outside the
|
||||
Paperclip-managed company tree, that home is self-managed. Paperclip does
|
||||
not seed or overwrite it, so its own `auth.json` wins.
|
||||
|
||||
For sandbox or SSH execution, Paperclip uploads the effective managed
|
||||
`CODEX_HOME` and launches Codex with `CODEX_HOME` pointing at that uploaded
|
||||
directory. Any `auth.json` already baked into the sandbox image is shadowed in
|
||||
managed-home mode. If the host has no usable `auth.json` and no per-agent
|
||||
`OPENAI_API_KEY`, the managed run fails fast instead of falling back to an
|
||||
in-sandbox login.
|
||||
|
||||
Worked example: a worker runs in a sandbox image that already has
|
||||
`$HOME/.codex/auth.json`, and the Paperclip host is logged in with a ChatGPT
|
||||
subscription. For a managed `codex_local` agent, Paperclip symlinks the host
|
||||
`auth.json` into the agent's managed home, uploads that home to the sandbox,
|
||||
and sets `CODEX_HOME` to the uploaded path. Codex reads the host-owned
|
||||
uploaded file, so the sandbox image login does not win.
|
||||
|
||||
For high-concurrency sandbox fleets, prefer a per-agent `OPENAI_API_KEY` over a
|
||||
shared ChatGPT-subscription login. API-key mode produces a standalone
|
||||
`auth.json` for each managed home and avoids many concurrent sandboxes sharing
|
||||
one rotating subscription credential. The tradeoff is billing: API-key mode is
|
||||
metered per token through the OpenAI API, while ChatGPT-subscription auth uses
|
||||
the subscription's flat-plan economics and quota behavior. Pick the mode
|
||||
deliberately for the fleet's cost and concurrency profile.
|
||||
|
||||
### Deferred config-validation warning spec
|
||||
|
||||
This section specifies a warning that is not implemented yet. The warning should
|
||||
help operators notice the host-owns-auth topology before they run a sandbox
|
||||
fleet with ChatGPT-subscription credentials.
|
||||
|
||||
- **Source fields:** resolved Codex auth mode (`api` vs `subscription`) and
|
||||
execution target kind (`local`, `remote:ssh`, or `remote:sandbox`). Infer the
|
||||
auth mode from the final managed `$CODEX_HOME/auth.json` shape after seeding:
|
||||
`{ "OPENAI_API_KEY": ... }` means API-key mode; subscription-token-shaped
|
||||
host auth, including the symlinked host file, means ChatGPT-subscription
|
||||
mode. Use top-level shape only; do not read credential values into the
|
||||
warning. The target kind comes from `AdapterExecutionTarget`.
|
||||
- **Transformations:** during config preparation or home seeding for a run,
|
||||
classify `(subscription auth mode AND remote/sandbox execution target)` as a
|
||||
warning condition. This is classification only. Do not read credential values
|
||||
into the warning.
|
||||
- **Sink fields:** emit a warning log line through `onLog("stderr", ...)` and,
|
||||
when the config-validation surface supports it, a surfaced validation warning.
|
||||
The sink may include only the auth-mode label and target type.
|
||||
- **Retention:** warning text may appear in ephemeral run logs or validation
|
||||
results. Do not persist auth material.
|
||||
- **Attacker-observable IDs:** none new. The warning must not print token
|
||||
values, email addresses, or `auth.json` contents.
|
||||
- **Hook point:** wire the check at the `codex_local` execute/config-prep path
|
||||
around managed-home seeding: `execute.ts` already has `executionTarget` /
|
||||
target transport in scope, calls `seedManagedCodexHome`, and calls
|
||||
`evaluateCodexCredentialReadiness` before uploading `CODEX_HOME`. If the
|
||||
warning is factored into `codex-home.ts`, pass the resolved target
|
||||
classification in rather than making `codex-home.ts` inspect execution
|
||||
targets on its own.
|
||||
|
||||
Because the warning touches authentication behavior, implementation must go
|
||||
through the security-review gate. Treat this docs section as the follow-up
|
||||
implementation spec, not as authorization to add the warning in a docs-only
|
||||
change.
|
||||
|
||||
## Manual Local CLI
|
||||
|
||||
For manual local CLI usage outside heartbeat runs (for example running as `codexcoder` directly), use:
|
||||
|
|
|
|||
|
|
@ -31,6 +31,28 @@ When a heartbeat fires, Paperclip:
|
|||
| [Process](/adapters/process) | `process` | Executes arbitrary shell commands |
|
||||
| [HTTP](/adapters/http) | `http` | Sends webhooks to external agents |
|
||||
|
||||
## Credential ownership for sandbox targets
|
||||
|
||||
Local CLI adapters can run on the Paperclip host, SSH targets, or managed
|
||||
sandbox targets. The adapter decides which credential home is authoritative
|
||||
before the CLI starts:
|
||||
|
||||
| Adapter | Credential topology | Which credential file wins on managed sandbox targets |
|
||||
|---------|---------------------|-------------------------------------------------------|
|
||||
| [`codex_local`](/adapters/codex-local) | Host-owns-auth for Paperclip-managed `CODEX_HOME` | A host-owned `auth.json` is symlinked into the managed `CODEX_HOME` and uploaded to the sandbox. If a per-agent `OPENAI_API_KEY` is configured, Paperclip writes an API-key `auth.json` instead and that file wins. A login baked into the sandbox image is shadowed because Codex runs with Paperclip's uploaded `CODEX_HOME`. |
|
||||
| [`claude_local`](/adapters/claude-local) | Snapshot-owns-auth for managed remote Claude config | Paperclip uploads only sanitized settings and skill/runtime assets. When the remote managed config has no Claude credential files, it copies `.credentials.json` or `credentials.json` from the sandbox image's own `$HOME/.claude`, so the image's login wins. |
|
||||
|
||||
Worked examples:
|
||||
|
||||
- **Codex sandbox with host ChatGPT login:** the host `~/.codex/auth.json`
|
||||
is symlinked into the managed home, then uploaded as the sandbox
|
||||
`CODEX_HOME`. Codex reads that uploaded file and does not use any
|
||||
`auth.json` already present inside the sandbox image.
|
||||
- **Claude sandbox with image login:** Paperclip materializes a remote
|
||||
`CLAUDE_CONFIG_DIR`, then fills missing `.credentials.json` /
|
||||
`credentials.json` from the sandbox image's own `$HOME/.claude`. The
|
||||
snapshot's Claude login is the credential source for the run.
|
||||
|
||||
### Hermes local vs gateway
|
||||
|
||||
Use `hermes_local` when Paperclip should start the local `hermes` CLI on the
|
||||
|
|
|
|||
Loading…
Reference in New Issue