claude: documented-recipe verifier (step 1 of 2)#747
Conversation
Add tools/verify_documented_recipes.sh, which runs the artifact-verification recipes documented in docs/verifying_artifacts.md against real coordinates so a showcase can prove the documented adopter commands still work. Anti-drift by construction (extract-and-run): each fenced ```bash block is extracted from the doc at run time, its <placeholders> substituted, and executed verbatim — the checker cannot diverge from the docs. A block is picked by a literal content signature matching exactly one template block (zero/many => hard error); any placeholder left after substitution fails the run; the block runs in a private temp CWD with `set -euo pipefail` prepended so mid-block asserts fail closed. Sigstore/attestation-store reads are retried at block granularity and fail (never skip) on exhaustion. Covered: file VSA via ampel jsonl + cosign/jq, container VSA via ampel oci + cosign download attestation, the github: collector, and gh attestation verify. Add actions/verify-showcase-recipes (thin composite: installs ampel+cosign from tools/go.mod — the single pin source, no second checksum to drift — and calls the script), hermetic unit tests (drift guard + stub-driven orchestration), and an integration test driving the script against the captured npm fixture. Co-Authored-By: Claude Opus 4.8 <[email protected]>
…ies) Co-Authored-By: Claude Opus 4.8 <[email protected]>
|
claude: Smoke run done — the mechanism is empirically proven, not just stub-tested. Installed real ampel v1.3.1 + cosign v3.0.6 from `tools/go.mod` (the exact path the composite uses) and ran the integration test against live Sigstore: ``` This executes the extracted-and-substituted blocks 3/6/7 end-to-end (temp script with prepended `set -euo pipefail`, staging, the `jq -e` asserts, base64 decode) through real tools — so "the substituted blocks are valid commands that actually verify a real VSA" is now verified, not asserted. It also resolves my #1 flagged uncertainty: the doc's remote `git+https://github.com/TomHennen/[email protected]#…\` policy locator resolves and verifies the v0.2.2-signed npm fixture (nothing else tests the remote git+ fetch path — `verify_consumer_vsa` uses the local policy file). Also eyeballed the substituted image blocks 4/8 (no live registry here to run them): `imagename=…; digest=…` first line and the `--digest "$digest" --digestAlg sha256` tail are correct; they're exercised for real in step 2's showcase. Also failed-fast the tamper test (`WRANGLE_RECIPE_RETRIES=1`) so its deterministic failure doesn't burn 3 Sigstore round-trips. |
Co-Authored-By: Claude Opus 4.8 <[email protected]>
bats `run` does not inherit an `export` set in the test body across all versions; a `WRANGLE_RECIPES_DOC=... run` prefix reaches the sourced script deterministically, so the drift-guard tests assert against the fixture doc rather than falling back to the real one. Co-Authored-By: Claude Opus 4.8 <[email protected]>
The awk extractor relied on `printf "%s\0"` NUL separators; busybox/mawk (the CI container's awk) does not emit them, collapsing duplicate blocks into one element so the duplicate-block drift guard passed selection instead of failing closed. Parse fence state in bash so block boundaries are host-awk independent. Co-Authored-By: Claude Opus 4.8 <[email protected]>
claude: Draft — step 1 of 2. Builds the wrangle-side core of a "documented-recipe verifier". Step 2 (wiring it into wrangle-test's showcase) is the owner's, after review.
What this does
docs/verifying_artifacts.mddocuments the exact rawampel/cosign/gh attestationcommands an adopter runs to verify wrangle-built artifacts. Nothing executes those recipes against live artifacts, so they can silently drift (today only the manual cut-release gate catches it). This adds a runner a showcase can call every heartbeat to prove the documented commands still verify.Anti-drift approach: extract-and-run (the brief's preferred option)
tools/verify_documented_recipes.shdoes not reimplement the recipes. At run time it extracts each fenced```bashblock from the doc, substitutes the<placeholders>from flags, and executes the block verbatim. The checker therefore cannot diverge from the docs — drift is impossible, not merely detected.I prototyped extraction first (as the brief asked). Of the three brittleness triggers, only "multiple commands per block" is hit (the two cosign blocks), and that's benign — the whole block is run. Prose sits between blocks, not inside; the one prose-y placeholder (
<resourceUri from the table above>) is a single<[^>]+>match. So extract-and-run held; I did not fall back to the equivalence-guard.Guards that give it the anti-drift property:
<...>) are never selected.<...>surviving substitution fails the run — a new doc placeholder breaks the checker instead of running a half-filled command.set -euo pipefailprepended (the doc blocks carry none; without it the mid-blockjq -easserts and thecosign download | jqpipeline would fail open).Recipes covered
ampel verify … jsonl:ampel verify … oci:ampel … github:collector--attestation-store)jq)cosign download attestationgh attestation verify--provenance)Deferred to the showcase (need live network/registry, can't be hermetic): the ecosystem-native
npm audit signatures/ PyPI PEP-740 checks are out of scope (not VSA/provenance recipes). Private-image pull auth is out of scope (doc calls it out).Two deviations from the literal brief — flagged per the draft's purpose
1. Tool install uses
tools/go.mod(go install), notdownload_verify.shwith a hardcoded checksum. ampel v1.3.1 and cosign v3.0.6 are already pinned intools/go.mod. A second download_verify pin of the same tools is exactly the duplicate-pin drift DEP_MGMT.md §Drift forbids ("a pin literal in more than one file must be single-sourced"); branch-1 /go installis the documented default for canonical Go tools, and #247 says ampel/cosign install via the go.mod manifest. So the composite installs them from go.mod (mirroringtest/setup_integration.sh) — single source, Dependabot-covered, no checksum to drift. I did not add a download_verify install.2. The "passes on good / fails on tampered" fixture check is an integration test, not the hermetic unit test. A keyless VSA verify needs Sigstore/Rekor/TUF; CLAUDE.md ("a test needing a real binary or network is an integration test") puts that out of the deterministic unit suite — which is why the existing
test/consumer/verify_consumer_vsa.batsgates onrequire_sigstore. So:actions/verify-showcase-recipes/*.bats, runs in the PRbatsjob): the drift guard (every recipe extracts + fully substitutes against the real doc; duplicate/missing/new-placeholder fail closed) + stub-driven orchestration (exit-code plumbing, bounded retry, input validation). No network.test/consumer/verify_documented_recipes.bats, inINTEGRATION_BATS+ the dogfood job): drives the script end-to-end against the captured npm fixture — good →3 passed, tampered byte → fail closed.(Note:
tools/verify_documented_recipes.batswould not be picked up bymake bats— its glob istools/*/test.bats— so the hermetic tests live under the action, which the brief allowed.)Retry note
Because a documented recipe is one fenced block, retry is at block granularity (coarser than the brief's "wrap only the Sigstore read"): the idempotent fetch is retried alongside the verify (harmless), and a genuine tamper burns the retries before failing (slower, still fail-closed). Direct consequence of extract-and-run.
Interface
--file/--bundle(file class) ·--image/--digest(image class) ·--provenance·--attestation-store·--resource-uri --repo --type·--non-strict(orWRANGLE_VSA_NON_STRICT=1, mirroring the verify-vsa gate). Exit 0 = all verified, 1 = a recipe failed, 2 = usage/config/doc-drift. All inputs are allowlist-validated before substitution (they reach an executed block).Verification
shellcheck -xclean on all new.shand.bats(runner's exact flags). WSL001-007 conform by inspection (ast-grep unavailable in my sandbox; scripts matchverify_vsa.shpreamble/[[ ]]/printfshape).check_pin_ancestry/check_pin_freshness/check_catalogall exit 0 — thetools/(non-catalog) +actions/additions do not trip freshness. No wrangle workflow references the new action, so no self-ref converge is needed.Unsure / for the owner
git+…@v0.3.1#…) against the v0.2.2-signed npm fixture; both resolve the same-v1contract, so it should PASS in the dogfood job exactly asverify_consumer_vsadoes — worth confirming on first CI run.@refs/tags/v[0-9.]+$anchor → any ref), mirroring the verify-vsa gate. The drift guard asserts the strict verbatim form; non-strict is a tested transform on top.🤖 Generated with Claude Code