secrets

package
v0.1.1 Latest Latest
Warning

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

Go to latest
Published: Aug 5, 2026 License: Apache-2.0 Imports: 11 Imported by: 0

Documentation

Overview

Package secrets resolves logical references to secret values. A Reference is what connectors and (eventually) workflows are allowed to hold — never a secret's actual value (ADR-0009, ADR-0020).

Index

Constants

View Source
const KeychainService = "patchcord"

KeychainService is the fixed Service every KeychainStore this build constructs uses. Not configurable — one Patchcord agent, one keychain namespace, same convention as vaultFileName below for FileStore.

Variables

This section is empty.

Functions

func GenerateMasterKey

func GenerateMasterKey() (string, error)

GenerateMasterKey returns a new random 32-byte AES-256 key, base64 encoded — the value an operator writes to the file pointed at by --secrets-master-key-file. Same construction as internal/auth.CreateToken's random secret: crypto/rand, never derived from anything guessable.

func LoadMasterKeyFile

func LoadMasterKeyFile(path string) ([32]byte, error)

LoadMasterKeyFile reads and decodes the base64 master key stored at path, rejecting anything that doesn't decode to exactly masterKeySize bytes — a truncated or corrupted key file fails loudly at startup rather than silently producing a FileStore that can never decrypt its vault.

func ValidateType

func ValidateType(t string) error

ValidateType returns an error unless t is a Reference type a Store in this build can resolve.

Types

type EnvStore

type EnvStore struct{}

EnvStore resolves "env" references by reading an environment variable.

func (EnvStore) Resolve

func (EnvStore) Resolve(_ context.Context, ref Reference) (string, error)

type FileStore

type FileStore struct {
	Path string
	Key  [32]byte
}

FileStore resolves "file" references against a single AES-256-GCM encrypted vault file on disk. Key must be exactly masterKeySize bytes (LoadMasterKeyFile enforces this); it is never persisted in Path or anywhere else the vault itself lives — see ADR-0040.

func NewFileStore

func NewFileStore(dataDir, masterKeyFile string) (FileStore, error)

NewFileStore loads the master key at masterKeyFile and returns the FileStore pointed at dataDir's vault — the same construction BuildStore uses for "file", exposed directly for internal/cli's `secret set`/`secret remove --type file`, which need a FileStore before any connector ever resolves against it.

func (FileStore) Remove

func (s FileStore) Remove(_ context.Context, key string) error

Remove deletes key from the vault, re-encrypting and writing the rest. Removing a key that isn't set is an error, same as Resolve on a missing key — a typo'd key silently no-op'ing would be a worse failure mode.

func (FileStore) Resolve

func (s FileStore) Resolve(_ context.Context, ref Reference) (string, error)

Resolve decrypts the vault at s.Path and returns the value stored under ref.Key. A vault that doesn't exist yet (no secret was ever Set) and a vault that exists but doesn't contain ref.Key are both reported as "not found" — indistinguishable on purpose, same convention as EnvStore.Resolve's unset-variable error.

func (FileStore) Set

func (s FileStore) Set(_ context.Context, key, value string) error

Set encrypts value under key, re-encrypting the whole vault with a fresh nonce and writing it atomically (temp file + rename, so a reader never observes a partially written vault). Creates the vault if it doesn't exist yet.

type KeychainStore

type KeychainStore struct {
	Service string
}

KeychainStore resolves "keychain" references against the current OS's native secret store — macOS Keychain, Windows Credential Manager, or (on Linux) whatever implements the freedesktop Secret Service, via github.com/zalando/go-keyring. Every entry lives under the same Service, keyed by Reference.Key.

This is a local-first adapter: a headless Linux server (in particular the distroless Docker image, ADR-0039) typically has no Secret Service daemon running, so Resolve fails there at call time — expected, see ADR-0040. FileStore is the adaptor meant for that deployment shape.

func NewKeychainStore

func NewKeychainStore() KeychainStore

NewKeychainStore returns the KeychainStore every entry point uses — internal/runtime.NewAgent via BuildStore, and internal/cli's `secret set`/`secret remove --type keychain`, which write to it directly.

func (KeychainStore) Remove

func (s KeychainStore) Remove(_ context.Context, key string) error

Remove deletes key from the OS keychain. Removing a key that isn't set is an error, same convention as FileStore.Remove.

func (KeychainStore) Resolve

func (s KeychainStore) Resolve(_ context.Context, ref Reference) (string, error)

func (KeychainStore) Set

func (s KeychainStore) Set(_ context.Context, key, value string) error

Set stores value under key in the OS keychain, overwriting any existing entry of the same key.

type MultiStore

type MultiStore map[string]Store

MultiStore dispatches Resolve to one of several Stores, keyed by Reference.Type — e.g. {"env": EnvStore{}, "file": FileStore{...}}. This is how an agent supports several secret adapters at once: which adapter resolves a given reference is a property of that reference (Type), not a single global choice for the whole agent (ADR-0040).

func BuildStore

func BuildStore(dataDir, masterKeyFile string) (MultiStore, error)

BuildStore assembles the MultiStore every entry point that resolves secrets uses — internal/runtime.NewAgent for the running agent, and the CLI commands that touch connectors/secrets directly (internal/cli) — so both resolve a given Reference exactly the same way (CLAUDE.md non-negotiable #8). "env" and "keychain" are always registered; "file" only once masterKeyFile is non-empty, since a "file" reference is valid to create before an operator has ever provisioned a master key (ValidateType doesn't require it — see its doc comment).

func (MultiStore) Resolve

func (m MultiStore) Resolve(ctx context.Context, ref Reference) (string, error)

type Reference

type Reference struct {
	Type string `json:"type"`
	Key  string `json:"key"`
}

Reference is a logical pointer to a secret's value, resolved on demand by a Store. Type selects which adapter resolves it — "env" (EnvStore), "keychain" (KeychainStore) or "file" (FileStore); see ADR-0020 for why environment variables were the first adapter and ADR-0040 for the other two.

type Store

type Store interface {
	Resolve(ctx context.Context, ref Reference) (string, error)
}

Store resolves a Reference to its actual secret value.

type WritableStore

type WritableStore interface {
	Set(ctx context.Context, key, value string) error
	Remove(ctx context.Context, key string) error
}

WritableStore is a Store an operator can also write to directly — KeychainStore and FileStore, not EnvStore (an "env" reference is provisioned by however the process's environment gets set, never through this package). internal/cli's `secret set`/`secret remove` commands are the only callers.

Jump to

Keyboard shortcuts

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