Documentation
¶
Overview ¶
Package credstore implements credential storage.
Per § Credentials: encrypted-file is the primary store (AES-GCM with a passphrase- or machine-bound key). OS keychain integrations are opt-in build-tagged plugins per platform, those live next to this file with `_darwin.go` / `_linux.go` / `_windows.go` suffixes and call back into Store.
Package credstore is part of the GoFastr harness.
See docs/harness-architecture.md for the architecture this package implements.
Index ¶
Constants ¶
This section is empty.
Variables ¶
var ErrAmbiguousLegacyKey = errors.New("credstore: ambiguous legacy credential key; re-enter the credential")
ErrAmbiguousLegacyKey is returned by Get when the only entry for the pair is a legacy "provider|account" key holding more than one '|': the old format cannot say which pair wrote it, so the secret is not handed to either. Re-enter it with Put (or remove it with Delete) on the right pair.
var ErrNotFound = errors.New("credstore: not found")
ErrNotFound is returned by Get when the (provider, account) pair has no entry.
Functions ¶
func DeriveKey ¶
DeriveKey returns a 32-byte key from a passphrase using PBKDF2-SHA256.
salt should be a stable per-install value (e.g. a UUID generated on first run and stored in `~/.config/gofastr/harness/salt`).
The PBKDF2 iteration count is intentionally high (200k) since unlocking is rare, once per harness boot for interactive use.
func MachineKey ¶
MachineKey derives a 32-byte key from machine-stable inputs without any user passphrase. Used for headless/CI where there's no human to type a passphrase. The threat model accepts that anyone with root on the machine can re-derive the same key, that's expected for the CI use case.
Types ¶
type EncryptedFileStore ¶
type EncryptedFileStore struct {
// contains filtered or unexported fields
}
EncryptedFileStore is the primary implementation: an AES-GCM encrypted JSON file at the configured path.
File layout (post-decryption):
{
"entries": {
"openrouter|default": "<api-key>",
"zai|default": "<api-key>"
}
}
func NewEncryptedFileStore ¶
func NewEncryptedFileStore(path string, key []byte) (*EncryptedFileStore, error)
NewEncryptedFileStore returns a Store backed by an encrypted file at the given path. The 32-byte key is derived elsewhere (DeriveKey from passphrase, or machine-bound key from /etc/machine-id + hostname).
func (*EncryptedFileStore) Delete ¶
func (s *EncryptedFileStore) Delete(provider, account string) error
func (*EncryptedFileStore) Get ¶
func (s *EncryptedFileStore) Get(provider, account string) (string, error)
func (*EncryptedFileStore) List ¶
func (s *EncryptedFileStore) List() ([]Entry, error)
func (*EncryptedFileStore) Put ¶
func (s *EncryptedFileStore) Put(provider, account, secret string) error
type Store ¶
type Store interface {
Get(provider, account string) (string, error)
Put(provider, account, secret string) error
Delete(provider, account string) error
List() ([]Entry, error)
}
Store is the credential store interface. Tokens are addressed by a {provider, account} key pair, most providers have one account per install (the API key); Copilot's auth flow has an explicit account-per-GitHub-user model.