Skip to content

test(CodexBarCore): isolate Claude keychain state under unit tests - #2441

Merged
steipete merged 11 commits into
steipete:mainfrom
ss251:fix/claude-keychain-test-isolation
Jul 28, 2026
Merged

test(CodexBarCore): isolate Claude keychain state under unit tests#2441
steipete merged 11 commits into
steipete:mainfrom
ss251:fix/claude-keychain-test-isolation

Conversation

@ss251

@ss251 ss251 commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Intent

Submit a focused upstream safety patch discovered while validating the recurring Claude Code-credentials prompt fix. CodexBar's standard test suite must never inherit the developer's persisted Claude prompt preference, resolve the real Claude credentials file, share pending cache-clear state across tests, or lose the captured prompt policy inside detached delegated-refresh work. Preserve release behavior and explicit live-test opt-in; live proof must fail closed unless CODEXBAR_ALLOW_TEST_KEYCHAIN_ACCESS=1 exposes real user state. Add deterministic regression coverage, address the P2 review comment, and keep unrelated SpendDashboard stabilization out because PR #2390 already owns it. This complements, but does not compete with, the production ownership-boundary fix in PR #2380. Do not edit CHANGELOG.md. Existing unrelated SpendDashboard CI failures must be reported honestly rather than hidden. Skip the CI monitor on this follow-up because GitHub will rerun the known external #2390-dependent shard, and the pipeline must not auto-add duplicate SpendDashboard fixes again.

What Changed

  • Under the standard test suite (without live keychain opt-in), Claude OAuth paths no longer inherit the developer’s persisted prompt preference, resolve the real credentials file, or write/share process-wide pending cache-clear state; pending clears are isolated per TaskLocal/isolation scope.
  • Detached delegated-refresh work now carries the captured keychain prompt preference in DEBUG so policy is not lost across task boundaries.
  • Live Claude keychain proof tests fail closed unless CODEXBAR_ALLOW_TEST_KEYCHAIN_ACCESS=1, with regression coverage for isolation and opt-in gates.

Risk Assessment

✅ Low: DEBUG/test-only isolation is well-bounded, release paths are unchanged, the prior process-shared pending sink was replaced with per-scope TaskLocal stores plus ephemeral sinks, and deterministic regression coverage matches the required safety invariants.

Testing

Exercised the isolation acceptance criteria with focused Swift Testing suites (not the full suite): prompt-preference isolation, credentials-file isolation, pending cache-clear isolation, detached delegated-refresh prompt-policy capture, and live-keychain fail-closed gating; confirmed CHANGELOG/SpendDashboard stay out of the patch. All isolation tests passed, and LIVE=1 without ALLOW intentionally recorded that real user state requires CODEXBAR_ALLOW_TEST_KEYCHAIN_ACCESS=1. No UI surface changed, so evidence is CLI transcripts rather than screenshots.

Evidence: Live proof fails closed without CODEXBAR_ALLOW_TEST_KEYCHAIN_ACCESS=1

✘ Test "live background Auto skips the opaque Claude Keychain boundary" recorded an issue at ClaudeKeychainLiveProofTests.swift:25:25: Issue recorded ↳ Live proof requires CODEXBAR_ALLOW_TEST_KEYCHAIN_ACCESS=1 to read the real prompt policy

[0/1] Planning build
Building for debugging...
[0/14] Write swift-version--58304C5D6DBC2206.txt
Build complete! (7.66s)
Test Suite 'Selected tests' started at 2026-07-24 20:10:06.718.
Test Suite 'CodexBarPackageTests.xctest' started at 2026-07-24 20:10:06.719.
Test Suite 'CodexBarPackageTests.xctest' passed at 2026-07-24 20:10:06.719.
	 Executed 0 tests, with 0 failures (0 unexpected) in 0.000 (0.000) seconds
Test Suite 'Selected tests' passed at 2026-07-24 20:10:06.719.
	 Executed 0 tests, with 0 failures (0 unexpected) in 0.000 (0.001) seconds
◇ Test run started.
↳ Testing Library Version: 1902
↳ Target Platform: arm64e-apple-macos14.0
◇ Suite ClaudeKeychainLiveProofTests started.
◇ Test "live background Auto skips the opaque Claude Keychain boundary" started.
✘ Test "live background Auto skips the opaque Claude Keychain boundary" recorded an issue at ClaudeKeychainLiveProofTests.swift:25:25: Issue recorded
↳ Live proof requires CODEXBAR_ALLOW_TEST_KEYCHAIN_ACCESS=1 to read the real prompt policy
✘ Test "live background Auto skips the opaque Claude Keychain boundary" failed after 0.001 seconds with 1 issue.
✘ Suite ClaudeKeychainLiveProofTests failed after 0.001 seconds with 1 issue.
✘ Test run with 1 test in 1 suite failed after 0.001 seconds with 1 issue.
Evidence: Safety-named isolation tests (prompt pref, credentials file, pending cache clear)
Building for debugging...
[0/14] Write swift-version--58304C5D6DBC2206.txt
Build complete! (0.54s)
Test Suite 'Selected tests' started at 2026-07-24 20:09:34.213.
Test Suite 'CodexBarPackageTests.xctest' started at 2026-07-24 20:09:34.214.
Test Suite 'CodexBarPackageTests.xctest' passed at 2026-07-24 20:09:34.214.
	 Executed 0 tests, with 0 failures (0 unexpected) in 0.000 (0.000) seconds
Test Suite 'Selected tests' passed at 2026-07-24 20:09:34.214.
	 Executed 0 tests, with 0 failures (0 unexpected) in 0.000 (0.002) seconds
◇ Test run started.
↳ Testing Library Version: 1902
↳ Target Platform: arm64e-apple-macos14.0
◇ Suite KeychainPromptSafetyAuditTests started.
◇ Suite ManagedCodexAccountServiceTests started.
◇ Suite KeychainNoUIQueryTests started.
◇ Suite CursorUsageEventsFetcherTests started.
◇ Suite ClaudeOAuthCredentialsStorePromptPolicyTests started.
◇ Test "production source routes Security item APIs through the test safety gateway" started.
◇ Test "auth failure cleanup uses managed root safety check" started.
◇ Suite ClaudeOAuthCredentialsStoreIsolatedSecurityCLITests started.
◇ Test "pagination fails closed when a full safety cap page reaches the raw total" started.
◇ Test "safety recognizes runner variants and explicit controls" started.
◇ Suite ClaudeOAuthCredentialsStoreTests started.
◇ Test "safety blocks security CLI access to the login keychain" started.
◇ Test "safety does not inherit the application prompt preference" started.
◇ Test "safety isolates the default Claude credentials file" started.
✔ Test "safety recognizes runner variants and explicit controls" passed after 0.001 seconds.
✔ Suite KeychainNoUIQueryTests passed after 0.002 seconds.
✔ Test "safety blocks security CLI access to the login keychain" passed after 0.002 seconds.
✔ Suite ClaudeOAuthCredentialsStoreIsolatedSecurityCLITests passed after 0.002 seconds.
✔ Test "safety isolates the default Claude credentials file" passed after 0.006 seconds.
◇ Test "safety isolates pending cache clear from the application suite" started.
✔ Test "safety does not inherit the application prompt preference" passed after 0.015 seconds.
✔ Suite ClaudeOAuthCredentialsStorePromptPolicyTests passed after 0.016 seconds.
✔ Test "safety isolates pending cache clear from the application suite" passed after 0.010 seconds.
◇ Test "safety isolates pending cache clear across isolation scopes" started.
✔ Test "safety isolates pending cache clear across isolation scopes" passed after 0.001 seconds.
✔ Suite ClaudeOAuthCredentialsStoreTests passed after 0.019 seconds.
✔ Test "auth failure cleanup uses managed root safety check" passed after 0.019 seconds.
✔ Suite ManagedCodexAccountServiceTests passed after 0.020 seconds.
✔ Test "pagination fails closed when a full safety cap page reaches the raw total" passed after 0.022 seconds.
✔ Suite CursorUsageEventsFetcherTests passed after 0.023 seconds.
✔ Test "production source routes Security item APIs through the test safety gateway" passed after 1.836 seconds.
✔ Suite KeychainPromptSafetyAuditTests passed after 1.837 seconds.
✔ Test run with 9 tests in 7 suites passed after 1.838 seconds.
Evidence: ClaudeOAuthCredentialsStoreTests including three new safety isolation tests
Building for debugging...
[0/14] Write swift-version--58304C5D6DBC2206.txt
Build complete! (0.29s)
Test Suite 'Selected tests' started at 2026-07-24 20:08:56.753.
Test Suite 'CodexBarPackageTests.xctest' started at 2026-07-24 20:08:56.755.
Test Suite 'CodexBarPackageTests.xctest' passed at 2026-07-24 20:08:56.755.
	 Executed 0 tests, with 0 failures (0 unexpected) in 0.000 (0.000) seconds
Test Suite 'Selected tests' passed at 2026-07-24 20:08:56.755.
	 Executed 0 tests, with 0 failures (0 unexpected) in 0.000 (0.001) seconds
◇ Test run started.
↳ Testing Library Version: 1902
↳ Target Platform: arm64e-apple-macos14.0
◇ Suite ClaudeOAuthCredentialsStoreTests started.
◇ Test "persistent reference hash stays stable across keychain metadata refresh" started.
✔ Test "persistent reference hash stays stable across keychain metadata refresh" passed after 0.009 seconds.
◇ Test "safety isolates the default Claude credentials file" started.
✔ Test "safety isolates the default Claude credentials file" passed after 0.003 seconds.
◇ Test "safety isolates pending cache clear from the application suite" started.
✔ Test "safety isolates pending cache clear from the application suite" passed after 0.006 seconds.
◇ Test "safety isolates pending cache clear across isolation scopes" started.
✔ Test "safety isolates pending cache clear across isolation scopes" passed after 0.001 seconds.
◇ Test "loads from keychain cache before expired file" started.
2026-07-24T20:08:57+0530 info com.steipete.codexbar.claude-usage: [CodexBarCore] Claude OAuth credentials file changed; invalidating cache
✔ Test "loads from keychain cache before expired file" passed after 0.010 seconds.
◇ Test "load record non interactive repair can be disabled" started.
2026-07-24T20:08:57+0530 info com.steipete.codexbar.claude-usage: interaction=user [CodexBarCore] Claude keychain credentials loaded without prompt; syncing OAuth cache
✔ Test "load record non interactive repair can be disabled" passed after 0.010 seconds.
◇ Test "invalidates cache when credentials file changes" started.
2026-07-24T20:08:57+0530 info com.steipete.codexbar.claude-usage: [CodexBarCore] Claude OAuth credentials file changed; invalidating cache
2026-07-24T20:08:57+0530 info com.steipete.codexbar.claude-usage: [CodexBarCore] Claude OAuth credentials file changed; invalidating cache
✔ Test "invalidates cache when credentials file changes" passed after 0.001 seconds.
◇ Test "returns expired file when no other sources" started.
2026-07-24T20:08:57+0530 info com.steipete.codexbar.claude-usage: [CodexBarCore] Claude OAuth credentials file changed; invalidating cache
✔ Test "returns expired file when no other sources" passed after 0.001 seconds.
◇ Test "load with auto refresh expired claude CLI owner throws delegated refresh" started.
2026-07-24T20:08:57+0530 info com.steipete.codexbar.claude-usage: allowKeychainPrompt=false expiresAtMs=1784900337503 expiresInSec=-3600 hasRefreshToken=true hasUserProfileScope=true isExpired=true owner=claudeCLI readStrategy=securityFramework respectPromptCooldown=true scopesCount=1 source=cacheKeychain [CodexBarCore] Claude OAuth credentials considered expired
2026-07-24T20:08:57+0530 info com.steipete.codexbar.claude-usage: allowKeychainPrompt=false expiresAtMs=1784900337503 expiresInSec=-3600 hasRefreshToken=true hasUserProfileScope=true isExpired=true owner=claudeCLI readStrategy=securityFramework respectPromptCooldown=true scopesCount=1 source=cacheKeychain [CodexBarCore] Claude OAuth credentials expired; delegating refresh to Claude CLI
✔ Test "load with auto refresh expired claude CLI owner throws delegated refresh" passed after 0.001 seconds.
◇ Test "load with auto refresh expired codexbar owner uses direct refresh path" started.
2026-07-24T20:08:57+0530 info com.steipete.codexbar.claude-usage: allowKeychainPrompt=false expiresAtMs=1784900337504 expiresInSec=-3600 hasRefreshToken=true hasUserProfileScope=true isExpired=true owner=codexbar readStrategy=securityFramework respectPromptCooldown=true scopesCount=1 source=cacheKeychain [CodexBarCore] Claude OAuth credentials considered expired
2026-07-24T20:08:57+0530 info com.steipete.codexbar.claude-usage: [CodexBarCore] Access token expired, attempting auto-refresh
2026-07-24T20:08:57+0530 error com.steipete.codexbar.claude-usage: [CodexBarCore] Token refresh failed: Claude OAuth token refresh failed: Claude OAuth refresh temporarily suppressed due to prior failures; will retry automatically.
✔ Test "load with auto refresh expired codexbar owner uses direct refresh path" passed after 0.002 seconds.
◇ Test "load record legacy cache entry without owner defaults to claude CLI owner" started.
✔ Test "load record legacy cache entry without owner defaults to claude CLI owner" passed after 0.001 seconds.
◇ Test "has cached credentials returns false for expired unrefreshable codexbar cache entry" started.
✔ Test "has cached credentials returns false for expired unrefreshable codexbar cache entry" passed after 0.001 seconds.
◇ Test "has cached credentials returns true for expired refreshable cache entry" started.
✔ Test "has cached credentials returns true for expired refreshable cache entry" passed after 0.001 seconds.
◇ Test "has cached credentials returns true for expired claude CLI backed credentials file" started.
✔ Test "has cached credentials returns true for expired claude CLI backed credentials file" passed after 0.001 seconds.
◇ Test "syncs cache when claude keychain fingerprint changes and token differs" started.
2026-07-24T20:08:57+0530 info com.steipete.codexbar.claude-usage: [CodexBarCore] Claude keychain credentials changed; syncing OAuth cache
✔ Test "syncs cache when claude keychain fingerprint changes and token differs" passed after 0.001 seconds.
◇ Test "does not sync in background when cache valid and prompt mode only on user action" started.
✔ Test "does not sync in background when cache valid and prompt mode only on user action" passed after 0.001 seconds.
◇ Test "does not sync when claude keychain fingerprint unchanged" started.
✔ Test "does not sync when claude keychain fingerprint unchanged" passed after 0.001 seconds.
◇ Test "does not sync when keychain credentials expired but cache valid" started.
✔ Test "does not sync when keychain credentials expired but cache valid" passed after 0.001 seconds.
◇ Test "respects prompt cooldown gate when disabled prompting" started.
✔ Test "respects prompt cooldown gate when disabled prompting" passed after 0.001 seconds.
◇ Test "sync from claude keychain without prompt respects backoff in background" started.
✔ Test "sync from claude keychain without prompt respects backoff in background" passed after 0.001 seconds.
◇ Test "testing override snapshot forwards mutable Claude keychain override store across detached task" started.
✔ Test "testing override snapshot forwards mutable Claude keychain override store across detached task" passed after 0.001 seconds.
◇ Test "never mode repairs a missing credentials file from a valid no-UI Keychain read" started.
2026-07-24T20:08:57+0530 info com.steipete.codexbar.claude-usage: interaction=background [CodexBarCore] Claude keychain credentials loaded without prompt; syncing OAuth cache
✔ Test "never mode repairs a missing credentials file from a valid no-UI Keychain read" passed after 0.002 seconds.
◇ Test "never mode skips the experimental security CLI before no-UI Keychain repair" started.
2026-07-24T20:08:57+0530 info com.steipete.codexbar.claude-usage: interaction=background [CodexBarCore] Claude keychain credentials loaded without prompt; syncing OAuth cache
✔ Test "never mode skips the experimental security CLI before no-UI Keychain repair" passed after 0.003 seconds.
◇ Test "never mode still blocks an interactive Keychain read even with a valid item present" started.
✔ Test "never mode still blocks an interactive Keychain read even with a valid item present" passed after 0.001 seconds.
◇ Test "never mode without any Keychain item still fails closed" started.
✔ Test "never mode without any Keychain item still fails closed" passed after 0.001 seconds.
◇ Test "global Keychain disable blocks no-UI repair in never mode" started.
✔ Test "global Keychain disable blocks no-UI repair in never mode" passed after 0.001 seconds.
✔ Suite ClaudeOAuthCredentialsStoreTests passed after 0.064 seconds.
✔ Test run with 26 tests in 1 suite passed after 0.064 seconds.
Evidence: Prompt policy, live-proof gate, delegated refresh, KeychainNoUI suites
Another instance of SwiftPM (PID: 47469) is already running using '/Users/thescoho/.no-mistakes/worktrees/cf1616a29cfb/01KYA7N2C9PSSPVHYBQTQJTGHQ/.build', waiting until that process has finished execution...Building for debugging...
[0/14] Write swift-version--58304C5D6DBC2206.txt
Build complete! (0.58s)
Test Suite 'Selected tests' started at 2026-07-24 20:08:58.409.
Test Suite 'CodexBarPackageTests.xctest' started at 2026-07-24 20:08:58.410.
Test Suite 'CodexBarPackageTests.xctest' passed at 2026-07-24 20:08:58.410.
	 Executed 0 tests, with 0 failures (0 unexpected) in 0.000 (0.000) seconds
Test Suite 'Selected tests' passed at 2026-07-24 20:08:58.410.
	 Executed 0 tests, with 0 failures (0 unexpected) in 0.000 (0.001) seconds
◇ Test run started.
↳ Testing Library Version: 1902
↳ Target Platform: arm64e-apple-macos14.0
◇ Suite ClaudeOAuthCredentialsStorePromptPolicyTests started.
◇ Suite ClaudeOAuthDelegatedRefreshCoordinatorTests started.
◇ Suite ClaudeKeychainLiveProofTests started.
◇ Suite KeychainNoUIQueryTests started.
◇ Test "processes block every Security item operation before system access" started.
◇ Test "safety recognizes runner variants and explicit controls" started.
◇ Test "preflight query is strictly non interactive and does not request secret data" started.
◇ Test "preflight query executes without invalid UI policy" started.
◇ Test "apply sets non interactive context and UI fail policy" started.
◇ Test "keychain prompt notify preserves its void function signature" started.
◇ Test "live proof requires explicit access to real user state" started.
◇ Test "cooldown prevents repeated attempts" started.
✔ Test "safety recognizes runner variants and explicit controls" passed after 0.001 seconds.
✔ Test "keychain prompt notify preserves its void function signature" passed after 0.001 seconds.
✔ Test "live proof requires explicit access to real user state" passed after 0.001 seconds.
◇ Test "live background Auto skips the opaque Claude Keychain boundary" started.
◇ Test "safety does not inherit the application prompt preference" started.
✔ Test "live background Auto skips the opaque Claude Keychain boundary" passed after 0.001 seconds.
◇ Test "live explicit user auth probe reports Claude login" started.
✔ Test "live explicit user auth probe reports Claude login" passed after 0.001 seconds.
✔ Test "processes block every Security item operation before system access" passed after 0.002 seconds.
✔ Suite ClaudeKeychainLiveProofTests passed after 0.003 seconds.
✔ Test "preflight query is strictly non interactive and does not request secret data" passed after 0.010 seconds.
✔ Test "apply sets non interactive context and UI fail policy" passed after 0.011 seconds.
2026-07-24T20:08:59+0530 info com.steipete.codexbar.claude-usage: [CodexBarCore] Claude OAuth delegated refresh touch succeeded
✔ Test "cooldown prevents repeated attempts" passed after 0.014 seconds.
◇ Test "cli unavailable returns cli unavailable" started.
2026-07-24T20:08:59+0530 info com.steipete.codexbar.claude-usage: [CodexBarCore] Claude OAuth delegated refresh skipped: claude CLI unavailable
✔ Test "cli unavailable returns cli unavailable" passed after 0.001 seconds.
◇ Test "background refresh never launches delegated Claude CLI without Keychain opt in" started.
✔ Test "safety does not inherit the application prompt preference" passed after 0.015 seconds.
◇ Test "does not read claude keychain in background when prompt mode only on user action" started.
◇ Test case passing 2 arguments promptMode → .onlyOnUserAction, keychainAccessDisabled → false to "background refresh never launches delegated Claude CLI without Keychain opt in" started.
2026-07-24T20:08:59+0530 info com.steipete.codexbar.claude-usage: [CodexBarCore] Claude OAuth delegated refresh skipped by Keychain prompt policy
◇ Test case passing 2 arguments promptMode → .never, keychainAccessDisabled → false to "background refresh never launches delegated Claude CLI without Keychain opt in" started.
2026-07-24T20:08:59+0530 info com.steipete.codexbar.claude-usage: [CodexBarCore] Claude OAuth delegated refresh skipped by Keychain prompt policy
◇ Test case passing 2 arguments promptMode → .always, keychainAccessDisabled → true to "background refresh never launches delegated Claude CLI without Keychain opt in" started.
2026-07-24T20:08:59+0530 info com.steipete.codexbar.claude-usage: [CodexBarCore] Claude OAuth delegated refresh skipped by Keychain prompt policy
✔ Test "background refresh never launches delegated Claude CLI without Keychain opt in" with 3 test cases passed after 0.004 seconds.
◇ Test "opaque delegated CLI honors stored prompt mode when read strategy effective mode differs" started.
2026-07-24T20:08:59+0530 info com.steipete.codexbar.claude-usage: [CodexBarCore] Claude OAuth delegated refresh skipped by Keychain prompt policy
✔ Test "does not read claude keychain in background when prompt mode only on user action" passed after 0.006 seconds.
◇ Test "can read claude keychain on user action when prompt mode only on user action" started.
2026-07-24T20:08:59+0530 info com.steipete.codexbar.claude-usage: interaction=user [CodexBarCore] Claude keychain credentials loaded without prompt; syncing OAuth cache
✔ Test "can read claude keychain on user action when prompt mode only on user action" passed after 0.003 seconds.
◇ Test "user initiated claude keychain reads respect pre alert acknowledgement cooldown" started.
✔ Test "preflight query executes without invalid UI policy" passed after 0.026 seconds.
✔ Suite KeychainNoUIQueryTests passed after 0.027 seconds.
✔ Test "user initiated claude keychain reads respect pre alert acknowledgement cooldown" passed after 0.001 seconds.
◇ Test "shows pre alert when claude keychain likely requires interaction" started.
✔ Test "shows pre alert when claude keychain likely requires interaction" passed after 0.001 seconds.
◇ Test "shows pre alert when claude keychain preflight fails" started.
✔ Test "shows pre alert when claude keychain preflight fails" passed after 0.001 seconds.
◇ Test "experimental reader skips pre alert when security CLI read succeeds" started.
✔ Test "experimental reader skips pre alert when security CLI read succeeds" passed after 0.001 seconds.
◇ Test "experimental reader shows pre alert when security CLI fails and fallback needs interaction" started.
2026-07-24T20:08:59+0530 warning com.steipete.codexbar.claude-usage: callerInteraction=user error_type=SecurityCLIReadError reader=securityCLI reason=timedOut [CodexBarCore] Claude keychain security CLI read failed; falling back
✔ Test "experimental reader shows pre alert when security CLI fails and fallback needs interaction" passed after 0.001 seconds.
◇ Test "experimental reader does not fallback in background when stored mode only on user action" started.
2026-07-24T20:08:59+0530 warning com.steipete.codexbar.claude-usage: callerInteraction=background error_type=SecurityCLIReadError reader=securityCLI reason=timedOut [CodexBarCore] Claude keychain security CLI read failed; falling back
✔ Test "experimental reader does not fallback in background when stored mode only on user action" passed after 0.001 seconds.
◇ Test "experimental reader does not fallback when stored mode never" started.
✔ Test "experimental reader does not fallback when stored mode never" passed after 0.001 seconds.
◇ Test "experimental reader non interactive fallback blocked in background when stored mode only on user action" started.
2026-07-24T20:08:59+0530 warning com.steipete.codexbar.claude-usage: callerInteraction=background error_type=SecurityCLIReadError reader=securityCLI reason=timedOut [CodexBarCore] Claude keychain security CLI read failed; falling back
2026-07-24T20:08:59+0530 warning com.steipete.codexbar.claude-usage: callerInteraction=background error_type=SecurityCLIReadError reader=securityCLI reason=timedOut [CodexBarCore] Claude keychain security CLI read failed; falling back
✔ Test "experimental reader non interactive fallback blocked in background when stored mode only on user action" passed after 0.001 seconds.
◇ Test "experimental reader allows fallback in background when stored mode always" started.
2026-07-24T20:08:59+0530 warning com.steipete.codexbar.claude-usage: callerInteraction=background error_type=SecurityCLIReadError reader=securityCLI reason=timedOut [CodexBarCore] Claude keychain security CLI read failed; falling back
✔ Test "experimental reader allows fallback in background when stored mode always" passed after 0.001 seconds.
✔ Suite ClaudeOAuthCredentialsStorePromptPolicyTests passed after 0.036 seconds.
2026-07-24T20:09:01+0530 warning com.steipete.codexbar.claude-usage: [CodexBarCore] Claude OAuth delegated refresh touch did not update Claude keychain
✔ Test "opaque delegated CLI honors stored prompt mode when read strategy effective mode differs" passed after 1.790 seconds.
◇ Test "successful auth touch reports attempted succeeded" started.
2026-07-24T20:09:01+0530 info com.steipete.codexbar.claude-usage: [CodexBarCore] Claude OAuth delegated refresh touch succeeded
✔ Test "successful auth touch reports attempted succeeded" passed after 0.001 seconds.
◇ Test "failed auth touch reports attempted failed" started.
2026-07-24T20:09:02+0530 warning com.steipete.codexbar.claude-usage: errorType=StubError [CodexBarCore] Claude OAuth delegated refresh touch failed
✔ Test "failed auth touch reports attempted failed" passed after 1.856 seconds.
◇ Test "environment CLI override avoids CLI unavailable" started.
2026-07-24T20:09:04+0530 warning com.steipete.codexbar.claude-usage: errorType=StubError [CodexBarCore] Claude OAuth delegated refresh touch failed
✔ Test "environment CLI override avoids CLI unavailable" passed after 1.855 seconds.
◇ Test "concurrent attempts join in flight" started.
2026-07-24T20:09:04+0530 info com.steipete.codexbar.claude-usage: [CodexBarCore] Claude OAuth delegated refresh touch succeeded
✔ Test "concurrent attempts join in flight" passed after 0.070 seconds.
◇ Test "user action retries after joining failed background attempt" started.
2026-07-24T20:09:06+0530 warning com.steipete.codexbar.claude-usage: errorType=StubError [CodexBarCore] Claude OAuth delegated refresh touch failed
2026-07-24T20:09:06+0530 info com.steipete.codexbar.claude-usage: [CodexBarCore] Claude OAuth delegated refresh touch succeeded
✔ Test "user action retries after joining failed background attempt" passed after 1.894 seconds.
◇ Test "experimental strategy does not use security framework fingerprint observation" started.
2026-07-24T20:09:08+0530 warning com.steipete.codexbar.claude-usage: [CodexBarCore] Claude OAuth delegated refresh touch did not update Claude keychain
✔ Test "experimental strategy does not use security framework fingerprint observation" passed after 1.875 seconds.
◇ Test "experimental strategy observes security CLI change after touch" started.
2026-07-24T20:09:08+0530 info com.steipete.codexbar.claude-usage: [CodexBarCore] Claude OAuth delegated refresh touch succeeded
✔ Test "experimental strategy observes security CLI change after touch" passed after 0.001 seconds.
◇ Test "experimental strategy missing baseline does not auto succeed when later read succeeds" started.
2026-07-24T20:09:10+0530 warning com.steipete.codexbar.claude-usage: [CodexBarCore] Claude OAuth delegated refresh touch did not update Claude keychain
✔ Test "experimental strategy missing baseline does not auto succeed when later read succeeds" passed after 1.876 seconds.
◇ Test "experimental strategy observation skips security CLI when global keychain disabled" started.
2026-07-24T20:09:10+0530 info com.steipete.codexbar.claude-usage: [CodexBarCore] Claude OAuth delegated refresh skipped by Keychain prompt policy
✔ Test "experimental strategy observation skips security CLI when global keychain disabled" passed after 0.001 seconds.
◇ Test "experimental strategy blocks background mcp O auth but lets user action retry" started.
2026-07-24T20:09:10+0530 warning com.steipete.codexbar.claude-usage: callerInteraction=background duration_ms=0.00 payload_bytes=71 reader=securityCLI status=0 stderr_length=0 [CodexBarCore] Claude keychain security CLI output is MCP OAuth only; falling back
2026-07-24T20:09:10+0530 warning com.steipete.codexbar.claude-usage: readStrategy=securityCLIExperimental [CodexBarCore] Claude OAuth delegated refresh skipped: Claude keychain has MCP OAuth state only
2026-07-24T20:09:10+0530 warning com.steipete.codexbar.claude-usage: callerInteraction=background duration_ms=0.00 payload_bytes=71 reader=securityCLI status=0 stderr_length=0 [CodexBarCore] Claude keychain security CLI output is MCP OAuth only; falling back
2026-07-24T20:09:10+0530 info com.steipete.codexbar.claude-usage: [CodexBarCore] Claude OAuth delegated refresh touch succeeded
✔ Test "experimental strategy blocks background mcp O auth but lets user action retry" passed after 0.002 seconds.
✔ Suite ClaudeOAuthDelegatedRefreshCoordinatorTests passed after 11.247 seconds.
✔ Test run with 35 tests in 4 suites passed after 11.248 seconds.
Evidence: Temporary keychain cache + isolated security CLI suites
Building for debugging...
[0/14] Write swift-version--58304C5D6DBC2206.txt
Build complete! (0.53s)
Test Suite 'Selected tests' started at 2026-07-24 20:09:38.508.
Test Suite 'CodexBarPackageTests.xctest' started at 2026-07-24 20:09:38.509.
Test Suite 'CodexBarPackageTests.xctest' passed at 2026-07-24 20:09:38.509.
	 Executed 0 tests, with 0 failures (0 unexpected) in 0.000 (0.000) seconds
Test Suite 'Selected tests' passed at 2026-07-24 20:09:38.509.
	 Executed 0 tests, with 0 failures (0 unexpected) in 0.000 (0.001) seconds
◇ Test run started.
↳ Testing Library Version: 1902
↳ Target Platform: arm64e-apple-macos14.0
◇ Suite ClaudeOAuthCredentialsStoreTemporaryKeychainCacheTests started.
◇ Suite ClaudeOAuthCredentialsStoreIsolatedSecurityCLITests started.
◇ Test "credentials file invalidation preserves keychain cache when temporarily unavailable" started.
◇ Test "safety blocks security CLI access to the login keychain" started.
✔ Test "safety blocks security CLI access to the login keychain" passed after 0.001 seconds.
◇ Test "isolated security CLI keychain requires global keychain disable" started.
✔ Test "isolated security CLI keychain requires global keychain disable" passed after 0.001 seconds.
◇ Test "isolated security CLI keychain remains readable while other keychain access is disabled" started.
2026-07-24T20:09:39+0530 warning com.steipete.codexbar.claude-usage: callerInteraction=background duration_ms=0.00 payload_bytes=56 reader=securityCLI status=0 stderr_length=0 [CodexBarCore] Claude keychain security CLI output is MCP OAuth only; falling back
2026-07-24T20:09:39+0530 info com.steipete.codexbar.claude-usage: [CodexBarCore] Claude OAuth credentials file changed; invalidating cache
✔ Test "isolated security CLI keychain remains readable while other keychain access is disabled" passed after 0.005 seconds.
◇ Test "never prompt mode still detects MCP-only payload via experimental security CLI reader" started.
✔ Test "never prompt mode still detects MCP-only payload via experimental security CLI reader" passed after 0.001 seconds.
✔ Suite ClaudeOAuthCredentialsStoreIsolatedSecurityCLITests passed after 0.006 seconds.
2026-07-24T20:09:39+0530 info com.steipete.codexbar.claude-usage: [CodexBarCore] Claude OAuth credentials file changed; invalidating cache
2026-07-24T20:09:39+0530 info com.steipete.codexbar.keychain-cache: [CodexBarCore] Keychain cache temporarily locked (oauth.claude), will retry on next access
2026-07-24T20:09:39+0530 info com.steipete.codexbar.claude-usage: [CodexBarCore] Claude OAuth credentials file changed; invalidating cache
✔ Test "credentials file invalidation preserves keychain cache when temporarily unavailable" passed after 0.010 seconds.
◇ Test "temporary keychain cache unavailability does not overwrite cache from credentials file fallback" started.
2026-07-24T20:09:39+0530 info com.steipete.codexbar.claude-usage: [CodexBarCore] Claude OAuth credentials file changed; invalidating cache
2026-07-24T20:09:39+0530 info com.steipete.codexbar.keychain-cache: [CodexBarCore] Keychain cache temporarily locked (oauth.claude), will retry on next access
2026-07-24T20:09:39+0530 info com.steipete.codexbar.keychain-cache: [CodexBarCore] Keychain cache temporarily locked (oauth.claude), will retry on next access
✔ Test "temporary keychain cache unavailability does not overwrite cache from credentials file fallback" passed after 0.001 seconds.
◇ Test "has cached credentials treats temporary keychain cache unavailability as present" started.
2026-07-24T20:09:39+0530 info com.steipete.codexbar.keychain-cache: [CodexBarCore] Keychain cache temporarily locked (oauth.claude), will retry on next access
✔ Test "has cached credentials treats temporary keychain cache unavailability as present" passed after 0.001 seconds.
◇ Test "invalid keychain cache is cleared by load" started.
✔ Test "invalid keychain cache is cleared by load" passed after 0.001 seconds.
✔ Suite ClaudeOAuthCredentialsStoreTemporaryKeychainCacheTests passed after 0.013 seconds.
✔ Test run with 8 tests in 2 suites passed after 0.014 seconds.
Evidence: Live-proof unit gate (empty env disallows real keychain access)
[0/1] Planning build
Building for debugging...
[0/14] Write swift-version--58304C5D6DBC2206.txt
Build complete! (6.18s)
Test Suite 'Selected tests' started at 2026-07-24 20:10:16.179.
Test Suite 'CodexBarPackageTests.xctest' started at 2026-07-24 20:10:16.180.
Test Suite 'CodexBarPackageTests.xctest' passed at 2026-07-24 20:10:16.180.
	 Executed 0 tests, with 0 failures (0 unexpected) in 0.000 (0.000) seconds
Test Suite 'Selected tests' passed at 2026-07-24 20:10:16.180.
	 Executed 0 tests, with 0 failures (0 unexpected) in 0.000 (0.001) seconds
◇ Test run started.
↳ Testing Library Version: 1902
↳ Target Platform: arm64e-apple-macos14.0
◇ Suite ClaudeKeychainLiveProofTests started.
◇ Test "live proof requires explicit access to real user state" started.
✔ Test "live proof requires explicit access to real user state" passed after 0.001 seconds.
✔ Suite ClaudeKeychainLiveProofTests passed after 0.001 seconds.
✔ Test run with 1 test in 1 suite passed after 0.001 seconds.
Evidence: Acceptance criteria transcript
CodexBar Claude keychain test isolation — local validation transcript
HEAD: b6f157cccb22b7c0dab79b6d9c93591f15262b32

1) Prompt preference isolation: PASS (safety does not inherit the application prompt preference)
2) Credentials file isolation: PASS (safety isolates the default Claude credentials file)
3) Pending cache-clear isolation: PASS (suite + across isolation scopes)
4) Detached delegated-refresh prompt policy: PASS (currentTaskOverrideForTesting == .always in detached path)
5) Live proof fail-closed without CODEXBAR_ALLOW_TEST_KEYCHAIN_ACCESS=1: PASS
   LIVE=1 ALLOW unset -> Issue: Live proof requires CODEXBAR_ALLOW_TEST_KEYCHAIN_ACCESS=1
6) CHANGELOG.md and SpendDashboard not in patch: confirmed
Result: isolation intent satisfied under targeted local validation
Evidence: Diff scope (no CHANGELOG / no SpendDashboard)

Source: Diff scope (no CHANGELOG / no SpendDashboard) (local file: /var/folders/nc/j5wdfhws2q56jzdcj_jkdvww0000gn/T/no-mistakes-evidence/01KYA7N2C9PSSPVHYBQTQJTGHQ/intent-scope.log)

CHANGELOG.md in diff: no
SpendDashboard in diff: no
- Evidence: Extracted key proof lines (local file: /var/folders/nc/j5wdfhws2q56jzdcj_jkdvww0000gn/T/no-mistakes-evidence/01KYA7N2C9PSSPVHYBQTQJTGHQ/key-proof-lines.txt)

Pipeline

Updates from git push no-mistakes

✅ **intent** - passed

✅ No issues found.

✅ **Rebase** - passed

✅ No issues found.

🔧 **Review** - 1 issue found → auto-fixed ✅
  • ⚠️ Sources/CodexBarCore/Providers/Claude/ClaudeOAuth/ClaudeOAuthCredentials.swift:134 - Intent requires the standard suite must never "share pending cache-clear state across tests", but the auto-isolation sink is a single process-static PendingCacheClearMemoryStore (isolatedTestPendingCacheClearStore, returned from currentPendingCodexBarOAuthKeychainCacheClearStore when no TaskLocal override is set). That still lets never-mode invalidateCache/markPending and _resetCredentialsFileTrackingForTesting (which now clears pending whenever isolation is active) couple concurrent/non-overridden tests. App-suite writes are correctly avoided; confirm whether process-wide memory sharing is acceptable, or whether pending should be TaskLocal/per-test by default under isolation.

🔧 Fix: Isolate pending cache-clear state per test scope
✅ Re-checked - no issues remain.

✅ **Test** - passed

✅ No issues found.

  • swift test --filter 'safety ' (prompt preference, credentials-file, pending-cache-clear, and related safety gates)
  • swift test --filter ClaudeOAuthCredentialsStoreTests
  • swift test --filter ClaudeOAuthCredentialsStorePromptPolicyTests --filter ClaudeKeychainLiveProofTests --filter ClaudeOAuthDelegatedRefreshCoordinatorTests --filter KeychainNoUIQueryTests
  • swift test --filter ClaudeOAuthCredentialsStoreTemporaryKeychainCacheTests --filter ClaudeOAuthCredentialsStoreIsolatedSecurityCLITests
  • LIVE_CLAUDE_KEYCHAIN_PROOF=1 with CODEXBAR_ALLOW_TEST_KEYCHAIN_ACCESS unset → swift test --filter 'live background Auto skips' (fail-closed live proof)
  • swift test --filter 'live proof requires explicit access'
  • git diff --name-only base..target for CHANGELOG.md / SpendDashboard scope check
✅ **Document** - passed

✅ No issues found.

✅ **Lint** - passed

✅ No issues found.

✅ **Push** - passed

✅ No issues found.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c5b618b722

ℹ️ 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".

@ss251 ss251 changed the title test: isolate Claude OAuth keychain state under unit tests test(CodexBarCore): isolate Claude keychain state under unit tests Jul 24, 2026
@clawsweeper

clawsweeper Bot commented Jul 24, 2026

Copy link
Copy Markdown

ClawSweeper status: review started.

I am starting a fresh review of this pull request: test(CodexBarCore): isolate Claude keychain state under unit tests This is item 1/1 in the current shard. Shard 0/1.

This placeholder means the worker is alive and reading the current context. I will edit this same comment with the actual review when the claws are done clicking.

Crustacean status: shell secured, claws on keyboard, evidence pebbles being sorted.

@ss251

ss251 commented Jul 24, 2026

Copy link
Copy Markdown
Contributor Author

Review follow-up at b6f157cccb22b7c0dab79b6d9c93591f15262b32:

  • addressed and resolved the P2 live-proof thread; real prompt policy is read only when CODEXBAR_ALLOW_TEST_KEYCHAIN_ACCESS=1 is explicitly present;
  • added deterministic coverage for that opt-in gate;
  • cross-provider re-review found and fixed one additional gap: pending cache-clear isolation is now per test scope rather than one process-shared memory sink;
  • removed the temporary SpendDashboard CI changes because Stabilize dashboard fixture clock #2390 already owns that unrelated stabilization.

Focused follow-up validation passed with no remaining review findings. GitHub CI is rerunning on the scoped head; if macOS shard 0 reproduces the known SpendDashboard date/defaults failure before #2390 lands, that is an external base failure rather than a Claude isolation regression.

@ss251

ss251 commented Jul 24, 2026

Copy link
Copy Markdown
Contributor Author

Final scoped-head CI result for b6f157cccb22b7c0dab79b6d9c93591f15262b32:

  • lint, changes, GitGuardian, both Linux CLI builds, musl build, and macOS shard 1: passed;
  • macOS shard 0: the same 10 SpendDashboardControllerTests date/defaults failures already isolated and green in Stabilize dashboard fixture clock #2390;
  • lint-build-test failed only because it aggregates that macOS result.

No Claude OAuth/keychain test failed. I intentionally removed the temporary duplicate SpendDashboard patch from this PR, so the scoped diff and the resolved P2 review fix remain clean. Once #2390 lands and this branch is rebased by the normal repository flow, the external shard failure should clear.

@steipete
steipete merged commit 9622058 into steipete:main Jul 28, 2026
9 checks passed
@steipete

Copy link
Copy Markdown
Owner

Merged after a fresh hostile review of exact head a6d360fbf0ac7ee0a25c6b578416985814d41633 found no blocking correctness issues.

Verification:

  • CI run 30392366879 passed lint, both Linux builds, musl, both macOS test shards, GitGuardian, and the aggregate gate.
  • Auth-free focused validation passed for the Claude credential-store, prompt-policy, delegated-refresh, isolated-security-CLI, temporary-cache, and no-UI suites. The deterministic live-proof opt-in gate also passed; no live Keychain/provider probe was run.
  • The repair routes both implicit defaults fixtures through UUID-scoped test suites, so abrupt test termination cannot alter the real CodexBar defaults domain.

Thanks @ss251 for the focused test-isolation layer and for preserving the production behavior boundary.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants