# How KeychainAccessGate Prevents macOS Keychain Prompts in CodexBar

> Learn how CodexBar's KeychainAccessGate prevents macOS keychain prompts by performing safety checks before any dialog appears. Streamline your workflow with enhanced security and control.

- Repository: [Peter Steinberger/CodexBar](https://github.com/steipete/CodexBar)
- Tags: internals
- Published: 2026-07-07

---

**CodexBar uses a centralized `KeychainAccessGate` class that evaluates multiple safety checks—from environment variables to task-local overrides—to block keychain access before macOS can display a permission dialog.**

The steipete/CodexBar repository implements a robust defense mechanism against intrusive macOS security dialogs. At the center of this system sits `KeychainAccessGate`, a Swift class defined in [`Sources/CodexBarCore/KeychainAccessGate.swift`](https://github.com/steipete/CodexBar/blob/main/Sources/CodexBarCore/KeychainAccessGate.swift) that intercepts all keychain access attempts to ensure that the "Keychain wants to access..." prompt never appears at inappropriate times.

## The Five-Layer Safety Architecture

The gate implements a hierarchical evaluation strategy that checks multiple conditions before allowing any keychain operation to proceed.

### Task-Local Overrides for Testing

Unit tests can inject temporary values without touching the real keychain. The `withTaskOverrideForTesting` method allows developers to simulate a closed gate for specific code blocks.

When wrapped in this override, any call to `KeychainAccessGate.isDisabled` returns `true` for the duration of the task, ensuring that test suites run in isolation from system keychain services.

### Environment Variable Lockdown

For CI/CD pipelines and automation, setting `CODEXBAR_DISABLE_KEYCHAIN_ACCESS=1` forces the gate closed for the entire process lifetime. This check is evaluated early in [`Sources/CodexBarCore/KeychainAccessGate.swift`](https://github.com/steipete/CodexBar/blob/main/Sources/CodexBarCore/KeychainAccessGate.swift) at line 39, providing a persistent guard that requires no code changes.

### Debug-Only Test Safety

When running under test conditions, the gate automatically invokes `KeychainTestSafety.shouldBlockRealKeychainAccess()` via the `forcesDisabledUnderTests` property (line 60). This prevents accidental keychain mutations during test execution, ensuring that integration tests cannot spawn unwanted UI dialogs.

### User Defaults Debug Flag

A hidden preference mechanism allows users or developers to toggle keychain access via `debugDisableKeychainAccess`. Stored in AppGroup defaults and checked at lines 24-28, this setting persists across application launches and can be triggered from the UI or via command-line configuration.

### Process-Wide Disable for Unbundled Executables

When CodexBar launches as an unbundled executable (outside a `.app` bundle), `KeychainPromptCoordinator` detects this condition and invokes `KeychainAccessGate.forceDisabledForProcess(reason:)` (lines 95-110 in [`Sources/CodexBar/KeychainPromptCoordinator.swift`](https://github.com/steipete/CodexBar/blob/main/Sources/CodexBar/KeychainPromptCoordinator.swift)). This immediately sets `isDisabled` to `true` for the process lifetime, logging a warning and preventing any keychain prompt from appearing.

## Implementation in Source Files

All credential providers must consult the gate before displaying UI. For example, the Claude OAuth provider in [`Sources/CodexBarCore/Providers/Claude/ClaudeOAuth/ClaudeOAuthKeychainAccessGate.swift`](https://github.com/steipete/CodexBar/blob/main/Sources/CodexBarCore/Providers/Claude/ClaudeOAuth/ClaudeOAuthKeychainAccessGate.swift) checks `KeychainAccessGate.isDisabled` at lines 26-28. If the gate reports disabled, the provider skips the UI entirely, using cached credentials or returning an error instead.

The gate's state is evaluated through the `isDisabled` computed property, which aggregates all five safety layers into a single boolean decision.

## Practical Usage Examples

Disable keychain access globally via environment variable:

```bash
export CODEXBAR_DISABLE_KEYCHAIN_ACCESS=1

# All subsequent keychain prompts are silently ignored

```

Inject a task-local override for unit tests:

```swift
KeychainAccessGate.withTaskOverrideForTesting(true) {
    // Code that would normally prompt the user
    // will see KeychainAccessGate.isDisabled == true
    // without touching the real keychain
}

```

Force disable for unbundled executables:

```swift
if KeychainPromptCoordinator.isUnbundledCodexBarExecutable(path) {
    KeychainAccessGate.forceDisabledForProcess(reason: "unbundled-executable")
}

```

## Summary

- **Task-local overrides** allow tests to mock keychain state without system access.
- **Environment variables** provide CI/CD-friendly global disable switches.
- **Debug-only test safety** automatically blocks real keychain access during test runs.
- **User defaults** offer persistent debug toggles for troubleshooting.
- **Process-wide disable** protects users from prompts when running unbundled binaries.

## Frequently Asked Questions

### What is KeychainAccessGate?

`KeychainAccessGate` is a centralized access control class in CodexBar that evaluates multiple safety conditions before allowing any code to interact with the macOS Keychain. It prevents the operating system from displaying "Keychain wants to access..." dialogs by intercepting requests at the application layer.

### How do I disable keychain prompts in CI/CD?

Set the environment variable `CODEXBAR_DISABLE_KEYCHAIN_ACCESS=1` before launching CodexBar. This forces `KeychainAccessGate.isDisabled` to return `true` for the entire process, ensuring that build scripts and automated tests never trigger interactive security dialogs.

### Why does CodexBar disable keychain access for unbundled executables?

When the binary runs outside a standard `.app` bundle, `KeychainPromptCoordinator` detects this state and calls `forceDisabledForProcess(reason:)`. This prevents keychain prompts from appearing during command-line usage or scripting scenarios where UI interaction is impossible or inappropriate.

### Which providers use the KeychainAccessGate?

All OAuth and credential providers in the codebase consult the gate. The Claude OAuth implementation in [`ClaudeOAuthKeychainAccessGate.swift`](https://github.com/steipete/CodexBar/blob/main/ClaudeOAuthKeychainAccessGate.swift) demonstrates the standard pattern: checking `isDisabled` before attempting to read or write keychain items, thereby ensuring consistent behavior across the application.