feat(auth): surface credential-store failures and add ggshield auth status - #1268
feat(auth): surface credential-store failures and add ggshield auth status#1268AGallouin wants to merge 3 commits into
ggshield auth status#1268Conversation
…tatus When writing a token to the OS credential store failed (e.g. macOS error -25244 after the ggshield binary path changed following a mise/asdf reshim, a pyenv/pipx reinstall or a Homebrew upgrade), the token stayed in cleartext in auth_config.yaml with only a hidden debug-level log. - Saves now print an actionable warning with the humanized error and the commands fixing the stale Keychain entry - Successful cleartext -> credential-store migrations are confirmed with an info message - New `ggshield auth status` command (text and --json) diagnoses the credential-store backend, its reachability and where each instance token actually lives, without ever writing to the store Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
GG-HH
left a comment
There was a problem hiding this comment.
Thanks for this,
While reviewing it, I wondered if we should have the keyring path depend on the installation path if it can only be accessed by that path ?
WDYT ?
| commands={ | ||
| "login": login_cmd, | ||
| "logout": logout_cmd, | ||
| "status": auth_status_cmd, |
There was a problem hiding this comment.
There is already a command ggshield api-status that i believe has the intended behavior. What I would suggest is to add an alias with ggshield auth status. WDYT ?
There was a problem hiding this comment.
From what i understood, api-status is more "can i talk to GG, is my token valid ?" it does network calls and check the token no matter its origin (plain text, keyring on mac or other password managers).
auth status runs only locally, checks if we have a token and if it is correctly stored. It would be able to be enriched with other OS specific diagnostics.
I don't thing they server the same purpose, so I think that 2 commands is the right call. In a world full of LLMs, I would keep it really straightforward, one command, one scoped mission, simple actionnable output. If you think it will be more manually ("humanly") called than programmatically called, having an "overall dashboard" can make sense, it's more of a product call.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #1268 +/- ##
==========================================
+ Coverage 93.38% 93.57% +0.18%
==========================================
Files 189 189
Lines 10782 11291 +509
==========================================
+ Hits 10069 10565 +496
- Misses 713 726 +13
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Keyring tokens are also "stored"; the function specifically reads the tokens as written in the config file. Addresses review feedback on GitGuardian#1268. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
You mean that instead of having (for example in mac): I'm not a big fan for many reasons:
In short, if I understood your point correctly, I'd lean toward keeping a single canonical entry, with the failure surfaced loudly and a one-time fix (what this PR does). But open to discussing it! |
Following review feedback on GitGuardian#1268, instead of a separate `auth status` command, fold the token-storage diagnostic into the existing `api-status` command and expose `auth status` as an alias of it. - `api-status` gains a token-storage section (text) and a `token_storage` key (--json), reporting the credential-store backend, its reachability and where each instance token actually lives. - The storage diagnostic is local and read-only, so it is shown even when the instance is unreachable or no usable token is configured: the API check now degrades to an error line instead of aborting. - Exit code stays driven solely by the API check, so a token stored in plaintext never changes api-status' exit status (non-breaking). - The alias is wired in ggshield.__main__ so cmd.auth does not import cmd.status (cmd.* packages are kept independent). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Context
When the ggshield binary path changes (mise/asdf reshim, pyenv/pipx reinstall, Homebrew upgrade…), the macOS Keychain entry created by the previous binary can no longer be overwritten: writes fail with
-25244(errSecInvalidOwnerEdit) because the entry's ACL is tied to the old path. ggshield silently fell back to storing the token in cleartext inauth_config.yaml, with only a debug-level log. The availability probe could not catch this, since it writes a fresh key with no ACL conflict.Fixes #1267.
What has been done
AuthConfig.save()prints a warning with a humanized error (the-25244case is translated to plain language), states that the token will stay in cleartext, and gives the copy-pasteable recovery commands (security delete-generic-password …+ggshield auth login). The fix advice is gated on the active keyring backend (not the OS), so a custom backend on macOS doesn't get Keychain-specific commands.ggshield auth statuscommand diagnosing token storage, in text and--json:ok/failed/plaintext/disabled/skipped), with fix commands when actionable;is_reachable()read-only check is used instead ofis_available());GGSHIELD_NO_KEYRINGis set (reachableis reported asnull);okeven if overwriting its entry would fail, because reads are what every command needs at runtime — write failures are surfaced at save time instead.credential_store+ per-instance{instance, status, message, fix}, withnullfor non-applicable fields) intended to be parseable by scripts; tests freeze the contract.Differences from the issue's proposed fixes: instead of making
is_available()probe real instance keys (which would put writes on every command's startup path), the conflict is detected where it matters — the save path warns on the actual failed write, andauth statusverifies each real instance key with reads only. The diagnostic command lives underggshield auth statusrather thanggshield config keyring-status, and its output is ASCII-only for legacy Windows terminals.Validation
Unit tests cover the new behavior (failure warning, migration message, silence on re-saves, read-only guarantee, JSON contract). To validate manually on macOS:
ggshield auth login, then runggshield auth status— the instance should reporttoken_storage: okwith the macOS Keychain location.ggshield auth login) — a warning should explain the failure and print thesecurity delete-generic-passwordfix;auth statusshould reportplaintextwith the same fix.auth statusshould reportokagain, and the save should print the migration confirmation.GGSHIELD_NO_KEYRING=1 ggshield auth status --jsonshould report"reachable": nulland not prompt for Keychain access.PR check list
skip-changeloglabel has been added to the PR.🤖 Generated with Claude Code