Documentation
¶
Overview ¶
Package keychain is gro's credential adapter. Despite the historical package name, it no longer shells out to macOS `security` or Linux `secret-tool`, and no longer writes a plaintext token.json: it is a thin wrapper over cli-common's credstore, which owns OS-keyring storage, §1.4 backend selection (incl. Linux fail-closed and the encrypted-file fallback), Windows Credential Manager, and the §1.5.2 allowed-key allowlist. The name is retained to avoid churning every importer during the Phase B migration (Open CLI Collective Secret-Handling Standard §2.3).
The access secret is the per-user OAuth token: the whole oauth2.Token (AccessToken AND RefreshToken are secret) serialized as one credstore string value under the single bundle key "oauth_token". The OAuth client JSON is deployment material (§1.2) and is NOT stored here.
Index ¶
- Constants
- Variables
- func EnsureMigrated() error
- func GetBackendFlagOverride() (value string, flagSet bool)
- func NewPersistentTokenSource(ctx context.Context, cfg *oauth2.Config, initial *oauth2.Token, ...) oauth2.TokenSource
- func PassphraseSource(service string) string
- func SetBackendFlagOverride(value string, flagSet bool)
- type PersistentTokenSource
- type Store
- func (s *Store) Backend() (credstore.Backend, credstore.Source)
- func (s *Store) Close() error
- func (s *Store) DeleteToken() error
- func (s *Store) HasToken() (bool, error)
- func (s *Store) Ref() string
- func (s *Store) Service() string
- func (s *Store) SetToken(tok *oauth2.Token) error
- func (s *Store) Token() (*oauth2.Token, error)
- type TokenPersister
Constants ¶
const KeyOAuthToken = "oauth_token" //nolint:gosec // G101: a bundle key name, not a credential
KeyOAuthToken is gro's single bundle key (§1.3). The migration renames the historical keychain account "oauth_token" into this same key under the resolved credential_ref.
Variables ¶
var ErrTokenNotFound = errors.New("no token found in secure storage")
ErrTokenNotFound indicates no token exists in the keyring (errors.Is-able wrapper of credstore.ErrNotFound). Name retained for existing callers.
Functions ¶
func EnsureMigrated ¶ added in v1.0.48
func EnsureMigrated() error
EnsureMigrated runs (and resolves) the one-time §1.8 legacy migration up front via the full Open() path, then closes. A legacy-vs-keyring conflict surfaces as a hard error. Shared by `gro init` and `gro set-credential` so the migration guarantee lives in exactly one place.
func GetBackendFlagOverride ¶ added in v1.0.53
GetBackendFlagOverride returns the current override. Two return values preserve the flag-set vs unset distinction credstore.BindBackendFlag depends on.
func NewPersistentTokenSource ¶
func NewPersistentTokenSource(ctx context.Context, cfg *oauth2.Config, initial *oauth2.Token, persist TokenPersister) oauth2.TokenSource
NewPersistentTokenSource creates a TokenSource that persists refreshed tokens through persist. When the underlying oauth2 package refreshes an expired token, this wrapper detects the change and writes it back via the caller-captured persister (no long-lived credstore Store handle).
func PassphraseSource ¶ added in v1.0.48
PassphraseSource describes, for `config show`, where the file-backend passphrase would come from (§1.4: the user must understand their posture). Only meaningful when the file backend is in use.
func SetBackendFlagOverride ¶ added in v1.0.53
SetBackendFlagOverride records the user-supplied --backend flag for the next openWith call. Called by root.WireBackendSelection at PersistentPreRunE time. flagSet matches cobra's pflag.Flag.Changed — true when the user passed --backend on the command line, regardless of whether the value is empty.
Types ¶
type PersistentTokenSource ¶
type PersistentTokenSource struct {
// contains filtered or unexported fields
}
PersistentTokenSource wraps a TokenSource and persists refreshed tokens via the injected persister. This solves the problem where oauth2's automatic token refresh does not persist the rotated token back to storage.
type Store ¶ added in v1.0.48
type Store struct {
// contains filtered or unexported fields
}
Store is an open handle to gro's credential bundle. Construct with one of the Open* functions, always Close. It carries the resolved ref so callers can report it in `config show` / errors without re-deriving it (the ref is not secret — §1.12).
func Open ¶ added in v1.0.48
Open resolves the authoritative credential_ref from config.yml (§1.3 — the service/profile are parsed, never assumed), opens the backing credstore, and runs the one-time legacy migration (§1.8) before returning. Used by all real API commands AND `config test` (the smoke check must surface migration/conflicts exactly as a real command would). A legacy-vs-keyring conflict surfaces here as a §1.8 error.
func OpenForMigrationOverwrite ¶ added in v1.0.48
OpenForMigrationOverwrite is Open with the §1.8 `--overwrite` resolution: a legacy value is forced over an existing keyring entry. It still cannot resolve a legacy-vs-legacy disagreement (the user must pick).
func OpenNoMigrate ¶ added in v1.0.48
OpenNoMigrate opens WITHOUT the one-time migration. Reserved for the diagnostic/remediation paths (`config show`, `config clear`): if migration ran first it would return a §1.8 conflict before the user could inspect or clear the conflicting entry, leaving no way out.
func OpenRef ¶ added in v1.0.48
OpenRef opens a store against an explicit ref instead of config.yml's credential_ref — used by `gro set-credential --ref` and the refresh persister. An empty ref falls back to the configured/default ref. Migration does NOT run here: the one-time §1.8 migration only ever targets the canonical configured ref (running it against an arbitrary --ref would discover the default ref's legacy data and could write it under the wrong service/profile).
func (*Store) Backend ¶ added in v1.0.48
Backend reports the credstore backend and how it was selected, for `config show` (§1.6). Neither value is secret.
func (*Store) DeleteToken ¶ added in v1.0.48
DeleteToken removes the token (idempotent: an absent key is not an error — §1.7). The Exists pre-check is backend-agnostic: credstore's file backend surfaces a raw os "not found" rather than ErrNotFound on Delete. A genuine Exists failure (e.g. keyring temporarily inaccessible) is surfaced, not swallowed — otherwise a non-deletion would be reported as success.
func (*Store) HasToken ¶ added in v1.0.48
HasToken reports presence without returning the value (`config show`, `init` overwrite check — §1.6). A genuine Exists failure (keyring temporarily inaccessible) is surfaced, not folded into "absent": callers that gate re-auth/overwrite on this must not mistake an error for "no token" and clobber a token that is actually present.
func (*Store) Ref ¶ added in v1.0.48
Ref returns the resolved credential ref (non-secret; safe to display).
func (*Store) Service ¶ added in v1.0.48
Service returns the resolved service segment (non-secret; used for the §1.4 passphrase-source label).
type TokenPersister ¶ added in v1.0.48
TokenPersister persists a refreshed OAuth token. It is supplied by the caller (auth.GetHTTPClient) bound to the ref captured at construction time, so the only sanctioned non-ingress keyring write (runtime token refresh, standard §ix / line 174) updates the existing oauth_token key under the active ref — never a new key, never a different ref.