evidence

package
v0.3.6 Latest Latest
Warning

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

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

Documentation

Overview

Package evidence holds strict parsing of CANARY evidence records and the single completion function ("has every claimed requirement been proven at the current commit") that downstream verification consumes. It is self-contained: stdlib only, no imports from the rest of this repo, so any package may depend on it without creating a cycle.

Index

Constants

View Source
const MaxEvidenceFileBytes = 64 << 20

MaxEvidenceFileBytes bounds a loadable evidence store.

Variables

This section is empty.

Functions

func CompleteReq

func CompleteReq(reqID string, keys []FeatureKey, recs []Record, projectID, commit string) bool

CompleteReq is the single-requirement form of Complete, and the shared entry point behind the two surfaces that answer "is this local dependency satisfied?" -- `canary next`'s dependency gate and `canary deps check`. reqID is complete iff every key has a PASS record for projectID at commit. An empty keys slice yields false (EMPTY_CLAIMS): a dependency with nothing to prove is not proven. Routing both callers through here keeps ONE completion definition -- a declared STATUS=TESTED is a claim on both surfaces, never proof.

Types

type FeatureKey

type FeatureKey struct {
	Feature string   `json:"feature"`
	Aspect  string   `json:"aspect"`
	Tests   []string `json:"tests,omitempty"`   // declared TEST= names, optionally "pkg/path:Name"
	Benches []string `json:"benches,omitempty"` // declared BENCH= names, optionally qualified
}

FeatureKey identifies one claimed feature/aspect within a requirement, and optionally the exact declared TEST=/BENCH= names that must each have their own passing evidence record. An entry may be package-qualified as "pkg/path:Name"; a bare name matches any package.

type File

type File struct {
	SchemaVersion int      `json:"schema_version"` // must be 3
	Records       []Record `json:"records"`
}

File is the top-level shape of an evidence document.

func Load

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

Load reads and strictly parses the evidence file at path. A missing file returns an error wrapping fs.ErrNotExist so callers can distinguish it (via errors.Is) from a malformed one.

func Parse

func Parse(r io.Reader) (*File, error)

Parse strictly decodes an evidence file from r. It rejects, with an error naming the offending record index and field: unknown fields anywhere, duplicate fields anywhere (encoding/json silently keeps the last value on a duplicate key, so this is caught with an explicit token walk before the struct decode), a schema_version other than 3, any empty required field, a result other than exactly "PASS", a malformed commit_sha, artifact_digest, or observed_at, an origin other than "executed" or "imported", an empty or control-character-carrying argv element, and a negative run_exit_status.

type Missing

type Missing struct {
	RequirementID string     `json:"requirement_id"`
	Key           FeatureKey `json:"key"`
	Reason        string     `json:"reason"` // "no_evidence" | "wrong_commit" | "scope_mismatch" | "test_unproven" | "bench_unproven" | "test_ambiguous" | "bench_ambiguous"
}

Missing describes one required feature/aspect that Complete could not find satisfying evidence for.

type Policy added in v0.3.6

type Policy struct {
	AllowImported        bool `json:"allow_imported"`
	AllowDirty           bool `json:"allow_dirty"`
	AllowEmpty           bool `json:"allow_empty"`
	AllowUnknownExternal bool `json:"allow_unknown_external"`
}

Policy records which relaxations of the strict verification contract were in effect for a run. Every field is an opt-out that widens what verify accepts as proof -- imported (not canary-executed) evidence, a dirty working tree, an empty claims file, or an unresolvable external dependency. The zero value is StrictPolicy: nothing relaxed.

A bare "VERIFIED" cannot, on its own, tell a downstream consumer whether the run was strict or degraded by one of these overrides (C5-10). Policy plus the receipt fields it feeds on evidence.Verdict close that gap: the verdict now carries the policy's hash, its named overrides, and whether it was degraded at all.

func StrictPolicy added in v0.3.6

func StrictPolicy() Policy

StrictPolicy is the zero-value Policy -- no overrides, the default verification contract. Named for readability at call sites.

func (Policy) Degraded added in v0.3.6

func (p Policy) Degraded() bool

Degraded reports whether any override is active -- the run accepted something the strict contract would have refused.

func (Policy) Hash added in v0.3.6

func (p Policy) Hash() string

Hash returns a stable content identity for p: "sha256:" followed by the hex-encoded sha256 of p's canonical JSON encoding. Policy's field order is fixed in source, so json.Marshal of the struct (never a map) is deterministic across runs -- identical policies always hash identically, and any differing field changes the hash.

func (Policy) Overrides added in v0.3.6

func (p Policy) Overrides() []string

Overrides returns the sorted, kebab-case names of every true field, e.g. ["allow-dirty", "allow-imported"]. An empty (nil) result means strict.

type Record

type Record struct {
	ProjectID      string `json:"project_id"`
	RequirementID  string `json:"requirement_id"`
	Feature        string `json:"feature"`
	Aspect         string `json:"aspect"`
	TestID         string `json:"test_id"`
	Package        string `json:"package,omitempty"` // import path the test ran in; "" in legacy records
	Kind           string `json:"kind,omitempty"`    // "" or "test" means test; "bench" means benchmark
	Command        string `json:"command"`
	Result         string `json:"result"`      // must be exactly "PASS"
	CommitSHA      string `json:"commit_sha"`  // exactly 40 lowercase hex
	ObservedAt     string `json:"observed_at"` // RFC3339, must be UTC (Z or +00:00)
	Runner         string `json:"runner"`
	ArtifactDigest string `json:"artifact_digest"` // "sha256:" + 64 lowercase hex
	Origin         string `json:"origin"`          // "executed" or "imported"
	Dirty          bool   `json:"dirty,omitempty"` // true when the working tree was not HEAD when this was recorded

	// Argv and RunExitStatus are schema v3 additions: they record the exact
	// argv vector a fixed-runner producer (e.g. `canary evidence
	// run-go-test`) executed and the process's exit status. Both are
	// optional -- an imported record (from-go-test, hand-authored) never
	// ran a process itself and so has neither.
	Argv          []string `json:"argv,omitempty"`            // executed: the exact argv vector run
	RunExitStatus *int     `json:"run_exit_status,omitempty"` // executed: the process's exit code
}

Record is one evidence claim: a single passing test run, tying a requirement's feature/aspect to a commit via a reproducible command and an observed result.

func Eligible added in v0.3.5

func Eligible(recs []Record, allowImported bool) (out []Record, droppedDirty, droppedImported int)

Eligible filters records by trust. Dirty records never verify anything: they describe a tree that was not HEAD. Imported records (origin "imported" or unset) verify only when the caller explicitly accepts unattested input.

type Verdict

type Verdict struct {
	OK      bool      `json:"ok"`
	State   string    `json:"state"` // "VERIFIED" | "UNVERIFIED" | "UNKNOWN"
	Code    string    `json:"code"`  // "OK" | "EVIDENCE_MISSING" | "EMPTY_CLAIMS" | "SCAN_INCOMPLETE" | "EXTERNAL_UNKNOWN"
	Message string    `json:"message"`
	Missing []Missing `json:"-"`

	// ProjectID and CommitSHA identify what was verified. CommitSHA may be
	// empty when the verdict was reached before HEAD could be determined
	// (e.g. SCAN_INCOMPLETE from an unreadable config).
	ProjectID string `json:"project_id,omitempty"`
	CommitSHA string `json:"commit_sha,omitempty"`
	// SourceDigest is the content digest of the scanned token-bearing tree
	// (index.ComputeScanDigest), when it could be computed.
	SourceDigest string `json:"source_digest,omitempty"`
	// PolicyHash, Overrides and Degraded describe the verification policy in
	// effect for this run -- see Policy.
	PolicyHash string   `json:"policy_hash,omitempty"`
	Overrides  []string `json:"overrides,omitempty"`
	Degraded   bool     `json:"degraded,omitempty"`
	// VerifierVersion is the canary binary version that produced this
	// verdict, and GeneratedAt is when it did so (RFC3339, UTC).
	VerifierVersion string `json:"verifier_version,omitempty"`
	GeneratedAt     string `json:"generated_at,omitempty"`
}

Verdict is the result of a completion check.

The trailing fields form the verification receipt (C5-10): identity and policy context stamped onto every verdict a verifier emits, so a downstream consumer can distinguish a strict pass from one reached only because some part of the contract was relaxed (--allow-dirty, --allow-imported, --allow-empty, --allow-unknown-external). They are all `omitempty` so the pre-C5-10 JSON shape stays a strict subset of the current one.

func Complete

func Complete(required map[string][]FeatureKey, recs []Record, projectID, commit string, allowEmpty bool) Verdict

Complete is THE completion function: every required feature/aspect of every required requirement must have at least one record with Result=PASS (guaranteed by Parse), ProjectID==projectID, and CommitSHA==commit. An empty required map yields EMPTY_CLAIMS unless allowEmpty is set, in which case it is treated as trivially satisfied.

The Missing list, when non-empty, is sorted deterministically by (RequirementID, Feature, Aspect) so repeated runs over the same inputs produce byte-identical output.

Jump to

Keyboard shortcuts

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