Documentation
¶
Overview ¶
Package gotest turns passing tests/benches (as parsed by the leaf package pkg/gotestevents) into evidence records, independent of the `canary evidence` command package. The stream-parsing and record-derivation primitives themselves live in pkg/gotestevents, which imports only stdlib + pkg/evidence so pkg/canaryscan can use them too without an import cycle (pkg/gotest imports pkg/canaryscan for canaryscan.Report, so canaryscan cannot import pkg/gotest back).
Index ¶
- func AttestationPath(base, artifactDigest string) string
- func AttestationValid(base string, rec ev.Record, trustedKeys []ed25519.PublicKey) bool
- func PassingBenches(raw []byte) (map[string]map[string]struct{}, error)
- func PassingTests(raw []byte) (map[string]map[string]struct{}, error)
- func Records(rep canaryscan.Report, passed, benches map[string]map[string]struct{}, ...) ([]ev.Record, error)
- type AttestationSidecar
- type Drops
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func AttestationPath ¶ added in v0.3.7
AttestationPath returns the sidecar path for an artifact digest under base (the project's .canary directory, the same root gotestevents.ArtifactPath uses for the artifact itself): "sha256:"-stripped hex digest, ".json", inside an "attestations" subdirectory kept separate from the raw "artifacts" one -- the artifact is the test output; the attestation is a claim ABOUT it, signed independently.
func AttestationValid ¶ added in v0.3.7
CANARY: REQ=CP-236; FEATURE="AttestationValid"; ASPECT=Engine; STATUS=TESTED; TEST=TestAttestationValidAccepted,TestAttestationValidNoSidecar,TestAttestationValidUntrustedKey,TestAttestationValidFieldMismatch,TestAttestationValidNoTrustedKeys,TestAttestationValidMalformedSidecar; UPDATED=2026-09-01 AttestationValid reports whether rec's origin:"executed" claim is backed by a valid, trusted attestation:
- rec carries an ArtifactDigest and at least one trusted key is configured (an empty trustedKeys means "attestation cannot be evaluated," never "trivially satisfied").
- A sidecar exists at AttestationPath(base, rec.ArtifactDigest) and parses as AttestationSidecar.
- Its Signature verifies (attest.Verify) against AT LEAST ONE of trustedKeys -- an attestation signed by an untrusted key is indistinguishable from an unsigned one.
- The verified attestation's ProjectID, CommitSHA, SourceDigest, ArtifactDigest, and ToolchainDigest all equal rec's own. A valid signature over a DIFFERENT claim proves nothing about THIS record -- an attacker who captured one genuine attestation could otherwise staple it onto an unrelated hand-authored record that happens to share an artifact digest with something else entirely.
Any failure along that chain reports false -- missing sidecar, malformed JSON, a signature that does not verify against any trusted key, or a field mismatch. There is no partial credit: an attestation either authenticates this exact record or it does not vouch for it at all.
func PassingBenches ¶
PassingBenches parses a `go test -json` event stream and returns, per benchmark name, the set of package import paths in which it ran to completion: an output event carried its result line, AND that package's terminal action was "pass". A benchmark inside a package whose run failed -- even if its own result line was printed before the failure -- produces no evidence, mirroring PassingTests' fail-vetoes-everywhere discipline at the only granularity benchmarks report: the package.
func PassingTests ¶
PassingTests parses a `go test -json` event stream and returns, per test name, the set of package import paths in which it passed. A test name that failed in ANY package is vetoed everywhere: passing in package A does not excuse failing in package B.
The actual event-stream parsing lives in pkg/gotestevents (a leaf package pkg/canaryscan can also import); this is a thin wrapper kept for existing callers.
func Records ¶
func Records(rep canaryscan.Report, passed, benches map[string]map[string]struct{}, projectID, commit, runner, observedAt, digest, origin string, dirty bool) ([]ev.Record, error)
Records builds one evidence record per (requirement, feature, aspect, test x passing package) declared by a token whose test is in passed, plus one per (requirement, feature, aspect, bench x completed package) declared by a token whose bench is in benches. Records are sorted by requirement, feature, aspect, test/bench, then package so repeated runs over the same inputs produce byte-identical output.
A declared name that is not package-qualified (no "pkg:Name" prefix) and was observed passing in more than one package is ambiguous -- an unrelated same-named test in another package could otherwise satisfy the declaration -- and Records refuses to emit any record for it, returning an error instead. Qualify the declaration as "pkg:Name" to disambiguate.
A bare name that passed in EXACTLY one package is accepted, and that package is stamped onto the record's Package field (C6-06b): the record is package-bound even though the declaration itself never named one. This does not by itself prove the one package is the "right" one -- a well-established convention in this codebase declares a requirement's TEST= where the requirement lives (e.g. mcp/mcp.go) but proves it with a centralized test elsewhere (e.g. internal/audit), so a token's own directory is not a reliable proxy for which package its declared test actually runs in, and Records deliberately does not try to derive or enforce one from Feature.Files. What the stamped Package DOES close: once a record names a concrete package, gotestevents.RecordDerivable's re-verification requires an exact match against that same package, so a same-named test that later appears in a DIFFERENT, still-unrelated package can never be used to re-derive (or re-prove, at ingest/verify time) THIS record. The residual risk this leaves open -- a bare name whose one and only observed pass, at production time, happens to be an unrelated (coincidental or planted) test rather than the intended one -- is closed only by qualifying the declaration as "pkg:Name"; see the GAP note in GAP_ANALYSIS.md.
origin and dirty are stamped onto every emitted record: origin records how the evidence was produced ("executed" or "imported"), and dirty records whether the working tree matched HEAD when it was produced.
Types ¶
type AttestationSidecar ¶ added in v0.3.7
type AttestationSidecar struct {
Attestation attest.Attestation `json:"attestation"`
Signature string `json:"signature"`
}
AttestationSidecar is the on-disk shape of one attestation file: the attestation itself alongside its detached signature. `evidence run-go-test --sign-key` writes exactly this shape at AttestationPath(base, artifactDigest); AttestationValid reads it back.
type Drops ¶
Drops counts the records LoadEligible removed from a store, broken out by reason: Dirty (working tree was not HEAD when recorded), Imported (origin other than "executed", refused unless the policy allows it), and Artifactless (an "executed" record whose local artifact is missing, unreadable, digest-mismatched, or not semantically derivable -- it exists and re-hashes correctly but its events do not actually contain a pass for this record's (TestID, Package)).
func LoadEligible ¶
LoadEligible loads <root>/.canary/evidence.json and filters it under policy p, applying the SAME trust rules `canary verify` enforces by default so that a record the verifier would refuse cannot suppress work in `next`, satisfy a `deps check`, or unlock a `ticket sync` transition (C5-02, and -- for the artifact stage -- C6-02):
- a Dirty record is always dropped: it describes a working tree that was not HEAD when it was produced, and can never prove anything about the tree in front of the caller.
- a record whose Origin is not "executed" (imported, or unset) is dropped unless p.AllowImported is true.
- an "executed" record is dropped when it cannot be independently re-proven from its own retained artifact -- at ArtifactPath(<root> /.canary, record.ArtifactDigest): the artifact is missing, its bytes do not re-hash to the record's ArtifactDigest, its `go test -json` stream is unparseable, or (having passed all of that) re-parsing it and checking gotestevents.RecordDerivable proves it does NOT actually contain a pass for this record's (TestID, Package). This is the FULL semantic re-derivation `canary verify`'s artifact stage performs (see pkg/cmds/verify/verify.go) -- re-derivation is no longer verify-only: LoadEligible's callers (next, deps, ticket) get the identical guarantee, so a record the verifier would refuse can never suppress work, satisfy a dependency, or unlock a ticket transition behind its back.
A missing evidence store is not an error -- nothing has been proven yet -- and returns (nil, Drops{}, nil). A malformed one IS an error: treating unparseable evidence as merely absent would hide tampering behind an outcome ("dependency incomplete", "no work available") that reads like ordinary progress.