Skip to content

fix(codex-oauth): surface secret-tool failure reason on credential save (#1338) - #1369

Closed
0xghost42 wants to merge 1 commit into
Twigpine:mainfrom
0xghost42:fix/1338-codex-oauth-credentials-surface-reason
Closed

0xghost42 wants to merge 1 commit into
Twigpine:mainfrom
0xghost42:fix/1338-codex-oauth-credentials-surface-reason

Conversation

@0xghost42

Copy link
Copy Markdown
Contributor

Closes #1338.

Summary

The Codex OAuth flow on Ubuntu / GNOME (and any Linux desktop without a working Secret Service) ends in the generic dialog:

Codex OAuth succeeded, but credentials could not be saved securely.

That message is the catch-all fallback in `useCodexOAuthFlow` for when `saveCodexCredentials` returns `{success: false}` without a `warning`. Tracing it back: `saveCodexCredentials` opts out of plaintext fallback (`allowPlainTextFallback: false`), so on Linux it hits `linuxSecretStorage.update`, and that path swallowed every `secret-tool` failure mode into a bare `{success: false}` with no diagnostic. Two of the most common Linux failure modes:

  1. The `secret-tool` CLI is not installed (`libsecret-tools` missing on Debian/Ubuntu, `libsecret` missing on Fedora).
  2. The Secret Service / gnome-keyring is not running, the default keyring is locked, or there is no D-Bus session (very common over SSH without an active desktop session).

The result is identical from the user side: OAuth succeeded, generic save-failure message, no path forward.

Fix

`src/utils/secureStorage/linuxSecretStorage.ts` `update()` now mirrors the existing pattern in `windowsCredentialStorage`:

  • Capture the `secret-tool` stderr from the `execaSync` result and surface it verbatim (prefixed with `secret-tool:`) when present.
  • Detect `ENOENT` (missing binary) both by `error.code` and the error message, and return an install hint that names the relevant package (`libsecret-tools` on apt, `libsecret` on dnf) plus the Secret Service requirement.
  • Fall back to a Secret-Service-runtime hint plus the exit code when stderr is empty but the call still failed.

The warning flows through:

  • `linuxSecretStorage.update` -> `saveCodexCredentials` (`src/utils/codexCredentials.ts:207`)
  • -> `persistCredentials` in `useCodexOAuthFlow` (`src/components/useCodexOAuthFlow.ts:103`) where `saved.warning` is now non-empty, so the thrown `Error.message` carries the real reason.
  • -> `status.message` rendered by both the `ProviderManager` (`src/components/ProviderManager.tsx:632`) and provider command (`src/commands/provider/provider.tsx:1133`) 'Codex OAuth failed' dialogs.

No dialog wiring change needed; the existing render already uses `status.message`.

Test plan

  • `bun test src/utils/secureStorage/platformStorage.test.ts` -> 19/19 pass (4 new "Linux secret-tool Interaction" cases: stderr passthrough, ENOENT install hint, exit-code-only fallback, unchanged success path).
  • `bun test src/utils/secureStorage src/utils/codexCredentials.test.ts src/components/useCodexOAuthFlow.test.ts` -> 31/31 pass across 3 files.
  • `bun test` -> 2911/2914 pass (3 failing `/export direct filename` tests pre-existing on `upstream/main`, unrelated to this PR).

Notes

Scope is intentionally limited to surfacing the existing-but-discarded failure reason on Linux. The behavior on success and on macOS / Windows is unchanged. macOS `security` CLI errors already surface through their own path, and Windows `update` already routes through `getFailureWarning`.

…ic 'could not be saved' (Twigpine#1338)

When the Codex OAuth flow completed and saveCodexCredentials() called into
linuxSecretStorage, any failure from the secret-tool CLI was swallowed and
returned as {success: false} with no warning. The user dialog then fell
back to the generic 'Codex OAuth succeeded, but credentials could not be
saved securely' message, leaving no actionable diagnostic. The Codex OAuth
path explicitly opts out of the plaintext fallback (allowPlainTextFallback:
false), so this swallowed error was the only signal the user ever saw on
Ubuntu / GNOME setups where secret-tool was missing or gnome-keyring was
not running (common over SSH without an active desktop session).

linuxSecretStorage.update now:
- Captures the secret-tool stderr from the execaSync result and surfaces
  it verbatim (prefixed with 'secret-tool:') when present, mirroring how
  windowsCredentialStorage already builds its warning via getFailureWarning.
- Detects ENOENT (the secret-tool binary is missing) by both error.code
  and message, and returns an install hint pointing at libsecret-tools
  (apt) / libsecret (dnf).
- Falls back to a Secret-Service-runtime hint plus the exit code when
  stderr is empty but the call still failed.

The warning flows through saveCodexCredentials -> persistCredentials in
useCodexOAuthFlow -> 'error' status, and is already rendered by both the
ProviderManager and provider command 'Codex OAuth failed' dialogs as
status.message. No dialog wiring change needed.

Tests: 4 new cases in platformStorage.test.ts cover the stderr passthrough,
ENOENT install-hint path, exit-code-only fallback, and the unchanged
success path. Existing 'Linux secret-tool Interaction' suite continues to
pass.

Closes Twigpine#1338
@jatmn

jatmn commented May 26, 2026

Copy link
Copy Markdown
Collaborator

#1347 already closed this.

@jatmn jatmn closed this May 26, 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.

Codex provider cannot be connected

2 participants