fix(wake): digest hard-locator gate covers top-level .claim entries
All checks were successful
ci/woodpecker/pr/ci Pipeline was successful
All checks were successful
ci/woodpecker/pr/ci Pipeline was successful
The W3 fail-loud hard-locator validator (digest.sh) treated an entry as
actionable via class=="actionable" OR .locators.claim, but the RENDER
tier also honors a top-level .claim (it renders via
`jq -r '.claim // .locators.claim'`). A hand-crafted entry like
{"class":"reaction","claim":"mergeable=true","locators":{}} fed via
--stdin/--from-file rendered as a CLAIM@seq with an EMPTY locator,
escaping the exit-4 hard-locator fail-loud gate.
store.sh never emits a top-level .claim (non-canonical shape), but a
non-canonical caller could bypass the gate. Align the validator to also
treat a top-level .claim as actionable, matching the render tier's
precedence, so any entry that WILL render as a claim must pass the hard
-locator gate or FAIL LOUD (exit 4, nothing emitted).
Closes #905
Part of #892
This commit is contained in:
@@ -229,7 +229,9 @@ cmd_render() {
|
||||
# --- FAIL-LOUD PASS FIRST (§2.1): validate every actionable claim carries a
|
||||
# hard locator BEFORE emitting a single byte. A malformed digest must never be
|
||||
# partially sent. Actionable-tier = class "actionable" OR any entry whose
|
||||
# locators carry a `claim` (a consequential fact). ------------------------
|
||||
# locators carry a `claim` OR a top-level `claim` (a consequential fact) —
|
||||
# matching the render tier's `.claim // .locators.claim` precedence, so no
|
||||
# entry can render as a CLAIM@seq without passing this gate. -------------
|
||||
local line class loc is_actionable
|
||||
while IFS= read -r line; do
|
||||
[ -n "$line" ] || continue
|
||||
@@ -241,6 +243,9 @@ cmd_render() {
|
||||
if jq -e 'has("claim") and ((.claim // "") != "")' >/dev/null 2>&1 <<<"$loc"; then
|
||||
is_actionable=1
|
||||
fi
|
||||
if jq -e 'has("claim") and ((.claim // "") != "")' >/dev/null 2>&1 <<<"$line"; then
|
||||
is_actionable=1
|
||||
fi
|
||||
if [ "$is_actionable" = "1" ] && ! _has_hard_locator "$loc"; then
|
||||
local seq
|
||||
seq="$(jq -r '.observed_seq // "?"' <<<"$line")"
|
||||
|
||||
@@ -117,6 +117,33 @@ echo "== D2: HARD-LOCATOR enforcement — actionable claim with no locator FAILS
|
||||
export WAKE_STATE_HOME
|
||||
"$STORE" enqueue --seq 1 --class actionable --locators "$(jq -cn --arg s "$SHA40" '{claim:"ci=green",sha:$s}')" >/dev/null
|
||||
"$DIGEST" render >/dev/null 2>&1 || fail_msg "D2: a well-located actionable claim must render"
|
||||
# --- #905: a NON-CANONICAL entry with a TOP-LEVEL `.claim` (store.sh never
|
||||
# emits this shape; only .locators.claim is canonical) and EMPTY .locators,
|
||||
# fed via --stdin / --from-file, must ALSO fail loud. The render tier honors
|
||||
# `.claim // .locators.claim` (renders CLAIM@seq either way), so the
|
||||
# fail-loud gate must cover top-level .claim too, else a hand-crafted /
|
||||
# non-canonical caller could bypass the hard-locator gate entirely.
|
||||
WAKE_STATE_HOME="$(fresh_state d2d)"
|
||||
export WAKE_STATE_HOME
|
||||
toplevel_claim_entry='{"class":"reaction","claim":"mergeable=true","locators":{}}'
|
||||
out=""
|
||||
if out="$(printf '%s\n' "$toplevel_claim_entry" | "$DIGEST" render --stdin 2>/dev/null)"; then
|
||||
fail_msg "D2(#905): top-level .claim + empty locators must FAIL via --stdin, but render succeeded"
|
||||
fi
|
||||
[ -z "${out:-}" ] || fail_msg "D2(#905): --stdin top-level-.claim bypass emitted body instead of failing loud [$out]"
|
||||
rc=0
|
||||
printf '%s\n' "$toplevel_claim_entry" | "$DIGEST" render --stdin >/dev/null 2>&1 || rc=$?
|
||||
[ "$rc" -eq 4 ] || fail_msg "D2(#905): expected fail-loud exit 4 for top-level .claim via --stdin, got $rc"
|
||||
ff="$TMP_ROOT/d2d-entry.jsonl"
|
||||
printf '%s\n' "$toplevel_claim_entry" >"$ff"
|
||||
out2=""
|
||||
if out2="$("$DIGEST" render --from-file "$ff" 2>/dev/null)"; then
|
||||
fail_msg "D2(#905): top-level .claim + empty locators must FAIL via --from-file, but render succeeded"
|
||||
fi
|
||||
[ -z "${out2:-}" ] || fail_msg "D2(#905): --from-file top-level-.claim bypass emitted body instead of failing loud [$out2]"
|
||||
rc=0
|
||||
"$DIGEST" render --from-file "$ff" >/dev/null 2>&1 || rc=$?
|
||||
[ "$rc" -eq 4 ] || fail_msg "D2(#905): expected fail-loud exit 4 for top-level .claim via --from-file, got $rc"
|
||||
) && ok
|
||||
|
||||
echo "== D3: TWO-TIER — orientation no-op with ZERO tool calls; actionable = claim-to-verify =="
|
||||
|
||||
Reference in New Issue
Block a user