Configuration reference¶
This module has no config file, no flags and no init function you tune. Its entire externally-visible configuration is one environment variable, one advisory constant, one validation rule, and a reserved keychain namespace. They are all listed here, with what happens when each is wrong.
CI¶
The only environment variable this module reads.
| Read by | IsCI, and through it RefuseLiteralUnderCI |
| Recognised value | the exact string true |
| Anything else | treated as "not CI" |
| Unset | treated as "not CI" |
The comparison is exact and case-sensitive. CI=1, CI=True, CI=TRUE,
CI=yes and CI=true (trailing space) all make IsCI() return false. When that
happens, literal mode is offered in the menu and RefuseLiteralUnderCI returns
nil — the CI protection is silently off, in the exact environment it exists for.
Not every CI system sets CI at all, and some set a different value. Do not assume;
check the runner and set it explicitly in the job when it is missing:
Confirm from inside a job with printf '[%s]\n' "$CI" — the brackets make a
trailing space or an empty value visible.
Nothing in the module reads CI on your behalf at a decision point.
RefuseLiteralUnderCI is a check you call, and
ModeChoices takes the CI state as an argument rather than
consulting the environment itself.
Environment variable names¶
The names a user may choose for ModeEnvVar are constrained by
ValidateEnvVarName:
| Rule | Consequence |
|---|---|
First character must be A–Z |
a leading digit, underscore or lowercase letter is rejected |
Remaining characters A–Z, 0–9, _ |
hyphens, dots and lowercase are rejected |
| 1 to 64 characters | 65 or more is rejected |
| ASCII only | non-ASCII uppercase such as É is rejected |
The rule is deliberately narrower than POSIX allows, so a chosen name survives shell
profiles, YAML and Docker --env files without quoting. It rejects names that would
work — myTool_token is a legal environment variable — and that is the trade-off:
one shape that is safe everywhere beats a permissive rule that breaks in one place.
Validation is not automatic. credentials.Store and the resolution of an env var
never see the name; the check runs only where you pass ValidateEnvVarName to a
prompter or a form validator.
KeychainOpTimeout¶
The suggested ceiling on a single backend operation. It is a value, not a
behaviour — the package never applies it. A call made with context.Background()
has no deadline, and against a locked keychain that means it waits for as long as
the platform takes, which on a headless Linux host waiting for an unlock prompt is
indefinitely.
Derive a context from it at every call site that runs during setup or startup:
Five seconds is chosen to be longer than any healthy local keychain round-trip and short enough that a wedged one does not read as a hung program. Use your own value if you have a remote backend that is legitimately slower.
The reserved credentials-keychain-probe service¶
Probe writes its canary under the keychain service name
credentials-keychain-probe, with an account of the form probe-<pid>-<8 hex
digits> and the value probe.
Do not store anything of your own under that service name. The account is randomised per invocation so concurrent probes from any number of processes cannot collide, but the service name is fixed and the entries under it are the module's.
Service and account names you choose¶
Store, Retrieve and Delete take a service and an account and pass them to
the backend unchanged. The module imposes no rules on them at all: no length limit,
no character restrictions, no rejection of empty strings. Any limits are the
platform's — macOS Keychain, the Secret Service and Windows Credential Manager each
have their own.
The convention used across the toolkit is the tool name as the service and a
dotted purpose as the account, e.g. mytool / github.auth. Both are safe to log:
the Backend contract forbids an implementation from logging them as secrets,
and no shipped backend puts either in a place a secret would not be allowed.
Where the default prompter reads and writes¶
DefaultPrompter is fixed to:
| Input | os.Stdin |
| Prompt output | os.Stderr — so prompts never pollute a piped stdout |
| Masking | golang.org/x/term, only when stdin is a terminal |
There is no exported constructor for a prompter over different streams. If you need
one — a test harness, an embedded shell — implement
Prompter yourself; it is three methods.
Build-time requirements¶
| Go | 1.26.5 or newer (go.mod declares go 1.26.5) |
| Core dependencies | github.com/cockroachdb/errors, golang.org/x/term |
Added by credentials/keychain |
github.com/zalando/go-keyring, and transitively github.com/godbus/dbus/v5 (Linux) and github.com/danieljoos/wincred (Windows) |
Added by credentials/test |
none |
The core carries no config framework, no CLI framework and no TUI. A
depfootprint_test.go guard fails the build if go-tool-base, cobra, pflag, viper,
charmbracelet, OpenTelemetry or a cloud SDK enters the graph — and separately if
go-keyring ever reaches the core or test packages, or ever leaves the keychain
subpackage.