Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions Sources/CodexBarCore/BrowserCookieAccessGate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down
28 changes: 17 additions & 11 deletions Tests/CodexBarTests/BrowserDetectionTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand All @@ -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() }

Expand All @@ -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() }

Expand All @@ -287,7 +289,7 @@ struct BrowserDetectionTests {
}
}

#expect(preflightCount == 1)
#expect(preflightCount == 0)
}

@Test
Expand Down Expand Up @@ -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)
}
}
Expand Down Expand Up @@ -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)
}
}
}

Expand All @@ -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)
}
}
}

Expand Down Expand Up @@ -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)
Expand Down