provenance

package
v0.9.2 Latest Latest
Warning

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

Go to latest
Published: Sep 5, 2026 License: Apache-2.0 Imports: 9 Imported by: 0

Documentation

Overview

Package provenance records which release manifest produced the billet that is installed on this machine, and proves the record still describes it.

WHY A VERSION STRING IS NOT ENOUGH. A rollout resolves a channel once, to one immutable signed manifest, and persists that manifest's DIGEST precisely so every host installs the same bytes. A node's registration, though, carries the version string its binary was BUILT with and nothing about the bytes behind it — so a host upgraded out of band, or rebuilt under the same name, converges a rollout on evidence weaker than the decision it is converging. This is the record that closes the gap: the updater writes what it installed, and the node reports it.

WHY THE BINARY'S OWN HASH IS IN IT. A record naming only a version is defeated by the exact case the digest exists to catch — two builds carrying one version string, which is what a moved tag produces. Binding the record to the bytes means a binary replaced by hand afterwards reports NOTHING rather than inheriting the last upgrade's provenance, and "nothing" is an answer the rollout already knows how to read.

A LEAF, ON PURPOSE. The updater in cmd/billet writes this and the node client in internal/nodeclient reads it, so it can depend on neither; stdlib only.

Index

Constants

This section is empty.

Variables

View Source
var ErrNoRecord = errors.New("provenance: this installation has no record of which " +
	"release manifest produced it")

ErrNoRecord means nothing on this machine says which manifest produced it.

THE ORDINARY CASE, NOT A FAULT. A host installed from a package, built from source, or upgraded before this existed has no record, and every caller has to treat that as "cannot tell" rather than as a refusal.

View Source
var ErrNotThisBinary = errors.New("provenance: the installed record describes different " +
	"bytes than the binary that is running")

ErrNotThisBinary means a record exists and describes different bytes.

DISTINCT FROM ErrNoRecord, because the two are different facts about the machine and only one of them is ordinary. This one says something replaced the binary without updating the record — which is exactly the case the hash is here to catch, and which a caller should say out loud rather than treat as silence.

Path is where the record lives.

A VAR SO A TEST CAN OWN THE DIRECTORY IT WRITES INTO, the same seam cmd/billet's upgradeRoot uses and for the same reason: the real path is durable state on the machine running the test.

Functions

func DefaultPathFor added in v0.6.0

func DefaultPathFor(goos string) string

DefaultPathFor is where the record lives on a platform.

BESIDE THE REST OF THE HOST'S UPDATE BOOKKEEPING: under /var/lib/billet on Linux, where the updater is root, and under /usr/local/var/lib/billet on a Mac, where the updater is the operator's launch agent and /var/lib does not exist. A record written where the account that reads it back cannot reach is a host that reports nothing after every upgrade.

func HashFile

func HashFile(path string) (string, error)

HashFile returns a file's sha256, lowercase hex.

func Installed

func Installed() (string, error)

Installed reports the manifest digest that produced the running binary.

IT PROVES THE RECORD STILL APPLIES rather than trusting it. A record whose binary hash does not match the executable is reported as ErrNotThisBinary and yields no digest, because the alternative is a host inheriting the last upgrade's provenance for bytes nobody can account for — which is worse than saying nothing, since a rollout reads "nothing" correctly and reads a wrong digest as proof.

CALL IT ONCE, AND EARLY, AND HOLD THE ANSWER. Hashing the executable is a ~22MB read and a node re-registers on every reconnect, so asking per registration pays for one answer repeatedly. More importantly the answer must describe the bytes the CALLER STARTED WITH: os.Executable resolves to a path on macOS, so a binary replaced later would otherwise be hashed in place of the one actually running. The caching lives in the caller rather than here because the caller is what has a lifetime — a package-level cache would be a value no test could clear and a state this leaf has no business owning.

func Write

func Write(record Record) error

Write makes a record durable.

ATOMIC, AND FLUSHED WITH ITS DIRECTORY. This is written during an upgrade, between stopping a machine's services and starting them again, so a power cut in that window must leave either the old record or the new one — never a half-written file that the next read refuses and that makes a correctly upgraded host report nothing.

Types

type Record

type Record struct {
	// Version is the release this was installed for, as `billet version` reports
	// it. Diagnostic: nothing decides from it, because the whole point of this
	// file is that a version string is not evidence.
	Version string `json:"version"`

	// ManifestDigest is the sha256 of the signed release manifest that named the
	// artifact this binary came from. It is the thing a rollout compares against
	// its own recorded decision.
	ManifestDigest string `json:"manifest_digest"`

	// BinarySHA256 is the sha256 of the binary that was installed.
	//
	// WHAT MAKES THE RECORD PROVE ANYTHING. Without it the file is a claim about
	// whatever binary happens to sit at the installed path now, which a later
	// hand-replacement inherits silently.
	BinarySHA256 string `json:"binary_sha256"`
}

Record is what produced the installed binary.

func Read

func Read() (Record, error)

Read returns the record on this machine, without checking that it still describes the running binary.

FOR A DIAGNOSTIC, NOT FOR A DECISION. `billet host-upgrade --status` and the operator reading it want to see what is written down even when it no longer matches; anything that DECIDES from provenance goes through Installed.

Jump to

Keyboard shortcuts

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