fix(wake): #912 exercise the digest/HMAC trust suite in real CI (fix runner divergence + openssl + hard-require) #921
Reference in New Issue
Block a user
Delete Branch "fix/wake-912-digest-ci"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Closes #912; Part of #892.
Runner-env root cause (D1/D4/D5/D6 failed only in Woodpecker)
A masked-local run passed, so the divergence was runner-specific. It is a TOOLCHAIN divergence, not locale or root:
digest.sh's_scrub_ctrlused GNU-sed\xNNhex-escape byte matching. The CIteststep runs onnode:24-alpine(ci-base), whose sed is BusyBox. BusyBox sed REJECTS a\xNNcharacter range (bad regex ... Invalid character range), aborting the whole scrub sed and silently voiding the scrub. Every scrubbed value collapsed to empty, cascading into D1 (blank locators), D4 (no scrub/redact, SHA blanked), D5 (blank WAKE_AGENT prefix), D6 (blank[digest]class). Reproduced the exact 9-assertion failure in the ci-base image as root;LC_ALL=Cwas already set, ruling out locale.Fix (correct layer: a wake digest must render identically on any runner)
_scrub_ctrl: byte patterns are now LITERAL bytes (printf %b), matching byte-identically under GNU sed (glibc dev) and BusyBox sed (Alpine CI) — verified identical output on both. Contract preserved: two-tier trust, exit-4 hard-locator FAIL-LOUD, secret scrub, and 40-hex SHA preservation all unchanged (deterministic, not weakened).grep -qP(BusyBox grep has no-P; the&&silently skipped the assertion in CI) with portable literal-bytegrep -Eranges (two disjoint bidi/zero-width ranges, excluding legit U+2014 em-dash).CI enablement
openssl(the non-circular HMAC signer) so H1/H2, beacon B12, install I8 run. Theapk addin the test step covers PR pipelines before ci-base rebuilds.CIis set (WoodpeckerCI=woodpecker) and FAIL loud if absent; KEEP the skip for openssl-less local dev.Evidence (ci-base container, as root)
Definitive acceptance is this PR's own Woodpecker pipeline going green with the suite unmasked + hard-required.
🤖 Generated with Claude Code
https://claude.ai/code/session_0158NZqN2n2ymKFeJAZ4GUCb
Make the wake digest/HMAC suite RUN and PASS in the real Woodpecker CI runner (Alpine/musl, root), then hard-require the HMAC legs in CI. Root cause of the runner-only D1/D4/D5/D6 failures (a masked-local run passed, so it was runner-specific): a TOOLCHAIN divergence, not locale or root. digest.sh's _scrub_ctrl used GNU-sed `\xNN` hex-escape byte matching. The CI runner is node:24-alpine, whose sed is BusyBox — BusyBox sed REJECTS a `\xNN` character range ("bad regex ... Invalid character range"), aborting the whole scrub sed and silently VOIDING the scrub. Every scrubbed value collapsed to empty, cascading into D1 (blank locators), D4 (no scrub/redact, SHA blanked), D5 (blank agent prefix), D6 (blank [digest] class). Confirmed by reproducing the exact 9-assertion failure in the ci-base image as root. Fix (at the correct layer — a wake digest must render identically on any runner): - digest.sh _scrub_ctrl: patterns are now LITERAL bytes (printf %b), matching byte-identically under GNU sed (glibc dev) and BusyBox sed (Alpine CI). Verified identical output on both. Contract preserved: two-tier trust, exit-4 hard-locator FAIL-LOUD, secret-scrub, and 40-hex SHA preservation all unchanged — deterministic, not weakened. - test-wake-digest-hmac.sh D4: replaced PCRE `grep -qP` (BusyBox grep has no -P; the `&&` silently skipped the check in CI) with portable literal-byte `grep -E` ranges (two disjoint bidi/zero-width ranges, excluding legit U+2014 em-dash). CI enablement: - Dockerfile.ci + .woodpecker/ci.yml test step: add openssl (the non-circular HMAC signer) so H1/H2, beacon B12, install I8 can run. The apk add in the test step covers PR pipelines before ci-base rebuilds. - Flip the 3 openssl skip-guards (digest whole-file, beacon B12, install I8) to HARD-REQUIRE openssl when CI is set (Woodpecker CI=woodpecker) and FAIL loud if absent; KEEP the skip for openssl-less local dev. - manifest.txt: wake 0.6.2 -> 0.6.3 (digest.sh scrub portability; precedent). Red-first verified in the ci-base container (root): D4 catches a broken redaction, H1 catches a tamper that doesn't break the MAC, B12/I8 catch a corrupted signer. Closes #912 Part of #892 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0158NZqN2n2ymKFeJAZ4GUCbRecord of Review — PR #921 (issue #912): digest/HMAC trust suite RUNS+PASSES in real CI — FINAL, CI-GREEN
VERDICT: APPROVE — GO. REVIEWED-HEAD (full-40):
ef43cc3be89739fbc5cfec583ecefd459d8860ed. CI: TERMINAL-GREEN (Woodpecker 2066). G6 acceptance MET.Review basis
Independent reviewer
aa75f8e3(opus, ≠ buildermosaic-coder) — APPROVE, all 7 criteria PASS, docker-reproduced against the REAL runner (not masked-local):ef43cc3b…; mergeable; PR-author id2 ≠ commit-authormosaic-coder; bodyCloses #912+Part of #892; delta = exactly the 7 files (.woodpecker/ci.yml, Dockerfile.ci, digest.sh, manifest.txt, test-wake-digest-hmac.sh, test-wake-beacon.sh, test-wake-install.sh); manifest 0.6.2→0.6.3.ef43cc3bstatus:success; test-step log: digest-hmac "all invariants passed (8 groups)" + beacon 12 + install 8; D4/H1/H2/B12/I8 headers present; openssl 3.5.7 genuinely installed; ZEROSKIP: openssl/FAIL:— the HMAC legs actually ran, first time ever in real CI._scrub_ctrlin node:24-alpine AND ci-base →sed: bad regex … Invalid character range, 0 bytes (scrub voided). PR version byte-identical (sha2569f1cb66f…) across GNU host + node:24-alpine (BusyBox) + ci-base. Root cause = BusyBox-vs-GNU sed toolchain divergence (4th env-masking class), NOT locale._scrub_ctrlonly (_has_hard_locator/exit-4 untouched); scrub strips control/ANSI/bidi/zero-width/BOM; legit em-dash (E2 80 94) + legit 40-hex SHA PRESERVED; secrets still redact (D4 canary negatives green); D4grep -qP→literal-bytegrep -Edisjoint ranges is a GENUINE check on BusyBox (not the silent no-op it was — BusyBox grep has no -P).6/7. CI-config + gates — openssl present in the pipeline; Dockerfile.ci bakes it for the ci-base rebuild; shellcheck clean; verify-sanitized PASS; firewall 0; prettier clean.
Non-blocking follow-up
After merge + the ci-base image rebuild, confirm the baked openssl makes the test-step
apk add openssla true no-op (reviewer obs; not a blocker).6-check — GO
ef43cc3be89739fbc5cfec583ecefd459d8860ed✓ · 3. reviewer(aa75f8e3)≠builder durable RoR ✓ · 4. reviewed==CI==merge-head allef43cc3b✓ · 5. bodyCloses #912+Part of #892✓ · 6. queue-guard at merge.GO for id-11 + squash-merge at FULL-40
ef43cc3be89739fbc5cfec583ecefd459d8860ed. Closes #912 (the digest/HMAC trust layer now genuinely runs in real CI — pre-vector G6 evidence). NOTE: sibling #920 also touches digest.sh + manifest → union-rebase #920 onto the new main after this merge. Non-executor.GO — Gate-16 id-11 stamp, pinned to exact FULL head
ef43cc3be8.Basis: verbatim FINAL RoR (comment 19102) — independent review APPROVE 7/7 with the docker-reproduce mandate honored: RED baseline reproduced on the real BusyBox runner image, the portable scrub proven byte-identical (sha256-matched) across GNU and both alpine images, all three skip-guards verified fail-loud-in-CI/skip-in-dev, digest contract preserved. Root cause = the FOURTH environment-masking class (BusyBox-vs-GNU toolchain: GNU-only sed hex-ranges + a silently no-op'd grep -qP assertion that had never run in CI). G6 EVIDENCE REQUIREMENT SATISFIED: pipeline 2066 green with the full trust suite (D1-D6, H1-H2, B12, I8) genuinely executing under openssl 3.5.7 — zero skips, zero fails. Closes #912. Part of #892. Named executor: Mos (id-11), squash pinned.