fix(wake): #934 mount-free, privilege-invariant seq-integrity fault injection (T9/T11 run in non-priv CI)
All checks were successful
ci/woodpecker/pr/ci Pipeline was successful
All checks were successful
ci/woodpecker/pr/ci Pipeline was successful
The seq-integrity fault-injection tests T9 (#908 arrow-1 no-burn) and T11 (#917 final-cursor gate + observed.set rollback) forced a write to fail via `unshare --mount --user --map-root-user` + a bind-mount EBUSY-on-mountpoint. The real Woodpecker runner is NON-privileged and DENIES mount-in-userns, so both injections SKIPPED in CI — the allocator's most safety-critical invariants were not exercised by the pipeline that gates merges (skipped-trust-layer, the class #912 cured for the digest suite). Replace the mount-based mechanism with a MOUNT-FREE, PROD-INERT fault seam in _wake-common.sh _atomic_write, honored ONLY when the test-only env var WAKE_TEST_FAULT explicitly names a write point (pending->pending.jsonl, cursor->observed_seq). It forces the ALREADY-EXISTING fail-loud/rollback PATH (#908/#917) to be taken for that one target and RUNS UNPRIVILEGED. No production input can set a process env var, so with WAKE_TEST_FAULT unset the seam is a no-op: on-disk format + allocator semantics are byte-for-byte unchanged in prod. T9/T11 are converted to the seam; the unshare+bind-mount path and its skip-when-unavailable guard/witness-marker are REMOVED. Both tests now RUN and ASSERT their failure paths in every environment including non-priv CI. Verified in a NON-privileged node:24-alpine container (unshare --mount DENIED): T9 and T11 execute their injection (no SKIP), the failure paths fire, and the fail-loud/rollback assertions pass; full `pnpm run test:framework-shell` rc=0. Closes #934 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0158NZqN2n2ymKFeJAZ4GUCb
This commit is contained in:
@@ -55,6 +55,25 @@ _wake_tmp_prefix='.wake.tmp.'
|
||||
# the old target fully intact and a stale .wake.tmp.* that readers ignore.
|
||||
_atomic_write() {
|
||||
local target="$1" dir tmp
|
||||
# --- TEST-ONLY FAULT SEAM (issue #934) — PROD-INERT. ------------------------
|
||||
# Forces the ALREADY-EXISTING atomic-write failure PATH (the fail-loud +
|
||||
# rollback handling #908/#917 built) to be taken for ONE named write target, so
|
||||
# the seq-integrity failure assertions (T9 arrow-1 no-burn, T11 cursor-write
|
||||
# gate) RUN UNPRIVILEGED in the real non-privileged CI runner instead of being
|
||||
# skipped behind an unshare+bind-mount injection. It is honored ONLY when the
|
||||
# test-only env var WAKE_TEST_FAULT is explicitly set to name a write point; it
|
||||
# writes nothing, adds no new behavior, and changes no on-disk format. No
|
||||
# production input (CLI args, locators JSON, on-disk state, watch-list) can set
|
||||
# a process env var, so with WAKE_TEST_FAULT unset this is a no-op and the write
|
||||
# proceeds exactly as before. Map: pending->pending.jsonl, cursor->observed_seq.
|
||||
if [ -n "${WAKE_TEST_FAULT:-}" ]; then
|
||||
case "${WAKE_TEST_FAULT}:$(basename -- "$target")" in
|
||||
pending:pending.jsonl | cursor:observed_seq)
|
||||
cat >/dev/null 2>&1 || true # drain the producer, then report the commit as failed
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
dir="$(dirname "$target")"
|
||||
[ -d "$dir" ] || mkdir -p "$dir"
|
||||
tmp="$(mktemp "$dir/${_wake_tmp_prefix}XXXXXX")" || return 1
|
||||
|
||||
Reference in New Issue
Block a user