vault

package
v0.3.0 Latest Latest
Warning

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

Go to latest
Published: Aug 15, 2026 License: MIT Imports: 17 Imported by: 0

Documentation

Overview

Package vault stores the credentials agents need, encrypted at rest, with every reveal audited.

Two design choices are deliberate departures from cabrain's vault, which was the obvious thing to reuse:

  • Reveal is its own grant. cabrain requires WRITE access on a brain to reveal a secret, so a read-only agent cannot read a credential — the permission is backwards. Here can_reveal is separate from can_list and from any write capability.
  • Every reveal writes an audit row in the same transaction as the decrypt, or the reveal does not happen. cabrain emits only a transient event, so there is no durable answer to "who read this key?".

Index

Constants

View Source
const KeySize = 32

KeySize is the AES-256 key length in bytes.

Variables

View Source
var ErrNoKey = errors.New("BUILDER_VAULT_KEY is not set")

ErrNoKey is returned when BUILDER_VAULT_KEY is absent.

Functions

func AAD

func AAD(scope, agentSlug, name string) string

AAD builds the additional-authenticated-data string for a secret row.

func Hint

func Hint(plaintext string) string

Hint returns a non-reversible display form: sk-…a1b2.

func ValidateVaultKey

func ValidateVaultKey(raw string) error

ValidateVaultKey reports whether raw is a usable 32-byte key.

Accepts standard or URL-safe base64, with or without padding, or 64 hex characters — because operators generate these with whichever of `openssl rand -base64 32` or `openssl rand -hex 32` they remember.

Types

type Service

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

Service is the vault.

func New

func New(k *togo.Kernel) (*Service, error)

New builds the vault from BUILDER_VAULT_KEY.

A missing or malformed key is fatal at boot rather than at first use: an app that starts with a broken vault fails later, inside an agent run, where the cause is far harder to see.

func (*Service) Open

func (s *Service) Open(stored, aad string) ([]byte, error)

Open decrypts a stored ciphertext. aad must match exactly what Seal was given.

func (*Service) Seal

func (s *Service) Seal(plaintext []byte, aad string) (string, error)

Seal encrypts plaintext under the row's identity.

aad binds the ciphertext to the row it belongs to (scope:agent_slug:name). AES-GCM authenticates it, so a ciphertext copied into a different row fails to decrypt — which makes row-swapping a non-attack rather than a privilege escalation.

type Store

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

Store is the vault's persistence + audit layer.

func NewStore

func NewStore(svc *Service, db *sql.DB, log *slog.Logger) *Store

func (*Store) HasSecret added in v0.3.0

func (s *Store) HasSecret(ctx context.Context, name string) bool

HasSecret reports whether a named secret exists, without decrypting it.

The gallery needs to answer "is this provider configured?" on every page load. Doing that with RevealSystem would decrypt a client secret, and write an audit row, purely to decide whether to enable a button — a read that happens dozens of times a day and never uses the value.

func (*Store) PutSystem added in v0.3.0

func (s *Store) PutSystem(ctx context.Context, name, value, reason string) error

PutSystem stores (or rotates) a secret the installation owns.

The write half of RevealSystem, and it exists for the same reason: an OAuth client secret is configuration the server holds, not a credential granted to an agent, so it has no agent to attribute the write to.

Rotation semantics match handleStore exactly — the previous version stays, marked not-current — because "what was live when this ran?" has to stay answerable after somebody replaces a key.

func (*Store) RevealFor

func (s *Store) RevealFor(ctx context.Context, name, agentSlug, runID string) (string, error)

RevealFor is the in-process path agents use, bypassing HTTP. Same contract: the audit row and the decrypt share a transaction.

func (*Store) RevealSystem added in v0.3.0

func (s *Store) RevealSystem(ctx context.Context, name, reason string) (string, error)

RevealSystem decrypts a secret held by the installation itself.

`reason` names the subsystem asking and lands in the audit row. It is required — an unattributed system read is exactly the thing this design is trying not to become.

func (*Store) Routes

func (s *Store) Routes(r chi.Router)

type SystemReader added in v0.3.0

type SystemReader interface {
	RevealSystem(ctx context.Context, name, reason string) (string, error)
}

SystemReader is the narrow capability a subsystem needs to read the installation's own credentials.

Jump to

Keyboard shortcuts

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