ci(docs): attest which wheels binary verify:docs exercises (path + version) - #3050
Conversation
…rsion) A green verify:docs run previously never stated WHICH wheels binary the cli/compile/tutorial blocks spawned — on CI that is the released brew CLI, not a CLI built from the checkout, so green attested to the release while reading like it attested to the PR branch (issue 3042). - lib/exec.mjs: new wheelsBinaryAttestation() returning a one-line attestation (resolved path, WHEELS_BIN vs PATH discovery, --version output). Pure addition; resolveWheels() untouched. - verify-docs.mjs: print the attestation line at run start. - docs-verify.yml: smoke-test step now logs 'command -v wheels' + version and documents that this workflow installs the RELEASED brew CLI; WHEELS_BIN can redirect the harness at a branch-built one. - VALIDATION.md: document the binary resolution order, the attestation line, the WHEELS_BIN knob, and the CI implication. Deliberately NOT in this slice: wiring docs-verify.yml to a CLI built from the checkout (so a branch CLI change can flip a cli block red). That remains tracked by the issue. Refs #3042 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: Peter Amiri <peter@alurium.com>
There was a problem hiding this comment.
Wheels Bot — Reviewer
TL;DR: This PR adds a binary-attestation line to verify:docs (resolved wheels path + resolution source + --version output), logs the same in the CI smoke-test step, and documents the released-CLI-vs-checkout attestation gap in VALIDATION.md. The change is a clean, well-scoped slice of #3042: pure addition, no shell-injection surface (runExec stays shell: false), commit message conforms to commitlint and carries a DCO sign-off, and no CFML is touched so cross-engine concerns don't apply. Verdict: comment — one minor accuracy nit in the attestation label, nothing blocking.
Correctness
web/sites/guides/scripts/verify-docs/lib/exec.mjs:40 — the (via PATH discovery) label is inaccurate for two of the three non-WHEELS_BIN resolution outcomes.
const source = process.env.WHEELS_BIN ? 'WHEELS_BIN' : 'PATH discovery';resolveWheels() (exec.mjs:14-27) has four outcomes: WHEELS_BIN, command -v on PATH, the Homebrew bin-dir scan (/opt/homebrew/bin, /usr/local/bin, /home/linuxbrew/.linuxbrew/bin), and the bare-'wheels' literal fallback. The Homebrew-dir branch only fires when command -v failed — i.e. the binary is not on PATH — yet the attestation line would still print (via PATH discovery). Same for the unresolved fallback, where the line reads wheels binary: wheels (via PATH discovery). For a feature whose entire purpose is stating accurately which binary ran, the label should not claim a resolution path that didn't happen. The resolved path itself is still printed (the load-bearing fact), and the --version probe surfaces the broken-fallback case, so this is minor — but it's cheap to fix without touching resolveWheels() (which I understand is deliberately kept minimal against the #3041 concurrent edits):
const source = process.env.WHEELS_BIN
? 'WHEELS_BIN'
: RESOLVED_WHEELS === 'wheels'
? 'unresolved fallback'
: 'PATH/Homebrew discovery';Or, when #3041 lands, have resolveWheels() return { path, source } so the label is exact per branch. Note the new VALIDATION.md section correctly documents PATH lookup and the Homebrew-dir scan as distinct resolution steps (items 2 and 3), so the doc and the label currently disagree with each other.
Tests
No unit test covers wheelsBinaryAttestation(), but there is no exec.test.mjs in web/sites/guides/scripts/verify-docs/test/ today (coverage there is cli / compile / extract / orchestrator / tutorial), and the function's interesting behavior is spawning the real binary — so the absence matches prior art and I'm not asking for one. The PR body's honest accounting of the 2 pre-existing harness failures (reproduced on pristine origin/develop via stash → baseline → pop) checks out against the continue-on-error: true steps in docs-verify.yml (lines 105 and 122).
Docs
The new VALIDATION.md section accurately reflects the implementation: the resolution order matches resolveWheels() line-for-line, the example output matches the actual format string at exec.mjs:50, and the CI implication matches the workflow (released brew CLI, WHEELS_BIN unset). No changelog fragment is required — this is ci-type internal tooling, not a user-facing fix/feat per changelog.d/README.md conventions.
Commits
ci(docs): attest which wheels binary verify:docs exercises (path + version) — valid type, header 76 chars (≤ 100), not ALL-CAPS, body explains the why, Signed-off-by: Peter Amiri <peter@alurium.com> present and DCO-conformant. The PR title matches the commit header, so the squash-merge lint gate passes.
Security
wheelsBinaryAttestation() goes through runExec, which spawns with shell: false (exec.mjs:66) — no new injection surface. The workflow's new command -v wheels / wheels --version lines contain no untrusted interpolation. Clean.
… wheels binary
The attestation docs claimed every spawned wheels command resolves
through resolveWheels() (WHEELS_BIN > PATH > brew dirs), but the
tutorial driver's ensureServer() started the dev server via a raw
spawn('wheels', ['start']) PATH lookup — the one wheels spawn site
that can't use runExec() because it needs the long-running child
handle. With WHEELS_BIN set, tutorial asserts-http blocks were served
by whatever wheels was on PATH while the attestation line named the
WHEELS_BIN binary: a false attestation.
- lib/exec.mjs: export RESOLVED_WHEELS for spawn sites that bypass
runExec(); resolveWheels() itself untouched.
- drivers/tutorial.mjs: spawn(RESOLVED_WHEELS, ['start']) so the
tutorial dev server is the same binary every other block exercises.
- VALIDATION.md: state explicitly that the tutorial dev server is
covered by the single-binary resolution.
Harness unit tests: 26 pass / 3 fail, byte-identical failure set to
unmodified HEAD (known local-env failures CI soft-fails); no
regressions.
Refs #3042
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Peter Amiri <peter@alurium.com>
There was a problem hiding this comment.
Wheels Bot — Reviewer
TL;DR: This PR makes every verify:docs run print which wheels binary it exercised (path + resolution source + --version), routes the tutorial dev-server spawn through the same resolved binary, and documents the CI attestation gap honestly. The implementation is correct, the scope discipline is good (the "what this deliberately does NOT do" section matches the diff), and the docs match the code. Verdict: comment — two minor non-blocking nits below, nothing that should hold up merge.
Correctness
Verified, no findings:
- The claim in
lib/exec.mjsthatensureServer()is "the one spawn site that cannot go through runExec()" checks out — a grep across the harness shows every otherwheelsinvocation flows throughrunExec()(drivers/compile.mjs,drivers/cli.mjs,lib/tutorial-fixture.mjs,lib/fixtures.mjs), anddrivers/tutorial.mjs:101was the only rawspawn('wheels', ...). WithWHEELS_BINset, the old code really did serve tutorialasserts-httpblocks from a different binary than the attestation names, so thefix(web/guides)commit closes a genuine false-attestation hole, not a theoretical one. wheelsBinaryAttestation()degrades gracefully:runExec()resolves (never rejects) on spawn error withcode: -1and the error message in stderr, so a missing binary produces--version failed (exit -1: spawn wheels ENOENT)and the run continues — extract-only/illustrative runs aren't broken by the new startup call.VALIDATION.md's documented resolution order (WHEELS_BIN→command -v wheels→ Homebrew bin dirs) matchesresolveWheels()inlib/exec.mjs:14-27line for line.
Conventions
Nit — (via PATH discovery) is inaccurate for the brew-dir fallback. lib/exec.mjs:47:
const source = process.env.WHEELS_BIN ? 'WHEELS_BIN' : 'PATH discovery';resolveWheels() has four outcomes (WHEELS_BIN, command -v hit, Homebrew-dir probe, bare 'wheels' fallback), but the attestation collapses the last three into "PATH discovery". When command -v misses and the binary is found by probing /opt/homebrew/bin etc. (exec.mjs:21-25), the binary was explicitly not found on PATH — the label says the opposite. The deeper cause is that this line re-derives the source instead of getting it from the resolver; the two can drift (it also reads process.env.WHEELS_BIN at call time while RESOLVED_WHEELS froze at module load). Suggested fix: have resolveWheels() return { path, source } (e.g. 'WHEELS_BIN' | 'PATH' | 'homebrew fallback' | 'unresolved') and have both RESOLVED_WHEELS and the attestation consume it. Non-blocking — the printed absolute path disambiguates in practice.
Tests
Optional suggestion, not a finding: there's no unit test asserting the attestation line's shape (test/ covers the drivers and orchestrator; lib/exec.mjs has no dedicated test file today, so this matches existing practice and I'm not flagging it as a gap). If the #3042 remainder lands CI logic that greps for this line, a cheap format assertion (/^wheels binary: .+ \(via .+\) — /) would keep that contract pinned. Fine to defer to the follow-up.
The PR's evidence section is commendably honest about the 2 pre-existing harness failures reproducing on pristine origin/develop.
Docs
VALIDATION.md additions are accurate against the code (resolution order, the WHEELS_BIN knob, the tutorial-dev-server coverage claim, the CI implication). The workflow comment in docs-verify.yml correctly states that green CI cli blocks attest to the released brew CLI, which is exactly the gap #3042 tracks. No changelog fragment needed — this is internal CI/docs-tooling, not a user-facing framework change.
Commits
Both commits conform to commitlint.config.js: valid types (ci, fix), headers ≤ 100 chars, not ALL-CAPS, DCO sign-off present, and the bodies explain the why (the false-attestation scenario) rather than restating the diff. No findings.
Signed-off-by: Peter Amiri <peter@alurium.com> # Conflicts: # web/sites/guides/scripts/verify-docs/verify-docs.mjs
There was a problem hiding this comment.
Wheels Bot — Reviewer
TL;DR: This head (3fd13fb) differs from the previously reviewed head (efbb716) only by a merge of origin/develop — the PR's own content (binary attestation line in verify:docs, routing the tutorial dev-server spawn through RESOLVED_WHEELS, CI smoke-step logging, VALIDATION.md documentation of the released-CLI-vs-checkout gap) is unchanged. I re-verified that the merge introduced no semantic conflicts with develop's concurrent verify-docs changes (#3043, #3052): the attestation invariants hold post-merge. Verdict: comment — one minor, previously-raised nit persists; nothing blocking.
Correctness
Re-verified on the merged tree, no findings:
- The attestation call survived the develop merge:
web/sites/guides/scripts/verify-docs/verify-docs.mjs:37still prints theverify-docs: wheels binary: ...attestation viawheelsBinaryAttestation()before scanning. - The single-binary invariant still holds after #3052's compile-driver rework landed via the merge: a grep across
web/sites/guides/scripts/verify-docs/shows the onlywheelsspawn sites arerunExec()'s substituted spawn (lib/exec.mjs:90, viaresolvedProgramat line 87) and the tutorial dev server'sspawn(RESOLVED_WHEELS, ['start'])(drivers/tutorial.mjs:101). No new rawspawn('wheels', ...)PATH lookups crept in. wheelsBinaryAttestation()(lib/exec.mjs:46-58) still degrades gracefully when the binary is missing —runExec()resolves withcode: -1and the error message in stderr, producing the--version failed (exit -1: ...)branch rather than crashing the run.
Conventions
Persisting nit (non-blocking, raised on both prior heads): lib/exec.mjs:47
const source = process.env.WHEELS_BIN ? 'WHEELS_BIN' : 'PATH discovery';resolveWheels() (lib/exec.mjs:14-27) has four outcomes — WHEELS_BIN, command -v hit, Homebrew bin-dir probe, bare 'wheels' fallback — but the label collapses the last three into "PATH discovery", which is the opposite of what happened when the Homebrew-dir probe fired (the binary was explicitly not on PATH). The printed absolute path disambiguates in practice, so this stays a nit. Cheapest exact fix remains having resolveWheels() return { path, source } and letting both RESOLVED_WHEELS and the attestation consume it — fine to fold into the #3042 remainder.
Tests
No new findings. test/ still has no exec.test.mjs (coverage is allowlist / cli / compile / extract / orchestrator / tutorial), so the absence of a format assertion for the attestation line matches existing practice. The earlier optional suggestion stands: if the #3042 remainder greps CI logs for this line, pin its shape with a cheap format assertion matching ^wheels binary: .+ \(via .+\) — then.
Commits
ci(docs): attest which wheels binary verify:docs exercises (path + version) and fix(web/guides): route tutorial dev-server spawn through the attested wheels binary both conform to commitlint.config.js (valid types, headers ≤ 100 chars, not ALL-CAPS, DCO sign-offs present, bodies explain the why). The third commit is the develop merge, which commitlint ignores by convention. No findings.
Security
Unchanged from prior review: runExec() keeps shell: false (lib/exec.mjs:73), the tutorial spawn keeps shell: false (drivers/tutorial.mjs:104), and the workflow's new command -v wheels / wheels --version lines contain no untrusted interpolation. Clean.
What
Smallest honest slice of #3042: make every
verify:docsrun state WHICHwheelsbinary its{test:cli}/{test:compile}/{test:tutorial}blocks exercised, and document the attestation gap.lib/exec.mjs— newwheelsBinaryAttestation(): one line with the resolved binary path, how it was resolved (WHEELS_BINvs PATH discovery), and the binary's--versionoutput. Pure addition;resolveWheels()andrunExec()untouched (kept minimal becauseverify-docs.mjsis concurrently edited on the verify:docs: compile driver executes snippets in a bare engine — 312/317 live-tree blocks fail on missing framework context, not content #3041 branch).verify-docs.mjs— prints the attestation line at run start (one import + one call site)..github/workflows/docs-verify.yml— smoke-test step now logscommand -v wheels+wheels --versionand carries a comment making the implication explicit: this workflow installs the released brew CLI, so green cli blocks attest to that release, not the checkout.VALIDATION.md— documents the binary resolution order, the attestation line, theWHEELS_BINoverride knob, and the CI implication.What this PR deliberately does NOT do
Wiring
docs-verify.ymlto a CLI built from the checkout (acceptance criterion 2 of #3042: a branch CLI change flipping a cli block red) is the issue remainder — left open, tracked by #3042.Evidence
Single-file
pnpm verify:docsrun (default resolution):Same run with
WHEELS_BIN=/opt/homebrew/bin/wheelsconfirms the knob is labeled:pnpm test:docs-harness: 31/33 pass with this change. The 2 failures (runCompile passes a valid CFC block,verify-docs reports pass/fail counts) reproduce identically on pristineorigin/developin the same environment — both trace to the local brew CLI'swheels cfmlexiting 1 withlucee.runtime.exp.NativeException: Index 0 out of bounds for length 0on acomponent extends="Model"body, unrelated to this diff (verified via stash → baseline run → pop). On CI both harness steps arecontinue-on-error: true.Workflow YAML parse-validated locally.
Refs #3042
🤖 Generated with Claude Code