evidence

package
v0.3.1 Latest Latest
Warning

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

Go to latest
Published: Aug 21, 2026 License: Apache-2.0 Imports: 18 Imported by: 0

Documentation

Overview

Package evidence builds and verifies tamper-evident evidence bundles for a Readproof run: an in-toto Statement whose subject digest is a Merkle root over the run's manifest entries.

Everything here is composed purely from client.Client calls (manifest, snapshots, resources, replay), so `readproof evidence` behaves identically in embedded mode and against a remote readproofd — a bundle is a projection of what any Readproof deployment can already answer, never a new storage or wire concept.

Index

Constants

View Source
const (
	// StatementType is the in-toto Statement v1 type. Bundles are valid
	// in-toto statements so existing supply-chain tooling (cosign, in-toto
	// attestation verifiers) can sign and transport them unmodified.
	StatementType = "https://in-toto.io/Statement/v1"

	// PredicateType is a PLACEHOLDER URN. Readproof has not settled its
	// final predicate schema, and the predicate type is the one string
	// external verifiers key off — keeping it in a single exported const
	// makes a bump a one-line change here, mirrored by the same const in
	// sdk/typescript/src/evidence.ts.
	PredicateType = "urn:readproof:evidence:v0.3"

	// ExporterName / ExporterVersion identify the producer of the bundle
	// format, not the Readproof deployment it was exported from — hence the
	// plain version.Version rather than version.String(): two builds of the
	// same source must export byte-identical bundles.
	ExporterName    = "readproof"
	ExporterVersion = version.Version

	// MerkleAlgorithm and MerkleLeafFormula are embedded in every bundle
	// so a verifier can recompute the root without reading this source.
	MerkleAlgorithm   = "sha256"
	MerkleLeafFormula = "sha256(position_be_uint32 || 0x00 || uri || 0x00 || content_hash)"
)

Variables

This section is empty.

Functions

func Encode

func Encode(b Bundle) ([]byte, error)

Encode renders a bundle as indented JSON with a trailing newline, so `readproof evidence export > bundle.json` produces a well-formed text file.

func LeafHash

func LeafHash(e Entry) []byte

LeafHash returns the Merkle leaf for one entry. The rule lives in internal/merkle so that the readproof.run.commit span can compute the same root from manifest entries without importing the bundle types; this is a thin projection of Entry onto the three fields the leaf commits to.

func MerkleRoot

func MerkleRoot(entries []Entry) string

MerkleRoot computes the hex-encoded root over the entries' leaves, in the order given. See internal/merkle for the tree rules and the reasons behind them; the fixed vectors in merkle_test.go pin the output.

Types

type Bundle

type Bundle struct {
	Type          string    `json:"_type"`
	Subject       []Subject `json:"subject"`
	PredicateType string    `json:"predicateType"`
	Predicate     Predicate `json:"predicate"`
}

Bundle is an in-toto Statement v1 describing one Readproof manifest. Field order is fixed by the struct definition rather than by map iteration, so the JSON encoding is stable across runs and byte-comparable between the Go and TypeScript exporters.

func Build

func Build(ctx context.Context, c client.Client, target string, opts Options) (Bundle, error)

Build assembles an evidence bundle for a manifest id or run id, using only client.Client calls so the result is identical in embedded mode and against a remote readproofd.

func Decode

func Decode(data []byte) (Bundle, error)

Decode parses a bundle. Unknown fields are deliberately tolerated (no DisallowUnknownFields): a bundle written by a newer exporter must still verify against an older binary for the checks that binary understands.

type Check

type Check struct {
	Name   string `json:"name"`
	OK     bool   `json:"ok"`
	Detail string `json:"detail,omitempty"`
}

Check is one verification step and its outcome. Detail always explains a failure, and usually describes a pass too.

type Digest

type Digest struct {
	SHA256 string `json:"sha256"`
}

type Entry

type Entry struct {
	Position int    `json:"position"`
	URI      string `json:"uri"`
	// Ref is the "@<tag>" the entry was mounted by ("" for a plain URI).
	// Descriptive only — it is deliberately NOT part of the Merkle leaf, so
	// roots stay stable for manifests recorded before tags existed.
	Ref               string            `json:"ref,omitempty"`
	SnapshotID        string            `json:"snapshot_id"`
	MaterializationID string            `json:"materialization_id"`
	ContentHash       string            `json:"content_hash"`
	SourceRevision    string            `json:"source_revision"`
	ObservedAt        time.Time         `json:"observed_at"`
	ContentType       string            `json:"content_type"`
	Bytes             int64             `json:"bytes"`
	Provenance        map[string]string `json:"provenance"`
	// ContentB64 is populated only with Options.WithContent. Without it a
	// bundle is metadata-only: safe to hand to an auditor who is allowed
	// to know what the agent read but not to read it.
	ContentB64 string `json:"content_b64,omitempty"`
}

Entry is one manifest entry hydrated with its snapshot metadata. Position, URI and ContentHash are the only fields that feed the Merkle leaf; everything else is descriptive.

type Exporter

type Exporter struct {
	Name    string `json:"name"`
	Version string `json:"version"`
}

type FilesystemConfig

type FilesystemConfig struct {
	Path string `json:"path"`
}

type GitHubConfig

type GitHubConfig struct {
	Owner string `json:"owner"`
	Repo  string `json:"repo"`
	Path  string `json:"path"`
	Ref   string `json:"ref"`
}

type HTTPConfig

type HTTPConfig struct {
	URL     string            `json:"url"`
	Headers map[string]string `json:"headers,omitempty"`
}

type Merkle

type Merkle struct {
	Algorithm string `json:"algorithm"`
	Leaf      string `json:"leaf"`
	Root      string `json:"root"`
}

type Options

type Options struct {
	// WithContent embeds each entry's replayed bytes as base64. Off by
	// default: the metadata-only bundle is the shareable one.
	WithContent bool
	// Now overrides the clock for generated_at / replay.verified_at so
	// tests can produce byte-stable bundles.
	Now func() time.Time
}

Options controls what Build puts in the bundle.

type Policy

type Policy struct {
	Strategy         string `json:"strategy"`
	MaxAgeSeconds    int64  `json:"max_age_seconds,omitempty"`
	PinnedSnapshotID string `json:"pinned_snapshot_id,omitempty"`
}

type Predicate

type Predicate struct {
	RunID             string     `json:"run_id"`
	ManifestID        string     `json:"manifest_id"`
	ManifestCreatedAt time.Time  `json:"manifest_created_at"`
	GeneratedAt       time.Time  `json:"generated_at"`
	Exporter          Exporter   `json:"exporter"`
	Merkle            Merkle     `json:"merkle"`
	Entries           []Entry    `json:"entries"`
	Resources         []Resource `json:"resources"`
	Replay            Replay     `json:"replay"`
}

type Replay

type Replay struct {
	VerifiedAt time.Time     `json:"verified_at"`
	AllMatch   bool          `json:"all_match"`
	Entries    []ReplayEntry `json:"entries"`
	// Error is set when replay could not run at all (e.g. a blob is gone).
	// The export still succeeds — an un-replayable manifest is precisely
	// the situation an auditor needs a durable record of.
	Error string `json:"error,omitempty"`
}

Replay records the reconstruction check performed at export time: every entry's bytes re-read from the blob store and re-hashed.

type ReplayEntry

type ReplayEntry struct {
	Position     int    `json:"position"`
	Match        bool   `json:"match"`
	ExpectedHash string `json:"expected_hash"`
	ActualHash   string `json:"actual_hash"`
	Error        string `json:"error,omitempty"`
}

type Report

type Report struct {
	OK             bool    `json:"ok"`
	Checks         []Check `json:"checks"`
	Entries        int     `json:"entries"`
	MerkleRoot     string  `json:"merkle_root"`
	ContentChecked int     `json:"content_checked"`
	ReplayChecked  bool    `json:"replay_checked"`
	ReplayMatched  int     `json:"replay_matched"`
	ReplayTotal    int     `json:"replay_total"`
}

Report is the result of Verify: every check that ran, plus the counts a caller needs for a one-line summary.

func Verify

func Verify(b Bundle, opts VerifyOptions) (Report, error)

Verify recomputes everything a bundle claims about itself, and — when a Client is supplied — cross-checks those claims against the live store.

The error return is reserved for operational failures; verification outcomes, including an unreachable store, are always reported as failed checks in the Report so a caller can print all of them at once.

type Resource

type Resource struct {
	URI       string `json:"uri"`
	Namespace string `json:"namespace"`
	Path      string `json:"path"`
	Source    Source `json:"source"`
	Policy    Policy `json:"policy"`
	// Missing marks a URI whose resource definition no longer exists.
	// Recorded rather than fatal: a manifest stays replayable after its
	// resource is deregistered, and the evidence should say exactly that.
	Missing bool `json:"missing,omitempty"`
}

Resource records the definition behind an entry's URI at export time. Source config is always redacted (see internal/redact): a bundle is an artifact meant to leave the building, so it must never carry credentials even when it was built in embedded mode from unredacted local state.

type Source

type Source struct {
	Kind   string       `json:"kind"`
	Config SourceConfig `json:"config"`
}

type SourceConfig

type SourceConfig struct {
	Filesystem *FilesystemConfig `json:"filesystem,omitempty"`
	GitHub     *GitHubConfig     `json:"github,omitempty"`
	HTTP       *HTTPConfig       `json:"http,omitempty"`
}

type Subject

type Subject struct {
	Name   string `json:"name"`
	Digest Digest `json:"digest"`
}

Subject names the manifest and digests it with the Merkle root over its entries — the single value an external attestation needs to sign.

type VerifyOptions

type VerifyOptions struct {
	// Client, when non-nil, adds the store cross-check: the manifest is
	// replayed again now and its hashes are compared with the ones the
	// bundle recorded. Leave nil for a fully offline verification.
	Client client.Client
	// Context is used for those Client calls. The Verify signature is
	// fixed by the evidence API, so the context rides along here instead
	// of being the first argument; nil means context.Background().
	Context context.Context
}

VerifyOptions configures the checks Verify runs.

Jump to

Keyboard shortcuts

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