fix(wake): #917 gate the final observed_seq cursor write + observed.set/cursor consistency (defense-in-depth) (#933)
All checks were successful
ci/woodpecker/push/publish Pipeline was successful
ci/woodpecker/push/ci Pipeline was successful

Co-authored-by: jason.woltje <jason@diversecanvas.com>
Co-committed-by: jason.woltje <jason@diversecanvas.com>
This commit was merged in pull request #933.
This commit is contained in:
2026-07-26 15:14:38 +00:00
committed by Mos
parent 17087efe15
commit 9becaf877f
3 changed files with 154 additions and 5 deletions

View File

@@ -472,6 +472,109 @@ else
ok
fi
echo "== T11: final observed_seq cursor write FAILURE — fail loud + observed.set/cursor stay CONSISTENT (#917 def-in-depth) =="
(
WAKE_STATE_HOME="$(fresh_state t11)"
export WAKE_STATE_HOME
unset WAKE_AGENT
STATE_DIR="$WAKE_STATE_HOME/default"
# Baseline: one clean allocation. observed_seq cursor=1, observed.set={1}, the
# cursor FILE now exists (so it can be bind-mounted over below).
s1="$("$STORE" enqueue --class actionable --locators '{"n":1}')"
[ "$s1" = "1" ] || fail_msg "T11: baseline allocation should be 1, got '$s1'"
obs_before="$("$STORE" cursors | sed -n 's/^observed_seq=//p')"
[ "$obs_before" = "1" ] || fail_msg "T11: observed_seq should be 1 before the forced failure, got '$obs_before'"
# Force ONLY the FINAL observed_seq cursor _atomic_write to fail, AFTER the
# pending + observed.set writes have already succeeded. Same privilege-invariant
# trigger as T9 (bind-mount a throwaway file OVER _atomic_write's rename TARGET
# so `mv -f tmp target` hits EBUSY — the kernel refuses to rename onto an ACTIVE
# MOUNT POINT; a structural VFS rule root does NOT bypass), but the mount is over
# $STATE_DIR/observed_seq (the CURSOR) instead of pending.jsonl. pending.jsonl and
# observed.set stay ordinary writable files, so their writes SUCCEED and only the
# cursor commit fails — exactly the #917 window (cursor-write failure after a good
# observed.set write). The mount lives inside a private mount+user namespace
# (unshare --mount --user --map-root-user) so it is identical unprivileged (dev)
# or as root (CI) and vanishes the instant the namespace exits — no cleanup.
#
# AVAILABILITY GUARD (matches T9): this injection needs unshare + a working
# bind-mount, which a NON-PRIVILEGED container (the real CI runner) DENIES —
# `unshare --mount` fails to set up ("unshare failed: Operation not permitted" /
# "can't mount none on /") and the inner enqueue NEVER runs. When the injection
# cannot be constructed we SKIP the failure-path assertions (there is no forced
# failure to observe) and keep the harness GREEN, exactly like T9 tolerates the
# same unavailability. The inner script drops a MARKER only AFTER the mount is in
# place and immediately before the enqueue, so its presence is an exact witness
# that the cursor-write fault was really injected; its absence => unavailable.
errfile="$TMP_ROOT/t11.err"
marker="$TMP_ROOT/t11.injected"
: >"$errfile"
rm -f "$marker"
rc=0
injected=0
if ! command -v unshare >/dev/null 2>&1; then
echo " SKIP: T11 — 'unshare' unavailable; cannot construct the cursor-write fault injection (like T9)"
else
ro_src="$TMP_ROOT/t11-ro-src"
mkdir -p "$ro_src"
# Seed the throwaway file with the CURRENT cursor value so the allocator's
# READ of observed_seq still returns 1 (an empty file would read as 0 and
# mis-allocate seq=1, never exercising the cursor-WRITE failure). Only the
# final `mv -f tmp observed_seq` commit is blocked by the mountpoint.
printf '%s' "$obs_before" >"$ro_src/observed_seq"
# shellcheck disable=SC2016 # deliberate: $1..$5 expand in the NESTED bash
# (inside the unshare'd namespace), not this outer single-quoted one.
unshare --mount --user --map-root-user bash -c '
set -u
ro_src="$1"
state_dir="$2"
store="$3"
errfile="$4"
marker="$5"
if ! mount --bind "$ro_src/observed_seq" "$state_dir/observed_seq" 2>/dev/null; then
exit 98
fi
mount -o remount,ro,bind "$state_dir/observed_seq" 2>/dev/null || true
: >"$marker" # WITNESS: mount is in place; the enqueue below WILL hit the mounted cursor.
"$store" enqueue --class actionable --locators "{\"n\":2}" >/dev/null 2>"$errfile"
' _ "$ro_src" "$STATE_DIR" "$STORE" "$errfile" "$marker" 2>/dev/null
rc=$?
if [ -f "$marker" ]; then
injected=1
else
# unshare --mount denied (non-priv CI) or bind-mount unavailable (exit 98):
# the inner enqueue never ran, so there is no forced cursor-write failure to
# assert. SKIP gracefully instead of asserting a failure that was not injected.
echo " SKIP: T11 — unshare/bind-mount fault injection unavailable in this sandbox (e.g. non-privileged CI); cursor-write failure path not exercised here (like T9)"
fi
fi
if [ "$injected" -eq 1 ]; then
# (1) FAIL LOUD: the cursor-write failure must EXIT NON-ZERO, never a silent
# success (RED against pre-#917 code, whose ungated final cursor write swallows
# the _atomic_write failure and returns 0).
[ "$rc" -ne 0 ] || fail_msg "T11: an enqueue whose FINAL cursor write fails must EXIT NON-ZERO (fail loud), got rc=$rc"
# The loud diagnostic names the cursor write (not a generic error).
grep -qi 'cursor' "$errfile" || fail_msg "T11: the failure diagnostic must name the observed_seq cursor write [$(cat "$errfile")]"
# (2) The cursor did NOT advance — the allocation is NOT committed.
obs_after="$("$STORE" cursors | sed -n 's/^observed_seq=//p')"
[ "$obs_after" = "1" ] || fail_msg "T11: a failed cursor write must NOT leave the cursor advanced, got '$obs_after'"
# (3) THE #917 CONSISTENCY ASSERTION: observed.set and the cursor must NEVER be
# left cross-file inconsistent. observed.set must carry NO seq greater than the
# cursor — either the observed.set advance was rolled back (neither advances) or
# both advanced together; there is no state where observed.set is ahead of the
# cursor. RED against pre-#917 code: observed.set={1,2} while the cursor lags at
# 1, so seq 2 is stranded above the cursor.
stranded="$(awk -v c="$obs_after" 'NF && $1+0 > c' "$STATE_DIR/observed.set" 2>/dev/null || true)"
[ -z "$stranded" ] || fail_msg "T11: observed.set left CROSS-FILE INCONSISTENT with the cursor — seq(s) above cursor $obs_after: [$stranded]"
# (4) The consumed prefix is intact — no interior gap corrupts future consume.
"$STORE" consume --upto 1 >/dev/null 2>&1 || fail_msg "T11: CONSUMED 1 must remain valid after the failed cursor write (no gap)"
fi
) && ok
echo
if [ -s "$FAILFILE" ]; then
echo "wake store/ack harness: FAILED ($(grep -c . "$FAILFILE") assertion(s))" >&2