Skip to content

Avoid repeated CodexBarCache keychain prompts in dev builds#1271

Open
Yuxin-Qiao wants to merge 4 commits into
steipete:mainfrom
Yuxin-Qiao:fix/keychain-prompt-storm
Open

Avoid repeated CodexBarCache keychain prompts in dev builds#1271
Yuxin-Qiao wants to merge 4 commits into
steipete:mainfrom
Yuxin-Qiao:fix/keychain-prompt-storm

Conversation

@Yuxin-Qiao
Copy link
Copy Markdown
Contributor

@Yuxin-Qiao Yuxin-Qiao commented Jun 1, 2026

Summary

  • Prevent repeated macOS CodexBar Cache keychain password prompts when contributors launch an ad-hoc / SwiftPM dev build directly from .build/.../debug/CodexBar.
  • Detect the risky launch mode once at startup and disable Keychain access for that process before CodexBar reaches the cache/cookie/OAuth keychain paths.
  • Keep installed production behavior unchanged: /Applications/CodexBar.app is not auto-disabled and still uses the normal Keychain path.

Impact

This is a contributor-facing local development failure mode. The macOS prompt is modal, asks for the user's login keychain password, and can appear repeatedly even after choosing Allow / Always Allow. That makes local validation feel broken and confusing because the dev build appears to demand sensitive credentials for CodexBar Cache over and over.

Runtime evidence from the failure mode showed:

ObjectAcl REJECTS
ACL partition mismatch
CodexBar wants to use your confidential information stored in "CodexBarCache" in your keychain

The root cause is identity churn: a direct SwiftPM debug executable is ad-hoc signed, has no certificate-backed stable identity, and gets a different code identity after rebuilds. Existing Keychain ACLs written for /Applications/CodexBar.app or a previous dev binary do not match the current ad-hoc executable, so macOS falls back to the legacy password prompt.

Fresh local repro boundary checked on 2026-06-02: the prompt can still be reproduced from an older installed /Applications/CodexBar.app (0.32.2, build 77) because that binary does not contain this patch. That does not invalidate the guard; it confirms the user-facing failure is real and that validation must be done with a rebuilt PR binary. The installed app is Developer ID signed with Team identifier Y5PE65HELJ, so production signing is stable; stale or dev-retrusted CodexBar Cache ACL entries can still make an older installed build prompt until the cache items are cleared or the patched build is used.

Behavior evidence

Before this PR

Direct local launch:

.build/arm64-apple-macosx/debug/CodexBar

When CodexBar later reads cached cookies/OAuth entries from com.steipete.codexbar.cache, the app can hit a Keychain ACL mismatch and macOS displays the blocking dialog:

CodexBar wants to use your confidential information stored in "CodexBarCache" in your keychain.

Because each ad-hoc rebuild has a new code identity, allowing the prompt does not reliably stop the next prompt.

After this PR

On startup, KeychainPromptCoordinator checks the running executable identity/path. If the process is a SwiftPM debug build or ad-hoc signed, it calls:

KeychainAccessGate.forceDisabledForProcess(reason: "ad-hoc-dev-build")

That process-level guard survives later settings initialization, so cache/cookie/OAuth keychain code sees KeychainAccessGate.isDisabled == true and avoids the real Keychain path. In particular:

  • KeychainCacheStore.load/store/clear/keys return missing/no-op/empty instead of calling SecItemCopyMatching for com.steipete.codexbar.cache.
  • Browser-cookie keychain access is disabled through the existing SweetCookieKit bridge.
  • Provider implementations already receive keychainDisabled and skip keychain-backed cookie imports.

This turns the risky dev-build path into an explicit no-Keychain local run instead of a recurring macOS password prompt loop.

Scope

  • Affects only ad-hoc / raw SwiftPM dev-build processes.
  • Does not change Keychain ACL construction.
  • Does not add an env-var bypass.
  • Does not disable Keychain for the installed Developer ID signed app.
  • Does not disable Keychain for a packaged CodexBar.app signed with a stable local dev certificate.
  • Does not alter production auth behavior for /Applications/CodexBar.app.
  • Documents the installed-app edge case: a stable signed app can still be prompted if existing cache item ACLs were previously re-trusted for a different dev-build identity, but this PR avoids creating or amplifying that state from raw dev builds.

Evidence

Focused dev-build prompt guard

Command:

swift test --filter KeychainPromptCoordinatorTests

Output excerpt:

✔ Suite KeychainPromptCoordinatorTests passed after 0.001 seconds.
✔ Test run with 6 tests in 1 suite passed after 0.001 seconds.

Covered cases:

  • /Applications/CodexBar.app does not trigger the guard.
  • SwiftPM .build/.../debug/CodexBar triggers the warning/guard.
  • Ad-hoc signed binaries trigger the warning/guard regardless of path.
  • Stable signed packaged dev apps keep normal keychain access.
  • The warning text points to concrete workarounds and states that Keychain access was disabled for the process.

Keychain regression suite

Command:

swift test --filter "KeychainPromptCoordinator|KeychainCacheStore|KeychainNoUIQuery|KeychainAccessGate|KeychainPromptSafetyAudit"

Output excerpt:

✔ Suite KeychainPromptCoordinatorTests passed after 0.001 seconds.
✔ Suite KeychainCacheStoreTests passed after 0.003 seconds.
✔ Suite ClaudeOAuthKeychainAccessGateTests passed after 0.004 seconds.
✔ Suite KeychainNoUIQueryTests passed after 0.007 seconds.
✔ Suite KeychainPromptSafetyAuditTests passed after 0.177 seconds.
✔ Test run with 30 tests in 5 suites passed after 0.184 seconds.

Important new coverage:

✔ Test "process force disable survives settings override" passed

This verifies the actual fix: once the dev-build guard disables Keychain access for the process, a later KeychainAccessGate.isDisabled = false from settings initialization cannot re-enable it and reintroduce the prompt loop.

Recommended local workflows

  • Normal use: launch /Applications/CodexBar.app.
  • Runtime validation: use ./Scripts/compile_and_run.sh, which packages and launches CodexBar.app with a stable local signing identity when available.
  • Direct .build/.../debug/CodexBar runs are still possible, but they now intentionally run without Keychain access to avoid the repeated macOS prompt.

@clawsweeper
Copy link
Copy Markdown

clawsweeper Bot commented Jun 1, 2026

Codex review: needs maintainer review before merge. Reviewed June 3, 2026, 12:02 AM ET / 04:02 UTC.

Summary
The PR adds startup detection for ad-hoc or raw SwiftPM dev launches, disables Keychain access for that process, and documents/tests the dev-build prompt behavior.

Reproducibility: yes. with a policy caveat: the concrete path is launching the raw SwiftPM debug binary from .build and then reaching CodexBarCache-backed keychain reads. I did not run live Keychain validation because AGENTS.md warns against checks that can display Keychain prompts, but the PR includes current-head runtime logs from that path.

Review metrics: 2 noteworthy metrics.

  • Diff surface: 5 files changed, +343/-0. The PR is focused but touches process-wide keychain gating, tests, and contributor docs.
  • Runtime proof: 1 current-head raw dev launch log proof. The proof directly exercises the non-visual keychain guard path that cannot be safely reproduced here without risking Keychain prompts.

Merge readiness
Overall: 🐚 platinum hermit
Proof: 🐚 platinum hermit
Patch quality: 🐚 platinum hermit
Result: ready for maintainer review.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • none.

Risk before merge

  • [P1] The PR intentionally makes raw ad-hoc SwiftPM launches run without keychain-backed auth/cache/browser-cookie access; contributors relying on that direct launch workflow must use a signed app bundle, the installed app, or manual credentials.
  • [P1] The production boundary depends on macOS signing inspection and path detection; maintainers should be comfortable with the supplied tests/log proof that Developer ID and stable signed packaged apps stay on the normal Keychain path.

Maintainer options:

  1. Accept no-Keychain raw dev builds (recommended)
    Merge as-is if maintainers agree that direct .build debug launches should trade keychain-backed providers for avoiding repeated modal Keychain prompts.
  2. Require signed-bundle smoke proof
    Before merge, maintainers can ask for or run one signed CodexBar.app smoke check showing the guard stays off for stable signed app launches.
  3. Pause for a narrower policy
    If raw dev builds must keep Keychain access, pause this PR and choose an opt-in or workflow-specific guard instead of process-wide disabling for ad-hoc launches.

Next step before merge

  • [P2] The remaining action is maintainer approval of the intentional raw-dev-build Keychain behavior, not an obvious automated code repair.

Security
Cleared: No concrete security or supply-chain issue was found; the diff reduces Keychain exposure for ad-hoc dev launches and adds no dependencies, secret reads, or broader permissions.

Review details

Best possible solution:

The end state should be that raw ad-hoc dev builds fail closed before real Keychain reads, while Developer ID releases and stable signed local app bundles keep normal Keychain behavior with tests and docs covering the boundary.

Do we have a high-confidence way to reproduce the issue?

Yes, with a policy caveat: the concrete path is launching the raw SwiftPM debug binary from .build and then reaching CodexBarCache-backed keychain reads. I did not run live Keychain validation because AGENTS.md warns against checks that can display Keychain prompts, but the PR includes current-head runtime logs from that path.

Is this the best way to solve the issue?

Yes, assuming maintainers accept the dev-workflow tradeoff. The process-level gate is narrower than the earlier env-var bypass idea and current source shows the main cache/browser/OAuth Keychain paths consult KeychainAccessGate, while tests cover release and stable signed dev app boundaries.

AGENTS.md: found and applied where relevant.

Codex review notes: model gpt-5.5, reasoning high; reviewed against 3387cc8b2d47.

Label changes

Label changes:

  • add merge-risk: 🚨 compatibility: Merging changes the behavior of existing raw SwiftPM dev launches by disabling Keychain access for the process.
  • add proof: sufficient: Contributor real behavior proof is sufficient. The PR comments include redacted live log output from launching the current PR-head raw SwiftPM debug binary and observing the after-fix keychain guard message.
  • add rating: 🐚 platinum hermit: Overall readiness is 🐚 platinum hermit; proof is 🐚 platinum hermit and patch quality is 🐚 platinum hermit.
  • add status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (logs): The PR comments include redacted live log output from launching the current PR-head raw SwiftPM debug binary and observing the after-fix keychain guard message.
  • remove rating: 🌊 off-meta tidepool: Current PR rating is rating: 🐚 platinum hermit, so this older rating label is no longer current.

Label justifications:

  • P2: This is a normal-priority contributor dev-build bug fix with limited production blast radius but real auth-provider implications.
  • merge-risk: 🚨 compatibility: Merging changes the behavior of existing raw SwiftPM dev launches by disabling Keychain access for the process.
  • merge-risk: 🚨 auth-provider: The changed process gate controls whether OAuth, cache, token, and browser-cookie provider paths may use Keychain access.
  • rating: 🐚 platinum hermit: Overall readiness is 🐚 platinum hermit; proof is 🐚 platinum hermit and patch quality is 🐚 platinum hermit.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (logs): The PR comments include redacted live log output from launching the current PR-head raw SwiftPM debug binary and observing the after-fix keychain guard message.
  • proof: sufficient: Contributor real behavior proof is sufficient. The PR comments include redacted live log output from launching the current PR-head raw SwiftPM debug binary and observing the after-fix keychain guard message.
Evidence reviewed

What I checked:

  • Repository policy applied: AGENTS.md was read fully; its Keychain guidance affected the review by avoiding live validation that could display macOS Keychain prompts. (AGENTS.md:23, 3387cc8b2d47)
  • Current main lacks dev-build guard: Current main initializes KeychainAccessGate from the stored debugDisableKeychainAccess preference and installs prompt handlers, but has no ad-hoc or SwiftPM dev-build detection before settings/store initialization. (Sources/CodexBar/CodexbarApp.swift:41, 3387cc8b2d47)
  • PR implements early process-level disable: The PR calls logAdHocDevBuildHintIfNeeded during prompt coordinator installation and force-disables Keychain access when the bundle path/signing check identifies a raw SwiftPM or ad-hoc launch. (Sources/CodexBar/KeychainPromptCoordinator.swift:112, 9134e106625e)
  • PR preserves forced disable against settings override: KeychainAccessGate checks processForceDisabledReason before persisted overrides, and forceDisabledForProcess also mirrors the effective disabled state into SweetCookieKit's browser-cookie gate. (Sources/CodexBarCore/KeychainAccessGate.swift:20, 9134e106625e)
  • Existing keychain paths honor global gate: Current main routes cache reads/writes, browser-cookie attempts, and Claude OAuth keychain access through KeychainAccessGate.isDisabled, so a process-level disable reaches the core keychain surfaces. (Sources/CodexBarCore/KeychainCacheStore.swift:268, 3387cc8b2d47)
  • Focused regression coverage: The PR adds tests for release apps, stable signed packaged dev apps, raw SwiftPM debug paths, ad-hoc paths, and forced-disable survival after a false settings override. (Tests/CodexBarTests/KeychainPromptCoordinatorTests.swift:20, 9134e106625e)

Likely related people:

  • steipete: Peter Steinberger introduced KeychainCacheStore, added the debug Keychain kill switch, and recently updated cache trusted-app behavior in the affected keychain path. (role: feature owner and recent area contributor; confidence: high; commits: 30e339548522, f7bb3d7c11e5, c66ea426e7d3; files: Sources/CodexBarCore/KeychainCacheStore.swift, Sources/CodexBarCore/KeychainAccessGate.swift, Sources/CodexBar/CodexbarApp.swift)
  • Nimrod Gutman: The dev prompt churn history is directly related: this contributor changed compile_and_run.sh signing identity detection and KeychainCacheStore ACL update behavior. (role: adjacent dev-signing/keychain contributor; confidence: medium; commits: 37dc64170fa6; files: Scripts/compile_and_run.sh, Sources/CodexBarCore/KeychainCacheStore.swift)
  • ratulsarna: Ratul Sarna previously added KeychainAccessGate test hooks and worked in the Claude OAuth keychain paths that this process-level disable affects. (role: adjacent Claude OAuth/keychain test contributor; confidence: medium; commits: a86e240ee9e7, f63e149821a5; files: Sources/CodexBarCore/KeychainAccessGate.swift, Sources/CodexBarCore/Providers/Claude/ClaudeOAuth/ClaudeOAuthCredentials.swift, Tests/CodexBarTests/ClaudeOAuthKeychainAccessGateTests.swift)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. P2 Normal priority bug or improvement with limited blast radius. merge-risk: 🚨 auth-provider 🚨 Merging this PR could break OAuth, tokens, provider routing, model choice, or credentials. labels Jun 1, 2026
@Yuxin-Qiao Yuxin-Qiao force-pushed the fix/keychain-prompt-storm branch 2 times, most recently from 3552dc7 to 0b751f8 Compare June 2, 2026 12:24
@Yuxin-Qiao Yuxin-Qiao changed the title Add dev-only Claude keychain prompt bypass Help contributors diagnose keychain prompts from ad-hoc dev builds Jun 2, 2026
@Yuxin-Qiao
Copy link
Copy Markdown
Contributor Author

I redirected this PR after collecting runtime evidence from the repeated CodexBarCache prompt. The original implementation used a Claude-only CODEXBAR_DEV TRUST_KEYCHAIN bypass, but that was too narrow and could affect release auth behavior if the env var leaked into production. The new version removes the bypass entirely and instead documents the ad-hoc dev-build keychain trap plus adds a one-shot diagnostic warning for SwiftPM/ad-hoc dev builds. No keychain/auth behavior is changed.

@clawsweeper clawsweeper Bot removed the merge-risk: 🚨 auth-provider 🚨 Merging this PR could break OAuth, tokens, provider routing, model choice, or credentials. label Jun 2, 2026
@Yuxin-Qiao Yuxin-Qiao force-pushed the fix/keychain-prompt-storm branch from 0b751f8 to 86ec4bd Compare June 2, 2026 12:52
@Yuxin-Qiao Yuxin-Qiao force-pushed the fix/keychain-prompt-storm branch from 86ec4bd to 74c009d Compare June 2, 2026 13:54
@Yuxin-Qiao
Copy link
Copy Markdown
Contributor Author

Real dev/ad-hoc launch proof captured for the one-shot diagnostic.

Setup:

  • PR head: 74c009d
  • Built and launched the PR branch SwiftPM dev binary:
    .build/arm64-apple-macosx/debug/CodexBar
  • The dev binary is ad-hoc signed:
    Signature=adhoc
    TeamIdentifier=not set
  • Launched briefly, captured unified logs, then stopped only the dev process.

Redacted log proof:

[com.steipete.codexbar:keychain-prompt] Ad-hoc dev build detected — may cause repeated macOS keychain prompts for CodexBarCache (adHocSigned=true bundlePath=~/CodexBar-src/.build/arm64-apple-macosx/debug doc=docs/LOCAL_DEV_BUILD.md)

[com.steipete.codexbar:keychain-prompt] CodexBar is running from a SwiftPM dev build or an ad-hoc-signed bundle (bundle=~/CodexBar-src/.build/arm64-apple-macosx/debug, exec=~/CodexBar-src/.build/arm64-apple-macosx/debug/CodexBar, adHoc=true). This commonly causes macOS to repeatedly prompt for 'CodexBar wants to use your confidential information stored in CodexBarCache in your keychain.' Use /Applications/CodexBar.app for normal use, or run via ./Scripts/compile_and_run.sh. See docs/LOCAL_DEV_BUILD.md.

@Yuxin-Qiao
Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@clawsweeper
Copy link
Copy Markdown

clawsweeper Bot commented Jun 2, 2026

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

Re-review progress:

@Yuxin-Qiao Yuxin-Qiao changed the title Help contributors diagnose keychain prompts from ad-hoc dev builds Avoid repeated CodexBarCache keychain prompts in dev builds Jun 2, 2026
@clawsweeper clawsweeper Bot added rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. merge-risk: 🚨 auth-provider 🚨 Merging this PR could break OAuth, tokens, provider routing, model choice, or credentials. and removed rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. labels Jun 2, 2026
@Yuxin-Qiao
Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@clawsweeper
Copy link
Copy Markdown

clawsweeper Bot commented Jun 2, 2026

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

@clawsweeper clawsweeper Bot added rating: 🌊 off-meta tidepool PR readiness rating does not apply to this item. and removed rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. labels Jun 2, 2026
@Yuxin-Qiao
Copy link
Copy Markdown
Contributor Author

Current-head validation for 9134e106625e98c96da1e64d7636c108edacd8fc.

Checked locally from a fresh PR checkout at /private/tmp/codexbar-pr1271.

Focused test:

swift test --filter KeychainPromptCoordinatorTests
✔ Suite KeychainPromptCoordinatorTests passed after 0.001 seconds.
✔ Test run with 6 tests in 1 suite passed after 0.001 seconds.

Raw SwiftPM debug binary signing:

Executable=/private/tmp/CodexBar-pr1271/.build/arm64-apple-macosx/debug/CodexBar
Signature=adhoc
TeamIdentifier=not set

Runtime log proof from launching that exact raw debug binary:

[com.steipete.codexbar:keychain-prompt] Ad-hoc dev build detected — disabling keychain access to avoid CodexBarCache prompts (adHocSigned=true bundlePath=/private/tmp/CodexBar-pr1271/.build/arm64-apple-macosx/debug doc=docs/LOCAL_DEV_BUILD.md)

[com.steipete.codexbar:keychain-prompt] CodexBar is running from a SwiftPM dev build or an ad-hoc-signed bundle (bundle=/private/tmp/CodexBar-pr1271/.build/arm64-apple-macosx/debug, exec=/private/tmp/CodexBar-pr1271/.build/arm64-apple-macosx/debug/CodexBar, adHoc=true). This commonly causes macOS to repeatedly prompt for 'CodexBar wants to use your confidential information stored in CodexBarCache in your keychain.' CodexBar has disabled keychain access for this process to avoid the prompt loop. Use /Applications/CodexBar.app for normal use, or run via ./Scripts/compile_and_run.sh. See docs/LOCAL_DEV_BUILD.md.

This verifies the current PR head detects the raw ad-hoc SwiftPM launch mode and disables Keychain access before the process can fall into the repeated CodexBarCache prompt loop.

@Yuxin-Qiao
Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@clawsweeper
Copy link
Copy Markdown

clawsweeper Bot commented Jun 3, 2026

🦞👀
ClawSweeper picked this up.

Command router queued. I will update this comment with the next step.

Re-review progress:

@clawsweeper clawsweeper Bot added proof: sufficient Contributor real behavior proof is sufficient. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. merge-risk: 🚨 compatibility 🚨 Merging this PR could break existing users, config, migrations, defaults, or upgrades. and removed rating: 🌊 off-meta tidepool PR readiness rating does not apply to this item. labels Jun 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

merge-risk: 🚨 auth-provider 🚨 Merging this PR could break OAuth, tokens, provider routing, model choice, or credentials. merge-risk: 🚨 compatibility 🚨 Merging this PR could break existing users, config, migrations, defaults, or upgrades. P2 Normal priority bug or improvement with limited blast radius. proof: sufficient Contributor real behavior proof is sufficient. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant