secretstore

package
v0.3.0 Latest Latest
Warning

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

Go to latest
Published: Jun 10, 2026 License: MIT Imports: 5 Imported by: 0

Documentation

Overview

Package secretstore provides a pluggable backend for storing the user's CLI bearer token. The default backend is the OS keychain (macOS Keychain, Linux Secret Service / libsecret, Windows Credential Manager); a plaintext file fallback is used when the keychain is unavailable (headless Linux, disabled service, sandboxed environment).

Why two backends?

  • The keychain is the right place for a long-lived production credential. A user's API key has no expiry and full team scope today, so a copy of it sitting in `~/.instant-config` mode 0600 is read by anything running as that user (backup tools, IDE extensions, malware, …). T16 P1-1.

  • We can't refuse to run in CI / SSH / Linux-no-DBus environments — the CLI must still work. So when the keychain reports "unavailable" we fall back to the existing file mechanism, with a clear stderr warning the first time so the user knows their token is on disk.

The interface deliberately stays tiny — Get / Set / Delete — so the test suite can swap in an in-memory implementation without touching the real keychain.

Index

Constants

View Source
const AccountName = "api_key"

AccountName is the keychain "account" we register the bearer token under. One CLI install -> one keychain entry (no per-profile multi-tenancy today).

View Source
const ServiceName = "instanode.dev"

ServiceName is the keychain "service" name we register under. macOS shows this as the Keychain item's Name; Linux secret-service treats it as the schema's "service" attribute; Windows Credential Manager shows it as the target name's prefix.

Variables

View Source
var ErrNotFound = errors.New("secretstore: no secret found")

ErrNotFound is returned when no secret has been stored yet. Callers should treat it as "anonymous mode" (no token), not as a fatal error.

Functions

func Delete

func Delete() error

Delete removes any stored secret. Idempotent.

func Get

func Get() (string, error)

Get returns the stored secret using the active backend. ErrNotFound means no secret has been written (anonymous mode).

func Name

func Name() string

Name returns a label for the active backend ("keychain", "memory", "file-fallback"). Used by `whoami` so the user can see where their secret lives.

func Set

func Set(value string) error

Set persists the secret using the active backend.

func TruncateForDisplay

func TruncateForDisplay(s string) string

TruncateForDisplay returns a safe-to-print prefix of a credential — at most 8 characters followed by an ellipsis. Never use this for anything security-sensitive; it's purely for "is the right account logged in?" UX.

Callers MUST use this for any UI that surfaces the key (whoami, list, ...). The previous CLI printed the first 16 characters of the key directly; the audit (T16 P1-1) flagged that as material disclosure.

func Use

func Use(b Backend)

Use installs a specific backend. Primarily used by tests; production code calls UseDefault.

Types

type Backend

type Backend interface {
	// Get returns the stored secret, or ErrNotFound if none exists.
	Get() (string, error)
	// Set persists the secret. An empty value is equivalent to Delete.
	Set(value string) error
	// Delete removes any stored secret. It must be idempotent (no error
	// when the key was already absent).
	Delete() error
	// Name returns a short label ("keychain", "memory", "file-fallback").
	// Surfaced by `whoami` so the user knows where their key lives.
	Name() string
	// Available reports whether the backend is usable in the current
	// environment. A false here causes the chain to walk to the next backend.
	Available() bool
}

Backend is the minimal interface every secret store must satisfy. The concrete types are kept inside this package so tests in the same package can swap them.

func UseDefault

func UseDefault() Backend

UseDefault selects the keychain if available, otherwise leaves any already-installed backend in place — the caller (cliconfig) handles file fallback when this returns nil. We split the "keychain backend" from "file fallback" because the file is owned by the cliconfig package (it already does atomic writes and 0600 mode); we don't duplicate that here.

IMPORTANT: UseDefault does NOT clobber a previously-installed backend (e.g. the in-memory backend that the test suite installs in TestMain). If you want to force a reset, call Use(nil) first.

type MemoryBackend

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

MemoryBackend keeps the secret in a process-local string. Use only in tests.

func UseMemoryBackend

func UseMemoryBackend() *MemoryBackend

UseMemoryBackend installs an in-memory backend. Tests should call this in TestMain so the real OS keychain is never touched by the suite.

func (*MemoryBackend) Available

func (m *MemoryBackend) Available() bool

func (*MemoryBackend) Delete

func (m *MemoryBackend) Delete() error

func (*MemoryBackend) Get

func (m *MemoryBackend) Get() (string, error)

func (*MemoryBackend) Name

func (m *MemoryBackend) Name() string

func (*MemoryBackend) Set

func (m *MemoryBackend) Set(value string) error

Jump to

Keyboard shortcuts

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