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
- Variables
- func AddKeyToPool(provider, key string) error
- func AtomicModify(fn func(Store) error) error
- func AtomicModifyForDir(configDir string, fn func(Store) error) error
- func AtomicWriteFile(path string, data []byte, perm os.FileMode) error
- func DecryptStore(data []byte) ([]byte, error)
- func DecryptWithPassphrase(data []byte, passphrase string) ([]byte, error)
- func DeleteFromActiveBackend(provider string) error
- func DeleteProviderPool(provider string) error
- func EncryptStore(plaintext []byte) ([]byte, error)
- func EncryptWithPassphrase(plaintext []byte, passphrase string) ([]byte, error)
- func GetAPIKeysLockPath() (string, error)
- func GetAPIKeysLockPathFromDir(configDir string) (string, error)
- func GetAPIKeysPath() (string, error)
- func GetAPIKeysPathFromDir(configDir string) (string, error)
- func GetBackendModePath() (string, error)
- func GetConfigDir() (string, error)
- func GetEncryptionMode() (string, error)
- func GetEncryptionModeFromDir(configDir string) (string, error)
- func GetFromActiveBackend(provider string) (string, string, error)
- func GetMachineKeyPath() (string, error)
- func GetMachineKeyPathFromDir(configDir string) (string, error)
- func GetNextKey(provider string) (string, error)
- func GetPoolSize(provider string) (int, error)
- func GetStorageMode() (string, error)
- func HasProviderCredential(provider string) bool
- func IsKeyringAvailable() (available bool)
- func IsPlaintextJSON(data []byte) bool
- func IsSensitiveEnvName(name string) bool
- func ListKeyringProviders() ([]string, error)
- func LoadOrCreateMachineKey() (*age.X25519Identity, error)
- func MaskValue(value string) string
- func MigrateFileToKeyring(clearFile bool) ([]string, error)
- func MigrateKeyringToFile(clearKeyring bool) ([]string, error)
- func ProviderEnvVar(provider string) string
- func RedactEnvMap(env map[string]string) map[string]string
- func RedactJSONBytes(data []byte) ([]byte, error)
- func RedactMap(m map[string]string) map[string]string
- func RemoveKeyFromPool(provider, key string) error
- func RemoveKeyFromPoolByIndex(provider string, index int) error
- func ResetProviderInfoFunc()
- func ResetStorageBackend()
- func ResolveProviderAPIKey(provider, displayName string) (string, error)
- func RotateKey(provider string)
- func RotateProviderKey(provider string)
- func Save(store Store) error
- func SaveKeyPool(provider string, pool *KeyPool) error
- func SaveToDir(store Store, configDir string) error
- func SetEncryptionMode(mode string) error
- func SetEncryptionModeForDir(configDir, mode string) error
- func SetPackageDebugLogging(enabled bool)
- func SetProviderInfoFunc(fn ProviderInfoFunc)
- func SetStorageMode(mode string) error
- func SetToActiveBackend(provider, value string) error
- type Backend
- type EncryptionStatus
- type FileBackend
- type KeyPool
- type KeyPoolResult
- type KeyRotator
- type OSKeyringBackend
- type ProviderInfo
- type ProviderInfoFunc
- type Resolved
- type StorageMode
- type Store
Constants ¶
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.
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).
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 ¶
var DefaultRotator = NewKeyRotator()
DefaultRotator is the package-level default rotator for use by the resolution layer and other components.
Functions ¶
func AddKeyToPool ¶
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 ¶
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 ¶
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 ¶
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 DecryptStore ¶
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 ¶
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 ¶
DeleteFromActiveBackend deletes a credential using the active backend.
func DeleteProviderPool ¶
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 ¶
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 ¶
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 ¶
GetAPIKeysLockPath returns the path to the API keys lock file.
func GetAPIKeysLockPathFromDir ¶
GetAPIKeysLockPathFromDir returns the path to the API keys lock file in a specific config directory.
func GetAPIKeysPath ¶
GetAPIKeysPath returns the path to the API keys file.
func GetAPIKeysPathFromDir ¶
GetAPIKeysPathFromDir returns the path to the API keys file in a specific config directory.
func GetBackendModePath ¶
GetBackendModePath returns the path to the backend mode file. This is the exported version of getBackendModePath() for use by external packages.
func GetConfigDir ¶
GetConfigDir returns the configuration directory path, creating it if it doesn't exist.
func GetEncryptionMode ¶
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 ¶
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 ¶
GetFromActiveBackend gets a credential using the active backend. Returns the value, source ("keyring" or "file"), and error.
func GetMachineKeyPath ¶
GetMachineKeyPath returns the path to the machine key file.
func GetMachineKeyPathFromDir ¶
GetMachineKeyPathFromDir returns the path to the machine key file in a specific config directory.
func GetNextKey ¶
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 ¶
GetPoolSize returns the number of keys in a provider's pool.
func GetStorageMode ¶
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 ¶
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 ¶
IsPlaintextJSON checks if the data is plaintext JSON (legacy unencrypted format).
func IsSensitiveEnvName ¶
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 ¶
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 MigrateFileToKeyring ¶
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 ¶
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 ¶
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 ¶
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 ¶
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:
- Key-aware: map keys whose names match IsSensitiveEnvName have their string values replaced with "[REDACTED]" wholesale.
- 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 ¶
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 ¶
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 ¶
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 ¶
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 ¶
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 ¶
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 ¶
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 ¶
SetEncryptionMode writes the encryption mode file. mode should be "machine-key" or "passphrase".
func SetEncryptionModeForDir ¶
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 ¶
SetStorageMode persists the storage mode. mode must be "keyring" or "file".
func SetToActiveBackend ¶
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 ¶
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 (*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 ¶
Resolved contains a resolved credential with source information.
func ResolveProvider ¶
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:
- Environment variable (looked up via ProviderInfoFunc or built-in metadata)
- Keyring backend (if active)
- 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.
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 ¶
Store holds the encrypted API key store.
func Load ¶
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 ¶
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.