Skip to content

fix(credentials): read the macOS keychain without an invalid target - #350

Closed
7smd7 wants to merge 1 commit into
Draculabo:mainfrom
7smd7:fix/macos-keychain-read-target
Closed

7smd7 wants to merge 1 commit into
Draculabo:mainfrom
7smd7:fix/macos-keychain-read-target

Conversation

@7smd7

@7smd7 7smd7 commented Oct 13, 2026 •

Copy link
Copy Markdown

Problem

On macOS, every cloud account switch fails with:

Backend message: Cloud account switch failed
Diagnostic code: target-write-failed

The log shows CredentialStoreReadError: The Antigravity credential store is unavailable. (storage: credential-store, errorCode: unavailable). Reproduced on v0.23.0 and v0.25.1, macOS arm64, with a valid gemini / antigravity item in the login keychain.

Root cause

createNativeCredentialEntry in src/modules/antigravity-runtime/credentials/antigravityCredentialStore.ts calls Entry.withTarget('gemini:antigravity', 'gemini', 'antigravity') on every non-Linux platform. The macOS backend of @napi-rs/keyring only accepts a keychain kind as the target, so the entry cannot even be constructed:

Value of 'keychain' is invalid: 'gemini:antigravity' is not User, System, Common, or Dynamic

classifyCredentialStoreReadError maps that to unavailable. Windows never reaches this function (it reads and writes through windowsCredentialStore), so the withTarget branch only ever ran on macOS, where it always fails. The existing unit test did not catch it because the withTarget mock accepts any target. OpenCodeNativeCredentialStore already documents this exact pitfall.

Fix

Use the default builder, new Entry('gemini', 'antigravity'), on both macOS and Linux. The macOS unit test now asserts the entry is built without a target. That assertion fails on main and passes with this change.

Verification

  • npx vitest run src/tests/unit/antigravity-credential-store-read.test.ts: 9/9 pass (the macOS case fails without the fix).
  • ESLint, Prettier and tsc --noEmit are clean on the changed files.
  • Ran the packaged keyring.darwin-arm64.node from v0.25.1 against the real login keychain: withTarget('gemini:antigravity', …) throws the error above; new Entry('gemini', 'antigravity').getSecret() returns the stored go-keyring-base64: payload.
  • Not verified: a full packaged-app account switch with this build.
  • Unrelated: three writeAntigravityCredentialStoreToken tests in security-migration.test.ts (Windows write paths) fail on macOS on main too (koffi import), with or without this change.

🤖 Generated with Claude Code

On macOS, createNativeCredentialEntry called
Entry.withTarget('gemini:antigravity', ...). The macOS keyring backend only
accepts a keychain kind (User / System / Common / Dynamic) as the target, so
constructing the entry threw "Value of 'keychain' is invalid", which was
classified as CredentialStoreReadError('unavailable'). Every cloud account
switch on macOS failed with "The Antigravity credential store is unavailable"
(diagnostic kind target-write-failed).

Only macOS and Linux reach the native keyring (Windows uses its own credential
target), so use the default builder new Entry('gemini', 'antigravity') on both,
matching OpenCodeNativeCredentialStore.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Copilot AI balanced review requested due to automatic review settings October 13, 2026 10:01

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

It modifies credential-storage behavior, a high-risk surface, and the full packaged-app macOS account switch remains unverified, so human review is warranted.

0 open findings

What changed in this PR

This PR fixes a macOS-only bug in the Antigravity cloud-account credential flow. createNativeCredentialEntry previously built the native keyring entry with Entry.withTarget('gemini:antigravity', 'gemini', 'antigravity') on every non-Linux platform. On macOS, @napi-rs/keyring interprets the first argument as a keychain kind (User/System/Common/Dynamic), so the entry could not be constructed at all, surfacing as CredentialStoreReadError: unavailable and a failed account switch. Windows never reaches this helper (it reads/writes via windowsCredentialStore), so the broken branch only ever ran on macOS. The fix uses the default new Entry('gemini', 'antigravity') builder on all platforms that reach the native keyring, matching the pattern already documented in OpenCodeNativeCredentialStore.

Changes:

  • Replace the platform-conditional Entry.withTarget(...) with the default new Entry('gemini', 'antigravity') builder in createNativeCredentialEntry.
  • Update the explanatory comment to describe why the credential target must not be passed to Entry.withTarget.
  • Extend the macOS read unit test to assert the entry is built without a target and that withTarget is never called, catching the regression.
File Description
src/​modules/​antigravity-runtime/​credentials/​antigravityCredentialStore.ts Builds the native keyring entry with the default new Entry(service, account) constructor instead of Entry.withTarget, fixing macOS reads/writes.
src/​tests/​unit/​antigravity-credential-store-read.test.ts Adds assertions to the macOS case verifying the entry is created with ('gemini', 'antigravity') and withTarget is not invoked.

I verified the fix against the surrounding code: both the read path (win32 returns at readAntigravityCredentialStoreToken before readViaNativeKeyring) and the write path (win32 returns in writeToSystemCredentialStore before writeViaNativeKeyring) confirm Windows never reaches createNativeCredentialEntry, so dropping withTarget is safe. The new assertions mirror the existing Linux test (antigravity-credential-store-read.test.ts:227-228), and no test expects withTarget to be called. I found no additional issues to flag.

🧠 Review effort: Balanced


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@7smd7

7smd7 commented Oct 13, 2026

Copy link
Copy Markdown
Author

Closing: this fixes the macOS keychain read, but the account switch still fails because of further problems in the write path. Details are in #351.

@7smd7 7smd7 closed this Oct 13, 2026
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.

2 participants