-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Claude: consented direct keychain read + CLI usage fallback (#2634) #2675
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 1 commit
Commits
Show all changes
16 commits
Select commit
Hold shift + click to select a range
ec037be
fix: restore Claude usage on 0.47+ via consented keychain read and CL…
ff109fc
Merge remote-tracking branch 'origin/main' into fix/2634-claude-conse…
steipete 8ba7af5
fix: invalidate CodexBar's Claude credential caches when direct-read …
steipete bdea822
Scope Claude OAuth terminal refresh block to the failed token lineage
avenoxai 89b7f8f
Stop hijacking Claude CLI refresh chains when keychain evidence is un…
avenoxai 3ce97e6
Keep unprovable chains CLI-owned; back off superseded lineages
avenoxai 3a979ec
chore: merge origin/main into PR #2745
steipete 2ef2fb7
chore: merge origin/main into PR #2675
steipete 9caaf31
Merge branch 'fix/claude-oauth-refresh-chain-ownership' into fix/2634…
steipete ceb458d
fix: compose Claude ownership with keychain consent
steipete d0f400e
chore: merge current main into PR #2675
steipete a7b9087
Merge branch 'main' into fix/2634-claude-consented-read
steipete 22c7fc8
Merge branch 'main' into fix/2634-claude-consented-read
steipete 36f0cb1
Merge remote-tracking branch 'origin/main' into fix/2634-claude-conse…
steipete 955e739
Merge remote-tracking branch 'origin/main' into fix/2634-claude-conse…
steipete 59d59e4
Merge remote-tracking branch 'origin/main' into fix/2634-claude-conse…
steipete File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
58 changes: 58 additions & 0 deletions
58
Sources/CodexBarCore/Providers/Claude/ClaudeOAuth/ClaudeOAuthDirectKeychainReadConsent.swift
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,58 @@ | ||
| import Foundation | ||
|
|
||
| /// Explicit, durable user consent for reading Claude Code's own Keychain item (`Claude Code-credentials`). | ||
| /// | ||
| /// CodexBar 0.47.0 stopped reading that foreign item entirely because Claude Code rewrites its ACL on | ||
| /// every token refresh, which makes any granted permission temporary and causes recurring macOS password | ||
| /// dialogs (#2380). That hard stop also removed every recovery path on Claude Code 2.1.x, which stores | ||
| /// credentials Keychain-only (#2634). This consent restores the pre-0.47 direct read as an informed opt-in: | ||
| /// default OFF, never enabled silently on upgrade, and revocable at any time from Claude provider settings. | ||
| /// | ||
| /// The stored flag feeds `ClaudeOAuthCredentialsStore.keychainAccessAllowed` — the single choke point for | ||
| /// the direct read, the pre-emptive freshness sync, and delegated-refresh success verification — so all | ||
| /// three paths open and close together. | ||
| public enum ClaudeOAuthDirectKeychainReadConsent { | ||
| /// Written by the app's SettingsStore; read here through the shared application defaults domain so the | ||
| /// CLI and helper processes resolve the same consent the app persisted. | ||
| public static let userDefaultsKey = "claudeOAuthDirectKeychainReadAllowed" | ||
|
|
||
| #if DEBUG | ||
| @TaskLocal private static var taskOverride: Bool? | ||
| #endif | ||
|
|
||
| public static func isGranted(userDefaults: UserDefaults? = nil) -> Bool { | ||
| #if DEBUG | ||
| if let taskOverride { | ||
| return taskOverride | ||
| } | ||
| // Unit tests must not inherit the developer's persisted consent. Tests that exercise consent use a | ||
| // task or UserDefaults override explicitly. | ||
| if userDefaults == nil, KeychainTestSafety.shouldIsolateUserStateUnderTests() { | ||
| return false | ||
| } | ||
| #endif | ||
| let defaults = userDefaults ?? ClaudeOAuthKeychainPromptPreference.applicationUserDefaults | ||
| return defaults.bool(forKey: self.userDefaultsKey) | ||
| } | ||
|
|
||
| #if DEBUG | ||
| public static func withTaskOverrideForTesting<T>( | ||
| _ granted: Bool?, | ||
| operation: () throws -> T) rethrows -> T | ||
| { | ||
| try self.$taskOverride.withValue(granted) { | ||
| try operation() | ||
| } | ||
| } | ||
|
|
||
| public static func withTaskOverrideForTesting<T>( | ||
| _ granted: Bool?, | ||
| isolation _: isolated (any Actor)? = #isolation, | ||
| operation: () async throws -> T) async rethrows -> T | ||
| { | ||
| try await self.$taskOverride.withValue(granted) { | ||
| try await operation() | ||
| } | ||
| } | ||
| #endif | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When a user turns this setting back off after a successful OAuth read, the setter only flips the defaults flag.
ClaudeOAuthCredentialsStore.loadRecordstill returns valid in-memory or CodexBar keychain-cache entries before thekeychainAccessAllowed-guarded freshness sync, so Claude OAuth usage can continue using the copied Claude Code token until the cache expires instead of immediately falling back to the CLI. Clear/invalidate the Claude OAuth credential cache whennewValueisfalse.Useful? React with 👍 / 👎.