secrets

package
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 13, 2026 License: MIT Imports: 11 Imported by: 0

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

View Source
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

View Source
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.

View Source
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

func DefaultFilePath() (string, error)

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

func DeleteAll(s Store, project string) error

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

func Has(s Store, project string) bool

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.

func Key

func Key(project, kind string) string

Key builds the storage key for one secret of one project, for example "fft:staging:refreshToken".

func ParseKey

func ParseKey(key string) (project, kind string, ok bool)

ParseKey splits a key produced by Key back into its parts.

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.

func (*MemStore) Delete

func (s *MemStore) Delete(key string) error

Delete implements Store. Deleting an absent key is not an error.

func (*MemStore) Get

func (s *MemStore) Get(key string) (string, error)

Get implements Store.

func (*MemStore) Kind

func (*MemStore) Kind() string

Kind implements Store.

func (*MemStore) Set

func (s *MemStore) Set(key, val string) error

Set implements Store.

func (*MemStore) Snapshot

func (s *MemStore) Snapshot() map[string]string

Snapshot returns a copy of everything the store holds.

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

func NewEnv(lookup func(string) (string, bool)) Store

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

func NewFile(path string) Store

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 NewKeyring

func NewKeyring() Store

NewKeyring returns a Store backed by the OS keychain.

func Open

func Open(noKeyring bool) (Store, error)

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.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL