Files
home-network-k3s-impl/conformance/tests/l0-static/whole-repo-invariants-wired/check.sh
T
jakman85andClaude Opus 5 a76ae3bdfa fix(ci): the content scan could not match R-C2-01/02 — a digit in the workstream segment
Checked as part of closing the C2 coverage gaps, and it was live on main. The content
scan's pattern was `R-[A-Z]+-[0-9]+`, which CANNOT match an ID whose workstream segment
carries a digit: `[A-Z]+` consumes the `C` of `R-C2-01` and then demands a `-` where the
`2` is. `R-C2-01` and `R-C2-02` are the only two such IDs in
conformance/requirements/registry.yaml, and the scan was blind to BOTH.

REPRODUCED before the fix, on a throwaway repo whose only change is a manifest declaring
both IDs on real (non-comment) lines, in a path the map keys to nothing:

    $ REPO_ROOT=$T BASE_REF=main ci/touched-requirements.sh
    R-NET-06                     # the all-letter control ID was the ONLY output

It failed by UNDER-attributing, which is the fail-OPEN direction: a change that retyped a
`conformance.home.k3s/R-C2-01` tag, or a manifest self-declaring R-C2-02, contributed
those IDs to NOBODY, so the C2 tests were filtered out of the merge gate. Same defect
class as the map's `*) : ;;` arm — a miss that reads as "nothing touched".

Every other consumer in the repo already allowed the digit, which is why this was the lone
dissenter: test_requirements_for_path() twenty lines above in this same script,
conformance/lib/coverage.py, conformance/lib/status.py and conformance/lib/
run_l1_offline.py all use `R-[A-Z0-9]+-[0-9]+`. Aligned to that form, with the reason
recorded at the line.

SCOPE OF THE HOLE. path_requirements() has no arm for platform/homepage/* or
platform/headlamp/* either, so before this the ONLY route to R-C2-01/02 was detection rule
3 (editing the C2 conformance test itself). No path-map arm is added here: c2-root-surface
declares `scope: whole-repo`, so ci/l0.sh Stage 3b's --include-scope union selects it on
EVERY gate invocation regardless of the touched set — which is the right mechanism for an
invariant whose input surface is the whole tree, and strictly stronger than a two-component
path arm would be.

REGRESSION-TESTED, in ci/tests/touched-requirements.test.sh (the suite `make -C ci test`
runs): a fixture declaring R-C2-01 / R-C2-02 / R-OBS-04 from `notes/` — a path outside
path_requirements(), so the IDs can only come from the content scan — asserts both digit
IDs ARE attributed, that the all-letter form still is (control), and that a purely numeric
workstream is not invented (the pattern must not widen the gate on noise).

PROVEN TO DETECT BREAKAGE: with the pattern reverted to `R-[A-Z]+-[0-9]+` the suite reports
`FAIL (2 failed, 14 passed)` naming both C2 IDs as missing; restored, all three ci/ suites
pass (16 assertions in this one).

ALSO: conformance/tests/l0-static/whole-repo-invariants-wired/check.sh cites this pattern
in the comment explaining why its BOGUS_REQ fixture is lowercase. Citation updated so the
reasoning still reads true; the fixture is unaffected (grep -E is case-sensitive, and the
check still passes 26/26).

NOTE: another branch may be editing this same script concurrently. This is a one-line
change to one statement plus its comment — expect a trivial conflict and keep the
`[A-Z0-9]` form.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-13 16:28:21 -05:00

209 lines
11 KiB
Bash
Executable File

#!/usr/bin/env bash
# =============================================================================
# L0 STATIC CHECK — the whole-repo scope mechanism is wired, works, and stays honest.
# See chainsaw-test.yaml's header for WHY this test exists and what it replaced.
#
# Exit 0 = all assertions pass. Exit 1 = a failure. This check has NO exit-3 path: the
# mechanism it audits is source in this repo, so "nothing to audit" is not a state it can
# legitimately be in.
#
# IT MUST NEVER EXECUTE THE SUITE IT IS PART OF. `run.sh --print-selection` resolves the
# selection and exits without running a single check, which is what makes assertion (2)
# possible without infinite recursion.
# =============================================================================
set -euo pipefail
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ROOT="$(cd "${DIR}/../../../.." && pwd)" # repo root
CONF="${ROOT}/conformance"
SCOPE="${WHOLE_REPO_SCOPE:-whole-repo}"
PASS=0
FAILED=0
note() { printf ' ok %s\n' "$1"; PASS=$((PASS+1)); }
bad() { printf ' FAIL %s\n' "$1" >&2; FAILED=$((FAILED+1)); }
chk() { if [ "$1" = 0 ]; then note "$2"; else bad "$3"; fi }
L0_SH="${ROOT}/ci/l0.sh"
GATE_SH="${ROOT}/ci/gate.sh"
RUN_SH="${CONF}/run.sh"
COMMON_SH="${CONF}/lib/common.sh"
OFFLINE_PY="${CONF}/lib/run_l1_offline.py"
# ---- (1) the mechanism exists, end to end -----------------------------------------------
for f in "$L0_SH" "$GATE_SH" "$RUN_SH" "$COMMON_SH" "$OFFLINE_PY"; do
[ -f "$f" ] || { bad "missing ${f#"$ROOT"/} — the mechanism cannot be audited"; }
done
if [ "$FAILED" -ne 0 ]; then
echo "CHECK FAIL (whole-repo-invariants-wired): the gate's own sources are missing" >&2
exit 1
fi
grep -q 'CONF_SCOPE_ANNOTATION' "$COMMON_SH" \
&& grep -q 'conf_dirs_for_scope' "$COMMON_SH"
chk $? "conformance/lib/common.sh resolves the scope annotation (conf_dirs_for_scope)" \
"conformance/lib/common.sh no longer resolves the scope annotation — no test can be
selected BY declaring a scope, so every whole-repo invariant is back to being
selectable away by the requirement filter"
grep -q -- '--include-scope' "$RUN_SH" && grep -q 'conf_dirs_for_scopes' "$RUN_SH"
chk $? "conformance/run.sh --include-scope unions scope-declared tests into select_dirs" \
"conformance/run.sh does not union scope-declared tests (--include-scope /
conf_dirs_for_scopes missing) — the annotation would be inert decoration"
grep -Eq -- '--include-scope[[:space:]]+"?\$\{?WHOLE_REPO_SCOPE' "$L0_SH" \
|| grep -Eq -- "--include-scope[[:space:]]+['\"]?${SCOPE}" "$L0_SH"
chk $? "ci/l0.sh passes --include-scope ${SCOPE} to the conformance runner" \
"ci/l0.sh does not pass --include-scope ${SCOPE}: the L0 merge-gate stage is back to a
purely requirement-scoped run, and every whole-repo invariant is filtered out of
exactly the change that breaks it"
# ---- (6) the declared set is non-empty and executable -----------------------------------
declared_dirs=()
while IFS= read -r d; do [ -n "$d" ] && declared_dirs+=("$d"); done < <(
CONF_ROOT="$CONF" bash -c 'source "${CONF_ROOT}/lib/common.sh"; conf_dirs_for_scope "$1"' _ "$SCOPE"
)
MIN_DECLARED="${MIN_DECLARED:-5}"
[ "${#declared_dirs[@]}" -ge "$MIN_DECLARED" ]
chk $? "${#declared_dirs[@]} test(s) declare scope='${SCOPE}' (floor ${MIN_DECLARED})" \
"only ${#declared_dirs[@]} test(s) declare scope='${SCOPE}' (floor ${MIN_DECLARED}) — either the
annotation was stripped from the whole-repo checks, or the resolver stopped matching
it. Every assertion below would then pass while checking nothing"
for d in ${declared_dirs[@]+"${declared_dirs[@]}"}; do
rel="${d#"$ROOT"/}"
[ -f "$d/check.sh" ] || [ -f "$d/render-check.sh" ]
chk $? "${rel}: declares the scope AND carries an executable offline check" \
"${rel} declares scope='${SCOPE}' but carries neither check.sh nor render-check.sh — an
unconditional run of a test with nothing to run is a guaranteed SKIP, i.e. a
permanent not-green, not a guard"
done
# ---- (2) IT WORKS: prove the selection cannot filter a declaring test out ---------------
# A requirement ID no test carries. With it alone the L0 selection MUST be empty; adding
# --include-scope MUST bring back every declaring test. Both halves are asserted, so this is
# falsifiable: if --include-scope became a no-op, the first half would still pass and the
# second would fail.
# Deliberately LOWERCASE: conf_normalize_reqs() upper-cases it, so the selection behaves
# identically — but the literal here does not match ci/touched-requirements.sh's content-scan
# pattern `R-[A-Z0-9]+-[0-9]+`, so editing this file does not attribute a nonexistent requirement
# to the change. (Same reason the synthetic fixture below carries no requirement label at all.)
BOGUS_REQ="r-nosuchreq-99"
sel_without="$(bash "$RUN_SH" --layer l0 --requirements "$BOGUS_REQ" --print-selection 2>/dev/null || true)"
sel_with="$(bash "$RUN_SH" --layer l0 --requirements "$BOGUS_REQ" --include-scope "$SCOPE" --print-selection 2>/dev/null || true)"
[ -z "$sel_without" ]
chk $? "a requirement filter matching no test resolves to an EMPTY L0 selection (control)" \
"the control case is broken: --requirements ${BOGUS_REQ} still selected tests
($(printf '%s' "$sel_without" | tr '\n' ' ')), so the assertion below proves nothing
about --include-scope"
missing=""
for d in ${declared_dirs[@]+"${declared_dirs[@]}"}; do
printf '%s\n' "$sel_with" | grep -qxF "$d" || missing="${missing} ${d#"$ROOT"/}"
done
[ -z "$missing" ]
chk $? "every scope-declared L0 test is selected DESPITE a requirement filter matching none" \
"the scope union does not actually select:${missing}. This is the blind spot itself: a
change that attributes no requirement would not run these checks"
# The union must not smuggle in another layer's tests when --layer bounds the run.
strays="$(printf '%s\n' "$sel_with" | grep -v '/tests/l0-static/' || true)"
[ -z "$strays" ]
chk $? "the scope union stays inside --layer l0 (no cross-layer leakage)" \
"--layer l0 --include-scope ${SCOPE} selected non-L0 test(s): $(printf '%s' "$strays" | tr '\n' ' ')"
# ---- (3) a SKIP of a scope-declared check is UNWIRED, NOT GREEN -------------------------
# Proven by running the real offline runner over two synthetic test dirs: one DECLARING the
# scope, one not. Both checks exit 3. The declaring one must make the runner exit 3; the
# other must leave it at 0. This is the half a refactor loses most easily, because nothing
# else in the suite notices when "skip" quietly starts meaning "pass".
WORK="$(mktemp -d)"
trap 'rm -rf "${WORK}"' EXIT
mk_synth() { # mk_synth <dir> <declare-scope: yes|no>
local d="$1" declare="$2"
mkdir -p "$d"
{
printf 'apiVersion: chainsaw.kyverno.io/v1alpha1\nkind: Test\nmetadata:\n'
printf ' name: %s\n annotations:\n' "$(basename "$d")"
[ "$declare" = yes ] && printf ' conformance.home.k3s/scope: "%s"\n' "$SCOPE"
printf ' conformance.home.k3s/layer: "L0"\nspec: {}\n'
} > "$d/chainsaw-test.yaml"
printf '#!/usr/bin/env bash\necho "synthetic: nothing to audit" >&2\nexit 3\n' > "$d/check.sh"
}
mk_synth "${WORK}/l0-static/synth-declared" yes
mk_synth "${WORK}/l0-static/synth-undeclared" no
run_offline() { # run_offline <dir...> -> echoes rc
local rc=0
python3 "$OFFLINE_PY" --junit "${WORK}/j.xml" \
--scope-annotation "conformance.home.k3s/scope" \
--unwired-scope "$SCOPE" "$@" >/dev/null 2>&1 || rc=$?
echo "$rc"
}
rc_declared="$(run_offline "${WORK}/l0-static/synth-declared")"
rc_undeclared="$(run_offline "${WORK}/l0-static/synth-undeclared")"
[ "$rc_declared" = 3 ]
chk $? "a SKIPPED check that DECLARES scope='${SCOPE}' makes the runner exit 3 (UNWIRED, not green)" \
"a SKIPPED scope-declared check made the offline runner exit ${rc_declared}, not 3. A
whole-repo invariant reporting 'nothing to audit' means the tree it audits has
VANISHED; the deleted ci/l0.sh stages called that 'not a pass' and set the gate's
rc=3. Exit 0 here turns that back into a silent green"
[ "$rc_undeclared" = 0 ]
chk $? "a SKIPPED check with NO scope declaration still exits 0 (unchanged for scaffolds)" \
"a SKIPPED undeclared check made the runner exit ${rc_undeclared}, not 0 — the strict
rule leaked onto ordinary scaffolds, which would make every unfinished test block"
# ...and ci/l0.sh must map that rc 3 to the GATE's rc 3, never to a pass.
l0_static_stage="$(sed -n '/Stage 3b: L0 STATIC/,/^case "\$rc" in/p' "$L0_SH")"
printf '%s\n' "$l0_static_stage" | grep -Eq '^[[:space:]]*3\)' \
&& printf '%s\n' "$l0_static_stage" | grep -Eq 'rc=3'
chk $? "ci/l0.sh maps the runner's rc 3 to the gate's own rc 3 (SKIPPED, not a pass)" \
"ci/l0.sh's L0-static stage has no rc-3 arm setting the gate's rc=3, so a scope-declared
check that SKIPPED would be reported as a PASS — the exact false green the deleted
stages were written to prevent"
# ---- (4) the bespoke per-check stage pattern has not crept back -------------------------
# Not forbidden outright: a ci/*.sh MAY hardcode a test's check.sh. But if it does, that test
# must ALSO declare the scope, so a hand-written stage can never be the only thing running a
# whole-repo check (which is how the mechanism silently stops covering a new invariant).
# Two exclusions, both the repo's existing "reference, not declaration" rule (see
# ci/touched-requirements.sh changed_diff() rules 2-3):
# * whole-line `#` comments — a path NAMED in prose is documentation, not an invocation;
# * ci/tests/ — those files embed example test paths as unit-test FIXTURE DATA.
hardcoded="$(find "${ROOT}/ci" -name '*.sh' -not -path '*/ci/tests/*' -print0 2>/dev/null \
| xargs -0 -r grep -hE -v '^[[:space:]]*#' \
| grep -hoE 'conformance/tests/[a-z0-9-]+/[a-zA-Z0-9._-]+/(check|render-check)\.sh' \
| sort -u || true)"
for rel in $hardcoded; do
tdir="${ROOT}/$(dirname "$rel")"
y="${tdir}/chainsaw-test.yaml"
if [ -f "$y" ] && grep -Eq "^[[:space:]]*conformance\.home\.k3s/scope:[[:space:]]*[\"']?${SCOPE}" "$y"; then
note "ci/ hardcodes ${rel}, and that test also DECLARES the scope (belt and braces, fine)"
else
bad "ci/ hardcodes ${rel} as a bespoke stage, but that test does NOT declare
conformance.home.k3s/scope: \"${SCOPE}\". That is the pattern this mechanism replaced: the
stage is then the ONLY thing running the check, it must be hand-maintained, and the
runner's own selection still does not know the invariant is whole-repo. Add the
annotation to ${rel%/*}/chainsaw-test.yaml and delete the stage."
fi
done
[ -z "$hardcoded" ] && note "no ci/*.sh hardcodes a conformance check path (fully declarative)"
# ---- (5) the gate still BLOCKS on an l0 failure -----------------------------------------
# Carried over from the three deleted stages' own checks — asserted once, here.
grep -Eq '^for s in .*\bl0\b.*; do' "$GATE_SH" && grep -Eq 'fail\).*BLOCK=1' "$GATE_SH"
chk $? "ci/gate.sh sets the merge block when the l0 stage fails" \
"ci/gate.sh does not set the merge block on an l0 stage failure — every assertion above
would hold while a red L0 stage merged anyway"
echo
echo "whole-repo scope: ${#declared_dirs[@]} declaring test(s): $(for d in ${declared_dirs[@]+"${declared_dirs[@]}"}; do printf '%s ' "$(basename "$d")"; done)"
if [ "$FAILED" -eq 0 ]; then
echo "check OK: whole-repo-invariants-wired — ${PASS} assertions (R-TEST-03)"
exit 0
fi
echo "CHECK FAIL (whole-repo-invariants-wired): ${FAILED} failed, ${PASS} passed" >&2
exit 1