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
- func Encode(b Bundle) ([]byte, error)
- func LeafHash(e Entry) []byte
- func MerkleRoot(entries []Entry) string
- type Bundle
- type Check
- type Digest
- type Entry
- type Exporter
- type FilesystemConfig
- type GitHubConfig
- type HTTPConfig
- type Merkle
- type Options
- type Policy
- type Predicate
- type Replay
- type ReplayEntry
- type Report
- type Resource
- type Source
- type SourceConfig
- type Subject
- type VerifyOptions
Constants ¶
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 ¶
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 ¶
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 ¶
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.
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 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 FilesystemConfig ¶
type FilesystemConfig struct {
Path string `json:"path"`
}
type GitHubConfig ¶
type HTTPConfig ¶
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 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 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 ¶
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.