secrets

package
v0.17.1 Latest Latest
Warning

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

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

Documentation

Overview

Package secrets assembles a namespace's secrets from the objects a backend holds for it: an append-only set of per-write segments over zero or more folded snapshots. Each write appends a new, uniquely named segment, so concurrent writers never overwrite one another. Reads fold the snapshots and segments together by a Lamport clock: last write per key wins, ties between machines are reported as conflicts. Compaction collapses what it reads into a fresh snapshot and deletes the objects it folded.

Every object is one age message sealed under the master key, and every object is bound to the vault's authenticated header by a manifest entry (a keyed MAC of its plaintext, see internal/crypto). A fold trusts the manifest, not the storage listing: a manifest-listed object that is missing, altered, or relocated is an alarm, and an object the manifest does not know is folded in only when it can be nothing but an honest in-flight write.

Index

Constants

View Source
const DefaultCompactThreshold = 16

DefaultCompactThreshold is the segment count at or above which a write triggers automatic compaction. It bounds the objects a cold read folds, so reads stay fast without anyone running `notenv compact` by hand.

Variables

This section is empty.

Functions

func Exists

func Exists(ctx context.Context, store backend.Backend, name string) (bool, error)

Exists reports whether a namespace has any stored object yet. It only lists, so it needs no master key.

Types

type Conflict

type Conflict struct {
	Key      string
	Winner   string
	Shadowed []string
}

Conflict reports a key written concurrently on more than one machine (equal Lamport). Winner's value is the one kept; the others are shadowed but remain recoverable from their segments until the next compaction.

type CorruptObject added in v0.16.0

type CorruptObject struct {
	Key    string
	Reason string
}

CorruptObject is a recorded object a salvage fold could not trust and dropped: missing from storage, undecryptable, or MAC-mismatched. Reason is the read error that disqualified it. A strict fold fails on the first such object; a salvage fold lists them here and resolves every key it still can.

type Meta added in v0.11.0

type Meta struct {
	Description string
	TS          int64
}

Meta is a live key's advisory metadata: what the secret is for and when its winning write happened (wall-clock Unix seconds; 0 means the write predates timestamps). Advisory means exactly that: nothing orders or trusts by it.

type Namespace

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

Namespace reads and writes one namespace's secrets through a backend, sealing every object under master. machine identifies and orders this machine's writes so two machines never produce the same segment. manifest is the verified header's object manifest; folds check every object against it.

func For

func For(store backend.Backend, name string, master *crypto.MasterKey, machine string, manifest map[string]crypto.ManifestEntry) *Namespace

For binds a namespace to a backend, master key, and the verified header's manifest.

func (*Namespace) Append

func (n *Namespace) Append(ctx context.Context, prev *State, seq int, w Write) (*State, string, crypto.ManifestEntry, error)

Append writes one key change as a new segment and returns the resulting state, the object key the segment landed under (so the caller can remove the write again if recording it in the manifest fails), and the manifest entry that records it. prev is the fold this write builds on; its Lamport sets the new clock.

func (*Namespace) Compact

func (n *Namespace) Compact(ctx context.Context, commit func(crypto.ManifestDelta) error) error

Compact folds the namespace into a single fresh snapshot and removes the objects it folded, adopting any in-flight writes it found along the way. It writes the new snapshot before deleting anything and only deletes objects it read, so a write that lands concurrently (under a name it never listed) is never lost.

commit makes the snapshot authoritative: it must apply the given manifest delta to the vault header (under the compare-and-swap, which also confirms the master this compaction sealed with is still the vault's master). If it errors, Compact removes its own snapshot and returns with the namespace untouched. After the subsumed objects are deleted, commit is called once more, best-effort, to prune their now-pointless entries.

func (*Namespace) Fold

func (n *Namespace) Fold(ctx context.Context) (*State, error)

Fold reads every object in the namespace and resolves the current secrets. A single untrustable recorded object (missing, undecryptable, MAC-mismatched) fails the whole fold closed, naming it: a dropped or altered write must never be silently skipped. FoldSalvage is the opt-in escape from that for a vault stuck on honest media loss.

func (*Namespace) FoldSalvage added in v0.16.0

func (n *Namespace) FoldSalvage(ctx context.Context) (*State, error)

FoldSalvage resolves what it can from a namespace that a strict Fold refuses, dropping every untrustable recorded object and reporting them on State.Corrupt instead of failing. It is non-destructive (it changes no storage and evicts nothing) and deliberately opt-in: the dropped keys revert to an older snapshot value or disappear, so serving the rest silently would hide an attacker who suppressed one object. The caller surfaces State.Corrupt loudly.

type State

type State struct {
	Secrets   map[string]string
	Meta      map[string]Meta
	Conflicts []Conflict
	// Adoptable lists objects the fold trusted as honest in-flight writes (see
	// classify) but the manifest does not record yet, with the entries a writer
	// should add to adopt them.
	Adoptable map[string]crypto.ManifestEntry
	// Prunable lists manifest entries marked folded whose objects are confirmed
	// gone; any writer may drop them.
	Prunable []string
	// Strays lists unknown snapshots the fold ignored (a compaction that crashed
	// between writing its snapshot and recording it); `notenv compact` removes
	// them.
	Strays []string
	// Corrupt lists recorded objects a salvage fold could not trust and dropped
	// (missing, undecryptable, or MAC-mismatched). It is empty unless the fold ran
	// in salvage mode (FoldSalvage); a strict fold fails on the first such object
	// instead of listing it.
	Corrupt []CorruptObject
	// contains filtered or unexported fields
}

State is a folded namespace: the resolved secrets and any same-key conflicts detected during the fold. lamport is the highest Lamport folded, the basis for the next write's clock; segments is how many segment objects it folded.

func (*State) HasHistory

func (s *State) HasHistory() bool

HasHistory reports whether any write has ever been folded into this state; false means the namespace is untouched (distinct from one emptied by deletes).

func (*State) HighWater added in v0.16.0

func (s *State) HighWater(machine string) int

HighWater is the highest seq this fold attributes to machine: the floor its next write must clear. A local seq counter that was lost or reset (it is disposable per-machine state) cannot then reissue a number already on storage, which a later fold would mistake for a replay. Zero for a machine with no folded writes.

func (*State) SegmentCount

func (s *State) SegmentCount() int

SegmentCount is how many uncompacted segment objects this fold read, the signal a caller uses to decide whether the next write should compact.

type Write added in v0.11.0

type Write struct {
	Key         string
	Value       string
	Description string
	TS          int64
	Deleted     bool
}

Write is one key change to append: a value (with optional advisory metadata) or a deletion. TS is the write's wall-clock Unix seconds, supplied by the caller so this package never reads a clock; 0 omits it.

Jump to

Keyboard shortcuts

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