credentials

package
v0.17.21 Latest Latest
Warning

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

Go to latest
Published: Aug 29, 2026 License: MIT Imports: 17 Imported by: 0

Documentation

Overview

Encryption and decryption operations

Machine key management and encryption status

Store persistence, loading, saving, and migration

Package credentials provides unified credential resolution for all providers. This package contains the single source of truth for environment variable names and credential resolution logic, replacing the hardcoded strings previously scattered across multiple files.

Package credentials provides unified credential resolution for all providers. This package contains the single source of truth for environment variable names and credential resolution logic, replacing the hardcoded strings previously scattered across multiple files.

Index

Constants

View Source
const MaxDecryptedSize = 10 << 20 // 10 MB

MaxDecryptedSize is the maximum size of decrypted API keys data (10 MB). This limit prevents memory exhaustion attacks from crafted encrypted files.

View Source
const MaxEncryptedSize = MaxDecryptedSize + (10 << 20) // 20 MB

MaxEncryptedSize is the maximum size of encrypted API keys data (20 MB). This limit prevents memory exhaustion attacks from crafted encrypted files. It accounts for the MaxDecryptedSize plus age encryption overhead (~10 MB).

View Source
const MaxPoolEntries = 100

MaxPoolEntries is the maximum number of pool entries to probe/cleanup for the keyring backend. This is a practical upper bound for pool sizes.

Variables

View Source
var DefaultRotator = NewKeyRotator()

DefaultRotator is the package-level default rotator for use by the resolution layer and other components.

Functions

func AddKeyToPool

func AddKeyToPool(provider, key string) error

AddKeyToPool adds a key to a provider's pool. Duplicates are rejected (exact string match after trim). If the pool was previously a single key (plain string format), it will be converted to JSON array format.

func AtomicModify

func AtomicModify(fn func(Store) error) error

AtomicModify acquires an exclusive lock, loads the API keys store, calls fn to modify it, and saves it back. The entire load-modify-save cycle is protected by the exclusive lock, preventing TOCTOU races. Uses a 15-second timeout to account for slow encryption operations.

func AtomicModifyForDir

func AtomicModifyForDir(configDir string, fn func(Store) error) error

AtomicModifyForDir acquires an exclusive lock, loads the API keys store from a specific config directory, calls fn to modify it, and saves it back. The entire load-modify-save cycle is protected by the exclusive lock, preventing TOCTOU races. Uses a 15-second timeout to account for slow encryption operations.

func AtomicWriteFile

func AtomicWriteFile(path string, data []byte, perm os.FileMode) error

AtomicWriteFile writes data to a file atomically using temp file + rename pattern. This prevents data corruption if the process crashes during the write. The file is created with the specified permissions.

func ConfigDir added in v0.17.17

func ConfigDir() (string, error)

ConfigDir returns the credentials directory, creating it if it doesn't exist. SP-133: credentials now live in <config>/credentials/ (mode 0700), isolated from the config dir so "don't sync / don't bundle" is a one-line path rule. The legacy ~/.sprout path is no longer used.

func DecryptStore

func DecryptStore(data []byte) ([]byte, error)

DecryptStore decrypts age-encrypted data, or returns raw bytes if plaintext.

This function first checks if the data is plaintext JSON (for backward compatibility with legacy unencrypted files). If the data is encrypted, it attempts to decrypt it using the machine-specific key.

Returns the decrypted data as a byte slice. If decryption fails due to a missing machine key, an error is returned with guidance on how to resolve the issue.

Maximum decrypted size is limited to 10 MB to prevent memory exhaustion attacks.

func DecryptWithPassphrase

func DecryptWithPassphrase(data []byte, passphrase string) ([]byte, error)

DecryptWithPassphrase decrypts data using a passphrase-derived key.

This function derives the decryption key from the provided passphrase using the same Scrypt algorithm used during encryption. It sets a maximum work factor of 15 to prevent denial-of-service attacks from maliciously crafted encrypted data with extremely high work factors.

Returns the decrypted data as a byte slice. Returns an error if the passphrase is incorrect or if the data cannot be decrypted.

Maximum decrypted size is limited to 10 MB to prevent memory exhaustion attacks.

func DeleteFromActiveBackend

func DeleteFromActiveBackend(provider string) error

DeleteFromActiveBackend deletes a credential using the active backend.

func DeleteProviderPool

func DeleteProviderPool(provider string) error

DeleteProviderPool removes all keys for a provider by saving an empty pool. This is the thread-safe way to delete a provider's entire pool — it holds poolMu for the full Load→modify→Save sequence. Use this from other packages instead of calling SaveKeyPool with an empty pool directly.

func EncryptStore

func EncryptStore(plaintext []byte) ([]byte, error)

EncryptStore encrypts plaintext data using the machine-specific X25519 key.

This function ensures the machine key exists (generating it if necessary), then encrypts the provided plaintext using age encryption. The encrypted output is returned as a byte slice.

Use this function when you want to encrypt data with the machine-specific key that is stored in ~/.config/sprout/key.age.

func EncryptWithPassphrase

func EncryptWithPassphrase(plaintext []byte, passphrase string) ([]byte, error)

EncryptWithPassphrase encrypts plaintext data using a passphrase-derived key.

This function uses the age library's Scrypt algorithm to derive an encryption key from the provided passphrase. It uses a work factor of 12, which provides a good balance between security and performance (~1 second on modern hardware).

The encrypted output can be decrypted using DecryptWithPassphrase with the same passphrase. This mode is useful for portable encryption where the same encrypted data needs to be accessed from multiple machines.

func GetAPIKeysLockPath

func GetAPIKeysLockPath() (string, error)

GetAPIKeysLockPath returns the path to the API keys lock file.

func GetAPIKeysLockPathFromDir

func GetAPIKeysLockPathFromDir(configDir string) (string, error)

GetAPIKeysLockPathFromDir returns the path to the API keys lock file in a specific config directory.

func GetAPIKeysPath

func GetAPIKeysPath() (string, error)

GetAPIKeysPath returns the path to the API keys file.

func GetAPIKeysPathFromDir

func GetAPIKeysPathFromDir(configDir string) (string, error)

GetAPIKeysPathFromDir returns the path to the API keys file in a specific config directory.

func GetBackendModePath

func GetBackendModePath() (string, error)

GetBackendModePath returns the path to the backend mode file. This is the exported version of getBackendModePath() for use by external packages.

func GetConfigDir deprecated

func GetConfigDir() (string, error)

GetConfigDir returns the configuration directory path, creating it if it doesn't exist.

Deprecated: use ConfigDir(). Retained for callers that haven't been migrated.

func GetEncryptionMode

func GetEncryptionMode() (string, error)

GetEncryptionMode returns the current encryption mode ("machine-key", "passphrase", or ""). Returns an empty string if no mode file exists (legacy or plaintext files).

func GetEncryptionModeFromDir

func GetEncryptionModeFromDir(configDir string) (string, error)

GetEncryptionModeFromDir returns the current encryption mode from a specific config directory. Returns an empty string if no mode file exists (legacy or plaintext files).

func GetFromActiveBackend

func GetFromActiveBackend(provider string) (string, string, error)

GetFromActiveBackend gets a credential using the active backend. Returns the value, source ("keyring" or "file"), and error.

func GetMachineKeyPath

func GetMachineKeyPath() (string, error)

GetMachineKeyPath returns the path to the machine key file.

func GetMachineKeyPathFromDir

func GetMachineKeyPathFromDir(configDir string) (string, error)

GetMachineKeyPathFromDir returns the path to the machine key file in a specific config directory.

func GetNextKey

func GetNextKey(provider string) (string, error)

GetNextKey is a convenience function that gets the next key from the default rotator. It loads the pool and returns the next key using round-robin.

func GetPoolSize

func GetPoolSize(provider string) (int, error)

GetPoolSize returns the number of keys in a provider's pool.

func GetStorageMode

func GetStorageMode() (string, error)

GetStorageMode returns the persisted storage mode ("keyring", "file", or ""). Returns empty string if no mode file exists (will be auto-detected on first use).

func HasProviderCredential

func HasProviderCredential(provider string) bool

HasProviderCredential checks if a provider has a configured API key. Uses ProviderInfoFunc callback (if registered) for env var and auth requirement lookup, falling back to built-in provider metadata. Returns true if the provider is always available (e.g., local providers) or if a non-empty credential is found via environment or stored credentials.

func IsKeyringAvailable

func IsKeyringAvailable() (available bool)

IsKeyringAvailable checks if the OS keyring is available for use. It is safe to call on any platform — panics from the underlying keyring library (e.g. on Android/Termux where no keyring service exists) are recovered and treated as "unavailable".

func IsPlaintextJSON

func IsPlaintextJSON(data []byte) bool

IsPlaintextJSON checks if the data is plaintext JSON (legacy unencrypted format).

func IsSensitiveEnvName

func IsSensitiveEnvName(name string) bool

IsSensitiveEnvName reports whether an environment variable name suggests it holds a credential. It reuses the heuristic from pkg/mcp but makes it available outside the mcp package.

NOTE: Do NOT import pkg/mcp from here (would create circular dependency since pkg/mcp already imports pkg/credentials). Instead, duplicate the simple keyword-list heuristic here.

func ListKeyringProviders

func ListKeyringProviders() ([]string, error)

ListKeyringProviders returns the list of providers that have entries in the keyring.

func LoadOrCreateMachineKey

func LoadOrCreateMachineKey() (*age.X25519Identity, error)

LoadOrCreateMachineKey loads the machine key from disk or generates a new one. Uses flock-based locking to prevent race conditions when multiple processes try to generate the key concurrently.

func MaskValue

func MaskValue(value string) string

MaskValue returns a masked version of the credential value for safe logging.

func MigrateFileToKeyring

func MigrateFileToKeyring(clearFile bool) ([]string, error)

MigrateFileToKeyring migrates all credentials from file store to keyring. Returns the list of providers that were migrated. If clearFile is true, removes all credentials from the file store after successful migration. On failure, rolls back any partially migrated credentials to prevent orphaned entries.

func MigrateKeyringToFile

func MigrateKeyringToFile(clearKeyring bool) ([]string, error)

MigrateKeyringToFile migrates all credentials from keyring to file store. Returns the list of providers that were migrated. If clearKeyring is true, removes all credentials from the keyring after successful migration. On failure, rolls back any partially migrated credentials to prevent orphaned entries.

func ProviderEnvVar

func ProviderEnvVar(provider string) string

ProviderEnvVar returns the standard environment variable name for a provider's API key. This provides a single source of truth for env var name mapping, replacing the hardcoded strings previously scattered across multiple files.

func RedactEnvMap

func RedactEnvMap(env map[string]string) map[string]string

RedactEnvMap returns a copy of env where values whose keys match IsSensitiveEnvName are replaced with "[REDACTED]". Non-sensitive values are kept as-is.

func RedactJSONBytes

func RedactJSONBytes(data []byte) ([]byte, error)

RedactJSONBytes applies credential redaction to JSON-encoded data. It unmarshals the data, recursively redacts string values, and re-marshals with indentation. Two redaction strategies are applied:

  1. Key-aware: map keys whose names match IsSensitiveEnvName have their string values replaced with "[REDACTED]" wholesale.
  2. Value-based: all string values are scanned by the secretdetect scanner (gitleaks-backed) and matched secrets are replaced with opaque "[REDACTED]" tokens.

Returns the redacted JSON bytes or an error if the input is not valid JSON.

func RedactMap

func RedactMap(m map[string]string) map[string]string

RedactMap returns a copy of m where every value is replaced with its masked form. Values that look like credential reference placeholders (e.g., "{{credential:...}}") are kept as-is since they are already safe indirect references, not actual secrets. Uses MaskValue for each value.

NOTE: MaskValue preserves the first 2–4 characters for debugging/verification purposes (e.g., "sk-a****"). This is intentional — it lets operators confirm the correct key is in place without exposing the full value. For fully opaque redaction (e.g., log exports), use RedactEnvMap or RedactJSONBytes instead.

func RemoveKeyFromPool

func RemoveKeyFromPool(provider, key string) error

RemoveKeyFromPool removes a specific key from a provider's pool. If only one key remains, it's stored as a plain string (backward compat format). Returns an error if the key is not found in the pool.

func RemoveKeyFromPoolByIndex

func RemoveKeyFromPoolByIndex(provider string, index int) error

RemoveKeyFromPoolByIndex removes the key at the given index from a provider's pool. Index is 0-based. This is the safe way to remove keys when the caller only has access to masked values (e.g., from a WebUI that displays masked keys). Returns an error if the index is out of bounds.

func ResetProviderInfoFunc

func ResetProviderInfoFunc()

ResetProviderInfoFunc clears the registered provider info callback. This is intended for use in tests to restore the default (callback-less) behavior.

func ResetStorageBackend

func ResetStorageBackend()

ResetStorageBackend resets the cached backend, forcing re-detection on next call. This is primarily useful for tests that need to verify different backend configurations.

func ResolveProviderAPIKey

func ResolveProviderAPIKey(provider, displayName string) (string, error)

ResolveProviderAPIKey resolves a provider's API key and validates it's non-empty. This is a convenience wrapper around ResolveProvider that returns just the key value with a clear error message when no credential is available.

This eliminates the duplicated "resolve → check empty → format error" pattern previously scattered across multiple files.

func RotateKey

func RotateKey(provider string)

RotateKey advances the default rotator for a provider by one position. Callers can use this to manually skip a key without going through the full resolve path. (The rate-limit handler uses RefreshAPIKey instead, which resolves and auto-advances via NextKey.)

func RotateProviderKey

func RotateProviderKey(provider string)

RotateProviderKey advances the key rotation for a provider. Call this when a 429 rate-limit error is encountered to skip to the next key.

func Save

func Save(store Store) error

Save saves the API keys store to disk, encrypting it first.

This function marshals the Store to JSON, encrypts it using the appropriate encryption mode (machine-key or passphrase), and writes the encrypted data to the configured API keys file.

The file is created with permissions 0600 (read/write for owner only) to ensure API keys are stored securely on disk. The write is atomic (using a temp file + rename) to prevent data corruption if the process crashes during the write.

If the API keys are passphrase-encrypted, this function requires the SPROUT_KEY_PASSPHRASE environment variable to be set. Otherwise, it returns an error directing the user to set the environment variable or switch to machine-key mode.

func SaveKeyPool

func SaveKeyPool(provider string, pool *KeyPool) error

SaveKeyPool saves the key pool to the active backend. For file backend, stores as JSON array if len > 1, plain string if len == 1. For keyring backend, stores provider (first key), provider__pool_1, etc. Cleans up removed pool entries (only for keyring backend). Note: The caller must hold poolMu when calling this function.

func SaveToDir

func SaveToDir(store Store, configDir string) error

SaveToDir saves the API keys store to a specific config directory, encrypting it first.

This function is like Save() but takes an explicit config directory instead of reading from environment variables. It's useful for test environments and other scenarios where you want to save to a specific location without mutating process state.

Uses flock-based locking to prevent race conditions when multiple processes write to the file concurrently.

func SetEncryptionMode

func SetEncryptionMode(mode string) error

SetEncryptionMode writes the encryption mode file. mode should be "machine-key" or "passphrase".

func SetEncryptionModeForDir

func SetEncryptionModeForDir(configDir, mode string) error

SetEncryptionModeForDir writes the encryption mode file in a specific config directory. mode should be "machine-key" or "passphrase".

func SetPackageDebugLogging added in v0.16.8

func SetPackageDebugLogging(enabled bool)

SetPackageDebugLogging toggles the debug gate at runtime (for the agent's --debug flag wiring and tests).

func SetProviderInfoFunc

func SetProviderInfoFunc(fn ProviderInfoFunc)

SetProviderInfoFunc registers a callback for looking up provider metadata. This is called by higher-level packages to provide env var names and auth requirements for custom/built-in providers.

The callback is invoked lazily at resolution time (not at registration time), so it can rely on runtime state (e.g., loaded config files).

IMPORTANT: This must be called before any credential resolution function (ResolveProvider, HasProviderCredential, etc.) is invoked. Typically this happens automatically via configuration.init() when the configuration package is imported. In test code that doesn't import configuration, no callback is registered and the built-in fallback metadata is used.

Use ResetProviderInfoFunc() in tests to clear the callback.

func SetStorageMode

func SetStorageMode(mode string) error

SetStorageMode persists the storage mode. mode must be "keyring" or "file".

func SetToActiveBackend

func SetToActiveBackend(provider, value string) error

SetToActiveBackend sets a credential using the active backend.

Types

type Backend

type Backend interface {
	// Get retrieves a credential for the given provider.
	// Returns empty string and no error if the provider has no stored credential.
	// Returns an error only for backend-specific failures (e.g., keyring unavailable).
	Get(provider string) (string, error)

	// Set stores a credential for the given provider.
	Set(provider, value string) error

	// Delete removes a credential for the given provider.
	// Returns no error if the provider has no stored credential.
	Delete(provider string) error

	// Source returns the source identifier for this backend (e.g., "keyring", "stored").
	Source() string
}

Backend interface defines the contract for credential storage backends. Implementations can be OS keyring, encrypted file store, or any other backend.

func GetStorageBackend

func GetStorageBackend() (Backend, error)

GetStorageBackend returns the active backend based on configuration and auto-detection. Resolution order: 1. If SPROUT_CREDENTIAL_BACKEND=keyring → OSKeyringBackend 2. If SPROUT_CREDENTIAL_BACKEND=file → FileBackend 3. Auto-detect: try OSKeyringBackend.Get("__sprout_probe__") to check availability

  • If available → use OSKeyringBackend (persist mode as "keyring")
  • If unavailable → fallback to FileBackend (persist mode as "file")

The backend is resolved once per process lifetime using sync.Once caching. Call ResetStorageBackend() to force re-detection (useful for tests).

type EncryptionStatus

type EncryptionStatus struct {
	Encrypted        bool
	Mode             string // "machine-key", "passphrase", or "plaintext"
	MachineKeyExists bool
}

EncryptionStatus describes the current encryption state of the API keys file.

func CheckEncryptionStatus

func CheckEncryptionStatus() (EncryptionStatus, error)

CheckEncryptionStatus returns the current encryption status of the API keys file.

This function analyzes the API keys file to determine: - Whether the file is encrypted or in plaintext - The encryption mode (machine-key, passphrase, or plaintext) - Whether a machine key exists on disk

Note: The Mode field is a best-effort heuristic. It cannot definitively distinguish between passphrase-encrypted and foreign-encrypted data without attempting decryption. If a machine key exists, it reports "machine-key" as the likely mode, but this may be incorrect if the data was encrypted with a different key.

type FileBackend

type FileBackend struct {
}

FileBackend wraps the existing encrypted file store as a Backend. This allows the Backend interface to be used uniformly for both keyring and file storage.

func NewFileBackend

func NewFileBackend() *FileBackend

NewFileBackend creates a new file backend.

func (*FileBackend) Delete

func (b *FileBackend) Delete(provider string) error

Delete removes a credential from the encrypted file store. Uses AtomicModify to ensure the load-modify-save cycle is atomic, preventing TOCTOU races when multiple processes modify the store concurrently.

func (*FileBackend) Get

func (b *FileBackend) Get(provider string) (string, error)

Get retrieves a credential from the encrypted file store.

func (*FileBackend) Set

func (b *FileBackend) Set(provider, value string) error

Set stores a credential in the encrypted file store. Uses AtomicModify to ensure the load-modify-save cycle is atomic, preventing TOCTOU races when multiple processes modify the store concurrently.

func (*FileBackend) Source

func (b *FileBackend) Source() string

Source returns the source identifier for FileBackend.

type KeyPool

type KeyPool struct {
	Keys []string // Ordered list of keys (never nil, may be empty)
}

KeyPool manages multiple keys for a single provider. Keys are stored in order. Rotation state is managed separately by KeyRotator.

type KeyPoolResult

type KeyPoolResult struct {
	Pool   *KeyPool
	Source string // Backend source ("keyring", "stored", "" if not found)
}

LoadKeyPool loads all keys for a provider from the active backend. For file backend, checks if value is JSON array string. KeyPoolResult holds the result of loading a key pool, including its source.

func LoadKeyPool

func LoadKeyPool(provider string) (*KeyPoolResult, error)

LoadKeyPool loads all keys for a provider from the active backend. For file backend, the stored value may be a JSON array or a plain string. For keyring backend, probes for provider__pool_N entries after the primary key. Returns a pool with 0 keys if no keys are found (no error). Returns an error only for backend failures (e.g., config dir inaccessible). Falls back to direct Load() if the active backend is unavailable.

type KeyRotator

type KeyRotator struct {
	// contains filtered or unexported fields
}

KeyRotator manages round-robin rotation across providers. It is thread-safe and uses in-memory state (per-process lifetime). The rotator tracks which key index should be used next for each provider.

func NewKeyRotator

func NewKeyRotator() *KeyRotator

NewKeyRotator creates a new KeyRotator instance with initialized state. The counters map is created here to ensure it's never nil.

func (*KeyRotator) Advance

func (r *KeyRotator) Advance(provider string)

Advance manually advances the rotation counter by 1 for a provider. This is useful when a caller wants to skip a key (e.g., manual rejection). The counter is incremented without bounds; NextKey applies modular arithmetic when selecting from the pool.

Note: NextKey() also auto-advances the counter after each call, so calling Advance immediately after NextKey will skip two positions, not one.

func (*KeyRotator) CurrentIndex

func (r *KeyRotator) CurrentIndex(provider string) int

CurrentIndex returns the current rotation index for a provider. Returns -1 if the provider has no tracked counter.

func (*KeyRotator) NextKey

func (r *KeyRotator) NextKey(provider string, pool *KeyPool) string

NextKey returns the next key using round-robin rotation. Advances the counter for the provider. If pool is empty, returns "". If pool has one key, always returns it. The rotator state is updated to track the next key to use.

func (*KeyRotator) Reset

func (r *KeyRotator) Reset(provider string)

Reset resets the rotation counter for a provider to 0. This is useful after a successful key validation or when you want to start rotation from the beginning.

type OSKeyringBackend

type OSKeyringBackend struct {
	// contains filtered or unexported fields
}

OSKeyringBackend wraps go-keyring for OS-native credential storage. It uses the system keyring (GNOME Keyring, macOS Keychain, Windows Credential Manager, etc.)

func NewOSKeyringBackend

func NewOSKeyringBackend() *OSKeyringBackend

NewOSKeyringBackend creates a new OS keyring backend.

func (*OSKeyringBackend) Delete

func (b *OSKeyringBackend) Delete(provider string) error

Delete removes a credential from the OS keyring. Returns no error if the credential doesn't exist.

func (*OSKeyringBackend) Get

func (b *OSKeyringBackend) Get(provider string) (string, error)

Get retrieves a credential from the OS keyring. Returns empty string and no error if the credential doesn't exist. Returns an error if the keyring is unavailable or another backend error occurs.

func (*OSKeyringBackend) Set

func (b *OSKeyringBackend) Set(provider, value string) error

Set stores a credential in the OS keyring.

func (*OSKeyringBackend) Source

func (b *OSKeyringBackend) Source() string

Source returns the source identifier for OSKeyringBackend.

type ProviderInfo

type ProviderInfo struct {
	EnvVar         string // Environment variable name for the provider's API key
	RequiresAPIKey bool   // Whether the provider requires an API key
}

ProviderInfo holds metadata about a provider needed for credential resolution. Higher-level packages (e.g., configuration) register a ProviderInfoFunc callback to supply provider-specific env var names and auth requirements.

type ProviderInfoFunc

type ProviderInfoFunc func(provider string) ProviderInfo

ProviderInfoFunc looks up provider metadata by provider name. Returns zero-value ProviderInfo if the provider is unknown.

type Resolved

type Resolved struct {
	Provider string
	EnvVar   string
	Value    string
	Source   string
}

Resolved contains a resolved credential with source information.

func ResolveProvider

func ResolveProvider(provider string) (Resolved, error)

ResolveProvider resolves a credential for a provider using the unified resolution chain. This is the single authoritative function for credential resolution.

IMPORTANT: Requires SetProviderInfoFunc to have been called (typically by configuration.init()) to properly resolve custom provider env vars. If no callback is registered, falls back to built-in provider metadata.

Resolution precedence:

  1. Environment variable (looked up via ProviderInfoFunc or built-in metadata)
  2. Keyring backend (if active)
  3. Encrypted file store

For providers that don't require API keys (local providers), returns immediately with Source="none" and Value="".

Returns credentials.Resolved with the value and source.

func (Resolved) String

func (r Resolved) String() string

String returns a safe string representation with the value always masked.

type StorageMode

type StorageMode string

StorageMode represents the active credential storage backend. Valid values: "keyring", "file", "" (unset/auto-detect)

const (
	// StorageModeKeyring uses OS-native keyring (GNOME Keyring, macOS Keychain, Windows Credential Manager)
	StorageModeKeyring StorageMode = "keyring"
	// StorageModeFile uses encrypted JSON file storage
	StorageModeFile StorageMode = "file"
	// StorageModeUnset means auto-detect on first use
	StorageModeUnset StorageMode = ""
)

type Store

type Store map[string]string

Store holds the encrypted API key store.

func Load

func Load() (Store, error)

Load loads the API keys store from disk.

This function reads the API keys file from the configured location, decrypts it if necessary (supporting both machine-key and passphrase encryption modes), and unmarshals the JSON into a Store.

If the file does not exist, an empty Store is returned without error. This allows the application to start cleanly even if no API keys have been configured yet.

Uses flock-based locking to prevent race conditions when multiple processes read the file concurrently.

func LoadFromDir

func LoadFromDir(configDir string) (Store, error)

LoadFromDir loads the API keys store from a specific config directory.

This function is like Load() but takes an explicit config directory instead of reading from environment variables. It's useful for test environments and other scenarios where you want to load from a specific location without mutating process state.

Uses flock-based locking to prevent race conditions when multiple processes read the file concurrently.

Jump to

Keyboard shortcuts

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