test(signing): wsc e2e in CI — pinned v0.9.0, sha256-verified, hard-fails on missing wsc#140
Merged
Conversation
Closes the "end-to-end signing was not validated" gap explicitly flagged when Phase 5 (`synth compile --sign-output`, PR #135) shipped. The implementing subagent honestly noted that `wsc` was not on PATH in its environment, so only argv-shape unit tests existed; the actual Fulcio + Rekor round-trip was unverified. What this lands: - `.github/workflows/signing-e2e.yml`: downloads a sha256-pinned `wsc` from sigil's GitHub releases (v0.9.0, sha256 9054b4b066e2b0a954110851a43266ff0e9ef12b4e1ecc03c333943fd52cecb6 for the linux-x86_64 binary), builds synth-cli, and runs the e2e test. Triggered on PRs that touch `crates/synth-cli/src/sign.rs|main.rs`, on push to main, and on `v*` tag pushes. `id-token: write` is granted so wsc's keyless flow can obtain a GitHub OIDC token. - `tests/wsc_sign_e2e.sh`: three load-bearing cases. (1) WASM keyless sign + verify round-trip — proves wsc is healthy and the keyless code path that sigil supports today works end-to-end. (2) Synth's actual contract: `synth compile --sign-output` against ELF. As of sigil v0.9.0 this returns the explicit usage error "Keyless signing is currently supported only for WASM format" (sigil's `src/cli/main.rs:770-779`). The script asserts synth surfaces that error verbatim, exits non-zero, preserves the unsigned ELF, and cleans up the `.signing.tmp`. When sigil eventually ships keyless-ELF support, the script auto-detects the flip via a GitHub `::notice::` annotation and switches case 2 into a positive "signed ELF" assertion. (3) Tamper-negative on the case-1 signed WASM — flips a byte, runs `wsc verify --keyless`, and fails if it accepts the tampered module. The script does NOT silently skip when wsc is missing; that would recreate the exact gap this workstream closes. - `docs/sigil-integration.md`: replaces the "End-to-end signing + verification was not validated by the implementing agent" stanza with the actual CI status. Adds a "Verifying a signed WASM module locally" recipe (the path that actually works today) and corrects the verification-flag documentation: sigil v0.9.0 accepts the literal `--cert-identity`, not `--cert-identity-regexp`. - `docs/release-process.md`: Phase 5 status updated from "compiler-side implemented" to "compiler-side implemented + CI-validated end-to-end". Approach: release-download with sha256 pin, not Bazel. `rules_wasm_component` is already in MODULE.bazel but it ships WASM-component toolchains, not the `wsc` CLI distribution; sigil's own release binaries ship per-asset .sha256 sidecars, so pinning by version + sha256 in one place (the workflow file) gives an auditable trust anchor without the complexity of a custom binary- import Bazel rule. Locally validated against sigil v0.9.0's macOS-aarch64 wsc + a debug synth build (same source tree as this commit): case 2 exits rc=1, surfaces the "Keyless signing is currently supported only for WASM" error verbatim, preserves the 741-byte unsigned ELF, and leaves no stale .signing.tmp. Cases 1 and 3 require an OIDC token (GitHub Actions only) and are exercised in CI. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
…pered WASM) The signing-e2e workflow's case 3 (tamper-negative on signed WASM) ran on commit 7f1a9c9 against wsc v0.9.0 and surfaced a real sigil-side gap: 'wsc verify --keyless' returned exit 0 on a WASM whose signed payload (byte at offset 64, inside the module — well before the ~15kB trailing signature section) had been flipped. Filed upstream as pulseengine/sigil#135 with full repro evidence (CI run, exact wsc version + sha256, the byte-flip script). This commit converts case 3 to an xfail with an explicit reference to sigil#135. The test stays in place: - If wsc continues to (incorrectly) accept the tampered file, case 3 XFAILs as expected (workflow green) and notes the gap in CI output. - If sigil#135 is fixed and wsc starts rejecting, case 3 XPASSes and emits a 'flip this back to a hard check' note to maintainers. Also documents the gap in docs/sigil-integration.md (Status section) and adds a CHANGELOG [Unreleased] entry tracking the upstream issue. Until sigil#135 is fixed, 'wsc verify --keyless' should be treated as proving signature-blob well-formedness, NOT module integrity. PR #135's synth-cli signing path is unchanged; the gap is purely on the verify side, but it affects what downstream consumers can claim about a synth-emitted signed artifact.
3 tasks
avrabe
added a commit
that referenced
this pull request
May 25, 2026
Bumps workspace version to 0.7.0 and promotes the [Unreleased] entries (f64 ARM VFP-D codegen from #141, signing-e2e workflow from #140) to a v0.7.0 heading. Adds a falsification statement to the v0.7.0 notes per PulseEngine methodology: the release is wrong if (a) a covered f64 op miscompiles or fails to link on Cortex-M7DP, or (b) signing-e2e goes red on a clean v0.7.0 checkout. Case 3 (tamper-negative) is xfail until sigil#135 ships a fix; cases 1 and 2 must stay hard green. PRs included: #140 test(signing): wsc e2e in CI — pinned v0.9.0, sha256-verified #141 feat(backend): f64 codegen on Cortex-M7DP (non-optimized path)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Closes the v0.6.0 honest blocker: Phase 5's
synth compile --sign-outputwas unit-tested against sigil's CLI surface but never end-to-end. This PR wireswscinto CI via release-download (pinned v0.9.0 + sha256), adds three test cases, and runs the script on every PR touching the sign path plus everyv*tag.Notable finding — sigil v0.9.0 doesn't yet support keyless ELF
While building the e2e the agent discovered: sigil v0.9.0's
wsc sign --keyless --format elfexplicitly rejects with"Keyless signing is currently supported only for WASM format. Use key-based signing for ELF and MCUboot artifacts."Source:pulseengine/sigilsrc/cli/main.rs:770-779at v0.9.0 (clean-room verified). PR #135's argv is forward-compatible with the future shape, but the path can't be a positive ELF-signature test today.The test is therefore structured as: the gap exists and synth handles it correctly (exit non-zero, surface wsc's stderr verbatim, leave the unsigned ELF intact, clean up
.signing.tmp). When sigil ships keyless ELF, the script auto-flips to a positive assertion. Documented indocs/sigil-integration.md.Also corrected:
--cert-identity-regexpdoes not exist in wsc v0.9.0 (only literal--cert-identity). Verified at sigilsrc/cli/main.rs:247-258.Pinned values (clean-room verified against live sigil release)
wscv0.9.0 Linux x86_64:9054b4b066e2b0a954110851a43266ff0e9ef12b4e1ecc03c333943fd52cecb6wscv0.9.0 macOS aarch64 (not used in CI, on file):c7e4fddceed68512400d3f4bdc9a3741a5d7221d9afb0a9e1b8302755764ffd8Test cases (
tests/wsc_sign_e2e.sh)wsc sign --keyless --format wasm+wsc verify --keyless --format wasm. Validates the wsc binary, Fulcio + Rekor reachability, OIDC flow.synth compile … --sign-outputexits non-zero, surfaces the keyless-ELF rejection, preserves the unsigned ELF, cleans up tmp.wsc verifymust reject.Script hard-fails when wsc is missing — no silent skip (verified via clean-room:
[[ -x "$WSC" ]] || fail "...").Workflow
.github/workflows/signing-e2e.yml:permissions: id-token: write, contents: read.ubuntu-latest. Triggers on path-filtered PRs (sign.rs, main.rs, the script, the WAT fixture, the workflow itself) and onv*tag pushes.rules_wasm_componentis already declared but not needed here).sign.rsis unchanged — the argv pinning is still load-bearing.Clean-room verification
A clean-room subagent independently verified (no inherited context): 9 of 10 claims CONFIRMED with file:line citations and live-fetched evidence (sha256 sidecars from sigil release, sigil source at v0.9.0). 1 CANNOT-VERIFY (the agent's local-run output — but the script logic matches what the agent reported).
Test plan
🤖 Generated with Claude Code