3.4 KiB
Summary
Fixes the background browser-launch regression in https://github.com/steipete/CodexBar/issues/1844: when Claude Code stores only MCP OAuth state in Claude Code-credentials (no claudeAiOauth), CodexBar no longer runs background delegated claude /status refresh—which can launch the default browser via /usr/bin/open.
Scope: fail-closed safety guard for both keychain readers. Discovery of Claude Code 2.1.x's primary OAuth storage location remains tracked by https://github.com/steipete/CodexBar/issues/1823.
Problem
On Claude Code 2.1.x, the Claude Code-credentials keychain item may contain only mcpOAuth. CodexBar then fails to parse Claude OAuth credentials, treats the session as expired, and may periodically attempt delegated CLI refresh. That path can open the user's default browser from the background.
Contributing issues on main:
- Delegated refresh used
ClaudeOAuthKeychainPromptPreference.current(), which becomes.alwayswhen the experimental security CLI reader is active—soonlyOnUserActiondid not suppress background repair. - Delegated refresh could still invoke
claude /statuseven when the keychain shape could not succeed.
Changes
- Honor stored keychain prompt mode for delegated refresh across all keychain read strategies (including
securityCLIExperimental). Background refresh withonlyOnUserActionfails closed with existing user-action guidance instead of callingclaude /status. - Detect MCP-only keychain payloads through both keychain readers via
ClaudeOAuthCredentialsError.mcpOAuthOnlyKeychain, skip delegated CLI touch, and fail fast during expired Claude CLI credential load. - Split security CLI read paths:
readRawClaudeKeychainPayloadViaSecurityCLIIfEnabledvs parsed credential load. - Isolated verification helper: the production
/usr/bin/securityreader can target a disposable keychain only while all general keychain access is disabled.Scripts/verify_1844_live.shcombines that keychain with disposableHOME,CFFIXED_USER_HOME, credentials, config, and a syntheticclaudefixture that distinguishes benign CLI discovery from/statustouch.
Tests
- Updated: background delegated-refresh suppression with experimental reader
- Added: MCP-only parse/shape detection
- Added: coordinator test—background MCP-only guard plus explicit Refresh recovery
- Added: store test—expired CLI owner fails closed in background and delegates on explicit Refresh
- Added: fail-closed tests for the isolated-keychain argument seam
- Added: standard Security.framework reader regression—background fails closed while explicit Refresh delegates
Verification
- Focused macOS integration tests (2026-07-03) — details in
docs/verify-1844-proof.md - Release-built
CodexBar.appand packagedCodexBarCLIisolated live proof - Real Claude-tab Refresh click against the isolated built app
- Final
make check, 45-shardmake test, and autoreview on the local port
Commands
make check
swift test --filter ClaudeOAuthTests
swift test --filter ClaudeUsageTests
swift test --filter ClaudeOAuthDelegatedRefreshCoordinatorTests
swift test --filter 'expired claude CLI owner blocks background'
swift test --filter ClaudeOAuthCredentialsStoreMCPOnlyGuardTests
./Scripts/verify_1844_live.sh
Fixes https://github.com/steipete/CodexBar/issues/1844. Primary OAuth storage discovery remains tracked by https://github.com/steipete/CodexBar/issues/1823.