keychain

package
v1.0.54 Latest Latest
Warning

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

Go to latest
Published: Jul 21, 2026 License: Apache-2.0 Imports: 13 Imported by: 0

Documentation

Overview

Package keychain provides cross-platform secure storage for secrets. - macOS: System Keychain stores DEK (Data Encryption Key), data encrypted with AES-256-GCM - Linux: File-based DEK storage with AES-256-GCM encryption - Windows: DPAPI + Registry storage

Index

Constants

View Source
const (
	// Service is the unified keychain service name for all secrets.
	Service = "dws-cli"

	// AccountToken is the account key for storing auth token data.
	AccountToken = "auth-token"

	// StorageDirEnv overrides the on-disk keychain storage root on
	// platforms that use file-backed storage (macOS, Linux). It is
	// intended for tests that need to isolate keychain state from the
	// real user environment and from sibling test packages running in
	// parallel. When empty, the platform default applies.
	StorageDirEnv = "DWS_KEYCHAIN_DIR"

	// TestNamespaceEnv isolates the Windows HKCU registry backend for tests.
	// Production code must not set it. Other platforms already isolate secure
	// storage through StorageDirEnv and ignore this value.
	TestNamespaceEnv = "DWS_KEYCHAIN_TEST_NAMESPACE"

	// DisableKeychainEnv opts the macOS implementation out of system
	// Keychain access for the DEK, falling back to a file-based DEK
	// (same scheme as Linux). Intended for sandboxed runtimes where
	// Keychain APIs are blocked (e.g. Codex App). This weakens the
	// at-rest protection — DEK and ciphertext live in the same
	// directory — and is therefore opt-in.
	DisableKeychainEnv = "DWS_DISABLE_KEYCHAIN"
)

Variables

View Source
var (
	// ErrDEKMissing means encrypted local data may exist, but the Data Encryption
	// Key needed to decrypt it is missing. Read paths must not create a new DEK,
	// because a fresh key cannot decrypt existing ciphertext.
	ErrDEKMissing = errors.New("dek missing")

	// ErrCiphertextKeyMismatch means encrypted data exists but none of the
	// available DEKs can decrypt it. Write paths must not overwrite the data.
	ErrCiphertextKeyMismatch = errors.New("ciphertext key mismatch")
)

Functions

func CleanupLegacyBackup

func CleanupLegacyBackup(configDir string) error

CleanupLegacyBackup removes the backup file created during migration. Call this after confirming the new keychain storage works correctly.

func Exists

func Exists(service, account string) bool

Exists checks if an entry exists in the keychain.

func Get

func Get(service, account string) (string, error)

Get retrieves a value from the keychain. Returns empty string and nil error if the entry does not exist.

func HasLegacyData

func HasLegacyData(configDir string) bool

HasLegacyData checks if legacy .data file exists.

func IsCiphertextKeyMismatch added in v1.0.52

func IsCiphertextKeyMismatch(err error) bool

func IsDEKMissing added in v1.0.51

func IsDEKMissing(err error) bool

func IsUnavailable added in v1.0.51

func IsUnavailable(err error) bool

func MigrateToFileDEK added in v1.0.52

func MigrateToFileDEK(service string, dryRun bool) (int, error)

MigrateToFileDEK re-encrypts the legacy and profile-scoped auth token entries for service with the macOS file DEK. It is supported only on macOS and must be invoked from a process that can still access the system Keychain. When dryRun is true, all selected entries are validated without modifying data.

func NewUnavailableError added in v1.0.51

func NewUnavailableError(op string, err error) error

func Remove

func Remove(service, account string) error

Remove deletes an entry from the keychain. Returns nil if the entry does not exist.

func RemoveAuthTokenEntries added in v1.0.54

func RemoveAuthTokenEntries(service string) error

RemoveAuthTokenEntries deletes the legacy token plus every organization and identity scoped auth-token entry for service. Other keychain accounts are preserved.

func Set

func Set(service, account, data string) error

Set stores a value in the keychain, overwriting any existing entry.

func StorageDir

func StorageDir(service string) string

StorageDir returns the storage directory for a given service name. Follows XDG Base Directory Specification: ~/.local/share/<service>. When the DWS_KEYCHAIN_DIR environment variable is set (used by tests for isolation), the storage root is taken from that env var instead.

func ValidateAuthTokenEntries added in v1.0.52

func ValidateAuthTokenEntries(service string) error

ValidateAuthTokenEntries verifies every persisted auth-token ciphertext, including profile slots not yet registered in profiles.json, without creating or rotating key material.

Types

type Diagnostic added in v1.0.51

type Diagnostic struct {
	OK      bool              `json:"ok"`
	Reason  string            `json:"reason,omitempty"`
	Message string            `json:"message"`
	Hint    string            `json:"hint,omitempty"`
	Detail  map[string]string `json:"detail,omitempty"`
}

Diagnostic is a read-only health report for the platform keychain backend. It never mutates credentials, DEKs, or OS keychain settings.

func Diagnose added in v1.0.51

func Diagnose() Diagnostic

type KeychainAccess

type KeychainAccess interface {
	Get(service, account string) (string, error)
	Set(service, account, value string) error
	Remove(service, account string) error
}

KeychainAccess abstracts keychain Get/Set/Remove for dependency injection.

type MigrationResult

type MigrationResult struct {
	Migrated    bool   // true if migration was performed
	FromPath    string // source file path
	BackupPath  string // backup file path (if migrated)
	Error       error  // error if migration failed
	NeedRelogin bool   // true if user needs to re-login
}

MigrationResult contains the result of a migration attempt.

func MigrateFromLegacy

func MigrateFromLegacy(configDir string) *MigrationResult

MigrateFromLegacy attempts to migrate from the legacy MAC-based encryption to the new keychain-based storage. It: 1. Checks if legacy .data file exists 2. Tries to decrypt with MAC address 3. Re-encrypts and stores in keychain 4. Backs up the old file

If the keychain already has data, migration is skipped. If the legacy file doesn't exist, migration is skipped. If decryption fails (wrong MAC/corrupted), returns NeedRelogin=true.

type UnavailableError added in v1.0.51

type UnavailableError struct {
	Op  string
	Err error
}

UnavailableError marks failures where the platform keychain itself could not be reached, unlocked, or created. Callers can surface a diagnostic instead of treating the result as a normal missing credential.

func (*UnavailableError) Error added in v1.0.51

func (e *UnavailableError) Error() string

func (*UnavailableError) Unwrap added in v1.0.51

func (e *UnavailableError) Unwrap() error

Jump to

Keyboard shortcuts

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