Documentation
¶
Overview ¶
Package secrets stores the per-project credentials that must never land in the config file: passwords, refresh tokens and cached id tokens.
The OS keychain is the default backing store, but it cannot be the only one. A GitHub Linux runner has no Secret Service, so go-keyring fails there outright; a headless Linux desktop may have none either. Store is therefore an interface with four implementations, selected at startup.
Index ¶
Constants ¶
const ( KindPassword = "password" KindRefreshToken = "refreshToken" KindIDToken = "idToken" KindIDTokenExp = "idTokenExp" )
Kinds of secret held per project. Each one is stored under its own key.
They are deliberately not bundled into a single JSON blob: the Windows Credential Manager caps one credential at roughly 2.5 KB and a Firebase id token alone is about 1 KB, so a combined blob would silently fail to save on Windows.
Variables ¶
var ErrNotFound = errors.New("secret not found")
ErrNotFound is returned by Get when the key holds no secret. Every implementation normalises its backend's "missing" error to this one so that callers can branch on it without knowing which store they got.
var ErrReadOnly = errors.New("secret store is read-only")
ErrReadOnly is returned by Set and Delete on a store that cannot be written, such as the environment-backed store used in CI.
Functions ¶
func AllKinds ¶
func AllKinds() []string
AllKinds lists every secret kind a project may have. `fft project remove` walks it to make sure nothing is left behind in the keychain.
func DefaultFilePath ¶
DefaultFilePath is the credentials file fft falls back to when the keychain is unavailable: $XDG_STATE_HOME/fft/credentials.json, or ~/.local/state/fft/ credentials.json when XDG_STATE_HOME is unset.
func DeleteAll ¶
DeleteAll removes every secret belonging to project. It keeps going after a failure so that one unreadable entry cannot strand the rest, and reports all the failures together.
func Has ¶
Has reports whether the project has any credential at all in the store — a password to sign in with, or an id token to use directly.
Types ¶
type MemStore ¶
type MemStore struct {
// contains filtered or unexported fields
}
MemStore keeps secrets in memory for the lifetime of the process. It backs the specs — which is why it is exported: they need MemStore.Snapshot to assert on exactly which keys were written.
func NewMem ¶
func NewMem() *MemStore
NewMem returns an in-memory Store. It is safe for concurrent use.
type Store ¶
type Store interface {
// Get returns the secret at key, or ErrNotFound if there is none.
Get(key string) (string, error)
// Set writes val to key, replacing any previous value.
Set(key, val string) error
// Delete removes key. Deleting a key that holds no secret is not an error.
Delete(key string) error
// Kind names the backing store for display: "keyring", "env", "file" or
// "memory".
Kind() string
}
Store keeps a secret per key. Keys are built with Key; a store must never interpret them.
func NewEnv ¶
NewEnv returns a read-only Store backed by the FFT_* environment variables. lookup may be nil, in which case os.LookupEnv is used.
func NewFile ¶
NewFile returns a Store backed by the JSON file at path. The file and its parent directory are created on first write, with modes 0600 and 0700.
func Open ¶
Open returns the Store implied by the environment.
The keychain is the default, because it is the only place a secret is protected by something other than a file mode. noKeyring (--no-keyring, or FFT_NO_KEYRING=1) selects the 0600 file fallback instead, for machines where there is no keychain to talk to.
The environment-backed store is not reachable from here: it belongs to the ephemeral project synthesized in headless mode, which the caller detects before it ever asks for a store.