vault

package
v0.9.5 Latest Latest
Warning

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

Go to latest
Published: Jul 1, 2026 License: MIT Imports: 12 Imported by: 0

Documentation

Overview

Package vault manages the on-disk vault layout, secret records, and recipient lists stored inside the Git repository.

Index

Constants

View Source
const DirName = ".envault"

DirName is the vault directory created inside the repository root.

Variables

View Source
var ErrAlreadyInitialized = errors.New("vault already initialized (use --force to reinitialize)")

ErrAlreadyInitialized is returned by Init when the vault already exists and force is false.

View Source
var ErrRecipientAlreadyExists = errors.New("recipient already exists for this id")

ErrRecipientAlreadyExists is returned by AddRecipient when an entry with the same ID is already present in the recipients file.

View Source
var ErrRecipientNotFound = errors.New("recipient not found")

ErrRecipientNotFound is returned by RemoveRecipient when no entry matches the given ID.

Functions

func AddRecipient

func AddRecipient(repoRoot string, r Recipient) (err error)

AddRecipient appends r to the recipients file inside repoRoot. Returns ErrRecipientAlreadyExists if an entry with the same ID is already present.

func IsInitialized

func IsInitialized(repoRoot string) bool

IsInitialized reports whether a vault directory exists inside repoRoot.

func MergeStores

func MergeStores(base, ours, theirs *Store) (*Store, []MergeWarning, []MergeConflict)

MergeStores performs a secret-level 3-way merge of base, ours, and theirs. Entry identity is (Name, Kind); equality is determined by UpdatedAt timestamp.

Merge rules:

  • Only ours added → keep ours
  • Only theirs added → keep theirs
  • Both added, same UpdatedAt → keep (idempotent)
  • Both added, different → conflict
  • Only ours changed → keep ours; warn if recipient dropped
  • Only theirs changed → keep theirs; warn if recipient dropped
  • Both changed to same UpdatedAt → keep
  • Both changed differently → conflict
  • Ours unchanged, theirs deleted → delete
  • Theirs unchanged, ours deleted → delete
  • Both deleted → delete
  • Ours modified, theirs deleted → conflict
  • Theirs modified, ours deleted → conflict

If len(conflicts) > 0, the caller must abort the merge.

func RemoveRecipient

func RemoveRecipient(repoRoot, id string) error

RemoveRecipient removes the entry with the given id from the recipients file. Returns ErrRecipientNotFound if no entry matches.

func SaveStore

func SaveStore(repoRoot string, s *Store) error

SaveStore atomically replaces the secrets store inside repoRoot.

Types

type Config

type Config struct {
	Backend string
	Remote  string
}

Config holds the vault configuration written to .envault/config.

func Init

func Init(repoRoot, remote string, force bool) (*Config, error)

Init creates the vault directory structure inside repoRoot. If the vault already exists and force is false, it returns ErrAlreadyInitialized.

type Entry

type Entry struct {
	Name       string                `json:"name"`
	Kind       EntryKind             `json:"kind"`
	Algorithm  envcrypto.CipherSuite `json:"algorithm"`
	Recipients []string              `json:"recipients"`
	CreatedAt  time.Time             `json:"created_at"`
	UpdatedAt  time.Time             `json:"updated_at"`
	Envelope   *envcrypto.Envelope   `json:"envelope"`
}

Entry is one sealed secret or file together with its self-describing metadata: the ciphertext carries its own timestamp, algorithm and recipient set.

type EntryKind

type EntryKind string

EntryKind distinguishes a secret sourced from an env var from an arbitrary file.

const (
	// KindEnv is a single environment variable imported from a dotenv file.
	KindEnv EntryKind = "env"
	// KindFile is an arbitrary file (text, JSON, CSV, PEM, binary) stored in the vault.
	KindFile EntryKind = "file"
)

type EnvVar

type EnvVar struct {
	Key   string
	Value string
}

EnvVar is a single key/value pair parsed from a dotenv file.

func ParseDotenv

func ParseDotenv(r io.Reader) ([]EnvVar, error)

ParseDotenv parses dotenv content: one KEY=VALUE per line. Blank lines and comments (lines starting with '#') are skipped, an optional leading "export " is honored, and a value wrapped in matching single or double quotes is unquoted. Inline comments are intentionally not stripped so values may contain '#'.

type MergeConflict

type MergeConflict struct {
	Name   string
	Kind   EntryKind
	Reason string
}

MergeConflict describes an entry-level conflict that could not be auto-resolved. The caller must surface this to the user and abort the merge.

type MergeWarning

type MergeWarning struct {
	Name    string
	Kind    EntryKind
	Message string
}

MergeWarning describes an auto-resolved change that should be surfaced to the user — most commonly a recipient losing access on one side of the merge.

type Recipient

type Recipient struct {
	ID        string
	PublicKey [32]byte
}

Recipient is a vault member identified by an ID and their X25519 public key.

func ListRecipients

func ListRecipients(repoRoot string) ([]Recipient, error)

ListRecipients reads all recipients from the recipients file inside repoRoot. Returns an empty slice (not an error) when the file does not exist.

func ParseRecipientLine

func ParseRecipientLine(line string) (Recipient, error)

ParseRecipientLine parses a "<id> <hex-pubkey>" string as written by AddRecipient and produced by "envault key export --public".

type Store

type Store struct {
	Version int     `json:"version"`
	Entries []Entry `json:"entries"`
}

Store is the on-disk collection of sealed entries (.envault/secrets.enc).

func LoadStore

func LoadStore(repoRoot string) (*Store, error)

LoadStore reads the secrets store from repoRoot. It returns an empty store (not an error) when the file does not yet exist.

func ParseStore

func ParseStore(data []byte) (*Store, error)

ParseStore decodes a JSON-encoded secrets store from raw bytes. Returns an error if the bytes are not valid JSON or the version is unsupported.

func (*Store) Delete

func (s *Store) Delete(name string, kind EntryKind) *Store

Delete returns a new Store with the entry of the given name and kind removed. If no matching entry exists, the store is returned unchanged. The receiver is never mutated.

func (*Store) Upsert

func (s *Store) Upsert(e Entry) *Store

Upsert returns a new Store with e added, or replacing an existing entry that has the same name and kind. The original CreatedAt is preserved on replace so it records first-seal time, while UpdatedAt reflects the latest seal. The receiver is never mutated.

type StoreChanges

type StoreChanges struct {
	Added   []string // entries present in after but not in before
	Removed []string // entries present in before but not in after
	Rotated []string // entries present in both but with a newer UpdatedAt
}

StoreChanges describes what changed between two snapshots of a Store.

func DiffStores

func DiffStores(before, after *Store) StoreChanges

DiffStores computes what changed between before and after. Comparison is by entry name only (kind is ignored for reporting).

func (StoreChanges) IsEmpty

func (c StoreChanges) IsEmpty() bool

IsEmpty reports whether there are no changes.

func (StoreChanges) Total

func (c StoreChanges) Total() int

Total returns the total number of changed entries.

Jump to

Keyboard shortcuts

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