Skip to content

Commit 8785295

Browse files
committed
docs(0.8.0): CHANGELOG entry for file-default credential backend
1 parent 6a50268 commit 8785295

1 file changed

Lines changed: 60 additions & 2 deletions

File tree

CHANGELOG.md

Lines changed: 60 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -167,8 +167,66 @@ and a Red/Green/Purple security pass. All work landed on
167167

168168
### Fixed
169169

170-
- **Repeated macOS keychain password prompt.** The `clx-mcp` server
171-
re-read `com.clx.credentials` from the OS keychain on every
170+
- **Repeated macOS keychain password prompt, eliminated at the root.**
171+
CLX no longer uses the macOS keychain by default. A parallel
172+
Codex + research investigation established definitively that no
173+
macOS keychain API can serve an unsigned / adhoc-signed binary
174+
prompt-free: the legacy keychain re-prompts on every read because
175+
its "Always Allow" ACL binds to a code signature that an
176+
adhoc-signed binary does not stably have, and the iOS-style
177+
data-protection keychain outright rejects unsigned binaries with
178+
`errSecMissingEntitlement (-34018)`. Therefore the keychain cannot
179+
be the default secret store for a tool distributed without an Apple
180+
Developer ID. CLX now follows the 2026 dev-CLI consensus
181+
(`gh`, `aws`, `stripe`, `doppler`, `cargo`): a local file backend by
182+
default, keychain opt-in.
183+
- New `CredentialBackend` trait under `CredentialStore`; scoping,
184+
validation, indexing, and the session cache are unchanged above it.
185+
- New default `AgeFileBackend`: secrets stored in
186+
`~/.clx/credentials.age` (mode 0600), encrypted with `age`
187+
(age-encryption.org v1, X25519 + ChaCha20-Poly1305) under a random
188+
identity at `~/.clx/cred.key` (mode 0600); `~/.clx` is 0700. Writes
189+
are atomic (temp file + rename). Encrypted at rest specifically to
190+
defeat the realistic CLX exposure path (dotfile sync, backups,
191+
log/support bundles); a same-uid attacker remains out of scope, as
192+
it is for the keychain.
193+
- `KeyringBackend` retains the previous keychain code and is selected
194+
only when the user explicitly sets `credentials.backend: keychain`
195+
(or `CLX_CREDENTIALS_BACKEND=keychain`). Default is `file`.
196+
- Credential resolution is now env (`api_key_env`) then the selected
197+
backend then `api_key_file`; under the default backend the keychain
198+
code path is never reached. Every credential-construction callsite
199+
(`resolve_azure_credential`, the MCP server, the `clx credentials`
200+
and `clx keychain-trust` commands) was repointed through a single
201+
config-aware constructor so nothing silently falls through to the
202+
keychain. A regression test asserts zero keychain calls under the
203+
default backend.
204+
- Fixed a latent `SecAccessCreate(NULL)` defect in the opt-in
205+
keychain path: `NULL` means "trust only the calling app" (the
206+
opposite of the intended permissive access); it now passes an
207+
empty trusted-application list, and the misleading comments were
208+
corrected. The opt-in keychain remains best-effort for adhoc
209+
binaries by macOS design.
210+
- New `clx credentials migrate <key>`: explicit, one-time move of a
211+
secret that exists only in the legacy keychain into the file
212+
backend. This is the single place a keychain prompt may still
213+
occur, and only when the user runs it deliberately and the secret
214+
is not already available from env / `api_key_file` / the file
215+
backend. Automatic paths never read the keychain.
216+
- Net result: a fresh user with default config sees zero macOS
217+
keychain prompts for the entire Claude Code session, with no code
218+
signing, no manual `security` command, and no temporary toggle.
219+
220+
Superseded earlier in this release cycle (kept for historical
221+
context): an interim session-scoped credential cache
222+
(`CredentialStore::new_cached`, `secrecy::SecretString`, zeroized on
223+
drop, owned by `McpServer`) and a `clx keychain-trust` repair command
224+
that relaxed the legacy keychain ACL with a single documented
225+
`security set-generic-password-partition-list` call. Both still exist
226+
and are correct for the opt-in keychain backend, but are no longer on
227+
the default path. The original interim note read:
228+
- **(interim, now superseded by the file backend above)** The `clx-mcp`
229+
server re-read `com.clx.credentials` from the OS keychain on every
172230
credential-bearing tool invocation (e.g. each `clx_credentials`
173231
call), so macOS prompted far more often than necessary.
174232
`CredentialStore` gained an opt-in session-scoped cache

0 commit comments

Comments
 (0)