Skip to content

ci(docs): attest which wheels binary verify:docs exercises (path + version) - #3050

Merged
bpamiri merged 3 commits into
developfrom
peter/issue-3042-verify-docs-binary-attestation
Jun 12, 2026
Merged

ci(docs): attest which wheels binary verify:docs exercises (path + version)#3050
bpamiri merged 3 commits into
developfrom
peter/issue-3042-verify-docs-binary-attestation

Conversation

@bpamiri

@bpamiri bpamiri commented Jun 12, 2026

Copy link
Copy Markdown
Collaborator

What

Smallest honest slice of #3042: make every verify:docs run state WHICH wheels binary its {test:cli} / {test:compile} / {test:tutorial} blocks exercised, and document the attestation gap.

  • lib/exec.mjs — new wheelsBinaryAttestation(): one line with the resolved binary path, how it was resolved (WHEELS_BIN vs PATH discovery), and the binary's --version output. Pure addition; resolveWheels() and runExec() untouched (kept minimal because verify-docs.mjs is 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 logs command -v wheels + wheels --version and 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, the WHEELS_BIN override knob, and the CI implication.

What this PR deliberately does NOT do

Wiring docs-verify.yml to 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:docs run (default resolution):

verify-docs: wheels binary: /opt/homebrew/bin/wheels (via PATH discovery) — Wheels Version: 4.0.3
verify-docs: scanning 1 file(s)
verify-docs: found 1 tagged block(s)

1 passed, 0 failed

Same run with WHEELS_BIN=/opt/homebrew/bin/wheels confirms the knob is labeled:

verify-docs: wheels binary: /opt/homebrew/bin/wheels (via WHEELS_BIN) — Wheels Version: 4.0.3

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 pristine origin/develop in the same environment — both trace to the local brew CLI's wheels cfml exiting 1 with lucee.runtime.exp.NativeException: Index 0 out of bounds for length 0 on a component extends="Model" body, unrelated to this diff (verified via stash → baseline run → pop). On CI both harness steps are continue-on-error: true.

Workflow YAML parse-validated locally.

Refs #3042

🤖 Generated with Claude Code

…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>
@github-actions github-actions Bot added the docs label Jun 12, 2026

@wheels-bot wheels-bot Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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>

@wheels-bot wheels-bot Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.mjs that ensureServer() is "the one spawn site that cannot go through runExec()" checks out — a grep across the harness shows every other wheels invocation flows through runExec() (drivers/compile.mjs, drivers/cli.mjs, lib/tutorial-fixture.mjs, lib/fixtures.mjs), and drivers/tutorial.mjs:101 was the only raw spawn('wheels', ...). With WHEELS_BIN set, the old code really did serve tutorial asserts-http blocks from a different binary than the attestation names, so the fix(web/guides) commit closes a genuine false-attestation hole, not a theoretical one.
  • wheelsBinaryAttestation() degrades gracefully: runExec() resolves (never rejects) on spawn error with code: -1 and 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_BINcommand -v wheels → Homebrew bin dirs) matches resolveWheels() in lib/exec.mjs:14-27 line 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

@wheels-bot wheels-bot Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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:37 still prints the verify-docs: wheels binary: ... attestation via wheelsBinaryAttestation() 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 only wheels spawn sites are runExec()'s substituted spawn (lib/exec.mjs:90, via resolvedProgram at line 87) and the tutorial dev server's spawn(RESOLVED_WHEELS, ['start']) (drivers/tutorial.mjs:101). No new raw spawn('wheels', ...) PATH lookups crept in.
  • wheelsBinaryAttestation() (lib/exec.mjs:46-58) still degrades gracefully when the binary is missing — runExec() resolves with code: -1 and 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.

@bpamiri
bpamiri merged commit f73a9cd into develop Jun 12, 2026
15 of 16 checks passed
@bpamiri
bpamiri deleted the peter/issue-3042-verify-docs-binary-attestation branch June 12, 2026 04:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant