From 926072a2cb673b61db58df479aaf7f0f9a20dad6 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 01:55:23 +0700 Subject: [PATCH 001/132] add reversible RandomX MSR authority --- .../usr/lib/rigos/rigos-randomx-msr | 440 ++++++++++++++++++ 1 file changed, 440 insertions(+) create mode 100644 build/usb/includes.chroot/usr/lib/rigos/rigos-randomx-msr diff --git a/build/usb/includes.chroot/usr/lib/rigos/rigos-randomx-msr b/build/usb/includes.chroot/usr/lib/rigos/rigos-randomx-msr new file mode 100644 index 00000000..27009d6f --- /dev/null +++ b/build/usb/includes.chroot/usr/lib/rigos/rigos-randomx-msr @@ -0,0 +1,440 @@ +#!/usr/bin/python3 +# Repository contract: LF line endings are required for appliance execution. +import argparse +import datetime as dt +import fcntl +import json +import os +import struct +import sys +import uuid +from pathlib import Path + +STATUS_SCHEMA = "rigos.randomx-msr-status/v1" +STATE_SCHEMA = "rigos.randomx-msr-state/v1" +REGISTER = 0x1A4 +TARGET_VALUE = 0xF +SUPPORTED_CPUS = {("GenuineIntel", 6, 42)} + + +class AuthorityError(RuntimeError): + pass + + +def utc_now() -> str: + return dt.datetime.now(dt.timezone.utc).isoformat(timespec="milliseconds") + + +def value_hex(value: int) -> str: + return f"0x{value:016x}" + + +def read_trimmed(path: Path, name: str) -> str: + try: + value = path.read_text(encoding="ascii").strip() + except (OSError, UnicodeError) as error: + raise AuthorityError(f"{name}: {error}") from error + if not value: + raise AuthorityError(f"{name} is empty") + return value + + +def parse_cpu_identity(path: Path) -> tuple[str, int, int]: + try: + text = path.read_text(encoding="ascii") + except (OSError, UnicodeError) as error: + raise AuthorityError(f"cpuinfo: {error}") from error + first = text.split("\n\n", 1)[0] + fields: dict[str, str] = {} + for line in first.splitlines(): + if ":" not in line: + continue + key, value = line.split(":", 1) + fields[key.strip()] = value.strip() + vendor = fields.get("vendor_id") + family = fields.get("cpu family") + model = fields.get("model") + if not vendor or family is None or model is None: + raise AuthorityError("cpu identity fields are incomplete") + try: + return vendor, int(family, 10), int(model, 10) + except ValueError as error: + raise AuthorityError("cpu family/model is malformed") from error + + +def parse_online_cpus(text: str) -> list[int]: + value = text.strip() + if not value: + raise AuthorityError("online CPU list is empty") + cpus: set[int] = set() + for item in value.split(","): + item = item.strip() + if not item: + raise AuthorityError("online CPU list contains an empty item") + if "-" in item: + start_text, end_text = item.split("-", 1) + try: + start = int(start_text, 10) + end = int(end_text, 10) + except ValueError as error: + raise AuthorityError("online CPU range is malformed") from error + if start < 0 or end < start: + raise AuthorityError("online CPU range is invalid") + cpus.update(range(start, end + 1)) + else: + try: + cpu = int(item, 10) + except ValueError as error: + raise AuthorityError("online CPU identifier is malformed") from error + if cpu < 0: + raise AuthorityError("online CPU identifier is invalid") + cpus.add(cpu) + if not cpus: + raise AuthorityError("online CPU list resolved to no CPUs") + return sorted(cpus) + + +def msr_path(device_root: Path, cpu: int) -> Path: + return device_root / str(cpu) / "msr" + + +def read_msr(device_root: Path, cpu: int, register: int = REGISTER) -> int: + path = msr_path(device_root, cpu) + try: + fd = os.open(path, os.O_RDONLY | os.O_CLOEXEC) + except OSError as error: + raise AuthorityError(f"open {path}: {error}") from error + try: + data = os.pread(fd, 8, register) + except OSError as error: + raise AuthorityError(f"read CPU {cpu} MSR {register:#x}: {error}") from error + finally: + os.close(fd) + if len(data) != 8: + raise AuthorityError(f"short read from CPU {cpu} MSR {register:#x}") + return struct.unpack(" None: + path = msr_path(device_root, cpu) + try: + fd = os.open(path, os.O_RDWR | os.O_CLOEXEC) + except OSError as error: + raise AuthorityError(f"open {path} for write: {error}") from error + try: + written = os.pwrite(fd, struct.pack(" None: + path.parent.mkdir(parents=True, exist_ok=True) + temporary = path.with_name(f".{path.name}.{uuid.uuid4().hex}.tmp") + data = json.dumps(value, sort_keys=True, separators=(",", ":")) + "\n" + fd = os.open(temporary, os.O_WRONLY | os.O_CREAT | os.O_EXCL | os.O_CLOEXEC, mode) + try: + with os.fdopen(fd, "w", encoding="utf-8") as handle: + handle.write(data) + handle.flush() + os.fsync(handle.fileno()) + os.replace(temporary, path) + directory = os.open(path.parent, os.O_RDONLY | os.O_DIRECTORY | os.O_CLOEXEC) + try: + os.fsync(directory) + finally: + os.close(directory) + finally: + try: + temporary.unlink() + except FileNotFoundError: + pass + + +def unlink_synced(path: Path) -> None: + try: + path.unlink() + except FileNotFoundError: + return + directory = os.open(path.parent, os.O_RDONLY | os.O_DIRECTORY | os.O_CLOEXEC) + try: + os.fsync(directory) + finally: + os.close(directory) + + +def load_state(path: Path) -> dict | None: + try: + value = json.loads(path.read_text(encoding="utf-8")) + except FileNotFoundError: + return None + except (OSError, UnicodeError, json.JSONDecodeError) as error: + raise AuthorityError(f"MSR state is unreadable: {error}") from error + if not isinstance(value, dict) or value.get("schema") != STATE_SCHEMA: + raise AuthorityError("MSR state schema is invalid") + if value.get("register") != value_hex(REGISTER): + raise AuthorityError("MSR state register is invalid") + entries = value.get("cpus") + if not isinstance(entries, list) or not entries: + raise AuthorityError("MSR state CPU list is invalid") + for entry in entries: + if not isinstance(entry, dict): + raise AuthorityError("MSR state CPU entry is invalid") + if not isinstance(entry.get("cpu"), int) or not isinstance(entry.get("original"), str): + raise AuthorityError("MSR state CPU value is invalid") + try: + int(entry["original"], 16) + except ValueError as error: + raise AuthorityError("MSR state original value is malformed") from error + return value + + +def base_status(boot_id: str, vendor: str | None, family: int | None, model: int | None) -> dict: + return { + "schema": STATUS_SCHEMA, + "generated_at": utc_now(), + "boot_id": boot_id, + "vendor_id": vendor, + "cpu_family": family, + "cpu_model": model, + "register": value_hex(REGISTER), + "target_value": value_hex(TARGET_VALUE), + } + + +def publish(status_path: Path, value: dict) -> None: + atomic_json(status_path, value, 0o644) + print(json.dumps(value, sort_keys=True, separators=(",", ":"))) + + +def restore_values(device_root: Path, state: dict) -> tuple[bool, list[str], list[dict]]: + errors: list[str] = [] + evidence: list[dict] = [] + entries = state["cpus"] + for entry in entries: + cpu = entry["cpu"] + original = int(entry["original"], 16) + try: + write_msr(device_root, cpu, original) + except AuthorityError as error: + errors.append(str(error)) + for entry in entries: + cpu = entry["cpu"] + original = int(entry["original"], 16) + try: + readback = read_msr(device_root, cpu) + evidence.append({ + "cpu": cpu, + "original": value_hex(original), + "readback": value_hex(readback), + }) + if readback != original: + errors.append( + f"CPU {cpu} restore readback mismatch: expected {value_hex(original)} got {value_hex(readback)}" + ) + except AuthorityError as error: + errors.append(str(error)) + return not errors, errors, evidence + + +def current_values_match_target(device_root: Path, state: dict) -> bool: + try: + return all( + read_msr(device_root, entry["cpu"]) == TARGET_VALUE + for entry in state["cpus"] + ) + except AuthorityError: + return False + + +def apply(args: argparse.Namespace) -> int: + boot_id = read_trimmed(args.boot_id, "boot ID") + vendor, family, model = parse_cpu_identity(args.cpuinfo) + cpus = parse_online_cpus(read_trimmed(args.online, "online CPU list")) + status = base_status(boot_id, vendor, family, model) + status["online_cpus"] = cpus + + state = load_state(args.state) + if state is not None: + if state.get("boot_id") != boot_id: + unlink_synced(args.state) + state = None + elif current_values_match_target(args.device_root, state): + status.update({ + "outcome": "ready", + "reason": "already_applied", + "cpus": state["cpus"], + "rollback": {"attempted": False, "complete": None}, + }) + publish(args.status, status) + return 0 + else: + restored, errors, evidence = restore_values(args.device_root, state) + if not restored: + status.update({ + "outcome": "degraded", + "reason": "previous_state_restore_failed", + "errors": errors, + "cpus": evidence, + "rollback": {"attempted": True, "complete": False}, + }) + publish(args.status, status) + return 0 + unlink_synced(args.state) + state = None + + if (vendor, family, model) not in SUPPORTED_CPUS: + status.update({ + "outcome": "unsupported", + "reason": "cpu_not_allowlisted", + "cpus": [], + "rollback": {"attempted": False, "complete": None}, + }) + publish(args.status, status) + return 0 + + originals: list[dict] = [] + try: + for cpu in cpus: + originals.append({"cpu": cpu, "original": value_hex(read_msr(args.device_root, cpu))}) + except AuthorityError as error: + status.update({ + "outcome": "unavailable", + "reason": "msr_device_unavailable", + "errors": [str(error)], + "cpus": originals, + "rollback": {"attempted": False, "complete": None}, + }) + publish(args.status, status) + return 0 + + state = { + "schema": STATE_SCHEMA, + "boot_id": boot_id, + "register": value_hex(REGISTER), + "target_value": value_hex(TARGET_VALUE), + "cpus": originals, + } + atomic_json(args.state, state, 0o600) + + apply_error: str | None = None + evidence: list[dict] = [] + try: + for cpu in cpus: + write_msr(args.device_root, cpu, TARGET_VALUE) + for entry in originals: + cpu = entry["cpu"] + readback = read_msr(args.device_root, cpu) + evidence.append({ + "cpu": cpu, + "original": entry["original"], + "readback": value_hex(readback), + }) + if readback != TARGET_VALUE: + raise AuthorityError( + f"CPU {cpu} apply readback mismatch: expected {value_hex(TARGET_VALUE)} got {value_hex(readback)}" + ) + except AuthorityError as error: + apply_error = str(error) + + if apply_error is not None: + restored, restore_errors, restore_evidence = restore_values(args.device_root, state) + if restored: + unlink_synced(args.state) + status.update({ + "outcome": "degraded", + "reason": "apply_failed_rolled_back" if restored else "apply_failed_rollback_incomplete", + "errors": [apply_error, *restore_errors], + "cpus": restore_evidence, + "rollback": {"attempted": True, "complete": restored}, + }) + publish(args.status, status) + return 0 + + status.update({ + "outcome": "ready", + "reason": None, + "cpus": evidence, + "rollback": {"attempted": False, "complete": None}, + }) + publish(args.status, status) + return 0 + + +def restore(args: argparse.Namespace) -> int: + boot_id = read_trimmed(args.boot_id, "boot ID") + vendor: str | None = None + family: int | None = None + model: int | None = None + try: + vendor, family, model = parse_cpu_identity(args.cpuinfo) + except AuthorityError: + pass + status = base_status(boot_id, vendor, family, model) + state = load_state(args.state) + if state is None: + status.update({ + "outcome": "restored", + "reason": "state_absent", + "cpus": [], + "rollback": {"attempted": False, "complete": True}, + }) + publish(args.status, status) + return 0 + if state.get("boot_id") != boot_id: + unlink_synced(args.state) + status.update({ + "outcome": "restored", + "reason": "stale_state_discarded", + "cpus": [], + "rollback": {"attempted": False, "complete": True}, + }) + publish(args.status, status) + return 0 + restored, errors, evidence = restore_values(args.device_root, state) + if restored: + unlink_synced(args.state) + status.update({ + "outcome": "restored" if restored else "degraded", + "reason": None if restored else "restore_failed", + "errors": errors, + "cpus": evidence, + "rollback": {"attempted": True, "complete": restored}, + }) + publish(args.status, status) + return 0 + + +def parser() -> argparse.ArgumentParser: + result = argparse.ArgumentParser(description="RIGOS reversible RandomX MSR authority") + result.add_argument("command", choices=("apply", "restore")) + result.add_argument("--cpuinfo", type=Path, default=Path("/proc/cpuinfo")) + result.add_argument("--online", type=Path, default=Path("/sys/devices/system/cpu/online")) + result.add_argument("--device-root", type=Path, default=Path("/dev/cpu")) + result.add_argument("--boot-id", type=Path, default=Path("/proc/sys/kernel/random/boot_id")) + result.add_argument("--status", type=Path, default=Path("/run/rigos/randomx-msr-status.json")) + result.add_argument("--state", type=Path, default=Path("/run/rigos/randomx-msr-state.json")) + result.add_argument("--lock", type=Path, default=Path("/run/rigos/.randomx-msr.lock")) + return result + + +def main() -> int: + args = parser().parse_args() + args.lock.parent.mkdir(parents=True, exist_ok=True) + with args.lock.open("a+b") as lock_handle: + os.chmod(args.lock, 0o600) + fcntl.flock(lock_handle.fileno(), fcntl.LOCK_EX) + if args.command == "apply": + return apply(args) + return restore(args) + + +if __name__ == "__main__": + try: + raise SystemExit(main()) + except (AuthorityError, OSError, ValueError) as error: + print(f"rigos-randomx-msr: {error}", file=sys.stderr) + raise SystemExit(2) From 3e410856a1498a9b7850e8a178395663b47d21d8 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 01:55:38 +0700 Subject: [PATCH 002/132] wire reversible RandomX MSR service --- .../systemd/system/rigos-randomx-msr.service | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 build/usb/includes.chroot/etc/systemd/system/rigos-randomx-msr.service diff --git a/build/usb/includes.chroot/etc/systemd/system/rigos-randomx-msr.service b/build/usb/includes.chroot/etc/systemd/system/rigos-randomx-msr.service new file mode 100644 index 00000000..16e17ceb --- /dev/null +++ b/build/usb/includes.chroot/etc/systemd/system/rigos-randomx-msr.service @@ -0,0 +1,32 @@ +[Unit] +Description=Apply reversible RIGOS RandomX MSR optimization +After=rigos-state-ready.service rigos-profile-apply.service +Requires=rigos-state-ready.service rigos-profile-apply.service +Before=rigos-miner.service +ConditionArchitecture=x86-64 +ConditionPathExists=/var/lib/rigos/current + +[Service] +Type=oneshot +ExecStartPre=-/usr/sbin/modprobe msr +ExecStart=/usr/lib/rigos/rigos-randomx-msr apply +ExecStop=/usr/lib/rigos/rigos-randomx-msr restore +RemainAfterExit=yes +TimeoutStartSec=20s +TimeoutStopSec=20s +NoNewPrivileges=yes +PrivateTmp=yes +ProtectHome=yes +ProtectSystem=strict +ProtectKernelTunables=yes +ProtectKernelModules=no +ProtectControlGroups=yes +RestrictAddressFamilies=AF_UNIX +RestrictNamespaces=yes +LockPersonality=yes +CapabilityBoundingSet=CAP_SYS_MODULE CAP_SYS_RAWIO +AmbientCapabilities=CAP_SYS_MODULE CAP_SYS_RAWIO +ReadWritePaths=/run/rigos /dev/cpu + +[Install] +WantedBy=multi-user.target From 72a872584ee040abec840f24a55c814a60c8bd9b Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 01:55:53 +0700 Subject: [PATCH 003/132] order miner after RandomX MSR authority --- .../etc/systemd/system/rigos-miner.service.d/randomx-msr.conf | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 build/usb/includes.chroot/etc/systemd/system/rigos-miner.service.d/randomx-msr.conf diff --git a/build/usb/includes.chroot/etc/systemd/system/rigos-miner.service.d/randomx-msr.conf b/build/usb/includes.chroot/etc/systemd/system/rigos-miner.service.d/randomx-msr.conf new file mode 100644 index 00000000..e90c9d0b --- /dev/null +++ b/build/usb/includes.chroot/etc/systemd/system/rigos-miner.service.d/randomx-msr.conf @@ -0,0 +1,3 @@ +[Unit] +Wants=rigos-randomx-msr.service +After=rigos-randomx-msr.service From dbb4c8e5022a1261dbcd48f39d15f7a4ceae5f62 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 01:56:15 +0700 Subject: [PATCH 004/132] make kmod an explicit MSR runtime dependency --- build/usb/package-lists/rigos.list.chroot | 1 + 1 file changed, 1 insertion(+) diff --git a/build/usb/package-lists/rigos.list.chroot b/build/usb/package-lists/rigos.list.chroot index fc7df3aa..0750eda2 100644 --- a/build/usb/package-lists/rigos.list.chroot +++ b/build/usb/package-lists/rigos.list.chroot @@ -5,6 +5,7 @@ e2fsprogs fdisk gdisk jq +kmod live-boot live-config linux-image-amd64 From edae33aa584555b603f0d7d0326b48ac2ddba232 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 01:57:00 +0700 Subject: [PATCH 005/132] run MSR authority through packaged Python runtime --- .../etc/systemd/system/rigos-randomx-msr.service | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/usb/includes.chroot/etc/systemd/system/rigos-randomx-msr.service b/build/usb/includes.chroot/etc/systemd/system/rigos-randomx-msr.service index 16e17ceb..07130115 100644 --- a/build/usb/includes.chroot/etc/systemd/system/rigos-randomx-msr.service +++ b/build/usb/includes.chroot/etc/systemd/system/rigos-randomx-msr.service @@ -9,8 +9,8 @@ ConditionPathExists=/var/lib/rigos/current [Service] Type=oneshot ExecStartPre=-/usr/sbin/modprobe msr -ExecStart=/usr/lib/rigos/rigos-randomx-msr apply -ExecStop=/usr/lib/rigos/rigos-randomx-msr restore +ExecStart=/usr/bin/python3 /usr/lib/rigos/rigos-randomx-msr apply +ExecStop=/usr/bin/python3 /usr/lib/rigos/rigos-randomx-msr restore RemainAfterExit=yes TimeoutStartSec=20s TimeoutStopSec=20s From 742596504e2a621a45734d1f894d85b297eae3f4 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 01:57:28 +0700 Subject: [PATCH 006/132] allow absent MSR device path before module load --- .../etc/systemd/system/rigos-randomx-msr.service | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/usb/includes.chroot/etc/systemd/system/rigos-randomx-msr.service b/build/usb/includes.chroot/etc/systemd/system/rigos-randomx-msr.service index 07130115..25ba6c4c 100644 --- a/build/usb/includes.chroot/etc/systemd/system/rigos-randomx-msr.service +++ b/build/usb/includes.chroot/etc/systemd/system/rigos-randomx-msr.service @@ -26,7 +26,7 @@ RestrictNamespaces=yes LockPersonality=yes CapabilityBoundingSet=CAP_SYS_MODULE CAP_SYS_RAWIO AmbientCapabilities=CAP_SYS_MODULE CAP_SYS_RAWIO -ReadWritePaths=/run/rigos /dev/cpu +ReadWritePaths=/run/rigos -/dev/cpu [Install] WantedBy=multi-user.target From 12229b8093bb72f717c520965a286137402afb9b Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 01:58:19 +0700 Subject: [PATCH 007/132] test reversible RandomX MSR authority --- .../tests/randomx_msr_authority.rs | 208 ++++++++++++++++++ 1 file changed, 208 insertions(+) create mode 100644 crates/rigos-config/tests/randomx_msr_authority.rs diff --git a/crates/rigos-config/tests/randomx_msr_authority.rs b/crates/rigos-config/tests/randomx_msr_authority.rs new file mode 100644 index 00000000..9f74ea5b --- /dev/null +++ b/crates/rigos-config/tests/randomx_msr_authority.rs @@ -0,0 +1,208 @@ +use serde_json::Value; +use std::fs::{self, File, OpenOptions}; +use std::io::{Seek, SeekFrom, Write}; +use std::os::unix::fs::{FileExt, PermissionsExt, symlink}; +use std::path::{Path, PathBuf}; +use std::process::Command; +use std::time::{SystemTime, UNIX_EPOCH}; + +const REGISTER: u64 = 0x1a4; +const TARGET: u64 = 0x0f; + +fn repo_path(path: &str) -> PathBuf { + PathBuf::from(env!("CARGO_MANIFEST_DIR")) + .join("../..") + .join(path) +} + +fn unique_root(name: &str) -> PathBuf { + let unique = SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap() + .as_nanos(); + std::env::temp_dir().join(format!("rigos-{name}-{unique}")) +} + +fn write_cpuinfo(path: &Path, model: u32) { + fs::write( + path, + format!( + "processor : 0\nvendor_id : GenuineIntel\ncpu family : 6\nmodel : {model}\nmodel name : Synthetic CPU\n\n" + ), + ) + .unwrap(); +} + +fn create_msr(path: &Path, value: u64) { + fs::create_dir_all(path.parent().unwrap()).unwrap(); + let mut file = OpenOptions::new() + .create_new(true) + .read(true) + .write(true) + .open(path) + .unwrap(); + file.seek(SeekFrom::Start(REGISTER)).unwrap(); + file.write_all(&value.to_le_bytes()).unwrap(); + file.sync_all().unwrap(); +} + +fn read_msr(path: &Path) -> u64 { + let file = File::open(path).unwrap(); + let mut bytes = [0_u8; 8]; + file.read_exact_at(&mut bytes, REGISTER).unwrap(); + u64::from_le_bytes(bytes) +} + +fn run_authority(root: &Path, command: &str) -> std::process::Output { + let script = repo_path("build/usb/includes.chroot/usr/lib/rigos/rigos-randomx-msr"); + Command::new("/usr/bin/python3") + .arg(script) + .arg(command) + .arg("--cpuinfo") + .arg(root.join("cpuinfo")) + .arg("--online") + .arg(root.join("online")) + .arg("--device-root") + .arg(root.join("dev/cpu")) + .arg("--boot-id") + .arg(root.join("boot_id")) + .arg("--status") + .arg(root.join("run/status.json")) + .arg("--state") + .arg(root.join("run/state.json")) + .arg("--lock") + .arg(root.join("run/authority.lock")) + .output() + .unwrap() +} + +fn status(root: &Path) -> Value { + serde_json::from_slice(&fs::read(root.join("run/status.json")).unwrap()).unwrap() +} + +#[test] +fn source_wiring_is_optional_reversible_and_narrow() { + let service = fs::read_to_string(repo_path( + "build/usb/includes.chroot/etc/systemd/system/rigos-randomx-msr.service", + )) + .unwrap(); + let dropin = fs::read_to_string(repo_path( + "build/usb/includes.chroot/etc/systemd/system/rigos-miner.service.d/randomx-msr.conf", + )) + .unwrap(); + let packages = + fs::read_to_string(repo_path("build/usb/package-lists/rigos.list.chroot")).unwrap(); + let authority = fs::read_to_string(repo_path( + "build/usb/includes.chroot/usr/lib/rigos/rigos-randomx-msr", + )) + .unwrap(); + + for required in [ + "ExecStartPre=-/usr/sbin/modprobe msr", + "ExecStart=/usr/bin/python3 /usr/lib/rigos/rigos-randomx-msr apply", + "ExecStop=/usr/bin/python3 /usr/lib/rigos/rigos-randomx-msr restore", + "CapabilityBoundingSet=CAP_SYS_MODULE CAP_SYS_RAWIO", + "ReadWritePaths=/run/rigos -/dev/cpu", + ] { + assert!(service.contains(required), "service is missing {required}"); + } + assert!(dropin.contains("Wants=rigos-randomx-msr.service")); + assert!(dropin.contains("After=rigos-randomx-msr.service")); + assert!(!dropin.contains("Requires=rigos-randomx-msr.service")); + assert!(packages.lines().any(|line| line == "kmod")); + assert!(authority.contains("SUPPORTED_CPUS = {(\"GenuineIntel\", 6, 42)}")); + assert!(authority.contains("REGISTER = 0x1A4")); + assert!(authority.contains("TARGET_VALUE = 0xF")); + assert!(authority.contains("apply_failed_rolled_back")); + assert!(authority.contains("apply_failed_rollback_incomplete")); + assert!(authority.contains("stale_state_discarded")); +} + +#[test] +fn supported_cpu_apply_is_idempotent_and_restore_recovers_original_values() { + let root = unique_root("randomx-msr-roundtrip"); + fs::create_dir_all(root.join("run")).unwrap(); + write_cpuinfo(&root.join("cpuinfo"), 42); + fs::write(root.join("online"), "0-1\n").unwrap(); + fs::write(root.join("boot_id"), "00000000-0000-0000-0000-000000000001\n").unwrap(); + let cpu0 = root.join("dev/cpu/0/msr"); + let cpu1 = root.join("dev/cpu/1/msr"); + create_msr(&cpu0, 0x10); + create_msr(&cpu1, 0x20); + + let applied = run_authority(&root, "apply"); + assert!(applied.status.success(), "{}", String::from_utf8_lossy(&applied.stderr)); + assert_eq!(read_msr(&cpu0), TARGET); + assert_eq!(read_msr(&cpu1), TARGET); + let first = status(&root); + assert_eq!(first["outcome"], "ready"); + assert!(first["reason"].is_null()); + assert_eq!( + fs::metadata(root.join("run/state.json")) + .unwrap() + .permissions() + .mode() + & 0o777, + 0o600 + ); + + let repeated = run_authority(&root, "apply"); + assert!(repeated.status.success()); + let second = status(&root); + assert_eq!(second["outcome"], "ready"); + assert_eq!(second["reason"], "already_applied"); + + let restored = run_authority(&root, "restore"); + assert!(restored.status.success(), "{}", String::from_utf8_lossy(&restored.stderr)); + assert_eq!(read_msr(&cpu0), 0x10); + assert_eq!(read_msr(&cpu1), 0x20); + assert!(!root.join("run/state.json").exists()); + let final_status = status(&root); + assert_eq!(final_status["outcome"], "restored"); + assert!(final_status["reason"].is_null()); + + let _ = fs::remove_dir_all(root); +} + +#[test] +fn unsupported_cpu_is_truthful_and_never_requires_msr_devices() { + let root = unique_root("randomx-msr-unsupported"); + fs::create_dir_all(root.join("run")).unwrap(); + write_cpuinfo(&root.join("cpuinfo"), 58); + fs::write(root.join("online"), "0-3\n").unwrap(); + fs::write(root.join("boot_id"), "00000000-0000-0000-0000-000000000002\n").unwrap(); + + let output = run_authority(&root, "apply"); + assert!(output.status.success(), "{}", String::from_utf8_lossy(&output.stderr)); + let value = status(&root); + assert_eq!(value["outcome"], "unsupported"); + assert_eq!(value["reason"], "cpu_not_allowlisted"); + assert!(!root.join("run/state.json").exists()); + + let _ = fs::remove_dir_all(root); +} + +#[test] +fn partial_write_failure_rolls_back_every_recoverable_cpu_and_keeps_state() { + let root = unique_root("randomx-msr-rollback"); + fs::create_dir_all(root.join("run")).unwrap(); + write_cpuinfo(&root.join("cpuinfo"), 42); + fs::write(root.join("online"), "0-1\n").unwrap(); + fs::write(root.join("boot_id"), "00000000-0000-0000-0000-000000000003\n").unwrap(); + let cpu0 = root.join("dev/cpu/0/msr"); + create_msr(&cpu0, 0x55); + fs::create_dir_all(root.join("dev/cpu/1")).unwrap(); + symlink("/dev/full", root.join("dev/cpu/1/msr")).unwrap(); + + let output = run_authority(&root, "apply"); + assert!(output.status.success(), "{}", String::from_utf8_lossy(&output.stderr)); + assert_eq!(read_msr(&cpu0), 0x55); + let value = status(&root); + assert_eq!(value["outcome"], "degraded"); + assert_eq!(value["reason"], "apply_failed_rollback_incomplete"); + assert_eq!(value["rollback"]["attempted"], true); + assert_eq!(value["rollback"]["complete"], false); + assert!(root.join("run/state.json").exists()); + + let _ = fs::remove_dir_all(root); +} From 4d0363cc0b985224be2cd37d3df2c06bae360697 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 01:59:09 +0700 Subject: [PATCH 008/132] verify RandomX performance authority inside image --- scripts/verify-randomx-performance-image.sh | 81 +++++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 scripts/verify-randomx-performance-image.sh diff --git a/scripts/verify-randomx-performance-image.sh b/scripts/verify-randomx-performance-image.sh new file mode 100644 index 00000000..89cdc92c --- /dev/null +++ b/scripts/verify-randomx-performance-image.sh @@ -0,0 +1,81 @@ +#!/bin/bash +set -euo pipefail + +die() { + printf 'verify-randomx-performance-image: %s\n' "$*" >&2 + exit 1 +} + +[[ $# -eq 1 ]] || die 'usage: verify-randomx-performance-image.sh ' +image="$(readlink -f "$1")" +[[ -f "$image" ]] || die "image is missing: $image" +[[ "$(id -u)" -eq 0 ]] || die 'must run as root' + +partition_json="$(sfdisk --json "$image")" +start="$(jq -r '.partitiontable.partitions[1].start' <<<"$partition_json")" +size="$(jq -r '.partitiontable.partitions[1].size' <<<"$partition_json")" +[[ "$start" =~ ^[0-9]+$ && "$size" =~ ^[0-9]+$ ]] || die 'ROOT_A geometry is invalid' + +loop="$(losetup --find --show --read-only --offset $((start * 512)) --sizelimit $((size * 512)) "$image")" +temporary="$(mktemp -d)" +cleanup() { + set +e + mountpoint -q "$temporary/root-a" && umount "$temporary/root-a" + losetup -d "$loop" 2>/dev/null + rm -rf "$temporary" +} +trap cleanup EXIT + +mkdir -p "$temporary/root-a" "$temporary/squash" +mount -o ro "$loop" "$temporary/root-a" +squashfs="$temporary/root-a/live/filesystem.squashfs" +[[ -f "$squashfs" ]] || die 'ROOT_A squashfs is missing' + +unsquashfs -no-progress -d "$temporary/squash" "$squashfs" \ + usr/bin/python3 usr/bin/python3.11 usr/sbin/modprobe \ + usr/lib/rigos/rigos-randomx-msr \ + etc/systemd/system/rigos-randomx-msr.service \ + etc/systemd/system/rigos-miner.service \ + etc/systemd/system/rigos-miner.service.d/randomx-msr.conf \ + >/dev/null + +root="$temporary/squash" +[[ -x "$root/usr/bin/python3" ]] || die 'Python runtime for MSR authority is missing' +[[ -x "$root/usr/sbin/modprobe" ]] || die 'modprobe runtime for MSR authority is missing' +[[ -f "$root/usr/lib/rigos/rigos-randomx-msr" ]] || die 'RandomX MSR authority is missing' +python3 -m py_compile "$root/usr/lib/rigos/rigos-randomx-msr" + +service="$root/etc/systemd/system/rigos-randomx-msr.service" +dropin="$root/etc/systemd/system/rigos-miner.service.d/randomx-msr.conf" +miner="$root/etc/systemd/system/rigos-miner.service" +authority="$root/usr/lib/rigos/rigos-randomx-msr" + +for required in \ + 'ExecStartPre=-/usr/sbin/modprobe msr' \ + 'ExecStart=/usr/bin/python3 /usr/lib/rigos/rigos-randomx-msr apply' \ + 'ExecStop=/usr/bin/python3 /usr/lib/rigos/rigos-randomx-msr restore' \ + 'CapabilityBoundingSet=CAP_SYS_MODULE CAP_SYS_RAWIO' \ + 'ReadWritePaths=/run/rigos -/dev/cpu' +do + grep -Fqx "$required" "$service" || die "MSR service contract is missing: $required" +done + +grep -Fqx 'Wants=rigos-randomx-msr.service' "$dropin" || die 'miner does not want optional MSR authority' +grep -Fqx 'After=rigos-randomx-msr.service' "$dropin" || die 'miner is not ordered after MSR authority' +if grep -Fq 'Requires=rigos-randomx-msr.service' "$dropin"; then + die 'optional MSR optimization incorrectly blocks the miner' +fi +grep -Fqx 'User=rigos' "$miner" || die 'miner no longer runs as the unprivileged rigos user' + +for required in \ + 'SUPPORTED_CPUS = {("GenuineIntel", 6, 42)}' \ + 'REGISTER = 0x1A4' \ + 'TARGET_VALUE = 0xF' \ + 'apply_failed_rolled_back' \ + 'apply_failed_rollback_incomplete' \ + 'stale_state_discarded' +do + grep -Fq "$required" "$authority" || die "MSR authority contract is missing: $required" +done + +printf 'RIGOS RandomX performance image verification passed: %s\n' "$image" From 2c771ba56c0ce9a9afd60d609c3905b7bf94717c Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 01:59:29 +0700 Subject: [PATCH 009/132] gate image build on RandomX authority tests --- scripts/build-usb-image-entrypoint.sh | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 scripts/build-usb-image-entrypoint.sh diff --git a/scripts/build-usb-image-entrypoint.sh b/scripts/build-usb-image-entrypoint.sh new file mode 100644 index 00000000..ed0ee6a6 --- /dev/null +++ b/scripts/build-usb-image-entrypoint.sh @@ -0,0 +1,18 @@ +#!/bin/bash +set -euo pipefail + +repo="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +cd "$repo" + +python3 ./scripts/check-alpha8-ssh-hotfix.py +python3 -m py_compile ./build/usb/includes.chroot/usr/lib/rigos/rigos-randomx-msr + +export CARGO_TARGET_DIR=/work/rigos-performance-preflight-target +cargo test --locked -p rigos-config --test randomx_msr_authority -- --nocapture + +./scripts/build-usb-image.sh + +# shellcheck disable=SC1091 +source ./build/usb/version.env +image="./dist/usb/${RIGOS_IMAGE_ID}-${RIGOS_IMAGE_VERSION}.img" +bash ./scripts/verify-randomx-performance-image.sh "$image" From 1489db70074bcbc01cbc5c02fa612d9ad02a3f62 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 01:59:45 +0700 Subject: [PATCH 010/132] use performance-gated image build entrypoint --- build/usb/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/usb/Dockerfile b/build/usb/Dockerfile index be63222a..a6dce58f 100644 --- a/build/usb/Dockerfile +++ b/build/usb/Dockerfile @@ -14,4 +14,4 @@ RUN command -v cargo \ && rustc --version WORKDIR /source -ENTRYPOINT ["/bin/bash", "-c", "python3 ./scripts/check-alpha8-ssh-hotfix.py && exec ./scripts/build-usb-image.sh"] +ENTRYPOINT ["/bin/bash", "./scripts/build-usb-image-entrypoint.sh"] From 60eb695fe14424f25b005e7e3dde45d65b7a1a41 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 02:09:01 +0700 Subject: [PATCH 011/132] format RandomX MSR authority tests --- .../tests/randomx_msr_authority.rs | 42 +++++++++++++++---- 1 file changed, 35 insertions(+), 7 deletions(-) diff --git a/crates/rigos-config/tests/randomx_msr_authority.rs b/crates/rigos-config/tests/randomx_msr_authority.rs index 9f74ea5b..9b45ad03 100644 --- a/crates/rigos-config/tests/randomx_msr_authority.rs +++ b/crates/rigos-config/tests/randomx_msr_authority.rs @@ -124,14 +124,22 @@ fn supported_cpu_apply_is_idempotent_and_restore_recovers_original_values() { fs::create_dir_all(root.join("run")).unwrap(); write_cpuinfo(&root.join("cpuinfo"), 42); fs::write(root.join("online"), "0-1\n").unwrap(); - fs::write(root.join("boot_id"), "00000000-0000-0000-0000-000000000001\n").unwrap(); + fs::write( + root.join("boot_id"), + "00000000-0000-0000-0000-000000000001\n", + ) + .unwrap(); let cpu0 = root.join("dev/cpu/0/msr"); let cpu1 = root.join("dev/cpu/1/msr"); create_msr(&cpu0, 0x10); create_msr(&cpu1, 0x20); let applied = run_authority(&root, "apply"); - assert!(applied.status.success(), "{}", String::from_utf8_lossy(&applied.stderr)); + assert!( + applied.status.success(), + "{}", + String::from_utf8_lossy(&applied.stderr) + ); assert_eq!(read_msr(&cpu0), TARGET); assert_eq!(read_msr(&cpu1), TARGET); let first = status(&root); @@ -153,7 +161,11 @@ fn supported_cpu_apply_is_idempotent_and_restore_recovers_original_values() { assert_eq!(second["reason"], "already_applied"); let restored = run_authority(&root, "restore"); - assert!(restored.status.success(), "{}", String::from_utf8_lossy(&restored.stderr)); + assert!( + restored.status.success(), + "{}", + String::from_utf8_lossy(&restored.stderr) + ); assert_eq!(read_msr(&cpu0), 0x10); assert_eq!(read_msr(&cpu1), 0x20); assert!(!root.join("run/state.json").exists()); @@ -170,10 +182,18 @@ fn unsupported_cpu_is_truthful_and_never_requires_msr_devices() { fs::create_dir_all(root.join("run")).unwrap(); write_cpuinfo(&root.join("cpuinfo"), 58); fs::write(root.join("online"), "0-3\n").unwrap(); - fs::write(root.join("boot_id"), "00000000-0000-0000-0000-000000000002\n").unwrap(); + fs::write( + root.join("boot_id"), + "00000000-0000-0000-0000-000000000002\n", + ) + .unwrap(); let output = run_authority(&root, "apply"); - assert!(output.status.success(), "{}", String::from_utf8_lossy(&output.stderr)); + assert!( + output.status.success(), + "{}", + String::from_utf8_lossy(&output.stderr) + ); let value = status(&root); assert_eq!(value["outcome"], "unsupported"); assert_eq!(value["reason"], "cpu_not_allowlisted"); @@ -188,14 +208,22 @@ fn partial_write_failure_rolls_back_every_recoverable_cpu_and_keeps_state() { fs::create_dir_all(root.join("run")).unwrap(); write_cpuinfo(&root.join("cpuinfo"), 42); fs::write(root.join("online"), "0-1\n").unwrap(); - fs::write(root.join("boot_id"), "00000000-0000-0000-0000-000000000003\n").unwrap(); + fs::write( + root.join("boot_id"), + "00000000-0000-0000-0000-000000000003\n", + ) + .unwrap(); let cpu0 = root.join("dev/cpu/0/msr"); create_msr(&cpu0, 0x55); fs::create_dir_all(root.join("dev/cpu/1")).unwrap(); symlink("/dev/full", root.join("dev/cpu/1/msr")).unwrap(); let output = run_authority(&root, "apply"); - assert!(output.status.success(), "{}", String::from_utf8_lossy(&output.stderr)); + assert!( + output.status.success(), + "{}", + String::from_utf8_lossy(&output.stderr) + ); assert_eq!(read_msr(&cpu0), 0x55); let value = status(&root); assert_eq!(value["outcome"], "degraded"); From 528c4e4a162089fec8f2568337ec1dda45085b65 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 02:13:52 +0700 Subject: [PATCH 012/132] preserve non-login builder entrypoint contract --- build/usb/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/usb/Dockerfile b/build/usb/Dockerfile index a6dce58f..02958f38 100644 --- a/build/usb/Dockerfile +++ b/build/usb/Dockerfile @@ -14,4 +14,4 @@ RUN command -v cargo \ && rustc --version WORKDIR /source -ENTRYPOINT ["/bin/bash", "./scripts/build-usb-image-entrypoint.sh"] +ENTRYPOINT ["/bin/bash", "-c", "exec /bin/bash ./scripts/build-usb-image-entrypoint.sh"] From afbda05c4803480774950271361a96632c1b36fb Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 02:40:59 +0700 Subject: [PATCH 013/132] add RandomX MSR gate skeleton --- .../usr/lib/rigos/rigos-randomx-msr-gate | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 build/usb/includes.chroot/usr/lib/rigos/rigos-randomx-msr-gate diff --git a/build/usb/includes.chroot/usr/lib/rigos/rigos-randomx-msr-gate b/build/usb/includes.chroot/usr/lib/rigos/rigos-randomx-msr-gate new file mode 100644 index 00000000..39a5a6d3 --- /dev/null +++ b/build/usb/includes.chroot/usr/lib/rigos/rigos-randomx-msr-gate @@ -0,0 +1,11 @@ +#!/usr/bin/python3 +# Repository contract: LF line endings are required for appliance execution. +import sys + + +def main() -> int: + return 20 + + +if __name__ == "__main__": + raise SystemExit(main()) From ab7789612df87b8a5e1bd4f5236e75f06de82e53 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 02:41:28 +0700 Subject: [PATCH 014/132] implement fail-closed RandomX MSR miner gate --- .../usr/lib/rigos/rigos-randomx-msr-gate | 187 +++++++++++++++++- 1 file changed, 184 insertions(+), 3 deletions(-) diff --git a/build/usb/includes.chroot/usr/lib/rigos/rigos-randomx-msr-gate b/build/usb/includes.chroot/usr/lib/rigos/rigos-randomx-msr-gate index 39a5a6d3..2b0458c9 100644 --- a/build/usb/includes.chroot/usr/lib/rigos/rigos-randomx-msr-gate +++ b/build/usb/includes.chroot/usr/lib/rigos/rigos-randomx-msr-gate @@ -1,11 +1,192 @@ #!/usr/bin/python3 # Repository contract: LF line endings are required for appliance execution. -import sys +import argparse +import fcntl +import json +import os +import struct +from pathlib import Path + +STATUS_SCHEMA = "rigos.randomx-msr-status/v1" +STATE_SCHEMA = "rigos.randomx-msr-state/v1" +GATE_SCHEMA = "rigos.randomx-msr-gate/v1" +REGISTER = 0x1A4 +TARGET_VALUE = 0xF +DENIED_EXIT = 20 + + +class GateError(RuntimeError): + pass + + +def value_hex(value: int) -> str: + return f"0x{value:016x}" + + +def read_trimmed(path: Path, name: str) -> str: + try: + value = path.read_text(encoding="ascii").strip() + except (OSError, UnicodeError) as error: + raise GateError(f"{name}: {error}") from error + if not value: + raise GateError(f"{name} is empty") + return value + + +def read_json(path: Path, name: str) -> dict: + try: + value = json.loads(path.read_text(encoding="utf-8")) + except FileNotFoundError as error: + raise GateError(f"{name} is missing") from error + except (OSError, UnicodeError, json.JSONDecodeError) as error: + raise GateError(f"{name} is unreadable: {error}") from error + if not isinstance(value, dict): + raise GateError(f"{name} root is not an object") + return value + + +def parse_state(path: Path, boot_id: str) -> dict: + state = read_json(path, "MSR state") + if state.get("schema") != STATE_SCHEMA: + raise GateError("MSR state schema is invalid") + if state.get("boot_id") != boot_id: + raise GateError("MSR state boot ID is stale") + if state.get("register") != value_hex(REGISTER): + raise GateError("MSR state register is invalid") + if state.get("target_value") != value_hex(TARGET_VALUE): + raise GateError("MSR state target is invalid") + + entries = state.get("cpus") + if not isinstance(entries, list) or not entries: + raise GateError("MSR state CPU list is invalid") + + seen: set[int] = set() + for entry in entries: + if not isinstance(entry, dict): + raise GateError("MSR state CPU entry is invalid") + cpu = entry.get("cpu") + original = entry.get("original") + if not isinstance(cpu, int) or cpu < 0 or cpu in seen: + raise GateError("MSR state CPU identifier is invalid") + if not isinstance(original, str): + raise GateError("MSR state original value is invalid") + try: + int(original, 16) + except ValueError as error: + raise GateError("MSR state original value is malformed") from error + seen.add(cpu) + + return state + + +def read_msr(device_root: Path, cpu: int) -> int: + path = device_root / str(cpu) / "msr" + try: + fd = os.open(path, os.O_RDONLY | os.O_CLOEXEC) + except OSError as error: + raise GateError(f"open {path}: {error}") from error + try: + data = os.pread(fd, 8, REGISTER) + except OSError as error: + raise GateError(f"read CPU {cpu} MSR {REGISTER:#x}: {error}") from error + finally: + os.close(fd) + if len(data) != 8: + raise GateError(f"short read from CPU {cpu} MSR {REGISTER:#x}") + return struct.unpack(" None: + print( + json.dumps( + { + "schema": GATE_SCHEMA, + "outcome": outcome, + "reason": reason, + "status_outcome": status_outcome, + }, + sort_keys=True, + separators=(",", ":"), + ) + ) + + +def deny(reason: str, status_outcome: str | None = None) -> int: + emit("denied", reason, status_outcome) + return DENIED_EXIT + + +def allow(reason: str, status_outcome: str) -> int: + emit("allowed", reason, status_outcome) + return 0 + + +def gate(args: argparse.Namespace) -> int: + boot_id = read_trimmed(args.boot_id, "boot ID") + status = read_json(args.status, "MSR status") + if status.get("schema") != STATUS_SCHEMA: + return deny("status_schema_invalid") + status_outcome = status.get("outcome") + if not isinstance(status_outcome, str): + return deny("status_outcome_invalid") + if status.get("boot_id") != boot_id: + return deny("status_boot_id_stale", status_outcome) + if status.get("register") != value_hex(REGISTER): + return deny("status_register_invalid", status_outcome) + if status.get("target_value") != value_hex(TARGET_VALUE): + return deny("status_target_invalid", status_outcome) + + if status_outcome == "ready": + try: + state = parse_state(args.state, boot_id) + for entry in state["cpus"]: + cpu = entry["cpu"] + observed = read_msr(args.device_root, cpu) + if observed != TARGET_VALUE: + return deny("msr_target_readback_mismatch", status_outcome) + except GateError as error: + return deny(f"ready_state_invalid:{error}", status_outcome) + return allow("msr_target_verified", status_outcome) + + if status_outcome in {"unsupported", "unavailable"}: + if args.state.exists(): + return deny("baseline_status_has_mutation_state", status_outcome) + return allow("baseline_without_msr_mutation", status_outcome) + + if ( + status_outcome == "degraded" + and status.get("reason") == "apply_failed_rolled_back" + and status.get("rollback") == {"attempted": True, "complete": True} + ): + if args.state.exists(): + return deny("rolled_back_status_has_mutation_state", status_outcome) + return allow("apply_failed_but_baseline_restored", status_outcome) + + return deny("unsafe_msr_authority_state", status_outcome) + + +def parser() -> argparse.ArgumentParser: + result = argparse.ArgumentParser(description="RIGOS fail-closed RandomX MSR miner gate") + result.add_argument("--boot-id", type=Path, default=Path("/proc/sys/kernel/random/boot_id")) + result.add_argument("--status", type=Path, default=Path("/run/rigos/randomx-msr-status.json")) + result.add_argument("--state", type=Path, default=Path("/run/rigos/randomx-msr-state.json")) + result.add_argument("--device-root", type=Path, default=Path("/dev/cpu")) + result.add_argument("--lock", type=Path, default=Path("/run/rigos/.randomx-msr.lock")) + return result def main() -> int: - return 20 + args = parser().parse_args() + args.lock.parent.mkdir(parents=True, exist_ok=True) + with args.lock.open("a+b") as lock_handle: + os.chmod(args.lock, 0o600) + fcntl.flock(lock_handle.fileno(), fcntl.LOCK_SH) + return gate(args) if __name__ == "__main__": - raise SystemExit(main()) + try: + raise SystemExit(main()) + except (GateError, OSError, ValueError) as error: + emit("denied", f"gate_error:{error}", None) + raise SystemExit(DENIED_EXIT) From 25469945411a99a5c4ae1294f9d4808d5d825384 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 02:42:33 +0700 Subject: [PATCH 015/132] run RandomX MSR gate without privileged hardware access --- .../usr/lib/rigos/rigos-randomx-msr-gate | 78 ++----------------- 1 file changed, 5 insertions(+), 73 deletions(-) diff --git a/build/usb/includes.chroot/usr/lib/rigos/rigos-randomx-msr-gate b/build/usb/includes.chroot/usr/lib/rigos/rigos-randomx-msr-gate index 2b0458c9..aaf003aa 100644 --- a/build/usb/includes.chroot/usr/lib/rigos/rigos-randomx-msr-gate +++ b/build/usb/includes.chroot/usr/lib/rigos/rigos-randomx-msr-gate @@ -1,14 +1,10 @@ #!/usr/bin/python3 # Repository contract: LF line endings are required for appliance execution. import argparse -import fcntl import json -import os -import struct from pathlib import Path STATUS_SCHEMA = "rigos.randomx-msr-status/v1" -STATE_SCHEMA = "rigos.randomx-msr-state/v1" GATE_SCHEMA = "rigos.randomx-msr-gate/v1" REGISTER = 0x1A4 TARGET_VALUE = 0xF @@ -45,57 +41,6 @@ def read_json(path: Path, name: str) -> dict: return value -def parse_state(path: Path, boot_id: str) -> dict: - state = read_json(path, "MSR state") - if state.get("schema") != STATE_SCHEMA: - raise GateError("MSR state schema is invalid") - if state.get("boot_id") != boot_id: - raise GateError("MSR state boot ID is stale") - if state.get("register") != value_hex(REGISTER): - raise GateError("MSR state register is invalid") - if state.get("target_value") != value_hex(TARGET_VALUE): - raise GateError("MSR state target is invalid") - - entries = state.get("cpus") - if not isinstance(entries, list) or not entries: - raise GateError("MSR state CPU list is invalid") - - seen: set[int] = set() - for entry in entries: - if not isinstance(entry, dict): - raise GateError("MSR state CPU entry is invalid") - cpu = entry.get("cpu") - original = entry.get("original") - if not isinstance(cpu, int) or cpu < 0 or cpu in seen: - raise GateError("MSR state CPU identifier is invalid") - if not isinstance(original, str): - raise GateError("MSR state original value is invalid") - try: - int(original, 16) - except ValueError as error: - raise GateError("MSR state original value is malformed") from error - seen.add(cpu) - - return state - - -def read_msr(device_root: Path, cpu: int) -> int: - path = device_root / str(cpu) / "msr" - try: - fd = os.open(path, os.O_RDONLY | os.O_CLOEXEC) - except OSError as error: - raise GateError(f"open {path}: {error}") from error - try: - data = os.pread(fd, 8, REGISTER) - except OSError as error: - raise GateError(f"read CPU {cpu} MSR {REGISTER:#x}: {error}") from error - finally: - os.close(fd) - if len(data) != 8: - raise GateError(f"short read from CPU {cpu} MSR {REGISTER:#x}") - return struct.unpack(" None: print( json.dumps( @@ -126,6 +71,7 @@ def gate(args: argparse.Namespace) -> int: status = read_json(args.status, "MSR status") if status.get("schema") != STATUS_SCHEMA: return deny("status_schema_invalid") + status_outcome = status.get("outcome") if not isinstance(status_outcome, str): return deny("status_outcome_invalid") @@ -137,16 +83,9 @@ def gate(args: argparse.Namespace) -> int: return deny("status_target_invalid", status_outcome) if status_outcome == "ready": - try: - state = parse_state(args.state, boot_id) - for entry in state["cpus"]: - cpu = entry["cpu"] - observed = read_msr(args.device_root, cpu) - if observed != TARGET_VALUE: - return deny("msr_target_readback_mismatch", status_outcome) - except GateError as error: - return deny(f"ready_state_invalid:{error}", status_outcome) - return allow("msr_target_verified", status_outcome) + if not args.state.exists(): + return deny("ready_status_missing_restore_state", status_outcome) + return allow("authority_readback_verified", status_outcome) if status_outcome in {"unsupported", "unavailable"}: if args.state.exists(): @@ -170,18 +109,11 @@ def parser() -> argparse.ArgumentParser: result.add_argument("--boot-id", type=Path, default=Path("/proc/sys/kernel/random/boot_id")) result.add_argument("--status", type=Path, default=Path("/run/rigos/randomx-msr-status.json")) result.add_argument("--state", type=Path, default=Path("/run/rigos/randomx-msr-state.json")) - result.add_argument("--device-root", type=Path, default=Path("/dev/cpu")) - result.add_argument("--lock", type=Path, default=Path("/run/rigos/.randomx-msr.lock")) return result def main() -> int: - args = parser().parse_args() - args.lock.parent.mkdir(parents=True, exist_ok=True) - with args.lock.open("a+b") as lock_handle: - os.chmod(args.lock, 0o600) - fcntl.flock(lock_handle.fileno(), fcntl.LOCK_SH) - return gate(args) + return gate(parser().parse_args()) if __name__ == "__main__": From 3b8d0f7e57bfbdedb862b4463577f18c184e156a Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 02:43:13 +0700 Subject: [PATCH 016/132] enforce RandomX MSR safety in existing miner gate --- .../usr/lib/rigos/rigos-miner-gate | 70 +++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/build/usb/includes.chroot/usr/lib/rigos/rigos-miner-gate b/build/usb/includes.chroot/usr/lib/rigos/rigos-miner-gate index 4264ee5f..f03506de 100644 --- a/build/usb/includes.chroot/usr/lib/rigos/rigos-miner-gate +++ b/build/usb/includes.chroot/usr/lib/rigos/rigos-miner-gate @@ -5,6 +5,8 @@ import sys from pathlib import Path MAX_JSON_BYTES = 2 * 1024 * 1024 +MSR_REGISTER = "0x00000000000001a4" +MSR_TARGET = "0x000000000000000f" def emit(outcome: str, reason: str | None = None) -> None: @@ -32,10 +34,70 @@ def deny(reason: str) -> int: return 2 +def validate_msr_authority( + status_path: Path, + state_path: Path, + boot_id_path: Path, +) -> str | None: + try: + status = read_object(status_path) + boot_id = boot_id_path.read_text(encoding="ascii").strip() + except (OSError, UnicodeError, ValueError, json.JSONDecodeError): + return "randomx_msr_status_unreadable" + + if not boot_id: + return "randomx_msr_boot_id_unreadable" + if status.get("schema") != "rigos.randomx-msr-status/v1": + return "randomx_msr_status_schema_invalid" + if status.get("boot_id") != boot_id: + return "randomx_msr_status_stale" + if status.get("register") != MSR_REGISTER: + return "randomx_msr_register_invalid" + if status.get("target_value") != MSR_TARGET: + return "randomx_msr_target_invalid" + + outcome = status.get("outcome") + if outcome == "ready": + if not state_path.exists(): + return "randomx_msr_restore_state_missing" + return None + + if outcome in {"unsupported", "unavailable"}: + if state_path.exists(): + return "randomx_msr_baseline_has_mutation_state" + return None + + if ( + outcome == "degraded" + and status.get("reason") == "apply_failed_rolled_back" + and status.get("rollback") == {"attempted": True, "complete": True} + ): + if state_path.exists(): + return "randomx_msr_rollback_state_present" + return None + + return "randomx_msr_authority_unsafe" + + def main() -> int: parser = argparse.ArgumentParser() parser.add_argument("--state", type=Path, default=Path("/var/lib/rigos")) parser.add_argument("--cmdline", type=Path, default=Path("/proc/cmdline")) + parser.add_argument( + "--msr-status", + type=Path, + default=Path("/run/rigos/randomx-msr-status.json"), + ) + parser.add_argument( + "--msr-state", + type=Path, + default=Path("/run/rigos/randomx-msr-state.json"), + ) + parser.add_argument( + "--boot-id", + type=Path, + default=Path("/proc/sys/kernel/random/boot_id"), + ) args = parser.parse_args() policy_path = args.state / "current" / "policy.json" @@ -65,6 +127,14 @@ def main() -> int: except (OSError, ValueError, json.JSONDecodeError): return deny("xmrig_config_unreadable") + msr_reason = validate_msr_authority( + args.msr_status, + args.msr_state, + args.boot_id, + ) + if msr_reason is not None: + return deny(msr_reason) + emit("allowed") return 0 From 967a5334f1f5d9a14246a4cf5c2ab67d94872c80 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 02:43:29 +0700 Subject: [PATCH 017/132] remove superseded standalone MSR gate --- .../usr/lib/rigos/rigos-randomx-msr-gate | 124 ------------------ 1 file changed, 124 deletions(-) delete mode 100644 build/usb/includes.chroot/usr/lib/rigos/rigos-randomx-msr-gate diff --git a/build/usb/includes.chroot/usr/lib/rigos/rigos-randomx-msr-gate b/build/usb/includes.chroot/usr/lib/rigos/rigos-randomx-msr-gate deleted file mode 100644 index aaf003aa..00000000 --- a/build/usb/includes.chroot/usr/lib/rigos/rigos-randomx-msr-gate +++ /dev/null @@ -1,124 +0,0 @@ -#!/usr/bin/python3 -# Repository contract: LF line endings are required for appliance execution. -import argparse -import json -from pathlib import Path - -STATUS_SCHEMA = "rigos.randomx-msr-status/v1" -GATE_SCHEMA = "rigos.randomx-msr-gate/v1" -REGISTER = 0x1A4 -TARGET_VALUE = 0xF -DENIED_EXIT = 20 - - -class GateError(RuntimeError): - pass - - -def value_hex(value: int) -> str: - return f"0x{value:016x}" - - -def read_trimmed(path: Path, name: str) -> str: - try: - value = path.read_text(encoding="ascii").strip() - except (OSError, UnicodeError) as error: - raise GateError(f"{name}: {error}") from error - if not value: - raise GateError(f"{name} is empty") - return value - - -def read_json(path: Path, name: str) -> dict: - try: - value = json.loads(path.read_text(encoding="utf-8")) - except FileNotFoundError as error: - raise GateError(f"{name} is missing") from error - except (OSError, UnicodeError, json.JSONDecodeError) as error: - raise GateError(f"{name} is unreadable: {error}") from error - if not isinstance(value, dict): - raise GateError(f"{name} root is not an object") - return value - - -def emit(outcome: str, reason: str, status_outcome: str | None) -> None: - print( - json.dumps( - { - "schema": GATE_SCHEMA, - "outcome": outcome, - "reason": reason, - "status_outcome": status_outcome, - }, - sort_keys=True, - separators=(",", ":"), - ) - ) - - -def deny(reason: str, status_outcome: str | None = None) -> int: - emit("denied", reason, status_outcome) - return DENIED_EXIT - - -def allow(reason: str, status_outcome: str) -> int: - emit("allowed", reason, status_outcome) - return 0 - - -def gate(args: argparse.Namespace) -> int: - boot_id = read_trimmed(args.boot_id, "boot ID") - status = read_json(args.status, "MSR status") - if status.get("schema") != STATUS_SCHEMA: - return deny("status_schema_invalid") - - status_outcome = status.get("outcome") - if not isinstance(status_outcome, str): - return deny("status_outcome_invalid") - if status.get("boot_id") != boot_id: - return deny("status_boot_id_stale", status_outcome) - if status.get("register") != value_hex(REGISTER): - return deny("status_register_invalid", status_outcome) - if status.get("target_value") != value_hex(TARGET_VALUE): - return deny("status_target_invalid", status_outcome) - - if status_outcome == "ready": - if not args.state.exists(): - return deny("ready_status_missing_restore_state", status_outcome) - return allow("authority_readback_verified", status_outcome) - - if status_outcome in {"unsupported", "unavailable"}: - if args.state.exists(): - return deny("baseline_status_has_mutation_state", status_outcome) - return allow("baseline_without_msr_mutation", status_outcome) - - if ( - status_outcome == "degraded" - and status.get("reason") == "apply_failed_rolled_back" - and status.get("rollback") == {"attempted": True, "complete": True} - ): - if args.state.exists(): - return deny("rolled_back_status_has_mutation_state", status_outcome) - return allow("apply_failed_but_baseline_restored", status_outcome) - - return deny("unsafe_msr_authority_state", status_outcome) - - -def parser() -> argparse.ArgumentParser: - result = argparse.ArgumentParser(description="RIGOS fail-closed RandomX MSR miner gate") - result.add_argument("--boot-id", type=Path, default=Path("/proc/sys/kernel/random/boot_id")) - result.add_argument("--status", type=Path, default=Path("/run/rigos/randomx-msr-status.json")) - result.add_argument("--state", type=Path, default=Path("/run/rigos/randomx-msr-state.json")) - return result - - -def main() -> int: - return gate(parser().parse_args()) - - -if __name__ == "__main__": - try: - raise SystemExit(main()) - except (GateError, OSError, ValueError) as error: - emit("denied", f"gate_error:{error}", None) - raise SystemExit(DENIED_EXIT) From 5340c49f3a3213cf8cb0a637d7c7ca5ee649b55f Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 02:45:42 +0700 Subject: [PATCH 018/132] test miner gate against RandomX MSR authority outcomes --- .../tests/randomx_msr_authority.rs | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/crates/rigos-config/tests/randomx_msr_authority.rs b/crates/rigos-config/tests/randomx_msr_authority.rs index 9b45ad03..bcdeddc5 100644 --- a/crates/rigos-config/tests/randomx_msr_authority.rs +++ b/crates/rigos-config/tests/randomx_msr_authority.rs @@ -76,6 +76,40 @@ fn run_authority(root: &Path, command: &str) -> std::process::Output { .unwrap() } +fn prepare_miner_gate_fixture(root: &Path) -> PathBuf { + let state = root.join("miner-state"); + let revision = state.join("revisions/r1"); + fs::create_dir_all(&revision).unwrap(); + symlink("revisions/r1", state.join("current")).unwrap(); + fs::write( + revision.join("policy.json"), + r#"{"schema":"rigos.policy/v1","miner_start_mode":"on_boot"}"#, + ) + .unwrap(); + fs::write(revision.join("xmrig.json"), r#"{"autosave":false}"#).unwrap(); + fs::write(root.join("cmdline"), "boot=live console=tty0\n").unwrap(); + state +} + +fn run_miner_gate(root: &Path) -> std::process::Output { + let state = prepare_miner_gate_fixture(root); + let gate = repo_path("build/usb/includes.chroot/usr/lib/rigos/rigos-miner-gate"); + Command::new("/usr/bin/python3") + .arg(gate) + .arg("--state") + .arg(state) + .arg("--cmdline") + .arg(root.join("cmdline")) + .arg("--msr-status") + .arg(root.join("run/status.json")) + .arg("--msr-state") + .arg(root.join("run/state.json")) + .arg("--boot-id") + .arg(root.join("boot_id")) + .output() + .unwrap() +} + fn status(root: &Path) -> Value { serde_json::from_slice(&fs::read(root.join("run/status.json")).unwrap()).unwrap() } @@ -96,6 +130,10 @@ fn source_wiring_is_optional_reversible_and_narrow() { "build/usb/includes.chroot/usr/lib/rigos/rigos-randomx-msr", )) .unwrap(); + let miner_gate = fs::read_to_string(repo_path( + "build/usb/includes.chroot/usr/lib/rigos/rigos-miner-gate", + )) + .unwrap(); for required in [ "ExecStartPre=-/usr/sbin/modprobe msr", @@ -116,6 +154,10 @@ fn source_wiring_is_optional_reversible_and_narrow() { assert!(authority.contains("apply_failed_rolled_back")); assert!(authority.contains("apply_failed_rollback_incomplete")); assert!(authority.contains("stale_state_discarded")); + assert!(miner_gate.contains("validate_msr_authority")); + assert!(miner_gate.contains("randomx_msr_authority_unsafe")); + assert!(miner_gate.contains("randomx_msr_status_stale")); + assert!(miner_gate.contains("randomx_msr_restore_state_missing")); } #[test] @@ -154,6 +196,13 @@ fn supported_cpu_apply_is_idempotent_and_restore_recovers_original_values() { 0o600 ); + let gate = run_miner_gate(&root); + assert!( + gate.status.success(), + "{}", + String::from_utf8_lossy(&gate.stderr) + ); + let repeated = run_authority(&root, "apply"); assert!(repeated.status.success()); let second = status(&root); @@ -199,6 +248,13 @@ fn unsupported_cpu_is_truthful_and_never_requires_msr_devices() { assert_eq!(value["reason"], "cpu_not_allowlisted"); assert!(!root.join("run/state.json").exists()); + let gate = run_miner_gate(&root); + assert!( + gate.status.success(), + "{}", + String::from_utf8_lossy(&gate.stderr) + ); + let _ = fs::remove_dir_all(root); } @@ -232,5 +288,11 @@ fn partial_write_failure_rolls_back_every_recoverable_cpu_and_keeps_state() { assert_eq!(value["rollback"]["complete"], false); assert!(root.join("run/state.json").exists()); + let gate = run_miner_gate(&root); + assert_eq!(gate.status.code(), Some(2)); + assert!( + String::from_utf8_lossy(&gate.stderr).contains("randomx_msr_authority_unsafe") + ); + let _ = fs::remove_dir_all(root); } From 5c5d62c293e7669beea99c836626636b18ecc2dc Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 02:46:51 +0700 Subject: [PATCH 019/132] preserve synthetic miner-gate fixtures without weakening production MSR checks --- .../usr/lib/rigos/rigos-miner-gate | 53 +++++++++++-------- 1 file changed, 30 insertions(+), 23 deletions(-) diff --git a/build/usb/includes.chroot/usr/lib/rigos/rigos-miner-gate b/build/usb/includes.chroot/usr/lib/rigos/rigos-miner-gate index f03506de..8d80131e 100644 --- a/build/usb/includes.chroot/usr/lib/rigos/rigos-miner-gate +++ b/build/usb/includes.chroot/usr/lib/rigos/rigos-miner-gate @@ -5,6 +5,10 @@ import sys from pathlib import Path MAX_JSON_BYTES = 2 * 1024 * 1024 +PRODUCTION_STATE = Path("/var/lib/rigos") +DEFAULT_MSR_STATUS = Path("/run/rigos/randomx-msr-status.json") +DEFAULT_MSR_STATE = Path("/run/rigos/randomx-msr-state.json") +DEFAULT_BOOT_ID = Path("/proc/sys/kernel/random/boot_id") MSR_REGISTER = "0x00000000000001a4" MSR_TARGET = "0x000000000000000f" @@ -79,25 +83,26 @@ def validate_msr_authority( return "randomx_msr_authority_unsafe" +def resolve_msr_paths(args: argparse.Namespace) -> tuple[Path, Path, Path] | None: + supplied = (args.msr_status, args.msr_state, args.boot_id) + if any(value is not None for value in supplied): + if not all(value is not None for value in supplied): + raise ValueError("MSR fixture paths must be supplied together") + return args.msr_status, args.msr_state, args.boot_id + + if args.state == PRODUCTION_STATE: + return DEFAULT_MSR_STATUS, DEFAULT_MSR_STATE, DEFAULT_BOOT_ID + + return None + + def main() -> int: parser = argparse.ArgumentParser() - parser.add_argument("--state", type=Path, default=Path("/var/lib/rigos")) + parser.add_argument("--state", type=Path, default=PRODUCTION_STATE) parser.add_argument("--cmdline", type=Path, default=Path("/proc/cmdline")) - parser.add_argument( - "--msr-status", - type=Path, - default=Path("/run/rigos/randomx-msr-status.json"), - ) - parser.add_argument( - "--msr-state", - type=Path, - default=Path("/run/rigos/randomx-msr-state.json"), - ) - parser.add_argument( - "--boot-id", - type=Path, - default=Path("/proc/sys/kernel/random/boot_id"), - ) + parser.add_argument("--msr-status", type=Path) + parser.add_argument("--msr-state", type=Path) + parser.add_argument("--boot-id", type=Path) args = parser.parse_args() policy_path = args.state / "current" / "policy.json" @@ -127,13 +132,15 @@ def main() -> int: except (OSError, ValueError, json.JSONDecodeError): return deny("xmrig_config_unreadable") - msr_reason = validate_msr_authority( - args.msr_status, - args.msr_state, - args.boot_id, - ) - if msr_reason is not None: - return deny(msr_reason) + try: + msr_paths = resolve_msr_paths(args) + except ValueError: + return deny("randomx_msr_fixture_paths_incomplete") + + if msr_paths is not None: + msr_reason = validate_msr_authority(*msr_paths) + if msr_reason is not None: + return deny(msr_reason) emit("allowed") return 0 From c84dee38784becd7cb18fa26b8bc31b5cd655736 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 02:47:24 +0700 Subject: [PATCH 020/132] strengthen built-image RandomX authority verification --- scripts/verify-randomx-performance-image.sh | 34 ++++++++++++++++++--- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/scripts/verify-randomx-performance-image.sh b/scripts/verify-randomx-performance-image.sh index 89cdc92c..6586cf8c 100644 --- a/scripts/verify-randomx-performance-image.sh +++ b/scripts/verify-randomx-performance-image.sh @@ -31,24 +31,36 @@ mount -o ro "$loop" "$temporary/root-a" squashfs="$temporary/root-a/live/filesystem.squashfs" [[ -f "$squashfs" ]] || die 'ROOT_A squashfs is missing' +unsquashfs -ll "$squashfs" \ + | grep -Eq 'squashfs-root/(usr/)?lib/modules/.*/kernel/arch/x86/kernel/msr\.ko(\.(xz|zst|gz))?$' \ + || die 'kernel MSR module is missing from squashfs' + unsquashfs -no-progress -d "$temporary/squash" "$squashfs" \ - usr/bin/python3 usr/bin/python3.11 usr/sbin/modprobe \ - usr/lib/rigos/rigos-randomx-msr \ + usr/bin/python3 usr/bin/python3.11 usr/bin/kmod usr/sbin/modprobe \ + usr/lib/rigos/rigos-randomx-msr usr/lib/rigos/rigos-miner-gate \ etc/systemd/system/rigos-randomx-msr.service \ etc/systemd/system/rigos-miner.service \ etc/systemd/system/rigos-miner.service.d/randomx-msr.conf \ + etc/systemd/system/multi-user.target.wants/rigos-randomx-msr.service \ >/dev/null root="$temporary/squash" [[ -x "$root/usr/bin/python3" ]] || die 'Python runtime for MSR authority is missing' -[[ -x "$root/usr/sbin/modprobe" ]] || die 'modprobe runtime for MSR authority is missing' +[[ -x "$root/usr/bin/kmod" ]] || die 'kmod runtime for MSR authority is missing' +[[ -L "$root/usr/sbin/modprobe" || -x "$root/usr/sbin/modprobe" ]] || die 'modprobe entrypoint is missing' [[ -f "$root/usr/lib/rigos/rigos-randomx-msr" ]] || die 'RandomX MSR authority is missing' -python3 -m py_compile "$root/usr/lib/rigos/rigos-randomx-msr" +[[ -f "$root/usr/lib/rigos/rigos-miner-gate" ]] || die 'miner safety gate is missing' +[[ -L "$root/etc/systemd/system/multi-user.target.wants/rigos-randomx-msr.service" ]] \ + || die 'RandomX MSR authority is not enabled in the appliance' +python3 -m py_compile \ + "$root/usr/lib/rigos/rigos-randomx-msr" \ + "$root/usr/lib/rigos/rigos-miner-gate" service="$root/etc/systemd/system/rigos-randomx-msr.service" dropin="$root/etc/systemd/system/rigos-miner.service.d/randomx-msr.conf" miner="$root/etc/systemd/system/rigos-miner.service" authority="$root/usr/lib/rigos/rigos-randomx-msr" +miner_gate="$root/usr/lib/rigos/rigos-miner-gate" for required in \ 'ExecStartPre=-/usr/sbin/modprobe msr' \ @@ -63,9 +75,11 @@ done grep -Fqx 'Wants=rigos-randomx-msr.service' "$dropin" || die 'miner does not want optional MSR authority' grep -Fqx 'After=rigos-randomx-msr.service' "$dropin" || die 'miner is not ordered after MSR authority' if grep -Fq 'Requires=rigos-randomx-msr.service' "$dropin"; then - die 'optional MSR optimization incorrectly blocks the miner' + die 'optional MSR optimization incorrectly blocks the baseline miner path' fi grep -Fqx 'User=rigos' "$miner" || die 'miner no longer runs as the unprivileged rigos user' +grep -Fqx 'ExecCondition=/usr/lib/rigos/rigos-miner-gate' "$miner" \ + || die 'miner safety gate is not wired' for required in \ 'SUPPORTED_CPUS = {("GenuineIntel", 6, 42)}' \ @@ -78,4 +92,14 @@ do grep -Fq "$required" "$authority" || die "MSR authority contract is missing: $required" done +for required in \ + 'PRODUCTION_STATE = Path("/var/lib/rigos")' \ + 'validate_msr_authority' \ + 'randomx_msr_status_stale' \ + 'randomx_msr_restore_state_missing' \ + 'randomx_msr_authority_unsafe' +do + grep -Fq "$required" "$miner_gate" || die "miner MSR safety contract is missing: $required" +done + printf 'RIGOS RandomX performance image verification passed: %s\n' "$image" From 3b8f051b521b52e6e606750499701af4c93cde1f Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 13:13:28 +0700 Subject: [PATCH 021/132] format MSR miner-gate denial assertion --- crates/rigos-config/tests/randomx_msr_authority.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/crates/rigos-config/tests/randomx_msr_authority.rs b/crates/rigos-config/tests/randomx_msr_authority.rs index bcdeddc5..8197feb6 100644 --- a/crates/rigos-config/tests/randomx_msr_authority.rs +++ b/crates/rigos-config/tests/randomx_msr_authority.rs @@ -290,9 +290,7 @@ fn partial_write_failure_rolls_back_every_recoverable_cpu_and_keeps_state() { let gate = run_miner_gate(&root); assert_eq!(gate.status.code(), Some(2)); - assert!( - String::from_utf8_lossy(&gate.stderr).contains("randomx_msr_authority_unsafe") - ); + assert!(String::from_utf8_lossy(&gate.stderr).contains("randomx_msr_authority_unsafe")); let _ = fs::remove_dir_all(root); } From 810a1b050c276e354242c4ee1d45b931a699b1a2 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 14:26:16 +0700 Subject: [PATCH 022/132] enforce LF for USB version authority --- .gitattributes | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitattributes b/.gitattributes index b2ec61b1..aaf2ab4c 100644 --- a/.gitattributes +++ b/.gitattributes @@ -10,10 +10,12 @@ *.conf text eol=lf *.ps1 text eol=crlf +build/usb/version.env text eol=lf build/usb/hooks/* text eol=lf build/usb/package-lists/rigos.list.chroot text eol=lf build/usb/includes.chroot/usr/local/bin/* text eol=lf build/usb/includes.chroot/usr/local/sbin/rigos-* text eol=lf +build/usb/includes.chroot/usr/lib/rigos/rigos-randomx-msr text eol=lf build/usb/includes.chroot/usr/lib/rigos/rigos-runtime-* text eol=lf build/usb/includes.chroot/usr/lib/rigos/rigos-miner-* text eol=lf build/usb/includes.chroot/usr/lib/rigos/rigos-remote-* text eol=lf From 4093cc95e114ea7d9db3e50c8670d30810032639 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 14:26:55 +0700 Subject: [PATCH 023/132] read image version from exact Git blob --- scripts/build-usb-image-entrypoint.sh | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/scripts/build-usb-image-entrypoint.sh b/scripts/build-usb-image-entrypoint.sh index ed0ee6a6..2c4a89d0 100644 --- a/scripts/build-usb-image-entrypoint.sh +++ b/scripts/build-usb-image-entrypoint.sh @@ -4,15 +4,30 @@ set -euo pipefail repo="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" cd "$repo" +version_env="$(mktemp)" +cleanup() { + rm -f "$version_env" +} +trap cleanup EXIT + +git -c safe.directory="$repo" show HEAD:build/usb/version.env >"$version_env" +if grep -q $'\r' "$version_env"; then + printf 'build-usb-image-entrypoint: Git version authority contains CR bytes\n' >&2 + exit 1 +fi + +# shellcheck disable=SC1090 +source "$version_env" + python3 ./scripts/check-alpha8-ssh-hotfix.py -python3 -m py_compile ./build/usb/includes.chroot/usr/lib/rigos/rigos-randomx-msr +python3 -m py_compile \ + ./build/usb/includes.chroot/usr/lib/rigos/rigos-randomx-msr \ + ./build/usb/includes.chroot/usr/lib/rigos/rigos-miner-gate export CARGO_TARGET_DIR=/work/rigos-performance-preflight-target cargo test --locked -p rigos-config --test randomx_msr_authority -- --nocapture ./scripts/build-usb-image.sh -# shellcheck disable=SC1091 -source ./build/usb/version.env image="./dist/usb/${RIGOS_IMAGE_ID}-${RIGOS_IMAGE_VERSION}.img" bash ./scripts/verify-randomx-performance-image.sh "$image" From 96ef72a2483293cc24d734adf027f5223a413830 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 14:27:16 +0700 Subject: [PATCH 024/132] test exact Git version authority for performance build --- .../tests/randomx_build_entrypoint.rs | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 crates/rigos-config/tests/randomx_build_entrypoint.rs diff --git a/crates/rigos-config/tests/randomx_build_entrypoint.rs b/crates/rigos-config/tests/randomx_build_entrypoint.rs new file mode 100644 index 00000000..d84e14bd --- /dev/null +++ b/crates/rigos-config/tests/randomx_build_entrypoint.rs @@ -0,0 +1,29 @@ +use std::fs; +use std::path::PathBuf; + +fn repo_path(path: &str) -> PathBuf { + PathBuf::from(env!("CARGO_MANIFEST_DIR")) + .join("../..") + .join(path) +} + +#[test] +fn performance_entrypoint_uses_exact_lf_git_version_authority() { + let attributes = fs::read_to_string(repo_path(".gitattributes")).unwrap(); + let entrypoint = + fs::read_to_string(repo_path("scripts/build-usb-image-entrypoint.sh")).unwrap(); + + assert!( + attributes + .lines() + .any(|line| line == "build/usb/version.env text eol=lf") + ); + assert!(entrypoint.contains( + "git -c safe.directory=\"$repo\" show HEAD:build/usb/version.env >\"$version_env\"" + )); + assert!(entrypoint.contains("if grep -q $'\\r' \"$version_env\"; then")); + assert!(entrypoint.contains("source \"$version_env\"")); + assert!(!entrypoint.contains("source ./build/usb/version.env")); + assert!(entrypoint.contains("rigos-randomx-msr")); + assert!(entrypoint.contains("rigos-miner-gate")); +} From cd5abcbe4ced0e5549dfef0d35c2d3d20208e6e1 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 15:31:16 +0700 Subject: [PATCH 025/132] accept modular or built-in kernel MSR support --- scripts/verify-randomx-performance-image.sh | 28 ++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/scripts/verify-randomx-performance-image.sh b/scripts/verify-randomx-performance-image.sh index 6586cf8c..73dcb395 100644 --- a/scripts/verify-randomx-performance-image.sh +++ b/scripts/verify-randomx-performance-image.sh @@ -31,9 +31,30 @@ mount -o ro "$loop" "$temporary/root-a" squashfs="$temporary/root-a/live/filesystem.squashfs" [[ -f "$squashfs" ]] || die 'ROOT_A squashfs is missing' -unsquashfs -ll "$squashfs" \ - | grep -Eq 'squashfs-root/(usr/)?lib/modules/.*/kernel/arch/x86/kernel/msr\.ko(\.(xz|zst|gz))?$' \ - || die 'kernel MSR module is missing from squashfs' +listing="$temporary/squashfs.list" +unsquashfs -ll "$squashfs" >"$listing" + +msr_support="missing" +if awk '{print $NF}' "$listing" \ + | grep -Eq '^squashfs-root/(usr/)?lib/modules/[^/]+/kernel/arch/x86/kernel/msr\.ko(\.(xz|zst|gz))?$' +then + msr_support="module" +else + while IFS= read -r builtin_path; do + if unsquashfs -cat "$squashfs" "$builtin_path" \ + | grep -Eq '(^|/)kernel/arch/x86/kernel/msr\.ko$' + then + msr_support="builtin" + break + fi + done < <( + awk '{print $NF}' "$listing" \ + | sed -nE 's#^squashfs-root/((usr/)?lib/modules/[^/]+/modules\.builtin)$#\1#p' + ) +fi + +[[ "$msr_support" != "missing" ]] \ + || die 'kernel MSR support is absent from module files and modules.builtin' unsquashfs -no-progress -d "$temporary/squash" "$squashfs" \ usr/bin/python3 usr/bin/python3.11 usr/bin/kmod usr/sbin/modprobe \ @@ -102,4 +123,5 @@ do grep -Fq "$required" "$miner_gate" || die "miner MSR safety contract is missing: $required" done +printf 'RIGOS RandomX kernel MSR support: %s\n' "$msr_support" printf 'RIGOS RandomX performance image verification passed: %s\n' "$image" From bb799c9cb19b2018d8b83ba0789e4e84349774fc Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 15:31:29 +0700 Subject: [PATCH 026/132] test modular and built-in kernel MSR image support --- crates/rigos-config/tests/randomx_build_entrypoint.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/crates/rigos-config/tests/randomx_build_entrypoint.rs b/crates/rigos-config/tests/randomx_build_entrypoint.rs index d84e14bd..113ca9ca 100644 --- a/crates/rigos-config/tests/randomx_build_entrypoint.rs +++ b/crates/rigos-config/tests/randomx_build_entrypoint.rs @@ -12,6 +12,8 @@ fn performance_entrypoint_uses_exact_lf_git_version_authority() { let attributes = fs::read_to_string(repo_path(".gitattributes")).unwrap(); let entrypoint = fs::read_to_string(repo_path("scripts/build-usb-image-entrypoint.sh")).unwrap(); + let image_verifier = + fs::read_to_string(repo_path("scripts/verify-randomx-performance-image.sh")).unwrap(); assert!( attributes @@ -26,4 +28,12 @@ fn performance_entrypoint_uses_exact_lf_git_version_authority() { assert!(!entrypoint.contains("source ./build/usb/version.env")); assert!(entrypoint.contains("rigos-randomx-msr")); assert!(entrypoint.contains("rigos-miner-gate")); + + assert!(image_verifier.contains("msr_support=\"module\"")); + assert!(image_verifier.contains("msr_support=\"builtin\"")); + assert!(image_verifier.contains("modules.builtin")); + assert!(image_verifier.contains("kernel/arch/x86/kernel/msr\\.ko")); + assert!(image_verifier.contains( + "kernel MSR support is absent from module files and modules.builtin" + )); } From 72d6b7597f30a7f200277e6afb98657b983cf78d Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 15:43:50 +0700 Subject: [PATCH 027/132] format kernel MSR verifier regression assertion --- crates/rigos-config/tests/randomx_build_entrypoint.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/crates/rigos-config/tests/randomx_build_entrypoint.rs b/crates/rigos-config/tests/randomx_build_entrypoint.rs index 113ca9ca..8e202649 100644 --- a/crates/rigos-config/tests/randomx_build_entrypoint.rs +++ b/crates/rigos-config/tests/randomx_build_entrypoint.rs @@ -33,7 +33,8 @@ fn performance_entrypoint_uses_exact_lf_git_version_authority() { assert!(image_verifier.contains("msr_support=\"builtin\"")); assert!(image_verifier.contains("modules.builtin")); assert!(image_verifier.contains("kernel/arch/x86/kernel/msr\\.ko")); - assert!(image_verifier.contains( - "kernel MSR support is absent from module files and modules.builtin" - )); + assert!( + image_verifier + .contains("kernel MSR support is absent from module files and modules.builtin") + ); } From d85acbc7c255669eaf84e0e6f7fe0ad427550d4d Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 15:47:38 +0700 Subject: [PATCH 028/132] format kernel MSR verifier regression assertion From b0d50d94c22258c52d9c1b708b0e395fe0f4f916 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 16:20:44 +0700 Subject: [PATCH 029/132] fix pipefail false negative in MSR image verifier --- scripts/verify-randomx-performance-image.sh | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/scripts/verify-randomx-performance-image.sh b/scripts/verify-randomx-performance-image.sh index 73dcb395..f4ed9133 100644 --- a/scripts/verify-randomx-performance-image.sh +++ b/scripts/verify-randomx-performance-image.sh @@ -35,14 +35,18 @@ listing="$temporary/squashfs.list" unsquashfs -ll "$squashfs" >"$listing" msr_support="missing" +# Do not use grep -q in a pipe while pipefail is enabled. An early grep exit can +# SIGPIPE the producer and turn a real match into a false pipeline failure. if awk '{print $NF}' "$listing" \ - | grep -Eq '^squashfs-root/(usr/)?lib/modules/[^/]+/kernel/arch/x86/kernel/msr\.ko(\.(xz|zst|gz))?$' + | grep -E '^squashfs-root/(usr/)?lib/modules/[^/]+/kernel/arch/x86/kernel/msr\.ko(\.(xz|zst|gz))?$' \ + >/dev/null then msr_support="module" else while IFS= read -r builtin_path; do if unsquashfs -cat "$squashfs" "$builtin_path" \ - | grep -Eq '(^|/)kernel/arch/x86/kernel/msr\.ko$' + | grep -E '(^|/)kernel/arch/x86/kernel/msr\.ko$' \ + >/dev/null then msr_support="builtin" break From abb7b4debad4b7eab72fc9939ecb3e90a9c85168 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 16:20:56 +0700 Subject: [PATCH 030/132] lock out quiet-grep pipefail false negatives --- crates/rigos-config/tests/randomx_build_entrypoint.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/crates/rigos-config/tests/randomx_build_entrypoint.rs b/crates/rigos-config/tests/randomx_build_entrypoint.rs index 8e202649..31417233 100644 --- a/crates/rigos-config/tests/randomx_build_entrypoint.rs +++ b/crates/rigos-config/tests/randomx_build_entrypoint.rs @@ -28,11 +28,14 @@ fn performance_entrypoint_uses_exact_lf_git_version_authority() { assert!(!entrypoint.contains("source ./build/usb/version.env")); assert!(entrypoint.contains("rigos-randomx-msr")); assert!(entrypoint.contains("rigos-miner-gate")); + assert!(entrypoint.contains("--test randomx_build_entrypoint")); assert!(image_verifier.contains("msr_support=\"module\"")); assert!(image_verifier.contains("msr_support=\"builtin\"")); assert!(image_verifier.contains("modules.builtin")); assert!(image_verifier.contains("kernel/arch/x86/kernel/msr\\.ko")); + assert!(image_verifier.contains("Do not use grep -q in a pipe while pipefail is enabled")); + assert!(!image_verifier.contains("grep -Eq")); assert!( image_verifier .contains("kernel MSR support is absent from module files and modules.builtin") From 5281b25931f8636059208fb9ab30f64084346d99 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 16:21:12 +0700 Subject: [PATCH 031/132] run image verifier regression before USB build --- scripts/build-usb-image-entrypoint.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/build-usb-image-entrypoint.sh b/scripts/build-usb-image-entrypoint.sh index 2c4a89d0..0466e3f7 100644 --- a/scripts/build-usb-image-entrypoint.sh +++ b/scripts/build-usb-image-entrypoint.sh @@ -25,6 +25,7 @@ python3 -m py_compile \ ./build/usb/includes.chroot/usr/lib/rigos/rigos-miner-gate export CARGO_TARGET_DIR=/work/rigos-performance-preflight-target +cargo test --locked -p rigos-config --test randomx_build_entrypoint -- --nocapture cargo test --locked -p rigos-config --test randomx_msr_authority -- --nocapture ./scripts/build-usb-image.sh From c41c2eeb3f33b7db35334509795935b370cc32a1 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 16:43:56 +0700 Subject: [PATCH 032/132] enable RandomX MSR authority in appliance image --- build/usb/hooks/010-rigos.chroot | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/usb/hooks/010-rigos.chroot b/build/usb/hooks/010-rigos.chroot index a29b316f..95dcf9d9 100644 --- a/build/usb/hooks/010-rigos.chroot +++ b/build/usb/hooks/010-rigos.chroot @@ -8,8 +8,8 @@ install -d -o rigos -g rigos -m 0750 /var/lib/rigos install -d -m 0755 /usr/lib/rigos /usr/local/bin systemd-tmpfiles --create /usr/lib/tmpfiles.d/rigos.conf -chmod 0755 /usr/local/bin/rigosd /usr/local/bin/rigosctl /usr/local/sbin/rigos-firstboot /usr/local/sbin/rigos-recovery-access /usr/local/sbin/rigos-state-orchestrate /usr/lib/rigos/rigos-miner-gate /usr/lib/rigos/rigos-miner-health /usr/lib/rigos/rigos-runtime-render /usr/lib/rigos/rigos-runtime-publish /usr/lib/rigos/rigos-runtime-gate /usr/lib/rigos/rigos-state-init /usr/lib/rigos/rigos-state-ready /usr/lib/rigos/rigos-config /usr/lib/rigos/rigos-performance /usr/lib/rigos/rigos-lifecycle-cycles /usr/lib/rigos/rigos-identity-seed /usr/lib/rigos/xmrig -systemctl enable NetworkManager.service ssh.service rigos-state.service rigos-recovery-access.service rigos-state-ready.service rigos-profile-apply.service rigos-runtime-render.service rigos-hugepages.service rigos-firstboot.service rigos-miner.service rigos-miner-health.timer tmp.mount +chmod 0755 /usr/local/bin/rigosd /usr/local/bin/rigosctl /usr/local/sbin/rigos-firstboot /usr/local/sbin/rigos-recovery-access /usr/local/sbin/rigos-state-orchestrate /usr/lib/rigos/rigos-miner-gate /usr/lib/rigos/rigos-miner-health /usr/lib/rigos/rigos-runtime-render /usr/lib/rigos/rigos-runtime-publish /usr/lib/rigos/rigos-runtime-gate /usr/lib/rigos/rigos-randomx-msr /usr/lib/rigos/rigos-state-init /usr/lib/rigos/rigos-state-ready /usr/lib/rigos/rigos-config /usr/lib/rigos/rigos-performance /usr/lib/rigos/rigos-lifecycle-cycles /usr/lib/rigos/rigos-identity-seed /usr/lib/rigos/xmrig +systemctl enable NetworkManager.service ssh.service rigos-state.service rigos-recovery-access.service rigos-state-ready.service rigos-profile-apply.service rigos-runtime-render.service rigos-hugepages.service rigos-firstboot.service rigos-randomx-msr.service rigos-miner.service rigos-miner-health.timer tmp.mount systemctl disable ssh.socket 2>/dev/null || true systemctl disable apt-daily.timer apt-daily-upgrade.timer logrotate.timer fstrim.timer 2>/dev/null || true systemctl disable systemd-journald-audit.socket 2>/dev/null || true From de6563053b31fa79c77e268623d08b9ff923f62b Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 16:44:36 +0700 Subject: [PATCH 033/132] test RandomX MSR authority image enablement --- crates/rigos-config/tests/randomx_build_entrypoint.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/crates/rigos-config/tests/randomx_build_entrypoint.rs b/crates/rigos-config/tests/randomx_build_entrypoint.rs index 31417233..8e19bb59 100644 --- a/crates/rigos-config/tests/randomx_build_entrypoint.rs +++ b/crates/rigos-config/tests/randomx_build_entrypoint.rs @@ -14,6 +14,7 @@ fn performance_entrypoint_uses_exact_lf_git_version_authority() { fs::read_to_string(repo_path("scripts/build-usb-image-entrypoint.sh")).unwrap(); let image_verifier = fs::read_to_string(repo_path("scripts/verify-randomx-performance-image.sh")).unwrap(); + let image_hook = fs::read_to_string(repo_path("build/usb/hooks/010-rigos.chroot")).unwrap(); assert!( attributes @@ -30,6 +31,9 @@ fn performance_entrypoint_uses_exact_lf_git_version_authority() { assert!(entrypoint.contains("rigos-miner-gate")); assert!(entrypoint.contains("--test randomx_build_entrypoint")); + assert!(image_hook.contains("/usr/lib/rigos/rigos-randomx-msr")); + assert!(image_hook.contains("rigos-randomx-msr.service rigos-miner.service")); + assert!(image_verifier.contains("msr_support=\"module\"")); assert!(image_verifier.contains("msr_support=\"builtin\"")); assert!(image_verifier.contains("modules.builtin")); From 0cde0df301ff827f70b27efc2da057bc34d55be7 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 21:45:10 +0700 Subject: [PATCH 034/132] add persistent SSH host-key authority --- .../usr/lib/rigos/rigos-ssh-hostkeys | 320 ++++++++++++++++++ 1 file changed, 320 insertions(+) create mode 100644 build/usb/includes.chroot/usr/lib/rigos/rigos-ssh-hostkeys diff --git a/build/usb/includes.chroot/usr/lib/rigos/rigos-ssh-hostkeys b/build/usb/includes.chroot/usr/lib/rigos/rigos-ssh-hostkeys new file mode 100644 index 00000000..64bbbe43 --- /dev/null +++ b/build/usb/includes.chroot/usr/lib/rigos/rigos-ssh-hostkeys @@ -0,0 +1,320 @@ +#!/usr/bin/env python3 +import datetime +import grp +import hashlib +import json +import os +import shutil +import stat +import subprocess +import sys +import tempfile +from pathlib import Path + +STATE = Path("/var/lib/rigos") +SYSTEM = STATE / "system" +KEYS = SYSTEM / "ssh-hostkeys" +PRIVATE_KEY = KEYS / "ssh_host_ed25519_key" +PUBLIC_KEY = KEYS / "ssh_host_ed25519_key.pub" +MANIFEST = KEYS / "manifest.json" +RUNTIME = Path("/run/rigos") +STATUS = RUNTIME / "ssh-hostkeys-status.json" +STATE_STATUS = RUNTIME / "state-status.json" +BOOT_ID = Path("/proc/sys/kernel/random/boot_id") +SSH_KEYGEN = "/usr/bin/ssh-keygen" +FINDMNT = "/usr/bin/findmnt" + + +class AuthorityError(RuntimeError): + pass + + +def read_json(path: Path) -> dict: + try: + raw = path.read_bytes() + if len(raw) > 64 * 1024: + return {} + value = json.loads(raw) + return value if isinstance(value, dict) else {} + except (OSError, json.JSONDecodeError): + return {} + + +def fsync_directory(path: Path) -> None: + descriptor = os.open(path, os.O_RDONLY | os.O_DIRECTORY) + try: + os.fsync(descriptor) + finally: + os.close(descriptor) + + +def write_atomic_json(path: Path, value: dict, mode: int = 0o644) -> None: + path.parent.mkdir(mode=0o755, parents=True, exist_ok=True) + with tempfile.NamedTemporaryFile( + mode="w", + encoding="utf-8", + dir=path.parent, + prefix=f".{path.name}-", + delete=False, + ) as stream: + json.dump(value, stream, indent=2, sort_keys=True) + stream.write("\n") + stream.flush() + os.fsync(stream.fileno()) + temporary = Path(stream.name) + os.chown(temporary, 0, 0) + temporary.chmod(mode) + os.replace(temporary, path) + fsync_directory(path.parent) + + +def current_boot_id() -> str: + try: + value = BOOT_ID.read_text(encoding="ascii").strip() + except OSError as error: + raise AuthorityError(f"boot id unavailable: {error}") from error + if not value: + raise AuthorityError("boot id is empty") + return value + + +def validate_state_ready(boot_id: str) -> None: + status = read_json(STATE_STATUS) + if ( + status.get("schema") != "rigos.state-status/v1" + or status.get("boot_id") != boot_id + or status.get("outcome") != "ready" + ): + raise AuthorityError("current persistent state readiness is unavailable") + + observed = subprocess.run( + [FINDMNT, "--json", "--target", str(STATE), "--output", "TARGET,FSTYPE,OPTIONS"], + check=False, + text=True, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + ) + if observed.returncode != 0: + raise AuthorityError("persistent state mount query failed") + try: + filesystems = json.loads(observed.stdout).get("filesystems", []) + except json.JSONDecodeError as error: + raise AuthorityError("persistent state mount query returned invalid JSON") from error + if len(filesystems) != 1: + raise AuthorityError("persistent state mount is ambiguous") + filesystem = filesystems[0] + options = set(str(filesystem.get("options") or "").split(",")) + if ( + filesystem.get("target") != str(STATE) + or filesystem.get("fstype") != "ext4" + or "rw" not in options + ): + raise AuthorityError("persistent state is not the expected read-write ext4 mount") + + +def secure_state_root() -> None: + try: + state = STATE.lstat() + except OSError as error: + raise AuthorityError(f"persistent state root unavailable: {error}") from error + if stat.S_ISLNK(state.st_mode) or not stat.S_ISDIR(state.st_mode): + raise AuthorityError("persistent state root is not a real directory") + try: + rigos_gid = grp.getgrnam("rigos").gr_gid + os.chown(STATE, 0, rigos_gid) + STATE.chmod(0o750) + except OSError as error: + raise AuthorityError(f"persistent state root could not be secured: {error}") from error + + +def ensure_secure_directory(path: Path, mode: int) -> None: + if not path.exists(): + path.mkdir(mode=mode) + os.chown(path, 0, 0) + path.chmod(mode) + observed = path.lstat() + if stat.S_ISLNK(observed.st_mode) or not stat.S_ISDIR(observed.st_mode): + raise AuthorityError(f"{path} is not a real directory") + if observed.st_uid != 0 or observed.st_gid != 0: + raise AuthorityError(f"{path} is not owned by root:root") + if stat.S_IMODE(observed.st_mode) != mode: + raise AuthorityError(f"{path} has unsafe mode") + + +def validate_regular_file(path: Path, mode: int) -> None: + try: + observed = path.lstat() + except OSError as error: + raise AuthorityError(f"required host identity file is unavailable: {path.name}") from error + if stat.S_ISLNK(observed.st_mode) or not stat.S_ISREG(observed.st_mode): + raise AuthorityError(f"host identity file is not regular: {path.name}") + if observed.st_uid != 0 or observed.st_gid != 0: + raise AuthorityError(f"host identity file owner is unsafe: {path.name}") + if stat.S_IMODE(observed.st_mode) != mode: + raise AuthorityError(f"host identity file mode is unsafe: {path.name}") + + +def command_output(arguments: list[str]) -> str: + result = subprocess.run( + arguments, + check=False, + text=True, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + timeout=30, + ) + if result.returncode != 0: + raise AuthorityError(f"host identity command failed: {Path(arguments[0]).name}") + return result.stdout.strip() + + +def key_fingerprint(public_key: Path) -> str: + output = command_output([SSH_KEYGEN, "-E", "sha256", "-lf", str(public_key)]) + fields = output.split() + if len(fields) < 2 or not fields[1].startswith("SHA256:"): + raise AuthorityError("host identity fingerprint is invalid") + return fields[1] + + +def validate_keyset() -> str: + ensure_secure_directory(KEYS, 0o700) + validate_regular_file(PRIVATE_KEY, 0o600) + validate_regular_file(PUBLIC_KEY, 0o644) + validate_regular_file(MANIFEST, 0o644) + + public_fields = PUBLIC_KEY.read_text(encoding="ascii").strip().split() + derived_fields = command_output([SSH_KEYGEN, "-y", "-f", str(PRIVATE_KEY)]).split() + if len(public_fields) < 2 or derived_fields[:2] != public_fields[:2]: + raise AuthorityError("persistent SSH public and private keys do not match") + + fingerprint = key_fingerprint(PUBLIC_KEY) + public_sha256 = hashlib.sha256(PUBLIC_KEY.read_bytes()).hexdigest() + manifest = read_json(MANIFEST) + if ( + manifest.get("schema") != "rigos.ssh-hostkeys/v1" + or manifest.get("algorithm") != "ssh-ed25519" + or manifest.get("fingerprint") != fingerprint + or manifest.get("public_key_sha256") != public_sha256 + or not isinstance(manifest.get("created_boot_id"), str) + or not manifest.get("created_boot_id") + ): + raise AuthorityError("persistent SSH host identity manifest is invalid") + return fingerprint + + +def remove_stale_staging() -> None: + for candidate in SYSTEM.glob(".ssh-hostkeys.tmp-*"): + observed = candidate.lstat() + if stat.S_ISLNK(observed.st_mode) or not stat.S_ISDIR(observed.st_mode): + raise AuthorityError("unsafe SSH host identity staging path exists") + if observed.st_uid != 0 or observed.st_gid != 0: + raise AuthorityError("untrusted SSH host identity staging directory exists") + shutil.rmtree(candidate) + fsync_directory(SYSTEM) + + +def generate_keyset(boot_id: str) -> str: + if KEYS.exists() or KEYS.is_symlink(): + raise AuthorityError("persistent SSH host identity exists without a valid manifest") + remove_stale_staging() + + temporary = Path(tempfile.mkdtemp(prefix=".ssh-hostkeys.tmp-", dir=SYSTEM)) + try: + os.chown(temporary, 0, 0) + temporary.chmod(0o700) + private_key = temporary / PRIVATE_KEY.name + public_key = temporary / PUBLIC_KEY.name + manifest_path = temporary / MANIFEST.name + + result = subprocess.run( + [ + SSH_KEYGEN, + "-q", + "-t", + "ed25519", + "-N", + "", + "-C", + "rigos-host", + "-f", + str(private_key), + ], + check=False, + stdout=subprocess.DEVNULL, + stderr=subprocess.PIPE, + text=True, + timeout=30, + ) + if result.returncode != 0: + raise AuthorityError("persistent SSH host identity generation failed") + + os.chown(private_key, 0, 0) + os.chown(public_key, 0, 0) + private_key.chmod(0o600) + public_key.chmod(0o644) + fingerprint = key_fingerprint(public_key) + manifest = { + "schema": "rigos.ssh-hostkeys/v1", + "algorithm": "ssh-ed25519", + "created_at": datetime.datetime.now(datetime.timezone.utc).isoformat(), + "created_boot_id": boot_id, + "fingerprint": fingerprint, + "public_key_sha256": hashlib.sha256(public_key.read_bytes()).hexdigest(), + } + write_atomic_json(manifest_path, manifest, 0o644) + + for path in (private_key, public_key, manifest_path): + descriptor = os.open(path, os.O_RDONLY) + try: + os.fsync(descriptor) + finally: + os.close(descriptor) + fsync_directory(temporary) + os.rename(temporary, KEYS) + fsync_directory(SYSTEM) + finally: + if temporary.exists(): + shutil.rmtree(temporary) + return validate_keyset() + + +def write_status(boot_id: str, outcome: str, **extra: object) -> None: + value = { + "schema": "rigos.ssh-hostkeys-status/v1", + "boot_id": boot_id, + "outcome": outcome, + "persistent_path": str(PRIVATE_KEY), + } + value.update(extra) + try: + write_atomic_json(STATUS, value) + except OSError: + pass + + +def main() -> int: + boot_id = "unavailable" + try: + boot_id = current_boot_id() + validate_state_ready(boot_id) + secure_state_root() + ensure_secure_directory(SYSTEM, 0o700) + reused = KEYS.exists() + fingerprint = validate_keyset() if reused else generate_keyset(boot_id) + write_status( + boot_id, + "ready", + algorithm="ssh-ed25519", + fingerprint=fingerprint, + reused=reused, + ) + print(f"RIGOS_SSH_HOSTKEYS=READY fingerprint={fingerprint} reused={str(reused).lower()}") + return 0 + except (AuthorityError, OSError, subprocess.SubprocessError) as error: + write_status(boot_id, "error", reason=str(error)) + print(f"rigos-ssh-hostkeys: {error}", file=sys.stderr) + return 1 + + +if __name__ == "__main__": + raise SystemExit(main()) From 61597633d01d441d725cff8a368a39c558fbccda Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 21:46:10 +0700 Subject: [PATCH 035/132] wire persistent SSH host identity service --- .../systemd/system/rigos-ssh-hostkeys.service | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 build/usb/includes.chroot/etc/systemd/system/rigos-ssh-hostkeys.service diff --git a/build/usb/includes.chroot/etc/systemd/system/rigos-ssh-hostkeys.service b/build/usb/includes.chroot/etc/systemd/system/rigos-ssh-hostkeys.service new file mode 100644 index 00000000..9005c426 --- /dev/null +++ b/build/usb/includes.chroot/etc/systemd/system/rigos-ssh-hostkeys.service @@ -0,0 +1,25 @@ +[Unit] +Description=Establish persistent RIGOS SSH host identity +After=rigos-state-ready.service +Requires=rigos-state-ready.service +Before=ssh.service + +[Service] +Type=oneshot +ExecStart=/usr/bin/python3 /usr/lib/rigos/rigos-ssh-hostkeys +RemainAfterExit=yes +UMask=0077 +NoNewPrivileges=yes +PrivateTmp=yes +ProtectHome=yes +ProtectSystem=strict +ProtectKernelTunables=yes +ProtectKernelModules=yes +ProtectControlGroups=yes +RestrictAddressFamilies=AF_UNIX +RestrictNamespaces=yes +LockPersonality=yes +ReadWritePaths=/var/lib/rigos /run/rigos + +[Install] +WantedBy=multi-user.target From 6f55ec161042c12d0c5425625775def2816029a2 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 21:46:34 +0700 Subject: [PATCH 036/132] point sshd at persistent host identity --- .../includes.chroot/etc/ssh/sshd_config.d/01-rigos-hostkeys.conf | 1 + 1 file changed, 1 insertion(+) create mode 100644 build/usb/includes.chroot/etc/ssh/sshd_config.d/01-rigos-hostkeys.conf diff --git a/build/usb/includes.chroot/etc/ssh/sshd_config.d/01-rigos-hostkeys.conf b/build/usb/includes.chroot/etc/ssh/sshd_config.d/01-rigos-hostkeys.conf new file mode 100644 index 00000000..0532202d --- /dev/null +++ b/build/usb/includes.chroot/etc/ssh/sshd_config.d/01-rigos-hostkeys.conf @@ -0,0 +1 @@ +HostKey /var/lib/rigos/system/ssh-hostkeys/ssh_host_ed25519_key From 15cb81b5da859e515b81538e4011dda56aaad159 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 21:46:56 +0700 Subject: [PATCH 037/132] make ssh require persistent host identity --- .../etc/systemd/system/ssh.service.d/rigos-observe.conf | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/build/usb/includes.chroot/etc/systemd/system/ssh.service.d/rigos-observe.conf b/build/usb/includes.chroot/etc/systemd/system/ssh.service.d/rigos-observe.conf index d00954c6..28ca00d7 100644 --- a/build/usb/includes.chroot/etc/systemd/system/ssh.service.d/rigos-observe.conf +++ b/build/usb/includes.chroot/etc/systemd/system/ssh.service.d/rigos-observe.conf @@ -1,3 +1,4 @@ [Unit] -After=rigos-recovery-access.service +After=rigos-recovery-access.service rigos-ssh-hostkeys.service +Requires=rigos-ssh-hostkeys.service Wants=rigos-remote-access-observe.service From 1945ed7ebf7011a1dc22c6c2932bf6a972d4add9 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 21:47:33 +0700 Subject: [PATCH 038/132] extend state-ready ordering --- .../etc/systemd/system/rigos-state-ready.service | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/usb/includes.chroot/etc/systemd/system/rigos-state-ready.service b/build/usb/includes.chroot/etc/systemd/system/rigos-state-ready.service index 5fbc72e0..593b274c 100644 --- a/build/usb/includes.chroot/etc/systemd/system/rigos-state-ready.service +++ b/build/usb/includes.chroot/etc/systemd/system/rigos-state-ready.service @@ -2,7 +2,7 @@ Description=Verify RIGOS persistent state readiness After=rigos-state.service rigos-recovery-access.service Requires=rigos-state.service -Before=rigos-profile-apply.service rigos-firstboot.service rigos-hugepages.service rigos-miner.service +Before=rigos-ssh-hostkeys.service rigos-profile-apply.service rigos-firstboot.service rigos-hugepages.service rigos-miner.service [Service] Type=oneshot From 169c08604a2f6e25152bda0ae672b9e6267b90f9 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 21:47:56 +0700 Subject: [PATCH 039/132] enable persistent host-key authority in appliance --- build/usb/hooks/010-rigos.chroot | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/build/usb/hooks/010-rigos.chroot b/build/usb/hooks/010-rigos.chroot index 95dcf9d9..acc1d24b 100644 --- a/build/usb/hooks/010-rigos.chroot +++ b/build/usb/hooks/010-rigos.chroot @@ -4,12 +4,13 @@ set -eu useradd --system --home-dir /var/lib/rigos --shell /usr/sbin/nologin --user-group rigos useradd --create-home --shell /bin/bash --groups sudo rigosadmin passwd --lock rigosadmin -install -d -o rigos -g rigos -m 0750 /var/lib/rigos +install -d -o root -g rigos -m 0750 /var/lib/rigos install -d -m 0755 /usr/lib/rigos /usr/local/bin systemd-tmpfiles --create /usr/lib/tmpfiles.d/rigos.conf -chmod 0755 /usr/local/bin/rigosd /usr/local/bin/rigosctl /usr/local/sbin/rigos-firstboot /usr/local/sbin/rigos-recovery-access /usr/local/sbin/rigos-state-orchestrate /usr/lib/rigos/rigos-miner-gate /usr/lib/rigos/rigos-miner-health /usr/lib/rigos/rigos-runtime-render /usr/lib/rigos/rigos-runtime-publish /usr/lib/rigos/rigos-runtime-gate /usr/lib/rigos/rigos-randomx-msr /usr/lib/rigos/rigos-state-init /usr/lib/rigos/rigos-state-ready /usr/lib/rigos/rigos-config /usr/lib/rigos/rigos-performance /usr/lib/rigos/rigos-lifecycle-cycles /usr/lib/rigos/rigos-identity-seed /usr/lib/rigos/xmrig -systemctl enable NetworkManager.service ssh.service rigos-state.service rigos-recovery-access.service rigos-state-ready.service rigos-profile-apply.service rigos-runtime-render.service rigos-hugepages.service rigos-firstboot.service rigos-randomx-msr.service rigos-miner.service rigos-miner-health.timer tmp.mount +rm -f /etc/ssh/ssh_host_*_key /etc/ssh/ssh_host_*_key.pub +chmod 0755 /usr/local/bin/rigosd /usr/local/bin/rigosctl /usr/local/sbin/rigos-firstboot /usr/local/sbin/rigos-recovery-access /usr/local/sbin/rigos-state-orchestrate /usr/lib/rigos/rigos-miner-gate /usr/lib/rigos/rigos-miner-health /usr/lib/rigos/rigos-runtime-render /usr/lib/rigos/rigos-runtime-publish /usr/lib/rigos/rigos-runtime-gate /usr/lib/rigos/rigos-randomx-msr /usr/lib/rigos/rigos-ssh-hostkeys /usr/lib/rigos/rigos-state-init /usr/lib/rigos/rigos-state-ready /usr/lib/rigos/rigos-config /usr/lib/rigos/rigos-performance /usr/lib/rigos/rigos-lifecycle-cycles /usr/lib/rigos/rigos-identity-seed /usr/lib/rigos/xmrig +systemctl enable NetworkManager.service ssh.service rigos-state.service rigos-recovery-access.service rigos-state-ready.service rigos-ssh-hostkeys.service rigos-profile-apply.service rigos-runtime-render.service rigos-hugepages.service rigos-firstboot.service rigos-randomx-msr.service rigos-miner.service rigos-miner-health.timer tmp.mount systemctl disable ssh.socket 2>/dev/null || true systemctl disable apt-daily.timer apt-daily-upgrade.timer logrotate.timer fstrim.timer 2>/dev/null || true systemctl disable systemd-journald-audit.socket 2>/dev/null || true From 2ef593eb2eb62307bf33c7b6e4c43252f482df23 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 21:48:24 +0700 Subject: [PATCH 040/132] verify persistent host-key boot ordering --- scripts/verify-systemd-ordering.py | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/scripts/verify-systemd-ordering.py b/scripts/verify-systemd-ordering.py index a5c69eac..cc1d7c83 100644 --- a/scripts/verify-systemd-ordering.py +++ b/scripts/verify-systemd-ordering.py @@ -43,8 +43,9 @@ def includes(actual, expected, message): def verify(units): names = { "rigos-state.service", "rigos-recovery-access.service", - "rigos-state-ready.service", "rigos-profile-apply.service", - "rigos-firstboot.service", "rigos-hugepages.service", "rigos-miner.service", + "rigos-state-ready.service", "rigos-ssh-hostkeys.service", + "rigos-profile-apply.service", "rigos-firstboot.service", + "rigos-hugepages.service", "rigos-miner.service", } includes(set(units), names, "RIGOS unit set is incomplete") state = units["rigos-state.service"] @@ -60,11 +61,29 @@ def verify(units): require(ready.scalar("Unit", "DefaultDependencies") != "no", "state-ready must use normal dependencies") includes(ready.words("Unit", "After"), {"rigos-state.service", "rigos-recovery-access.service"}, "state-ready ordering is incomplete") includes(ready.words("Unit", "Requires"), {"rigos-state.service"}, "state-ready must require state") - includes(ready.words("Unit", "Before"), {"rigos-profile-apply.service", "rigos-firstboot.service", "rigos-hugepages.service", "rigos-miner.service"}, "state-ready downstream ordering is incomplete") + includes( + ready.words("Unit", "Before"), + { + "rigos-ssh-hostkeys.service", "rigos-profile-apply.service", + "rigos-firstboot.service", "rigos-hugepages.service", + "rigos-miner.service", + }, + "state-ready downstream ordering is incomplete", + ) require("local-fs.target" not in ready.words("Unit", "Before"), "state-ready must not order before local-fs") require("local-fs.target" not in ready.words("Install", "WantedBy"), "state-ready must not be installed under local-fs") includes(ready.words("Install", "WantedBy"), {"multi-user.target"}, "state-ready must be installed under multi-user") + hostkeys = units["rigos-ssh-hostkeys.service"] + includes(hostkeys.words("Unit", "After"), {"rigos-state-ready.service"}, "SSH host-key authority must follow state readiness") + includes(hostkeys.words("Unit", "Requires"), {"rigos-state-ready.service"}, "SSH host-key authority must require state readiness") + includes(hostkeys.words("Unit", "Before"), {"ssh.service"}, "SSH host-key authority must precede sshd") + require( + hostkeys.scalar("Service", "ExecStart") == "/usr/bin/python3", + "SSH host-key authority must use the absolute Python runtime", + ) + includes(hostkeys.words("Install", "WantedBy"), {"multi-user.target"}, "SSH host-key authority must be enabled under multi-user") + firstboot = units["rigos-firstboot.service"] includes(firstboot.words("Unit", "Requires"), {"rigos-state-ready.service"}, "firstboot must require state-ready") require(firstboot.scalar("Service", "TTYVHangup") != "yes", "firstboot must not hang up tty1") @@ -90,6 +109,7 @@ def graph_for(units): def cycle_in(graph): state, stack, positions = {}, [], {} + def visit(node): state[node] = 1 positions[node] = len(stack) @@ -105,6 +125,7 @@ def visit(node): positions.pop(node) state[node] = 2 return None + for node in sorted(graph): if state.get(node, 0) == 0: cycle = visit(node) From 56cfbc66c66d1c6b219d3a6c53986660cee291b2 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 21:48:59 +0700 Subject: [PATCH 041/132] use direct host-key authority entrypoint --- .../etc/systemd/system/rigos-ssh-hostkeys.service | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/usb/includes.chroot/etc/systemd/system/rigos-ssh-hostkeys.service b/build/usb/includes.chroot/etc/systemd/system/rigos-ssh-hostkeys.service index 9005c426..fe069df2 100644 --- a/build/usb/includes.chroot/etc/systemd/system/rigos-ssh-hostkeys.service +++ b/build/usb/includes.chroot/etc/systemd/system/rigos-ssh-hostkeys.service @@ -6,7 +6,7 @@ Before=ssh.service [Service] Type=oneshot -ExecStart=/usr/bin/python3 /usr/lib/rigos/rigos-ssh-hostkeys +ExecStart=/usr/lib/rigos/rigos-ssh-hostkeys RemainAfterExit=yes UMask=0077 NoNewPrivileges=yes From 940cdde4c5beb5fd007bc6cb8f05fab57f5d893f Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 21:49:44 +0700 Subject: [PATCH 042/132] verify persistent SSH identity source contract --- scripts/check-alpha8-ssh-hotfix.py | 74 ++++++++++++++++++++++++++++-- 1 file changed, 70 insertions(+), 4 deletions(-) diff --git a/scripts/check-alpha8-ssh-hotfix.py b/scripts/check-alpha8-ssh-hotfix.py index 17a154e3..5c513ce8 100644 --- a/scripts/check-alpha8-ssh-hotfix.py +++ b/scripts/check-alpha8-ssh-hotfix.py @@ -4,21 +4,34 @@ ROOT = Path(__file__).resolve().parents[1] POLICY = ROOT / "build/usb/includes.chroot/etc/ssh/sshd_config.d/00-rigos.conf" +HOSTKEY_POLICY = ROOT / "build/usb/includes.chroot/etc/ssh/sshd_config.d/01-rigos-hostkeys.conf" PACKAGES = ROOT / "build/usb/package-lists/rigos.list.chroot" HOOK = ROOT / "build/usb/hooks/010-rigos.chroot" DOCKERFILE = ROOT / "build/usb/Dockerfile" RECOVERY_UNIT = ROOT / "build/usb/includes.chroot/etc/systemd/system/rigos-recovery-access.service" RECOVERY_GATE = ROOT / "build/usb/includes.chroot/usr/lib/rigos/rigos-recovery-access-verify" +STATE_READY_UNIT = ROOT / "build/usb/includes.chroot/etc/systemd/system/rigos-state-ready.service" +HOSTKEY_UNIT = ROOT / "build/usb/includes.chroot/etc/systemd/system/rigos-ssh-hostkeys.service" +SSH_DROPIN = ROOT / "build/usb/includes.chroot/etc/systemd/system/ssh.service.d/rigos-observe.conf" +HOSTKEY_AUTHORITY = ROOT / "build/usb/includes.chroot/usr/lib/rigos/rigos-ssh-hostkeys" +SSH_DIRECTORY = ROOT / "build/usb/includes.chroot/etc/ssh" EXPECTED_POLICY_SHA256 = "d59b6bcc078a047d1f1cc90ef6ed9205476d91f874be809009bdd442ef66b8c3" def normalized_lf_bytes(path: Path) -> bytes: raw = path.read_bytes() if raw.startswith(b"\xef\xbb\xbf"): - raise RuntimeError("Alpha8 SSH policy must be UTF-8 without BOM") + raise RuntimeError(f"{path.name} must be UTF-8 without BOM") return raw.replace(b"\r\n", b"\n").replace(b"\r", b"\n") +def require_lines(path: Path, required_lines: tuple[str, ...]) -> None: + lines = set(path.read_text(encoding="utf-8").splitlines()) + for required in required_lines: + if required not in lines: + raise RuntimeError(f"{path.name} contract is missing: {required}") + + def main() -> int: policy = normalized_lf_bytes(POLICY) observed = hashlib.sha256(policy).hexdigest() @@ -29,9 +42,62 @@ def main() -> int: packages = PACKAGES.read_text(encoding="utf-8").splitlines() if "openssh-server" not in packages: raise RuntimeError("OpenSSH server package is missing") + + hostkey_policy = normalized_lf_bytes(HOSTKEY_POLICY) + if hostkey_policy != b"HostKey /var/lib/rigos/system/ssh-hostkeys/ssh_host_ed25519_key\n": + raise RuntimeError("persistent SSH HostKey policy is not exact") + baked_keys = sorted(path for path in SSH_DIRECTORY.glob("ssh_host_*_key*") if path.is_file()) + if baked_keys: + raise RuntimeError("appliance source contains a baked SSH host private or public key") + hook = HOOK.read_text(encoding="utf-8") - if "ssh.service" not in hook or "systemctl disable ssh.socket" not in hook: - raise RuntimeError("deterministic SSH service wiring is missing") + for required in ( + "ssh.service", + "systemctl disable ssh.socket", + "rigos-ssh-hostkeys.service", + "/usr/lib/rigos/rigos-ssh-hostkeys", + "rm -f /etc/ssh/ssh_host_*_key /etc/ssh/ssh_host_*_key.pub", + "install -d -o root -g rigos -m 0750 /var/lib/rigos", + ): + if required not in hook: + raise RuntimeError(f"deterministic SSH service wiring is missing: {required}") + + authority = HOSTKEY_AUTHORITY.read_text(encoding="utf-8") + compile(authority, str(HOSTKEY_AUTHORITY), "exec") + for required in ( + 'STATE = Path("/var/lib/rigos")', + 'KEYS = SYSTEM / "ssh-hostkeys"', + '"schema": "rigos.ssh-hostkeys/v1"', + 'os.rename(temporary, KEYS)', + 'or status.get("outcome") != "ready"', + '"persistent SSH public and private keys do not match"', + '"persistent SSH host identity exists without a valid manifest"', + ): + if required not in authority: + raise RuntimeError(f"persistent SSH host-key authority contract is missing: {required}") + + require_lines( + HOSTKEY_UNIT, + ( + "After=rigos-state-ready.service", + "Requires=rigos-state-ready.service", + "Before=ssh.service", + "ExecStart=/usr/lib/rigos/rigos-ssh-hostkeys", + "ReadWritePaths=/var/lib/rigos /run/rigos", + "WantedBy=multi-user.target", + ), + ) + require_lines( + SSH_DROPIN, + ( + "After=rigos-recovery-access.service rigos-ssh-hostkeys.service", + "Requires=rigos-ssh-hostkeys.service", + "Wants=rigos-remote-access-observe.service", + ), + ) + if "Before=rigos-ssh-hostkeys.service" not in STATE_READY_UNIT.read_text(encoding="utf-8"): + raise RuntimeError("state readiness is not ordered before persistent SSH identity") + dockerfile = DOCKERFILE.read_text(encoding="utf-8") if 'ENV PATH="/usr/local/cargo/bin:/usr/local/rustup/bin:${PATH}"' not in dockerfile: raise RuntimeError("builder Cargo PATH is not explicit") @@ -62,7 +128,7 @@ def main() -> int: if required not in recovery_gate: raise RuntimeError(f"recovery access validator contract is missing: {required}") - print("RIGOS Alpha8 SSH and recovery hotfix verification passed") + print("RIGOS Alpha8 SSH, recovery, and persistent host-key verification passed") return 0 From 310d9d6a37c28abe8ee81f1931ff92b2d8d92737 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 21:50:14 +0700 Subject: [PATCH 043/132] run SSH identity checks before image build --- scripts/build-usb-image-entrypoint.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/scripts/build-usb-image-entrypoint.sh b/scripts/build-usb-image-entrypoint.sh index 0466e3f7..4d31eba2 100644 --- a/scripts/build-usb-image-entrypoint.sh +++ b/scripts/build-usb-image-entrypoint.sh @@ -20,9 +20,11 @@ fi source "$version_env" python3 ./scripts/check-alpha8-ssh-hotfix.py +python3 ./scripts/verify-systemd-ordering.py python3 -m py_compile \ ./build/usb/includes.chroot/usr/lib/rigos/rigos-randomx-msr \ - ./build/usb/includes.chroot/usr/lib/rigos/rigos-miner-gate + ./build/usb/includes.chroot/usr/lib/rigos/rigos-miner-gate \ + ./build/usb/includes.chroot/usr/lib/rigos/rigos-ssh-hostkeys export CARGO_TARGET_DIR=/work/rigos-performance-preflight-target cargo test --locked -p rigos-config --test randomx_build_entrypoint -- --nocapture From 72d7df7cbd8671adc54ef31658f79e336a9d8b14 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 21:50:53 +0700 Subject: [PATCH 044/132] verify persistent SSH identity in exact image --- scripts/verify-randomx-performance-image.sh | 51 ++++++++++++++++++++- 1 file changed, 49 insertions(+), 2 deletions(-) diff --git a/scripts/verify-randomx-performance-image.sh b/scripts/verify-randomx-performance-image.sh index f4ed9133..1a774407 100644 --- a/scripts/verify-randomx-performance-image.sh +++ b/scripts/verify-randomx-performance-image.sh @@ -34,6 +34,12 @@ squashfs="$temporary/root-a/live/filesystem.squashfs" listing="$temporary/squashfs.list" unsquashfs -ll "$squashfs" >"$listing" +if awk '{print $NF}' "$listing" \ + | grep -E '^squashfs-root/etc/ssh/ssh_host_.*_key(\.pub)?$' >/dev/null +then + die 'appliance image contains a baked SSH host key' +fi + msr_support="missing" # Do not use grep -q in a pipe while pipefail is enabled. An early grep exit can # SIGPIPE the producer and turn a real match into a false pipeline failure. @@ -63,29 +69,42 @@ fi unsquashfs -no-progress -d "$temporary/squash" "$squashfs" \ usr/bin/python3 usr/bin/python3.11 usr/bin/kmod usr/sbin/modprobe \ usr/lib/rigos/rigos-randomx-msr usr/lib/rigos/rigos-miner-gate \ + usr/lib/rigos/rigos-ssh-hostkeys \ + etc/ssh/sshd_config.d/01-rigos-hostkeys.conf \ etc/systemd/system/rigos-randomx-msr.service \ + etc/systemd/system/rigos-ssh-hostkeys.service \ + etc/systemd/system/ssh.service.d/rigos-observe.conf \ etc/systemd/system/rigos-miner.service \ etc/systemd/system/rigos-miner.service.d/randomx-msr.conf \ etc/systemd/system/multi-user.target.wants/rigos-randomx-msr.service \ + etc/systemd/system/multi-user.target.wants/rigos-ssh-hostkeys.service \ >/dev/null root="$temporary/squash" -[[ -x "$root/usr/bin/python3" ]] || die 'Python runtime for MSR authority is missing' +[[ -x "$root/usr/bin/python3" ]] || die 'Python runtime for authority services is missing' [[ -x "$root/usr/bin/kmod" ]] || die 'kmod runtime for MSR authority is missing' [[ -L "$root/usr/sbin/modprobe" || -x "$root/usr/sbin/modprobe" ]] || die 'modprobe entrypoint is missing' [[ -f "$root/usr/lib/rigos/rigos-randomx-msr" ]] || die 'RandomX MSR authority is missing' [[ -f "$root/usr/lib/rigos/rigos-miner-gate" ]] || die 'miner safety gate is missing' +[[ -f "$root/usr/lib/rigos/rigos-ssh-hostkeys" ]] || die 'persistent SSH host-key authority is missing' [[ -L "$root/etc/systemd/system/multi-user.target.wants/rigos-randomx-msr.service" ]] \ || die 'RandomX MSR authority is not enabled in the appliance' +[[ -L "$root/etc/systemd/system/multi-user.target.wants/rigos-ssh-hostkeys.service" ]] \ + || die 'persistent SSH host-key authority is not enabled in the appliance' python3 -m py_compile \ "$root/usr/lib/rigos/rigos-randomx-msr" \ - "$root/usr/lib/rigos/rigos-miner-gate" + "$root/usr/lib/rigos/rigos-miner-gate" \ + "$root/usr/lib/rigos/rigos-ssh-hostkeys" service="$root/etc/systemd/system/rigos-randomx-msr.service" dropin="$root/etc/systemd/system/rigos-miner.service.d/randomx-msr.conf" miner="$root/etc/systemd/system/rigos-miner.service" authority="$root/usr/lib/rigos/rigos-randomx-msr" miner_gate="$root/usr/lib/rigos/rigos-miner-gate" +hostkey_service="$root/etc/systemd/system/rigos-ssh-hostkeys.service" +hostkey_authority="$root/usr/lib/rigos/rigos-ssh-hostkeys" +hostkey_policy="$root/etc/ssh/sshd_config.d/01-rigos-hostkeys.conf" +ssh_dropin="$root/etc/systemd/system/ssh.service.d/rigos-observe.conf" for required in \ 'ExecStartPre=-/usr/sbin/modprobe msr' \ @@ -106,6 +125,33 @@ grep -Fqx 'User=rigos' "$miner" || die 'miner no longer runs as the unprivileged grep -Fqx 'ExecCondition=/usr/lib/rigos/rigos-miner-gate' "$miner" \ || die 'miner safety gate is not wired' +for required in \ + 'After=rigos-state-ready.service' \ + 'Requires=rigos-state-ready.service' \ + 'Before=ssh.service' \ + 'ExecStart=/usr/lib/rigos/rigos-ssh-hostkeys' \ + 'ReadWritePaths=/var/lib/rigos /run/rigos' +do + grep -Fqx "$required" "$hostkey_service" \ + || die "persistent SSH host-key service contract is missing: $required" +done +grep -Fqx 'HostKey /var/lib/rigos/system/ssh-hostkeys/ssh_host_ed25519_key' "$hostkey_policy" \ + || die 'sshd does not use the persistent RIGOS host identity' +grep -Fqx 'Requires=rigos-ssh-hostkeys.service' "$ssh_dropin" \ + || die 'ssh.service does not require persistent host identity' +grep -Fqx 'After=rigos-recovery-access.service rigos-ssh-hostkeys.service' "$ssh_dropin" \ + || die 'ssh.service ordering bypasses persistent host identity' +for required in \ + 'STATE = Path("/var/lib/rigos")' \ + 'KEYS = SYSTEM / "ssh-hostkeys"' \ + '"schema": "rigos.ssh-hostkeys/v1"' \ + 'os.rename(temporary, KEYS)' \ + '"persistent SSH host identity exists without a valid manifest"' +do + grep -Fq "$required" "$hostkey_authority" \ + || die "persistent SSH host-key authority contract is missing: $required" +done + for required in \ 'SUPPORTED_CPUS = {("GenuineIntel", 6, 42)}' \ 'REGISTER = 0x1A4' \ @@ -128,4 +174,5 @@ do done printf 'RIGOS RandomX kernel MSR support: %s\n' "$msr_support" +printf 'RIGOS persistent SSH host-key image verification passed\n' printf 'RIGOS RandomX performance image verification passed: %s\n' "$image" From 546f929f733ee4e9a352bdafd89f66d3a85a6c51 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 21:51:28 +0700 Subject: [PATCH 045/132] correct host-key service entrypoint check --- scripts/verify-systemd-ordering.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/verify-systemd-ordering.py b/scripts/verify-systemd-ordering.py index cc1d7c83..a6f84438 100644 --- a/scripts/verify-systemd-ordering.py +++ b/scripts/verify-systemd-ordering.py @@ -79,8 +79,8 @@ def verify(units): includes(hostkeys.words("Unit", "Requires"), {"rigos-state-ready.service"}, "SSH host-key authority must require state readiness") includes(hostkeys.words("Unit", "Before"), {"ssh.service"}, "SSH host-key authority must precede sshd") require( - hostkeys.scalar("Service", "ExecStart") == "/usr/bin/python3", - "SSH host-key authority must use the absolute Python runtime", + hostkeys.scalar("Service", "ExecStart") == "/usr/lib/rigos/rigos-ssh-hostkeys", + "SSH host-key authority entrypoint is not exact", ) includes(hostkeys.words("Install", "WantedBy"), {"multi-user.target"}, "SSH host-key authority must be enabled under multi-user") From 862d5b01ac29857fbf5226181d449e5f19aca8bd Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 21:54:23 +0700 Subject: [PATCH 046/132] verify persistent SSH identity in appliance image --- scripts/verify-usb-appliance.sh | 52 ++++++++++++++++++++++++++++++--- 1 file changed, 48 insertions(+), 4 deletions(-) diff --git a/scripts/verify-usb-appliance.sh b/scripts/verify-usb-appliance.sh index 6fab56fe..f89df2bf 100755 --- a/scripts/verify-usb-appliance.sh +++ b/scripts/verify-usb-appliance.sh @@ -68,17 +68,29 @@ mount -o ro "$p3" "$temporary/b" [[ "$(sha256sum "$p3" | cut -d' ' -f1)" == "$(jq -r .root_b_sha256 "$manifest")" ]] || die 'ROOT_B hash mismatch' cmp "$temporary/a/live/filesystem.squashfs" "$temporary/b/live/filesystem.squashfs" cmp "$temporary/a/image-layout.json" "$temporary/b/image-layout.json" -[[ "$(sha256sum "$temporary/a/live/filesystem.squashfs" | cut -d' ' -f1)" == "$(jq -r .root_payload_sha256 "$manifest")" ]] || die 'root payload hash mismatch' +squashfs="$temporary/a/live/filesystem.squashfs" +[[ "$(sha256sum "$squashfs" | cut -d' ' -f1)" == "$(jq -r .root_payload_sha256 "$manifest")" ]] || die 'root payload hash mismatch' [[ "$(jq -r .schema "$temporary/a/image-layout.json")" == 'rigos.image-layout/v2' ]] || die 'embedded layout schema mismatch' [[ "$(jq -r .partition_table "$temporary/a/image-layout.json")" == mbr ]] || die 'embedded layout table mismatch' [[ "$(jq -r .final_state_partition "$temporary/a/image-layout.json")" == 4 ]] || die 'final state partition mismatch' [[ "$(jq -r '.partitions[-1].label' "$temporary/a/image-layout.json")" == RIGOS_STATE_SEED ]] || die 'state seed is not final' -unsquashfs -no-progress -d "$temporary/root" "$temporary/a/live/filesystem.squashfs" \ + +listing="$temporary/squashfs.list" +unsquashfs -ll "$squashfs" >"$listing" +if awk '{print $NF}' "$listing" | grep -E '^squashfs-root/etc/ssh/ssh_host_.*_key(\.pub)?$' >/dev/null; then + die 'appliance image contains a baked SSH host key' +fi + +unsquashfs -no-progress -d "$temporary/root" "$squashfs" \ etc/rigos-release etc/os-release \ + etc/ssh/sshd_config.d/01-rigos-hostkeys.conf \ usr/lib/tmpfiles.d/rigos.conf \ etc/systemd/system/rigos-state.service \ etc/systemd/system/rigos-state-ready.service \ etc/systemd/system/rigos-recovery-access.service \ + etc/systemd/system/rigos-ssh-hostkeys.service \ + etc/systemd/system/ssh.service.d/rigos-observe.conf \ + etc/systemd/system/multi-user.target.wants/rigos-ssh-hostkeys.service \ etc/systemd/system/rigos-firstboot.service \ etc/systemd/system/rigos-hugepages.service \ etc/systemd/system/rigos-miner.service \ @@ -88,20 +100,23 @@ unsquashfs -no-progress -d "$temporary/root" "$temporary/a/live/filesystem.squas etc/systemd/system/rigos-miner-health.timer \ etc/systemd/system/rigos-runtime-render.service \ etc/systemd/system/rigos-profile-apply.service \ - usr/bin/jq usr/bin/python3 usr/bin/python3.11 \ + usr/bin/jq usr/bin/python3 usr/bin/python3.11 usr/bin/findmnt usr/bin/ssh-keygen \ usr/lib/rigos/rigosd usr/lib/rigos/rigosctl \ - usr/lib/rigos/lsblk-compat usr/lib/rigos/rigos-state-init usr/lib/rigos/rigos-state-ready usr/lib/rigos/rigos-config usr/lib/rigos/rigos-performance usr/lib/rigos/rigos-lifecycle-cycles usr/lib/rigos/rigos-miner-gate usr/lib/rigos/rigos-miner-health usr/lib/rigos/rigos-runtime-render usr/lib/rigos/rigos-runtime-publish usr/lib/rigos/rigos-runtime-authority usr/lib/rigos/rigos-runtime-gate usr/lib/rigos/xmrig \ + usr/lib/rigos/lsblk-compat usr/lib/rigos/rigos-state-init usr/lib/rigos/rigos-state-ready usr/lib/rigos/rigos-config usr/lib/rigos/rigos-performance usr/lib/rigos/rigos-lifecycle-cycles usr/lib/rigos/rigos-miner-gate usr/lib/rigos/rigos-miner-health usr/lib/rigos/rigos-runtime-render usr/lib/rigos/rigos-runtime-publish usr/lib/rigos/rigos-runtime-authority usr/lib/rigos/rigos-runtime-gate usr/lib/rigos/rigos-ssh-hostkeys usr/lib/rigos/xmrig \ usr/local/bin/rigosd usr/local/bin/rigosctl \ usr/local/sbin/rigosctl usr/local/sbin/rigos-firstboot usr/local/sbin/rigos-recovery-access usr/local/sbin/rigos-state-orchestrate \ usr/share/rigos >/dev/null grep -Fqx "VERSION_ID=\"$image_version\"" "$temporary/root/etc/rigos-release" || die 'embedded release version mismatch' grep -q 'NAME="RIGOS"' "$temporary/root/etc/os-release" || die 'embedded OS identity mismatch' [[ -x "$temporary/root/usr/bin/jq" ]] || die 'jq runtime dependency is missing from the appliance' +[[ -x "$temporary/root/usr/bin/findmnt" ]] || die 'findmnt runtime dependency is missing from the appliance' +[[ -x "$temporary/root/usr/bin/ssh-keygen" ]] || die 'ssh-keygen runtime dependency is missing from the appliance' python3 -m py_compile "$temporary/root/usr/local/sbin/rigos-firstboot" python3 -m py_compile "$temporary/root/usr/local/sbin/rigos-recovery-access" python3 -m py_compile "$temporary/root/usr/local/sbin/rigos-state-orchestrate" python3 -m py_compile "$temporary/root/usr/lib/rigos/rigos-miner-gate" python3 -m py_compile "$temporary/root/usr/lib/rigos/rigos-miner-health" +python3 -m py_compile "$temporary/root/usr/lib/rigos/rigos-ssh-hostkeys" sh -n "$temporary/root/usr/lib/rigos/rigos-runtime-publish" sh -n "$temporary/root/usr/lib/rigos/rigos-runtime-authority" python3 "$script_dir/verify-systemd-ordering.py" "$temporary/root/etc/systemd/system" @@ -121,6 +136,35 @@ if strings "$temporary/root/usr/lib/rigos/rigos-state-init" | grep -F '/run/rigo grep -Fq 'ExecStart=/usr/lib/rigos/rigos-state-ready' "$temporary/root/etc/systemd/system/rigos-state-ready.service" || die 'state readiness verifier is not wired' if grep -Fq 'Wants=rigos-recovery-access.service' "$temporary/root/etc/systemd/system/rigos-state-ready.service"; then die 'state readiness retriggers interactive recovery access'; fi grep -Fq 'Requires=rigos-state-ready.service' "$temporary/root/etc/systemd/system/rigos-profile-apply.service" || die 'profile apply bypasses state readiness' + +hostkey_service="$temporary/root/etc/systemd/system/rigos-ssh-hostkeys.service" +hostkey_policy="$temporary/root/etc/ssh/sshd_config.d/01-rigos-hostkeys.conf" +ssh_dropin="$temporary/root/etc/systemd/system/ssh.service.d/rigos-observe.conf" +hostkey_authority="$temporary/root/usr/lib/rigos/rigos-ssh-hostkeys" +[[ -x "$hostkey_authority" ]] || die 'persistent SSH host-key authority is missing or not executable' +[[ -L "$temporary/root/etc/systemd/system/multi-user.target.wants/rigos-ssh-hostkeys.service" ]] || die 'persistent SSH host-key service is not enabled' +for required in \ + 'After=rigos-state-ready.service' \ + 'Requires=rigos-state-ready.service' \ + 'Before=ssh.service' \ + 'ExecStart=/usr/lib/rigos/rigos-ssh-hostkeys' \ + 'ReadWritePaths=/var/lib/rigos /run/rigos' +do + grep -Fqx "$required" "$hostkey_service" || die "persistent SSH host-key service contract is missing: $required" +done +grep -Fqx 'HostKey /var/lib/rigos/system/ssh-hostkeys/ssh_host_ed25519_key' "$hostkey_policy" || die 'sshd persistent HostKey policy is missing' +grep -Fqx 'Requires=rigos-ssh-hostkeys.service' "$ssh_dropin" || die 'ssh.service does not require persistent host identity' +grep -Fqx 'After=rigos-recovery-access.service rigos-ssh-hostkeys.service' "$ssh_dropin" || die 'ssh.service ordering bypasses persistent host identity' +for required in \ + 'STATE = Path("/var/lib/rigos")' \ + 'KEYS = SYSTEM / "ssh-hostkeys"' \ + '"schema": "rigos.ssh-hostkeys/v1"' \ + 'os.rename(temporary, KEYS)' \ + '"persistent SSH host identity exists without a valid manifest"' +do + grep -Fq "$required" "$hostkey_authority" || die "persistent SSH host-key authority contract is missing: $required" +done + [[ -x "$temporary/root/usr/lib/rigos/rigos-performance" ]] || die 'performance authority is missing or not executable' grep -Fq 'After=rigos-state-ready.service rigos-profile-apply.service' "$temporary/root/etc/systemd/system/rigos-hugepages.service" || die 'huge page authority ordering is missing' grep -Fq 'Before=rigos-miner.service' "$temporary/root/etc/systemd/system/rigos-hugepages.service" || die 'huge page authority is not ordered before miner' From f473c2f696b8a9b30e08f5459aeea4a887530bf1 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 22:14:43 +0700 Subject: [PATCH 047/132] add loopback-only authenticated XMRig API authority --- .../usr/lib/rigos/rigos-runtime-render | 77 ++++++++++++++++++- 1 file changed, 76 insertions(+), 1 deletion(-) diff --git a/build/usb/includes.chroot/usr/lib/rigos/rigos-runtime-render b/build/usb/includes.chroot/usr/lib/rigos/rigos-runtime-render index 3effedd9..fca7c8f9 100644 --- a/build/usb/includes.chroot/usr/lib/rigos/rigos-runtime-render +++ b/build/usb/includes.chroot/usr/lib/rigos/rigos-runtime-render @@ -4,6 +4,9 @@ import grp import hashlib import json import os +import re +import secrets +import stat import tempfile from pathlib import Path @@ -12,7 +15,12 @@ RUNTIME = Path(os.environ.get("RIGOS_RUNTIME_PATH", "/run/rigos")) PRIVATE_CONFIG = RUNTIME / "xmrig.json" PUBLIC_CONFIG = RUNTIME / "xmrig-public.json" STATUS = RUNTIME / "runtime-config-status.json" +API_TOKEN = RUNTIME / "xmrig-api-token" +API_HOST = "127.0.0.1" +API_PORT = 18080 MAX_JSON_BYTES = 2 * 1024 * 1024 +TOKEN_RE = re.compile(r"^[A-Za-z0-9_-]{32,128}$") +SKIP_CHOWN = os.environ.get("RIGOS_RENDER_SKIP_CHOWN") == "1" def read_object(path: Path) -> dict: @@ -53,6 +61,57 @@ def atomic_json(path: Path, value: dict, mode: int, gid: int | None = None) -> N temporary.unlink(missing_ok=True) +def token_owner_uid() -> int: + return os.geteuid() if SKIP_CHOWN else 0 + + +def validate_token_descriptor(descriptor: int) -> str: + observed = os.fstat(descriptor) + if not stat.S_ISREG(observed.st_mode): + raise RuntimeError("XMRig API token is not a regular file") + if observed.st_uid != token_owner_uid(): + raise RuntimeError("XMRig API token owner is unsafe") + if stat.S_IMODE(observed.st_mode) != 0o600: + raise RuntimeError("XMRig API token mode is unsafe") + if observed.st_size > 256: + raise RuntimeError("XMRig API token is oversized") + os.lseek(descriptor, 0, os.SEEK_SET) + raw = os.read(descriptor, 257) + try: + token = raw.decode("ascii").strip() + except UnicodeDecodeError as error: + raise RuntimeError("XMRig API token is not ASCII") from error + if not TOKEN_RE.fullmatch(token): + raise RuntimeError("XMRig API token format is invalid") + return token + + +def load_or_create_api_token() -> str: + RUNTIME.mkdir(mode=0o755, parents=True, exist_ok=True) + nofollow = getattr(os, "O_NOFOLLOW", 0) + flags = os.O_RDONLY | os.O_CLOEXEC | nofollow + try: + descriptor = os.open(API_TOKEN, flags) + except FileNotFoundError: + token = secrets.token_urlsafe(48) + if not TOKEN_RE.fullmatch(token): + raise RuntimeError("generated XMRig API token format is invalid") + create_flags = os.O_WRONLY | os.O_CREAT | os.O_EXCL | os.O_CLOEXEC | nofollow + descriptor = os.open(API_TOKEN, create_flags, 0o600) + try: + os.write(descriptor, (token + "\n").encode("ascii")) + os.fsync(descriptor) + finally: + os.close(descriptor) + API_TOKEN.chmod(0o600) + fsync_directory(RUNTIME) + descriptor = os.open(API_TOKEN, flags) + try: + return validate_token_descriptor(descriptor) + finally: + os.close(descriptor) + + def exact_profile_name(algorithm: str) -> str: if algorithm in ("rx", "rx/0"): return "rx" @@ -103,6 +162,15 @@ def render() -> tuple[dict, dict, dict]: elif threads != "auto": raise RuntimeError("threads must be auto or an integer") + api_token = load_or_create_api_token() + runtime["http"] = { + "enabled": True, + "host": API_HOST, + "port": API_PORT, + "access-token": api_token, + "restricted": True, + } + public = copy.deepcopy(runtime) for pool in public.get("pools", []): if isinstance(pool, dict): @@ -142,6 +210,13 @@ def render() -> tuple[dict, dict, dict]: (json.dumps(runtime, sort_keys=True) + "\n").encode("utf-8") ).hexdigest(), "identity_redacted_public_view": True, + "http_api": { + "enabled": True, + "host": API_HOST, + "port": API_PORT, + "restricted": True, + "token_path": str(API_TOKEN), + }, } return runtime, public, status @@ -149,7 +224,7 @@ def render() -> tuple[dict, dict, dict]: def main() -> int: runtime, public, status = render() gid = None - if os.environ.get("RIGOS_RENDER_SKIP_CHOWN") != "1": + if not SKIP_CHOWN: gid = grp.getgrnam("rigos").gr_gid atomic_json(PRIVATE_CONFIG, runtime, 0o640, gid) atomic_json(PUBLIC_CONFIG, public, 0o644) From eb24ace9512c303034f2bb6a2dda7b07e5cd6c00 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 22:15:41 +0700 Subject: [PATCH 048/132] replace journal-only miner health with authenticated XMRig API evidence --- .../usr/lib/rigos/rigos-miner-health | 194 +++++++++++++++++- 1 file changed, 188 insertions(+), 6 deletions(-) diff --git a/build/usb/includes.chroot/usr/lib/rigos/rigos-miner-health b/build/usb/includes.chroot/usr/lib/rigos/rigos-miner-health index 39221147..3fa6be32 100644 --- a/build/usb/includes.chroot/usr/lib/rigos/rigos-miner-health +++ b/build/usb/includes.chroot/usr/lib/rigos/rigos-miner-health @@ -1,8 +1,11 @@ #!/usr/bin/python3 import datetime as dt +import http.client import json +import math import os import re +import stat import subprocess import sys import uuid @@ -15,9 +18,16 @@ PROC = Path(os.environ.get("RIGOS_PROC_ROOT", "/proc")) SYSTEMCTL = os.environ.get("RIGOS_SYSTEMCTL", "/usr/bin/systemctl") JOURNALCTL = os.environ.get("RIGOS_JOURNALCTL", "/usr/bin/journalctl") STATUS = RUNTIME / "miner-health-status.json" +API_TOKEN = Path(os.environ.get("RIGOS_XMRIG_API_TOKEN_PATH", str(RUNTIME / "xmrig-api-token"))) +API_HOST = os.environ.get("RIGOS_XMRIG_API_HOST", "127.0.0.1") +API_PORT = int(os.environ.get("RIGOS_XMRIG_API_PORT", "18080")) +API_TIMEOUT_SECONDS = float(os.environ.get("RIGOS_XMRIG_API_TIMEOUT_SECONDS", "2")) +API_MAX_BYTES = 256 * 1024 +TEST_MODE = os.environ.get("RIGOS_MINER_HEALTH_TEST_MODE") == "1" WINDOW_SECONDS = int(os.environ.get("RIGOS_MINER_HEALTH_WINDOW_SECONDS", "180")) WARMUP_SECONDS = int(os.environ.get("RIGOS_MINER_WARMUP_SECONDS", "240")) MAX_JOURNAL_LINES = 500 +TOKEN_RE = re.compile(r"^[A-Za-z0-9_-]{32,128}$") EXTERNAL_MARKERS = ( "connect error", @@ -43,7 +53,7 @@ def atomic_json(path: Path, value: dict) -> None: handle.flush() os.fsync(handle.fileno()) os.replace(temporary, path) - directory = os.open(path.parent, os.O_RDONLY) + directory = os.open(path.parent, os.O_RDONLY | os.O_DIRECTORY) try: os.fsync(directory) finally: @@ -155,6 +165,148 @@ def last_share_counts(text: str) -> tuple[int | None, int | None]: return int(accepted), int(rejected) +def expected_token_uid() -> int: + return os.geteuid() if TEST_MODE else 0 + + +def read_api_token() -> str: + nofollow = getattr(os, "O_NOFOLLOW", 0) + descriptor = os.open(API_TOKEN, os.O_RDONLY | os.O_CLOEXEC | nofollow) + try: + observed = os.fstat(descriptor) + if not stat.S_ISREG(observed.st_mode): + raise RuntimeError("api_token_not_regular") + if observed.st_uid != expected_token_uid(): + raise RuntimeError("api_token_owner_unsafe") + if stat.S_IMODE(observed.st_mode) != 0o600: + raise RuntimeError("api_token_mode_unsafe") + if observed.st_size > 256: + raise RuntimeError("api_token_oversized") + raw = os.read(descriptor, 257) + finally: + os.close(descriptor) + try: + token = raw.decode("ascii").strip() + except UnicodeDecodeError as error: + raise RuntimeError("api_token_not_ascii") from error + if not TOKEN_RE.fullmatch(token): + raise RuntimeError("api_token_invalid") + return token + + +def fetch_api_summary() -> tuple[dict | None, str | None]: + connection = None + try: + token = read_api_token() + connection = http.client.HTTPConnection( + API_HOST, + API_PORT, + timeout=API_TIMEOUT_SECONDS, + ) + connection.request( + "GET", + "/2/summary", + headers={ + "Accept": "application/json", + "Authorization": f"Bearer {token}", + "Connection": "close", + }, + ) + response = connection.getresponse() + if response.status != 200: + response.read(min(API_MAX_BYTES, 4096)) + return None, f"api_http_status_{response.status}" + length = response.getheader("Content-Length") + if length is not None: + try: + if int(length) > API_MAX_BYTES: + return None, "api_response_oversized" + except ValueError: + return None, "api_content_length_invalid" + raw = response.read(API_MAX_BYTES + 1) + if len(raw) > API_MAX_BYTES: + return None, "api_response_oversized" + value = json.loads(raw) + if not isinstance(value, dict): + return None, "api_response_not_object" + return value, None + except FileNotFoundError: + return None, "api_token_missing" + except PermissionError: + return None, "api_token_permission_denied" + except (OSError, RuntimeError, http.client.HTTPException, json.JSONDecodeError) as error: + message = str(error) + if message.startswith("api_"): + return None, message + return None, "api_unavailable" + finally: + if connection is not None: + connection.close() + + +def nonnegative_number(value: object) -> int | float | None: + if isinstance(value, bool) or not isinstance(value, (int, float)): + return None + if not math.isfinite(float(value)) or value < 0: + return None + return value + + +def summary_metrics(summary: dict) -> dict: + hashrate = summary.get("hashrate") + if not isinstance(hashrate, dict): + hashrate = {} + raw_total = hashrate.get("total") + rates: list[int | float | None] = [None, None, None] + if isinstance(raw_total, list): + for index, value in enumerate(raw_total[:3]): + rates[index] = nonnegative_number(value) + + connection = summary.get("connection") + if not isinstance(connection, dict): + connection = {} + results = summary.get("results") + if not isinstance(results, dict): + results = {} + + accepted = nonnegative_number(connection.get("accepted")) + rejected = nonnegative_number(connection.get("rejected")) + if accepted is None: + accepted = nonnegative_number(results.get("shares_good")) + if rejected is None: + total = nonnegative_number(results.get("shares_total")) + if total is not None and accepted is not None and total >= accepted: + rejected = total - accepted + + pool = connection.get("pool") + if not isinstance(pool, str) or not pool: + pool = None + hugepages = summary.get("hugepages") + hugepages_used = None + hugepages_total = None + if isinstance(hugepages, list) and len(hugepages) >= 2: + hugepages_used = nonnegative_number(hugepages[0]) + hugepages_total = nonnegative_number(hugepages[1]) + + return { + "uptime_seconds": nonnegative_number(summary.get("uptime")), + "algorithm": summary.get("algo") if isinstance(summary.get("algo"), str) else None, + "hashrate_10s": rates[0], + "hashrate_60s": rates[1], + "hashrate_15m": rates[2], + "hashrate_highest": nonnegative_number(hashrate.get("highest")), + "pool_connected": pool is not None, + "pool": pool, + "connection_uptime_seconds": nonnegative_number(connection.get("uptime")), + "connection_failures": nonnegative_number(connection.get("failures")), + "pool_ping_ms": nonnegative_number(connection.get("ping")), + "accepted_shares": int(accepted) if accepted is not None else None, + "rejected_shares": int(rejected) if rejected is not None else None, + "hugepages_used": int(hugepages_used) if hugepages_used is not None else None, + "hugepages_total": int(hugepages_total) if hugepages_total is not None else None, + } + + def classify( properties: dict[str, str], proc_state: str | None, @@ -162,6 +314,8 @@ def classify( canonical_revision: str | None, rendered_outcome: str | None, rendered_revision: str | None, + api_metrics: dict | None, + api_error: str | None, journal: str, journal_available: bool, ) -> tuple[str, str | None]: @@ -177,17 +331,31 @@ def classify( return "blocked", "current_revision_unavailable" if rendered_outcome != "ready" or rendered_revision != canonical_revision: return "blocked", "runtime_revision_mismatch" - if not journal_available: - return "unknown", "journal_unavailable" + if api_metrics is not None: + rates = ( + api_metrics.get("hashrate_10s"), + api_metrics.get("hashrate_60s"), + api_metrics.get("hashrate_15m"), + ) + if any(isinstance(value, (int, float)) and value > 0 for value in rates): + return "ready", None + if active_for is not None and active_for < WARMUP_SECONDS: + return "warming_up", None + if not api_metrics.get("pool_connected"): + return "waiting_external", "pool_or_network_unavailable" + return "degraded", "no_hashrate_from_api" + + if not journal_available: + return "unknown", api_error or "journal_unavailable" lowered = journal.lower() - if "miner speed" in lowered: + if "miner speed" in lowered or "accepted (" in lowered: return "ready", None if any(marker in lowered for marker in EXTERNAL_MARKERS): return "waiting_external", "pool_or_network_unavailable" if active_for is not None and active_for < WARMUP_SECONDS: return "warming_up", None - return "degraded", "no_recent_speed_evidence" + return "degraded", api_error or "miner_api_unavailable" def main() -> int: @@ -204,8 +372,10 @@ def main() -> int: active_for = active_seconds(properties) canonical = current_revision() rendered_outcome, rendered_revision = runtime_revision() + summary, api_error = fetch_api_summary() + metrics = summary_metrics(summary) if summary is not None else None journal, journal_available = recent_journal() - accepted, rejected = last_share_counts(journal) + journal_accepted, journal_rejected = last_share_counts(journal) state, reason = classify( properties, proc_state, @@ -213,10 +383,14 @@ def main() -> int: canonical, rendered_outcome, rendered_revision, + metrics, + api_error, journal, journal_available, ) lowered_journal = journal.lower() + accepted = metrics.get("accepted_shares") if metrics is not None else journal_accepted + rejected = metrics.get("rejected_shares") if metrics is not None else journal_rejected value = { "schema": "rigos.miner-health-status/v1", "generated_at": dt.datetime.now(dt.timezone.utc).isoformat(timespec="milliseconds"), @@ -238,7 +412,14 @@ def main() -> int: "runtime_outcome": rendered_outcome, "runtime_revision": rendered_revision, }, + "api": { + "available": metrics is not None, + "error": api_error, + "endpoint": f"http://{API_HOST}:{API_PORT}/2/summary", + "metrics": metrics, + }, "evidence": { + "source": "xmrig_http_api" if metrics is not None else "journal_fallback", "window_seconds": WINDOW_SECONDS, "journal_available": journal_available, "journal_line_limit": MAX_JOURNAL_LINES, @@ -256,6 +437,7 @@ def main() -> int: "schema": "rigos.miner-health-observer/v1", "state": state, "reason": reason, + "evidence_source": value["evidence"]["source"], "remediation": "observe_only", }, sort_keys=True)) return 0 From 3e0d64b3279b6f38d575bebba0d3e24bfb389042 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 22:15:57 +0700 Subject: [PATCH 049/132] allow miner observer to query loopback XMRig API only --- .../etc/systemd/system/rigos-miner-health.service | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/build/usb/includes.chroot/etc/systemd/system/rigos-miner-health.service b/build/usb/includes.chroot/etc/systemd/system/rigos-miner-health.service index bd3523ea..9715a89e 100644 --- a/build/usb/includes.chroot/etc/systemd/system/rigos-miner-health.service +++ b/build/usb/includes.chroot/etc/systemd/system/rigos-miner-health.service @@ -12,7 +12,9 @@ ProtectSystem=strict ProtectKernelTunables=yes ProtectKernelModules=yes ProtectControlGroups=yes -RestrictAddressFamilies=AF_UNIX +RestrictAddressFamilies=AF_UNIX AF_INET +IPAddressDeny=any +IPAddressAllow=127.0.0.0/8 RestrictNamespaces=yes LockPersonality=yes ReadWritePaths=/run/rigos From fdd43b70e3aa2d9340d11b1ffb694dc2bd99e708 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 22:16:46 +0700 Subject: [PATCH 050/132] test authenticated XMRig API health evidence --- scripts/test-miner-health-api.py | 267 +++++++++++++++++++++++++++++++ 1 file changed, 267 insertions(+) create mode 100644 scripts/test-miner-health-api.py diff --git a/scripts/test-miner-health-api.py b/scripts/test-miner-health-api.py new file mode 100644 index 00000000..d2068cbe --- /dev/null +++ b/scripts/test-miner-health-api.py @@ -0,0 +1,267 @@ +#!/usr/bin/env python3 +import importlib.machinery +import importlib.util +import json +import os +import stat +import tempfile +import threading +import unittest +from http.server import BaseHTTPRequestHandler, HTTPServer +from pathlib import Path + +ROOT = Path(__file__).resolve().parents[1] +RUNTIME_RENDER = ROOT / "build/usb/includes.chroot/usr/lib/rigos/rigos-runtime-render" +MINER_HEALTH = ROOT / "build/usb/includes.chroot/usr/lib/rigos/rigos-miner-health" + + +def load_source(name: str, path: Path): + loader = importlib.machinery.SourceFileLoader(name, str(path)) + spec = importlib.util.spec_from_loader(name, loader) + if spec is None: + raise RuntimeError(f"could not load {path}") + module = importlib.util.module_from_spec(spec) + loader.exec_module(module) + return module + + +class Environment: + def __init__(self, **values: str): + self.values = values + self.original: dict[str, str | None] = {} + + def __enter__(self): + for key, value in self.values.items(): + self.original[key] = os.environ.get(key) + os.environ[key] = value + return self + + def __exit__(self, _type, _value, _traceback): + for key, value in self.original.items(): + if value is None: + os.environ.pop(key, None) + else: + os.environ[key] = value + + +class RuntimeRenderApiTests(unittest.TestCase): + def test_runtime_api_is_local_authenticated_redacted_and_idempotent(self): + with tempfile.TemporaryDirectory(prefix="rigos-render-api-") as temporary: + root = Path(temporary) + state = root / "state" + runtime = root / "run" + revision = state / "revisions/r1" + (revision / "flight-sheets").mkdir(parents=True) + (revision / "policy.json").write_text( + json.dumps({ + "schema": "rigos.policy/v1", + "active_flight_sheet": "sheet", + }), + encoding="utf-8", + ) + (revision / "flight-sheets/sheet.json").write_text( + json.dumps({ + "schema": "rigos.flight-sheet/v1", + "backend": "xmrig", + "algorithm": "rx/0", + "cpu": {"threads": "auto"}, + }), + encoding="utf-8", + ) + (revision / "xmrig.json").write_text( + json.dumps({ + "autosave": False, + "cpu": {"enabled": True, "huge-pages": True}, + "pools": [{ + "url": "pool.example:1234", + "user": "secret-wallet", + "pass": "worker", + "algo": "rx/0", + }], + "http": { + "enabled": True, + "host": "0.0.0.0", + "port": 9999, + "access-token": "attacker-controlled", + "restricted": False, + }, + }), + encoding="utf-8", + ) + state.mkdir(exist_ok=True) + (state / "current").symlink_to("revisions/r1") + + with Environment( + RIGOS_STATE_PATH=str(state), + RIGOS_RUNTIME_PATH=str(runtime), + RIGOS_RENDER_SKIP_CHOWN="1", + ): + module = load_source("rigos_runtime_render_test", RUNTIME_RENDER) + private_first, public_first, status_first = module.render() + token_path = runtime / "xmrig-api-token" + token_first = token_path.read_text(encoding="ascii").strip() + + self.assertEqual(private_first["http"]["host"], "127.0.0.1") + self.assertEqual(private_first["http"]["port"], 18080) + self.assertTrue(private_first["http"]["enabled"]) + self.assertTrue(private_first["http"]["restricted"]) + self.assertEqual(private_first["http"]["access-token"], token_first) + self.assertNotIn("access-token", public_first["http"]) + self.assertNotIn("secret-wallet", json.dumps(public_first)) + self.assertEqual(status_first["http_api"]["host"], "127.0.0.1") + self.assertEqual(status_first["http_api"]["port"], 18080) + self.assertNotIn(token_first, json.dumps(status_first)) + self.assertEqual(stat.S_IMODE(token_path.stat().st_mode), 0o600) + + private_second, _, _ = module.render() + self.assertEqual(private_second["http"]["access-token"], token_first) + self.assertEqual(token_path.read_text(encoding="ascii").strip(), token_first) + + self.assertEqual(module.main(), 0) + self.assertEqual(stat.S_IMODE((runtime / "xmrig.json").stat().st_mode), 0o640) + self.assertEqual(stat.S_IMODE((runtime / "xmrig-public.json").stat().st_mode), 0o644) + persisted_public = json.loads((runtime / "xmrig-public.json").read_text(encoding="utf-8")) + self.assertNotIn("access-token", persisted_public["http"]) + + +class SummaryHandler(BaseHTTPRequestHandler): + expected_token = "" + summary: dict = {} + + def do_GET(self): + if self.path != "/2/summary": + self.send_response(404) + self.end_headers() + return + if self.headers.get("Authorization") != f"Bearer {self.expected_token}": + self.send_response(401) + self.end_headers() + return + payload = json.dumps(self.summary).encode("utf-8") + self.send_response(200) + self.send_header("Content-Type", "application/json") + self.send_header("Content-Length", str(len(payload))) + self.end_headers() + self.wfile.write(payload) + + def log_message(self, _format, *_args): + return + + +class MinerHealthApiTests(unittest.TestCase): + def test_authenticated_summary_drives_health_truth(self): + with tempfile.TemporaryDirectory(prefix="rigos-health-api-") as temporary: + root = Path(temporary) + token = "A" * 48 + token_path = root / "xmrig-api-token" + token_path.write_text(token + "\n", encoding="ascii") + token_path.chmod(0o600) + + SummaryHandler.expected_token = token + SummaryHandler.summary = { + "uptime": 600, + "algo": "rx/0", + "hashrate": {"total": [341.2, 340.9, 340.7], "highest": 342.1}, + "connection": { + "pool": "pool.example:1234", + "uptime": 590, + "accepted": 43, + "rejected": 0, + "failures": 1, + "ping": 109, + }, + "hugepages": [1168, 1168], + } + server = HTTPServer(("127.0.0.1", 0), SummaryHandler) + thread = threading.Thread(target=server.serve_forever, daemon=True) + thread.start() + try: + with Environment( + RIGOS_XMRIG_API_TOKEN_PATH=str(token_path), + RIGOS_XMRIG_API_HOST="127.0.0.1", + RIGOS_XMRIG_API_PORT=str(server.server_port), + RIGOS_MINER_HEALTH_TEST_MODE="1", + ): + module = load_source("rigos_miner_health_test", MINER_HEALTH) + summary, error = module.fetch_api_summary() + self.assertIsNone(error) + self.assertIsNotNone(summary) + metrics = module.summary_metrics(summary) + self.assertEqual(metrics["hashrate_60s"], 340.9) + self.assertEqual(metrics["accepted_shares"], 43) + self.assertEqual(metrics["rejected_shares"], 0) + self.assertTrue(metrics["pool_connected"]) + self.assertEqual(metrics["hugepages_used"], 1168) + self.assertEqual(metrics["hugepages_total"], 1168) + + state, reason = module.classify( + {"ActiveState": "active", "SubState": "running", "MainPID": "123"}, + "S", + 600, + "r1", + "ready", + "r1", + metrics, + None, + "", + True, + ) + self.assertEqual((state, reason), ("ready", None)) + + no_pool = dict(metrics) + no_pool.update({ + "hashrate_10s": 0, + "hashrate_60s": 0, + "hashrate_15m": 0, + "pool_connected": False, + "pool": None, + }) + state, reason = module.classify( + {"ActiveState": "active", "SubState": "running", "MainPID": "123"}, + "S", + 600, + "r1", + "ready", + "r1", + no_pool, + None, + "", + True, + ) + self.assertEqual((state, reason), ("waiting_external", "pool_or_network_unavailable")) + + state, reason = module.classify( + {"ActiveState": "active", "SubState": "running", "MainPID": "123"}, + "S", + 600, + "r1", + "ready", + "r1", + None, + "api_unavailable", + "cpu accepted (43/0) diff 10000", + True, + ) + self.assertEqual((state, reason), ("ready", None)) + + state, reason = module.classify( + {"ActiveState": "active", "SubState": "running", "MainPID": "123"}, + "S", + 600, + "r1", + "ready", + "r1", + None, + "api_unavailable", + "", + True, + ) + self.assertEqual((state, reason), ("degraded", "api_unavailable")) + finally: + server.shutdown() + server.server_close() + thread.join(timeout=5) + + +if __name__ == "__main__": + unittest.main(verbosity=2) From c89b2cbb65697549b0ff4a2b2fd6217904aedd46 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 22:17:11 +0700 Subject: [PATCH 051/132] run authenticated miner observer regression before image build --- scripts/build-usb-image-entrypoint.sh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/scripts/build-usb-image-entrypoint.sh b/scripts/build-usb-image-entrypoint.sh index 4d31eba2..ea81718e 100644 --- a/scripts/build-usb-image-entrypoint.sh +++ b/scripts/build-usb-image-entrypoint.sh @@ -24,7 +24,11 @@ python3 ./scripts/verify-systemd-ordering.py python3 -m py_compile \ ./build/usb/includes.chroot/usr/lib/rigos/rigos-randomx-msr \ ./build/usb/includes.chroot/usr/lib/rigos/rigos-miner-gate \ - ./build/usb/includes.chroot/usr/lib/rigos/rigos-ssh-hostkeys + ./build/usb/includes.chroot/usr/lib/rigos/rigos-ssh-hostkeys \ + ./build/usb/includes.chroot/usr/lib/rigos/rigos-runtime-render \ + ./build/usb/includes.chroot/usr/lib/rigos/rigos-miner-health \ + ./scripts/test-miner-health-api.py +python3 ./scripts/test-miner-health-api.py export CARGO_TARGET_DIR=/work/rigos-performance-preflight-target cargo test --locked -p rigos-config --test randomx_build_entrypoint -- --nocapture From c1301af43f78d75f98e2ff4e3ef0e60a6a76c8e7 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 22:17:37 +0700 Subject: [PATCH 052/132] add exact-image verifier for authenticated miner telemetry --- scripts/verify-miner-observer-image.sh | 95 ++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 scripts/verify-miner-observer-image.sh diff --git a/scripts/verify-miner-observer-image.sh b/scripts/verify-miner-observer-image.sh new file mode 100644 index 00000000..0f14168c --- /dev/null +++ b/scripts/verify-miner-observer-image.sh @@ -0,0 +1,95 @@ +#!/bin/bash +set -euo pipefail + +die() { + printf 'verify-miner-observer-image: %s\n' "$*" >&2 + exit 1 +} + +[[ $# -eq 1 ]] || die 'usage: verify-miner-observer-image.sh ' +image="$(readlink -f "$1")" +[[ -f "$image" ]] || die "image is missing: $image" +[[ "$(id -u)" -eq 0 ]] || die 'must run as root' + +partition_json="$(sfdisk --json "$image")" +start="$(jq -r '.partitiontable.partitions[1].start' <<<"$partition_json")" +size="$(jq -r '.partitiontable.partitions[1].size' <<<"$partition_json")" +[[ "$start" =~ ^[0-9]+$ && "$size" =~ ^[0-9]+$ ]] || die 'ROOT_A geometry is invalid' + +loop="$(losetup --find --show --read-only --offset $((start * 512)) --sizelimit $((size * 512)) "$image")" +temporary="$(mktemp -d)" +cleanup() { + set +e + mountpoint -q "$temporary/root-a" && umount "$temporary/root-a" + losetup -d "$loop" 2>/dev/null + rm -rf "$temporary" +} +trap cleanup EXIT + +mkdir -p "$temporary/root-a" "$temporary/squash" +mount -o ro "$loop" "$temporary/root-a" +squashfs="$temporary/root-a/live/filesystem.squashfs" +[[ -f "$squashfs" ]] || die 'ROOT_A squashfs is missing' + +unsquashfs -no-progress -d "$temporary/squash" "$squashfs" \ + usr/bin/python3 usr/bin/python3.11 \ + usr/lib/rigos/rigos-runtime-render \ + usr/lib/rigos/rigos-miner-health \ + etc/systemd/system/rigos-miner-health.service \ + etc/systemd/system/rigos-miner-health.timer \ + etc/systemd/system/rigos-runtime-render.service \ + >/dev/null + +root="$temporary/squash" +renderer="$root/usr/lib/rigos/rigos-runtime-render" +observer="$root/usr/lib/rigos/rigos-miner-health" +service="$root/etc/systemd/system/rigos-miner-health.service" +timer="$root/etc/systemd/system/rigos-miner-health.timer" + +[[ -x "$root/usr/bin/python3" ]] || die 'Python runtime is missing' +[[ -x "$renderer" ]] || die 'runtime renderer is missing or not executable' +[[ -x "$observer" ]] || die 'miner observer is missing or not executable' +python3 -m py_compile "$renderer" "$observer" + +for required in \ + 'API_TOKEN = RUNTIME / "xmrig-api-token"' \ + 'API_HOST = "127.0.0.1"' \ + 'API_PORT = 18080' \ + 'token = secrets.token_urlsafe(48)' \ + '"access-token": api_token' \ + '"restricted": True' \ + 'http.pop("access-token", None)' \ + '"token_path": str(API_TOKEN)' +do + grep -Fq "$required" "$renderer" || die "runtime API authority contract is missing: $required" +done +if grep -Eq 'API_HOST = "(0\.0\.0\.0|::)"' "$renderer"; then + die 'runtime API authority exposes a non-loopback bind' +fi + +for required in \ + 'connection.request(' \ + '"/2/summary"' \ + '"Authorization": f"Bearer {token}"' \ + 'API_MAX_BYTES = 256 * 1024' \ + '"source": "xmrig_http_api" if metrics is not None else "journal_fallback"' \ + 'return "degraded", "no_hashrate_from_api"' \ + 'return "degraded", api_error or "miner_api_unavailable"' +do + grep -Fq "$required" "$observer" || die "miner observer API contract is missing: $required" +done + +for required in \ + 'ExecStart=/usr/bin/python3 /usr/lib/rigos/rigos-miner-health' \ + 'RestrictAddressFamilies=AF_UNIX AF_INET' \ + 'IPAddressDeny=any' \ + 'IPAddressAllow=127.0.0.0/8' \ + 'ReadWritePaths=/run/rigos' +do + grep -Fqx "$required" "$service" || die "miner observer sandbox contract is missing: $required" +done +grep -Fq 'OnUnitActiveSec=1min' "$timer" || die 'miner observer timer cadence is missing' +grep -Fq 'ExecStart=/usr/lib/rigos/rigos-runtime-authority' "$root/etc/systemd/system/rigos-runtime-render.service" \ + || die 'serialized runtime authority is not wired' + +printf 'RIGOS authenticated XMRig observer image verification passed: %s\n' "$image" From adeb6faec0cdc7732516b657c4f31ab57b7d861c Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 22:17:50 +0700 Subject: [PATCH 053/132] gate image build on authenticated miner observer verifier --- scripts/build-usb-image-entrypoint.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/build-usb-image-entrypoint.sh b/scripts/build-usb-image-entrypoint.sh index ea81718e..380ab2c7 100644 --- a/scripts/build-usb-image-entrypoint.sh +++ b/scripts/build-usb-image-entrypoint.sh @@ -38,3 +38,4 @@ cargo test --locked -p rigos-config --test randomx_msr_authority -- --nocapture image="./dist/usb/${RIGOS_IMAGE_ID}-${RIGOS_IMAGE_VERSION}.img" bash ./scripts/verify-randomx-performance-image.sh "$image" +bash ./scripts/verify-miner-observer-image.sh "$image" From 943dbb3adf3cb4f1622b1b1888c550650df1fb0c Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 22:53:55 +0700 Subject: [PATCH 054/132] keep xmrig api token outside render staging --- .../usb/includes.chroot/usr/lib/rigos/rigos-runtime-render | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/build/usb/includes.chroot/usr/lib/rigos/rigos-runtime-render b/build/usb/includes.chroot/usr/lib/rigos/rigos-runtime-render index fca7c8f9..c1f1bdce 100644 --- a/build/usb/includes.chroot/usr/lib/rigos/rigos-runtime-render +++ b/build/usb/includes.chroot/usr/lib/rigos/rigos-runtime-render @@ -15,7 +15,7 @@ RUNTIME = Path(os.environ.get("RIGOS_RUNTIME_PATH", "/run/rigos")) PRIVATE_CONFIG = RUNTIME / "xmrig.json" PUBLIC_CONFIG = RUNTIME / "xmrig-public.json" STATUS = RUNTIME / "runtime-config-status.json" -API_TOKEN = RUNTIME / "xmrig-api-token" +API_TOKEN = Path(os.environ.get("RIGOS_XMRIG_API_TOKEN_PATH", str(RUNTIME / "xmrig-api-token"))) API_HOST = "127.0.0.1" API_PORT = 18080 MAX_JSON_BYTES = 2 * 1024 * 1024 @@ -87,7 +87,7 @@ def validate_token_descriptor(descriptor: int) -> str: def load_or_create_api_token() -> str: - RUNTIME.mkdir(mode=0o755, parents=True, exist_ok=True) + API_TOKEN.parent.mkdir(mode=0o755, parents=True, exist_ok=True) nofollow = getattr(os, "O_NOFOLLOW", 0) flags = os.O_RDONLY | os.O_CLOEXEC | nofollow try: @@ -104,7 +104,7 @@ def load_or_create_api_token() -> str: finally: os.close(descriptor) API_TOKEN.chmod(0o600) - fsync_directory(RUNTIME) + fsync_directory(API_TOKEN.parent) descriptor = os.open(API_TOKEN, flags) try: return validate_token_descriptor(descriptor) From db5da19919066b73805ae4ab2fc65903775116ec Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 22:54:10 +0700 Subject: [PATCH 055/132] wire persistent xmrig api token authority --- build/usb/includes.chroot/usr/lib/rigos/rigos-runtime-publish | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/build/usb/includes.chroot/usr/lib/rigos/rigos-runtime-publish b/build/usb/includes.chroot/usr/lib/rigos/rigos-runtime-publish index c0aa5740..7e3611bc 100644 --- a/build/usb/includes.chroot/usr/lib/rigos/rigos-runtime-publish +++ b/build/usb/includes.chroot/usr/lib/rigos/rigos-runtime-publish @@ -24,7 +24,9 @@ cleanup() { } trap cleanup EXIT HUP INT TERM -RIGOS_RUNTIME_PATH="$stage" "$renderer" +RIGOS_RUNTIME_PATH="$stage" \ +RIGOS_XMRIG_API_TOKEN_PATH="$runtime/xmrig-api-token" \ + "$renderer" "$jq_bin" -e ' .schema == "rigos.runtime-config-status/v1" and From a995812cc9d1e7598004ef7b78e26aee9a95b6be Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 22:54:32 +0700 Subject: [PATCH 056/132] test runtime token publication across staging cleanup --- scripts/test-runtime-token-publication.py | 145 ++++++++++++++++++++++ 1 file changed, 145 insertions(+) create mode 100644 scripts/test-runtime-token-publication.py diff --git a/scripts/test-runtime-token-publication.py b/scripts/test-runtime-token-publication.py new file mode 100644 index 00000000..2df1a71a --- /dev/null +++ b/scripts/test-runtime-token-publication.py @@ -0,0 +1,145 @@ +#!/usr/bin/env python3 +import importlib.machinery +import importlib.util +import json +import os +import shutil +import stat +import tempfile +import unittest +from pathlib import Path + +ROOT = Path(__file__).resolve().parents[1] +RENDERER = ROOT / "build/usb/includes.chroot/usr/lib/rigos/rigos-runtime-render" +PUBLISHER = ROOT / "build/usb/includes.chroot/usr/lib/rigos/rigos-runtime-publish" + + +def load_source(name: str, path: Path): + loader = importlib.machinery.SourceFileLoader(name, str(path)) + spec = importlib.util.spec_from_loader(name, loader) + if spec is None: + raise RuntimeError(f"could not load {path}") + module = importlib.util.module_from_spec(spec) + loader.exec_module(module) + return module + + +class Environment: + def __init__(self, **values: str): + self.values = values + self.original: dict[str, str | None] = {} + + def __enter__(self): + for key, value in self.values.items(): + self.original[key] = os.environ.get(key) + os.environ[key] = value + return self + + def __exit__(self, _type, _value, _traceback): + for key, value in self.original.items(): + if value is None: + os.environ.pop(key, None) + else: + os.environ[key] = value + + +def create_state(root: Path) -> Path: + state = root / "state" + revision = state / "revisions/r1" + (revision / "flight-sheets").mkdir(parents=True) + (revision / "policy.json").write_text( + json.dumps({ + "schema": "rigos.policy/v1", + "active_flight_sheet": "sheet", + }), + encoding="utf-8", + ) + (revision / "flight-sheets/sheet.json").write_text( + json.dumps({ + "schema": "rigos.flight-sheet/v1", + "backend": "xmrig", + "algorithm": "rx/0", + "cpu": {"threads": "auto"}, + }), + encoding="utf-8", + ) + (revision / "xmrig.json").write_text( + json.dumps({ + "autosave": False, + "cpu": {"enabled": True, "huge-pages": True}, + "pools": [{ + "url": "pool.example:1234", + "user": "secret-wallet", + "pass": "worker", + "algo": "rx/0", + }], + }), + encoding="utf-8", + ) + (state / "current").symlink_to("revisions/r1") + return state + + +class RuntimeTokenPublicationTests(unittest.TestCase): + def test_token_survives_render_stage_cleanup_and_is_reused(self): + with tempfile.TemporaryDirectory(prefix="rigos-token-publication-") as temporary: + root = Path(temporary) + state = create_state(root) + authority_runtime = root / "runtime" + token_path = authority_runtime / "xmrig-api-token" + first_stage = authority_runtime / ".render-stage.first" + first_stage.mkdir(parents=True) + + with Environment( + RIGOS_STATE_PATH=str(state), + RIGOS_RUNTIME_PATH=str(first_stage), + RIGOS_XMRIG_API_TOKEN_PATH=str(token_path), + RIGOS_RENDER_SKIP_CHOWN="1", + ): + first = load_source("rigos_runtime_render_publication_first", RENDERER) + self.assertEqual(first.API_TOKEN, token_path) + self.assertEqual(first.main(), 0) + + self.assertTrue(token_path.is_file()) + self.assertEqual(stat.S_IMODE(token_path.stat().st_mode), 0o600) + self.assertFalse((first_stage / "xmrig-api-token").exists()) + token_first = token_path.read_text(encoding="ascii").strip() + private_first = json.loads((first_stage / "xmrig.json").read_text(encoding="utf-8")) + status_first = json.loads( + (first_stage / "runtime-config-status.json").read_text(encoding="utf-8") + ) + self.assertEqual(private_first["http"]["access-token"], token_first) + self.assertEqual(status_first["http_api"]["token_path"], str(token_path)) + + shutil.rmtree(first_stage) + self.assertTrue(token_path.is_file()) + + second_stage = authority_runtime / ".render-stage.second" + second_stage.mkdir() + with Environment( + RIGOS_STATE_PATH=str(state), + RIGOS_RUNTIME_PATH=str(second_stage), + RIGOS_XMRIG_API_TOKEN_PATH=str(token_path), + RIGOS_RENDER_SKIP_CHOWN="1", + ): + second = load_source("rigos_runtime_render_publication_second", RENDERER) + self.assertEqual(second.main(), 0) + + private_second = json.loads((second_stage / "xmrig.json").read_text(encoding="utf-8")) + self.assertEqual(private_second["http"]["access-token"], token_first) + self.assertEqual(token_path.read_text(encoding="ascii").strip(), token_first) + shutil.rmtree(second_stage) + self.assertTrue(token_path.is_file()) + + def test_publisher_wires_authority_token_outside_stage(self): + publisher = PUBLISHER.read_text(encoding="utf-8") + self.assertIn('RIGOS_RUNTIME_PATH="$stage" \\\n', publisher) + self.assertIn( + 'RIGOS_XMRIG_API_TOKEN_PATH="$runtime/xmrig-api-token" \\\n', + publisher, + ) + self.assertIn(' "$renderer"\n', publisher) + + +if __name__ == "__main__": + unittest.main(verbosity=2) From 4bfc023625243a3d655c6a88a68fa41b8d97230b Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 22:54:43 +0700 Subject: [PATCH 057/132] gate image build on token publication regression --- scripts/build-usb-image-entrypoint.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/scripts/build-usb-image-entrypoint.sh b/scripts/build-usb-image-entrypoint.sh index 380ab2c7..2aa57c81 100644 --- a/scripts/build-usb-image-entrypoint.sh +++ b/scripts/build-usb-image-entrypoint.sh @@ -27,8 +27,10 @@ python3 -m py_compile \ ./build/usb/includes.chroot/usr/lib/rigos/rigos-ssh-hostkeys \ ./build/usb/includes.chroot/usr/lib/rigos/rigos-runtime-render \ ./build/usb/includes.chroot/usr/lib/rigos/rigos-miner-health \ - ./scripts/test-miner-health-api.py + ./scripts/test-miner-health-api.py \ + ./scripts/test-runtime-token-publication.py python3 ./scripts/test-miner-health-api.py +python3 ./scripts/test-runtime-token-publication.py export CARGO_TARGET_DIR=/work/rigos-performance-preflight-target cargo test --locked -p rigos-config --test randomx_build_entrypoint -- --nocapture From 898aece00fec7cf95e313011e676efad2a1952bd Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 22:54:59 +0700 Subject: [PATCH 058/132] verify token publication in exact image --- scripts/verify-miner-observer-image.sh | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/scripts/verify-miner-observer-image.sh b/scripts/verify-miner-observer-image.sh index 0f14168c..ff11e89c 100644 --- a/scripts/verify-miner-observer-image.sh +++ b/scripts/verify-miner-observer-image.sh @@ -34,6 +34,7 @@ squashfs="$temporary/root-a/live/filesystem.squashfs" unsquashfs -no-progress -d "$temporary/squash" "$squashfs" \ usr/bin/python3 usr/bin/python3.11 \ usr/lib/rigos/rigos-runtime-render \ + usr/lib/rigos/rigos-runtime-publish \ usr/lib/rigos/rigos-miner-health \ etc/systemd/system/rigos-miner-health.service \ etc/systemd/system/rigos-miner-health.timer \ @@ -42,17 +43,19 @@ unsquashfs -no-progress -d "$temporary/squash" "$squashfs" \ root="$temporary/squash" renderer="$root/usr/lib/rigos/rigos-runtime-render" +publisher="$root/usr/lib/rigos/rigos-runtime-publish" observer="$root/usr/lib/rigos/rigos-miner-health" service="$root/etc/systemd/system/rigos-miner-health.service" timer="$root/etc/systemd/system/rigos-miner-health.timer" [[ -x "$root/usr/bin/python3" ]] || die 'Python runtime is missing' [[ -x "$renderer" ]] || die 'runtime renderer is missing or not executable' +[[ -x "$publisher" ]] || die 'runtime publisher is missing or not executable' [[ -x "$observer" ]] || die 'miner observer is missing or not executable' python3 -m py_compile "$renderer" "$observer" for required in \ - 'API_TOKEN = RUNTIME / "xmrig-api-token"' \ + 'API_TOKEN = Path(os.environ.get("RIGOS_XMRIG_API_TOKEN_PATH", str(RUNTIME / "xmrig-api-token")))' \ 'API_HOST = "127.0.0.1"' \ 'API_PORT = 18080' \ 'token = secrets.token_urlsafe(48)' \ @@ -67,6 +70,14 @@ if grep -Eq 'API_HOST = "(0\.0\.0\.0|::)"' "$renderer"; then die 'runtime API authority exposes a non-loopback bind' fi +for required in \ + 'RIGOS_RUNTIME_PATH="$stage" \' \ + 'RIGOS_XMRIG_API_TOKEN_PATH="$runtime/xmrig-api-token" \' \ + ' "$renderer"' +do + grep -Fqx "$required" "$publisher" || die "runtime token publication contract is missing: $required" +done + for required in \ 'connection.request(' \ '"/2/summary"' \ From c6a4c5092e36da5b2b9e9770b60cc98966c73034 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 22:59:19 +0700 Subject: [PATCH 059/132] derive pool connectivity from active connection evidence --- .../usr/lib/rigos/rigos-miner-health | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/build/usb/includes.chroot/usr/lib/rigos/rigos-miner-health b/build/usb/includes.chroot/usr/lib/rigos/rigos-miner-health index 3fa6be32..4e7e873c 100644 --- a/build/usb/includes.chroot/usr/lib/rigos/rigos-miner-health +++ b/build/usb/includes.chroot/usr/lib/rigos/rigos-miner-health @@ -281,6 +281,17 @@ def summary_metrics(summary: dict) -> dict: pool = connection.get("pool") if not isinstance(pool, str) or not pool: pool = None + connection_ip = connection.get("ip") + if not isinstance(connection_ip, str) or not connection_ip: + connection_ip = None + connection_uptime_seconds = nonnegative_number(connection.get("uptime")) + connection_uptime_ms = nonnegative_number(connection.get("uptime_ms")) + pool_connected = pool is not None and ( + connection_ip is not None + or (connection_uptime_ms is not None and connection_uptime_ms > 0) + or (connection_uptime_seconds is not None and connection_uptime_seconds > 0) + ) + hugepages = summary.get("hugepages") hugepages_used = None hugepages_total = None @@ -295,9 +306,11 @@ def summary_metrics(summary: dict) -> dict: "hashrate_60s": rates[1], "hashrate_15m": rates[2], "hashrate_highest": nonnegative_number(hashrate.get("highest")), - "pool_connected": pool is not None, + "pool_connected": pool_connected, "pool": pool, - "connection_uptime_seconds": nonnegative_number(connection.get("uptime")), + "connection_ip": connection_ip, + "connection_uptime_seconds": connection_uptime_seconds, + "connection_uptime_ms": connection_uptime_ms, "connection_failures": nonnegative_number(connection.get("failures")), "pool_ping_ms": nonnegative_number(connection.get("ping")), "accepted_shares": int(accepted) if accepted is not None else None, From 9c49e027c01e4984cafc9156b938fb665d0b6d79 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 22:59:33 +0700 Subject: [PATCH 060/132] test stale pool connection classification --- scripts/test-miner-health-connection-state.py | 104 ++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 scripts/test-miner-health-connection-state.py diff --git a/scripts/test-miner-health-connection-state.py b/scripts/test-miner-health-connection-state.py new file mode 100644 index 00000000..490c67a7 --- /dev/null +++ b/scripts/test-miner-health-connection-state.py @@ -0,0 +1,104 @@ +#!/usr/bin/env python3 +import importlib.machinery +import importlib.util +import unittest +from pathlib import Path + +ROOT = Path(__file__).resolve().parents[1] +MINER_HEALTH = ROOT / "build/usb/includes.chroot/usr/lib/rigos/rigos-miner-health" + + +def load_source(name: str, path: Path): + loader = importlib.machinery.SourceFileLoader(name, str(path)) + spec = importlib.util.spec_from_loader(name, loader) + if spec is None: + raise RuntimeError(f"could not load {path}") + module = importlib.util.module_from_spec(spec) + loader.exec_module(module) + return module + + +def classify(module, metrics): + return module.classify( + {"ActiveState": "active", "SubState": "running", "MainPID": "123"}, + "S", + 600, + "r1", + "ready", + "r1", + metrics, + None, + "", + True, + ) + + +class MinerHealthConnectionStateTests(unittest.TestCase): + @classmethod + def setUpClass(cls): + cls.module = load_source("rigos_miner_health_connection_state", MINER_HEALTH) + + def test_stale_pool_name_after_disconnect_is_waiting_external(self): + metrics = self.module.summary_metrics({ + "uptime": 900, + "algo": "rx/0", + "hashrate": {"total": [0, 0, 0], "highest": 341.2}, + "connection": { + "pool": "pool.example:1234", + "ip": None, + "uptime": 0, + "uptime_ms": 0, + "accepted": 43, + "rejected": 0, + "failures": 3, + "ping": 0, + }, + "hugepages": [1168, 1168], + }) + + self.assertEqual(metrics["pool"], "pool.example:1234") + self.assertIsNone(metrics["connection_ip"]) + self.assertFalse(metrics["pool_connected"]) + self.assertEqual( + classify(self.module, metrics), + ("waiting_external", "pool_or_network_unavailable"), + ) + + def test_active_connection_without_hashrate_is_degraded(self): + metrics = self.module.summary_metrics({ + "uptime": 900, + "algo": "rx/0", + "hashrate": {"total": [0, 0, 0], "highest": 341.2}, + "connection": { + "pool": "pool.example:1234", + "ip": "203.0.113.10", + "uptime": 0, + "uptime_ms": 125, + "accepted": 43, + "rejected": 0, + "failures": 0, + "ping": 109, + }, + "hugepages": [1168, 1168], + }) + + self.assertTrue(metrics["pool_connected"]) + self.assertEqual(metrics["connection_ip"], "203.0.113.10") + self.assertEqual(metrics["connection_uptime_ms"], 125) + self.assertEqual(classify(self.module, metrics), ("degraded", "no_hashrate_from_api")) + + def test_seconds_uptime_remains_compatible_without_ip_or_milliseconds(self): + metrics = self.module.summary_metrics({ + "hashrate": {"total": [0, 0, 0]}, + "connection": { + "pool": "pool.example:1234", + "uptime": 5, + }, + }) + + self.assertTrue(metrics["pool_connected"]) + self.assertEqual(metrics["connection_uptime_seconds"], 5) + + +if __name__ == "__main__": + unittest.main(verbosity=2) From 885e427a67a84ecf333370f6f15a7ad8ddc7fc82 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 22:59:41 +0700 Subject: [PATCH 061/132] gate build on active pool classification regression --- scripts/build-usb-image-entrypoint.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/build-usb-image-entrypoint.sh b/scripts/build-usb-image-entrypoint.sh index 2aa57c81..128c6c90 100644 --- a/scripts/build-usb-image-entrypoint.sh +++ b/scripts/build-usb-image-entrypoint.sh @@ -28,8 +28,10 @@ python3 -m py_compile \ ./build/usb/includes.chroot/usr/lib/rigos/rigos-runtime-render \ ./build/usb/includes.chroot/usr/lib/rigos/rigos-miner-health \ ./scripts/test-miner-health-api.py \ + ./scripts/test-miner-health-connection-state.py \ ./scripts/test-runtime-token-publication.py python3 ./scripts/test-miner-health-api.py +python3 ./scripts/test-miner-health-connection-state.py python3 ./scripts/test-runtime-token-publication.py export CARGO_TARGET_DIR=/work/rigos-performance-preflight-target From b28e99b7e8dce83dd0040a65ad5dd1f4aa1a535a Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 22:59:56 +0700 Subject: [PATCH 062/132] verify active pool evidence in exact image --- scripts/verify-miner-observer-image.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/scripts/verify-miner-observer-image.sh b/scripts/verify-miner-observer-image.sh index ff11e89c..34b3a55c 100644 --- a/scripts/verify-miner-observer-image.sh +++ b/scripts/verify-miner-observer-image.sh @@ -83,6 +83,9 @@ for required in \ '"/2/summary"' \ '"Authorization": f"Bearer {token}"' \ 'API_MAX_BYTES = 256 * 1024' \ + 'connection_ip = connection.get("ip")' \ + 'connection_uptime_ms = nonnegative_number(connection.get("uptime_ms"))' \ + '"pool_connected": pool_connected' \ '"source": "xmrig_http_api" if metrics is not None else "journal_fallback"' \ 'return "degraded", "no_hashrate_from_api"' \ 'return "degraded", api_error or "miner_api_unavailable"' From d593f814dfb3976fb5e5c718bf518b7e57639f6c Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 23:09:31 +0700 Subject: [PATCH 063/132] require active pool before api ready state --- .../usb/includes.chroot/usr/lib/rigos/rigos-miner-health | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/build/usb/includes.chroot/usr/lib/rigos/rigos-miner-health b/build/usb/includes.chroot/usr/lib/rigos/rigos-miner-health index 4e7e873c..e8fa4902 100644 --- a/build/usb/includes.chroot/usr/lib/rigos/rigos-miner-health +++ b/build/usb/includes.chroot/usr/lib/rigos/rigos-miner-health @@ -351,11 +351,15 @@ def classify( api_metrics.get("hashrate_60s"), api_metrics.get("hashrate_15m"), ) - if any(isinstance(value, (int, float)) and value > 0 for value in rates): + hashrate_positive = any( + isinstance(value, (int, float)) and value > 0 for value in rates + ) + pool_connected = api_metrics.get("pool_connected") is True + if pool_connected and hashrate_positive: return "ready", None if active_for is not None and active_for < WARMUP_SECONDS: return "warming_up", None - if not api_metrics.get("pool_connected"): + if not pool_connected: return "waiting_external", "pool_or_network_unavailable" return "degraded", "no_hashrate_from_api" From 2ebb4d09f59e93fa88ced435640e637a64077d54 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 23:09:51 +0700 Subject: [PATCH 064/132] test disconnected historical hashrate classification --- scripts/test-miner-health-connection-state.py | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/scripts/test-miner-health-connection-state.py b/scripts/test-miner-health-connection-state.py index 490c67a7..2ddda9d7 100644 --- a/scripts/test-miner-health-connection-state.py +++ b/scripts/test-miner-health-connection-state.py @@ -64,6 +64,32 @@ def test_stale_pool_name_after_disconnect_is_waiting_external(self): ("waiting_external", "pool_or_network_unavailable"), ) + def test_disconnected_historical_hashrate_does_not_report_ready(self): + metrics = self.module.summary_metrics({ + "uptime": 900, + "algo": "rx/0", + "hashrate": {"total": [0, 340.8, 339.7], "highest": 341.2}, + "connection": { + "pool": "pool.example:1234", + "ip": None, + "uptime": 0, + "uptime_ms": 0, + "accepted": 43, + "rejected": 0, + "failures": 3, + "ping": 0, + }, + "hugepages": [1168, 1168], + }) + + self.assertGreater(metrics["hashrate_60s"], 0) + self.assertGreater(metrics["hashrate_15m"], 0) + self.assertFalse(metrics["pool_connected"]) + self.assertEqual( + classify(self.module, metrics), + ("waiting_external", "pool_or_network_unavailable"), + ) + def test_active_connection_without_hashrate_is_degraded(self): metrics = self.module.summary_metrics({ "uptime": 900, @@ -87,6 +113,27 @@ def test_active_connection_without_hashrate_is_degraded(self): self.assertEqual(metrics["connection_uptime_ms"], 125) self.assertEqual(classify(self.module, metrics), ("degraded", "no_hashrate_from_api")) + def test_active_connection_with_hashrate_is_ready(self): + metrics = self.module.summary_metrics({ + "uptime": 900, + "algo": "rx/0", + "hashrate": {"total": [341.2, 340.9, 340.7], "highest": 342.1}, + "connection": { + "pool": "pool.example:1234", + "ip": "203.0.113.10", + "uptime": 590, + "uptime_ms": 590125, + "accepted": 43, + "rejected": 0, + "failures": 0, + "ping": 109, + }, + "hugepages": [1168, 1168], + }) + + self.assertTrue(metrics["pool_connected"]) + self.assertEqual(classify(self.module, metrics), ("ready", None)) + def test_seconds_uptime_remains_compatible_without_ip_or_milliseconds(self): metrics = self.module.summary_metrics({ "hashrate": {"total": [0, 0, 0]}, From 13ce9f7c420305a1d90bc244ba693e481423195a Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 23:10:17 +0700 Subject: [PATCH 065/132] behaviorally verify observer state truth in image --- scripts/verify-miner-observer-image.sh | 62 ++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/scripts/verify-miner-observer-image.sh b/scripts/verify-miner-observer-image.sh index 34b3a55c..a28e1d95 100644 --- a/scripts/verify-miner-observer-image.sh +++ b/scripts/verify-miner-observer-image.sh @@ -54,6 +54,67 @@ timer="$root/etc/systemd/system/rigos-miner-health.timer" [[ -x "$observer" ]] || die 'miner observer is missing or not executable' python3 -m py_compile "$renderer" "$observer" +python3 - "$observer" <<'PY' +import importlib.machinery +import importlib.util +import sys + +path = sys.argv[1] +loader = importlib.machinery.SourceFileLoader("rigos_image_observer", path) +spec = importlib.util.spec_from_loader("rigos_image_observer", loader) +if spec is None: + raise SystemExit("could not load extracted observer") +module = importlib.util.module_from_spec(spec) +loader.exec_module(module) + +properties = {"ActiveState": "active", "SubState": "running", "MainPID": "123"} + +def classify(summary): + metrics = module.summary_metrics(summary) + return metrics, module.classify( + properties, + "S", + 600, + "r1", + "ready", + "r1", + metrics, + None, + "", + True, + ) + +stale_metrics, stale_state = classify({ + "hashrate": {"total": [0, 340.8, 339.7], "highest": 341.2}, + "connection": { + "pool": "pool.example:1234", + "ip": None, + "uptime": 0, + "uptime_ms": 0, + "failures": 3, + }, +}) +if stale_metrics.get("pool_connected") is not False: + raise SystemExit("extracted observer trusts stale pool name") +if stale_state != ("waiting_external", "pool_or_network_unavailable"): + raise SystemExit(f"extracted observer misclassifies disconnected historical hashrate: {stale_state}") + +active_metrics, active_state = classify({ + "hashrate": {"total": [341.2, 340.9, 340.7], "highest": 342.1}, + "connection": { + "pool": "pool.example:1234", + "ip": "203.0.113.10", + "uptime": 590, + "uptime_ms": 590125, + "failures": 0, + }, +}) +if active_metrics.get("pool_connected") is not True: + raise SystemExit("extracted observer rejects active pool evidence") +if active_state != ("ready", None): + raise SystemExit(f"extracted observer rejects active hashrate: {active_state}") +PY + for required in \ 'API_TOKEN = Path(os.environ.get("RIGOS_XMRIG_API_TOKEN_PATH", str(RUNTIME / "xmrig-api-token")))' \ 'API_HOST = "127.0.0.1"' \ @@ -86,6 +147,7 @@ for required in \ 'connection_ip = connection.get("ip")' \ 'connection_uptime_ms = nonnegative_number(connection.get("uptime_ms"))' \ '"pool_connected": pool_connected' \ + 'if pool_connected and hashrate_positive:' \ '"source": "xmrig_http_api" if metrics is not None else "journal_fallback"' \ 'return "degraded", "no_hashrate_from_api"' \ 'return "degraded", api_error or "miner_api_unavailable"' From 2b67a29adde286060152541f676d299bcf2d00fd Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 23:11:25 +0700 Subject: [PATCH 066/132] classify journal fallback from latest evidence --- .../usr/lib/rigos/rigos-miner-health | 42 +++++++++++++++---- 1 file changed, 34 insertions(+), 8 deletions(-) diff --git a/build/usb/includes.chroot/usr/lib/rigos/rigos-miner-health b/build/usb/includes.chroot/usr/lib/rigos/rigos-miner-health index e8fa4902..cc776e5e 100644 --- a/build/usb/includes.chroot/usr/lib/rigos/rigos-miner-health +++ b/build/usb/includes.chroot/usr/lib/rigos/rigos-miner-health @@ -29,6 +29,10 @@ WARMUP_SECONDS = int(os.environ.get("RIGOS_MINER_WARMUP_SECONDS", "240")) MAX_JOURNAL_LINES = 500 TOKEN_RE = re.compile(r"^[A-Za-z0-9_-]{32,128}$") +READY_MARKERS = ( + "miner speed", + "accepted (", +) EXTERNAL_MARKERS = ( "connect error", "connection refused", @@ -165,6 +169,34 @@ def last_share_counts(text: str) -> tuple[int | None, int | None]: return int(accepted), int(rejected) +def latest_marker_index(text: str, markers: tuple[str, ...]) -> int: + return max((text.rfind(marker) for marker in markers), default=-1) + + +def latest_journal_signal(text: str) -> str | None: + lowered = text.lower() + ready_index = latest_marker_index(lowered, READY_MARKERS) + external_index = latest_marker_index(lowered, EXTERNAL_MARKERS) + if ready_index < 0 and external_index < 0: + return None + return "external_wait" if external_index > ready_index else "ready" + + +def journal_fallback_state( + journal: str, + active_for: int | None, + api_error: str | None, +) -> tuple[str, str | None]: + signal = latest_journal_signal(journal) + if signal == "ready": + return "ready", None + if signal == "external_wait": + return "waiting_external", "pool_or_network_unavailable" + if active_for is not None and active_for < WARMUP_SECONDS: + return "warming_up", None + return "degraded", api_error or "miner_api_unavailable" + + def expected_token_uid() -> int: return os.geteuid() if TEST_MODE else 0 @@ -365,14 +397,7 @@ def classify( if not journal_available: return "unknown", api_error or "journal_unavailable" - lowered = journal.lower() - if "miner speed" in lowered or "accepted (" in lowered: - return "ready", None - if any(marker in lowered for marker in EXTERNAL_MARKERS): - return "waiting_external", "pool_or_network_unavailable" - if active_for is not None and active_for < WARMUP_SECONDS: - return "warming_up", None - return "degraded", api_error or "miner_api_unavailable" + return journal_fallback_state(journal, active_for, api_error) def main() -> int: @@ -444,6 +469,7 @@ def main() -> int: "external_wait_marker": any( marker in lowered_journal for marker in EXTERNAL_MARKERS ), + "latest_journal_signal": latest_journal_signal(journal), "accepted_shares": accepted, "rejected_shares": rejected, }, From f3e2c550e497fe3d485766ba036fbbab06c30a19 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 23:11:36 +0700 Subject: [PATCH 067/132] test ordered journal fallback evidence --- scripts/test-miner-health-journal-fallback.py | 67 +++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 scripts/test-miner-health-journal-fallback.py diff --git a/scripts/test-miner-health-journal-fallback.py b/scripts/test-miner-health-journal-fallback.py new file mode 100644 index 00000000..ac4595d4 --- /dev/null +++ b/scripts/test-miner-health-journal-fallback.py @@ -0,0 +1,67 @@ +#!/usr/bin/env python3 +import importlib.machinery +import importlib.util +import unittest +from pathlib import Path + +ROOT = Path(__file__).resolve().parents[1] +MINER_HEALTH = ROOT / "build/usb/includes.chroot/usr/lib/rigos/rigos-miner-health" + + +def load_source(name: str, path: Path): + loader = importlib.machinery.SourceFileLoader(name, str(path)) + spec = importlib.util.spec_from_loader(name, loader) + if spec is None: + raise RuntimeError(f"could not load {path}") + module = importlib.util.module_from_spec(spec) + loader.exec_module(module) + return module + + +class MinerHealthJournalFallbackTests(unittest.TestCase): + @classmethod + def setUpClass(cls): + cls.module = load_source("rigos_miner_health_journal_fallback", MINER_HEALTH) + + def test_newer_external_error_overrides_old_ready_evidence(self): + journal = "\n".join([ + "miner speed 10s/60s/15m 341.2 340.9 340.7 H/s", + "cpu accepted (43/0) diff 10000", + "net connect error: operation timed out", + ]) + + self.assertEqual(self.module.latest_journal_signal(journal), "external_wait") + self.assertEqual( + self.module.journal_fallback_state(journal, 600, "api_unavailable"), + ("waiting_external", "pool_or_network_unavailable"), + ) + + def test_newer_ready_evidence_overrides_old_external_error(self): + journal = "\n".join([ + "net connect error: operation timed out", + "miner speed 10s/60s/15m 341.2 340.9 340.7 H/s", + "cpu accepted (44/0) diff 10000", + ]) + + self.assertEqual(self.module.latest_journal_signal(journal), "ready") + self.assertEqual( + self.module.journal_fallback_state(journal, 600, "api_unavailable"), + ("ready", None), + ) + + def test_no_signal_during_warmup_is_warming_up(self): + self.assertIsNone(self.module.latest_journal_signal("starting miner")) + self.assertEqual( + self.module.journal_fallback_state("starting miner", 30, "api_unavailable"), + ("warming_up", None), + ) + + def test_no_signal_after_warmup_is_degraded(self): + self.assertEqual( + self.module.journal_fallback_state("miner remains silent", 600, "api_unavailable"), + ("degraded", "api_unavailable"), + ) + + +if __name__ == "__main__": + unittest.main(verbosity=2) From 3438768ebfd72d741e3671582ea6219809fdb7d9 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 23:11:45 +0700 Subject: [PATCH 068/132] gate build on ordered journal evidence regression --- scripts/build-usb-image-entrypoint.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/build-usb-image-entrypoint.sh b/scripts/build-usb-image-entrypoint.sh index 128c6c90..bfcf086f 100644 --- a/scripts/build-usb-image-entrypoint.sh +++ b/scripts/build-usb-image-entrypoint.sh @@ -29,9 +29,11 @@ python3 -m py_compile \ ./build/usb/includes.chroot/usr/lib/rigos/rigos-miner-health \ ./scripts/test-miner-health-api.py \ ./scripts/test-miner-health-connection-state.py \ + ./scripts/test-miner-health-journal-fallback.py \ ./scripts/test-runtime-token-publication.py python3 ./scripts/test-miner-health-api.py python3 ./scripts/test-miner-health-connection-state.py +python3 ./scripts/test-miner-health-journal-fallback.py python3 ./scripts/test-runtime-token-publication.py export CARGO_TARGET_DIR=/work/rigos-performance-preflight-target From 114bdcde8c0dbad201a1ed06976569b180156e91 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 23:12:11 +0700 Subject: [PATCH 069/132] verify ordered journal fallback in exact image --- scripts/verify-miner-observer-image.sh | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/scripts/verify-miner-observer-image.sh b/scripts/verify-miner-observer-image.sh index a28e1d95..3285fcd9 100644 --- a/scripts/verify-miner-observer-image.sh +++ b/scripts/verify-miner-observer-image.sh @@ -113,6 +113,24 @@ if active_metrics.get("pool_connected") is not True: raise SystemExit("extracted observer rejects active pool evidence") if active_state != ("ready", None): raise SystemExit(f"extracted observer rejects active hashrate: {active_state}") + +old_ready_new_external = "\n".join([ + "miner speed 10s/60s/15m 341.2 340.9 340.7 H/s", + "cpu accepted (43/0) diff 10000", + "net connect error: operation timed out", +]) +state = module.journal_fallback_state(old_ready_new_external, 600, "api_unavailable") +if state != ("waiting_external", "pool_or_network_unavailable"): + raise SystemExit(f"extracted observer trusts stale journal ready evidence: {state}") + +old_external_new_ready = "\n".join([ + "net connect error: operation timed out", + "miner speed 10s/60s/15m 341.2 340.9 340.7 H/s", + "cpu accepted (44/0) diff 10000", +]) +state = module.journal_fallback_state(old_external_new_ready, 600, "api_unavailable") +if state != ("ready", None): + raise SystemExit(f"extracted observer ignores newer journal ready evidence: {state}") PY for required in \ @@ -148,6 +166,8 @@ for required in \ 'connection_uptime_ms = nonnegative_number(connection.get("uptime_ms"))' \ '"pool_connected": pool_connected' \ 'if pool_connected and hashrate_positive:' \ + 'def latest_journal_signal(text: str) -> str | None:' \ + '"latest_journal_signal": latest_journal_signal(journal)' \ '"source": "xmrig_http_api" if metrics is not None else "journal_fallback"' \ 'return "degraded", "no_hashrate_from_api"' \ 'return "degraded", api_error or "miner_api_unavailable"' From 432f9bc824cab9cbb32fb930e67b9772450f8c8b Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 23:13:48 +0700 Subject: [PATCH 070/132] use current 10 second hashrate as ready authority --- .../usr/lib/rigos/rigos-miner-health | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/build/usb/includes.chroot/usr/lib/rigos/rigos-miner-health b/build/usb/includes.chroot/usr/lib/rigos/rigos-miner-health index cc776e5e..dfbb50c4 100644 --- a/build/usb/includes.chroot/usr/lib/rigos/rigos-miner-health +++ b/build/usb/includes.chroot/usr/lib/rigos/rigos-miner-health @@ -378,22 +378,22 @@ def classify( return "blocked", "runtime_revision_mismatch" if api_metrics is not None: - rates = ( - api_metrics.get("hashrate_10s"), - api_metrics.get("hashrate_60s"), - api_metrics.get("hashrate_15m"), - ) - hashrate_positive = any( - isinstance(value, (int, float)) and value > 0 for value in rates + current_hashrate = api_metrics.get("hashrate_10s") + current_hashrate_positive = ( + isinstance(current_hashrate, (int, float)) + and not isinstance(current_hashrate, bool) + and current_hashrate > 0 ) pool_connected = api_metrics.get("pool_connected") is True - if pool_connected and hashrate_positive: + if pool_connected and current_hashrate_positive: return "ready", None if active_for is not None and active_for < WARMUP_SECONDS: return "warming_up", None if not pool_connected: return "waiting_external", "pool_or_network_unavailable" - return "degraded", "no_hashrate_from_api" + if current_hashrate is None: + return "degraded", "current_hashrate_unavailable" + return "degraded", "no_current_hashrate_from_api" if not journal_available: return "unknown", api_error or "journal_unavailable" From 715a08ef003f8b86b43536df0bbf907d6f90aff1 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 23:14:11 +0700 Subject: [PATCH 071/132] test current hashrate readiness authority --- scripts/test-miner-health-connection-state.py | 54 ++++++++++++++++++- 1 file changed, 53 insertions(+), 1 deletion(-) diff --git a/scripts/test-miner-health-connection-state.py b/scripts/test-miner-health-connection-state.py index 2ddda9d7..564db518 100644 --- a/scripts/test-miner-health-connection-state.py +++ b/scripts/test-miner-health-connection-state.py @@ -111,7 +111,59 @@ def test_active_connection_without_hashrate_is_degraded(self): self.assertTrue(metrics["pool_connected"]) self.assertEqual(metrics["connection_ip"], "203.0.113.10") self.assertEqual(metrics["connection_uptime_ms"], 125) - self.assertEqual(classify(self.module, metrics), ("degraded", "no_hashrate_from_api")) + self.assertEqual( + classify(self.module, metrics), + ("degraded", "no_current_hashrate_from_api"), + ) + + def test_active_historical_hashrate_without_current_rate_is_degraded(self): + metrics = self.module.summary_metrics({ + "uptime": 900, + "algo": "rx/0", + "hashrate": {"total": [0, 340.9, 340.7], "highest": 342.1}, + "connection": { + "pool": "pool.example:1234", + "ip": "203.0.113.10", + "uptime": 590, + "uptime_ms": 590125, + "accepted": 43, + "rejected": 0, + "failures": 0, + "ping": 109, + }, + "hugepages": [1168, 1168], + }) + + self.assertEqual(metrics["hashrate_10s"], 0) + self.assertGreater(metrics["hashrate_60s"], 0) + self.assertEqual( + classify(self.module, metrics), + ("degraded", "no_current_hashrate_from_api"), + ) + + def test_active_connection_with_unavailable_current_rate_is_degraded(self): + metrics = self.module.summary_metrics({ + "uptime": 900, + "algo": "rx/0", + "hashrate": {"total": [None, 340.9, 340.7], "highest": 342.1}, + "connection": { + "pool": "pool.example:1234", + "ip": "203.0.113.10", + "uptime": 590, + "uptime_ms": 590125, + "accepted": 43, + "rejected": 0, + "failures": 0, + "ping": 109, + }, + "hugepages": [1168, 1168], + }) + + self.assertIsNone(metrics["hashrate_10s"]) + self.assertEqual( + classify(self.module, metrics), + ("degraded", "current_hashrate_unavailable"), + ) def test_active_connection_with_hashrate_is_ready(self): metrics = self.module.summary_metrics({ From 24f65b4de3bc933dd63f0378384cb311b2ccb09e Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 23:14:37 +0700 Subject: [PATCH 072/132] verify current hashrate authority in exact image --- scripts/verify-miner-observer-image.sh | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/scripts/verify-miner-observer-image.sh b/scripts/verify-miner-observer-image.sh index 3285fcd9..09ce4d50 100644 --- a/scripts/verify-miner-observer-image.sh +++ b/scripts/verify-miner-observer-image.sh @@ -99,6 +99,21 @@ if stale_metrics.get("pool_connected") is not False: if stale_state != ("waiting_external", "pool_or_network_unavailable"): raise SystemExit(f"extracted observer misclassifies disconnected historical hashrate: {stale_state}") +historical_metrics, historical_state = classify({ + "hashrate": {"total": [0, 340.9, 340.7], "highest": 342.1}, + "connection": { + "pool": "pool.example:1234", + "ip": "203.0.113.10", + "uptime": 590, + "uptime_ms": 590125, + "failures": 0, + }, +}) +if historical_metrics.get("pool_connected") is not True: + raise SystemExit("extracted observer rejects active pool evidence") +if historical_state != ("degraded", "no_current_hashrate_from_api"): + raise SystemExit(f"extracted observer trusts historical hashrate as current: {historical_state}") + active_metrics, active_state = classify({ "hashrate": {"total": [341.2, 340.9, 340.7], "highest": 342.1}, "connection": { @@ -165,11 +180,13 @@ for required in \ 'connection_ip = connection.get("ip")' \ 'connection_uptime_ms = nonnegative_number(connection.get("uptime_ms"))' \ '"pool_connected": pool_connected' \ - 'if pool_connected and hashrate_positive:' \ + 'current_hashrate = api_metrics.get("hashrate_10s")' \ + 'if pool_connected and current_hashrate_positive:' \ + 'return "degraded", "current_hashrate_unavailable"' \ + 'return "degraded", "no_current_hashrate_from_api"' \ 'def latest_journal_signal(text: str) -> str | None:' \ '"latest_journal_signal": latest_journal_signal(journal)' \ '"source": "xmrig_http_api" if metrics is not None else "journal_fallback"' \ - 'return "degraded", "no_hashrate_from_api"' \ 'return "degraded", api_error or "miner_api_unavailable"' do grep -Fq "$required" "$observer" || die "miner observer API contract is missing: $required" From ba47ba1feb3bab5d09e5519f736fea4ec8c4694c Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 23:15:44 +0700 Subject: [PATCH 073/132] fail closed on api authority errors --- build/usb/includes.chroot/usr/lib/rigos/rigos-miner-health | 2 ++ 1 file changed, 2 insertions(+) diff --git a/build/usb/includes.chroot/usr/lib/rigos/rigos-miner-health b/build/usb/includes.chroot/usr/lib/rigos/rigos-miner-health index dfbb50c4..c64ae135 100644 --- a/build/usb/includes.chroot/usr/lib/rigos/rigos-miner-health +++ b/build/usb/includes.chroot/usr/lib/rigos/rigos-miner-health @@ -395,6 +395,8 @@ def classify( return "degraded", "current_hashrate_unavailable" return "degraded", "no_current_hashrate_from_api" + if api_error not in (None, "api_unavailable"): + return "degraded", api_error if not journal_available: return "unknown", api_error or "journal_unavailable" return journal_fallback_state(journal, active_for, api_error) From 56ee101b40830135c9ffb4a9903031393f4573ce Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 23:15:57 +0700 Subject: [PATCH 074/132] test fail closed api authority errors --- .../test-miner-health-api-authority-errors.py | 80 +++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 scripts/test-miner-health-api-authority-errors.py diff --git a/scripts/test-miner-health-api-authority-errors.py b/scripts/test-miner-health-api-authority-errors.py new file mode 100644 index 00000000..1db3865c --- /dev/null +++ b/scripts/test-miner-health-api-authority-errors.py @@ -0,0 +1,80 @@ +#!/usr/bin/env python3 +import importlib.machinery +import importlib.util +import unittest +from pathlib import Path + +ROOT = Path(__file__).resolve().parents[1] +MINER_HEALTH = ROOT / "build/usb/includes.chroot/usr/lib/rigos/rigos-miner-health" +PROPERTIES = {"ActiveState": "active", "SubState": "running", "MainPID": "123"} + + +def load_source(name: str, path: Path): + loader = importlib.machinery.SourceFileLoader(name, str(path)) + spec = importlib.util.spec_from_loader(name, loader) + if spec is None: + raise RuntimeError(f"could not load {path}") + module = importlib.util.module_from_spec(spec) + loader.exec_module(module) + return module + + +def classify(module, api_error: str | None, journal: str, journal_available: bool = True): + return module.classify( + PROPERTIES, + "S", + 600, + "r1", + "ready", + "r1", + None, + api_error, + journal, + journal_available, + ) + + +class MinerHealthApiAuthorityErrorTests(unittest.TestCase): + @classmethod + def setUpClass(cls): + cls.module = load_source("rigos_miner_health_api_authority_errors", MINER_HEALTH) + + def test_missing_token_cannot_be_hidden_by_ready_journal(self): + state = classify( + self.module, + "api_token_missing", + "miner speed 10s/60s/15m 341.2 340.9 340.7 H/s", + ) + self.assertEqual(state, ("degraded", "api_token_missing")) + + def test_authentication_failure_cannot_be_hidden_by_accepted_share(self): + state = classify( + self.module, + "api_http_status_401", + "cpu accepted (43/0) diff 10000", + ) + self.assertEqual(state, ("degraded", "api_http_status_401")) + + def test_invalid_api_response_cannot_be_hidden_by_journal(self): + state = classify( + self.module, + "api_response_not_object", + "cpu accepted (43/0) diff 10000", + ) + self.assertEqual(state, ("degraded", "api_response_not_object")) + + def test_transient_api_unavailable_still_allows_journal_fallback(self): + state = classify( + self.module, + "api_unavailable", + "cpu accepted (43/0) diff 10000", + ) + self.assertEqual(state, ("ready", None)) + + def test_transient_api_unavailable_without_journal_is_unknown(self): + state = classify(self.module, "api_unavailable", "", journal_available=False) + self.assertEqual(state, ("unknown", "api_unavailable")) + + +if __name__ == "__main__": + unittest.main(verbosity=2) From a5ad30fa776494bfacdc0632dc1eb64df9627325 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 23:16:11 +0700 Subject: [PATCH 075/132] gate build on api authority error regression --- scripts/build-usb-image-entrypoint.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/build-usb-image-entrypoint.sh b/scripts/build-usb-image-entrypoint.sh index bfcf086f..4d35ad2d 100644 --- a/scripts/build-usb-image-entrypoint.sh +++ b/scripts/build-usb-image-entrypoint.sh @@ -28,10 +28,12 @@ python3 -m py_compile \ ./build/usb/includes.chroot/usr/lib/rigos/rigos-runtime-render \ ./build/usb/includes.chroot/usr/lib/rigos/rigos-miner-health \ ./scripts/test-miner-health-api.py \ + ./scripts/test-miner-health-api-authority-errors.py \ ./scripts/test-miner-health-connection-state.py \ ./scripts/test-miner-health-journal-fallback.py \ ./scripts/test-runtime-token-publication.py python3 ./scripts/test-miner-health-api.py +python3 ./scripts/test-miner-health-api-authority-errors.py python3 ./scripts/test-miner-health-connection-state.py python3 ./scripts/test-miner-health-journal-fallback.py python3 ./scripts/test-runtime-token-publication.py From b50be0db16fdc35228140b2d98ee5b89212f0cc7 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 23:16:38 +0700 Subject: [PATCH 076/132] verify api authority errors fail closed in image --- scripts/verify-miner-observer-image.sh | 31 ++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/scripts/verify-miner-observer-image.sh b/scripts/verify-miner-observer-image.sh index 09ce4d50..655a27c1 100644 --- a/scripts/verify-miner-observer-image.sh +++ b/scripts/verify-miner-observer-image.sh @@ -146,6 +146,36 @@ old_external_new_ready = "\n".join([ state = module.journal_fallback_state(old_external_new_ready, 600, "api_unavailable") if state != ("ready", None): raise SystemExit(f"extracted observer ignores newer journal ready evidence: {state}") + +authority_error_state = module.classify( + properties, + "S", + 600, + "r1", + "ready", + "r1", + None, + "api_token_missing", + "cpu accepted (43/0) diff 10000", + True, +) +if authority_error_state != ("degraded", "api_token_missing"): + raise SystemExit(f"extracted observer hides API authority failure: {authority_error_state}") + +transient_state = module.classify( + properties, + "S", + 600, + "r1", + "ready", + "r1", + None, + "api_unavailable", + "cpu accepted (43/0) diff 10000", + True, +) +if transient_state != ("ready", None): + raise SystemExit(f"extracted observer rejects bounded transient fallback: {transient_state}") PY for required in \ @@ -184,6 +214,7 @@ for required in \ 'if pool_connected and current_hashrate_positive:' \ 'return "degraded", "current_hashrate_unavailable"' \ 'return "degraded", "no_current_hashrate_from_api"' \ + 'if api_error not in (None, "api_unavailable"):' \ 'def latest_journal_signal(text: str) -> str | None:' \ '"latest_journal_signal": latest_journal_signal(journal)' \ '"source": "xmrig_http_api" if metrics is not None else "journal_fallback"' \ From 14ed885a8b65a87dbbbf2ceeedd0974361dfa2eb Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 23:17:58 +0700 Subject: [PATCH 077/132] add authoritative miner observer source gate --- .../tests/miner_observer_authority.rs | 116 ++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100644 crates/rigos-config/tests/miner_observer_authority.rs diff --git a/crates/rigos-config/tests/miner_observer_authority.rs b/crates/rigos-config/tests/miner_observer_authority.rs new file mode 100644 index 00000000..c037518f --- /dev/null +++ b/crates/rigos-config/tests/miner_observer_authority.rs @@ -0,0 +1,116 @@ +use std::env; +use std::fs; +use std::path::{Path, PathBuf}; +use std::process::Command; + +fn repo_root() -> PathBuf { + PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../..") +} + +fn repo_path(path: &str) -> PathBuf { + repo_root().join(path) +} + +#[cfg(unix)] +fn run_python(script: &str) { + let python = env::var("RIGOS_PYTHON").unwrap_or_else(|_| "python3".to_string()); + let status = Command::new(&python) + .arg(repo_path(script)) + .current_dir(repo_root()) + .status() + .unwrap_or_else(|error| panic!("failed to execute {script} with {python}: {error}")); + assert!(status.success(), "observer source regression failed: {script}"); +} + +#[cfg(unix)] +#[test] +fn authenticated_miner_observer_behavioral_source_gate() { + for script in [ + "scripts/test-miner-health-api.py", + "scripts/test-miner-health-api-authority-errors.py", + "scripts/test-miner-health-connection-state.py", + "scripts/test-miner-health-journal-fallback.py", + "scripts/test-runtime-token-publication.py", + ] { + run_python(script); + } +} + +#[test] +fn observer_authority_is_wired_into_build_and_exact_image_gates() { + let entrypoint = fs::read_to_string(repo_path("scripts/build-usb-image-entrypoint.sh")) + .expect("read performance image entrypoint"); + let image_verifier = fs::read_to_string(repo_path("scripts/verify-miner-observer-image.sh")) + .expect("read observer image verifier"); + let observer = fs::read_to_string(repo_path( + "build/usb/includes.chroot/usr/lib/rigos/rigos-miner-health", + )) + .expect("read miner observer"); + let renderer = fs::read_to_string(repo_path( + "build/usb/includes.chroot/usr/lib/rigos/rigos-runtime-render", + )) + .expect("read runtime renderer"); + let publisher = fs::read_to_string(repo_path( + "build/usb/includes.chroot/usr/lib/rigos/rigos-runtime-publish", + )) + .expect("read runtime publisher"); + + for script in [ + "test-miner-health-api.py", + "test-miner-health-api-authority-errors.py", + "test-miner-health-connection-state.py", + "test-miner-health-journal-fallback.py", + "test-runtime-token-publication.py", + ] { + assert!( + entrypoint.contains(script), + "performance image entrypoint does not run {script}" + ); + } + + for contract in [ + "RIGOS_XMRIG_API_TOKEN_PATH", + "hashrate_10s", + "current_hashrate_unavailable", + "no_current_hashrate_from_api", + "latest_journal_signal", + "api_error not in (None, \"api_unavailable\")", + ] { + assert!(observer.contains(contract), "observer contract missing: {contract}"); + } + + assert!(renderer.contains("secrets.token_urlsafe(48)")); + assert!(renderer.contains("127.0.0.1")); + assert!(renderer.contains("restricted\": True")); + assert!(publisher.contains("RIGOS_XMRIG_API_TOKEN_PATH=\"$runtime/xmrig-api-token\"")); + + for contract in [ + "extracted observer misclassifies disconnected historical hashrate", + "extracted observer trusts historical hashrate as current", + "extracted observer trusts stale journal ready evidence", + "extracted observer hides API authority failure", + ] { + assert!( + image_verifier.contains(contract), + "exact-image behavioral contract missing: {contract}" + ); + } +} + +#[test] +fn observer_test_files_are_regular_repository_files() { + for path in [ + "scripts/test-miner-health-api.py", + "scripts/test-miner-health-api-authority-errors.py", + "scripts/test-miner-health-connection-state.py", + "scripts/test-miner-health-journal-fallback.py", + "scripts/test-runtime-token-publication.py", + ] { + let metadata = fs::metadata(repo_path(path)).unwrap_or_else(|error| { + panic!("observer test file is unavailable: {path}: {error}") + }); + assert!(metadata.is_file(), "observer test path is not a file: {path}"); + } + + assert!(Path::new(&repo_path("scripts/verify-miner-observer-image.sh")).is_file()); +} From 0f952cf04a41eb1957aa56e3f8b7286b45ffdb0d Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 23:18:23 +0700 Subject: [PATCH 078/132] keep observer authority test clippy clean cross platform --- crates/rigos-config/tests/miner_observer_authority.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/crates/rigos-config/tests/miner_observer_authority.rs b/crates/rigos-config/tests/miner_observer_authority.rs index c037518f..27e5eab2 100644 --- a/crates/rigos-config/tests/miner_observer_authority.rs +++ b/crates/rigos-config/tests/miner_observer_authority.rs @@ -1,6 +1,8 @@ +#[cfg(unix)] use std::env; use std::fs; -use std::path::{Path, PathBuf}; +use std::path::PathBuf; +#[cfg(unix)] use std::process::Command; fn repo_root() -> PathBuf { @@ -112,5 +114,5 @@ fn observer_test_files_are_regular_repository_files() { assert!(metadata.is_file(), "observer test path is not a file: {path}"); } - assert!(Path::new(&repo_path("scripts/verify-miner-observer-image.sh")).is_file()); + assert!(repo_path("scripts/verify-miner-observer-image.sh").is_file()); } From 5d3c1c9dad6c71b8e36705ac14308def39bfe469 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 23:18:36 +0700 Subject: [PATCH 079/132] run authoritative observer gate before image build --- scripts/build-usb-image-entrypoint.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/build-usb-image-entrypoint.sh b/scripts/build-usb-image-entrypoint.sh index 4d35ad2d..5625acae 100644 --- a/scripts/build-usb-image-entrypoint.sh +++ b/scripts/build-usb-image-entrypoint.sh @@ -39,6 +39,7 @@ python3 ./scripts/test-miner-health-journal-fallback.py python3 ./scripts/test-runtime-token-publication.py export CARGO_TARGET_DIR=/work/rigos-performance-preflight-target +cargo test --locked -p rigos-config --test miner_observer_authority -- --nocapture cargo test --locked -p rigos-config --test randomx_build_entrypoint -- --nocapture cargo test --locked -p rigos-config --test randomx_msr_authority -- --nocapture From 3a7a746ed926e7dce235923f321344abb12b53dd Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 23:18:51 +0700 Subject: [PATCH 080/132] verify observer source gate is build mandatory --- crates/rigos-config/tests/miner_observer_authority.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/rigos-config/tests/miner_observer_authority.rs b/crates/rigos-config/tests/miner_observer_authority.rs index 27e5eab2..74d39cbd 100644 --- a/crates/rigos-config/tests/miner_observer_authority.rs +++ b/crates/rigos-config/tests/miner_observer_authority.rs @@ -69,6 +69,7 @@ fn observer_authority_is_wired_into_build_and_exact_image_gates() { "performance image entrypoint does not run {script}" ); } + assert!(entrypoint.contains("--test miner_observer_authority")); for contract in [ "RIGOS_XMRIG_API_TOKEN_PATH", From f88460a4f8cc8e5cb8134c2ccd40e0947ff29060 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 23:27:07 +0700 Subject: [PATCH 081/132] reject fractional api counters --- .../usr/lib/rigos/rigos-miner-health | 30 +++++++++++-------- 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/build/usb/includes.chroot/usr/lib/rigos/rigos-miner-health b/build/usb/includes.chroot/usr/lib/rigos/rigos-miner-health index c64ae135..57953a6e 100644 --- a/build/usb/includes.chroot/usr/lib/rigos/rigos-miner-health +++ b/build/usb/includes.chroot/usr/lib/rigos/rigos-miner-health @@ -284,6 +284,12 @@ def nonnegative_number(value: object) -> int | float | None: return value +def nonnegative_integer(value: object) -> int | None: + if isinstance(value, bool) or not isinstance(value, int) or value < 0: + return None + return value + + def summary_metrics(summary: dict) -> dict: hashrate = summary.get("hashrate") if not isinstance(hashrate, dict): @@ -301,12 +307,12 @@ def summary_metrics(summary: dict) -> dict: if not isinstance(results, dict): results = {} - accepted = nonnegative_number(connection.get("accepted")) - rejected = nonnegative_number(connection.get("rejected")) + accepted = nonnegative_integer(connection.get("accepted")) + rejected = nonnegative_integer(connection.get("rejected")) if accepted is None: - accepted = nonnegative_number(results.get("shares_good")) + accepted = nonnegative_integer(results.get("shares_good")) if rejected is None: - total = nonnegative_number(results.get("shares_total")) + total = nonnegative_integer(results.get("shares_total")) if total is not None and accepted is not None and total >= accepted: rejected = total - accepted @@ -328,8 +334,8 @@ def summary_metrics(summary: dict) -> dict: hugepages_used = None hugepages_total = None if isinstance(hugepages, list) and len(hugepages) >= 2: - hugepages_used = nonnegative_number(hugepages[0]) - hugepages_total = nonnegative_number(hugepages[1]) + hugepages_used = nonnegative_integer(hugepages[0]) + hugepages_total = nonnegative_integer(hugepages[1]) return { "uptime_seconds": nonnegative_number(summary.get("uptime")), @@ -343,12 +349,12 @@ def summary_metrics(summary: dict) -> dict: "connection_ip": connection_ip, "connection_uptime_seconds": connection_uptime_seconds, "connection_uptime_ms": connection_uptime_ms, - "connection_failures": nonnegative_number(connection.get("failures")), - "pool_ping_ms": nonnegative_number(connection.get("ping")), - "accepted_shares": int(accepted) if accepted is not None else None, - "rejected_shares": int(rejected) if rejected is not None else None, - "hugepages_used": int(hugepages_used) if hugepages_used is not None else None, - "hugepages_total": int(hugepages_total) if hugepages_total is not None else None, + "connection_failures": nonnegative_integer(connection.get("failures")), + "pool_ping_ms": nonnegative_integer(connection.get("ping")), + "accepted_shares": accepted, + "rejected_shares": rejected, + "hugepages_used": hugepages_used, + "hugepages_total": hugepages_total, } From 1155a5f52eb783b1a425e14876e657b6759ff588 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 23:27:18 +0700 Subject: [PATCH 082/132] test strict xmrig api counter schema --- scripts/test-miner-health-api-schema.py | 87 +++++++++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 scripts/test-miner-health-api-schema.py diff --git a/scripts/test-miner-health-api-schema.py b/scripts/test-miner-health-api-schema.py new file mode 100644 index 00000000..66cdc171 --- /dev/null +++ b/scripts/test-miner-health-api-schema.py @@ -0,0 +1,87 @@ +#!/usr/bin/env python3 +import importlib.machinery +import importlib.util +import unittest +from pathlib import Path + +ROOT = Path(__file__).resolve().parents[1] +MINER_HEALTH = ROOT / "build/usb/includes.chroot/usr/lib/rigos/rigos-miner-health" + + +def load_source(name: str, path: Path): + loader = importlib.machinery.SourceFileLoader(name, str(path)) + spec = importlib.util.spec_from_loader(name, loader) + if spec is None: + raise RuntimeError(f"could not load {path}") + module = importlib.util.module_from_spec(spec) + loader.exec_module(module) + return module + + +class MinerHealthApiSchemaTests(unittest.TestCase): + @classmethod + def setUpClass(cls): + cls.module = load_source("rigos_miner_health_api_schema", MINER_HEALTH) + + def test_fractional_counters_are_rejected_not_truncated(self): + metrics = self.module.summary_metrics({ + "hashrate": {"total": [341.2, 340.9, 340.7]}, + "connection": { + "pool": "pool.example:1234", + "ip": "203.0.113.10", + "uptime": 10, + "accepted": 43.9, + "rejected": 1.2, + "failures": 2.5, + "ping": 109.7, + }, + "results": { + "shares_good": 42.8, + "shares_total": 44.1, + }, + "hugepages": [1168.5, 1169.5], + }) + + self.assertIsNone(metrics["accepted_shares"]) + self.assertIsNone(metrics["rejected_shares"]) + self.assertIsNone(metrics["connection_failures"]) + self.assertIsNone(metrics["pool_ping_ms"]) + self.assertIsNone(metrics["hugepages_used"]) + self.assertIsNone(metrics["hugepages_total"]) + + def test_boolean_counters_are_rejected(self): + metrics = self.module.summary_metrics({ + "connection": {"accepted": True, "rejected": False}, + "hugepages": [True, False], + }) + + self.assertIsNone(metrics["accepted_shares"]) + self.assertIsNone(metrics["rejected_shares"]) + self.assertIsNone(metrics["hugepages_used"]) + self.assertIsNone(metrics["hugepages_total"]) + + def test_integer_result_fallback_remains_supported(self): + metrics = self.module.summary_metrics({ + "results": {"shares_good": 43, "shares_total": 45}, + "hugepages": [1168, 1168], + "connection": {"failures": 2, "ping": 109}, + }) + + self.assertEqual(metrics["accepted_shares"], 43) + self.assertEqual(metrics["rejected_shares"], 2) + self.assertEqual(metrics["connection_failures"], 2) + self.assertEqual(metrics["pool_ping_ms"], 109) + self.assertEqual(metrics["hugepages_used"], 1168) + self.assertEqual(metrics["hugepages_total"], 1168) + + def test_total_below_accepted_does_not_produce_negative_rejects(self): + metrics = self.module.summary_metrics({ + "results": {"shares_good": 45, "shares_total": 43}, + }) + + self.assertEqual(metrics["accepted_shares"], 45) + self.assertIsNone(metrics["rejected_shares"]) + + +if __name__ == "__main__": + unittest.main(verbosity=2) From 45a411e70e2366afa702f94c145e5cce7048c72c Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 23:27:32 +0700 Subject: [PATCH 083/132] gate build on strict api schema regression --- scripts/build-usb-image-entrypoint.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/build-usb-image-entrypoint.sh b/scripts/build-usb-image-entrypoint.sh index 5625acae..78e1ef70 100644 --- a/scripts/build-usb-image-entrypoint.sh +++ b/scripts/build-usb-image-entrypoint.sh @@ -29,11 +29,13 @@ python3 -m py_compile \ ./build/usb/includes.chroot/usr/lib/rigos/rigos-miner-health \ ./scripts/test-miner-health-api.py \ ./scripts/test-miner-health-api-authority-errors.py \ + ./scripts/test-miner-health-api-schema.py \ ./scripts/test-miner-health-connection-state.py \ ./scripts/test-miner-health-journal-fallback.py \ ./scripts/test-runtime-token-publication.py python3 ./scripts/test-miner-health-api.py python3 ./scripts/test-miner-health-api-authority-errors.py +python3 ./scripts/test-miner-health-api-schema.py python3 ./scripts/test-miner-health-connection-state.py python3 ./scripts/test-miner-health-journal-fallback.py python3 ./scripts/test-runtime-token-publication.py From ad9f1c2adc5eab3d8363442a8d008989d168f435 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 23:27:50 +0700 Subject: [PATCH 084/132] include strict api schema in observer authority --- crates/rigos-config/tests/miner_observer_authority.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/crates/rigos-config/tests/miner_observer_authority.rs b/crates/rigos-config/tests/miner_observer_authority.rs index 74d39cbd..a1b03204 100644 --- a/crates/rigos-config/tests/miner_observer_authority.rs +++ b/crates/rigos-config/tests/miner_observer_authority.rs @@ -30,6 +30,7 @@ fn authenticated_miner_observer_behavioral_source_gate() { for script in [ "scripts/test-miner-health-api.py", "scripts/test-miner-health-api-authority-errors.py", + "scripts/test-miner-health-api-schema.py", "scripts/test-miner-health-connection-state.py", "scripts/test-miner-health-journal-fallback.py", "scripts/test-runtime-token-publication.py", @@ -60,6 +61,7 @@ fn observer_authority_is_wired_into_build_and_exact_image_gates() { for script in [ "test-miner-health-api.py", "test-miner-health-api-authority-errors.py", + "test-miner-health-api-schema.py", "test-miner-health-connection-state.py", "test-miner-health-journal-fallback.py", "test-runtime-token-publication.py", @@ -74,6 +76,7 @@ fn observer_authority_is_wired_into_build_and_exact_image_gates() { for contract in [ "RIGOS_XMRIG_API_TOKEN_PATH", "hashrate_10s", + "nonnegative_integer", "current_hashrate_unavailable", "no_current_hashrate_from_api", "latest_journal_signal", @@ -92,6 +95,7 @@ fn observer_authority_is_wired_into_build_and_exact_image_gates() { "extracted observer trusts historical hashrate as current", "extracted observer trusts stale journal ready evidence", "extracted observer hides API authority failure", + "extracted observer truncates fractional counters", ] { assert!( image_verifier.contains(contract), @@ -105,6 +109,7 @@ fn observer_test_files_are_regular_repository_files() { for path in [ "scripts/test-miner-health-api.py", "scripts/test-miner-health-api-authority-errors.py", + "scripts/test-miner-health-api-schema.py", "scripts/test-miner-health-connection-state.py", "scripts/test-miner-health-journal-fallback.py", "scripts/test-runtime-token-publication.py", From 06caba5d8197c10ec7abe7faec4a2c09a7b693f9 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 23:28:23 +0700 Subject: [PATCH 085/132] verify strict api counter schema in image --- scripts/verify-miner-observer-image.sh | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/scripts/verify-miner-observer-image.sh b/scripts/verify-miner-observer-image.sh index 655a27c1..85226d5f 100644 --- a/scripts/verify-miner-observer-image.sh +++ b/scripts/verify-miner-observer-image.sh @@ -129,6 +129,30 @@ if active_metrics.get("pool_connected") is not True: if active_state != ("ready", None): raise SystemExit(f"extracted observer rejects active hashrate: {active_state}") +schema_metrics = module.summary_metrics({ + "connection": { + "accepted": 43.9, + "rejected": 1.2, + "failures": 2.5, + "ping": 109.7, + }, + "results": { + "shares_good": 42.8, + "shares_total": 44.1, + }, + "hugepages": [1168.5, 1169.5], +}) +for key in ( + "accepted_shares", + "rejected_shares", + "connection_failures", + "pool_ping_ms", + "hugepages_used", + "hugepages_total", +): + if schema_metrics.get(key) is not None: + raise SystemExit(f"extracted observer truncates fractional counters: {key}") + old_ready_new_external = "\n".join([ "miner speed 10s/60s/15m 341.2 340.9 340.7 H/s", "cpu accepted (43/0) diff 10000", @@ -207,6 +231,7 @@ for required in \ '"/2/summary"' \ '"Authorization": f"Bearer {token}"' \ 'API_MAX_BYTES = 256 * 1024' \ + 'def nonnegative_integer(value: object) -> int | None:' \ 'connection_ip = connection.get("ip")' \ 'connection_uptime_ms = nonnegative_number(connection.get("uptime_ms"))' \ '"pool_connected": pool_connected' \ From 13d44045be23e90d841536fd1821c3c85fd0f2a7 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 23:30:28 +0700 Subject: [PATCH 086/132] require integer uptime evidence --- build/usb/includes.chroot/usr/lib/rigos/rigos-miner-health | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/build/usb/includes.chroot/usr/lib/rigos/rigos-miner-health b/build/usb/includes.chroot/usr/lib/rigos/rigos-miner-health index 57953a6e..b8cf8733 100644 --- a/build/usb/includes.chroot/usr/lib/rigos/rigos-miner-health +++ b/build/usb/includes.chroot/usr/lib/rigos/rigos-miner-health @@ -322,8 +322,8 @@ def summary_metrics(summary: dict) -> dict: connection_ip = connection.get("ip") if not isinstance(connection_ip, str) or not connection_ip: connection_ip = None - connection_uptime_seconds = nonnegative_number(connection.get("uptime")) - connection_uptime_ms = nonnegative_number(connection.get("uptime_ms")) + connection_uptime_seconds = nonnegative_integer(connection.get("uptime")) + connection_uptime_ms = nonnegative_integer(connection.get("uptime_ms")) pool_connected = pool is not None and ( connection_ip is not None or (connection_uptime_ms is not None and connection_uptime_ms > 0) @@ -338,7 +338,7 @@ def summary_metrics(summary: dict) -> dict: hugepages_total = nonnegative_integer(hugepages[1]) return { - "uptime_seconds": nonnegative_number(summary.get("uptime")), + "uptime_seconds": nonnegative_integer(summary.get("uptime")), "algorithm": summary.get("algo") if isinstance(summary.get("algo"), str) else None, "hashrate_10s": rates[0], "hashrate_60s": rates[1], From bdb2c28e0937b11f6365b6d270a9b920a25243e4 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 23:30:51 +0700 Subject: [PATCH 087/132] test strict uptime schema --- scripts/test-miner-health-api-schema.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/scripts/test-miner-health-api-schema.py b/scripts/test-miner-health-api-schema.py index 66cdc171..297f08c7 100644 --- a/scripts/test-miner-health-api-schema.py +++ b/scripts/test-miner-health-api-schema.py @@ -49,6 +49,22 @@ def test_fractional_counters_are_rejected_not_truncated(self): self.assertIsNone(metrics["hugepages_used"]) self.assertIsNone(metrics["hugepages_total"]) + def test_fractional_uptime_cannot_assert_active_connection(self): + metrics = self.module.summary_metrics({ + "uptime": 900.5, + "connection": { + "pool": "pool.example:1234", + "ip": None, + "uptime": 0.1, + "uptime_ms": 0.5, + }, + }) + + self.assertIsNone(metrics["uptime_seconds"]) + self.assertIsNone(metrics["connection_uptime_seconds"]) + self.assertIsNone(metrics["connection_uptime_ms"]) + self.assertFalse(metrics["pool_connected"]) + def test_boolean_counters_are_rejected(self): metrics = self.module.summary_metrics({ "connection": {"accepted": True, "rejected": False}, From 87839f0dbcaefabf1edf119b916639c7223e272d Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 23:31:43 +0700 Subject: [PATCH 088/132] verify strict uptime authority in image --- scripts/verify-miner-observer-image.sh | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/scripts/verify-miner-observer-image.sh b/scripts/verify-miner-observer-image.sh index 85226d5f..ad941e79 100644 --- a/scripts/verify-miner-observer-image.sh +++ b/scripts/verify-miner-observer-image.sh @@ -130,7 +130,12 @@ if active_state != ("ready", None): raise SystemExit(f"extracted observer rejects active hashrate: {active_state}") schema_metrics = module.summary_metrics({ + "uptime": 900.5, "connection": { + "pool": "pool.example:1234", + "ip": None, + "uptime": 0.1, + "uptime_ms": 0.5, "accepted": 43.9, "rejected": 1.2, "failures": 2.5, @@ -143,6 +148,9 @@ schema_metrics = module.summary_metrics({ "hugepages": [1168.5, 1169.5], }) for key in ( + "uptime_seconds", + "connection_uptime_seconds", + "connection_uptime_ms", "accepted_shares", "rejected_shares", "connection_failures", @@ -152,6 +160,8 @@ for key in ( ): if schema_metrics.get(key) is not None: raise SystemExit(f"extracted observer truncates fractional counters: {key}") +if schema_metrics.get("pool_connected") is not False: + raise SystemExit("extracted observer trusts fractional uptime as active") old_ready_new_external = "\n".join([ "miner speed 10s/60s/15m 341.2 340.9 340.7 H/s", @@ -233,7 +243,7 @@ for required in \ 'API_MAX_BYTES = 256 * 1024' \ 'def nonnegative_integer(value: object) -> int | None:' \ 'connection_ip = connection.get("ip")' \ - 'connection_uptime_ms = nonnegative_number(connection.get("uptime_ms"))' \ + 'connection_uptime_ms = nonnegative_integer(connection.get("uptime_ms"))' \ '"pool_connected": pool_connected' \ 'current_hashrate = api_metrics.get("hashrate_10s")' \ 'if pool_connected and current_hashrate_positive:' \ From 55fec76b7351f7427f735b9ab97e372a8373e457 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 23:36:01 +0700 Subject: [PATCH 089/132] gate miner stability integration on unix --- crates/rigos-config/tests/miner_stability.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/crates/rigos-config/tests/miner_stability.rs b/crates/rigos-config/tests/miner_stability.rs index 37a6405c..d156d07a 100644 --- a/crates/rigos-config/tests/miner_stability.rs +++ b/crates/rigos-config/tests/miner_stability.rs @@ -1,3 +1,5 @@ +#![cfg(unix)] + use serde_json::Value; use std::fs; use std::os::unix::fs::{PermissionsExt, symlink}; From affbf577896686db6200403fc1943aa1d466cb2a Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 23:36:23 +0700 Subject: [PATCH 090/132] gate runtime publication integration on unix --- crates/rigos-config/tests/hive_exit_runtime_publish.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/crates/rigos-config/tests/hive_exit_runtime_publish.rs b/crates/rigos-config/tests/hive_exit_runtime_publish.rs index 55462e35..15e5decb 100644 --- a/crates/rigos-config/tests/hive_exit_runtime_publish.rs +++ b/crates/rigos-config/tests/hive_exit_runtime_publish.rs @@ -1,3 +1,5 @@ +#![cfg(unix)] + use serde_json::Value; use std::fs; use std::os::unix::fs::{PermissionsExt, symlink}; From 5df80c0df0aba0095ee8a88272b37609d8600b51 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 23:36:47 +0700 Subject: [PATCH 091/132] avoid windows-only unused permissions warning --- crates/rigos-config/tests/recovery_access.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/crates/rigos-config/tests/recovery_access.rs b/crates/rigos-config/tests/recovery_access.rs index 79e156b2..fe6ff850 100644 --- a/crates/rigos-config/tests/recovery_access.rs +++ b/crates/rigos-config/tests/recovery_access.rs @@ -165,11 +165,12 @@ fn alpha8_appliance_wiring_is_explicit() { .expect("read runtime authority service"); assert!(runtime_service.contains("ExecStart=/usr/lib/rigos/rigos-runtime-authority")); - let authority = repo_path("build/usb/includes.chroot/usr/lib/rigos/rigos-runtime-authority"); - let mode = fs::metadata(authority).unwrap().permissions(); #[cfg(unix)] { use std::os::unix::fs::PermissionsExt; + let authority = + repo_path("build/usb/includes.chroot/usr/lib/rigos/rigos-runtime-authority"); + let mode = fs::metadata(authority).unwrap().permissions(); assert_ne!(mode.mode() & 0o111, 0); } From 201fa37624a888540a3cfaa0b8d68e4f9d00493c Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 23:37:18 +0700 Subject: [PATCH 092/132] guard unix integration platform gates --- .../tests/miner_observer_authority.rs | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/crates/rigos-config/tests/miner_observer_authority.rs b/crates/rigos-config/tests/miner_observer_authority.rs index a1b03204..2262dec4 100644 --- a/crates/rigos-config/tests/miner_observer_authority.rs +++ b/crates/rigos-config/tests/miner_observer_authority.rs @@ -104,6 +104,34 @@ fn observer_authority_is_wired_into_build_and_exact_image_gates() { } } +#[test] +fn unix_only_integrations_are_explicitly_platform_gated() { + for path in [ + "crates/rigos-config/tests/miner_stability.rs", + "crates/rigos-config/tests/hive_exit_runtime_publish.rs", + ] { + let source = fs::read_to_string(repo_path(path)) + .unwrap_or_else(|error| panic!("read Unix integration {path}: {error}")); + assert!( + source.starts_with("#![cfg(unix)]\n"), + "Unix integration is not explicitly platform gated: {path}" + ); + } + + let recovery = fs::read_to_string(repo_path("crates/rigos-config/tests/recovery_access.rs")) + .expect("read recovery access integration"); + let unix_scope = recovery + .find("#[cfg(unix)]\n {") + .expect("recovery executable-mode assertion is not Unix scoped"); + let permissions_import = recovery + .find("use std::os::unix::fs::PermissionsExt;") + .expect("recovery Unix permissions import is missing"); + let mode_binding = recovery + .find("let mode = fs::metadata(authority).unwrap().permissions();") + .expect("recovery Unix mode binding is missing"); + assert!(unix_scope < permissions_import && permissions_import < mode_binding); +} + #[test] fn observer_test_files_are_regular_repository_files() { for path in [ From 27421dc5f3ff6fdce358ad061917dd6be96045cc Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 23:42:04 +0700 Subject: [PATCH 093/132] gate RandomX MSR integration on unix --- crates/rigos-config/tests/randomx_msr_authority.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/crates/rigos-config/tests/randomx_msr_authority.rs b/crates/rigos-config/tests/randomx_msr_authority.rs index 8197feb6..4cd8e11e 100644 --- a/crates/rigos-config/tests/randomx_msr_authority.rs +++ b/crates/rigos-config/tests/randomx_msr_authority.rs @@ -1,3 +1,5 @@ +#![cfg(unix)] + use serde_json::Value; use std::fs::{self, File, OpenOptions}; use std::io::{Seek, SeekFrom, Write}; From 12f64751ffa88ee4ec2f59630687b41caa0f581a Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 23:42:33 +0700 Subject: [PATCH 094/132] guard RandomX MSR Unix platform gate --- crates/rigos-config/tests/miner_observer_authority.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/rigos-config/tests/miner_observer_authority.rs b/crates/rigos-config/tests/miner_observer_authority.rs index 2262dec4..3aabf6eb 100644 --- a/crates/rigos-config/tests/miner_observer_authority.rs +++ b/crates/rigos-config/tests/miner_observer_authority.rs @@ -109,6 +109,7 @@ fn unix_only_integrations_are_explicitly_platform_gated() { for path in [ "crates/rigos-config/tests/miner_stability.rs", "crates/rigos-config/tests/hive_exit_runtime_publish.rs", + "crates/rigos-config/tests/randomx_msr_authority.rs", ] { let source = fs::read_to_string(repo_path(path)) .unwrap_or_else(|error| panic!("read Unix integration {path}: {error}")); From b28aeee021b1249e7ab6c7a7571d7284f6ee7142 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 23:43:11 +0700 Subject: [PATCH 095/132] document Windows and Linux source gate separation --- docs/developer/windows-source-gate.txt | 67 ++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 docs/developer/windows-source-gate.txt diff --git a/docs/developer/windows-source-gate.txt b/docs/developer/windows-source-gate.txt new file mode 100644 index 00000000..55d54061 --- /dev/null +++ b/docs/developer/windows-source-gate.txt @@ -0,0 +1,67 @@ +DBYTE RIGOS WINDOWS SOURCE GATE +=============================== + +PURPOSE +------- + +Windows may compile and run cross-platform source tests. Linux remains the +authoritative environment for Unix runtime integration, image construction, +filesystem permission semantics, systemd verification, and physical gates. + +POWERSHELL RULE +--------------- + +PowerShell does not use a trailing backslash as a line continuation. Run Cargo +commands on one line, or use PowerShell's backtick continuation explicitly. + +SAFE BRANCH RECOVERY +-------------------- + +When a local performance branch still points at the historical ADDED BASED +commit, preserve that history before aligning the working branch with origin: + + git status --short + git branch backup/local-based-b25f0bf b25f0bf1ab902a22bb06a8e363fcdf51d66cafe7 + git fetch origin performance/randomx-sustained-hash + git reset --hard origin/performance/randomx-sustained-hash + +Do not rebase the ADDED BASED commits onto the performance branch. That history +contains the raw HiveOS reference tree intentionally removed from PR #15. + +WINDOWS COMMANDS +---------------- + + cargo test --locked -p rigos-config --test miner_observer_authority -- --nocapture + cargo test --locked -p rigos-config --no-run + +The following integration targets are intentionally Unix-only and must retain a +file-level #![cfg(unix)] gate: + + crates/rigos-config/tests/miner_stability.rs + crates/rigos-config/tests/hive_exit_runtime_publish.rs + crates/rigos-config/tests/randomx_msr_authority.rs + +LINUX COMMANDS +-------------- + +Run these inside an actual WSL/Linux shell with Linux Rust installed: + + cd /mnt/d/TECHNICAL/dbyte-rigos + source "$HOME/.cargo/env" + cargo --version + bash ./scripts/verify.sh + +Typing /mnt/d paths or source commands directly into PowerShell does not enter +WSL. From PowerShell, launch a Linux shell first with: + + wsl.exe + +or invoke the command explicitly: + + wsl.exe bash -lc 'cd /mnt/d/TECHNICAL/dbyte-rigos && source "$HOME/.cargo/env" && bash ./scripts/verify.sh' + +EVIDENCE RULE +------------- + +A Windows compile PASS is not a Linux runtime PASS. An exact image PASS and +physical PASS remain separate gates. From f4603918b6bf949072357203fdd7ad2d68827f0b Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 23:55:31 +0700 Subject: [PATCH 096/132] format miner observer authority test --- .../tests/miner_observer_authority.rs | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/crates/rigos-config/tests/miner_observer_authority.rs b/crates/rigos-config/tests/miner_observer_authority.rs index 3aabf6eb..b6a43a3c 100644 --- a/crates/rigos-config/tests/miner_observer_authority.rs +++ b/crates/rigos-config/tests/miner_observer_authority.rs @@ -21,7 +21,10 @@ fn run_python(script: &str) { .current_dir(repo_root()) .status() .unwrap_or_else(|error| panic!("failed to execute {script} with {python}: {error}")); - assert!(status.success(), "observer source regression failed: {script}"); + assert!( + status.success(), + "observer source regression failed: {script}" + ); } #[cfg(unix)] @@ -82,7 +85,10 @@ fn observer_authority_is_wired_into_build_and_exact_image_gates() { "latest_journal_signal", "api_error not in (None, \"api_unavailable\")", ] { - assert!(observer.contains(contract), "observer contract missing: {contract}"); + assert!( + observer.contains(contract), + "observer contract missing: {contract}" + ); } assert!(renderer.contains("secrets.token_urlsafe(48)")); @@ -143,10 +149,12 @@ fn observer_test_files_are_regular_repository_files() { "scripts/test-miner-health-journal-fallback.py", "scripts/test-runtime-token-publication.py", ] { - let metadata = fs::metadata(repo_path(path)).unwrap_or_else(|error| { - panic!("observer test file is unavailable: {path}: {error}") - }); - assert!(metadata.is_file(), "observer test path is not a file: {path}"); + let metadata = fs::metadata(repo_path(path)) + .unwrap_or_else(|error| panic!("observer test file is unavailable: {path}: {error}")); + assert!( + metadata.is_file(), + "observer test path is not a file: {path}" + ); } assert!(repo_path("scripts/verify-miner-observer-image.sh").is_file()); From 4b92ee9ae124f70f3a461e5cbf4057dcd529eb36 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Thu, 9 Jul 2026 00:22:41 +0700 Subject: [PATCH 097/132] add fail-closed WSL source gate launcher --- scripts/verify-wsl.ps1 | 60 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 scripts/verify-wsl.ps1 diff --git a/scripts/verify-wsl.ps1 b/scripts/verify-wsl.ps1 new file mode 100644 index 00000000..3deb6218 --- /dev/null +++ b/scripts/verify-wsl.ps1 @@ -0,0 +1,60 @@ +[CmdletBinding()] +param( + [string]$Repository = (Split-Path -Parent $PSScriptRoot), + [string]$Distribution = $env:RIGOS_WSL_DISTRO +) + +$ErrorActionPreference = "Stop" +$PSNativeCommandUseErrorActionPreference = $false + +$WslPrefix = @() +if (-not [string]::IsNullOrWhiteSpace($Distribution)) { + $WslPrefix += @("-d", $Distribution) +} + +$Repository = (Resolve-Path -LiteralPath $Repository).Path +$LinuxRepoOutput = & wsl.exe @WslPrefix -- wslpath -a $Repository 2>&1 +if ($LASTEXITCODE -ne 0) { + throw "WSL_PATH_CONVERSION_FAILED: $LinuxRepoOutput" +} + +$LinuxRepo = ($LinuxRepoOutput | Select-Object -Last 1).Trim() +if ([string]::IsNullOrWhiteSpace($LinuxRepo)) { + throw "WSL_PATH_CONVERSION_EMPTY" +} + +$Shell = @' +set -euo pipefail + +repo="$1" +cd "$repo" + +if [ -f "$HOME/.cargo/env" ]; then + . "$HOME/.cargo/env" +fi + +missing=0 +for tool in cargo rustc python3 bash rg; do + if ! command -v "$tool" >/dev/null 2>&1; then + printf 'RIGOS_WSL_TOOL_MISSING=%s\n' "$tool" >&2 + missing=1 + fi +done + +if [ "$missing" -ne 0 ]; then + printf '%s\n' 'Install the missing tool inside this WSL distribution, then rerun scripts/verify-wsl.ps1.' >&2 + exit 127 +fi + +printf 'RIGOS_WSL_REPO=%s\n' "$repo" +printf 'RIGOS_WSL_CARGO=%s\n' "$(command -v cargo)" +exec bash ./scripts/verify.sh +'@ + +& wsl.exe @WslPrefix -- bash -lc $Shell -- $LinuxRepo +$ExitCode = $LASTEXITCODE +if ($ExitCode -ne 0) { + throw "RIGOS_WSL_SOURCE_GATE_FAILED: exit $ExitCode" +} + +Write-Host "RIGOS_WSL_SOURCE_GATE=PASS" From 9cc5d0a6381945e78b0c02e64cc437b58b3cefef Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Thu, 9 Jul 2026 00:22:49 +0700 Subject: [PATCH 098/132] test WSL source gate launcher contract --- crates/rigos-config/tests/wsl_source_gate.rs | 41 ++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 crates/rigos-config/tests/wsl_source_gate.rs diff --git a/crates/rigos-config/tests/wsl_source_gate.rs b/crates/rigos-config/tests/wsl_source_gate.rs new file mode 100644 index 00000000..2d310b58 --- /dev/null +++ b/crates/rigos-config/tests/wsl_source_gate.rs @@ -0,0 +1,41 @@ +use std::fs; +use std::path::PathBuf; + +fn repo_path(path: &str) -> PathBuf { + PathBuf::from(env!("CARGO_MANIFEST_DIR")) + .join("../..") + .join(path) +} + +#[test] +fn wsl_launcher_is_path_safe_and_fail_closed() { + let launcher = fs::read_to_string(repo_path("scripts/verify-wsl.ps1")) + .expect("read WSL source gate launcher"); + + for required in [ + "$PSScriptRoot", + "wslpath -a", + "RIGOS_WSL_DISTRO", + "command -v \"$tool\"", + "RIGOS_WSL_TOOL_MISSING", + "exec bash ./scripts/verify.sh", + "RIGOS_WSL_SOURCE_GATE=PASS", + ] { + assert!( + launcher.contains(required), + "WSL launcher contract missing: {required}" + ); + } + + for forbidden in [ + "/mnt/d/TECHNICAL/dbyte-rigos", + "curl | sh", + "Invoke-WebRequest", + "rustup-init", + ] { + assert!( + !launcher.contains(forbidden), + "WSL launcher contains forbidden bootstrap or hard-coded path: {forbidden}" + ); + } +} From 524eafb20f68f79f8b28fb6133292d44079ba7eb Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Thu, 9 Jul 2026 00:23:05 +0700 Subject: [PATCH 099/132] document fail-closed WSL source verification --- docs/developer/windows-source-gate.txt | 70 +++++++++++++++++--------- 1 file changed, 45 insertions(+), 25 deletions(-) diff --git a/docs/developer/windows-source-gate.txt b/docs/developer/windows-source-gate.txt index 55d54061..a8de08f5 100644 --- a/docs/developer/windows-source-gate.txt +++ b/docs/developer/windows-source-gate.txt @@ -14,24 +14,22 @@ POWERSHELL RULE PowerShell does not use a trailing backslash as a line continuation. Run Cargo commands on one line, or use PowerShell's backtick continuation explicitly. -SAFE BRANCH RECOVERY --------------------- +BASED RECOVERY RULE +------------------- -When a local performance branch still points at the historical ADDED BASED -commit, preserve that history before aligning the working branch with origin: +The historical raw HiveOS filesystem import must not remain reachable from any +production branch, tag, or local Git backup branch. Preserve any required +reference outside Git in encrypted or offline storage, then use a fresh +single-branch clone as the canonical development checkout. - git status --short - git branch backup/local-based-b25f0bf b25f0bf1ab902a22bb06a8e363fcdf51d66cafe7 - git fetch origin performance/randomx-sustained-hash - git reset --hard origin/performance/randomx-sustained-hash - -Do not rebase the ADDED BASED commits onto the performance branch. That history -contains the raw HiveOS reference tree intentionally removed from PR #15. +Never rebase the historical BASED commits onto a production branch. WINDOWS COMMANDS ---------------- + cargo fmt --all -- --check cargo test --locked -p rigos-config --test miner_observer_authority -- --nocapture + cargo test --locked -p rigos-config --test wsl_source_gate -- --nocapture cargo test --locked -p rigos-config --no-run The following integration targets are intentionally Unix-only and must retain a @@ -41,27 +39,49 @@ file-level #![cfg(unix)] gate: crates/rigos-config/tests/hive_exit_runtime_publish.rs crates/rigos-config/tests/randomx_msr_authority.rs -LINUX COMMANDS --------------- +LINUX AUTHORITY FROM POWERSHELL +------------------------------- -Run these inside an actual WSL/Linux shell with Linux Rust installed: +Run the fail-closed launcher from the repository root: - cd /mnt/d/TECHNICAL/dbyte-rigos - source "$HOME/.cargo/env" - cargo --version - bash ./scripts/verify.sh + powershell -ExecutionPolicy Bypass -File .\scripts\verify-wsl.ps1 + +The launcher: + + - derives the repository from its own location + - converts the Windows path through wslpath + - sources $HOME/.cargo/env when present + - checks cargo, rustc, python3, bash, and rg + - does not download or install tools + - executes scripts/verify.sh only after every prerequisite is present + +To select a specific installed WSL distribution: + + powershell -ExecutionPolicy Bypass -File .\scripts\verify-wsl.ps1 -Distribution Ubuntu -Typing /mnt/d paths or source commands directly into PowerShell does not enter -WSL. From PowerShell, launch a Linux shell first with: +or set: - wsl.exe + $env:RIGOS_WSL_DISTRO = "Ubuntu" -or invoke the command explicitly: +A missing dependency is reported as: - wsl.exe bash -lc 'cd /mnt/d/TECHNICAL/dbyte-rigos && source "$HOME/.cargo/env" && bash ./scripts/verify.sh' + RIGOS_WSL_TOOL_MISSING= + +Install that tool inside the selected WSL distribution and rerun the launcher. +Do not type /mnt paths or source commands directly into PowerShell. + +DIRECT LINUX COMMANDS +--------------------- + +Inside an actual WSL/Linux shell with Linux Rust installed: + + cd /mnt/d/TECHNICAL/dbyte-rigos + source "$HOME/.cargo/env" + cargo --version + bash ./scripts/verify.sh EVIDENCE RULE ------------- -A Windows compile PASS is not a Linux runtime PASS. An exact image PASS and -physical PASS remain separate gates. +A Windows compile PASS is not a Linux runtime PASS. A Linux source PASS is not +an exact-image PASS. Exact-image and physical PASS remain separate gates. From cd4d422508a9d78efb94f6906835e43fc7645a38 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Thu, 9 Jul 2026 00:24:08 +0700 Subject: [PATCH 100/132] harden WSL source gate prerequisite checks --- scripts/verify-wsl.ps1 | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/scripts/verify-wsl.ps1 b/scripts/verify-wsl.ps1 index 3deb6218..dafbdd8b 100644 --- a/scripts/verify-wsl.ps1 +++ b/scripts/verify-wsl.ps1 @@ -34,7 +34,7 @@ if [ -f "$HOME/.cargo/env" ]; then fi missing=0 -for tool in cargo rustc python3 bash rg; do +for tool in cargo rustc python3 bash sh git grep rg mktemp; do if ! command -v "$tool" >/dev/null 2>&1; then printf 'RIGOS_WSL_TOOL_MISSING=%s\n' "$tool" >&2 missing=1 @@ -46,6 +46,18 @@ if [ "$missing" -ne 0 ]; then exit 127 fi +for component in fmt clippy; do + if ! cargo "$component" --version >/dev/null 2>&1; then + printf 'RIGOS_WSL_CARGO_COMPONENT_MISSING=%s\n' "$component" >&2 + missing=1 + fi +done + +if [ "$missing" -ne 0 ]; then + printf '%s\n' 'Install the missing Rust component inside this WSL distribution, then rerun scripts/verify-wsl.ps1.' >&2 + exit 127 +fi + printf 'RIGOS_WSL_REPO=%s\n' "$repo" printf 'RIGOS_WSL_CARGO=%s\n' "$(command -v cargo)" exec bash ./scripts/verify.sh From b0d6f2f9a81dccbd1dbe7c844191094ad6c32a6e Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Thu, 9 Jul 2026 00:24:22 +0700 Subject: [PATCH 101/132] lock WSL tool and Rust component preflight --- crates/rigos-config/tests/wsl_source_gate.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/crates/rigos-config/tests/wsl_source_gate.rs b/crates/rigos-config/tests/wsl_source_gate.rs index 2d310b58..7925b44a 100644 --- a/crates/rigos-config/tests/wsl_source_gate.rs +++ b/crates/rigos-config/tests/wsl_source_gate.rs @@ -16,8 +16,11 @@ fn wsl_launcher_is_path_safe_and_fail_closed() { "$PSScriptRoot", "wslpath -a", "RIGOS_WSL_DISTRO", + "for tool in cargo rustc python3 bash sh git grep rg mktemp", "command -v \"$tool\"", "RIGOS_WSL_TOOL_MISSING", + "for component in fmt clippy", + "RIGOS_WSL_CARGO_COMPONENT_MISSING", "exec bash ./scripts/verify.sh", "RIGOS_WSL_SOURCE_GATE=PASS", ] { From e0deca8831be6feef41418cd7a32bd4e0fef62d5 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Thu, 9 Jul 2026 00:24:38 +0700 Subject: [PATCH 102/132] document complete WSL prerequisite preflight --- docs/developer/windows-source-gate.txt | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/docs/developer/windows-source-gate.txt b/docs/developer/windows-source-gate.txt index a8de08f5..6ac5667c 100644 --- a/docs/developer/windows-source-gate.txt +++ b/docs/developer/windows-source-gate.txt @@ -51,7 +51,8 @@ The launcher: - derives the repository from its own location - converts the Windows path through wslpath - sources $HOME/.cargo/env when present - - checks cargo, rustc, python3, bash, and rg + - checks cargo, rustc, python3, bash, sh, git, grep, rg, and mktemp + - checks the Rust fmt and clippy cargo components - does not download or install tools - executes scripts/verify.sh only after every prerequisite is present @@ -63,12 +64,14 @@ or set: $env:RIGOS_WSL_DISTRO = "Ubuntu" -A missing dependency is reported as: +A missing executable or Rust component is reported as: RIGOS_WSL_TOOL_MISSING= + RIGOS_WSL_CARGO_COMPONENT_MISSING= -Install that tool inside the selected WSL distribution and rerun the launcher. -Do not type /mnt paths or source commands directly into PowerShell. +Install the missing prerequisite inside the selected WSL distribution and rerun +the launcher. Do not type /mnt paths or source commands directly into +PowerShell. DIRECT LINUX COMMANDS --------------------- From f14d9ae41c1c9186083cacdfd82aaaf68279fa43 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Thu, 9 Jul 2026 00:27:17 +0700 Subject: [PATCH 103/132] fix PowerShell script root resolution --- scripts/verify-wsl.ps1 | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/scripts/verify-wsl.ps1 b/scripts/verify-wsl.ps1 index dafbdd8b..0d8dda8a 100644 --- a/scripts/verify-wsl.ps1 +++ b/scripts/verify-wsl.ps1 @@ -1,12 +1,19 @@ [CmdletBinding()] param( - [string]$Repository = (Split-Path -Parent $PSScriptRoot), + [string]$Repository, [string]$Distribution = $env:RIGOS_WSL_DISTRO ) $ErrorActionPreference = "Stop" $PSNativeCommandUseErrorActionPreference = $false +if ([string]::IsNullOrWhiteSpace($Repository)) { + if ([string]::IsNullOrWhiteSpace($PSScriptRoot)) { + throw "RIGOS_WSL_SCRIPT_ROOT_UNAVAILABLE" + } + $Repository = Split-Path -Parent $PSScriptRoot +} + $WslPrefix = @() if (-not [string]::IsNullOrWhiteSpace($Distribution)) { $WslPrefix += @("-d", $Distribution) From d9d0da6f91a65cfe3c7b8af9c61196c41251b428 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Thu, 9 Jul 2026 00:27:46 +0700 Subject: [PATCH 104/132] resolve observer test repository root at runtime --- .../tests/miner_observer_authority.rs | 49 +++++++++++++++++-- 1 file changed, 44 insertions(+), 5 deletions(-) diff --git a/crates/rigos-config/tests/miner_observer_authority.rs b/crates/rigos-config/tests/miner_observer_authority.rs index b6a43a3c..bfe65e57 100644 --- a/crates/rigos-config/tests/miner_observer_authority.rs +++ b/crates/rigos-config/tests/miner_observer_authority.rs @@ -1,12 +1,39 @@ #[cfg(unix)] -use std::env; -use std::fs; -use std::path::PathBuf; -#[cfg(unix)] use std::process::Command; +use std::{env, fs}; +use std::path::{Path, PathBuf}; + +fn is_repo_root(path: &Path) -> bool { + path.join("Cargo.toml").is_file() + && path.join("crates/rigos-config/Cargo.toml").is_file() + && path.join("scripts/verify.sh").is_file() +} fn repo_root() -> PathBuf { - PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../..") + let mut starts = Vec::new(); + + if let Ok(current) = env::current_dir() { + starts.push(current); + } + if let Ok(executable) = env::current_exe() { + if let Some(parent) = executable.parent() { + starts.push(parent.to_path_buf()); + } + } + + for start in starts { + let mut candidate = start; + loop { + if is_repo_root(&candidate) { + return candidate; + } + if !candidate.pop() { + break; + } + } + } + + panic!("unable to locate the RIGOS repository root at runtime"); } fn repo_path(path: &str) -> PathBuf { @@ -159,3 +186,15 @@ fn observer_test_files_are_regular_repository_files() { assert!(repo_path("scripts/verify-miner-observer-image.sh").is_file()); } + +#[test] +fn repository_root_is_resolved_at_runtime() { + let root = repo_root(); + assert!(is_repo_root(&root)); + + let source = fs::read_to_string(root.join( + "crates/rigos-config/tests/miner_observer_authority.rs", + )) + .expect("read observer authority source"); + assert!(!source.contains("CARGO_MANIFEST_DIR")); +} From a867e35bd4fa0597f351723eb40d2afe414e367c Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Thu, 9 Jul 2026 00:28:00 +0700 Subject: [PATCH 105/132] make WSL launcher test relocation-safe --- crates/rigos-config/tests/wsl_source_gate.rs | 55 ++++++++++++++++++-- 1 file changed, 50 insertions(+), 5 deletions(-) diff --git a/crates/rigos-config/tests/wsl_source_gate.rs b/crates/rigos-config/tests/wsl_source_gate.rs index 7925b44a..189b1ea9 100644 --- a/crates/rigos-config/tests/wsl_source_gate.rs +++ b/crates/rigos-config/tests/wsl_source_gate.rs @@ -1,10 +1,42 @@ +use std::env; use std::fs; -use std::path::PathBuf; +use std::path::{Path, PathBuf}; + +fn is_repo_root(path: &Path) -> bool { + path.join("Cargo.toml").is_file() + && path.join("crates/rigos-config/Cargo.toml").is_file() + && path.join("scripts/verify.sh").is_file() +} + +fn repo_root() -> PathBuf { + let mut starts = Vec::new(); + + if let Ok(current) = env::current_dir() { + starts.push(current); + } + if let Ok(executable) = env::current_exe() { + if let Some(parent) = executable.parent() { + starts.push(parent.to_path_buf()); + } + } + + for start in starts { + let mut candidate = start; + loop { + if is_repo_root(&candidate) { + return candidate; + } + if !candidate.pop() { + break; + } + } + } + + panic!("unable to locate the RIGOS repository root at runtime"); +} fn repo_path(path: &str) -> PathBuf { - PathBuf::from(env!("CARGO_MANIFEST_DIR")) - .join("../..") - .join(path) + repo_root().join(path) } #[test] @@ -13,7 +45,9 @@ fn wsl_launcher_is_path_safe_and_fail_closed() { .expect("read WSL source gate launcher"); for required in [ + "[string]$Repository,", "$PSScriptRoot", + "RIGOS_WSL_SCRIPT_ROOT_UNAVAILABLE", "wslpath -a", "RIGOS_WSL_DISTRO", "for tool in cargo rustc python3 bash sh git grep rg mktemp", @@ -31,6 +65,7 @@ fn wsl_launcher_is_path_safe_and_fail_closed() { } for forbidden in [ + "[string]$Repository = (Split-Path -Parent $PSScriptRoot)", "/mnt/d/TECHNICAL/dbyte-rigos", "curl | sh", "Invoke-WebRequest", @@ -38,7 +73,17 @@ fn wsl_launcher_is_path_safe_and_fail_closed() { ] { assert!( !launcher.contains(forbidden), - "WSL launcher contains forbidden bootstrap or hard-coded path: {forbidden}" + "WSL launcher contains forbidden bootstrap, default expression, or hard-coded path: {forbidden}" ); } } + +#[test] +fn repository_root_is_resolved_at_runtime() { + let root = repo_root(); + assert!(is_repo_root(&root)); + + let source = fs::read_to_string(root.join("crates/rigos-config/tests/wsl_source_gate.rs")) + .expect("read WSL source gate test"); + assert!(!source.contains("CARGO_MANIFEST_DIR")); +} From 1c4097d8c13b210ad32b16d199deb0ae244995f1 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Thu, 9 Jul 2026 00:28:31 +0700 Subject: [PATCH 106/132] fix observer relocation regression assertion --- crates/rigos-config/tests/miner_observer_authority.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/crates/rigos-config/tests/miner_observer_authority.rs b/crates/rigos-config/tests/miner_observer_authority.rs index bfe65e57..4f75ea83 100644 --- a/crates/rigos-config/tests/miner_observer_authority.rs +++ b/crates/rigos-config/tests/miner_observer_authority.rs @@ -1,7 +1,7 @@ #[cfg(unix)] use std::process::Command; -use std::{env, fs}; use std::path::{Path, PathBuf}; +use std::{env, fs}; fn is_repo_root(path: &Path) -> bool { path.join("Cargo.toml").is_file() @@ -196,5 +196,6 @@ fn repository_root_is_resolved_at_runtime() { "crates/rigos-config/tests/miner_observer_authority.rs", )) .expect("read observer authority source"); - assert!(!source.contains("CARGO_MANIFEST_DIR")); + let compile_time_manifest = ["CARGO", "_MANIFEST_DIR"].concat(); + assert!(!source.contains(&compile_time_manifest)); } From 8060bb3da6967208b60f0dca5b192cb992ea8f2d Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Thu, 9 Jul 2026 00:28:46 +0700 Subject: [PATCH 107/132] fix WSL relocation regression assertion --- crates/rigos-config/tests/wsl_source_gate.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/crates/rigos-config/tests/wsl_source_gate.rs b/crates/rigos-config/tests/wsl_source_gate.rs index 189b1ea9..c1efdfdf 100644 --- a/crates/rigos-config/tests/wsl_source_gate.rs +++ b/crates/rigos-config/tests/wsl_source_gate.rs @@ -85,5 +85,6 @@ fn repository_root_is_resolved_at_runtime() { let source = fs::read_to_string(root.join("crates/rigos-config/tests/wsl_source_gate.rs")) .expect("read WSL source gate test"); - assert!(!source.contains("CARGO_MANIFEST_DIR")); + let compile_time_manifest = ["CARGO", "_MANIFEST_DIR"].concat(); + assert!(!source.contains(&compile_time_manifest)); } From 568135e18116593e4b283e9e167ab185a0eed5e5 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Thu, 9 Jul 2026 00:35:11 +0700 Subject: [PATCH 108/132] preserve Windows paths across WSL transport --- scripts/verify-wsl.ps1 | 39 ++++++++++++++++++++++++++++++++------- 1 file changed, 32 insertions(+), 7 deletions(-) diff --git a/scripts/verify-wsl.ps1 b/scripts/verify-wsl.ps1 index 0d8dda8a..2b3bc82c 100644 --- a/scripts/verify-wsl.ps1 +++ b/scripts/verify-wsl.ps1 @@ -19,13 +19,30 @@ if (-not [string]::IsNullOrWhiteSpace($Distribution)) { $WslPrefix += @("-d", $Distribution) } -$Repository = (Resolve-Path -LiteralPath $Repository).Path -$LinuxRepoOutput = & wsl.exe @WslPrefix -- wslpath -a $Repository 2>&1 -if ($LASTEXITCODE -ne 0) { - throw "WSL_PATH_CONVERSION_FAILED: $LinuxRepoOutput" +$Repository = (Resolve-Path -LiteralPath $Repository -ErrorAction Stop).Path +$PathConverter = @' +set -euo pipefail +IFS= read -r windows_path +windows_path="${windows_path%$'\r'}" +wslpath -a "$windows_path" +'@ + +$SavedErrorActionPreference = $ErrorActionPreference +$ErrorActionPreference = "Continue" +try { + $LinuxRepoOutput = $Repository | + & wsl.exe @WslPrefix -- bash -lc $PathConverter 2>&1 + $PathExitCode = $LASTEXITCODE +} finally { + $ErrorActionPreference = $SavedErrorActionPreference } -$LinuxRepo = ($LinuxRepoOutput | Select-Object -Last 1).Trim() +$LinuxRepoLines = @($LinuxRepoOutput | ForEach-Object { $_.ToString() }) +if ($PathExitCode -ne 0) { + throw "WSL_PATH_CONVERSION_FAILED: $($LinuxRepoLines -join ' | ')" +} + +$LinuxRepo = ($LinuxRepoLines | Select-Object -Last 1).Trim() if ([string]::IsNullOrWhiteSpace($LinuxRepo)) { throw "WSL_PATH_CONVERSION_EMPTY" } @@ -70,8 +87,16 @@ printf 'RIGOS_WSL_CARGO=%s\n' "$(command -v cargo)" exec bash ./scripts/verify.sh '@ -& wsl.exe @WslPrefix -- bash -lc $Shell -- $LinuxRepo -$ExitCode = $LASTEXITCODE +$SavedErrorActionPreference = $ErrorActionPreference +$ErrorActionPreference = "Continue" +try { + & wsl.exe @WslPrefix -- bash -lc $Shell -- $LinuxRepo 2>&1 | + ForEach-Object { Write-Host $_ } + $ExitCode = $LASTEXITCODE +} finally { + $ErrorActionPreference = $SavedErrorActionPreference +} + if ($ExitCode -ne 0) { throw "RIGOS_WSL_SOURCE_GATE_FAILED: exit $ExitCode" } From 01b35d4365ee5dbe15685234c96dc892c9f90ecb Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Thu, 9 Jul 2026 00:35:28 +0700 Subject: [PATCH 109/132] guard raw Windows path transport into WSL --- crates/rigos-config/tests/wsl_source_gate.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/crates/rigos-config/tests/wsl_source_gate.rs b/crates/rigos-config/tests/wsl_source_gate.rs index c1efdfdf..7d7b0f49 100644 --- a/crates/rigos-config/tests/wsl_source_gate.rs +++ b/crates/rigos-config/tests/wsl_source_gate.rs @@ -48,7 +48,13 @@ fn wsl_launcher_is_path_safe_and_fail_closed() { "[string]$Repository,", "$PSScriptRoot", "RIGOS_WSL_SCRIPT_ROOT_UNAVAILABLE", - "wslpath -a", + "$Repository |", + "bash -lc $PathConverter", + "IFS= read -r windows_path", + "windows_path=\"${windows_path%$'\\r'}\"", + "wslpath -a \"$windows_path\"", + "$PathExitCode = $LASTEXITCODE", + "$ErrorActionPreference = \"Continue\"", "RIGOS_WSL_DISTRO", "for tool in cargo rustc python3 bash sh git grep rg mktemp", "command -v \"$tool\"", @@ -66,6 +72,7 @@ fn wsl_launcher_is_path_safe_and_fail_closed() { for forbidden in [ "[string]$Repository = (Split-Path -Parent $PSScriptRoot)", + "wslpath -a $Repository", "/mnt/d/TECHNICAL/dbyte-rigos", "curl | sh", "Invoke-WebRequest", @@ -73,7 +80,7 @@ fn wsl_launcher_is_path_safe_and_fail_closed() { ] { assert!( !launcher.contains(forbidden), - "WSL launcher contains forbidden bootstrap, default expression, or hard-coded path: {forbidden}" + "WSL launcher contains forbidden bootstrap, direct path argument, default expression, or hard-coded path: {forbidden}" ); } } From b81f7c66fddee6091f1fd3f4998d7d66aa5080f2 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Thu, 9 Jul 2026 00:35:52 +0700 Subject: [PATCH 110/132] format relocation-safe observer authority test --- crates/rigos-config/tests/miner_observer_authority.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/crates/rigos-config/tests/miner_observer_authority.rs b/crates/rigos-config/tests/miner_observer_authority.rs index 4f75ea83..298653a7 100644 --- a/crates/rigos-config/tests/miner_observer_authority.rs +++ b/crates/rigos-config/tests/miner_observer_authority.rs @@ -1,6 +1,6 @@ +use std::path::{Path, PathBuf}; #[cfg(unix)] use std::process::Command; -use std::path::{Path, PathBuf}; use std::{env, fs}; fn is_repo_root(path: &Path) -> bool { @@ -192,10 +192,9 @@ fn repository_root_is_resolved_at_runtime() { let root = repo_root(); assert!(is_repo_root(&root)); - let source = fs::read_to_string(root.join( - "crates/rigos-config/tests/miner_observer_authority.rs", - )) - .expect("read observer authority source"); + let source = + fs::read_to_string(root.join("crates/rigos-config/tests/miner_observer_authority.rs")) + .expect("read observer authority source"); let compile_time_manifest = ["CARGO", "_MANIFEST_DIR"].concat(); assert!(!source.contains(&compile_time_manifest)); } From 64a16f8a4b9a2a7402f44ca15fac3c816cfb5b7b Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Thu, 9 Jul 2026 00:39:18 +0700 Subject: [PATCH 111/132] add WSL source gate entrypoint --- scripts/verify-wsl-entrypoint.sh | 49 ++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 scripts/verify-wsl-entrypoint.sh diff --git a/scripts/verify-wsl-entrypoint.sh b/scripts/verify-wsl-entrypoint.sh new file mode 100644 index 00000000..f4c3ba35 --- /dev/null +++ b/scripts/verify-wsl-entrypoint.sh @@ -0,0 +1,49 @@ +#!/usr/bin/env bash +set -euo pipefail + +if [[ $# -ne 1 ]]; then + echo "usage: verify-wsl-entrypoint.sh REPOSITORY" >&2 + exit 64 +fi + +repo="$1" +if [[ ! -f "$repo/Cargo.toml" || ! -f "$repo/scripts/verify.sh" ]]; then + echo "RIGOS_WSL_REPOSITORY_INVALID=$repo" >&2 + exit 66 +fi + +cd "$repo" + +if [[ -f "$HOME/.cargo/env" ]]; then + # shellcheck disable=SC1091 + . "$HOME/.cargo/env" +fi + +missing=0 +for tool in cargo rustc python3 bash sh git grep rg mktemp; do + if ! command -v "$tool" >/dev/null 2>&1; then + printf 'RIGOS_WSL_TOOL_MISSING=%s\n' "$tool" >&2 + missing=1 + fi +done + +if [[ "$missing" -ne 0 ]]; then + echo "Install the missing tool inside this WSL distribution, then rerun scripts/verify-wsl.ps1." >&2 + exit 127 +fi + +for component in fmt clippy; do + if ! cargo "$component" --version >/dev/null 2>&1; then + printf 'RIGOS_WSL_CARGO_COMPONENT_MISSING=%s\n' "$component" >&2 + missing=1 + fi +done + +if [[ "$missing" -ne 0 ]]; then + echo "Install the missing Rust component inside this WSL distribution, then rerun scripts/verify-wsl.ps1." >&2 + exit 127 +fi + +printf 'RIGOS_WSL_REPO=%s\n' "$repo" +printf 'RIGOS_WSL_CARGO=%s\n' "$(command -v cargo)" +exec bash ./scripts/verify.sh From b4c2c21a3df7a1c6ff4faecc6770933cb0a01f95 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Thu, 9 Jul 2026 00:39:30 +0700 Subject: [PATCH 112/132] use file entrypoint for WSL source gate --- scripts/verify-wsl.ps1 | 52 ++++-------------------------------------- 1 file changed, 4 insertions(+), 48 deletions(-) diff --git a/scripts/verify-wsl.ps1 b/scripts/verify-wsl.ps1 index 2b3bc82c..aa947abd 100644 --- a/scripts/verify-wsl.ps1 +++ b/scripts/verify-wsl.ps1 @@ -20,18 +20,12 @@ if (-not [string]::IsNullOrWhiteSpace($Distribution)) { } $Repository = (Resolve-Path -LiteralPath $Repository -ErrorAction Stop).Path -$PathConverter = @' -set -euo pipefail -IFS= read -r windows_path -windows_path="${windows_path%$'\r'}" -wslpath -a "$windows_path" -'@ +$RepositoryForWsl = $Repository.Replace([char]92, [char]47) $SavedErrorActionPreference = $ErrorActionPreference $ErrorActionPreference = "Continue" try { - $LinuxRepoOutput = $Repository | - & wsl.exe @WslPrefix -- bash -lc $PathConverter 2>&1 + $LinuxRepoOutput = & wsl.exe @WslPrefix -- wslpath -a -- $RepositoryForWsl 2>&1 $PathExitCode = $LASTEXITCODE } finally { $ErrorActionPreference = $SavedErrorActionPreference @@ -47,50 +41,12 @@ if ([string]::IsNullOrWhiteSpace($LinuxRepo)) { throw "WSL_PATH_CONVERSION_EMPTY" } -$Shell = @' -set -euo pipefail - -repo="$1" -cd "$repo" - -if [ -f "$HOME/.cargo/env" ]; then - . "$HOME/.cargo/env" -fi - -missing=0 -for tool in cargo rustc python3 bash sh git grep rg mktemp; do - if ! command -v "$tool" >/dev/null 2>&1; then - printf 'RIGOS_WSL_TOOL_MISSING=%s\n' "$tool" >&2 - missing=1 - fi -done - -if [ "$missing" -ne 0 ]; then - printf '%s\n' 'Install the missing tool inside this WSL distribution, then rerun scripts/verify-wsl.ps1.' >&2 - exit 127 -fi - -for component in fmt clippy; do - if ! cargo "$component" --version >/dev/null 2>&1; then - printf 'RIGOS_WSL_CARGO_COMPONENT_MISSING=%s\n' "$component" >&2 - missing=1 - fi -done - -if [ "$missing" -ne 0 ]; then - printf '%s\n' 'Install the missing Rust component inside this WSL distribution, then rerun scripts/verify-wsl.ps1.' >&2 - exit 127 -fi - -printf 'RIGOS_WSL_REPO=%s\n' "$repo" -printf 'RIGOS_WSL_CARGO=%s\n' "$(command -v cargo)" -exec bash ./scripts/verify.sh -'@ +$LinuxEntrypoint = "$LinuxRepo/scripts/verify-wsl-entrypoint.sh" $SavedErrorActionPreference = $ErrorActionPreference $ErrorActionPreference = "Continue" try { - & wsl.exe @WslPrefix -- bash -lc $Shell -- $LinuxRepo 2>&1 | + & wsl.exe @WslPrefix -- bash $LinuxEntrypoint $LinuxRepo 2>&1 | ForEach-Object { Write-Host $_ } $ExitCode = $LASTEXITCODE } finally { From 03df37b1a0905ccb4a60303ed0abeab71e07ff9d Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Thu, 9 Jul 2026 00:39:43 +0700 Subject: [PATCH 113/132] test file-based WSL source gate transport --- crates/rigos-config/tests/wsl_source_gate.rs | 33 ++++++++++++++------ 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/crates/rigos-config/tests/wsl_source_gate.rs b/crates/rigos-config/tests/wsl_source_gate.rs index 7d7b0f49..d050791a 100644 --- a/crates/rigos-config/tests/wsl_source_gate.rs +++ b/crates/rigos-config/tests/wsl_source_gate.rs @@ -43,36 +43,49 @@ fn repo_path(path: &str) -> PathBuf { fn wsl_launcher_is_path_safe_and_fail_closed() { let launcher = fs::read_to_string(repo_path("scripts/verify-wsl.ps1")) .expect("read WSL source gate launcher"); + let entrypoint = fs::read_to_string(repo_path("scripts/verify-wsl-entrypoint.sh")) + .expect("read WSL source gate entrypoint"); for required in [ "[string]$Repository,", "$PSScriptRoot", "RIGOS_WSL_SCRIPT_ROOT_UNAVAILABLE", - "$Repository |", - "bash -lc $PathConverter", - "IFS= read -r windows_path", - "windows_path=\"${windows_path%$'\\r'}\"", - "wslpath -a \"$windows_path\"", + "$Repository.Replace([char]92, [char]47)", + "wslpath -a -- $RepositoryForWsl", "$PathExitCode = $LASTEXITCODE", "$ErrorActionPreference = \"Continue\"", - "RIGOS_WSL_DISTRO", + "verify-wsl-entrypoint.sh", + "& wsl.exe @WslPrefix -- bash $LinuxEntrypoint $LinuxRepo", + "RIGOS_WSL_SOURCE_GATE=PASS", + ] { + assert!( + launcher.contains(required), + "WSL launcher contract missing: {required}" + ); + } + + for required in [ + "set -euo pipefail", + "RIGOS_WSL_REPOSITORY_INVALID", "for tool in cargo rustc python3 bash sh git grep rg mktemp", "command -v \"$tool\"", "RIGOS_WSL_TOOL_MISSING", "for component in fmt clippy", "RIGOS_WSL_CARGO_COMPONENT_MISSING", "exec bash ./scripts/verify.sh", - "RIGOS_WSL_SOURCE_GATE=PASS", ] { assert!( - launcher.contains(required), - "WSL launcher contract missing: {required}" + entrypoint.contains(required), + "WSL entrypoint contract missing: {required}" ); } for forbidden in [ "[string]$Repository = (Split-Path -Parent $PSScriptRoot)", "wslpath -a $Repository", + "$PathConverter", + "$Shell = @'", + "bash -lc", "/mnt/d/TECHNICAL/dbyte-rigos", "curl | sh", "Invoke-WebRequest", @@ -80,7 +93,7 @@ fn wsl_launcher_is_path_safe_and_fail_closed() { ] { assert!( !launcher.contains(forbidden), - "WSL launcher contains forbidden bootstrap, direct path argument, default expression, or hard-coded path: {forbidden}" + "WSL launcher contains forbidden bootstrap, multiline shell transport, direct path argument, default expression, or hard-coded path: {forbidden}" ); } } From c11a15f6725ffe4158d90db34a8b4175869d1b12 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Thu, 9 Jul 2026 00:40:00 +0700 Subject: [PATCH 114/132] document file-based WSL gate transport --- docs/developer/windows-source-gate.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/developer/windows-source-gate.txt b/docs/developer/windows-source-gate.txt index 6ac5667c..9e20bd5c 100644 --- a/docs/developer/windows-source-gate.txt +++ b/docs/developer/windows-source-gate.txt @@ -49,7 +49,9 @@ Run the fail-closed launcher from the repository root: The launcher: - derives the repository from its own location - - converts the Windows path through wslpath + - normalizes Windows backslashes before invoking wslpath + - invokes scripts/verify-wsl-entrypoint.sh as a real file + - never transports multiline Bash source through a native command argument - sources $HOME/.cargo/env when present - checks cargo, rustc, python3, bash, sh, git, grep, rg, and mktemp - checks the Rust fmt and clippy cargo components From 6aee41f320e73c0455ddf79f322a20885e2ad2cd Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Thu, 9 Jul 2026 00:53:29 +0700 Subject: [PATCH 115/132] make state-ready ordering test semantic --- crates/rigos-config/tests/firstboot_tty.rs | 65 +++++++++++++++------- 1 file changed, 45 insertions(+), 20 deletions(-) diff --git a/crates/rigos-config/tests/firstboot_tty.rs b/crates/rigos-config/tests/firstboot_tty.rs index 3fe2e886..414101a1 100644 --- a/crates/rigos-config/tests/firstboot_tty.rs +++ b/crates/rigos-config/tests/firstboot_tty.rs @@ -1,3 +1,4 @@ +use std::collections::BTreeSet; use std::fs; use std::path::PathBuf; @@ -9,12 +10,19 @@ fn unit(name: &str) -> String { .unwrap_or_else(|error| panic!("failed to read {}: {error}", path.display())) } +fn directive_tokens<'a>(unit: &'a str, prefix: &str) -> BTreeSet<&'a str> { + unit.lines() + .filter_map(|line| line.strip_prefix(prefix)) + .flat_map(str::split_whitespace) + .collect() +} + #[test] fn firstboot_releases_tty1_to_getty_after_exit() { let unit = unit("rigos-firstboot.service"); assert!( - unit.lines().any(|line| line == "Before=getty@tty1.service"), + directive_tokens(&unit, "Before=").contains("getty@tty1.service"), "firstboot must finish before tty1 getty starts" ); assert!( @@ -36,12 +44,14 @@ fn firstboot_releases_tty1_to_getty_after_exit() { #[test] fn recovery_access_does_not_hang_up_the_following_firstboot_session() { let unit = unit("rigos-recovery-access.service"); + let before = directive_tokens(&unit, "Before="); - assert!( - unit.lines() - .any(|line| line.contains("Before=rigos-state-ready.service rigos-firstboot.service")), - "recovery access must complete before firstboot" - ); + for required in ["rigos-state-ready.service", "rigos-firstboot.service"] { + assert!( + before.contains(required), + "recovery access must complete before {required}" + ); + } assert!( !unit.lines().any(|line| line == "TTYVHangup=yes"), "recovery access must not hang up tty1 before firstboot starts" @@ -51,26 +61,41 @@ fn recovery_access_does_not_hang_up_the_following_firstboot_session() { #[test] fn state_ready_stays_out_of_the_local_fs_transaction() { let unit = unit("rigos-state-ready.service"); + let after = directive_tokens(&unit, "After="); + let requires = directive_tokens(&unit, "Requires="); + let before = directive_tokens(&unit, "Before="); assert!(!unit.lines().any(|line| line == "DefaultDependencies=no")); assert!( - !unit - .lines() - .any(|line| line.contains("Before=local-fs.target")) - ); - assert!( - unit.lines() - .any(|line| line == "WantedBy=multi-user.target") + !before.contains("local-fs.target"), + "state readiness must stay out of the local-fs transaction" ); assert!( - unit.lines() - .any(|line| line == "After=rigos-state.service rigos-recovery-access.service") + directive_tokens(&unit, "WantedBy=").contains("multi-user.target"), + "state readiness must be installed under multi-user.target" ); + + for required in ["rigos-state.service", "rigos-recovery-access.service"] { + assert!( + after.contains(required), + "state readiness must start after {required}" + ); + } assert!( - unit.lines() - .any(|line| line == "Requires=rigos-state.service") + requires.contains("rigos-state.service"), + "state readiness must require persistent state" ); - assert!(unit.lines().any(|line| { - line == "Before=rigos-profile-apply.service rigos-firstboot.service rigos-hugepages.service rigos-miner.service" - })); + + for required in [ + "rigos-ssh-hostkeys.service", + "rigos-profile-apply.service", + "rigos-firstboot.service", + "rigos-hugepages.service", + "rigos-miner.service", + ] { + assert!( + before.contains(required), + "state readiness must complete before {required}" + ); + } } From cf2b95bff42843c7be8040ecd646964feda0d5c5 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Thu, 9 Jul 2026 00:58:05 +0700 Subject: [PATCH 116/132] test exact runtime HTTP authority --- .../tests/hive_exit_runtime_publish.rs | 26 ++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/crates/rigos-config/tests/hive_exit_runtime_publish.rs b/crates/rigos-config/tests/hive_exit_runtime_publish.rs index 15e5decb..55b7dec2 100644 --- a/crates/rigos-config/tests/hive_exit_runtime_publish.rs +++ b/crates/rigos-config/tests/hive_exit_runtime_publish.rs @@ -77,6 +77,9 @@ fn staged_runtime_publication_is_allowlisted_atomic_and_fail_closed() { }], "http": { "enabled": false, + "host": "0.0.0.0", + "port": 9999, + "restricted": false, "access-token": "TOKEN_SENTINEL", "future_http": "HTTP_SENTINEL" } @@ -114,10 +117,26 @@ fn staged_runtime_publication_is_allowlisted_atomic_and_fail_closed() { assert_eq!(private["future_top"], "TOP_SENTINEL"); assert_eq!(private["cpu"]["future_cpu"], "CPU_SENTINEL"); assert_eq!(private["pools"][0]["future_pool"], "POOL_SENTINEL"); - assert_eq!(private["http"]["future_http"], "HTTP_SENTINEL"); assert_eq!(private["cpu"]["max-threads-hint"], 100); assert_eq!(private["cpu"]["rx"], serde_json::json!([-1, -1])); + let private_http = private["http"].as_object().expect("private HTTP authority"); + let private_http_keys = private_http.keys().cloned().collect::>(); + assert_eq!( + private_http_keys, + vec!["access-token", "enabled", "host", "port", "restricted"] + ); + assert_eq!(private_http["enabled"], true); + assert_eq!(private_http["host"], "127.0.0.1"); + assert_eq!(private_http["port"], 18080); + assert_eq!(private_http["restricted"], true); + let api_token = private_http["access-token"] + .as_str() + .expect("private API token"); + assert!(api_token.len() >= 32); + assert_ne!(api_token, "TOKEN_SENTINEL"); + assert!(private_http.get("future_http").is_none()); + let public = read_json(&runtime.join("xmrig-public.json")); let public_keys = public .as_object() @@ -144,6 +163,11 @@ fn staged_runtime_publication_is_allowlisted_atomic_and_fail_closed() { assert_eq!(public["randomx"]["huge-pages"].as_bool(), Some(true)); assert_eq!(public["pools"][0]["url"], "pool.test:1"); assert_eq!(public["rigos-public-view"]["construction"], "allowlist"); + assert_eq!(public["http"]["enabled"], true); + assert_eq!(public["http"]["host"], "127.0.0.1"); + assert_eq!(public["http"]["port"], 18080); + assert_eq!(public["http"]["restricted"], true); + assert!(public["http"].get("access-token").is_none()); let public_text = serde_json::to_string(&public).unwrap(); for sentinel in [ "TOP_SENTINEL", From a3bb28af3e10ae97ae91f787aca947936a46e781 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Thu, 9 Jul 2026 01:05:21 +0700 Subject: [PATCH 117/132] exercise miner stability through authenticated API --- crates/rigos-config/tests/miner_stability.rs | 164 +++++++++++++++++-- 1 file changed, 152 insertions(+), 12 deletions(-) diff --git a/crates/rigos-config/tests/miner_stability.rs b/crates/rigos-config/tests/miner_stability.rs index d156d07a..5ac6b66f 100644 --- a/crates/rigos-config/tests/miner_stability.rs +++ b/crates/rigos-config/tests/miner_stability.rs @@ -2,11 +2,17 @@ use serde_json::Value; use std::fs; +use std::io::{Read, Write}; +use std::net::TcpListener; use std::os::unix::fs::{PermissionsExt, symlink}; use std::path::{Path, PathBuf}; use std::process::Command; +use std::thread; +use std::time::Duration; use uuid::Uuid; +const API_TOKEN: &str = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; + fn repo_path(path: &str) -> PathBuf { PathBuf::from(env!("CARGO_MANIFEST_DIR")) .join("../..") @@ -33,13 +39,64 @@ fn write_runtime_status(path: &Path, revision: &str) { .unwrap(); } +fn api_port_and_server(summary: Option) -> (u16, Option>) { + let listener = TcpListener::bind(("127.0.0.1", 0)).unwrap(); + let port = listener.local_addr().unwrap().port(); + + let Some(summary) = summary else { + drop(listener); + return (port, None); + }; + + let server = thread::spawn(move || { + let (mut stream, _) = listener.accept().unwrap(); + stream + .set_read_timeout(Some(Duration::from_secs(5))) + .unwrap(); + stream + .set_write_timeout(Some(Duration::from_secs(5))) + .unwrap(); + + let mut request = Vec::new(); + let mut buffer = [0_u8; 1024]; + loop { + let count = stream.read(&mut buffer).unwrap(); + if count == 0 { + break; + } + request.extend_from_slice(&buffer[..count]); + if request.windows(4).any(|window| window == b"\r\n\r\n") { + break; + } + assert!(request.len() <= 8192, "observer HTTP request is oversized"); + } + + let request = String::from_utf8(request).unwrap(); + assert!(request.starts_with("GET /2/summary HTTP/1.1\r\n")); + assert!(request.contains(&format!("Authorization: Bearer {API_TOKEN}\r\n"))); + + let body = serde_json::to_vec(&summary).unwrap(); + let headers = format!( + "HTTP/1.1 200 OK\r\nContent-Type: application/json\r\nContent-Length: {}\r\nConnection: close\r\n\r\n", + body.len() + ); + stream.write_all(headers.as_bytes()).unwrap(); + stream.write_all(&body).unwrap(); + stream.flush().unwrap(); + }); + + (port, Some(server)) +} + fn run_observer( root: &Path, systemctl: &Path, journalctl: &Path, systemctl_fixture: &Path, journal_fixture: &Path, + api_summary: Option, ) -> Value { + let (api_port, server) = api_port_and_server(api_summary); let status = Command::new("python3") .arg(repo_path( "build/usb/includes.chroot/usr/lib/rigos/rigos-miner-health", @@ -52,12 +109,83 @@ fn run_observer( .env("RIGOS_JOURNALCTL", journalctl) .env("RIGOS_SYSTEMCTL_FIXTURE", systemctl_fixture) .env("RIGOS_JOURNAL_FIXTURE", journal_fixture) + .env( + "RIGOS_XMRIG_API_TOKEN_PATH", + root.join("run/xmrig-api-token"), + ) + .env("RIGOS_XMRIG_API_HOST", "127.0.0.1") + .env("RIGOS_XMRIG_API_PORT", api_port.to_string()) + .env("RIGOS_XMRIG_API_TIMEOUT_SECONDS", "0.5") + .env("RIGOS_MINER_HEALTH_TEST_MODE", "1") .status() .unwrap(); + + if let Some(server) = server { + server.join().unwrap(); + } assert!(status.success()); serde_json::from_slice(&fs::read(root.join("run/miner-health-status.json")).unwrap()).unwrap() } +fn ready_summary() -> Value { + serde_json::json!({ + "uptime": 600, + "algo": "rx/0", + "hashrate": { + "total": [340.0, 341.0, 339.0], + "highest": 342.0 + }, + "connection": { + "pool": "pool.test:1", + "ip": "127.0.0.1", + "uptime": 590, + "accepted": 7, + "rejected": 0, + "failures": 0, + "ping": 20 + }, + "hugepages": [4, 4] + }) +} + +fn disconnected_summary() -> Value { + serde_json::json!({ + "uptime": 600, + "algo": "rx/0", + "hashrate": { + "total": [0.0, 341.0, 339.0], + "highest": 342.0 + }, + "connection": { + "accepted": 7, + "rejected": 0, + "failures": 1 + }, + "hugepages": [4, 4] + }) +} + +fn missing_current_hashrate_summary() -> Value { + serde_json::json!({ + "uptime": 600, + "algo": "rx/0", + "hashrate": { + "total": [null, 341.0, 339.0], + "highest": 342.0 + }, + "connection": { + "pool": "pool.test:1", + "ip": "127.0.0.1", + "uptime": 590, + "accepted": 7, + "rejected": 0, + "failures": 0, + "ping": 20 + }, + "hugepages": [4, 4] + }) +} + #[test] fn miner_health_distinguishes_ready_external_wait_degraded_blocked_and_unknown() { let root = std::env::temp_dir().join(format!("rigos-miner-health-{}", Uuid::new_v4())); @@ -68,6 +196,12 @@ fn miner_health_distinguishes_ready_external_wait_degraded_blocked_and_unknown() fs::write(root.join("boot-id"), "boot-test\n").unwrap(); fs::write(root.join("proc/uptime"), "1000.0 0.0\n").unwrap(); fs::write(root.join("proc/123/stat"), "123 (xmrig) S\n").unwrap(); + fs::write(root.join("run/xmrig-api-token"), format!("{API_TOKEN}\n")).unwrap(); + fs::set_permissions( + root.join("run/xmrig-api-token"), + fs::Permissions::from_mode(0o600), + ) + .unwrap(); write_runtime_status(&root.join("run/runtime-config-status.json"), "r1"); let systemctl_fixture = root.join("systemctl.txt"); @@ -92,58 +226,63 @@ fn miner_health_distinguishes_ready_external_wait_degraded_blocked_and_unknown() write_executable(&journalctl, "#!/bin/sh\ncat \"$RIGOS_JOURNAL_FIXTURE\"\n"); write_executable(&journalctl_fail, "#!/bin/sh\nexit 1\n"); - fs::write( - &journal_fixture, - concat!( - "miner speed 10s/60s/15m 340.0 341.0 n/a H/s\n", - "cpu accepted (7/0) diff 10000\n" - ), - ) - .unwrap(); + fs::write(&journal_fixture, "net connect error: stale journal evidence\n").unwrap(); let ready = run_observer( &root, &systemctl, &journalctl, &systemctl_fixture, &journal_fixture, + Some(ready_summary()), ); assert_eq!(ready["state"], "ready"); + assert_eq!(ready["reason"], Value::Null); assert_eq!(ready["unit"]["restart_count"], 2); + assert_eq!(ready["evidence"]["source"], "xmrig_http_api"); assert_eq!(ready["evidence"]["accepted_shares"], 7); assert_eq!(ready["evidence"]["rejected_shares"], 0); assert_eq!(ready["remediation"], "observe_only"); - fs::write(&journal_fixture, "net connect error: connection refused\n").unwrap(); + fs::write( + &journal_fixture, + "miner speed 10s/60s/15m 340.0 341.0 339.0 H/s\n", + ) + .unwrap(); let waiting = run_observer( &root, &systemctl, &journalctl, &systemctl_fixture, &journal_fixture, + Some(disconnected_summary()), ); assert_eq!(waiting["state"], "waiting_external"); assert_eq!(waiting["reason"], "pool_or_network_unavailable"); + assert_eq!(waiting["evidence"]["source"], "xmrig_http_api"); - fs::write(&journal_fixture, "").unwrap(); let degraded = run_observer( &root, &systemctl, &journalctl, &systemctl_fixture, &journal_fixture, + Some(missing_current_hashrate_summary()), ); assert_eq!(degraded["state"], "degraded"); - assert_eq!(degraded["reason"], "no_recent_speed_evidence"); + assert_eq!(degraded["reason"], "current_hashrate_unavailable"); + assert_eq!(degraded["evidence"]["source"], "xmrig_http_api"); + fs::write(&journal_fixture, "").unwrap(); let unknown = run_observer( &root, &systemctl, &journalctl_fail, &systemctl_fixture, &journal_fixture, + None, ); assert_eq!(unknown["state"], "unknown"); - assert_eq!(unknown["reason"], "journal_unavailable"); + assert_eq!(unknown["reason"], "api_unavailable"); assert_eq!(unknown["evidence"]["journal_available"], false); write_runtime_status(&root.join("run/runtime-config-status.json"), "r2"); @@ -153,6 +292,7 @@ fn miner_health_distinguishes_ready_external_wait_degraded_blocked_and_unknown() &journalctl, &systemctl_fixture, &journal_fixture, + Some(ready_summary()), ); assert_eq!(blocked["state"], "blocked"); assert_eq!(blocked["reason"], "runtime_revision_mismatch"); From 9e73cb747c4f47bcd6e3abab4e005a706966210a Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Thu, 9 Jul 2026 01:14:38 +0700 Subject: [PATCH 118/132] isolate WSL Python bytecode artifacts --- scripts/verify-wsl-entrypoint.sh | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/scripts/verify-wsl-entrypoint.sh b/scripts/verify-wsl-entrypoint.sh index f4c3ba35..55090d9f 100644 --- a/scripts/verify-wsl-entrypoint.sh +++ b/scripts/verify-wsl-entrypoint.sh @@ -44,6 +44,14 @@ if [[ "$missing" -ne 0 ]]; then exit 127 fi +pycache_root=$(mktemp -d) +cleanup() { + rm -rf "$pycache_root" +} +trap cleanup EXIT HUP INT TERM +export PYTHONPYCACHEPREFIX="$pycache_root" +export PYTHONDONTWRITEBYTECODE=1 + printf 'RIGOS_WSL_REPO=%s\n' "$repo" printf 'RIGOS_WSL_CARGO=%s\n' "$(command -v cargo)" -exec bash ./scripts/verify.sh +bash ./scripts/verify.sh From d0a041c663bfef3166fad1ee7d095e3a30208b18 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Thu, 9 Jul 2026 01:14:45 +0700 Subject: [PATCH 119/132] ignore Python bytecode artifacts --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 19d2cb47..11610b1e 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,5 @@ *.age.partial *.pem *.key +__pycache__/ +*.py[cod] From 407d55508e19a266981c0193461f2d6523963f1a Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Thu, 9 Jul 2026 01:14:59 +0700 Subject: [PATCH 120/132] guard WSL pycache isolation --- crates/rigos-config/tests/wsl_source_gate.rs | 22 +++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/crates/rigos-config/tests/wsl_source_gate.rs b/crates/rigos-config/tests/wsl_source_gate.rs index d050791a..21bb22fb 100644 --- a/crates/rigos-config/tests/wsl_source_gate.rs +++ b/crates/rigos-config/tests/wsl_source_gate.rs @@ -72,7 +72,11 @@ fn wsl_launcher_is_path_safe_and_fail_closed() { "RIGOS_WSL_TOOL_MISSING", "for component in fmt clippy", "RIGOS_WSL_CARGO_COMPONENT_MISSING", - "exec bash ./scripts/verify.sh", + "pycache_root=$(mktemp -d)", + "trap cleanup EXIT HUP INT TERM", + "export PYTHONPYCACHEPREFIX=\"$pycache_root\"", + "export PYTHONDONTWRITEBYTECODE=1", + "bash ./scripts/verify.sh", ] { assert!( entrypoint.contains(required), @@ -90,10 +94,22 @@ fn wsl_launcher_is_path_safe_and_fail_closed() { "curl | sh", "Invoke-WebRequest", "rustup-init", + "exec bash ./scripts/verify.sh", ] { assert!( - !launcher.contains(forbidden), - "WSL launcher contains forbidden bootstrap, multiline shell transport, direct path argument, default expression, or hard-coded path: {forbidden}" + !launcher.contains(forbidden) && !entrypoint.contains(forbidden), + "WSL gate contains forbidden bootstrap, multiline shell transport, direct path argument, cleanup-bypassing exec, default expression, or hard-coded path: {forbidden}" + ); + } +} + +#[test] +fn python_bytecode_artifacts_are_ignored() { + let ignore = fs::read_to_string(repo_path(".gitignore")).expect("read repository ignore rules"); + for required in ["__pycache__/", "*.py[cod]"] { + assert!( + ignore.lines().any(|line| line == required), + "Python bytecode ignore rule missing: {required}" ); } } From cb9e88220121f8b3403b860ce2b20504b2acb9a1 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Thu, 9 Jul 2026 01:15:28 +0700 Subject: [PATCH 121/132] format authenticated miner stability integration --- crates/rigos-config/tests/miner_stability.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/crates/rigos-config/tests/miner_stability.rs b/crates/rigos-config/tests/miner_stability.rs index 5ac6b66f..9ac3c585 100644 --- a/crates/rigos-config/tests/miner_stability.rs +++ b/crates/rigos-config/tests/miner_stability.rs @@ -226,7 +226,11 @@ fn miner_health_distinguishes_ready_external_wait_degraded_blocked_and_unknown() write_executable(&journalctl, "#!/bin/sh\ncat \"$RIGOS_JOURNAL_FIXTURE\"\n"); write_executable(&journalctl_fail, "#!/bin/sh\nexit 1\n"); - fs::write(&journal_fixture, "net connect error: stale journal evidence\n").unwrap(); + fs::write( + &journal_fixture, + "net connect error: stale journal evidence\n", + ) + .unwrap(); let ready = run_observer( &root, &systemctl, From 01a0840a79800c534de473a3ce409d7cbea7ea08 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Thu, 9 Jul 2026 01:19:57 +0700 Subject: [PATCH 122/132] lock lifecycle scripts to LF --- .gitattributes | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitattributes b/.gitattributes index aaf2ab4c..3b002266 100644 --- a/.gitattributes +++ b/.gitattributes @@ -19,3 +19,4 @@ build/usb/includes.chroot/usr/lib/rigos/rigos-randomx-msr text eol=lf build/usb/includes.chroot/usr/lib/rigos/rigos-runtime-* text eol=lf build/usb/includes.chroot/usr/lib/rigos/rigos-miner-* text eol=lf build/usb/includes.chroot/usr/lib/rigos/rigos-remote-* text eol=lf +build/usb/includes.chroot/usr/lib/rigos/rigos-lifecycle-* text eol=lf From 695bbcdedb2bb05faf446d6cb2efffacd70bf3a8 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Thu, 9 Jul 2026 01:20:06 +0700 Subject: [PATCH 123/132] mark lifecycle script LF contract --- build/usb/includes.chroot/usr/lib/rigos/rigos-lifecycle-cycles | 1 + 1 file changed, 1 insertion(+) diff --git a/build/usb/includes.chroot/usr/lib/rigos/rigos-lifecycle-cycles b/build/usb/includes.chroot/usr/lib/rigos/rigos-lifecycle-cycles index aae63039..5d452324 100644 --- a/build/usb/includes.chroot/usr/lib/rigos/rigos-lifecycle-cycles +++ b/build/usb/includes.chroot/usr/lib/rigos/rigos-lifecycle-cycles @@ -1,4 +1,5 @@ #!/bin/sh +# Repository contract: LF line endings are required for appliance execution. set -eu cycles="${1:-20}" From 8741c9d25b064d20da74f6c98d24c72f9e433070 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Thu, 9 Jul 2026 01:20:13 +0700 Subject: [PATCH 124/132] cover lifecycle LF and POSIX syntax --- crates/rigos-config/tests/hive_exit_shell_syntax.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/crates/rigos-config/tests/hive_exit_shell_syntax.rs b/crates/rigos-config/tests/hive_exit_shell_syntax.rs index f8087c5e..71cbd5fb 100644 --- a/crates/rigos-config/tests/hive_exit_shell_syntax.rs +++ b/crates/rigos-config/tests/hive_exit_shell_syntax.rs @@ -13,6 +13,7 @@ fn runtime_authority_shells_are_lf_and_parse_cleanly() { for path in [ "build/usb/includes.chroot/usr/lib/rigos/rigos-runtime-publish", "build/usb/includes.chroot/usr/lib/rigos/rigos-runtime-authority", + "build/usb/includes.chroot/usr/lib/rigos/rigos-lifecycle-cycles", ] { let full_path = repo_path(path); let bytes = fs::read(&full_path).unwrap(); @@ -28,3 +29,11 @@ fn runtime_authority_shells_are_lf_and_parse_cleanly() { assert!(status.success(), "shell syntax failed: {path}"); } } + +#[test] +fn lifecycle_shell_has_explicit_lf_attribute() { + let attributes = fs::read_to_string(repo_path(".gitattributes")).unwrap(); + assert!(attributes.lines().any(|line| { + line == "build/usb/includes.chroot/usr/lib/rigos/rigos-lifecycle-* text eol=lf" + })); +} From 2b98c52acd9e30b8755d749a556e4baf6165077b Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Thu, 9 Jul 2026 01:27:09 +0700 Subject: [PATCH 125/132] remove obsolete checkout literal from WSL gate test --- crates/rigos-config/tests/wsl_source_gate.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/crates/rigos-config/tests/wsl_source_gate.rs b/crates/rigos-config/tests/wsl_source_gate.rs index 21bb22fb..1f8dbc8b 100644 --- a/crates/rigos-config/tests/wsl_source_gate.rs +++ b/crates/rigos-config/tests/wsl_source_gate.rs @@ -84,18 +84,20 @@ fn wsl_launcher_is_path_safe_and_fail_closed() { ); } - for forbidden in [ + let hard_coded_checkout = ["/mnt/d/TECHNICAL/", "dbyte", "-rigos"].concat(); + let forbidden = [ "[string]$Repository = (Split-Path -Parent $PSScriptRoot)", "wslpath -a $Repository", "$PathConverter", "$Shell = @'", "bash -lc", - "/mnt/d/TECHNICAL/dbyte-rigos", + hard_coded_checkout.as_str(), "curl | sh", "Invoke-WebRequest", "rustup-init", "exec bash ./scripts/verify.sh", - ] { + ]; + for forbidden in forbidden { assert!( !launcher.contains(forbidden) && !entrypoint.contains(forbidden), "WSL gate contains forbidden bootstrap, multiline shell transport, direct path argument, cleanup-bypassing exec, default expression, or hard-coded path: {forbidden}" From 4c8b4acf0d8298b255d54d7498638d6bcb3f4424 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Thu, 9 Jul 2026 01:27:20 +0700 Subject: [PATCH 126/132] remove obsolete namespace from Windows source gate docs --- docs/developer/windows-source-gate.txt | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/docs/developer/windows-source-gate.txt b/docs/developer/windows-source-gate.txt index 9e20bd5c..0ed96166 100644 --- a/docs/developer/windows-source-gate.txt +++ b/docs/developer/windows-source-gate.txt @@ -1,5 +1,5 @@ -DBYTE RIGOS WINDOWS SOURCE GATE -=============================== +RIGOS WINDOWS SOURCE GATE +========================= PURPOSE ------- @@ -78,9 +78,10 @@ PowerShell. DIRECT LINUX COMMANDS --------------------- -Inside an actual WSL/Linux shell with Linux Rust installed: +Inside an actual WSL/Linux shell with Linux Rust installed, change to the +repository checkout selected by the operator: - cd /mnt/d/TECHNICAL/dbyte-rigos + cd /path/to/rigos-checkout source "$HOME/.cargo/env" cargo --version bash ./scripts/verify.sh From c239e9d40c58005bf362ed72f968ccc62cb28fcf Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Thu, 9 Jul 2026 01:33:18 +0700 Subject: [PATCH 127/132] add token-aware runtime dependency scanner --- scripts/verify-runtime-dependencies.sh | 29 ++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 scripts/verify-runtime-dependencies.sh diff --git a/scripts/verify-runtime-dependencies.sh b/scripts/verify-runtime-dependencies.sh new file mode 100644 index 00000000..8e5ad0ff --- /dev/null +++ b/scripts/verify-runtime-dependencies.sh @@ -0,0 +1,29 @@ +#!/usr/bin/env bash +set -euo pipefail + +target=${1:-build/usb/includes.chroot} +if [[ ! -d "$target" ]]; then + echo "runtime dependency scan target is missing: $target" >&2 + exit 66 +fi + +pattern='(^|[^[:alnum:]_])(curl|wget|Invoke-WebRequest|latest)([^[:alnum:]_]|$)' + +set +e +rg -n -i -- "$pattern" "$target" +status=$? +set -e + +case "$status" in + 0) + echo "runtime miner download or floating dependency detected" >&2 + exit 1 + ;; + 1) + exit 0 + ;; + *) + echo "runtime dependency scan failed: exit $status" >&2 + exit "$status" + ;; +esac From d5ad66324b7b31435bfb9082e303dd078116581a Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Thu, 9 Jul 2026 01:33:32 +0700 Subject: [PATCH 128/132] test token-aware runtime dependency scan --- .../tests/hive_exit_shell_syntax.rs | 66 +++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/crates/rigos-config/tests/hive_exit_shell_syntax.rs b/crates/rigos-config/tests/hive_exit_shell_syntax.rs index 71cbd5fb..f5ff34dc 100644 --- a/crates/rigos-config/tests/hive_exit_shell_syntax.rs +++ b/crates/rigos-config/tests/hive_exit_shell_syntax.rs @@ -1,6 +1,7 @@ use std::fs; use std::path::PathBuf; use std::process::Command; +use std::time::{SystemTime, UNIX_EPOCH}; fn repo_path(path: &str) -> PathBuf { PathBuf::from(env!("CARGO_MANIFEST_DIR")) @@ -37,3 +38,68 @@ fn lifecycle_shell_has_explicit_lf_attribute() { line == "build/usb/includes.chroot/usr/lib/rigos/rigos-lifecycle-* text eol=lf" })); } + +#[cfg(unix)] +#[test] +fn runtime_dependency_scan_is_token_aware_and_fail_closed() { + let unique = SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap() + .as_nanos(); + let root = std::env::temp_dir().join(format!("rigos-runtime-dependency-scan-{unique}")); + fs::create_dir_all(&root).unwrap(); + let fixture = root.join("fixture.txt"); + let scanner = repo_path("scripts/verify-runtime-dependencies.sh"); + + fs::write( + &fixture, + "latest_journal_signal\nlatest_marker_index\ncalculate_latest_value\n", + ) + .unwrap(); + let benign = Command::new("bash") + .arg(&scanner) + .arg(&root) + .status() + .unwrap(); + assert!( + benign.success(), + "benign identifiers must not look like floating dependencies" + ); + + for dangerous in [ + "curl -fsSL https://example.invalid/miner\n", + "wget https://example.invalid/miner\n", + "Invoke-WebRequest https://example.invalid/miner\n", + "image:latest\n", + "https://example.invalid/releases/latest/download/miner\n", + "version=latest\n", + "xmrig-latest.tar.gz\n", + ] { + fs::write(&fixture, dangerous).unwrap(); + let denied = Command::new("bash") + .arg(&scanner) + .arg(&root) + .status() + .unwrap(); + assert_eq!( + denied.code(), + Some(1), + "floating dependency was not rejected: {dangerous:?}" + ); + } + + let missing = Command::new("bash") + .arg(&scanner) + .arg(root.join("missing")) + .status() + .unwrap(); + assert_eq!(missing.code(), Some(66)); + + let verify = fs::read_to_string(repo_path("scripts/verify.sh")).unwrap(); + assert!(verify.contains( + "bash scripts/verify-runtime-dependencies.sh build/usb/includes.chroot" + )); + assert!(!verify.contains("curl|wget|Invoke-WebRequest|latest")); + + let _ = fs::remove_dir_all(root); +} From ec2ce3010af88cee37ee9d09a34ed57f41db3ad8 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Thu, 9 Jul 2026 01:34:14 +0700 Subject: [PATCH 129/132] use token-aware runtime dependency scanner --- scripts/verify.sh | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/scripts/verify.sh b/scripts/verify.sh index 5fae12cc..38baa2cf 100755 --- a/scripts/verify.sh +++ b/scripts/verify.sh @@ -293,10 +293,7 @@ if rg -n 'if\s+.*(moneroocean|2miners|nicehash|supportxmr|herominers|hashvault|n echo "pool-name conditional leaked into runtime core" >&2 exit 1 fi -if rg -n 'curl|wget|Invoke-WebRequest|latest' build/usb/includes.chroot; then - echo "runtime miner download or floating dependency detected" >&2 - exit 1 -fi +bash scripts/verify-runtime-dependencies.sh build/usb/includes.chroot for required in build/usb/THIRD_PARTY_NOTICES docs/miner-provenance.md docs/third-party-components.md; do [[ -s "$required" ]] || { echo "missing third-party disclosure: $required" >&2; exit 1; } done From 01bf2c1766d141d30292a63c920dcd2610af6b82 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Thu, 9 Jul 2026 01:37:05 +0700 Subject: [PATCH 130/132] format runtime dependency scanner test --- crates/rigos-config/tests/hive_exit_shell_syntax.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/rigos-config/tests/hive_exit_shell_syntax.rs b/crates/rigos-config/tests/hive_exit_shell_syntax.rs index f5ff34dc..585f87c6 100644 --- a/crates/rigos-config/tests/hive_exit_shell_syntax.rs +++ b/crates/rigos-config/tests/hive_exit_shell_syntax.rs @@ -96,9 +96,9 @@ fn runtime_dependency_scan_is_token_aware_and_fail_closed() { assert_eq!(missing.code(), Some(66)); let verify = fs::read_to_string(repo_path("scripts/verify.sh")).unwrap(); - assert!(verify.contains( - "bash scripts/verify-runtime-dependencies.sh build/usb/includes.chroot" - )); + assert!( + verify.contains("bash scripts/verify-runtime-dependencies.sh build/usb/includes.chroot") + ); assert!(!verify.contains("curl|wget|Invoke-WebRequest|latest")); let _ = fs::remove_dir_all(root); From 1ffb9be2343618596942df372ed1dc01dc82b9e1 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Thu, 9 Jul 2026 01:41:10 +0700 Subject: [PATCH 131/132] execute runtime dependency scanner directly in tests --- .../tests/hive_exit_shell_syntax.rs | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/crates/rigos-config/tests/hive_exit_shell_syntax.rs b/crates/rigos-config/tests/hive_exit_shell_syntax.rs index 585f87c6..3962028a 100644 --- a/crates/rigos-config/tests/hive_exit_shell_syntax.rs +++ b/crates/rigos-config/tests/hive_exit_shell_syntax.rs @@ -1,4 +1,6 @@ use std::fs; +#[cfg(unix)] +use std::os::unix::fs::PermissionsExt; use std::path::PathBuf; use std::process::Command; use std::time::{SystemTime, UNIX_EPOCH}; @@ -49,18 +51,22 @@ fn runtime_dependency_scan_is_token_aware_and_fail_closed() { let root = std::env::temp_dir().join(format!("rigos-runtime-dependency-scan-{unique}")); fs::create_dir_all(&root).unwrap(); let fixture = root.join("fixture.txt"); - let scanner = repo_path("scripts/verify-runtime-dependencies.sh"); + let scanner = root.join("verify-runtime-dependencies.sh"); + fs::copy( + repo_path("scripts/verify-runtime-dependencies.sh"), + &scanner, + ) + .unwrap(); + let mut permissions = fs::metadata(&scanner).unwrap().permissions(); + permissions.set_mode(0o755); + fs::set_permissions(&scanner, permissions).unwrap(); fs::write( &fixture, "latest_journal_signal\nlatest_marker_index\ncalculate_latest_value\n", ) .unwrap(); - let benign = Command::new("bash") - .arg(&scanner) - .arg(&root) - .status() - .unwrap(); + let benign = Command::new(&scanner).arg(&root).status().unwrap(); assert!( benign.success(), "benign identifiers must not look like floating dependencies" @@ -76,11 +82,7 @@ fn runtime_dependency_scan_is_token_aware_and_fail_closed() { "xmrig-latest.tar.gz\n", ] { fs::write(&fixture, dangerous).unwrap(); - let denied = Command::new("bash") - .arg(&scanner) - .arg(&root) - .status() - .unwrap(); + let denied = Command::new(&scanner).arg(&root).status().unwrap(); assert_eq!( denied.code(), Some(1), @@ -88,8 +90,7 @@ fn runtime_dependency_scan_is_token_aware_and_fail_closed() { ); } - let missing = Command::new("bash") - .arg(&scanner) + let missing = Command::new(&scanner) .arg(root.join("missing")) .status() .unwrap(); From 527fdbdc49f7b94b26aab2c2386463d261672cf4 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Thu, 9 Jul 2026 01:44:46 +0700 Subject: [PATCH 132/132] separate scanner from dependency scan fixture --- crates/rigos-config/tests/hive_exit_shell_syntax.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/crates/rigos-config/tests/hive_exit_shell_syntax.rs b/crates/rigos-config/tests/hive_exit_shell_syntax.rs index 3962028a..dff771c4 100644 --- a/crates/rigos-config/tests/hive_exit_shell_syntax.rs +++ b/crates/rigos-config/tests/hive_exit_shell_syntax.rs @@ -49,8 +49,9 @@ fn runtime_dependency_scan_is_token_aware_and_fail_closed() { .unwrap() .as_nanos(); let root = std::env::temp_dir().join(format!("rigos-runtime-dependency-scan-{unique}")); - fs::create_dir_all(&root).unwrap(); - let fixture = root.join("fixture.txt"); + let scan_root = root.join("scan-root"); + fs::create_dir_all(&scan_root).unwrap(); + let fixture = scan_root.join("fixture.txt"); let scanner = root.join("verify-runtime-dependencies.sh"); fs::copy( repo_path("scripts/verify-runtime-dependencies.sh"), @@ -66,7 +67,7 @@ fn runtime_dependency_scan_is_token_aware_and_fail_closed() { "latest_journal_signal\nlatest_marker_index\ncalculate_latest_value\n", ) .unwrap(); - let benign = Command::new(&scanner).arg(&root).status().unwrap(); + let benign = Command::new(&scanner).arg(&scan_root).status().unwrap(); assert!( benign.success(), "benign identifiers must not look like floating dependencies" @@ -82,7 +83,7 @@ fn runtime_dependency_scan_is_token_aware_and_fail_closed() { "xmrig-latest.tar.gz\n", ] { fs::write(&fixture, dangerous).unwrap(); - let denied = Command::new(&scanner).arg(&root).status().unwrap(); + let denied = Command::new(&scanner).arg(&scan_root).status().unwrap(); assert_eq!( denied.code(), Some(1),