From 7a27d6a3e5ac1e37da95f60eb4ea538f7895669d Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 10 Nov 2026 04:41:07 +0000 Subject: [PATCH] test(stick): the rest of MINT-ZUSE's sessions -- refused, small, a used stick, the system stick pulled, her stick first (#92, 4.8) [skip ci] Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01GE3SDvQn5EoxdGufk84zz2 --- ...-10-29-stick-5-proxy-zuse-and-real-zuse.md | 2 +- kernel/Makefile | 2 +- scripts/qemu_session.py | 122 +++++++++++++++++- 3 files changed, 123 insertions(+), 3 deletions(-) diff --git a/docs/v4.0.0/plans/2026-10-29-stick-5-proxy-zuse-and-real-zuse.md b/docs/v4.0.0/plans/2026-10-29-stick-5-proxy-zuse-and-real-zuse.md index fcb5dcc0..db49a2ea 100644 --- a/docs/v4.0.0/plans/2026-10-29-stick-5-proxy-zuse-and-real-zuse.md +++ b/docs/v4.0.0/plans/2026-10-29-stick-5-proxy-zuse-and-real-zuse.md @@ -358,7 +358,7 @@ Tasks 1-3 accepted and merged (#159, master 594d2f93); #155 merged with them. - [x] 4.5 `sk_v4_mint.c`: the flow -- plug-in line, size line, `YES`, GPT, zeroed, minted, read back, marker. Builds on three ISAs; not yet called. The gate gained a **spare**: the last stick turned away as not this system's (or handed back by a refused mint) is offered first by the next mint (for `mint_zuse_refuse`: "a second `MINT-ZUSE` is offered again"); and accessors `sk_v4_identity_stick_in/offered_present/release_offered/marker/set_marker`. - [x] 4.6 `MINT-ZUSE` in `sk_v4_words[]` (request 2): word_count 317 -> 318. `mint_zuse` PASSES on amd64 (logs/20261108-181556): the size line, YES, "real Zuse minted", the prompt, 7 ok, the new stick one clean identity partition. (Her session is still the proxy's: recognising the real Zuse stick is 4.7.) - [x] 4.7 the real Zuse stick recognised and attached after the system stick; her session (`sk_v4_real_zuse_arrived()`: identity partition, no Artemis, checked against the marker's real key; attached at the chain's tail; a session already running moves to her; arriving before the system stick, remembered in `g_pending_real` and checked once the marker is read; the installed key now set at every login). Builds on three ISAs; `mint_zuse` checks "identity confirmed" after the minted line: PASS on amd64 (logs/20261110-043807). Not yet handled: pulling the system stick while hers is in (her stick is the chain's tail, so it must go first -- Task 5's `system_pull_real`). -- [ ] 4.8 `mint_zuse` passes on amd64; then the other tests: `mint_zuse_refuse`, `mint_pull_system`, `zuse_stick_first`, `mint_small`, the pair's stick offered +- [~] 4.8 `mint_zuse` passes on amd64 (4.7); the other sessions written (`mint_zuse_refuse`, `mint_small`, `mint_zuse_used`, `mint_pull_system`, `zuse_stick_first`; the data stick's QEMU device now `id=datadev`, so it can be pulled) -- running (build/t4/suite48/). Then the other tests: `mint_zuse_refuse`, `mint_pull_system`, `zuse_stick_first`, `mint_small`, the pair's stick offered - [ ] 4.9 regressions, full acceptance on three ISAs (new dict_hash, equal), FABRIC entry, commit Working notes: the boot's own words are `sk_v4_words[]` in `kernel/src/v4/sk_v4.c`, served by diff --git a/kernel/Makefile b/kernel/Makefile index 8b24d8bf..b6115efc 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -217,7 +217,7 @@ endif # DATASTICK= boots v4 with no drive at all (headless). DATASTICK ?= $(if $(QEMU_V3_BOOT),,1) ifneq ($(strip $(DATASTICK)),) -DATASTICK_QEMU_ARGS = -drive if=none,id=datadrv,file=$(DATASTICK_IMG),format=raw -device usb-storage,bus=xhci0.0,port=2,drive=datadrv +DATASTICK_QEMU_ARGS = -drive if=none,id=datadrv,file=$(DATASTICK_IMG),format=raw -device usb-storage,bus=xhci0.0,port=2,drive=datadrv,id=datadev DATASTICK_DEP := datastick else DATASTICK_QEMU_ARGS := diff --git a/scripts/qemu_session.py b/scripts/qemu_session.py index 728a085a..e1cf10d9 100755 --- a/scripts/qemu_session.py +++ b/scripts/qemu_session.py @@ -69,6 +69,15 @@ the stick's, plan 2026-10-26-stick-1-screen-and-keyboard.md): its size said, YES typed, "real Zuse minted onto the second stick", the prompt, 7 ok; afterwards sfdisk --verify on it clean, one StarshipOS identity partition (plan 2026-10-29-stick-5, Task 4) + mint_zuse_refuse as mint_zuse, `no` typed: "stopped -- nothing written", the stick's bytes the + same, the prompt (still the proxy); a second MINT-ZUSE offers the same stick again + mint_small a 32 MiB stick offered: "under 64 MiB", nothing written, the prompt + mint_zuse_used as mint_zuse, the stick offered the pair's Zuse stick (Review Focus 2): rewritten, + the new Zuse recognised + mint_pull_system MINT-ZUSE, then the data stick pulled (Review Focus 3): "stopped -- nothing + written", session ended, headless; replugged: the proxy logs in again + zuse_stick_first after a mint on a data stick made in the session, the same copy booted again with + her stick on port 1 and the data stick on port 2 (Review Focus 1): she is logged in bam_flush --target qemu-stick --stick-gib 16: an Artemis block changed and SAVE-BUFFERS'd three times, each timed (TIME:); each answers ok within 2 s (#155: it took 5-6 s); then the BAM's bytes on the stick hashed (BAM:), to be the same before and after #155's change @@ -115,7 +124,8 @@ NO_ZUSE_MODES = {"gpt_zuse", "gpt_hotplug", "gpt_foreign", "gpt_bad_crc", "gpt_b "alttab_after_logout", "alttab_before_pull", "emergency_pull", "screen_dark_until_login", "screen_console_after_login", "screen_dark_after_logout", "kbd_typeahead", "stick_boot", "stick_v3", "stick_zuse", "screen_boot", "genesis", - "stick_genesis", "stick_grow", "stick_small", "bam_flush"} + "stick_genesis", "stick_grow", "stick_small", "bam_flush", + "zuse_stick_first"} label = a.label or f"{a.mode}-{a.arch}" work = os.path.join(ROOT, "build", "qemu-session", label) shutil.rmtree(work, ignore_errors=True) @@ -167,6 +177,12 @@ if a.stick_gib: make_args.append(f"STICK_GIB={a.stick_gib}") if a.mode in ("stick_grow", "stick_small", "bam_flush"): make_args.append("KERNEL_ARGS=--log-level=info") # the blk: disk lines the sizes are read from +if a.mode == "zuse_stick_first": + # a data stick made once into the session's directory: minted on, then booted again + dstick = os.path.join(work, "data.img") + subprocess.run(["make", "-f", "kernel/Makefile", f"ARCH={a.arch}", "datastick", f"DATASTICK_IMG={dstick}"], + cwd=ROOT, check=True, stdout=subprocess.DEVNULL) + make_args += ["DATASTICK=1", f"DATASTICK_IMG={dstick}", "DATASTICK_DEP="] if a.mode == "genesis": # a fresh data stick, made once into this session's directory and booted twice: the second # boot is the same copy, so it finds what the first wrote (plan 2026-10-29-stick-5, Task 1) @@ -546,6 +562,110 @@ elif m in ("stick_grow", "stick_small"): v.returncode == 0 and "No errors detected" in v.stdout + v.stderr) boot_done = True +elif m in ("mint_zuse_refuse", "mint_small", "mint_zuse_used", "mint_pull_system", "zuse_stick_first"): + import hashlib + + def sha(path): + with open(path, "rb") as f: + return hashlib.sha256(f.read()).hexdigest() + + def mint_offer(img, port=3, n=1): + c = count(r"MINT-ZUSE: plug in the stick for the real Zuse") + type_line("MINT-ZUSE") + check("MINT-ZUSE: plug in the stick for the real Zuse", + wait_for(r"MINT-ZUSE: plug in the stick for the real Zuse", 60, c), near=r"MINT-ZUSE") + if img: + add_stick(n, img, port) + + check("[zuse@Hera] ok> (the proxy, on a fresh data stick)", wait_for(PROMPT, 300)) + if m == "mint_zuse_refuse": + img = os.path.join(work, "offered.img") + subprocess.run(["truncate", "-s", "600M", img], check=True) + before = sha(img) + mint_offer(img) + check("the size line", wait_for(r"MINT-ZUSE: a stick of 600 MiB -- all of it is erased", 120), near=r"MINT-ZUSE") + wait_for(r"MINT-ZUSE: type YES to write it", 30) + n = count(PROMPT) + type_line("no") + check("MINT-ZUSE: stopped -- nothing written", wait_for(r"MINT-ZUSE: stopped -- nothing written", 60), near=r"MINT-ZUSE") + check("the prompt", wait_for(PROMPT, 60, n)) + check("no real Zuse minted", count(r"real Zuse minted") == 0) + # a second MINT-ZUSE: the same stick, still plugged in, offered again + type_line("MINT-ZUSE") + check("offered again: the size line a second time", + wait_for(r"MINT-ZUSE: a stick of 600 MiB -- all of it is erased", 60, 1), near=r"MINT-ZUSE") + wait_for(r"MINT-ZUSE: type YES to write it", 30, 1) + n = count(PROMPT) + type_line("no") + check("stopped again", wait_for(r"MINT-ZUSE: stopped -- nothing written", 60, 1)) + check("the prompt again", wait_for(PROMPT, 60, n)) + shutdown() + boot_done = True + check("the offered stick's bytes are the same (sha256)", sha(img) == before) + elif m == "mint_small": + img = os.path.join(work, "small.img") + subprocess.run(["truncate", "-s", "32M", img], check=True) + before = sha(img) + n = count(PROMPT) + mint_offer(img) + check("MINT-ZUSE: the stick is under 64 MiB", wait_for(r"MINT-ZUSE: the stick is under 64 MiB", 120), near=r"MINT-ZUSE") + check("the prompt", wait_for(PROMPT, 60, n)) + check("no real Zuse minted", count(r"real Zuse minted") == 0) + shutdown() + boot_done = True + check("the small stick's bytes are the same (sha256)", sha(img) == before) + elif m == "mint_zuse_used": + img = os.path.join(work, "used.img") + subprocess.run(["cp", "--sparse=always", zimg, img], check=True) # the pair's Zuse stick + mint_offer(img) + check("the size line names the used stick", wait_for(r"MINT-ZUSE: a stick of \d+ MiB -- all of it is erased", 120), + near=r"MINT-ZUSE") + wait_for(r"MINT-ZUSE: type YES to write it", 30) + type_line("YES") + minted = wait_for(r"Zuse: real Zuse minted onto the second stick", 300) + check("Zuse: real Zuse minted onto the second stick", minted, near=r"MINT-ZUSE|Zuse:") + t = text() + after = t[t.find("real Zuse minted"):] if minted else "" + check("the new Zuse recognised on it", "Zuse: identity confirmed from attached thumbdrive" in after) + shutdown() + boot_done = True + sf = shutil.which("sfdisk") or "/usr/sbin/sfdisk" + j = subprocess.run([sf, "--json", img], capture_output=True, text=True) + parts = json.loads(j.stdout)["partitiontable"]["partitions"] if j.returncode == 0 and j.stdout else [] + check(f"rewritten: one identity partition, no Artemis ({len(parts)} partition(s))", + len(parts) == 1 and parts[0]["type"].upper() == GPT_IDENTITY) + elif m == "mint_pull_system": + mint_offer(None) + time.sleep(3) + qcmd("device_del", id="datadev") + check("MINT-ZUSE: stopped -- nothing written", wait_for(r"MINT-ZUSE: stopped -- nothing written", 120), near=r"MINT-ZUSE") + check("Zuse: session ended", wait_for(r"Zuse: session ended -- reattach to re-authenticate", 60)) + n = count(ANYPROMPT) + check("headless: no new ok> for 20 s", not wait_for(ANYPROMPT, 20, n)) + data = os.path.join(ROOT, "build", a.arch, "kernel", "datastick.img") + c = count(r"Zuse: identity confirmed from attached thumbdrive") + add_stick(9, data, 2) + check("replugged: the proxy logs in again", wait_for(r"Zuse: identity confirmed from attached thumbdrive", 120, c)) + check("no real Zuse minted", count(r"real Zuse minted") == 0) + elif m == "zuse_stick_first": + img = os.path.join(work, "zuse-real.img") + subprocess.run(["truncate", "-s", "600M", img], check=True) + mint_offer(img) + wait_for(r"MINT-ZUSE: type YES to write it", 120) + type_line("YES") + check("the real Zuse minted", wait_for(r"Zuse: real Zuse minted onto the second stick", 300), near=r"MINT-ZUSE|Zuse:") + shutdown() + print("-- the second boot: her stick on port 1, the same data stick on port 2", flush=True) + boot([x for x in make_args if x != "clean" and not x.startswith("ZUSEDISK=")] + [f"ZUSEDISK={img}"]) + check("POST: PASSED (second boot)", wait_for(r"POST: PASSED", 900)) + check("she is logged in: identity confirmed", + wait_for(r"Zuse: identity confirmed from attached thumbdrive", 300), near=r"Artemis: |Zuse: |USB: ") + check("[zuse@Hera] ok> (second boot)", wait_for(PROMPT, 120)) + time.sleep(5) + check(f"identity confirmed once ({count(r'Zuse: identity confirmed')})", count(r"Zuse: identity confirmed") == 1) + check("no genesis on the second boot", count(r"Zuse: genesis minted") == 0) + check("no fault", count(r"EXCEPTION|PANIC|panic") == 0) + elif m == "mint_zuse": blank = os.path.join(work, "zuse-real.img") subprocess.run(["truncate", "-s", "600M", blank], check=True)