You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Parent:#1400 · Labels:enhancement, area/recipes (auto, recipes/**), area/ci (auto, .github/**) · Size: M · Depends on: none · Implements:#1347
Goal. Establish the in-repo recipes/evidence/ pointer contract per #1347 as the community/partner entry point, wire first-party UAT to ingest directly (no per-run commit), and stand up the maintained signer allowlist + path-ownership enforcement.
Scope.
Create recipes/evidence/ (does not exist at HEAD) and adopt the Make evidence pointers per-source (per contributing party) #1347 Option A per-source, add-only layoutrecipes/evidence/<slug>/<source>/<bundle-digest>.yaml (see Pointer file topology): one immutable single-attestation V1 pointer per run, where <source> is a stable slug derived from the verified signer OIDC identity. Each file is the existing schema (pkg/evidence/attestation/types.go:188, PointerSchemaVersion = "1.0.0", :34), parseable by LoadAndValidatePointer (pointer.go:37); discovery is by glob <slug>/<source>/*.yaml; nothing is overwritten. (Supersedes the earlier per-signer-file sketch.)
Path ownership (anti-squat). Add CODEOWNERS rules (and/or a CI check) per recipes/evidence/<slug>/<source>/ so a party can only write under its own <source>/ — the path is otherwise squattable (Make evidence pointers per-source (per contributing party) #1347 cross-cutting).
First-party UAT does NOT commit a pointer per run. That would churn main nightly. The UAT workflow already pushes a signed bundle to OCI (uat-gcp.yaml:291) with its OIDC identity pinned (uat-aws.yaml:258-260); it invokes GP2 ingest directly with the bundle ref instead. (A single low-cadence first-party pointer per launch recipe MAY be committed for discoverability/parity, drift-refreshed à la bom-refresh.yaml — but not per run.)
Signer allowlist. An in-tree, PR-reviewed allowlist (recipes/evidence/allowlist.yaml) with a first-party-issuer pin (GitHub-Actions OIDC for NVIDIA/aicr), a community section, and a partner section. Entry semantics so the allowlist is not itself a sybil surface: each entry pins a fully-anchored issuer + identity pair (exact identity, or a tightly-bounded regex with no wildcard org/repo); classes disjoint; no two entries overlap. GP2's verify step and GP4's consensus model read it to classify a signer and decide corroboration weight; an unknown verified signer is admitted as "reported," never corroborating.
Verifier/consumer follow-ups (Make evidence pointers per-source (per contributing party) #1347). Generalize the fixed-path Attestations[0] consumers (verify.go:147-148, fetch.go:136-139) to glob-based multi-source discovery, and update the hardcoded emit/publish path (emit.go:166, publish.go:120). Each file stays a single-attestation V1 pointer — no per-file schema change; the delta is discovery + path convention.
Community-PR pointer path. A contributor adds their ownrecipes/evidence/<slug>/<source>/<digest>.yaml (and, for corroboration weight, an allowlist entry) via PR — alongside, never replacing, any other party's; maintainer review is the trust gate; the AICR ingest job (GP2) does the bucket write.
Out of scope. The ingest job (GP2); the bucket/SA (GP3); the generator (GP4). Producing the bundle (existing nightly / ADR-007). The schema-2.0 multi-attestation file (deferred — Option A needs none).
Tests. Each committed pointer parses+validates via LoadAndValidatePointer (pointer.go:37) with a non-empty PointerSigner.Identity/Issuer; a two-sources-one-recipe test asserting two files under <slug>/<source-a>/ and <slug>/<source-b>/ both parse and are found by glob discovery (no overwrite); a path-ownership test that a pointer written under another party's <source>/ is rejected by the CODEOWNERS/CI check; an allowlist-schema test (well-formed, classes disjoint, no duplicate identities, no over-broad entry — an identity pattern matching more than its intended single org/workflow is rejected); determinism of any generated pointer YAML (MarshalYAMLDeterministic, pkg/serializer/yaml.go:31).
Acceptance.recipes/evidence/ uses the #1347 per-source add-only layout with CODEOWNERS path-ownership; two distinct sources for one recipe produce two non-colliding immutable pointers discovered by glob; first-party UAT ingests directly without committing a per-run pointer; an in-tree community/partner allowlist with anchored, disjoint, non-overlapping entries exists and is documented; the community-PR path is documented; pointers validate against the existing schema.
Child of #1400 · staged from docs/design/013-interim-evidence-dashboard.md (GP1).
Parent: #1400 · Labels:
enhancement,area/recipes(auto,recipes/**),area/ci(auto,.github/**) · Size: M · Depends on: none · Implements: #1347Goal. Establish the in-repo
recipes/evidence/pointer contract per #1347 as the community/partner entry point, wire first-party UAT to ingest directly (no per-run commit), and stand up the maintained signer allowlist + path-ownership enforcement.Scope.
recipes/evidence/(does not exist at HEAD) and adopt the Make evidence pointers per-source (per contributing party) #1347 Option A per-source, add-only layoutrecipes/evidence/<slug>/<source>/<bundle-digest>.yaml(see Pointer file topology): one immutable single-attestation V1 pointer per run, where<source>is a stable slug derived from the verified signer OIDC identity. Each file is the existing schema (pkg/evidence/attestation/types.go:188,PointerSchemaVersion = "1.0.0",:34), parseable byLoadAndValidatePointer(pointer.go:37); discovery is by glob<slug>/<source>/*.yaml; nothing is overwritten. (Supersedes the earlier per-signer-file sketch.)CODEOWNERSrules (and/or a CI check) perrecipes/evidence/<slug>/<source>/so a party can only write under its own<source>/— the path is otherwise squattable (Make evidence pointers per-source (per contributing party) #1347 cross-cutting).mainnightly. The UAT workflow already pushes a signed bundle to OCI (uat-gcp.yaml:291) with its OIDC identity pinned (uat-aws.yaml:258-260); it invokes GP2 ingest directly with the bundle ref instead. (A single low-cadence first-party pointer per launch recipe MAY be committed for discoverability/parity, drift-refreshed à labom-refresh.yaml— but not per run.)recipes/evidence/allowlist.yaml) with a first-party-issuer pin (GitHub-Actions OIDC forNVIDIA/aicr), a community section, and a partner section. Entry semantics so the allowlist is not itself a sybil surface: each entry pins a fully-anchored issuer + identity pair (exact identity, or a tightly-bounded regex with no wildcard org/repo); classes disjoint; no two entries overlap. GP2's verify step and GP4's consensus model read it to classify a signer and decide corroboration weight; an unknown verified signer is admitted as "reported," never corroborating.Attestations[0]consumers (verify.go:147-148,fetch.go:136-139) to glob-based multi-source discovery, and update the hardcoded emit/publish path (emit.go:166,publish.go:120). Each file stays a single-attestation V1 pointer — no per-file schema change; the delta is discovery + path convention.recipes/evidence/<slug>/<source>/<digest>.yaml(and, for corroboration weight, an allowlist entry) via PR — alongside, never replacing, any other party's; maintainer review is the trust gate; the AICR ingest job (GP2) does the bucket write.Out of scope. The ingest job (GP2); the bucket/SA (GP3); the generator (GP4). Producing the bundle (existing nightly / ADR-007). The schema-2.0 multi-attestation file (deferred — Option A needs none).
Key files. New
recipes/evidence/<slug>/<source>/<digest>.yaml+recipes/evidence/allowlist.yaml+.github/CODEOWNERSentries; pointer schemapkg/evidence/attestation/types.go:188-226; loaderpkg/evidence/verifier/pointer.go:37; fixed-path consumers to generalizeverifier/verify.go:147-148,verifier/fetch.go:136-139; hardcoded emit/publish pathpkg/evidence/attestation/emit.go:166,publish.go:120; first-party identity pinuat-aws.yaml:258-260, UAT OCI pushuat-gcp.yaml:291; bot-PR precedent.github/workflows/bom-refresh.yaml; #1347.Tests. Each committed pointer parses+validates via
LoadAndValidatePointer(pointer.go:37) with a non-emptyPointerSigner.Identity/Issuer; a two-sources-one-recipe test asserting two files under<slug>/<source-a>/and<slug>/<source-b>/both parse and are found by glob discovery (no overwrite); a path-ownership test that a pointer written under another party's<source>/is rejected by the CODEOWNERS/CI check; an allowlist-schema test (well-formed, classes disjoint, no duplicate identities, no over-broad entry — an identity pattern matching more than its intended single org/workflow is rejected); determinism of any generated pointer YAML (MarshalYAMLDeterministic,pkg/serializer/yaml.go:31).Acceptance.
recipes/evidence/uses the #1347 per-source add-only layout with CODEOWNERS path-ownership; two distinct sources for one recipe produce two non-colliding immutable pointers discovered by glob; first-party UAT ingests directly without committing a per-run pointer; an in-tree community/partner allowlist with anchored, disjoint, non-overlapping entries exists and is documented; the community-PR path is documented; pointers validate against the existing schema.Child of #1400 · staged from
docs/design/013-interim-evidence-dashboard.md(GP1).