store

package
v0.6.5 Latest Latest
Warning

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

Go to latest
Published: Jul 9, 2026 License: MIT Imports: 6 Imported by: 0

Documentation

Overview

Package store is arca's on-disk secret store: a single JSON document holding cleartext metadata plus per-value age ciphertext.

Why JSON (and not, say, SQLite) for the store:

  • it diffs and merges in git, so the store can live in a dotfiles repo as the source of truth, and `git log` gives a free "created/modified" history;
  • metadata (names, tags, descriptions) stays human-readable, so `ls`/`show` can answer questions without ever decrypting a value.

Read tracking deliberately does NOT live here — it goes to the separate (local) audit DB — so a `get` never rewrites this file and never churns git. The store therefore only changes on real mutations (set/rotate/rm), which is exactly what you want versioned.

Index

Constants

View Source
const Version = 1

Version is the on-disk schema version, bumped if the JSON shape ever changes incompatibly.

Variables

This section is empty.

Functions

This section is empty.

Types

type Secret

type Secret struct {
	Value           string            `json:"value"`                      // armored age ciphertext
	CreatedAt       time.Time         `json:"created_at"`                 // first set; preserved across rotate
	UpdatedAt       time.Time         `json:"updated_at"`                 // last value change
	Tags            []string          `json:"tags,omitempty"`             // free-form labels for filtering
	Description     string            `json:"description,omitempty"`      // human note
	RotateAfter     *time.Time        `json:"rotate_after,omitempty"`     // rotation due date (drives `stale`)
	ExpiresAt       *time.Time        `json:"expires_at,omitempty"`       // hard expiry: reads/use refuse the value after this
	Disabled        bool              `json:"disabled,omitempty"`         // kill switch: refused on every access path until re-enabled; independent of ExpiresAt (SEC-13)
	NoPrint         bool              `json:"no_print,omitempty"`         // exec-only: never reveal to stdout
	RequireApproval bool              `json:"require_approval,omitempty"` // human must approve each release
	Canary          bool              `json:"canary,omitempty"`           // DEPRECATED (pre-0.6.2): decoy flag. Read for back-compat but no longer written — the designation now lives in the local canary registry, out of the synced store (SEC-04).
	RequireGrant    bool              `json:"require_grant,omitempty"`    // usable only via exec/MCP with a matching active grant
	RateLimit       int               `json:"rate_limit,omitempty"`       // max uses per RateWindow (0 = unlimited)
	RateWindow      string            `json:"rate_window,omitempty"`      // the window for RateLimit (e.g. "1h"); empty defaults to 1h
	Meta            map[string]string `json:"meta,omitempty"`             // open-ended extensibility bag
}

Secret is one entry. Value is the armored age ciphertext; every other field is cleartext metadata so the store can be listed and queried without the decryption key.

func (*Secret) Expired added in v0.2.0

func (s *Secret) Expired(now time.Time) bool

Expired reports whether the secret has a hard expiry that has already passed as of now. Unlike RotateAfter (a soft "should rotate" surfaced by `stale`), an expired secret is refused by every access path — it cannot be read, injected, or exec-injected.

type Store

type Store struct {
	Version    int                `json:"version"`
	Generation int                `json:"generation,omitempty"` // monotonic save counter; bumped on every Save so a rollback (a restored older copy) is detectable (SEC-14)
	Recipients []string           `json:"recipients"`           // age recipients re-encrypted to on `set`
	Secrets    map[string]*Secret `json:"secrets"`
	// contains filtered or unexported fields
}

Store is the whole document. path is where it loads from / saves to (not serialized).

func Load

func Load(path string) (*Store, error)

Load reads and parses the store at path. A missing file is reported as a friendly "run `arca init`" error rather than a raw os error.

func New

func New(path string, recipients []string) *Store

New returns an empty in-memory store bound to path, with the given recipients.

func (*Store) Names

func (s *Store) Names() []string

Names returns the secret names in sorted order, for stable listing output.

func (*Store) Save

func (s *Store) Save() error

Save writes the store atomically and with restrictive permissions:

  • serialize to a temp file in the same directory (so rename is atomic on the same fs),
  • chmod 0600 before writing any bytes,
  • fsync-free rename over the destination.

The temp file is removed on any early-return error path via the deferred Remove.

Jump to

Keyboard shortcuts

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