diff --git a/Sources/CodexBarCore/BrowserCookieAccessGate.swift b/Sources/CodexBarCore/BrowserCookieAccessGate.swift index 436d316565..569cf74fba 100644 --- a/Sources/CodexBarCore/BrowserCookieAccessGate.swift +++ b/Sources/CodexBarCore/BrowserCookieAccessGate.swift @@ -82,6 +82,12 @@ public enum BrowserCookieAccessGate { public static func shouldAttempt(_ browser: Browser, now: Date = Date()) -> Bool { guard browser.usesKeychainForCookieDecryption else { return true } guard !KeychainAccessGate.isDisabled else { return false } + guard ProviderInteractionContext.current == .userInitiated else { + self.log.info( + "Skipping background Chromium cookie import to avoid a Keychain prompt", + metadata: ["browser": browser.displayName]) + return false + } if self.deniedBrowsersForTesting?.contains(browser) == true { return self.isExplicitRetryAllowed(for: browser) } diff --git a/Tests/CodexBarTests/BrowserDetectionTests.swift b/Tests/CodexBarTests/BrowserDetectionTests.swift index ded7bb35c2..742b4f1d54 100644 --- a/Tests/CodexBarTests/BrowserDetectionTests.swift +++ b/Tests/CodexBarTests/BrowserDetectionTests.swift @@ -130,7 +130,9 @@ struct BrowserDetectionTests { let client = BrowserCookieClient(configuration: .init(homeDirectories: [temp])) let stores = try KeychainAccessGate.withTaskOverrideForTesting(false) { try KeychainAccessPreflight.withCheckGenericPasswordOverrideForTesting { _, _ in .allowed } operation: { - try client.codexBarStores(for: .chrome) + try ProviderInteractionContext.$current.withValue(.userInitiated) { + try client.codexBarStores(for: .chrome) + } } } #expect(stores.count == 1) @@ -221,7 +223,7 @@ struct BrowserDetectionTests { var preflightCount = 0 KeychainAccessGate.withTaskOverrideForTesting(false) { - ProviderInteractionContext.$current.withValue(.background) { + ProviderInteractionContext.$current.withValue(.userInitiated) { KeychainAccessPreflight.withCheckGenericPasswordOverrideForTesting { _, _ in preflightCount += 1 return .interactionRequired @@ -247,7 +249,7 @@ struct BrowserDetectionTests { } @Test - func `background cookie import allows authorized chromium keychain sources`() { + func `background cookie import skips chromium before keychain preflight`() { BrowserCookieAccessGate.resetForTesting() defer { BrowserCookieAccessGate.resetForTesting() } @@ -259,17 +261,17 @@ struct BrowserDetectionTests { return .allowed } operation: { ProviderInteractionContext.$current.withValue(.background) { - #expect(BrowserCookieAccessGate.shouldAttempt(.chrome) == true) + #expect(BrowserCookieAccessGate.shouldAttempt(.chrome) == false) #expect(BrowserCookieAccessGate.shouldAttempt(.safari) == true) } } } - #expect(preflightCount == 1) + #expect(preflightCount == 0) } @Test - func `background cookie import suppresses chromium keychain sources requiring interaction`() { + func `background cookie import skips chromium without probing keychain interaction`() { BrowserCookieAccessGate.resetForTesting() defer { BrowserCookieAccessGate.resetForTesting() } @@ -287,7 +289,7 @@ struct BrowserDetectionTests { } } - #expect(preflightCount == 1) + #expect(preflightCount == 0) } @Test @@ -320,7 +322,7 @@ struct BrowserDetectionTests { BrowserCookieAccessGate.recordAllowed(for: .arc) } } - ProviderInteractionContext.$current.withValue(.background) { + ProviderInteractionContext.$current.withValue(.userInitiated) { #expect(BrowserCookieAccessGate.shouldAttempt(.chrome, now: start.addingTimeInterval(3)) == true) } } @@ -367,7 +369,9 @@ struct BrowserDetectionTests { queriedLabels.append(label) return .notFound } operation: { - #expect(BrowserCookieAccessGate.shouldAttempt(.chrome) == true) + ProviderInteractionContext.$current.withValue(.userInitiated) { + #expect(BrowserCookieAccessGate.shouldAttempt(.chrome) == true) + } } } @@ -390,7 +394,9 @@ struct BrowserDetectionTests { queriedLabels.append(label) return .notFound } operation: { - #expect(BrowserCookieAccessGate.shouldAttempt(.dia) == true) + ProviderInteractionContext.$current.withValue(.userInitiated) { + #expect(BrowserCookieAccessGate.shouldAttempt(.dia) == true) + } } } @@ -419,7 +425,7 @@ struct BrowserDetectionTests { if label == firstDiaLabel { return .interactionRequired } return .notFound } operation: { - ProviderInteractionContext.$current.withValue(.background) { + ProviderInteractionContext.$current.withValue(.userInitiated) { #expect(BrowserCookieAccessGate.shouldAttempt(.chrome, now: start) == true) #expect(BrowserCookieAccessGate.shouldAttempt(.dia, now: start.addingTimeInterval(1)) == false) #expect(BrowserCookieAccessGate.shouldAttempt(.chrome, now: start.addingTimeInterval(60)) == false)