mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-07 07:23:08 +02:00
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - The codex_local adapter supports a device login that runs in a trusted sandbox and promotes the credential into the per-company managed Codex home > - The managed-home re-seeding step treats every regular-file `auth.json` as apikey-mode residue and removes it so the shared-home symlink can be restored > - The promotion writes the company credential as a regular file, so the first environment Test or run after a successful login deletes it > - On a server with no shared Codex login — any containerized deployment — nothing replaces the file, and the UI reports that the sandbox has no ready authentication right after it reported a successful login > - This pull request makes the cleanup identity-anchored: a subscription credential whose identity the shared source does not hold survives re-seeding > - The benefit is that a device login stays usable after Test and runs, on hosts with and without a shared Codex login ## Linked Issues or Issue Description No public GitHub issue covers this. The problem is described in-PR following the bug template. Related public PRs: [#11237](https://github.com/paperclipai/paperclip/pull/11237) added the sandbox device login and the credential promotion, [#11097](https://github.com/paperclipai/paperclip/pull/11097) added its building blocks, and the `ensureSymlink` heal for stale copies came from the fix for #5028. [#9621](https://github.com/paperclipai/paperclip/pull/9621) touches the adjacent sandbox auth sync-back lane but not this defect. **Subsystem affected** packages/adapters/codex-local — managed `CODEX_HOME` seeding (`codex-home.ts`). **Current behavior** A successful device login promotes the subscription `auth.json` into the company Codex home as a regular file, and the UI reports the login as authenticated. The next `seedManagedCodexHome` call — the environment Test probe and every execute both run it — removes any regular-file `auth.json` when no API key is configured, because the cleanup assumes such a file is apikey-mode residue left by a previous run. It then symlinks `auth.json` from the shared source home. On a server whose shared home has no Codex login (a container image, for example), there is no source to symlink, so the home ends with no credential at all. The Test probe then reports "The sandbox has no ready authentication for this adapter" immediately after a successful login, and a fresh login repeats the same cycle. On a server whose shared home does hold a login, the symlink silently replaces the promoted account with the host account. **Expected behavior** The credential a device login promoted stays in the company home across Test probes and runs. The #5028 heal (a stale regular-file copy of the shared credential becomes a symlink to the live source) and the apikey-residue cleanup keep working. **Steps to reproduce** 1. Run the server in an environment whose shared Codex home (`$CODEX_HOME` or `~/.codex`) has no `auth.json`. 2. Complete a Codex device login for a company; the promotion writes the company home `auth.json` and the UI reports authenticated. 3. Click Test on a codex_local agent (or start a run). The probe reports no ready authentication, and the promoted `auth.json` is gone from the company home. **Proposed solution** Make the cleanup identity-anchored, the same rule the promotion and the cache vend already use. A regular-file `auth.json` survives re-seeding when it holds a usable subscription identity that the shared source does not also hold, and the shared symlink does not replace it. A same-identity regular file is still the #5028 stale copy and is still healed into the symlink, because the symlink serves the same account with live, rotating tokens. An apikey-mode or unreadable file is still removed. ## What Changed - `seedManagedCodexHome` reads the target `auth.json` before the cleanup and keeps it when `readSubscriptionAccountId` yields an identity the shared source `auth.json` does not hold. The kept file is excluded from the shared symlink pass, and the function logs a fixed line when it keeps the file. - The function doc comment states the kept-promoted-credential rule. - Four new `seedManagedCodexHome` test cases: a promoted credential with no shared auth, a promoted credential with a different shared identity, the same-identity #5028 heal, and apikey-mode residue removal. ## Verification ```sh cd packages/adapters/codex-local npx tsc --noEmit # clean npx vitest run # 28 files, 321 passed, 1 skipped ``` The four new cases fail on the previous code: the first two observed the promoted file deleted (and, with a shared login present, replaced by the shared symlink). ## Risks Low risk. The change narrows one deletion path. Deployments that never use the device login see no difference: without a promoted subscription file, the cleanup and the symlink behave exactly as before, and the #5028 heal is pinned by an existing test plus a new same-identity test. The one deliberate behavioral shift: after a device login, the promoted company credential now stays authoritative over the shared host login for that company — which is the promotion's documented contract ("the company credential slot"). ## Model Used Claude Fable 5 (`claude-fable-5`), extended thinking, with tool use and code execution — investigation, implementation, and tests. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [ ] All Paperclip CI gates are green - [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge