#!/usr/bin/env python3 """CP1 statische + adversariale Tests (A-J) für control_reader.py.""" import os import shutil import sys import tempfile import control_reader as cr PASS = 0 FAIL = 0 results = [] def check(name, cond): global PASS, FAIL if cond: PASS += 1 results.append(f"PASS {name}") else: FAIL += 1 results.append(f"FAIL {name}") class Env: def __init__(self): self.tmp = tempfile.mkdtemp() self.state_dir = os.path.join(self.tmp, "state") os.makedirs(self.state_dir, exist_ok=True) # aktuelle boot_id simulieren self.cur_boot = "boot-test-1234" self.boot_file = os.path.join(self.tmp, "boot_id") with open(self.boot_file, "w") as f: f.write(self.cur_boot + "\n") cr.STATE_DIR = self.state_dir cr.BOOT_ID_FILE = self.boot_file def write(self, name, content): with open(os.path.join(self.state_dir, name), "w") as f: f.write(content) def missing_boot(self): os.remove(self.boot_file) def read(): return cr.read_control_state() def fmt(eff): return {k: v for k, v in eff.items() if k.endswith("_effective")} # ---------- TEST 1: initial safe state ---------- print("== TEST 1: Initial Safe State ==") e = Env() e.write("global_autonomy", "OFF") e.write("productive_mutations", "OFF") e.write("save_execution", "OFF") e.write("delete_execution", "OFF") e.write("trading_execution", "OFF") e.write("emergency_stop", "ON") s = read() check("initial global=OFF", s["global_autonomy_effective"] == "OFF") check("initial mutations=OFF", s["productive_mutations_effective"] == "OFF") check("initial save=OFF", s["save_effective"] == "OFF") check("initial delete=OFF", s["delete_effective"] == "OFF") check("initial trading=OFF", s["trading_effective"] == "OFF") check("initial emergency=ON", s["emergency_effective"] == "ON") # ---------- TEST A: positive ON mit falscher Boot-ID -> OFF ---------- print("== TEST A: wrong boot-id -> OFF ==") e = Env() e.write("global_autonomy", "ON\nboot_id=other-boot\n") e.write("productive_mutations", "OFF") e.write("save_execution", "OFF") e.write("delete_execution", "OFF") e.write("trading_execution", "OFF") e.write("emergency_stop", "OFF") s = read() check("A global OFF bei falscher boot_id", s["global_autonomy_effective"] == "OFF") # ---------- TEST B: ON aktueller boot_id aber emergency ON -> OFF ---------- print("== TEST B: emergency ON blockiert positives Gate ==") e = Env() e.write("global_autonomy", f"ON\nboot_id={e.cur_boot}\n") e.write("productive_mutations", "OFF") e.write("save_execution", "OFF") e.write("delete_execution", "OFF") e.write("trading_execution", "OFF") e.write("emergency_stop", "ON") s = read() check("B global OFF bei emergency ON", s["global_autonomy_effective"] == "OFF") check("B emergency ON", s["emergency_effective"] == "ON") # ---------- TEST C: save ON aber mutations OFF -> SAVE OFF ---------- print("== TEST C: save ON, mutations OFF -> SAVE OFF ==") e = Env() e.write("global_autonomy", f"ON\nboot_id={e.cur_boot}\n") e.write("productive_mutations", "OFF") e.write("save_execution", f"ON\nboot_id={e.cur_boot}\n") e.write("delete_execution", "OFF") e.write("trading_execution", "OFF") e.write("emergency_stop", "OFF") s = read() check("C save OFF bei mutations OFF", s["save_effective"] == "OFF") check("C global ON", s["global_autonomy_effective"] == "ON") # ---------- TEST D: delete ON aber global OFF -> DELETE OFF ---------- print("== TEST D: delete ON, global OFF -> DELETE OFF ==") e = Env() e.write("global_autonomy", "OFF") e.write("productive_mutations", "OFF") e.write("save_execution", "OFF") e.write("delete_execution", f"ON\nboot_id={e.cur_boot}\n") e.write("trading_execution", "OFF") e.write("emergency_stop", "OFF") s = read() check("D delete OFF bei global OFF", s["delete_effective"] == "OFF") check("D global OFF", s["global_autonomy_effective"] == "OFF") # ---------- TEST E: trading ON aber emergency ON -> TRADING OFF ---------- print("== TEST E: trading ON, emergency ON -> TRADING OFF ==") e = Env() e.write("global_autonomy", "OFF") e.write("productive_mutations", "OFF") e.write("save_execution", "OFF") e.write("delete_execution", "OFF") e.write("trading_execution", f"ON\nboot_id={e.cur_boot}\n") e.write("emergency_stop", "ON") s = read() check("E trading OFF bei emergency ON", s["trading_effective"] == "OFF") check("E emergency ON", s["emergency_effective"] == "ON") # ---------- TEST F: fehlende emergency_stop -> EMERGENCY ON ---------- print("== TEST F: missing emergency_stop -> ON ==") e = Env() e.write("global_autonomy", "OFF") e.write("productive_mutations", "OFF") e.write("save_execution", "OFF") e.write("delete_execution", "OFF") e.write("trading_execution", "OFF") # KEIN emergency_stop schreiben s = read() check("F emergency ON bei fehlender Datei", s["emergency_effective"] == "ON") # ---------- TEST G: malformed emergency_stop -> ON ---------- print("== TEST G: malformed emergency_stop -> ON ==") e = Env() e.write("global_autonomy", "OFF") e.write("productive_mutations", "OFF") e.write("save_execution", "OFF") e.write("delete_execution", "OFF") e.write("trading_execution", "OFF") e.write("emergency_stop", "MAYBE\n") s = read() check("G emergency ON bei malformed", s["emergency_effective"] == "ON") # ---------- TEST H: alter Grant nach simuliertem Reboot -> OFF ---------- print("== TEST H: alter Grant nach Reboot -> OFF ==") e = Env() e.write("global_autonomy", f"ON\nboot_id={e.cur_boot}\n") e.write("productive_mutations", "OFF") e.write("save_execution", "OFF") e.write("delete_execution", "OFF") e.write("trading_execution", "OFF") e.write("emergency_stop", "OFF") s = read() check("H vor Reboot global ON", s["global_autonomy_effective"] == "ON") # simulierter Reboot: boot_id ändert sich with open(e.boot_file, "w") as f: f.write("boot-after-reboot-999\n") s = read() check("H nach Reboot global OFF", s["global_autonomy_effective"] == "OFF") # ---------- Missing boot_id file -> positive gates OFF ---------- print("== TEST: missing boot_id file ==") e = Env() e.write("global_autonomy", f"ON\nboot_id={e.cur_boot}\n") e.write("productive_mutations", "OFF") e.write("save_execution", "OFF") e.write("delete_execution", "OFF") e.write("trading_execution", "OFF") e.write("emergency_stop", "OFF") e.missing_boot() s = read() check("missing boot_id -> global OFF", s["global_autonomy_effective"] == "OFF") # ---------- Permission/read error ---------- print("== TEST: unreadable control file ==") e = Env() e.write("global_autonomy", "ON") # no boot_id -> invalid anyway e.write("productive_mutations", "OFF") e.write("save_execution", "OFF") e.write("delete_execution", "OFF") e.write("trading_execution", "OFF") e.write("emergency_stop", "ON") os.chmod(os.path.join(e.state_dir, "emergency_stop"), 0o000) s = read() check("unreadable emergency -> ON", s["emergency_effective"] == "ON") os.chmod(os.path.join(e.state_dir, "emergency_stop"), 0o644) # ---------- Positive gate OHNE boot_id (ON-Grant ohne Binding) -> OFF ---------- print("== TEST: ON-Grant ohne boot_id ==") e = Env() e.write("global_autonomy", "ON\n") # no boot_id line e.write("productive_mutations", "OFF") e.write("save_execution", "OFF") e.write("delete_execution", "OFF") e.write("trading_execution", "OFF") e.write("emergency_stop", "OFF") s = read() check("ON ohne boot_id -> global OFF", s["global_autonomy_effective"] == "OFF") # ---------- Empty file -> OFF (positive), ON (emergency) ---------- print("== TEST: empty positive file ==") e = Env() e.write("global_autonomy", "") # empty e.write("productive_mutations", "OFF") e.write("save_execution", "OFF") e.write("delete_execution", "OFF") e.write("trading_execution", "OFF") e.write("emergency_stop", "OFF") s = read() check("empty positive -> global OFF", s["global_autonomy_effective"] == "OFF") check("empty positive raw MISSING", s["global_autonomy_raw"] == "MISSING") # ---------- unknown field -> malformed -> OFF ---------- print("== TEST: unknown field ==") e = Env() e.write("global_autonomy", "ON\nfoo=bar\nboot_id=xyz\n") e.write("productive_mutations", "OFF") e.write("save_execution", "OFF") e.write("delete_execution", "OFF") e.write("trading_execution", "OFF") e.write("emergency_stop", "OFF") s = read() check("unknown field -> global OFF", s["global_autonomy_effective"] == "OFF") print() print(f"RESULT: PASS={PASS} FAIL={FAIL}") for r in results: print(r) sys.exit(1 if FAIL else 0)