Documentation
¶
Overview ¶
Package secretstore provides a pluggable backend for storing the user's CLI bearer token. The default backend is the OS keychain (macOS Keychain, Linux Secret Service / libsecret, Windows Credential Manager); a plaintext file fallback is used when the keychain is unavailable (headless Linux, disabled service, sandboxed environment).
Why two backends?
The keychain is the right place for a long-lived production credential. A user's API key has no expiry and full team scope today, so a copy of it sitting in `~/.instant-config` mode 0600 is read by anything running as that user (backup tools, IDE extensions, malware, …). T16 P1-1.
We can't refuse to run in CI / SSH / Linux-no-DBus environments — the CLI must still work. So when the keychain reports "unavailable" we fall back to the existing file mechanism, with a clear stderr warning the first time so the user knows their token is on disk.
The interface deliberately stays tiny — Get / Set / Delete — so the test suite can swap in an in-memory implementation without touching the real keychain.
Index ¶
Constants ¶
const AccountName = "api_key"
AccountName is the keychain "account" we register the bearer token under. One CLI install -> one keychain entry (no per-profile multi-tenancy today).
const ServiceName = "instanode.dev"
ServiceName is the keychain "service" name we register under. macOS shows this as the Keychain item's Name; Linux secret-service treats it as the schema's "service" attribute; Windows Credential Manager shows it as the target name's prefix.
Variables ¶
var ErrNotFound = errors.New("secretstore: no secret found")
ErrNotFound is returned when no secret has been stored yet. Callers should treat it as "anonymous mode" (no token), not as a fatal error.
Functions ¶
func Get ¶
Get returns the stored secret using the active backend. ErrNotFound means no secret has been written (anonymous mode).
func Name ¶
func Name() string
Name returns a label for the active backend ("keychain", "memory", "file-fallback"). Used by `whoami` so the user can see where their secret lives.
func TruncateForDisplay ¶
TruncateForDisplay returns a safe-to-print prefix of a credential — at most 8 characters followed by an ellipsis. Never use this for anything security-sensitive; it's purely for "is the right account logged in?" UX.
Callers MUST use this for any UI that surfaces the key (whoami, list, ...). The previous CLI printed the first 16 characters of the key directly; the audit (T16 P1-1) flagged that as material disclosure.
Types ¶
type Backend ¶
type Backend interface {
// Get returns the stored secret, or ErrNotFound if none exists.
Get() (string, error)
// Set persists the secret. An empty value is equivalent to Delete.
Set(value string) error
// Delete removes any stored secret. It must be idempotent (no error
// when the key was already absent).
Delete() error
// Name returns a short label ("keychain", "memory", "file-fallback").
// Surfaced by `whoami` so the user knows where their key lives.
Name() string
// Available reports whether the backend is usable in the current
// environment. A false here causes the chain to walk to the next backend.
Available() bool
}
Backend is the minimal interface every secret store must satisfy. The concrete types are kept inside this package so tests in the same package can swap them.
func UseDefault ¶
func UseDefault() Backend
UseDefault selects the keychain if available, otherwise leaves any already-installed backend in place — the caller (cliconfig) handles file fallback when this returns nil. We split the "keychain backend" from "file fallback" because the file is owned by the cliconfig package (it already does atomic writes and 0600 mode); we don't duplicate that here.
IMPORTANT: UseDefault does NOT clobber a previously-installed backend (e.g. the in-memory backend that the test suite installs in TestMain). If you want to force a reset, call Use(nil) first.
type MemoryBackend ¶
type MemoryBackend struct {
// contains filtered or unexported fields
}
MemoryBackend keeps the secret in a process-local string. Use only in tests.
func UseMemoryBackend ¶
func UseMemoryBackend() *MemoryBackend
UseMemoryBackend installs an in-memory backend. Tests should call this in TestMain so the real OS keychain is never touched by the suite.
func (*MemoryBackend) Available ¶
func (m *MemoryBackend) Available() bool
func (*MemoryBackend) Delete ¶
func (m *MemoryBackend) Delete() error
func (*MemoryBackend) Get ¶
func (m *MemoryBackend) Get() (string, error)
func (*MemoryBackend) Name ¶
func (m *MemoryBackend) Name() string
func (*MemoryBackend) Set ¶
func (m *MemoryBackend) Set(value string) error