fix(wake): #912 exercise the digest/HMAC trust suite in real CI (fix runner divergence + openssl + hard-require) #921

Merged
Mos merged 1 commits from fix/wake-912-digest-ci into main 2026-07-26 08:11:29 +00:00
Owner

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_ctrl used GNU-sed \xNN hex-escape byte matching. The CI test step runs on node:24-alpine (ci-base), 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 WAKE_AGENT prefix), D6 (blank [digest] class). Reproduced the exact 9-assertion failure in the ci-base image as root; LC_ALL=C was already set, ruling out locale.

Fix (correct layer: a wake digest must render identically on any runner)

  • digest.sh _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).
  • test harness D4: replaced PCRE grep -qP (BusyBox grep has no -P; the && silently skipped the assertion 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 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; per #914 precedent).

Evidence (ci-base container, as root)

  • CI+openssl: digest 8 groups, beacon 12 groups, install 8 groups — all pass.
  • CI+no-openssl: all three hard-fail loud.
  • dev+no-openssl: all three skip cleanly.
  • Red-first: D4 catches a broken redaction; H1 catches a tamper that doesn't break the MAC; B12/I8 catch a corrupted signer.

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

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_ctrl` used GNU-sed `\xNN` hex-escape byte matching. The CI `test` step runs on `node:24-alpine` (ci-base), 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 WAKE_AGENT prefix), D6 (blank `[digest]` class). Reproduced the exact 9-assertion failure in the ci-base image as root; `LC_ALL=C` was already set, ruling out locale. ## Fix (correct layer: a wake digest must render identically on any runner) - **digest.sh `_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). - **test harness D4**: replaced PCRE `grep -qP` (BusyBox grep has no `-P`; the `&&` silently skipped the assertion 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 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; per #914 precedent). ## Evidence (ci-base container, as root) - CI+openssl: digest 8 groups, beacon 12 groups, install 8 groups — all pass. - CI+no-openssl: all three hard-fail loud. - dev+no-openssl: all three skip cleanly. - Red-first: D4 catches a broken redaction; H1 catches a tamper that doesn't break the MAC; B12/I8 catch a corrupted signer. Definitive acceptance is this PR's own Woodpecker pipeline going green with the suite unmasked + hard-required. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_0158NZqN2n2ymKFeJAZ4GUCb
jason.woltje added 1 commit 2026-07-26 07:50:04 +00:00
fix(wake): #912 exercise the digest/HMAC trust suite in real CI
All checks were successful
ci/woodpecker/pr/ci Pipeline was successful
ef43cc3be8
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_0158NZqN2n2ymKFeJAZ4GUCb
Author
Owner

Record 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, ≠ builder mosaic-coder) — APPROVE, all 7 criteria PASS, docker-reproduced against the REAL runner (not masked-local):

  1. Scope/provenance — head==ef43cc3b…; mergeable; PR-author id2 ≠ commit-author mosaic-coder; body Closes #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.
  2. ★ G6 — suite RUNS+PASSES in real CI — Woodpecker pipeline 2066 @ ef43cc3b status: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; ZERO SKIP: openssl/FAIL: — the HMAC legs actually ran, first time ever in real CI.
  3. ★ Byte-determinism (docker) — RED baseline reproduced: origin/main _scrub_ctrl in node:24-alpine AND ci-base → sed: bad regex … Invalid character range, 0 bytes (scrub voided). PR version byte-identical (sha256 9f1cb66f…) across GNU host + node:24-alpine (BusyBox) + ci-base. Root cause = BusyBox-vs-GNU sed toolchain divergence (4th env-masking class), NOT locale.
  4. Contract preserved — digest.sh diff scoped to _scrub_ctrl only (_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); D4 grep -qP→literal-byte grep -E disjoint ranges is a GENUINE check on BusyBox (not the silent no-op it was — BusyBox grep has no -P).
  5. Skip-guards hard-require — reproduced in openssl-less Alpine: 5B CI+no-openssl → all 3 FAIL LOUD (exit 1); 5C dev+no-openssl → all 3 SKIP (exit 0). CI can no longer silently skip the trust layer.
    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 openssl a true no-op (reviewer obs; not a blocker).

6-check — GO

  1. open/mergeable base main ✓ · 2. CI TERMINAL-GREEN @ full-40 ef43cc3be89739fbc5cfec583ecefd459d8860ed ✓ · 3. reviewer(aa75f8e3)≠builder durable RoR ✓ · 4. reviewed==CI==merge-head all ef43cc3b ✓ · 5. body Closes #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.
# Record 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, ≠ builder `mosaic-coder`) — **APPROVE, all 7 criteria PASS**, docker-reproduced against the REAL runner (not masked-local): 1. **Scope/provenance** — head==`ef43cc3b…`; mergeable; PR-author id2 ≠ commit-author `mosaic-coder`; body `Closes #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. 2. **★ G6 — suite RUNS+PASSES in real CI** — Woodpecker pipeline 2066 @ `ef43cc3b` `status: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; **ZERO `SKIP: openssl`/`FAIL:`** — the HMAC legs actually ran, first time ever in real CI. 3. **★ Byte-determinism (docker)** — RED baseline reproduced: origin/main `_scrub_ctrl` in node:24-alpine AND ci-base → `sed: bad regex … Invalid character range`, 0 bytes (scrub voided). PR version byte-identical (sha256 `9f1cb66f…`) across GNU host + node:24-alpine (BusyBox) + ci-base. Root cause = BusyBox-vs-GNU sed toolchain divergence (4th env-masking class), NOT locale. 4. **Contract preserved** — digest.sh diff scoped to `_scrub_ctrl` only (`_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); D4 `grep -qP`→literal-byte `grep -E` disjoint ranges is a GENUINE check on BusyBox (not the silent no-op it was — BusyBox grep has no -P). 5. **Skip-guards hard-require** — reproduced in openssl-less Alpine: 5B CI+no-openssl → all 3 FAIL LOUD (exit 1); 5C dev+no-openssl → all 3 SKIP (exit 0). CI can no longer silently skip the trust layer. 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 openssl` a true no-op (reviewer obs; not a blocker). ## 6-check — GO 1. open/mergeable base main ✓ · 2. **CI TERMINAL-GREEN @ full-40 `ef43cc3be89739fbc5cfec583ecefd459d8860ed`** ✓ · 3. reviewer(`aa75f8e3`)≠builder durable RoR ✓ · 4. reviewed==CI==merge-head all `ef43cc3b` ✓ · 5. body `Closes #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.**
Mos approved these changes 2026-07-26 08:11:27 +00:00
Mos left a comment
First-time contributor

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.

GO — Gate-16 id-11 stamp, pinned to exact FULL head ef43cc3be89739fbc5cfec583ecefd459d8860ed. 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.
Mos merged commit 712c770b7a into main 2026-07-26 08:11:29 +00:00
Mos deleted branch fix/wake-912-digest-ci 2026-07-26 08:11:30 +00:00
Sign in to join this conversation.
No Reviewers
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: mosaicstack/stack#921