#!/overlayer/syshub/bin/python3
# Zainium OS release tests (2 Nov 2026). Run as root: elevate python3 -I ~/zainium-test/release-tests.py
# Every line in the log is a real result from this machine; nothing is assumed.
import ctypes, errno, fcntl, glob, os, struct, subprocess, sys, time

HOME = "/home/alizain"
LOG = f"{HOME}/zainium-test/release-tests.log"
out = open(LOG, "w")
results = []

def log(s=""):
    print(s); out.write(s + "\n"); out.flush()

def check(name, ok, detail=""):
    results.append((name, ok))
    log(f"[{'PASS' if ok else 'FAIL'}] {name}" + (f" -- {detail}" if detail else ""))

def section(t):
    log(""); log("=" * 70); log(t); log("=" * 70)

def read(p):
    try:
        return open(p).read()
    except OSError as e:
        return f"<{os.strerror(e.errno)}>"

def run(cmd):
    r = subprocess.run(cmd, shell=True, capture_output=True, text=True)
    return (r.stdout + r.stderr).strip()

libc = ctypes.CDLL(None, use_errno=True)
MS_RDONLY, MS_REMOUNT, MS_BIND = 1, 32, 4096
FS_IOC_GETFLAGS = 0x80086601
FS_VERITY_FL = 0x00100000
FS_IOC_MEASURE_VERITY = 0xC0046686

def verity_on(path):
    try:
        fd = os.open(path, os.O_RDONLY | os.O_NOFOLLOW)
    except OSError:
        return None
    try:
        buf = fcntl.ioctl(fd, FS_IOC_GETFLAGS, struct.pack("l", 0))
        return bool(struct.unpack("l", buf)[0] & FS_VERITY_FL)
    except OSError:
        return None
    finally:
        os.close(fd)

def verity_digest(path):
    fd = os.open(path, os.O_RDONLY)
    try:
        arg = bytearray(struct.pack("HH", 0, 64) + bytes(64))
        fcntl.ioctl(fd, FS_IOC_MEASURE_VERITY, arg)
        alg, size = struct.unpack("HH", arg[:4])
        return {1: "sha256", 2: "sha512"}.get(alg, str(alg)) + ":" + arg[4:4 + size].hex()
    finally:
        os.close(fd)

log(f"Zainium OS release tests -- {time.strftime('%Y-%m-%d %H:%M:%S %z')}")
log(f"kernel: {os.uname().release} {os.uname().version}")
if os.geteuid() != 0:
    log("must run as root (elevate)"); sys.exit(1)

# ── 1. kernel, lockdown, LSMs ────────────────────────────────────────────────
section("1. Kernel, lockdown and LSMs")
lsm = read("/sys/kernel/security/lsm").strip()
log(f"lsm: {lsm}")
check("IPE, IMA, AppArmor, Landlock, Yama, lockdown active",
      all(x in lsm.split(",") for x in ["lockdown", "ipe", "ima", "apparmor", "landlock", "yama"]), lsm)
lock = read("/sys/kernel/security/lockdown").strip()
check("kernel lockdown = integrity", "[integrity]" in lock, lock)
sig = read("/sys/module/module/parameters/sig_enforce").strip()
check("module signatures enforced", sig == "Y", f"sig_enforce={sig}")
mods = read("/proc/modules").count("\n")
check("new kernel modules load", mods > 50, f"{mods} modules loaded")

# ── 2. IMA ───────────────────────────────────────────────────────────────────
section("2. IMA")
pol = read("/sys/kernel/security/ima/policy")
log(pol.strip())
check("IMA policy from /overlayer/syshub/etc/ima/ima-policy is loaded",
      "func=BPRM_CHECK" in pol and "func=MODULE_CHECK" in pol)
meas = read("/sys/kernel/security/ima/ascii_runtime_measurements").splitlines()
log(f"measurements: {len(meas)}")
for m in meas[:3] + meas[-3:]:
    log("  " + m[:160])
check("IMA measures programs and modules (more than boot_aggregate)", len(meas) > 10, f"{len(meas)} entries")
check("IMA measured the zex binary", any("/bin/zex" in m for m in meas))
jr = run("journalctl -b --no-pager -o cat | grep -iE 'IMA policy' | head -5")
log(f"journal: {jr or '<nothing>'}")
check("no 'Failed to load IMA policy' in this boot", "Failed to load IMA policy" not in jr)

# ── 3. IPE ───────────────────────────────────────────────────────────────────
section("3. IPE")
active = read("/sys/kernel/security/ipe/policies/zainium/active").strip()
check("IPE built-in policy 'zainium' is active", active == "1", f"active={active}")
log(read("/sys/kernel/security/ipe/policies/zainium/policy").strip())
log(f"enforce={read('/sys/kernel/security/ipe/enforce').strip()} success_audit={read('/sys/kernel/security/ipe/success_audit').strip()}")
check("IPE is enforcing", read("/sys/kernel/security/ipe/enforce").strip() == "1")
fd = os.open("/overlayer/syshub/bin/bash", os.O_RDONLY)
r = libc.syscall(320, fd, -1, 0, None, 4)  # kexec_file_load(kernel_fd, initrd=-1, cmdline_len=0, NULL, NO_INITRAMFS)
e = ctypes.get_errno()
os.close(fd)
check("IPE refuses a kexec image (EACCES)", r != 0 and e == errno.EACCES, f"rc={r} errno={errno.errorcode.get(e, e)}")

# ── 4. read-only system view ─────────────────────────────────────────────────
section("4. Sealed system view (OverlayFS)")
mi = [l for l in read("/proc/self/mountinfo").splitlines()
      if any(f" {p} " in l for p in ["/overlayer/syshub", "/overlayer/syshub/etc", "/overlayer/syshub/var", "/overlayer/zaisys", "/overlayer/zexlib"])]
for l in mi:
    f = l.split(" ")
    log(f"  {f[4]:24} {f[5]:18} {' '.join(f[f.index('-') + 1:])[:150]}")
def mopts(t):
    for l in mi:
        f = l.split(" ")
        if f[4] == t:
            return f[5] + "," + f[-1]
    return ""
check("/overlayer/syshub is ro and sealed", "ro" in mopts("/overlayer/syshub").split(",") and "sealed" in mopts("/overlayer/syshub"), mopts("/overlayer/syshub"))
check("/overlayer/zaisys is ro, separate, no upper layer",
      "ro" in mopts("/overlayer/zaisys").split(",") and "upperdir" not in mopts("/overlayer/zaisys"), mopts("/overlayer/zaisys"))
check("/overlayer/syshub/etc and /var are rw", "rw" in mopts("/overlayer/syshub/etc").split(",") and "rw" in mopts("/overlayer/syshub/var").split(","))
for t in ["/overlayer/syshub", "/overlayer/zaisys"]:
    r = libc.mount(None, t.encode(), None, MS_REMOUNT, None)
    e = ctypes.get_errno()
    if r == 0:
        libc.mount(None, t.encode(), None, MS_REMOUNT | MS_RDONLY, None)
    check(f"root cannot remount {t} writable", r != 0 and e == errno.EROFS, "refused: EROFS" if r else "REMOUNTED RW")
for p in ["/overlayer/syshub/bin/zz-release-test", "/overlayer/zaisys/zz-release-test"]:
    try:
        open(p, "w").close(); os.unlink(p); ok, d = False, "write allowed"
    except OSError as ex:
        ok, d = ex.errno == errno.EROFS, os.strerror(ex.errno)
    check(f"root cannot write {os.path.dirname(p)}", ok, d)
for d in ["etc", "var"]:
    p = f"/overlayer/syshub/{d}/zz-release-test"
    open(p, "w").close()
    up = f"/overlayer/zexlib/union/{d}/zz-release-test"
    check(f"writes to /overlayer/syshub/{d} land in zexlib/union/{d}", os.path.exists(up))
    os.unlink(up)
name = f"zz-live-{os.getpid()}"
cached = os.path.exists(f"/overlayer/syshub/bin/{name}")  # caches "not found"
open(f"/overlayer/zexlib/union/bin/{name}", "w").close()
seen = os.path.exists(f"/overlayer/syshub/bin/{name}")
os.unlink(f"/overlayer/zexlib/union/bin/{name}")
check("software installed into the union shows at once (after a cached 'not found')", not cached and seen)
check("/zairoot (the disk) is not reachable", not os.path.exists("/zairoot"))

# ── 5. fs-verity ─────────────────────────────────────────────────────────────
section("5. fs-verity")
def scan(root, skip=()):
    on = off = err = 0; bad = []
    for d, dirs, files in os.walk(root):
        if d == root:
            dirs[:] = [x for x in dirs if x not in skip]
        for f in files:
            p = os.path.join(d, f)
            if os.path.islink(p) or not os.path.isfile(p):
                continue
            v = verity_on(p)
            if v is True: on += 1
            elif v is False: off += 1; bad.append(p)
            else: err += 1
    return on, off, err, bad
for root, skip in [("/overlayer/syshub", ("etc", "var")), ("/overlayer/zaisys", ())]:
    on, off, err, bad = scan(root, skip)
    total = on + off
    pct = 100.0 * on / total if total else 0
    log(f"{root} (without {', '.join(skip) or '-'}): {on}/{total} sealed ({pct:.2f}%), {err} unreadable")
    for b in bad[:15]:
        log(f"  not sealed: {b}")
    check(f"every file in {root} is sealed", off == 0 and total > 0, f"{on}/{total}")
target = None
for d, _, files in os.walk("/overlayer/zexlib/union/lib"):
    for f in files:
        p = os.path.join(d, f)
        if not os.path.islink(p) and verity_on(p):
            target = p; break
    if target: break
if target:
    try:
        os.close(os.open(target, os.O_WRONLY)); ok, d = False, "opened for writing"
    except OSError as ex:
        ok, d = ex.errno in (errno.EPERM, errno.ETXTBSY, errno.EACCES), os.strerror(ex.errno)
    check("a sealed file cannot be opened for writing, even by root", ok, f"{target}: {d}")
for p in ["/overlayer/syshub/bin/elevate", "/overlayer/syshub/bin/zex", "/overlayer/syshub/bin/sudo",
          "/overlayer/syshub/lib/libsys_resolver.so", "/overlayer/syshub/lib/systemd/systemd"]:
    try:
        log(f"  {verity_digest(p)}  {p}")
    except OSError as ex:
        log(f"  <{os.strerror(ex.errno)}>  {p}")

# ── 6. services and packages ─────────────────────────────────────────────────
section("6. Services and packages")
failed = run("systemctl --no-pager --failed --no-legend")
log(failed or "<no failed units>")
check("no failed systemd units", failed == "")
hn = run("hostnamectl 2>&1 | head -3")
log(hn)
check("hostnamed answers over D-Bus", "Static hostname" in hn, "needs systemd pkgrel 4 (PR #207) if it fails")
log(run("zex --version"))
for b in ["udisksd", "gvfsd"]:
    p = glob.glob(f"/overlayer/syshub/libexec/{b}") + glob.glob(f"/overlayer/syshub/libexec/udisks2/{b}")
    log(f"{b}: {p[0] if p else 'not installed'}")

# ── summary ─────────────────────────────────────────────────────────────────
section("Summary")
passed = sum(1 for _, ok in results if ok)
log(f"{passed}/{len(results)} checks passed")
for n, ok in results:
    if not ok:
        log(f"  FAILED: {n}")
out.close()
os.chmod(LOG, 0o644)
