R-502: the ISO first-boot harness is a gate, full runs only, "not checked" without docker

iso_bootstrap_gate.py runs scripts/iso/test/bootstrap-modes.sh in felhom-iso-assistant:trixie
(staged copy, read-only mount, --network none), registered fast=False in repo_gates.py so the
pre-push hook and CI (both --fast) never run it (decision 147). No docker / no image / docker
error -> exit 2 NOT CHECKED. Every green run is followed by a built-in decoy: the harness must
FAIL a bootstrap whose pairing banner never paints (R-496 shape), or the gate convicts the
instrument as blind. Docker-free decoys in test_iso_bootstrap_gate.py (fake docker on a
one-directory PATH), run from test_gate_decoys.py (COVERS).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
This commit is contained in:
2026-10-06 11:20:51 +02:00
parent 6b5804c63c
commit 9d39faabf8
4 changed files with 329 additions and 0 deletions
+157
View File
@@ -0,0 +1,157 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""iso_bootstrap_gate.py — the ISO first-boot harness, run as a gate (R-502, decision 147).
Usage: python3 scripts/iso_bootstrap_gate.py
Exit 0 harness green AND its planted-broken copy convicted · 1 a harness check failed, or the harness
could not see a planted broken banner · 2 NOT CHECKED (no docker, no image, docker itself failed).
WHAT IT RUNS. scripts/iso/test/bootstrap-modes.sh — felhom-bootstrap.sh's two modes, the network gate,
the console banners against their goldens and the postinst — inside `felhom-iso-assistant:trixie`.
Until this gate it ran only by hand, and it was RED for two days before anyone saw (R-586).
WHERE IT RUNS. Full runs only — `fast=False` in repo_gates.py, so never in --fast, never in the
pre-push hook, never in CI (both call --fast; CI has no docker). Operator ruling 2026-10-06, `09` §3
decision 147. Pinned by scripts/test_iso_bootstrap_gate.py (`test_registered_full_runs_only`).
NOT CHECKED IS NEVER A PASS. No docker binary, no image, or a docker error (exit 125-127, a timeout)
is exit 2 with the words "not checked". The image is built by hand:
docker build -f scripts/iso/Dockerfile.assistant -t felhom-iso-assistant:trixie scripts/iso
THE TREE STAYS CLEAN. The harness writes into /work (fakes, logs, /etc/felhom). It never sees the repo:
the four inputs are copied to a temp dir, mounted READ-ONLY at /src, and copied to /work INSIDE the
container. `--network none`: the harness fakes curl and needs no network.
THE BUILT-IN DECOY (the positive control, every run). After a green run the gate runs the harness a
second time against a copy of felhom-bootstrap.sh whose print_pairing_banner returns at once — the
exact shape that left the household's first screen untested until ISO 1.27.0 (R-496). The harness
MUST fail it, naming the banner. If it passes, the instrument is blind and the green run proved
nothing: exit 1. A green run is also required to show its own pass line AND at least MIN_OK `ok:`
lines — a harness that printed the pass line and checked nothing is not green.
"""
import os
import re
import shutil
import subprocess
import sys
import tempfile
import uuid
ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
ISO = os.path.join(ROOT, "scripts", "iso")
IMAGE = "felhom-iso-assistant:trixie"
TIMEOUT_S = 300
# The harness carried 76 `ok:` checks on 2026-10-06. Far below that, deliberately: this is the floor
# of "it ran", not a count to keep in step.
MIN_OK = 40
PASS_LINE = "ALL BOOTSTRAP-MODE TESTS PASSED"
# The planted decoy: the banner function returns before painting.
MUTANT_ANCHOR = "print_pairing_banner() {\n"
MUTANT_TEXT = MUTANT_ANCHOR + " return 0 # R-502 planted decoy: the banner never paints\n"
# A FAIL line the mutant must produce (ASCII fragment of the harness's own check name).
MUTANT_MUST_FAIL = re.compile(r"^\s*FAIL: R-496: banner painted", re.M)
INPUTS = [ # (repo path, path under /work) — what the harness reads, per its own header
(os.path.join(ISO, "felhom-bootstrap.sh"), "felhom-bootstrap.sh"),
(os.path.join(ISO, "pkg", "debian", "postinst"), "postinst"),
(os.path.join(ISO, "test", "golden"), "golden"),
(os.path.join(ISO, "test", "bootstrap-modes.sh"), os.path.join("test", "bootstrap-modes.sh")),
]
def not_checked(why):
print("iso-bootstrap: NOT CHECKED — %s" % why)
print("iso-bootstrap: INCONCLUSIVE (exit 2) — an unrun harness is never a pass")
return 2
def stage(dest, mutate=False):
"""Copy the harness inputs into dest. Returns None, or a reason the staging failed."""
for src, rel in INPUTS:
if not os.path.exists(src):
return "harness input missing: %s" % src
out = os.path.join(dest, rel)
os.makedirs(os.path.dirname(out), exist_ok=True)
if os.path.isdir(src):
shutil.copytree(src, out)
else:
shutil.copy2(src, out)
if mutate:
p = os.path.join(dest, "felhom-bootstrap.sh")
with open(p, encoding="utf-8") as f:
text = f.read()
if text.count(MUTANT_ANCHOR) != 1:
return ("the decoy anchor %r occurs %d time(s) in felhom-bootstrap.sh (want 1) — the "
"built-in decoy cannot be planted" % (MUTANT_ANCHOR.strip(), text.count(MUTANT_ANCHOR)))
with open(p, "w", encoding="utf-8") as f:
f.write(text.replace(MUTANT_ANCHOR, MUTANT_TEXT))
return None
def run_harness(docker, mutate):
"""Return (rc, output) of one harness run; rc None means docker itself failed (output says why)."""
tmp = tempfile.mkdtemp(prefix="felhom-iso-gate-")
name = "felhom-iso-gate-%s" % uuid.uuid4().hex[:12]
try:
err = stage(tmp, mutate)
if err:
return None, err
cmd = [docker, "run", "--rm", "--name", name, "--network", "none",
"-v", "%s:/src:ro" % tmp, IMAGE, "bash", "-c",
"mkdir -p /work && cp -a /src/. /work/ && exec bash /work/test/bootstrap-modes.sh"]
try:
p = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, timeout=TIMEOUT_S)
except subprocess.TimeoutExpired:
subprocess.run([docker, "rm", "-f", name], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
return None, "the harness did not finish in %d s (container %s removed)" % (TIMEOUT_S, name)
out = p.stdout.decode("utf-8", "replace")
if p.returncode in (125, 126, 127):
return None, "docker run exited %d:\n%s" % (p.returncode, out[-600:])
return p.returncode, out
finally:
shutil.rmtree(tmp, ignore_errors=True)
def main():
docker = shutil.which("docker")
if not docker:
return not_checked("no docker on PATH")
p = subprocess.run([docker, "image", "inspect", IMAGE],
stdout=subprocess.DEVNULL, stderr=subprocess.PIPE)
if p.returncode != 0:
return not_checked("image %s is absent or docker is unreachable (%s). Build it with: docker build "
"-f scripts/iso/Dockerfile.assistant -t %s scripts/iso"
% (IMAGE, p.stderr.decode("utf-8", "replace").strip()[:200], IMAGE))
rc, out = run_harness(docker, mutate=False)
if rc is None:
return not_checked(out)
print(out.rstrip())
oks = len(re.findall(r"^\s*ok: ", out, re.M))
fails = re.findall(r"^\s*FAIL: .*$", out, re.M)
if rc != 0 or fails:
print("\niso-bootstrap: FAILED — the harness exited %d with %d failing check(s):" % (rc, len(fails)))
for f in fails:
print(" " + f.strip())
return 1
if PASS_LINE not in out or oks < MIN_OK:
print("\niso-bootstrap: FAILED — exit 0 but %s (pass line %s, %d ok lines, want >= %d)"
% ("the harness proved nothing", "present" if PASS_LINE in out else "ABSENT", oks, MIN_OK))
return 1
mrc, mout = run_harness(docker, mutate=True)
if mrc is None:
return not_checked("the built-in decoy could not run: %s" % mout)
if mrc == 0 or not MUTANT_MUST_FAIL.search(mout):
print("\niso-bootstrap: FAILED — the harness PASSED a bootstrap whose pairing banner never paints "
"(exit %d). The instrument is blind; the green run above proves nothing." % mrc)
print(mout[-800:])
return 1
print("\niso-bootstrap: built-in decoy convicted (a banner that never paints -> harness exit %d)" % mrc)
print("iso-bootstrap gate OK — %d harness checks green in %s" % (oks, IMAGE))
return 0
if __name__ == "__main__":
sys.exit(main())
+7
View File
@@ -27,6 +27,8 @@ Gates, in order (all must pass; **non-zero exit on any failure**):
14b. stands where-felhom-stands.yaml: every claim cites a source that resolves, and every
'walked' cites a walk (R-819; it was red and ran in no runner)
15. script-tests every Python test suite under scripts/ (found by a walk), by exit code (R-885)
15b. iso-bootstrap the ISO first-boot harness in felhom-iso-assistant:trixie, with a built-in
decoy — FULL RUNS ONLY, "not checked" (exit 2) without docker (R-502, decision 147)
16. decoy-coverage every registered gate in all four repos has a decoy, or a named exemption (R-421)
**THE `GATES` TABLE BELOW IS THE LIST; THIS IS A POINTER TO IT.** It drifted once already —
@@ -162,6 +164,11 @@ GATES = [
# R-885 — the Python test suites under scripts/ (found by a walk) ran only by hand; a change that broke the
# 15 tests of the DooPlex hub-DB scripts, or the 73 of the instructions gate, reached main green. ~20 s.
("script-tests", os.path.join(SCRIPTS, "script_tests_gate.py"), [ROOT], True, False),
# R-502 — the ISO first-boot harness (scripts/iso/test/bootstrap-modes.sh) was run by no gate and was RED
# for two days unseen (R-586). It needs docker and an image, so it is fast=False: FULL RUNS ONLY, never
# the pre-push hook, never CI (operator ruling 2026-10-06, `09` §3 decision 147). Without docker or the
# image it says "not checked" and exits 2 — never a pass. Pinned by test_iso_bootstrap_gate.py.
("iso-bootstrap", os.path.join(SCRIPTS, "iso_bootstrap_gate.py"), [], False, False),
# R-421 — every registered gate across all four repos ships with a decoy test, or is
# named in the exemption list with its row. Registered LAST, after every runner was green:
# a failing gate refuses every push, which is what instructions_gate learned the hard way.
+18
View File
@@ -53,6 +53,11 @@ COVERS = {
"(2026-10-03) an old-shape row under the new header, a near-miss category, an "
"old rank tag as Sev, an undefined state word, and a pipe outside backticks"),
"decoy-coverage": "a gate registered in a runner with no decoy and no exemption (its red-proof)",
"iso-bootstrap": ("R-502: SIX decoys + the genuine article in scripts/test_iso_bootstrap_gate.py, run from here, docker-free (a "
"fake docker on a one-directory PATH): a BLIND harness that passes a bootstrap whose "
"pairing banner never paints (the R-496 shape), a failing harness, the pass line with no "
"checks behind it, and no docker / no image / a docker error, each 'not checked' (exit 2); "
"the gate also plants that broken banner itself in the real container on every full run"),
"instructions": "R-426: a version literal in a CLAUDE.md's effective text; the same in an HTML comment must pass",
"wire-contract": ("R-555: an emitted tag whose name the receiver carries ONLY in a // and a /* */ comment "
"must convict (it passed for months as `language` did); the genuine article — the same "
@@ -455,6 +460,19 @@ else:
_n = _gq.stdout.strip().splitlines()[-1] if _gq.stdout.strip() else "?"
print(" ok %-20s %s" % ("guide-quote", _n))
# ── iso-bootstrap (R-502) ────────────────────────────────────────────────────────────────────────
#
# Its decoys need a fake docker on a one-directory PATH, so they live in their own file and are RUN from
# here (guide-quote's shape). The suite never reaches the real docker, so this stays CI-safe.
ran += 1
_ib = subprocess.run([sys.executable, os.path.join("scripts", "test_iso_bootstrap_gate.py")],
cwd=ROOT, capture_output=True, text=True)
if _ib.returncode != 0:
fails.append("iso-bootstrap: its decoy suite FAILED — a decoy did not convict\n%s"
% (_ib.stdout + _ib.stderr)[-800:])
else:
print(" ok %-20s %s" % ("iso-bootstrap", (_ib.stderr.strip().splitlines() or ["?"])[-1]))
# ── site (R-423) ─────────────────────────────────────────────────────────────────────────────────
# A page that exists but is not in PAGES. The content is a perfectly valid page, so only the scope rule can convict.
decoy("site/unlisted-page", "site_gates.py",
+147
View File
@@ -0,0 +1,147 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""Decoys for scripts/iso_bootstrap_gate.py (R-502). DOCKER-FREE — runs on the CI runner (BusyBox +
python3 + git) and on DooPlex alike, and never reaches the real docker.
HOW. The gate finds docker with shutil.which, so every case runs the REAL gate as a subprocess with
PATH set to ONE temp directory: empty (no docker), or holding a FAKE `docker` written in python with
an absolute shebang (so it needs nothing else on PATH — /usr/bin, where the real docker lives on
DooPlex, is never on it). The fake answers `image inspect` and `run` per FAKE_DOCKER_MODE, and for
`run` reads the STAGED felhom-bootstrap.sh from the `-v <dir>:/src:ro` mount, so it can tell the
genuine run from the gate's built-in banner decoy.
What the fake cannot do is run the harness — that needs root and the image. The harness's power to
see a broken banner is proven by the gate itself, in the real container, on every full run (its
built-in decoy). This file proves the gate's verdicts: that a blind harness, a failing harness, a
harness that checked nothing, and an unrun harness can never read as green.
Run: python3 scripts/test_iso_bootstrap_gate.py
"""
import os
import shutil
import subprocess
import sys
import tempfile
import unittest
HERE = os.path.dirname(os.path.abspath(__file__))
ROOT = os.path.dirname(HERE)
GATE = os.path.join(HERE, "iso_bootstrap_gate.py")
sys.path.insert(0, HERE)
import iso_bootstrap_gate as g # noqa: E402
import repo_gates # noqa: E402
FAKE = r'''#!%(py)s
import os, re, sys
mode = os.environ.get("FAKE_DOCKER_MODE", "genuine")
a = sys.argv[1:]
log = os.environ.get("FAKE_DOCKER_LOG")
if log:
open(log, "a").write(" ".join(a) + "\n")
if a[:2] == ["image", "inspect"]:
sys.exit(1 if mode == "no-image" else 0)
if a[:1] == ["rm"]:
sys.exit(0)
if a[:1] != ["run"]:
sys.exit(3)
if mode == "daemon-error":
print("docker: Error response from daemon: something broke."); sys.exit(125)
src = [x for x in a if x.endswith(":/src:ro")][0][:-len(":/src:ro")]
mutant = "R-502 planted decoy" in open(os.path.join(src, "felhom-bootstrap.sh"), encoding="utf-8").read()
oks = "".join(" ok: check %%d\n" %% i for i in range(60))
if mode == "fails" or (mutant and mode != "blind"):
print(oks + " FAIL: R-496: banner painted to the console seam\nSOME TESTS FAILED"); sys.exit(1)
if mode == "hollow":
print("ALL BOOTSTRAP-MODE TESTS PASSED"); sys.exit(0)
print(oks + "ALL BOOTSTRAP-MODE TESTS PASSED"); sys.exit(0)
'''
def run_gate(mode=None):
"""Run the real gate. mode None = no docker on PATH at all."""
d = tempfile.mkdtemp(prefix="iso-gate-test-")
try:
log = os.path.join(d, "calls.log")
if mode is not None:
p = os.path.join(d, "docker")
with open(p, "w") as f:
f.write(FAKE % {"py": sys.executable})
os.chmod(p, 0o755)
env = {"PATH": d, "FAKE_DOCKER_MODE": mode or "", "FAKE_DOCKER_LOG": log,
"HOME": d, "PYTHONDONTWRITEBYTECODE": "1"}
r = subprocess.run([sys.executable, GATE], cwd=ROOT, env=env,
stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
calls = ""
if os.path.exists(log):
with open(log) as f:
calls = f.read()
return r.returncode, r.stdout.decode("utf-8", "replace"), calls
finally:
shutil.rmtree(d, ignore_errors=True)
class IsoBootstrapGateTest(unittest.TestCase):
def test_genuine_passes_and_runs_the_decoy_too(self):
rc, out, calls = run_gate("genuine")
self.assertEqual(rc, 0, out)
self.assertIn("built-in decoy convicted", out)
self.assertEqual(calls.count("run "), 2, "want the genuine run AND the decoy run:\n" + calls)
self.assertIn("--network none", calls)
def test_blind_harness_convicts(self):
# The harness passes a bootstrap whose banner never paints: the R-496 shape. Must be 1.
rc, out, _ = run_gate("blind")
self.assertEqual(rc, 1, out)
self.assertIn("instrument is blind", out)
def test_failing_harness_convicts(self):
rc, out, calls = run_gate("fails")
self.assertEqual(rc, 1, out)
self.assertIn("FAIL: R-496: banner painted", out)
self.assertEqual(calls.count("run "), 1)
def test_pass_line_without_checks_convicts(self):
rc, out, _ = run_gate("hollow")
self.assertEqual(rc, 1, out)
self.assertIn("proved nothing", out)
def test_no_docker_is_not_checked(self):
rc, out, _ = run_gate(None)
self.assertEqual(rc, 2, out)
self.assertIn("NOT CHECKED", out)
def test_no_image_is_not_checked(self):
rc, out, calls = run_gate("no-image")
self.assertEqual(rc, 2, out)
self.assertIn("NOT CHECKED", out)
self.assertNotIn("run ", calls)
def test_docker_error_is_not_checked(self):
rc, out, _ = run_gate("daemon-error")
self.assertEqual(rc, 2, out)
def test_decoy_plants_on_the_real_bootstrap(self):
# The built-in decoy's anchor must exist ONCE in the real script, and the plant must apply.
d = tempfile.mkdtemp()
try:
self.assertIsNone(g.stage(d, mutate=True))
with open(os.path.join(d, "felhom-bootstrap.sh"), encoding="utf-8") as f:
text = f.read()
self.assertIn("R-502 planted decoy", text)
for _src, rel in g.INPUTS:
self.assertTrue(os.path.exists(os.path.join(d, rel)), rel)
finally:
shutil.rmtree(d, ignore_errors=True)
def test_registered_full_runs_only(self):
# Decision 147: never in --fast (pre-push hook and CI both run --fast; CI has no docker).
rows = [r for r in repo_gates.GATES if r[0] == "iso-bootstrap"]
self.assertEqual(len(rows), 1, "iso-bootstrap must be registered once in repo_gates.GATES")
self.assertTrue(rows[0][1].endswith("iso_bootstrap_gate.py"))
self.assertIs(rows[0][3], False, "iso-bootstrap must be fast=False (full runs only)")
self.assertIs(rows[0][4], False, "iso-bootstrap must not be exemptible")
if __name__ == "__main__":
unittest.main(verbosity=2)