Scope Claude OAuth cache by profile - #2380
Conversation
Redacted live credential-ownership proofExact PR head: This proof intentionally excludes account identity, credentials, token values, usage amounts, raw Keychain records, raw CLI payloads, raw unified-log lines, and private filesystem paths. The private verifier directory was not uploaded. Before / root causeRedacted historical live logs showed Claude replace its owned credential item and CodexBar prompt again 15 seconds later. That proves a user ACL grant was temporary: Claude's next credential refresh replaced the item CodexBar was reading. Exact-head results
Release executable hashes
The manifest was rechecked against the packaged app after the run; all four hashes passed. Broader validation
@clawsweeper re-review |
|
🦞🧹 I asked ClawSweeper to review this item again. Re-review progress:
|
Exact-head redacted live proof — 2026-07-21 22:27 PDTCandidate: Build integrity:
Logged-in Claude owner-path result:
Runtime ownership/prompt audit:
Automated gates on the same candidate:
Behavioral boundaries covered:
Environment caveats, included for completeness:
No account identity, token, usage amount, raw Keychain value, raw log, or private artifact path is included or uploaded. @clawsweeper re-review |
|
🦞🧹 I asked ClawSweeper to review this item again. Re-review progress:
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 3d0dc5e09f
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Redacted exact-head proofThis supersedes the earlier proof and validates exact head
The public proof intentionally excludes account identity, credentials, token values, usage amounts, raw Keychain records, raw unified-log lines, and private filesystem paths. @clawsweeper re-review |
|
🦞🧹 I asked ClawSweeper to review this item again. Re-review progress:
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: b12c844e43
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: b00d85e90b
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7e6e23ff73
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
Exact-head redacted proof for
Raw account identity, credentials, tokens, usage values, Keychain records, logs, hashes, and local paths are intentionally excluded. @clawsweeper re-review |
|
🦞🧹 I asked ClawSweeper to review this item again. Re-review progress:
|
|
CI follow-up: the current aggregate failure is the unrelated date-sensitive SpendDashboard test group, not the Claude ownership change. It is isolated in draft PR #2390; this branch remains unchanged. |
|
@clawsweeper re-review Please publish the exact-head review for |
Independent exact-head validation found a test-safety gap; focused follow-up submittedI ran That means this run did not reach the owner-CLI process/log audit; it did not modify the real credential or ACL, and I am not presenting it as a passing live proof. The failures are the concrete, independently useful gap now addressed by #2441 at
Focused validation on the follow-up passed, cross-provider review completed with no remaining findings, and the P2 live-proof review thread is resolved. The unrelated SpendDashboard stabilization was deliberately removed because #2390 already owns it. The live reproduction proving that Always Allow succeeds and then is lost after foreign-item replacement is recorded in #1823: #1823 (comment) Once #2441 is available on this branch (or equivalent isolation is applied), the verifier should be rerun with the explicit live opt-in so Phase 1 cannot be host-state dependent and the process/log ownership audit remains meaningful. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8cf84bb793
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: b12e060f93
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Verification follow-up —
|
|
🦞🧹 I asked ClawSweeper to review this item again. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 9ba5485bbe
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review |
1 similar comment
|
@codex review |
|
Codex Review: Didn't find any major issues. Bravo. Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 30d8655967
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review |
Exact-head validation —
|
|
🦞🧹 I asked ClawSweeper to review this item again. |
b60fa59 to
3e4f495
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 3e4f4955cb
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
Layer 1 is dropped as requested. #2380 is rebased onto merged #2441 ( Exact-head verification after the rebase:
For the new #2484 extraction, I also prepared a clean residual stack on top of its current The two open #2484 environment-routing findings are already covered by that residual stack; a minimal foundation-only patch with 3/3 focused tests and |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: fe0171b584
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a49d5197fa
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a49d5197fa
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review |
|
Codex Review: Didn't find any major issues. 👍 Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 39065009d1
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 911b4b698b
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review Exact head: 72916db Latest fix preserves selected-profile OAuth authority over unrelated global MCP-only Keychain state across credential loading, strategy availability, and delegated refresh. Local proof: focused routing suites 42/42; make check green; canonical make test 732/732 selections, 61/61 first-pass groups, zero retries and zero timeouts. |
|
@codex review Exact head: c852ad4 CI lint follow-up: the selected-profile strategy regression moved into its own suite because the current merge base made ClaudeOAuthFetchStrategyAvailabilityTests 801 lines (limit 800). Production code and assertions are unchanged. Local proof after the split: focused OAuth routing suites 42/42; make check green with SwiftFormat 0/1595 and SwiftLint 0/1594. The preceding exact production tree also passed canonical make test 732/732 selections in 61/61 first-pass groups with zero retries and zero timeouts. |
|
Codex Review: Didn't find any major issues. 👍 Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
|
Exact-head local verification completed for c852ad4: canonical make test passed 733/733 selections across 62/62 first-pass groups, with zero failed groups, retries, recoveries, or timeouts. The one live-account test remained intentionally skipped because LIVE_TEST is disabled; all isolated fake-data regressions ran and passed. |
|
Exact-head CI is fully green for c852ad4: https://github.com/steipete/CodexBar/actions/runs/30411136486
The prepared residual stack on #2484 still has the identical tree (254fc91fa3a0542ca92ddd7957b61cb20908f78e). I am holding the final restack and ClawSweeper re-review until the maintainer updates/lands #2484, so those results are not invalidated by another base change. |
Layer 2 of 5: profile/cache foundation and safe cache access
This replaces the former aggregate diff with the cache/migration layer requested in maintainer review.
Depends on #2441 (test isolation). Until #2441 lands, this branch contains its current-main rebased equivalent so the layer remains independently buildable and testable. The production review target is five commits on top: profile-scoped Claude OAuth cache state, the Keychain ACL safety gate found by exact packaged-app verification, serialized delegated-refresh attribution found by Codex review, the ambient-attribution/profile-corroboration correction, and the latest cross-profile prompt/preflight/failure-gate safety corrections.
Root cause and principles-first fix
The repeated password dialog was not controlled solely by the Claude prompt preference. CodexBar cache reads used a secret-data Keychain query, and an attributes-only preflight could report success even when the cache item's decrypt ACL did not trust the current packaged executable. The later secret query could therefore invoke macOS authorization UI despite the no-prompt setting.
The shared cache boundary now:
Codex review also identified two attribution hazards. First, the coordinator released profile A's in-flight slot before A synchronized Claude's global Keychain result, allowing profile B to replace that global item in the gap. File reconciliation and Keychain-to-profile-cache synchronization now execute inside the same serialized coordinator task, before the in-flight slot is released. Second, an ordinary profile-cache miss could copy Claude's global, profile-less Keychain item into any selected profile. Ordinary cache misses now fail closed; only the explicitly attributed serialized post-delegated-refresh path can seed a profile cache from that item.
Account corroboration and credential-file fingerprints now use the same selected fetch environment, including custom
CLAUDE_CONFIG_DIRandHOME, so a default-home account cannot be mistaken for the selected profile.The latest review found three remaining shared-state boundaries. Interactive prompt outcomes are now tagged with the selected profile and cannot be replayed into another profile in the same refresh request. Cache ACL preflight now authorizes only the executable that will actually perform the secret operation, so trust granted to the app cannot authorize the CLI (or vice versa). Refresh-failure fingerprints now observe only the selected profile's credentials file, so an unrelated change to Claude's global Keychain item cannot unblock another profile.
The follow-up review closed the final persistence gaps: an unsafe cache ACL is now a typed cache miss so it cannot suppress owner-mediated recovery; an interactive read of Claude's global, profile-less item remains ephemeral and is never persisted under a selected profile; and delegated refresh recovery now seeds the profile cache only from that selected profile's credentials file, never from a global item that another process could replace.
The final diagnostics review found one remaining profile-labeling error: the debug cooldown query used the process-default profile. It now receives the same selected fetch environment as the rest of the Claude diagnostic, with a regression proving a custom
CLAUDE_CONFIG_DIRcannot display another profile's cooldown.Profile and upgrade behavior
CLAUDE_CONFIG_DIR,CLAUDE_SECURESTORAGE_CONFIG_DIR, andHOME;legacyRecheckPendingstate when the legacy lookup is temporarily unavailable;invalid_grant;.neverpolicy for foreign Claude Keychain reads while allowing CodexBar-owned cache use.Regression coverage
The tests cover:
CLAUDE_CONFIG_DIRprofiles and a customHOME;Scope boundary
This PR intentionally does not contain the owner-CLI shutdown/routing changes, UI/recovery copy, or live verifier. Those remain prepared as layers 3–5 so each concern is independently reviewable. The forward-integration candidate below proves the complete user-visible path.
Verification
Exact PR head
b60fa59b6efcd9323f2efccbf750432e65ef0bd6:make check: passed; SwiftFormat 0/1,598 and SwiftLint 0/1,597;make test: 734/734 selections in 62/62 groups, zero failures, retries, or timeouts;git diff --check: passed;Forward-integration candidate
143dfed7aba3f548093ceb46285ec9afcaedccbf(layers 1–5):make check: passed; SwiftFormat 0/1,598 and SwiftLint 0/1,597;make test: 734/734 selections in 62/62 groups, zero failures, retries, or timeouts;provider=claude,source=claude, structured usage payload present;c430b636011683c8ebc02f621da7ea1cbbd173f58f67747d1127a3924e740f2f;ce2695823cbb1c624ac6592265f219cb6b71e4de80d48ce6184cc8ef2cc32c1b;af36af80f2cab4e520658bdce60b8e9a0297f8c35c8bbe1a0d294bcf5db74f94.The bounded live run completed July 28, 2026 at 12:14 PM PDT. The proof contains hashes, counts, and route status only—no account identity, credential/token values, usage values, customer data, or raw logs. The local package is ad-hoc signed because this machine has no Developer ID Application identity; a maintainer-signed artifact remains the release-signing gate.