This commit is contained in:
@@ -0,0 +1,206 @@
|
||||
#!/usr/bin/env python3
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
"""Synthetic host-only tests for the Phase-1.0Z passive batch contract."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
from dataclasses import asdict, replace
|
||||
from datetime import datetime, timezone
|
||||
import importlib.util
|
||||
from pathlib import Path
|
||||
import sys
|
||||
|
||||
|
||||
CURRENT_COMMANDS = "authid browse cat cd chgrp chmod chown chroot cmp cp df echo env exec exit export file find grep hbdbg hbldr hexdump http2_get id kill launch ln ls mkdir mknod mount mv notify pkg_install procstat ps pwd reptyr rm rmdir sfocreate sfoinfo sleep stat sum suspend sync sysctl touch umount".split()
|
||||
|
||||
|
||||
def load(path: Path):
|
||||
spec = importlib.util.spec_from_file_location("phase10z_contract", path)
|
||||
assert spec and spec.loader
|
||||
module = importlib.util.module_from_spec(spec)
|
||||
sys.modules[spec.name] = module
|
||||
spec.loader.exec_module(module)
|
||||
return module
|
||||
|
||||
|
||||
def require(value: bool, message: str) -> None:
|
||||
if not value:
|
||||
raise RuntimeError(message)
|
||||
|
||||
|
||||
def greeting(extra: str = "", eol: str = "\n") -> bytes:
|
||||
text = (
|
||||
"Welcome to shsrv.elf running on pid 123, compiled Jul 22 2026 at 12:34:56\n"
|
||||
"Model: synthetic-model\nS/N: SYNTHETIC-SERIAL-NEVER-RETAIN\n"
|
||||
"S/W: 9.60\nSoC temp: 40 C\nCPU temp: 41 C\n"
|
||||
"CPU freq: 3500 MHz\n" + extra)
|
||||
return text.replace("\n", eol).encode("ascii")
|
||||
|
||||
|
||||
def help_output() -> str:
|
||||
return "Builtin commands:\n" + "".join(
|
||||
f" {command} - synthetic\n" for command in CURRENT_COMMANDS) + "\n"
|
||||
|
||||
|
||||
def main() -> int:
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--root", type=Path, required=True)
|
||||
args = parser.parse_args()
|
||||
root = args.root.resolve()
|
||||
sys.path.insert(0, str(root / "tools"))
|
||||
module = load(root / "tools/phase10z_passive_batch_contract.py")
|
||||
from phase10w_shsrv_client_policy import SessionPlan
|
||||
|
||||
def plan(window="T2_GREETING_AND_HELP", path=None):
|
||||
commands = ("help",) if window == "T2_GREETING_AND_HELP" else ("stat", "sum")
|
||||
return SessionPlan("synthetic_run", "not-retained.invalid", 2323,
|
||||
window, path, commands, 10,
|
||||
datetime(2030, 1, 1, tzinfo=timezone.utc))
|
||||
|
||||
def expect_failure(function):
|
||||
try:
|
||||
function()
|
||||
except module.PassiveContractError:
|
||||
return
|
||||
raise RuntimeError("invalid input was accepted")
|
||||
|
||||
cases = []
|
||||
|
||||
def case(name):
|
||||
def register(function):
|
||||
cases.append((name, function)); return function
|
||||
return register
|
||||
|
||||
@case("01 help batch is exact plain LF")
|
||||
def _(): require(module.build_passive_batch(plan()).payload == b"help\n", "help bytes differ")
|
||||
|
||||
@case("02 stat and sum form one ordered batch")
|
||||
def _(): require(module.build_passive_batch(plan("T3_ONE_EXACT_PATH", "/data/a.elf")).payload == b"stat /data/a.elf\nsum /data/a.elf\n", "path batch differs")
|
||||
|
||||
@case("03 maximum safe path reaches exact batch bound")
|
||||
def _():
|
||||
batch = module.build_passive_batch(plan("T3_ONE_EXACT_PATH", "/" + "a" * 511))
|
||||
require(len(batch.payload) == module.MAX_BATCH_BYTES == 1035, "batch bound differs")
|
||||
|
||||
@case("04 batch contains no CR NUL IAC or shell separators")
|
||||
def _():
|
||||
payload = module.build_passive_batch(plan("T3_ONE_EXACT_PATH", "/data/a.elf")).payload
|
||||
require(not any(value in payload for value in (0, 13, 255, ord(";"), ord("|"), ord("&"))), "forbidden byte present")
|
||||
|
||||
@case("05 target is not retained")
|
||||
def _(): require("target" not in asdict(module.build_passive_batch(plan())) and "not-retained" not in repr(module.build_passive_batch(plan())), "target retained")
|
||||
|
||||
@case("06 wrong command sequence is rejected")
|
||||
def _(): expect_failure(lambda: module.build_passive_batch(replace(plan(), commands=("stat",))))
|
||||
|
||||
@case("07 help path is rejected")
|
||||
def _(): expect_failure(lambda: module.build_passive_batch(replace(plan(), exact_literal_path="/x")))
|
||||
|
||||
@case("08 missing exact path is rejected")
|
||||
def _(): expect_failure(lambda: module.build_passive_batch(plan("T3_ONE_EXACT_PATH")))
|
||||
|
||||
@case("09 path injection and non ASCII are rejected")
|
||||
def _():
|
||||
for path in ("/x;id", "/x y", "/x\nhelp", "/café"):
|
||||
expect_failure(lambda path=path: module.build_passive_batch(plan("T3_ONE_EXACT_PATH", path)))
|
||||
|
||||
@case("10 incoming IAC fails closed")
|
||||
def _():
|
||||
value = module.PassiveResultAccumulator(module.build_passive_batch(plan()))
|
||||
expect_failure(lambda: value.feed_supplied_chunk(b"x\xffy"))
|
||||
|
||||
@case("10b forged direct batch is rejected")
|
||||
def _():
|
||||
forged = module.PassiveBatch("T3_ONE_EXACT_PATH", b"help\n", (), 2, 10)
|
||||
expect_failure(lambda: module.PassiveResultAccumulator(forged))
|
||||
|
||||
@case("10c resumed direct batch is rejected")
|
||||
def _():
|
||||
batch = module.build_passive_batch(plan())
|
||||
expect_failure(lambda: module.PassiveResultAccumulator(replace(batch, resume_allowed=True)))
|
||||
|
||||
@case("11 legacy LF help transcript seals at deadline")
|
||||
def _():
|
||||
value = module.PassiveResultAccumulator(module.build_passive_batch(plan()))
|
||||
value.feed_supplied_chunk(greeting(help_output()))
|
||||
require(value.seal_at_hard_deadline(True)["classification"] == "SOURCE_FAMILY_FINGERPRINT_ONLY", "legacy transcript failed")
|
||||
|
||||
@case("12 current CRLF help transcript seals at deadline")
|
||||
def _():
|
||||
value = module.PassiveResultAccumulator(module.build_passive_batch(plan()))
|
||||
value.feed_supplied_chunk(greeting(help_output(), "\r\n"))
|
||||
require(value.seal_at_hard_deadline(True)["passive_batch_contract"]["source_family_selected"] is False, "current transcript failed")
|
||||
|
||||
@case("13 exact path transcript requires stat and sum")
|
||||
def _():
|
||||
path = "/data/a.elf"; value = module.PassiveResultAccumulator(module.build_passive_batch(plan("T3_ONE_EXACT_PATH", path)))
|
||||
value.feed_supplied_chunk(greeting(f"filename: {path}\nsize: 123\nmtime: 456\n12345 {path}\n"))
|
||||
result = value.seal_at_hard_deadline(True)
|
||||
require(result["file_observations"][0]["size"] == 123 and result["exact_identity"] is False, "path result promoted or lost")
|
||||
|
||||
@case("14 partial help fails closed")
|
||||
def _():
|
||||
value = module.PassiveResultAccumulator(module.build_passive_batch(plan())); value.feed_supplied_chunk(greeting("Builtin commands:\n help - partial\n\n"))
|
||||
expect_failure(lambda: value.seal_at_hard_deadline(True))
|
||||
|
||||
@case("15 stat without sum fails closed")
|
||||
def _():
|
||||
path = "/data/a.elf"; value = module.PassiveResultAccumulator(module.build_passive_batch(plan("T3_ONE_EXACT_PATH", path)))
|
||||
value.feed_supplied_chunk(greeting(f"filename: {path}\nsize: 123\n")); expect_failure(lambda: value.seal_at_hard_deadline(True))
|
||||
|
||||
@case("16 sum without stat fails closed")
|
||||
def _():
|
||||
path = "/data/a.elf"; value = module.PassiveResultAccumulator(module.build_passive_batch(plan("T3_ONE_EXACT_PATH", path)))
|
||||
value.feed_supplied_chunk(greeting(f"12345 {path}\n")); expect_failure(lambda: value.seal_at_hard_deadline(True))
|
||||
|
||||
@case("16b extra fields cannot mask missing size")
|
||||
def _():
|
||||
path = "/data/a.elf"; value = module.PassiveResultAccumulator(module.build_passive_batch(plan("T3_ONE_EXACT_PATH", path)))
|
||||
observation = {"path": path, "metadata_seen": True, "weak_checksum": "12345", "weak_checksum_algorithm": "BSD_ROTATE_16", "cryptographic_checksum": False, "proves_exact_binary": False, "extra": 1}
|
||||
expect_failure(lambda: value._validate_complete_result({"classification": "WEAK_FILE_CORRELATION_ONLY", "file_observations": [observation]}))
|
||||
|
||||
@case("17 prompt is not an early completion event")
|
||||
def _():
|
||||
value = module.PassiveResultAccumulator(module.build_passive_batch(plan())); value.feed_supplied_chunk(b"/$ ")
|
||||
require(value.state == "RECEIVING" and not hasattr(value, "seal_at_prompt"), "prompt completion exists")
|
||||
|
||||
@case("18 absent deadline event fails closed")
|
||||
def _():
|
||||
value = module.PassiveResultAccumulator(module.build_passive_batch(plan())); value.feed_supplied_chunk(greeting(help_output()))
|
||||
expect_failure(lambda: value.seal_at_hard_deadline(False))
|
||||
|
||||
@case("19 seal is one shot")
|
||||
def _():
|
||||
value = module.PassiveResultAccumulator(module.build_passive_batch(plan())); value.feed_supplied_chunk(greeting(help_output())); value.seal_at_hard_deadline(True)
|
||||
expect_failure(lambda: value.seal_at_hard_deadline(True))
|
||||
|
||||
@case("20 feed after seal fails")
|
||||
def _():
|
||||
value = module.PassiveResultAccumulator(module.build_passive_batch(plan())); value.feed_supplied_chunk(greeting(help_output())); value.seal_at_hard_deadline(True)
|
||||
expect_failure(lambda: value.feed_supplied_chunk(b"later"))
|
||||
|
||||
@case("21 abort cannot produce a result")
|
||||
def _():
|
||||
value = module.PassiveResultAccumulator(module.build_passive_batch(plan())); value.abort()
|
||||
expect_failure(lambda: value.seal_at_hard_deadline(True))
|
||||
|
||||
@case("22 no EOF prompt transport CLI or exact proof API exists")
|
||||
def _():
|
||||
names = set(dir(module.PassiveResultAccumulator)) | set(dir(module))
|
||||
require(not ({"seal_at_eof", "seal_at_prompt", "connect", "main"} & names), "forbidden API exists")
|
||||
|
||||
failures = []
|
||||
for name, function in cases:
|
||||
try:
|
||||
function(); print(f"PASS {name}")
|
||||
except Exception as error: # noqa: BLE001 - synthetic harness
|
||||
failures.append(f"{name}: {error}"); print(f"FAIL {name}: {error}")
|
||||
if failures:
|
||||
return 1
|
||||
print(f"Phase-1.0Z passive-batch tests passed: {len(cases)}")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Reference in New Issue
Block a user