Skip to content

Store CLI token in OS system keychain#1191

Draft
michael-webster wants to merge 3 commits intodevelopfrom
feature/system-keychain-credentials-v2
Draft

Store CLI token in OS system keychain#1191
michael-webster wants to merge 3 commits intodevelopfrom
feature/system-keychain-credentials-v2

Conversation

@michael-webster
Copy link
Contributor

Summary

  • Adds github.com/zalando/go-keyring to store the API token in the OS keychain (macOS Keychain, Windows Credential Manager, Linux Secret Service) under the service name com.circleci.cli keyed by host URL
  • Existing tokens in ~/.circleci/cli.yml are silently migrated to the keychain on first LoadFromDisk call
  • Falls back transparently to the YAML token when the keychain is unavailable (CI/headless Linux); CIRCLECI_CLI_TOKEN env var still overrides everything
  • Other CircleCI-owned tools can retrieve the token with keyring.Get("com.circleci.cli", "https://circleci.com")

Test plan

  • go test ./settings/... passes (uses keyring.MockInit() in tests)
  • go build ./... passes
  • Manual: circleci setup → token appears in macOS Keychain Access under com.circleci.cli
  • Manual: ~/.circleci/cli.yml has blank token: field after setup
  • Manual: existing token in YAML is auto-migrated to keychain on next CLI run
  • Manual: CLI still authenticates correctly after migration (circleci whoami)

Uses github.com/zalando/go-keyring to store the API token in the OS
keychain (macOS Keychain, Windows Credential Manager, Linux Secret
Service) under the service name "com.circleci.cli" keyed by host URL.

Existing tokens in ~/.circleci/cli.yml are silently migrated to the
keychain on first load. Falls back to the YAML token when the keychain
is unavailable (CI/headless environments).
webster added 2 commits March 12, 2026 16:05
- Split .goreleaser.yml into two builds: darwin (CGO_ENABLED=1) and
  linux/windows (CGO_ENABLED=0) so the darwin keychain integration
  can link against Apple Security.framework
- Move deploy and deploy-test jobs to the mac executor so goreleaser
  builds darwin natively with CGO available
- Extract docker image build/push into a new deploy-docker job on the
  Linux executor (macOS executor has no Docker support)
- Extract install-go-mac and install-goreleaser-mac as reusable commands
- Remove CGO_ENABLED=0 from the mac executor (goreleaser sets it per-build)
On macOS CI runners the Security framework blocks indefinitely waiting
for user authorisation when a keychain item is read or written.

Add settings/keychain_mock_init.go (build tag: keychain_mock) which
calls keyring.MockInit() in init() so all keychain calls use an
in-memory store instead of the OS keychain.

Pass -tags=keychain_mock to every gexec.Build call so the subprocess
CLI binary used in cmd tests always gets the mock backend.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant