From 99f3956de2920c26e8b002fd490513f584fd1374 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Tue, 7 Jul 2026 20:09:06 +0700 Subject: [PATCH 01/64] stability persist SSH host identity --- .../usr/lib/rigos/rigos-ssh-hostkeys | 179 ++++++++++++++++++ 1 file changed, 179 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..8b79ced6 --- /dev/null +++ b/build/usb/includes.chroot/usr/lib/rigos/rigos-ssh-hostkeys @@ -0,0 +1,179 @@ +#!/usr/bin/python3 +import json +import os +import stat +import subprocess +import sys +import uuid +from pathlib import Path + +STATE = Path(os.environ.get("RIGOS_STATE_PATH", "/var/lib/rigos")) +RUNTIME = Path(os.environ.get("RIGOS_RUNTIME_PATH", "/run/rigos")) +BOOT_ID = Path(os.environ.get("RIGOS_BOOT_ID_PATH", "/proc/sys/kernel/random/boot_id")) +KEYGEN = os.environ.get("RIGOS_SSH_KEYGEN", "/usr/bin/ssh-keygen") +STORE = STATE / "ssh-hostkeys" +STATUS = RUNTIME / "ssh-hostkeys-status.json" +KEY_SPECS = ( + ("ed25519", ()), + ("rsa", ("-b", "3072")), +) + + +def fail(reason: str) -> int: + print(f"rigos-ssh-hostkeys: {reason}", file=sys.stderr) + return 2 + + +def fsync_path(path: Path) -> None: + fd = os.open(path, os.O_RDONLY) + try: + os.fsync(fd) + finally: + os.close(fd) + + +def atomic_json(path: Path, value: dict) -> 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, 0o644) + try: + with os.fdopen(fd, "w", encoding="utf-8") as handle: + handle.write(data) + handle.flush() + os.fsync(handle.fileno()) + os.replace(temporary, path) + fsync_path(path.parent) + finally: + try: + temporary.unlink() + except FileNotFoundError: + pass + + +def run_keygen(arguments: list[str]) -> subprocess.CompletedProcess[str]: + return subprocess.run( + [KEYGEN, *arguments], + text=True, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + timeout=20, + check=False, + ) + + +def public_identity(path: Path) -> tuple[str, str]: + private = path + public = Path(f"{path}.pub") + if private.is_symlink() or public.is_symlink(): + raise RuntimeError("host_key_symlink") + if not private.is_file() or not public.is_file(): + raise RuntimeError("host_key_incomplete") + private_mode = stat.S_IMODE(private.stat().st_mode) + if private_mode != 0o600: + raise RuntimeError("host_key_private_mode") + + derived = run_keygen(["-y", "-f", str(private)]) + if derived.returncode != 0: + raise RuntimeError("host_key_private_invalid") + expected = public.read_text(encoding="ascii").strip().split() + actual = derived.stdout.strip().split() + if len(expected) < 2 or len(actual) < 2 or expected[:2] != actual[:2]: + raise RuntimeError("host_key_pair_mismatch") + + fingerprint = run_keygen(["-l", "-E", "sha256", "-f", str(public)]) + if fingerprint.returncode != 0: + raise RuntimeError("host_key_public_invalid") + fields = fingerprint.stdout.strip().split() + if len(fields) < 2 or not fields[1].startswith("SHA256:"): + raise RuntimeError("host_key_fingerprint_invalid") + return expected[0], fields[1] + + +def validate_store() -> list[dict]: + if STORE.is_symlink() or not STORE.is_dir(): + raise RuntimeError("host_key_store_unsafe") + if stat.S_IMODE(STORE.stat().st_mode) != 0o700: + raise RuntimeError("host_key_store_mode") + + identities = [] + for key_type, _extra in KEY_SPECS: + algorithm, fingerprint = public_identity(STORE / f"ssh_host_{key_type}_key") + identities.append({ + "type": key_type, + "algorithm": algorithm, + "fingerprint": fingerprint, + }) + return identities + + +def create_store() -> None: + temporary = STATE / f".ssh-hostkeys.{uuid.uuid4().hex}" + temporary.mkdir(mode=0o700) + try: + for key_type, extra in KEY_SPECS: + destination = temporary / f"ssh_host_{key_type}_key" + result = run_keygen([ + "-q", + "-t", + key_type, + *extra, + "-N", + "", + "-C", + "rigos-host", + "-f", + str(destination), + ]) + if result.returncode != 0: + raise RuntimeError(f"host_key_generate_{key_type}") + destination.chmod(0o600) + Path(f"{destination}.pub").chmod(0o644) + fsync_path(destination) + fsync_path(Path(f"{destination}.pub")) + fsync_path(temporary) + os.replace(temporary, STORE) + fsync_path(STATE) + finally: + if temporary.exists(): + for child in temporary.iterdir(): + child.unlink() + temporary.rmdir() + + +def main() -> int: + try: + if STATE.is_symlink() or not STATE.is_dir(): + return fail("state_path_unsafe") + RUNTIME.mkdir(parents=True, exist_ok=True) + boot_id = BOOT_ID.read_text(encoding="ascii").strip() + if not boot_id: + return fail("boot_id_unavailable") + + created = False + if not STORE.exists(): + create_store() + created = True + + identities = validate_store() + atomic_json(STATUS, { + "schema": "rigos.ssh-hostkeys-status/v1", + "outcome": "ready", + "boot_id": boot_id, + "persistent": True, + "created": created, + "keys": identities, + }) + print(json.dumps({ + "schema": "rigos.ssh-hostkeys-gate/v1", + "outcome": "allowed", + "created": created, + "keys": identities, + }, sort_keys=True)) + return 0 + except (OSError, UnicodeError, RuntimeError, subprocess.SubprocessError) as error: + return fail(str(error)) + + +if __name__ == "__main__": + raise SystemExit(main()) From d56788188500efc2fc52d37be5951bcfeb020b46 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Tue, 7 Jul 2026 20:09:42 +0700 Subject: [PATCH 02/64] stability bound miner restart behavior --- .../system/rigos-miner.service.d/stability.conf | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 build/usb/includes.chroot/etc/systemd/system/rigos-miner.service.d/stability.conf diff --git a/build/usb/includes.chroot/etc/systemd/system/rigos-miner.service.d/stability.conf b/build/usb/includes.chroot/etc/systemd/system/rigos-miner.service.d/stability.conf new file mode 100644 index 00000000..5bf95881 --- /dev/null +++ b/build/usb/includes.chroot/etc/systemd/system/rigos-miner.service.d/stability.conf @@ -0,0 +1,17 @@ +[Unit] +StartLimitIntervalSec=10min +StartLimitBurst=5 + +[Service] +Restart=on-failure +RestartSec=15s +TimeoutStartSec=2min +TimeoutStopSec=30s +KillSignal=SIGINT +FinalKillSignal=SIGKILL +SendSIGKILL=yes +SuccessExitStatus=SIGINT SIGTERM +OOMPolicy=stop +OOMScoreAdjust=-500 +TasksMax=64 +LimitNOFILE=4096 From 3c2b42854d721ddf395d0540e7a882e029cd7de5 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Tue, 7 Jul 2026 20:12:18 +0700 Subject: [PATCH 03/64] stability observe miner liveness truth --- .../usr/lib/rigos/rigos-miner-health | 256 ++++++++++++++++++ 1 file changed, 256 insertions(+) create mode 100644 build/usb/includes.chroot/usr/lib/rigos/rigos-miner-health diff --git a/build/usb/includes.chroot/usr/lib/rigos/rigos-miner-health b/build/usb/includes.chroot/usr/lib/rigos/rigos-miner-health new file mode 100644 index 00000000..10d876f3 --- /dev/null +++ b/build/usb/includes.chroot/usr/lib/rigos/rigos-miner-health @@ -0,0 +1,256 @@ +#!/usr/bin/python3 +import datetime as dt +import json +import os +import re +import subprocess +import sys +import uuid +from pathlib import Path + +RUNTIME = Path(os.environ.get("RIGOS_RUNTIME_PATH", "/run/rigos")) +BOOT_ID = Path(os.environ.get("RIGOS_BOOT_ID_PATH", "/proc/sys/kernel/random/boot_id")) +CURRENT = Path(os.environ.get("RIGOS_CURRENT_REVISION_PATH", "/var/lib/rigos/current")) +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" +WINDOW_SECONDS = int(os.environ.get("RIGOS_MINER_HEALTH_WINDOW_SECONDS", "180")) +WARMUP_SECONDS = int(os.environ.get("RIGOS_MINER_WARMUP_SECONDS", "240")) + +EXTERNAL_MARKERS = ( + "connect error", + "connection refused", + "connection reset", + "network error", + "dns error", + "no active pools", + "operation timed out", + "connection timeout", +) +SHARE_RE = re.compile(r"accepted \((\d+)/(\d+)\)") + + +def atomic_json(path: Path, value: dict) -> 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, 0o644) + 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) + try: + os.fsync(directory) + finally: + os.close(directory) + finally: + try: + temporary.unlink() + except FileNotFoundError: + pass + + +def command(argv: list[str]) -> subprocess.CompletedProcess[str]: + return subprocess.run( + argv, + text=True, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + timeout=10, + check=False, + ) + + +def systemd_properties() -> dict[str, str]: + result = command([ + SYSTEMCTL, + "show", + "rigos-miner.service", + "--property=ActiveState", + "--property=SubState", + "--property=MainPID", + "--property=NRestarts", + "--property=Result", + "--property=ExecMainStatus", + "--property=ActiveEnterTimestampMonotonic", + "--no-pager", + ]) + if result.returncode != 0: + raise RuntimeError("systemctl_show_failed") + values = {} + for line in result.stdout.splitlines(): + if "=" in line: + key, value = line.split("=", 1) + values[key] = value + return values + + +def current_revision() -> str | None: + try: + return CURRENT.resolve(strict=True).name + except OSError: + return None + + +def runtime_revision() -> tuple[str | None, str | None]: + try: + value = json.loads((RUNTIME / "runtime-config-status.json").read_text(encoding="utf-8")) + except (OSError, UnicodeError, json.JSONDecodeError): + return None, None + if not isinstance(value, dict): + return None, None + return value.get("outcome"), value.get("revision") + + +def process_state(pid: int) -> str | None: + try: + raw = (PROC / str(pid) / "stat").read_text(encoding="ascii") + except (OSError, UnicodeError): + return None + end = raw.rfind(")") + if end < 0: + return None + fields = raw[end + 1 :].split() + return fields[0] if fields else None + + +def active_seconds(properties: dict[str, str]) -> int | None: + try: + entered = int(properties.get("ActiveEnterTimestampMonotonic", "0")) + uptime = float((PROC / "uptime").read_text(encoding="ascii").split()[0]) + except (OSError, UnicodeError, ValueError, IndexError): + return None + if entered <= 0: + return None + return max(0, int(uptime - entered / 1_000_000)) + + +def recent_journal() -> str: + result = command([ + JOURNALCTL, + "-b", + "-u", + "rigos-miner.service", + "--since", + f"-{WINDOW_SECONDS} seconds", + "--no-pager", + "-o", + "cat", + ]) + return result.stdout if result.returncode == 0 else "" + + +def last_share_counts(text: str) -> tuple[int | None, int | None]: + matches = SHARE_RE.findall(text) + if not matches: + return None, None + accepted, rejected = matches[-1] + return int(accepted), int(rejected) + + +def classify( + properties: dict[str, str], + proc_state: str | None, + active_for: int | None, + canonical_revision: str | None, + rendered_outcome: str | None, + rendered_revision: str | None, + journal: str, +) -> tuple[str, str | None]: + if properties.get("ActiveState") != "active" or properties.get("SubState") != "running": + return "failed", "miner_unit_not_running" + try: + pid = int(properties.get("MainPID", "0")) + except ValueError: + pid = 0 + if pid <= 0 or proc_state is None or proc_state in ("X", "Z"): + return "failed", "miner_process_unavailable" + if canonical_revision is None: + return "blocked", "current_revision_unavailable" + if rendered_outcome != "ready" or rendered_revision != canonical_revision: + return "blocked", "runtime_revision_mismatch" + + lowered = journal.lower() + if "miner speed" in lowered: + return "ready", None + if active_for is not None and active_for < WARMUP_SECONDS: + return "warming_up", None + if any(marker in lowered for marker in EXTERNAL_MARKERS): + return "waiting_external", "pool_or_network_unavailable" + return "degraded", "no_recent_speed_evidence" + + +def main() -> int: + try: + boot_id = BOOT_ID.read_text(encoding="ascii").strip() + if not boot_id: + raise RuntimeError("boot_id_unavailable") + properties = systemd_properties() + try: + pid = int(properties.get("MainPID", "0")) + except ValueError: + pid = 0 + proc_state = process_state(pid) if pid > 0 else None + active_for = active_seconds(properties) + canonical = current_revision() + rendered_outcome, rendered_revision = runtime_revision() + journal = recent_journal() + accepted, rejected = last_share_counts(journal) + state, reason = classify( + properties, + proc_state, + active_for, + canonical, + rendered_outcome, + rendered_revision, + journal, + ) + value = { + "schema": "rigos.miner-health-status/v1", + "generated_at": dt.datetime.now(dt.timezone.utc).isoformat(timespec="milliseconds"), + "boot_id": boot_id, + "state": state, + "reason": reason, + "unit": { + "active_state": properties.get("ActiveState"), + "sub_state": properties.get("SubState"), + "result": properties.get("Result"), + "main_pid": pid or None, + "process_state": proc_state, + "restart_count": int(properties.get("NRestarts", "0") or 0), + "exec_main_status": int(properties.get("ExecMainStatus", "0") or 0), + "active_seconds": active_for, + }, + "config": { + "current_revision": canonical, + "runtime_outcome": rendered_outcome, + "runtime_revision": rendered_revision, + }, + "evidence": { + "window_seconds": WINDOW_SECONDS, + "recent_speed": "miner speed" in journal.lower(), + "external_wait_marker": any(marker in journal.lower() for marker in EXTERNAL_MARKERS), + "accepted_shares": accepted, + "rejected_shares": rejected, + }, + "remediation": "observe_only", + } + atomic_json(STATUS, value) + print(json.dumps({ + "schema": "rigos.miner-health-observer/v1", + "state": state, + "reason": reason, + "remediation": "observe_only", + }, sort_keys=True)) + return 0 + except (OSError, UnicodeError, RuntimeError, subprocess.SubprocessError, ValueError) as error: + print(f"rigos-miner-health: {error}", file=sys.stderr) + return 2 + + +if __name__ == "__main__": + raise SystemExit(main()) From 2647f037726bf69173c1ee00c312a23cc4591429 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Tue, 7 Jul 2026 20:12:36 +0700 Subject: [PATCH 04/64] stability add miner health observer --- .../systemd/system/rigos-miner-health.service | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 build/usb/includes.chroot/etc/systemd/system/rigos-miner-health.service 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 new file mode 100644 index 00000000..64923930 --- /dev/null +++ b/build/usb/includes.chroot/etc/systemd/system/rigos-miner-health.service @@ -0,0 +1,19 @@ +[Unit] +Description=Observe RIGOS miner health truth +After=rigos-state-ready.service rigos-runtime-render.service rigos-miner.service +Wants=rigos-miner.service + +[Service] +Type=oneshot +ExecStart=/usr/bin/python3 /usr/lib/rigos/rigos-miner-health +NoNewPrivileges=yes +PrivateTmp=yes +ProtectHome=yes +ProtectSystem=strict +ProtectKernelTunables=yes +ProtectKernelModules=yes +ProtectControlGroups=yes +RestrictAddressFamilies=AF_UNIX +RestrictNamespaces=yes +LockPersonality=yes +ReadWritePaths=/run/rigos From 65c709247c972ce9dbc920849c5635119defec02 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Tue, 7 Jul 2026 20:12:54 +0700 Subject: [PATCH 05/64] stability sample miner health every minute --- .../etc/systemd/system/rigos-miner-health.timer | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 build/usb/includes.chroot/etc/systemd/system/rigos-miner-health.timer diff --git a/build/usb/includes.chroot/etc/systemd/system/rigos-miner-health.timer b/build/usb/includes.chroot/etc/systemd/system/rigos-miner-health.timer new file mode 100644 index 00000000..97de0c73 --- /dev/null +++ b/build/usb/includes.chroot/etc/systemd/system/rigos-miner-health.timer @@ -0,0 +1,11 @@ +[Unit] +Description=Sample RIGOS miner health truth + +[Timer] +OnBootSec=2min +OnUnitActiveSec=1min +AccuracySec=5s +Unit=rigos-miner-health.service + +[Install] +WantedBy=timers.target From 51ba465343297b55e184aec70fbbe51bf5a087b5 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Tue, 7 Jul 2026 20:13:16 +0700 Subject: [PATCH 06/64] stability wire miner observer and restart policy --- 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 f7e37ac5..9525437d 100644 --- a/build/usb/hooks/010-rigos.chroot +++ b/build/usb/hooks/010-rigos.chroot @@ -10,8 +10,8 @@ ln -sfn /usr/lib/rigos/rigosd /usr/local/bin/rigosd ln -sfn /usr/lib/rigos/rigosctl /usr/local/bin/rigosctl systemd-tmpfiles --create /usr/lib/tmpfiles.d/rigos.conf -chmod 0755 /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-runtime-render /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 tmp.mount +chmod 0755 /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-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 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 b793d6ffb24cd204ba150717b21f44d187800ef0 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Tue, 7 Jul 2026 20:13:56 +0700 Subject: [PATCH 07/64] test miner stability observer and restart bounds --- crates/rigos-config/tests/miner_stability.rs | 176 +++++++++++++++++++ 1 file changed, 176 insertions(+) create mode 100644 crates/rigos-config/tests/miner_stability.rs diff --git a/crates/rigos-config/tests/miner_stability.rs b/crates/rigos-config/tests/miner_stability.rs new file mode 100644 index 00000000..3bc27e1b --- /dev/null +++ b/crates/rigos-config/tests/miner_stability.rs @@ -0,0 +1,176 @@ +use serde_json::Value; +use std::fs; +use std::os::unix::fs::{PermissionsExt, symlink}; +use std::path::{Path, PathBuf}; +use std::process::Command; +use uuid::Uuid; + +fn repo_path(path: &str) -> PathBuf { + PathBuf::from(env!("CARGO_MANIFEST_DIR")) + .join("../..") + .join(path) +} + +fn write_executable(path: &Path, content: &str) { + fs::write(path, content).unwrap(); + let mut permissions = fs::metadata(path).unwrap().permissions(); + permissions.set_mode(0o755); + fs::set_permissions(path, permissions).unwrap(); +} + +fn write_runtime_status(path: &Path, revision: &str) { + fs::write( + path, + serde_json::to_vec(&serde_json::json!({ + "schema": "rigos.runtime-config-status/v1", + "outcome": "ready", + "revision": revision + })) + .unwrap(), + ) + .unwrap(); +} + +fn run_observer( + root: &Path, + systemctl: &Path, + journalctl: &Path, + systemctl_fixture: &Path, + journal_fixture: &Path, +) -> Value { + let status = Command::new("python3") + .arg(repo_path( + "build/usb/includes.chroot/usr/lib/rigos/rigos-miner-health", + )) + .env("RIGOS_RUNTIME_PATH", root.join("run")) + .env("RIGOS_BOOT_ID_PATH", root.join("boot-id")) + .env("RIGOS_CURRENT_REVISION_PATH", root.join("state/current")) + .env("RIGOS_PROC_ROOT", root.join("proc")) + .env("RIGOS_SYSTEMCTL", systemctl) + .env("RIGOS_JOURNALCTL", journalctl) + .env("RIGOS_SYSTEMCTL_FIXTURE", systemctl_fixture) + .env("RIGOS_JOURNAL_FIXTURE", journal_fixture) + .status() + .unwrap(); + assert!(status.success()); + serde_json::from_slice( + &fs::read(root.join("run/miner-health-status.json")).unwrap(), + ) + .unwrap() +} + +#[test] +fn miner_health_distinguishes_ready_external_wait_degraded_and_blocked() { + let root = std::env::temp_dir().join(format!("rigos-miner-health-{}", Uuid::new_v4())); + fs::create_dir_all(root.join("run")).unwrap(); + fs::create_dir_all(root.join("state/revisions/r1")).unwrap(); + fs::create_dir_all(root.join("proc/123")).unwrap(); + symlink("revisions/r1", root.join("state/current")).unwrap(); + 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(); + write_runtime_status(&root.join("run/runtime-config-status.json"), "r1"); + + let systemctl_fixture = root.join("systemctl.txt"); + fs::write( + &systemctl_fixture, + "ActiveState=active\nSubState=running\nMainPID=123\nNRestarts=2\nResult=success\nExecMainStatus=0\nActiveEnterTimestampMonotonic=100000000\n", + ) + .unwrap(); + let journal_fixture = root.join("journal.txt"); + let systemctl = root.join("systemctl"); + let journalctl = root.join("journalctl"); + write_executable( + &systemctl, + "#!/bin/sh\ncat \"$RIGOS_SYSTEMCTL_FIXTURE\"\n", + ); + write_executable( + &journalctl, + "#!/bin/sh\ncat \"$RIGOS_JOURNAL_FIXTURE\"\n", + ); + + fs::write( + &journal_fixture, + "miner speed 10s/60s/15m 340.0 341.0 n/a H/s\ncpu accepted (7/0) diff 10000\n", + ) + .unwrap(); + let ready = run_observer( + &root, + &systemctl, + &journalctl, + &systemctl_fixture, + &journal_fixture, + ); + assert_eq!(ready["state"], "ready"); + assert_eq!(ready["unit"]["restart_count"], 2); + 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(); + let waiting = run_observer( + &root, + &systemctl, + &journalctl, + &systemctl_fixture, + &journal_fixture, + ); + assert_eq!(waiting["state"], "waiting_external"); + assert_eq!(waiting["reason"], "pool_or_network_unavailable"); + + fs::write(&journal_fixture, "").unwrap(); + let degraded = run_observer( + &root, + &systemctl, + &journalctl, + &systemctl_fixture, + &journal_fixture, + ); + assert_eq!(degraded["state"], "degraded"); + assert_eq!(degraded["reason"], "no_recent_speed_evidence"); + + write_runtime_status(&root.join("run/runtime-config-status.json"), "r2"); + let blocked = run_observer( + &root, + &systemctl, + &journalctl, + &systemctl_fixture, + &journal_fixture, + ); + assert_eq!(blocked["state"], "blocked"); + assert_eq!(blocked["reason"], "runtime_revision_mismatch"); + + let _ = fs::remove_dir_all(root); +} + +#[test] +fn miner_restart_policy_is_bounded_and_observer_never_mutates_service() { + let stability = fs::read_to_string(repo_path( + "build/usb/includes.chroot/etc/systemd/system/rigos-miner.service.d/stability.conf", + )) + .unwrap(); + assert!(stability.contains("StartLimitIntervalSec=10min")); + assert!(stability.contains("StartLimitBurst=5")); + assert!(stability.contains("Restart=on-failure")); + assert!(stability.contains("RestartSec=15s")); + assert!(stability.contains("TimeoutStopSec=30s")); + assert!(!stability.contains("Restart=always")); + + let observer = fs::read_to_string(repo_path( + "build/usb/includes.chroot/usr/lib/rigos/rigos-miner-health", + )) + .unwrap(); + assert!(observer.contains("\"remediation\": \"observe_only\"")); + assert!(!observer.contains("systemctl restart")); + assert!(!observer.contains("systemctl kill")); + + let timer = fs::read_to_string(repo_path( + "build/usb/includes.chroot/etc/systemd/system/rigos-miner-health.timer", + )) + .unwrap(); + assert!(timer.contains("OnBootSec=2min")); + assert!(timer.contains("OnUnitActiveSec=1min")); + + let hook = fs::read_to_string(repo_path("build/usb/hooks/010-rigos.chroot")).unwrap(); + assert!(hook.contains("rigos-miner-health.timer")); +} From 466dfea4e89ae65e80db447073c1854b59880986 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Tue, 7 Jul 2026 20:14:51 +0700 Subject: [PATCH 08/64] stability default inspector to redacted miner view --- build/usb/includes.chroot/usr/local/bin/rigosd | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 build/usb/includes.chroot/usr/local/bin/rigosd diff --git a/build/usb/includes.chroot/usr/local/bin/rigosd b/build/usb/includes.chroot/usr/local/bin/rigosd new file mode 100644 index 00000000..336a08dc --- /dev/null +++ b/build/usb/includes.chroot/usr/local/bin/rigosd @@ -0,0 +1,14 @@ +#!/bin/sh +set -eu + +for argument in "$@"; do + case "$argument" in + --xmrig-config|--xmrig-config=*) + exec /usr/lib/rigos/rigosd "$@" + ;; + esac +done + +exec /usr/lib/rigos/rigosd \ + --xmrig-config /run/rigos/xmrig-public.json \ + "$@" From 5ef1b9d97569959f82fdb9472b999c7ae2dfd6a3 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Tue, 7 Jul 2026 20:15:18 +0700 Subject: [PATCH 09/64] stability default control alias to redacted miner view --- build/usb/includes.chroot/usr/local/bin/rigosctl | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 build/usb/includes.chroot/usr/local/bin/rigosctl diff --git a/build/usb/includes.chroot/usr/local/bin/rigosctl b/build/usb/includes.chroot/usr/local/bin/rigosctl new file mode 100644 index 00000000..593f87d5 --- /dev/null +++ b/build/usb/includes.chroot/usr/local/bin/rigosctl @@ -0,0 +1,14 @@ +#!/bin/sh +set -eu + +for argument in "$@"; do + case "$argument" in + --xmrig-config|--xmrig-config=*) + exec /usr/lib/rigos/rigosctl "$@" + ;; + esac +done + +exec /usr/lib/rigos/rigosctl \ + --xmrig-config /run/rigos/xmrig-public.json \ + "$@" From 562ac49b5d76ebf4ef758e2f8aacd6bcdc4f7426 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Tue, 7 Jul 2026 20:15:43 +0700 Subject: [PATCH 10/64] stability wire redacted inspector wrappers --- build/usb/hooks/010-rigos.chroot | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/build/usb/hooks/010-rigos.chroot b/build/usb/hooks/010-rigos.chroot index 9525437d..83da94f0 100644 --- a/build/usb/hooks/010-rigos.chroot +++ b/build/usb/hooks/010-rigos.chroot @@ -6,11 +6,9 @@ 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 -m 0755 /usr/lib/rigos /usr/local/bin -ln -sfn /usr/lib/rigos/rigosd /usr/local/bin/rigosd -ln -sfn /usr/lib/rigos/rigosctl /usr/local/bin/rigosctl systemd-tmpfiles --create /usr/lib/tmpfiles.d/rigos.conf -chmod 0755 /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-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 +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-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 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 From 368da9e3c4b4eb6de464944bea8a7a98c9469ac8 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Tue, 7 Jul 2026 20:16:30 +0700 Subject: [PATCH 11/64] stability expose safe inspector compatibility fields --- .../usr/lib/rigos/rigos-runtime-render | 15 +++++++++++++++ 1 file changed, 15 insertions(+) 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 9e5a0fc2..3effedd9 100644 --- a/build/usb/includes.chroot/usr/lib/rigos/rigos-runtime-render +++ b/build/usb/includes.chroot/usr/lib/rigos/rigos-runtime-render @@ -102,6 +102,7 @@ def render() -> tuple[dict, dict, dict]: exact_threads = threads elif threads != "auto": raise RuntimeError("threads must be auto or an integer") + public = copy.deepcopy(runtime) for pool in public.get("pools", []): if isinstance(pool, dict): @@ -110,11 +111,25 @@ def render() -> tuple[dict, dict, dict]: http = public.get("http") if isinstance(http, dict): http.pop("access-token", None) + + public["algo"] = algorithm + if exact_threads is not None: + public["threads"] = exact_threads + else: + public.pop("threads", None) + public_randomx = public.get("randomx") + if not isinstance(public_randomx, dict): + public_randomx = {} + huge_pages = cpu.get("huge-pages") + if isinstance(huge_pages, bool): + public_randomx["huge-pages"] = huge_pages + public["randomx"] = public_randomx public["rigos-public-view"] = { "schema": "rigos.xmrig-public-config/v1", "identity_redacted": True, "source_revision": current.name, } + status = { "schema": "rigos.runtime-config-status/v1", "outcome": "ready", From fc658305e7b829da80e1d67a8ad2a70bfc5c4afd Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Tue, 7 Jul 2026 20:17:08 +0700 Subject: [PATCH 12/64] test redacted inspector wrapper wiring --- crates/rigos-config/tests/recovery_access.rs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/crates/rigos-config/tests/recovery_access.rs b/crates/rigos-config/tests/recovery_access.rs index 4d6b5772..bed08c28 100644 --- a/crates/rigos-config/tests/recovery_access.rs +++ b/crates/rigos-config/tests/recovery_access.rs @@ -143,11 +143,21 @@ fn alpha8_runtime_authority_is_exact_and_fail_closed() { fn alpha8_appliance_wiring_is_explicit() { let hook = fs::read_to_string(repo_path("build/usb/hooks/010-rigos.chroot")) .expect("read appliance hook"); - assert!(hook.contains("ln -sfn /usr/lib/rigos/rigosd /usr/local/bin/rigosd")); - assert!(hook.contains("ln -sfn /usr/lib/rigos/rigosctl /usr/local/bin/rigosctl")); + assert!(hook.contains("chmod 0755 /usr/local/bin/rigosd /usr/local/bin/rigosctl")); + assert!(!hook.contains("ln -sfn /usr/lib/rigos/rigosd /usr/local/bin/rigosd")); + assert!(!hook.contains("ln -sfn /usr/lib/rigos/rigosctl /usr/local/bin/rigosctl")); assert!(hook.contains("rigos-runtime-render.service")); assert!(hook.contains("systemctl disable ssh.socket")); + for command in ["rigosd", "rigosctl"] { + let wrapper = fs::read_to_string(repo_path(&format!( + "build/usb/includes.chroot/usr/local/bin/{command}" + ))) + .expect("read inspector wrapper"); + assert!(wrapper.contains("--xmrig-config /run/rigos/xmrig-public.json")); + assert!(wrapper.contains(&format!("exec /usr/lib/rigos/{command}"))); + } + let miner = fs::read_to_string(repo_path( "build/usb/includes.chroot/etc/systemd/system/rigos-miner.service.d/runtime-render.conf", )) From 8f2b32209b1c304e0c149cb84205c41c69175bfe Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Tue, 7 Jul 2026 20:17:49 +0700 Subject: [PATCH 13/64] test redacted inspector runtime contract --- scripts/check-alpha8-runtime.py | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/scripts/check-alpha8-runtime.py b/scripts/check-alpha8-runtime.py index cd67fff7..21846204 100644 --- a/scripts/check-alpha8-runtime.py +++ b/scripts/check-alpha8-runtime.py @@ -48,8 +48,18 @@ def verify_runtime_authority(root: Path) -> None: "huge-pages": True, "max-threads-hint": 2, }, - "pools": [{"url": "pool.test:1", "algo": "rx/0"}], - "http": {"enabled": False}, + "pools": [ + { + "url": "pool.test:1", + "algo": "rx/0", + "user": "fixture-private-identity", + "pass": "fixture-worker", + } + ], + "http": { + "enabled": False, + "access-token": "fixture-private-token", + }, }, ) environment = os.environ.copy() @@ -64,6 +74,21 @@ def verify_runtime_authority(root: Path) -> None: config = json.loads((runtime / "xmrig.json").read_text(encoding="utf-8")) assert config["cpu"]["max-threads-hint"] == 100 assert config["cpu"]["rx"] == [-1, -1] + assert config["pools"][0]["user"] == "fixture-private-identity" + + public = json.loads((runtime / "xmrig-public.json").read_text(encoding="utf-8")) + assert public["algo"] == "rx/0" + assert public["threads"] == 2 + assert public["randomx"]["huge-pages"] is True + assert public["rigos-public-view"]["identity_redacted"] is True + assert "user" not in public["pools"][0] + assert "pass" not in public["pools"][0] + assert "access-token" not in public["http"] + public_text = json.dumps(public, sort_keys=True) + assert "fixture-private-identity" not in public_text + assert "fixture-worker" not in public_text + assert "fixture-private-token" not in public_text + status = json.loads( (runtime / "runtime-config-status.json").read_text(encoding="utf-8") ) @@ -142,7 +167,7 @@ def main() -> int: root = Path(temporary) verify_runtime_authority(root) verify_remote_truth(root) - print("RIGOS Alpha8 runtime and remote truth verification passed") + print("RIGOS runtime, redacted inspector, and remote truth verification passed") return 0 From 148c9526a6d0c4cc4c045bbf21e480e202c4c937 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Tue, 7 Jul 2026 20:18:52 +0700 Subject: [PATCH 14/64] remove unwired SSH host key prototype --- .../usr/lib/rigos/rigos-ssh-hostkeys | 179 ------------------ 1 file changed, 179 deletions(-) delete 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 deleted file mode 100644 index 8b79ced6..00000000 --- a/build/usb/includes.chroot/usr/lib/rigos/rigos-ssh-hostkeys +++ /dev/null @@ -1,179 +0,0 @@ -#!/usr/bin/python3 -import json -import os -import stat -import subprocess -import sys -import uuid -from pathlib import Path - -STATE = Path(os.environ.get("RIGOS_STATE_PATH", "/var/lib/rigos")) -RUNTIME = Path(os.environ.get("RIGOS_RUNTIME_PATH", "/run/rigos")) -BOOT_ID = Path(os.environ.get("RIGOS_BOOT_ID_PATH", "/proc/sys/kernel/random/boot_id")) -KEYGEN = os.environ.get("RIGOS_SSH_KEYGEN", "/usr/bin/ssh-keygen") -STORE = STATE / "ssh-hostkeys" -STATUS = RUNTIME / "ssh-hostkeys-status.json" -KEY_SPECS = ( - ("ed25519", ()), - ("rsa", ("-b", "3072")), -) - - -def fail(reason: str) -> int: - print(f"rigos-ssh-hostkeys: {reason}", file=sys.stderr) - return 2 - - -def fsync_path(path: Path) -> None: - fd = os.open(path, os.O_RDONLY) - try: - os.fsync(fd) - finally: - os.close(fd) - - -def atomic_json(path: Path, value: dict) -> 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, 0o644) - try: - with os.fdopen(fd, "w", encoding="utf-8") as handle: - handle.write(data) - handle.flush() - os.fsync(handle.fileno()) - os.replace(temporary, path) - fsync_path(path.parent) - finally: - try: - temporary.unlink() - except FileNotFoundError: - pass - - -def run_keygen(arguments: list[str]) -> subprocess.CompletedProcess[str]: - return subprocess.run( - [KEYGEN, *arguments], - text=True, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - timeout=20, - check=False, - ) - - -def public_identity(path: Path) -> tuple[str, str]: - private = path - public = Path(f"{path}.pub") - if private.is_symlink() or public.is_symlink(): - raise RuntimeError("host_key_symlink") - if not private.is_file() or not public.is_file(): - raise RuntimeError("host_key_incomplete") - private_mode = stat.S_IMODE(private.stat().st_mode) - if private_mode != 0o600: - raise RuntimeError("host_key_private_mode") - - derived = run_keygen(["-y", "-f", str(private)]) - if derived.returncode != 0: - raise RuntimeError("host_key_private_invalid") - expected = public.read_text(encoding="ascii").strip().split() - actual = derived.stdout.strip().split() - if len(expected) < 2 or len(actual) < 2 or expected[:2] != actual[:2]: - raise RuntimeError("host_key_pair_mismatch") - - fingerprint = run_keygen(["-l", "-E", "sha256", "-f", str(public)]) - if fingerprint.returncode != 0: - raise RuntimeError("host_key_public_invalid") - fields = fingerprint.stdout.strip().split() - if len(fields) < 2 or not fields[1].startswith("SHA256:"): - raise RuntimeError("host_key_fingerprint_invalid") - return expected[0], fields[1] - - -def validate_store() -> list[dict]: - if STORE.is_symlink() or not STORE.is_dir(): - raise RuntimeError("host_key_store_unsafe") - if stat.S_IMODE(STORE.stat().st_mode) != 0o700: - raise RuntimeError("host_key_store_mode") - - identities = [] - for key_type, _extra in KEY_SPECS: - algorithm, fingerprint = public_identity(STORE / f"ssh_host_{key_type}_key") - identities.append({ - "type": key_type, - "algorithm": algorithm, - "fingerprint": fingerprint, - }) - return identities - - -def create_store() -> None: - temporary = STATE / f".ssh-hostkeys.{uuid.uuid4().hex}" - temporary.mkdir(mode=0o700) - try: - for key_type, extra in KEY_SPECS: - destination = temporary / f"ssh_host_{key_type}_key" - result = run_keygen([ - "-q", - "-t", - key_type, - *extra, - "-N", - "", - "-C", - "rigos-host", - "-f", - str(destination), - ]) - if result.returncode != 0: - raise RuntimeError(f"host_key_generate_{key_type}") - destination.chmod(0o600) - Path(f"{destination}.pub").chmod(0o644) - fsync_path(destination) - fsync_path(Path(f"{destination}.pub")) - fsync_path(temporary) - os.replace(temporary, STORE) - fsync_path(STATE) - finally: - if temporary.exists(): - for child in temporary.iterdir(): - child.unlink() - temporary.rmdir() - - -def main() -> int: - try: - if STATE.is_symlink() or not STATE.is_dir(): - return fail("state_path_unsafe") - RUNTIME.mkdir(parents=True, exist_ok=True) - boot_id = BOOT_ID.read_text(encoding="ascii").strip() - if not boot_id: - return fail("boot_id_unavailable") - - created = False - if not STORE.exists(): - create_store() - created = True - - identities = validate_store() - atomic_json(STATUS, { - "schema": "rigos.ssh-hostkeys-status/v1", - "outcome": "ready", - "boot_id": boot_id, - "persistent": True, - "created": created, - "keys": identities, - }) - print(json.dumps({ - "schema": "rigos.ssh-hostkeys-gate/v1", - "outcome": "allowed", - "created": created, - "keys": identities, - }, sort_keys=True)) - return 0 - except (OSError, UnicodeError, RuntimeError, subprocess.SubprocessError) as error: - return fail(str(error)) - - -if __name__ == "__main__": - raise SystemExit(main()) From a3b062a3bf1073c31defdff9e80eeb029e07a509 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Tue, 7 Jul 2026 20:19:43 +0700 Subject: [PATCH 15/64] stability keep miner observer non-mutating --- .../etc/systemd/system/rigos-miner-health.service | 1 - 1 file changed, 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 64923930..bd3523ea 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 @@ -1,7 +1,6 @@ [Unit] Description=Observe RIGOS miner health truth After=rigos-state-ready.service rigos-runtime-render.service rigos-miner.service -Wants=rigos-miner.service [Service] Type=oneshot From 8e3a96c137b44602588c42216ef6dcb5dff78455 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Tue, 7 Jul 2026 20:20:30 +0700 Subject: [PATCH 16/64] stability make miner observation bounded and truthful --- .../usr/lib/rigos/rigos-miner-health | 26 ++++++++++++++----- 1 file changed, 19 insertions(+), 7 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 10d876f3..39221147 100644 --- a/build/usb/includes.chroot/usr/lib/rigos/rigos-miner-health +++ b/build/usb/includes.chroot/usr/lib/rigos/rigos-miner-health @@ -17,6 +17,7 @@ JOURNALCTL = os.environ.get("RIGOS_JOURNALCTL", "/usr/bin/journalctl") STATUS = RUNTIME / "miner-health-status.json" 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 EXTERNAL_MARKERS = ( "connect error", @@ -129,7 +130,7 @@ def active_seconds(properties: dict[str, str]) -> int | None: return max(0, int(uptime - entered / 1_000_000)) -def recent_journal() -> str: +def recent_journal() -> tuple[str, bool]: result = command([ JOURNALCTL, "-b", @@ -137,11 +138,13 @@ def recent_journal() -> str: "rigos-miner.service", "--since", f"-{WINDOW_SECONDS} seconds", + "--lines", + str(MAX_JOURNAL_LINES), "--no-pager", "-o", "cat", ]) - return result.stdout if result.returncode == 0 else "" + return result.stdout, result.returncode == 0 def last_share_counts(text: str) -> tuple[int | None, int | None]: @@ -160,6 +163,7 @@ def classify( rendered_outcome: str | None, rendered_revision: str | None, journal: str, + journal_available: bool, ) -> tuple[str, str | None]: if properties.get("ActiveState") != "active" or properties.get("SubState") != "running": return "failed", "miner_unit_not_running" @@ -173,14 +177,16 @@ 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" lowered = journal.lower() if "miner speed" in lowered: return "ready", None - if active_for is not None and active_for < WARMUP_SECONDS: - return "warming_up", 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" @@ -198,7 +204,7 @@ def main() -> int: active_for = active_seconds(properties) canonical = current_revision() rendered_outcome, rendered_revision = runtime_revision() - journal = recent_journal() + journal, journal_available = recent_journal() accepted, rejected = last_share_counts(journal) state, reason = classify( properties, @@ -208,7 +214,9 @@ def main() -> int: rendered_outcome, rendered_revision, journal, + journal_available, ) + lowered_journal = journal.lower() value = { "schema": "rigos.miner-health-status/v1", "generated_at": dt.datetime.now(dt.timezone.utc).isoformat(timespec="milliseconds"), @@ -232,8 +240,12 @@ def main() -> int: }, "evidence": { "window_seconds": WINDOW_SECONDS, - "recent_speed": "miner speed" in journal.lower(), - "external_wait_marker": any(marker in journal.lower() for marker in EXTERNAL_MARKERS), + "journal_available": journal_available, + "journal_line_limit": MAX_JOURNAL_LINES, + "recent_speed": "miner speed" in lowered_journal, + "external_wait_marker": any( + marker in lowered_journal for marker in EXTERNAL_MARKERS + ), "accepted_shares": accepted, "rejected_shares": rejected, }, From bf419bd901236d029240b29d66baccd41213584b Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Tue, 7 Jul 2026 20:21:21 +0700 Subject: [PATCH 17/64] test non-mutating and unknown miner health states --- crates/rigos-config/tests/miner_stability.rs | 45 ++++++++++++++++---- 1 file changed, 37 insertions(+), 8 deletions(-) diff --git a/crates/rigos-config/tests/miner_stability.rs b/crates/rigos-config/tests/miner_stability.rs index 3bc27e1b..7c98515c 100644 --- a/crates/rigos-config/tests/miner_stability.rs +++ b/crates/rigos-config/tests/miner_stability.rs @@ -1,6 +1,6 @@ use serde_json::Value; use std::fs; -use std::os::unix::fs::{PermissionsExt, symlink}; +use std::os::unix::fs::{symlink, PermissionsExt}; use std::path::{Path, PathBuf}; use std::process::Command; use uuid::Uuid; @@ -53,14 +53,11 @@ fn run_observer( .status() .unwrap(); assert!(status.success()); - serde_json::from_slice( - &fs::read(root.join("run/miner-health-status.json")).unwrap(), - ) - .unwrap() + serde_json::from_slice(&fs::read(root.join("run/miner-health-status.json")).unwrap()).unwrap() } #[test] -fn miner_health_distinguishes_ready_external_wait_degraded_and_blocked() { +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())); fs::create_dir_all(root.join("run")).unwrap(); fs::create_dir_all(root.join("state/revisions/r1")).unwrap(); @@ -74,12 +71,21 @@ fn miner_health_distinguishes_ready_external_wait_degraded_and_blocked() { let systemctl_fixture = root.join("systemctl.txt"); fs::write( &systemctl_fixture, - "ActiveState=active\nSubState=running\nMainPID=123\nNRestarts=2\nResult=success\nExecMainStatus=0\nActiveEnterTimestampMonotonic=100000000\n", + concat!( + "ActiveState=active\n", + "SubState=running\n", + "MainPID=123\n", + "NRestarts=2\n", + "Result=success\n", + "ExecMainStatus=0\n", + "ActiveEnterTimestampMonotonic=100000000\n" + ), ) .unwrap(); let journal_fixture = root.join("journal.txt"); let systemctl = root.join("systemctl"); let journalctl = root.join("journalctl"); + let journalctl_fail = root.join("journalctl-fail"); write_executable( &systemctl, "#!/bin/sh\ncat \"$RIGOS_SYSTEMCTL_FIXTURE\"\n", @@ -88,10 +94,14 @@ fn miner_health_distinguishes_ready_external_wait_degraded_and_blocked() { &journalctl, "#!/bin/sh\ncat \"$RIGOS_JOURNAL_FIXTURE\"\n", ); + write_executable(&journalctl_fail, "#!/bin/sh\nexit 1\n"); fs::write( &journal_fixture, - "miner speed 10s/60s/15m 340.0 341.0 n/a H/s\ncpu accepted (7/0) diff 10000\n", + concat!( + "miner speed 10s/60s/15m 340.0 341.0 n/a H/s\n", + "cpu accepted (7/0) diff 10000\n" + ), ) .unwrap(); let ready = run_observer( @@ -129,6 +139,17 @@ fn miner_health_distinguishes_ready_external_wait_degraded_and_blocked() { assert_eq!(degraded["state"], "degraded"); assert_eq!(degraded["reason"], "no_recent_speed_evidence"); + let unknown = run_observer( + &root, + &systemctl, + &journalctl_fail, + &systemctl_fixture, + &journal_fixture, + ); + assert_eq!(unknown["state"], "unknown"); + assert_eq!(unknown["reason"], "journal_unavailable"); + assert_eq!(unknown["evidence"]["journal_available"], false); + write_runtime_status(&root.join("run/runtime-config-status.json"), "r2"); let blocked = run_observer( &root, @@ -161,9 +182,17 @@ fn miner_restart_policy_is_bounded_and_observer_never_mutates_service() { )) .unwrap(); assert!(observer.contains("\"remediation\": \"observe_only\"")); + assert!(observer.contains("MAX_JOURNAL_LINES = 500")); assert!(!observer.contains("systemctl restart")); assert!(!observer.contains("systemctl kill")); + let service = fs::read_to_string(repo_path( + "build/usb/includes.chroot/etc/systemd/system/rigos-miner-health.service", + )) + .unwrap(); + assert!(!service.contains("Wants=rigos-miner.service")); + assert!(!service.contains("Requires=rigos-miner.service")); + let timer = fs::read_to_string(repo_path( "build/usb/includes.chroot/etc/systemd/system/rigos-miner-health.timer", )) From 53efcb826f35eef72ef14924c6201e65f7d68217 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Tue, 7 Jul 2026 20:28:51 +0700 Subject: [PATCH 18/64] format miner stability fixture --- crates/rigos-config/tests/miner_stability.rs | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/crates/rigos-config/tests/miner_stability.rs b/crates/rigos-config/tests/miner_stability.rs index 7c98515c..37a6405c 100644 --- a/crates/rigos-config/tests/miner_stability.rs +++ b/crates/rigos-config/tests/miner_stability.rs @@ -1,6 +1,6 @@ use serde_json::Value; use std::fs; -use std::os::unix::fs::{symlink, PermissionsExt}; +use std::os::unix::fs::{PermissionsExt, symlink}; use std::path::{Path, PathBuf}; use std::process::Command; use uuid::Uuid; @@ -86,14 +86,8 @@ fn miner_health_distinguishes_ready_external_wait_degraded_blocked_and_unknown() let systemctl = root.join("systemctl"); let journalctl = root.join("journalctl"); let journalctl_fail = root.join("journalctl-fail"); - write_executable( - &systemctl, - "#!/bin/sh\ncat \"$RIGOS_SYSTEMCTL_FIXTURE\"\n", - ); - write_executable( - &journalctl, - "#!/bin/sh\ncat \"$RIGOS_JOURNAL_FIXTURE\"\n", - ); + write_executable(&systemctl, "#!/bin/sh\ncat \"$RIGOS_SYSTEMCTL_FIXTURE\"\n"); + write_executable(&journalctl, "#!/bin/sh\ncat \"$RIGOS_JOURNAL_FIXTURE\"\n"); write_executable(&journalctl_fail, "#!/bin/sh\nexit 1\n"); fs::write( From b784dff620dd3f6eb7d690e8e9d73cb4d01c09be Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Tue, 7 Jul 2026 20:39:50 +0700 Subject: [PATCH 19/64] ci apply hostile review fixes --- .github/workflows/hive-exit-review-fixes.yml | 47 ++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 .github/workflows/hive-exit-review-fixes.yml diff --git a/.github/workflows/hive-exit-review-fixes.yml b/.github/workflows/hive-exit-review-fixes.yml new file mode 100644 index 00000000..258847ef --- /dev/null +++ b/.github/workflows/hive-exit-review-fixes.yml @@ -0,0 +1,47 @@ +name: Apply Hive Exit Review Fixes + +on: + push: + branches: + - stability/hive-exit-gates + paths: + - scripts/apply-hive-exit-review-fixes.py + +permissions: + contents: write + +jobs: + apply: + if: github.actor != 'github-actions[bot]' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + ref: stability/hive-exit-gates + fetch-depth: 0 + + - uses: dtolnay/rust-toolchain@1.85.1 + with: + components: rustfmt + + - name: Apply exact source patches + run: python3 scripts/apply-hive-exit-review-fixes.py + + - name: Verify patched sources + run: | + cargo fmt --all + cargo fmt --all -- --check + cargo test -p rigos-xmrig --lib + python3 scripts/check-alpha8-runtime.py + git diff --check + + - name: Commit verified review fixes + run: | + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git add crates/rigos-xmrig/src/lib.rs \ + build/usb/includes.chroot/usr/lib/rigos/rigos-runtime-render \ + scripts/check-alpha8-runtime.py + git diff --cached --quiet && exit 0 + git commit -m "stability enforce public inspector boundary" + git push origin HEAD:stability/hive-exit-gates From c3ffa4bff2a5cec26f433248396671fbf1bc8257 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Tue, 7 Jul 2026 20:40:40 +0700 Subject: [PATCH 20/64] apply hostile review source fixes --- scripts/apply-hive-exit-review-fixes.py | 253 ++++++++++++++++++++++++ 1 file changed, 253 insertions(+) create mode 100644 scripts/apply-hive-exit-review-fixes.py diff --git a/scripts/apply-hive-exit-review-fixes.py b/scripts/apply-hive-exit-review-fixes.py new file mode 100644 index 00000000..f266812f --- /dev/null +++ b/scripts/apply-hive-exit-review-fixes.py @@ -0,0 +1,253 @@ +#!/usr/bin/env python3 +from pathlib import Path + +ROOT = Path(__file__).resolve().parents[1] + + +def replace_once(path: Path, old: str, new: str) -> None: + text = path.read_text(encoding="utf-8") + count = text.count(old) + if count != 1: + raise RuntimeError(f"expected exactly one match in {path}, found {count}") + path.write_text(text.replace(old, new, 1), encoding="utf-8") + + +def patch_xmrig_backend() -> None: + path = ROOT / "crates/rigos-xmrig/src/lib.rs" + replace_once( + path, + """ let config_path = cmdline + .as_deref() + .and_then(extract_config_path) + .or_else(|| self.explicit_config.clone());""", + """ let config_path = self + .explicit_config + .clone() + .or_else(|| cmdline.as_deref().and_then(extract_config_path));""", + ) + + marker = """ #[test] + fn discovers_xmrig_from_synthetic_proc_without_mutation() {""" + test = """ #[test] + fn explicit_config_overrides_process_cmdline_config() { + let unique = SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap() + .as_nanos(); + let root = std::env::temp_dir().join(format!("rigos-proc-explicit-{unique}")); + let proc_root = root.join("proc"); + let pid_dir = proc_root.join("42"); + fs::create_dir_all(&pid_dir).unwrap(); + let private = root.join("private.json"); + let public = root.join("public.json"); + fs::write( + &private, + r#"{"algo":"rx/private","http":{"enabled":false}}"#, + ) + .unwrap(); + fs::write( + &public, + r#"{"algo":"rx/0","threads":2,"randomx":{"huge-pages":true},"http":{"enabled":false}}"#, + ) + .unwrap(); + fs::write(pid_dir.join("comm"), "xmrig\n").unwrap(); + fs::write( + pid_dir.join("cmdline"), + format!("xmrig\0--config={}\0", private.display()), + ) + .unwrap(); + fs::write( + pid_dir.join("status"), + "Name:\txmrig\nUid:\t1000 1000 1000 1000\n", + ) + .unwrap(); + fs::write(pid_dir.join("cgroup"), "0::/system.slice/xmrig.service\n").unwrap(); + fs::write( + pid_dir.join("stat"), + "42 (xmrig) S 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 100 0\n", + ) + .unwrap(); + fs::write(proc_root.join("uptime"), "100.0 0.0\n").unwrap(); + + let expected_path = public.to_string_lossy().into_owned(); + let backend = XmrigBackend { + explicit_executable: None, + explicit_config: Some(public), + probe_version: false, + }; + let result = backend.discover(&MachineContext { + proc_root, + sys_root: root.join("sys"), + }); + let _ = fs::remove_dir_all(root); + let snapshot = result.value.unwrap(); + assert_eq!(snapshot.config.path, Some(expected_path)); + assert_eq!(snapshot.config.algorithm.as_deref(), Some("rx/0")); + assert_eq!(snapshot.config.thread_hint, Some(2)); + assert_eq!(snapshot.config.huge_pages_requested, Some(true)); + } + +""" + replace_once(path, marker, test + marker) + + +def patch_runtime_renderer() -> None: + path = ROOT / "build/usb/includes.chroot/usr/lib/rigos/rigos-runtime-render" + helper_marker = """def render() -> tuple[dict, dict, dict]:""" + helpers = """def public_pool(pool: dict) -> dict: + safe = {} + url = pool.get("url") + if isinstance(url, str) and url: + safe["url"] = url.rsplit("@", 1)[-1] + algo = pool.get("algo") + if isinstance(algo, str) and algo: + safe["algo"] = algo + for key in ("tls", "nicehash", "keepalive"): + value = pool.get(key) + if isinstance(value, bool): + safe[key] = value + priority = pool.get("priority") + if isinstance(priority, int) and not isinstance(priority, bool): + safe["priority"] = priority + return safe + + +def public_http(http: object) -> dict: + if not isinstance(http, dict): + return {"enabled": False} + safe = {} + enabled = http.get("enabled") + safe["enabled"] = enabled if isinstance(enabled, bool) else False + host = http.get("host") + if isinstance(host, str) and host: + safe["host"] = host + port = http.get("port") + if isinstance(port, int) and not isinstance(port, bool) and 1 <= port <= 65535: + safe["port"] = port + restricted = http.get("restricted") + if isinstance(restricted, bool): + safe["restricted"] = restricted + return safe + + +""" + replace_once(path, helper_marker, helpers + helper_marker) + + replace_once( + path, + """ public = copy.deepcopy(runtime) + for pool in public.get("pools", []): + if isinstance(pool, dict): + pool.pop("user", None) + pool.pop("pass", None) + http = public.get("http") + if isinstance(http, dict): + http.pop("access-token", None) + + public["algo"] = algorithm + if exact_threads is not None: + public["threads"] = exact_threads + else: + public.pop("threads", None) + public_randomx = public.get("randomx") + if not isinstance(public_randomx, dict): + public_randomx = {} + huge_pages = cpu.get("huge-pages") + if isinstance(huge_pages, bool): + public_randomx["huge-pages"] = huge_pages + public["randomx"] = public_randomx + public["rigos-public-view"] = { + "schema": "rigos.xmrig-public-config/v1", + "identity_redacted": True, + "source_revision": current.name, + } +""", + """ huge_pages = cpu.get("huge-pages") + public_cpu = {} + enabled = cpu.get("enabled") + if isinstance(enabled, bool): + public_cpu["enabled"] = enabled + if isinstance(huge_pages, bool): + public_cpu["huge-pages"] = huge_pages + max_threads_hint = cpu.get("max-threads-hint") + if isinstance(max_threads_hint, int) and not isinstance(max_threads_hint, bool): + public_cpu["max-threads-hint"] = max_threads_hint + if profile is not None and exact_threads is not None: + public_cpu[profile] = [-1] * exact_threads + + public = { + "algo": algorithm, + "cpu": public_cpu, + "http": public_http(runtime.get("http")), + "pools": [public_pool(pool) for pool in pools], + "randomx": { + "huge-pages": huge_pages if isinstance(huge_pages, bool) else False, + }, + "rigos-public-view": { + "schema": "rigos.xmrig-public-config/v1", + "identity_redacted": True, + "construction": "allowlist", + "source_revision": current.name, + }, + } + if exact_threads is not None: + public["threads"] = exact_threads +""", + ) + + replace_once( + path, + ' "identity_redacted_public_view": True,\n', + ' "identity_redacted_public_view": True,\n "public_view_construction": "allowlist",\n', + ) + + +def patch_runtime_fixture() -> None: + path = ROOT / "scripts/check-alpha8-runtime.py" + replace_once( + path, + ' "max-threads-hint": 2,\n', + ' "max-threads-hint": 2,\n "future-secret": "fixture-cpu-secret",\n', + ) + replace_once( + path, + ' "pass": "fixture-worker",\n', + ' "pass": "fixture-worker",\n "future-secret": "fixture-pool-secret",\n', + ) + replace_once( + path, + ' "access-token": "fixture-private-token",\n', + ' "access-token": "fixture-private-token",\n "future-secret": "fixture-http-secret",\n', + ) + replace_once( + path, + ' "http": {\n', + ' "future-secret": "fixture-top-secret",\n "http": {\n', + ) + replace_once( + path, + ' assert public["rigos-public-view"]["identity_redacted"] is True\n', + ' assert public["rigos-public-view"]["identity_redacted"] is True\n assert public["rigos-public-view"]["construction"] == "allowlist"\n assert set(public) == {"algo", "cpu", "http", "pools", "randomx", "rigos-public-view", "threads"}\n assert set(public["pools"][0]) <= {"url", "algo", "tls", "nicehash", "keepalive", "priority"}\n assert set(public["http"]) <= {"enabled", "host", "port", "restricted"}\n', + ) + replace_once( + path, + ' assert "fixture-private-token" not in public_text\n', + ' assert "fixture-private-token" not in public_text\n assert "fixture-cpu-secret" not in public_text\n assert "fixture-pool-secret" not in public_text\n assert "fixture-http-secret" not in public_text\n assert "fixture-top-secret" not in public_text\n', + ) + replace_once( + path, + ' assert status["profile"] == "rx"\n', + ' assert status["profile"] == "rx"\n assert status["public_view_construction"] == "allowlist"\n', + ) + + +def main() -> int: + patch_xmrig_backend() + patch_runtime_renderer() + patch_runtime_fixture() + print("Hive Exit hostile review fixes applied") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) From 7cb7d4d63262367e1a86852148bd90ad5e47e3c3 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Tue, 7 Jul 2026 20:52:54 +0700 Subject: [PATCH 21/64] document hostile review findings --- docs/hive-exit-hostile-review.md | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 docs/hive-exit-hostile-review.md diff --git a/docs/hive-exit-hostile-review.md b/docs/hive-exit-hostile-review.md new file mode 100644 index 00000000..5d731dba --- /dev/null +++ b/docs/hive-exit-hostile-review.md @@ -0,0 +1,8 @@ +# Hive Exit hostile review + +The first stability batch passed source verification, but review found two release blockers before image construction: + +1. An explicit inspector configuration must take precedence over a configuration discovered from the running process command line. +2. The public XMRig view must be constructed from an allowlist. Copying the private configuration and deleting known secret fields is not an acceptable security boundary. + +The review fix must pass Rust formatting, the `rigos-xmrig` unit suite, the runtime redaction fixture, and `git diff --check` before it is committed to the stability branch. From 42f71f5a0e95d92d8742bde78177cef02d846766 Mon Sep 17 00:00:00 2001 From: Deadbytes101 Date: Tue, 7 Jul 2026 20:56:18 +0700 Subject: [PATCH 22/64] trigger Hive Exit hostile review From b9f1f3d304f5d7ffbb7638b9c85e49d4140bad05 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Tue, 7 Jul 2026 21:00:10 +0700 Subject: [PATCH 23/64] ci run Hive Exit review fixes on branch pushes --- .github/workflows/hive-exit-review-fixes.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/hive-exit-review-fixes.yml b/.github/workflows/hive-exit-review-fixes.yml index 258847ef..0f9644b5 100644 --- a/.github/workflows/hive-exit-review-fixes.yml +++ b/.github/workflows/hive-exit-review-fixes.yml @@ -4,8 +4,6 @@ on: push: branches: - stability/hive-exit-gates - paths: - - scripts/apply-hive-exit-review-fixes.py permissions: contents: write From c9cbbc86736077b48ed6b900f26a559dd1db7355 Mon Sep 17 00:00:00 2001 From: Deadbytes101 Date: Tue, 7 Jul 2026 21:20:10 +0700 Subject: [PATCH 24/64] run Hive Exit review fixes From c23847ce3042db777c50101dd15156960961ee40 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Tue, 7 Jul 2026 21:51:39 +0700 Subject: [PATCH 25/64] stability publish staged runtime allowlist --- .../usr/lib/rigos/rigos-runtime-publish | 99 +++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 build/usb/includes.chroot/usr/lib/rigos/rigos-runtime-publish diff --git a/build/usb/includes.chroot/usr/lib/rigos/rigos-runtime-publish b/build/usb/includes.chroot/usr/lib/rigos/rigos-runtime-publish new file mode 100644 index 00000000..d7bb471c --- /dev/null +++ b/build/usb/includes.chroot/usr/lib/rigos/rigos-runtime-publish @@ -0,0 +1,99 @@ +#!/bin/sh +set -eu + +runtime=${RIGOS_RUNTIME_PATH:-/run/rigos} +renderer=${RIGOS_RUNTIME_RENDERER:-/usr/lib/rigos/rigos-runtime-render} +mkdir -p "$runtime" +chmod 0755 "$runtime" +stage=$(mktemp -d "$runtime/.render-stage.XXXXXX") +chmod 0700 "$stage" +cleanup() { + rm -rf "$stage" +} +trap cleanup EXIT HUP INT TERM + +RIGOS_RUNTIME_PATH="$stage" "$renderer" + +jq -e ' + .schema == "rigos.runtime-config-status/v1" and + .outcome == "ready" and + (.revision | type == "string") and + (.algorithm | type == "string") +' "$stage/runtime-config-status.json" >/dev/null + +algorithm=$(jq -r '.algorithm' "$stage/runtime-config-status.json") +revision=$(jq -r '.revision' "$stage/runtime-config-status.json") +thread_count=$(jq -r '.exact_threads // empty' "$stage/runtime-config-status.json") +profile=$(jq -r '.profile // empty' "$stage/runtime-config-status.json") + +public_tmp=$(mktemp "$runtime/.xmrig-public.XXXXXX") +status_tmp=$(mktemp "$runtime/.runtime-status.XXXXXX") +config_tmp=$(mktemp "$runtime/.xmrig-runtime.XXXXXX") +trap 'rm -f "$public_tmp" "$status_tmp" "$config_tmp"; cleanup' EXIT HUP INT TERM + +jq \ + --arg algorithm "$algorithm" \ + --arg revision "$revision" \ + --arg profile "$profile" \ + --argjson thread_count "${thread_count:-null}" ' + def present: with_entries(select(.value != null)); + def endpoint: + if type == "string" then split("@") | last else null end; + { + algo: $algorithm, + cpu: ({ + enabled: .cpu.enabled, + "huge-pages": .cpu["huge-pages"], + "max-threads-hint": .cpu["max-threads-hint"] + } | present), + pools: [ + .pools[] | ({ + url: (.url | endpoint), + algo: .algo, + tls: .tls, + nicehash: .nicehash, + keepalive: .keepalive, + priority: .priority + } | present) + ], + http: ({ + enabled: (.http.enabled // false), + host: .http.host, + port: .http.port, + restricted: .http.restricted + } | present), + randomx: { + "huge-pages": (.cpu["huge-pages"] // false) + }, + "rigos-public-view": { + schema: "rigos.xmrig-public-config/v1", + identity_redacted: true, + construction: "allowlist", + source_revision: $revision + } + } + | if $thread_count != null then .threads = $thread_count else . end + | if ($profile | length) > 0 and $thread_count != null + then .cpu[$profile] = [range(0; $thread_count) | -1] + else . + end +' "$stage/xmrig.json" >"$public_tmp" + +jq '. + { + identity_redacted_public_view: true, + public_view_construction: "allowlist" +}' "$stage/runtime-config-status.json" >"$status_tmp" + +cp "$stage/xmrig.json" "$config_tmp" +chmod 0640 "$config_tmp" +if [ "${RIGOS_RENDER_SKIP_CHOWN:-0}" != 1 ]; then + chown root:rigos "$config_tmp" +fi +chmod 0644 "$public_tmp" "$status_tmp" +sync -f "$config_tmp" +sync -f "$public_tmp" +sync -f "$status_tmp" +mv -f "$config_tmp" "$runtime/xmrig.json" +mv -f "$public_tmp" "$runtime/xmrig-public.json" +mv -f "$status_tmp" "$runtime/runtime-config-status.json" +sync -f "$runtime" From 96acf9cb68aebb665cac13626407faad45943ea1 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Tue, 7 Jul 2026 21:52:04 +0700 Subject: [PATCH 26/64] stability gate runtime publication through staged authority --- .../etc/systemd/system/rigos-runtime-render.service | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/usb/includes.chroot/etc/systemd/system/rigos-runtime-render.service b/build/usb/includes.chroot/etc/systemd/system/rigos-runtime-render.service index 166dfc49..06b7d29f 100644 --- a/build/usb/includes.chroot/etc/systemd/system/rigos-runtime-render.service +++ b/build/usb/includes.chroot/etc/systemd/system/rigos-runtime-render.service @@ -1,5 +1,5 @@ [Unit] -Description=Render RIGOS runtime miner configuration +Description=Render and publish RIGOS runtime miner configuration After=rigos-state-ready.service rigos-profile-apply.service Requires=rigos-state-ready.service rigos-profile-apply.service Before=rigos-hugepages.service rigos-miner.service @@ -7,7 +7,7 @@ ConditionPathExists=/var/lib/rigos/current [Service] Type=oneshot -ExecStart=/usr/lib/rigos/rigos-runtime-render +ExecStart=/usr/lib/rigos/rigos-runtime-publish NoNewPrivileges=yes PrivateTmp=yes ProtectHome=yes From 2d6ccd402ea4a8d0a944b1108ae6bed8c730872f Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Tue, 7 Jul 2026 21:52:22 +0700 Subject: [PATCH 27/64] stability consume staged runtime authority --- .../systemd/system/rigos-miner.service.d/runtime-render.conf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/usb/includes.chroot/etc/systemd/system/rigos-miner.service.d/runtime-render.conf b/build/usb/includes.chroot/etc/systemd/system/rigos-miner.service.d/runtime-render.conf index 030eecfd..a9f754a2 100644 --- a/build/usb/includes.chroot/etc/systemd/system/rigos-miner.service.d/runtime-render.conf +++ b/build/usb/includes.chroot/etc/systemd/system/rigos-miner.service.d/runtime-render.conf @@ -5,7 +5,7 @@ ConditionPathExists= ConditionPathExists=/var/lib/rigos/current [Service] -ExecCondition=+/usr/lib/rigos/rigos-runtime-render +ExecCondition=+/usr/lib/rigos/rigos-runtime-publish ExecCondition=/usr/lib/rigos/rigos-runtime-gate ExecStart= -ExecStart=/usr/lib/rigos/xmrig --config=/run/rigos/xmrig.json +ExecStart=/usr/lib/rigos/xmrig -c /run/rigos/xmrig.json From fb30573c38252c74c59ad64405de286f7ec75b9a Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Tue, 7 Jul 2026 21:53:21 +0700 Subject: [PATCH 28/64] stability install runtime publication authority --- build/usb/hooks/010-rigos.chroot | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/usb/hooks/010-rigos.chroot b/build/usb/hooks/010-rigos.chroot index 83da94f0..a29b316f 100644 --- a/build/usb/hooks/010-rigos.chroot +++ b/build/usb/hooks/010-rigos.chroot @@ -8,7 +8,7 @@ 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-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 +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 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 From ff7fe8c7305a5d8afada347d2070c1379d9de11b Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Tue, 7 Jul 2026 21:54:17 +0700 Subject: [PATCH 29/64] test staged runtime publication wiring --- crates/rigos-config/tests/recovery_access.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/crates/rigos-config/tests/recovery_access.rs b/crates/rigos-config/tests/recovery_access.rs index bed08c28..61924961 100644 --- a/crates/rigos-config/tests/recovery_access.rs +++ b/crates/rigos-config/tests/recovery_access.rs @@ -146,6 +146,7 @@ fn alpha8_appliance_wiring_is_explicit() { assert!(hook.contains("chmod 0755 /usr/local/bin/rigosd /usr/local/bin/rigosctl")); assert!(!hook.contains("ln -sfn /usr/lib/rigos/rigosd /usr/local/bin/rigosd")); assert!(!hook.contains("ln -sfn /usr/lib/rigos/rigosctl /usr/local/bin/rigosctl")); + assert!(hook.contains("/usr/lib/rigos/rigos-runtime-publish")); assert!(hook.contains("rigos-runtime-render.service")); assert!(hook.contains("systemctl disable ssh.socket")); @@ -158,15 +159,22 @@ fn alpha8_appliance_wiring_is_explicit() { assert!(wrapper.contains(&format!("exec /usr/lib/rigos/{command}"))); } + let runtime_service = fs::read_to_string(repo_path( + "build/usb/includes.chroot/etc/systemd/system/rigos-runtime-render.service", + )) + .expect("read runtime authority service"); + assert!(runtime_service.contains("ExecStart=/usr/lib/rigos/rigos-runtime-publish")); + let miner = fs::read_to_string(repo_path( "build/usb/includes.chroot/etc/systemd/system/rigos-miner.service.d/runtime-render.conf", )) .expect("read miner runtime override"); assert!(miner.contains("Requires=rigos-runtime-render.service")); assert!(miner.contains("ConditionPathExists=/var/lib/rigos/current")); - assert!(miner.contains("ExecCondition=+/usr/lib/rigos/rigos-runtime-render")); + assert!(miner.contains("ExecCondition=+/usr/lib/rigos/rigos-runtime-publish")); assert!(miner.contains("ExecCondition=/usr/lib/rigos/rigos-runtime-gate")); - assert!(miner.contains("--config=/run/rigos/xmrig.json")); + assert!(miner.contains("ExecStart=/usr/lib/rigos/xmrig -c /run/rigos/xmrig.json")); + assert!(!miner.contains("--config=/run/rigos/xmrig.json")); let ssh = fs::read_to_string(repo_path( "build/usb/includes.chroot/etc/systemd/system/ssh.service.d/rigos-observe.conf", From a25867686b540a5bf2d4103678d5d79901234fc9 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Tue, 7 Jul 2026 21:57:34 +0700 Subject: [PATCH 30/64] test staged runtime publication authority --- .../tests/hive_exit_runtime_publish.rs | 211 ++++++++++++++++++ 1 file changed, 211 insertions(+) create mode 100644 crates/rigos-config/tests/hive_exit_runtime_publish.rs diff --git a/crates/rigos-config/tests/hive_exit_runtime_publish.rs b/crates/rigos-config/tests/hive_exit_runtime_publish.rs new file mode 100644 index 00000000..aa67dcc6 --- /dev/null +++ b/crates/rigos-config/tests/hive_exit_runtime_publish.rs @@ -0,0 +1,211 @@ +use serde_json::Value; +use std::fs; +use std::os::unix::fs::{symlink, PermissionsExt}; +use std::path::{Path, PathBuf}; +use std::process::Command; +use std::time::{SystemTime, UNIX_EPOCH}; + +fn repo_path(path: &str) -> PathBuf { + PathBuf::from(env!("CARGO_MANIFEST_DIR")) + .join("../..") + .join(path) +} + +fn write_json(path: &Path, value: Value) { + if let Some(parent) = path.parent() { + fs::create_dir_all(parent).unwrap(); + } + fs::write(path, serde_json::to_vec(&value).unwrap()).unwrap(); +} + +fn read_json(path: &Path) -> Value { + serde_json::from_slice(&fs::read(path).unwrap()).unwrap() +} + +#[test] +fn staged_runtime_publication_is_allowlisted_atomic_and_fail_closed() { + let unique = SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap() + .as_nanos(); + let root = std::env::temp_dir().join(format!("rigos-runtime-publish-{unique}")); + let state = root.join("state"); + let runtime = root.join("run"); + let revision = state.join("revisions/r1"); + fs::create_dir_all(revision.join("flight-sheets")).unwrap(); + fs::create_dir_all(&runtime).unwrap(); + symlink("revisions/r1", state.join("current")).unwrap(); + + write_json( + &revision.join("policy.json"), + serde_json::json!({ + "schema": "rigos.policy/v1", + "active_flight_sheet": "xmr" + }), + ); + write_json( + &revision.join("flight-sheets/xmr.json"), + serde_json::json!({ + "schema": "rigos.flight-sheet/v1", + "backend": "xmrig", + "algorithm": "rx/0", + "cpu": { + "threads": 2, + "huge_pages": true, + "max_threads_hint": 100 + } + }), + ); + write_json( + &revision.join("xmrig.json"), + serde_json::json!({ + "future_top": "TOP_SENTINEL", + "cpu": { + "enabled": true, + "huge-pages": true, + "max-threads-hint": 2, + "future_cpu": "CPU_SENTINEL" + }, + "pools": [{ + "url": "identity:worker@pool.test:1", + "algo": "rx/0", + "user": "IDENTITY_SENTINEL", + "pass": "WORKER_SENTINEL", + "future_pool": "POOL_SENTINEL" + }], + "http": { + "enabled": false, + "access-token": "TOKEN_SENTINEL", + "future_http": "HTTP_SENTINEL" + } + }), + ); + + let renderer = repo_path( + "build/usb/includes.chroot/usr/lib/rigos/rigos-runtime-render", + ); + let publisher = repo_path( + "build/usb/includes.chroot/usr/lib/rigos/rigos-runtime-publish", + ); + let gate = repo_path( + "build/usb/includes.chroot/usr/lib/rigos/rigos-runtime-gate", + ); + let renderer_wrapper = root.join("renderer"); + fs::write( + &renderer_wrapper, + format!("#!/bin/sh\nexec python3 '{}'\n", renderer.display()), + ) + .unwrap(); + fs::set_permissions(&renderer_wrapper, fs::Permissions::from_mode(0o755)).unwrap(); + + let jq = Command::new("jq").arg("--version").status().unwrap(); + assert!(jq.success(), "jq is required by runtime publication authority"); + + let result = Command::new("sh") + .arg(&publisher) + .env("RIGOS_STATE_PATH", &state) + .env("RIGOS_RUNTIME_PATH", &runtime) + .env("RIGOS_RUNTIME_RENDERER", &renderer_wrapper) + .env("RIGOS_RENDER_SKIP_CHOWN", "1") + .status() + .unwrap(); + assert!(result.success(), "runtime publisher failed"); + + let private = read_json(&runtime.join("xmrig.json")); + 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 public = read_json(&runtime.join("xmrig-public.json")); + let public_keys = public.as_object().unwrap().keys().cloned().collect::>(); + assert_eq!( + public_keys, + vec![ + "algo", + "cpu", + "http", + "pools", + "randomx", + "rigos-public-view", + "threads" + ] + ); + assert_eq!(public["algo"], "rx/0"); + assert_eq!(public["threads"], 2); + assert_eq!(public["cpu"]["max-threads-hint"], 100); + assert_eq!(public["cpu"]["rx"], serde_json::json!([-1, -1])); + assert_eq!(public["randomx"]["huge-pages"], true); + assert_eq!(public["pools"][0]["url"], "pool.test:1"); + assert_eq!(public["rigos-public-view"]["construction"], "allowlist"); + let public_text = serde_json::to_string(&public).unwrap(); + for sentinel in [ + "TOP_SENTINEL", + "CPU_SENTINEL", + "POOL_SENTINEL", + "HTTP_SENTINEL", + "IDENTITY_SENTINEL", + "WORKER_SENTINEL", + "TOKEN_SENTINEL", + ] { + assert!(!public_text.contains(sentinel), "public view leaked {sentinel}"); + } + + let status = read_json(&runtime.join("runtime-config-status.json")); + assert_eq!(status["outcome"], "ready"); + assert_eq!(status["revision"], "r1"); + assert_eq!(status["exact_threads"], 2); + assert_eq!(status["public_view_construction"], "allowlist"); + + assert_eq!( + fs::metadata(runtime.join("xmrig.json")) + .unwrap() + .permissions() + .mode() + & 0o777, + 0o640 + ); + for path in [ + runtime.join("xmrig-public.json"), + runtime.join("runtime-config-status.json"), + ] { + assert_eq!( + fs::metadata(path).unwrap().permissions().mode() & 0o777, + 0o644 + ); + } + let leftovers = fs::read_dir(&runtime) + .unwrap() + .filter_map(Result::ok) + .map(|entry| entry.file_name().to_string_lossy().into_owned()) + .filter(|name| name.starts_with('.')) + .collect::>(); + assert!(leftovers.is_empty(), "temporary runtime files remain: {leftovers:?}"); + + let allowed = Command::new("python3") + .arg(&gate) + .arg("--state") + .arg(&state) + .arg("--runtime") + .arg(&runtime) + .status() + .unwrap(); + assert!(allowed.success()); + + let mut invalid = private; + invalid["cpu"]["rx"] = serde_json::json!([-1]); + write_json(&runtime.join("xmrig.json"), invalid); + let denied = Command::new("python3") + .arg(&gate) + .arg("--state") + .arg(&state) + .arg("--runtime") + .arg(&runtime) + .status() + .unwrap(); + assert_eq!(denied.code(), Some(2)); + + let _ = fs::remove_dir_all(root); +} From c55453de596885256aa31bddc3b81cfd209e54c2 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Tue, 7 Jul 2026 21:58:11 +0700 Subject: [PATCH 31/64] test explicit public inspector boundary --- .../tests/explicit_config_boundary.rs | 74 +++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 crates/rigos-xmrig/tests/explicit_config_boundary.rs diff --git a/crates/rigos-xmrig/tests/explicit_config_boundary.rs b/crates/rigos-xmrig/tests/explicit_config_boundary.rs new file mode 100644 index 00000000..8c1c8e26 --- /dev/null +++ b/crates/rigos-xmrig/tests/explicit_config_boundary.rs @@ -0,0 +1,74 @@ +use rigos_machine::MachineContext; +use rigos_miner::MinerBackend; +use rigos_xmrig::{ConfigParseState, XmrigBackend}; +use std::fs; +use std::path::PathBuf; +use std::time::{SystemTime, UNIX_EPOCH}; + +#[test] +fn explicit_public_config_wins_when_runtime_uses_xmrig_short_config_option() { + let unique = SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap() + .as_nanos(); + let root = std::env::temp_dir().join(format!("rigos-explicit-config-{unique}")); + let proc_root = root.join("proc"); + let pid_dir = proc_root.join("42"); + fs::create_dir_all(&pid_dir).unwrap(); + + let private = root.join("private.json"); + let public = root.join("public.json"); + fs::write( + &private, + r#"{"algo":"rx/private","threads":99,"future":"PRIVATE_SENTINEL","http":{"enabled":false}}"#, + ) + .unwrap(); + fs::write( + &public, + r#"{"algo":"rx/0","threads":2,"randomx":{"huge-pages":true},"pools":[{"url":"pool.test:1"}],"http":{"enabled":false}}"#, + ) + .unwrap(); + + fs::write(pid_dir.join("comm"), "xmrig\n").unwrap(); + let mut cmdline = Vec::new(); + cmdline.extend_from_slice(b"xmrig\0-c\0"); + cmdline.extend_from_slice(private.as_os_str().as_encoded_bytes()); + cmdline.push(0); + fs::write(pid_dir.join("cmdline"), cmdline).unwrap(); + fs::write( + pid_dir.join("status"), + "Name:\txmrig\nUid:\t1000 1000 1000 1000\n", + ) + .unwrap(); + fs::write(pid_dir.join("cgroup"), "0::/system.slice/rigos-miner.service\n").unwrap(); + fs::write( + pid_dir.join("stat"), + "42 (xmrig) S 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 100 0\n", + ) + .unwrap(); + fs::write(proc_root.join("uptime"), "100.0 0.0\n").unwrap(); + + let expected_path = public.to_string_lossy().into_owned(); + let backend = XmrigBackend { + explicit_executable: None, + explicit_config: Some(PathBuf::from(&public)), + probe_version: false, + }; + let result = backend.discover(&MachineContext { + proc_root, + sys_root: root.join("sys"), + }); + let _ = fs::remove_dir_all(root); + + let snapshot = result.value.unwrap(); + assert!(snapshot.running); + assert_eq!(snapshot.config.path, Some(expected_path)); + assert!(matches!(snapshot.config.parse_state, ConfigParseState::Valid)); + assert_eq!(snapshot.config.algorithm.as_deref(), Some("rx/0")); + assert_eq!(snapshot.config.thread_hint, Some(2)); + assert_eq!(snapshot.config.huge_pages_requested, Some(true)); + assert_eq!(snapshot.config.pools, vec!["pool.test:1"]); + assert!(!serde_json::to_string(&snapshot) + .unwrap() + .contains("PRIVATE_SENTINEL")); +} From 3157841ae3a57ba11499280602713b17e44c4efd Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Tue, 7 Jul 2026 21:58:41 +0700 Subject: [PATCH 32/64] remove unusable Hive Exit Actions workflow --- .github/workflows/hive-exit-review-fixes.yml | 45 -------------------- 1 file changed, 45 deletions(-) delete mode 100644 .github/workflows/hive-exit-review-fixes.yml diff --git a/.github/workflows/hive-exit-review-fixes.yml b/.github/workflows/hive-exit-review-fixes.yml deleted file mode 100644 index 0f9644b5..00000000 --- a/.github/workflows/hive-exit-review-fixes.yml +++ /dev/null @@ -1,45 +0,0 @@ -name: Apply Hive Exit Review Fixes - -on: - push: - branches: - - stability/hive-exit-gates - -permissions: - contents: write - -jobs: - apply: - if: github.actor != 'github-actions[bot]' - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - ref: stability/hive-exit-gates - fetch-depth: 0 - - - uses: dtolnay/rust-toolchain@1.85.1 - with: - components: rustfmt - - - name: Apply exact source patches - run: python3 scripts/apply-hive-exit-review-fixes.py - - - name: Verify patched sources - run: | - cargo fmt --all - cargo fmt --all -- --check - cargo test -p rigos-xmrig --lib - python3 scripts/check-alpha8-runtime.py - git diff --check - - - name: Commit verified review fixes - run: | - git config user.name "github-actions[bot]" - git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - git add crates/rigos-xmrig/src/lib.rs \ - build/usb/includes.chroot/usr/lib/rigos/rigos-runtime-render \ - scripts/check-alpha8-runtime.py - git diff --cached --quiet && exit 0 - git commit -m "stability enforce public inspector boundary" - git push origin HEAD:stability/hive-exit-gates From b77d87e85262a976b5b46a53f6ff364e7a2c3f52 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Tue, 7 Jul 2026 21:59:06 +0700 Subject: [PATCH 33/64] remove obsolete hostile-review applicator --- scripts/apply-hive-exit-review-fixes.py | 253 ------------------------ 1 file changed, 253 deletions(-) delete mode 100644 scripts/apply-hive-exit-review-fixes.py diff --git a/scripts/apply-hive-exit-review-fixes.py b/scripts/apply-hive-exit-review-fixes.py deleted file mode 100644 index f266812f..00000000 --- a/scripts/apply-hive-exit-review-fixes.py +++ /dev/null @@ -1,253 +0,0 @@ -#!/usr/bin/env python3 -from pathlib import Path - -ROOT = Path(__file__).resolve().parents[1] - - -def replace_once(path: Path, old: str, new: str) -> None: - text = path.read_text(encoding="utf-8") - count = text.count(old) - if count != 1: - raise RuntimeError(f"expected exactly one match in {path}, found {count}") - path.write_text(text.replace(old, new, 1), encoding="utf-8") - - -def patch_xmrig_backend() -> None: - path = ROOT / "crates/rigos-xmrig/src/lib.rs" - replace_once( - path, - """ let config_path = cmdline - .as_deref() - .and_then(extract_config_path) - .or_else(|| self.explicit_config.clone());""", - """ let config_path = self - .explicit_config - .clone() - .or_else(|| cmdline.as_deref().and_then(extract_config_path));""", - ) - - marker = """ #[test] - fn discovers_xmrig_from_synthetic_proc_without_mutation() {""" - test = """ #[test] - fn explicit_config_overrides_process_cmdline_config() { - let unique = SystemTime::now() - .duration_since(UNIX_EPOCH) - .unwrap() - .as_nanos(); - let root = std::env::temp_dir().join(format!("rigos-proc-explicit-{unique}")); - let proc_root = root.join("proc"); - let pid_dir = proc_root.join("42"); - fs::create_dir_all(&pid_dir).unwrap(); - let private = root.join("private.json"); - let public = root.join("public.json"); - fs::write( - &private, - r#"{"algo":"rx/private","http":{"enabled":false}}"#, - ) - .unwrap(); - fs::write( - &public, - r#"{"algo":"rx/0","threads":2,"randomx":{"huge-pages":true},"http":{"enabled":false}}"#, - ) - .unwrap(); - fs::write(pid_dir.join("comm"), "xmrig\n").unwrap(); - fs::write( - pid_dir.join("cmdline"), - format!("xmrig\0--config={}\0", private.display()), - ) - .unwrap(); - fs::write( - pid_dir.join("status"), - "Name:\txmrig\nUid:\t1000 1000 1000 1000\n", - ) - .unwrap(); - fs::write(pid_dir.join("cgroup"), "0::/system.slice/xmrig.service\n").unwrap(); - fs::write( - pid_dir.join("stat"), - "42 (xmrig) S 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 100 0\n", - ) - .unwrap(); - fs::write(proc_root.join("uptime"), "100.0 0.0\n").unwrap(); - - let expected_path = public.to_string_lossy().into_owned(); - let backend = XmrigBackend { - explicit_executable: None, - explicit_config: Some(public), - probe_version: false, - }; - let result = backend.discover(&MachineContext { - proc_root, - sys_root: root.join("sys"), - }); - let _ = fs::remove_dir_all(root); - let snapshot = result.value.unwrap(); - assert_eq!(snapshot.config.path, Some(expected_path)); - assert_eq!(snapshot.config.algorithm.as_deref(), Some("rx/0")); - assert_eq!(snapshot.config.thread_hint, Some(2)); - assert_eq!(snapshot.config.huge_pages_requested, Some(true)); - } - -""" - replace_once(path, marker, test + marker) - - -def patch_runtime_renderer() -> None: - path = ROOT / "build/usb/includes.chroot/usr/lib/rigos/rigos-runtime-render" - helper_marker = """def render() -> tuple[dict, dict, dict]:""" - helpers = """def public_pool(pool: dict) -> dict: - safe = {} - url = pool.get("url") - if isinstance(url, str) and url: - safe["url"] = url.rsplit("@", 1)[-1] - algo = pool.get("algo") - if isinstance(algo, str) and algo: - safe["algo"] = algo - for key in ("tls", "nicehash", "keepalive"): - value = pool.get(key) - if isinstance(value, bool): - safe[key] = value - priority = pool.get("priority") - if isinstance(priority, int) and not isinstance(priority, bool): - safe["priority"] = priority - return safe - - -def public_http(http: object) -> dict: - if not isinstance(http, dict): - return {"enabled": False} - safe = {} - enabled = http.get("enabled") - safe["enabled"] = enabled if isinstance(enabled, bool) else False - host = http.get("host") - if isinstance(host, str) and host: - safe["host"] = host - port = http.get("port") - if isinstance(port, int) and not isinstance(port, bool) and 1 <= port <= 65535: - safe["port"] = port - restricted = http.get("restricted") - if isinstance(restricted, bool): - safe["restricted"] = restricted - return safe - - -""" - replace_once(path, helper_marker, helpers + helper_marker) - - replace_once( - path, - """ public = copy.deepcopy(runtime) - for pool in public.get("pools", []): - if isinstance(pool, dict): - pool.pop("user", None) - pool.pop("pass", None) - http = public.get("http") - if isinstance(http, dict): - http.pop("access-token", None) - - public["algo"] = algorithm - if exact_threads is not None: - public["threads"] = exact_threads - else: - public.pop("threads", None) - public_randomx = public.get("randomx") - if not isinstance(public_randomx, dict): - public_randomx = {} - huge_pages = cpu.get("huge-pages") - if isinstance(huge_pages, bool): - public_randomx["huge-pages"] = huge_pages - public["randomx"] = public_randomx - public["rigos-public-view"] = { - "schema": "rigos.xmrig-public-config/v1", - "identity_redacted": True, - "source_revision": current.name, - } -""", - """ huge_pages = cpu.get("huge-pages") - public_cpu = {} - enabled = cpu.get("enabled") - if isinstance(enabled, bool): - public_cpu["enabled"] = enabled - if isinstance(huge_pages, bool): - public_cpu["huge-pages"] = huge_pages - max_threads_hint = cpu.get("max-threads-hint") - if isinstance(max_threads_hint, int) and not isinstance(max_threads_hint, bool): - public_cpu["max-threads-hint"] = max_threads_hint - if profile is not None and exact_threads is not None: - public_cpu[profile] = [-1] * exact_threads - - public = { - "algo": algorithm, - "cpu": public_cpu, - "http": public_http(runtime.get("http")), - "pools": [public_pool(pool) for pool in pools], - "randomx": { - "huge-pages": huge_pages if isinstance(huge_pages, bool) else False, - }, - "rigos-public-view": { - "schema": "rigos.xmrig-public-config/v1", - "identity_redacted": True, - "construction": "allowlist", - "source_revision": current.name, - }, - } - if exact_threads is not None: - public["threads"] = exact_threads -""", - ) - - replace_once( - path, - ' "identity_redacted_public_view": True,\n', - ' "identity_redacted_public_view": True,\n "public_view_construction": "allowlist",\n', - ) - - -def patch_runtime_fixture() -> None: - path = ROOT / "scripts/check-alpha8-runtime.py" - replace_once( - path, - ' "max-threads-hint": 2,\n', - ' "max-threads-hint": 2,\n "future-secret": "fixture-cpu-secret",\n', - ) - replace_once( - path, - ' "pass": "fixture-worker",\n', - ' "pass": "fixture-worker",\n "future-secret": "fixture-pool-secret",\n', - ) - replace_once( - path, - ' "access-token": "fixture-private-token",\n', - ' "access-token": "fixture-private-token",\n "future-secret": "fixture-http-secret",\n', - ) - replace_once( - path, - ' "http": {\n', - ' "future-secret": "fixture-top-secret",\n "http": {\n', - ) - replace_once( - path, - ' assert public["rigos-public-view"]["identity_redacted"] is True\n', - ' assert public["rigos-public-view"]["identity_redacted"] is True\n assert public["rigos-public-view"]["construction"] == "allowlist"\n assert set(public) == {"algo", "cpu", "http", "pools", "randomx", "rigos-public-view", "threads"}\n assert set(public["pools"][0]) <= {"url", "algo", "tls", "nicehash", "keepalive", "priority"}\n assert set(public["http"]) <= {"enabled", "host", "port", "restricted"}\n', - ) - replace_once( - path, - ' assert "fixture-private-token" not in public_text\n', - ' assert "fixture-private-token" not in public_text\n assert "fixture-cpu-secret" not in public_text\n assert "fixture-pool-secret" not in public_text\n assert "fixture-http-secret" not in public_text\n assert "fixture-top-secret" not in public_text\n', - ) - replace_once( - path, - ' assert status["profile"] == "rx"\n', - ' assert status["profile"] == "rx"\n assert status["public_view_construction"] == "allowlist"\n', - ) - - -def main() -> int: - patch_xmrig_backend() - patch_runtime_renderer() - patch_runtime_fixture() - print("Hive Exit hostile review fixes applied") - return 0 - - -if __name__ == "__main__": - raise SystemExit(main()) From c7c9f4dc1aa06acae20f0c11e55317bd05fa4ade Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Tue, 7 Jul 2026 21:59:55 +0700 Subject: [PATCH 34/64] document staged runtime authority boundary --- docs/hive-exit-hostile-review.md | 53 +++++++++++++++++++++++++++++--- 1 file changed, 48 insertions(+), 5 deletions(-) diff --git a/docs/hive-exit-hostile-review.md b/docs/hive-exit-hostile-review.md index 5d731dba..d4904ab0 100644 --- a/docs/hive-exit-hostile-review.md +++ b/docs/hive-exit-hostile-review.md @@ -1,8 +1,51 @@ -# Hive Exit hostile review +HIVE EXIT HOSTILE REVIEW +======================== -The first stability batch passed source verification, but review found two release blockers before image construction: +The first stability batch passed source verification, but review found two +release blockers before image construction. -1. An explicit inspector configuration must take precedence over a configuration discovered from the running process command line. -2. The public XMRig view must be constructed from an allowlist. Copying the private configuration and deleting known secret fields is not an acceptable security boundary. +1. The inspector must never select the identity-bearing runtime configuration + when the public configuration was explicitly requested. -The review fix must pass Rust formatting, the `rigos-xmrig` unit suite, the runtime redaction fixture, and `git diff --check` before it is committed to the stability branch. +2. The public XMRig view must be constructed from an allowlist. Copying the + private configuration and deleting known fields is not a security boundary. + +CURRENT BOUNDARY +---------------- + +The legacy renderer now runs only inside a private staging directory under +/run/rigos with mode 0700. The runtime publication authority then creates a +new public document from an explicit jq allowlist and atomically publishes: + + /run/rigos/xmrig.json mode 0640 + /run/rigos/xmrig-public.json mode 0644 + /run/rigos/runtime-config-status.json mode 0644 + +The status document is published last. A failed publication therefore cannot +claim a new ready state before the private and public documents are in place. + +The managed XMRig process uses the supported short option: + + xmrig -c /run/rigos/xmrig.json + +RIGOS process discovery currently recognizes only the long --config forms. +The rigosd and rigosctl wrappers explicitly select xmrig-public.json, so the +managed process command line cannot override the public inspection path. +This compatibility boundary is covered by an integration test and must not be +changed independently from the parser or systemd wiring. + +REQUIRED VERIFICATION +--------------------- + + cargo fmt --all -- --check + cargo test -p rigos-xmrig --test explicit_config_boundary + cargo test -p rigos-config --test hive_exit_runtime_publish + ./scripts/verify.sh + +The publication fixture injects unknown sentinel fields at the top level and +inside CPU, pool, and HTTP objects. Private runtime truth must retain them. +The public view must contain none of them. + +GitHub Actions are disabled for this account. Verification evidence therefore +comes from the local WSL source gate and exact artifact provenance, not from a +remote workflow badge. From ef76972ea8767da15f52507d2fb91fc0a1d0c1ea Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Tue, 7 Jul 2026 22:00:50 +0700 Subject: [PATCH 35/64] format staged runtime publication test --- .../tests/hive_exit_runtime_publish.rs | 36 +++++++++++-------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/crates/rigos-config/tests/hive_exit_runtime_publish.rs b/crates/rigos-config/tests/hive_exit_runtime_publish.rs index aa67dcc6..9fb67014 100644 --- a/crates/rigos-config/tests/hive_exit_runtime_publish.rs +++ b/crates/rigos-config/tests/hive_exit_runtime_publish.rs @@ -1,6 +1,6 @@ use serde_json::Value; use std::fs; -use std::os::unix::fs::{symlink, PermissionsExt}; +use std::os::unix::fs::{PermissionsExt, symlink}; use std::path::{Path, PathBuf}; use std::process::Command; use std::time::{SystemTime, UNIX_EPOCH}; @@ -81,15 +81,9 @@ fn staged_runtime_publication_is_allowlisted_atomic_and_fail_closed() { }), ); - let renderer = repo_path( - "build/usb/includes.chroot/usr/lib/rigos/rigos-runtime-render", - ); - let publisher = repo_path( - "build/usb/includes.chroot/usr/lib/rigos/rigos-runtime-publish", - ); - let gate = repo_path( - "build/usb/includes.chroot/usr/lib/rigos/rigos-runtime-gate", - ); + let renderer = repo_path("build/usb/includes.chroot/usr/lib/rigos/rigos-runtime-render"); + let publisher = repo_path("build/usb/includes.chroot/usr/lib/rigos/rigos-runtime-publish"); + let gate = repo_path("build/usb/includes.chroot/usr/lib/rigos/rigos-runtime-gate"); let renderer_wrapper = root.join("renderer"); fs::write( &renderer_wrapper, @@ -99,7 +93,10 @@ fn staged_runtime_publication_is_allowlisted_atomic_and_fail_closed() { fs::set_permissions(&renderer_wrapper, fs::Permissions::from_mode(0o755)).unwrap(); let jq = Command::new("jq").arg("--version").status().unwrap(); - assert!(jq.success(), "jq is required by runtime publication authority"); + assert!( + jq.success(), + "jq is required by runtime publication authority" + ); let result = Command::new("sh") .arg(&publisher) @@ -120,7 +117,12 @@ fn staged_runtime_publication_is_allowlisted_atomic_and_fail_closed() { assert_eq!(private["cpu"]["rx"], serde_json::json!([-1, -1])); let public = read_json(&runtime.join("xmrig-public.json")); - let public_keys = public.as_object().unwrap().keys().cloned().collect::>(); + let public_keys = public + .as_object() + .unwrap() + .keys() + .cloned() + .collect::>(); assert_eq!( public_keys, vec![ @@ -150,7 +152,10 @@ fn staged_runtime_publication_is_allowlisted_atomic_and_fail_closed() { "WORKER_SENTINEL", "TOKEN_SENTINEL", ] { - assert!(!public_text.contains(sentinel), "public view leaked {sentinel}"); + assert!( + !public_text.contains(sentinel), + "public view leaked {sentinel}" + ); } let status = read_json(&runtime.join("runtime-config-status.json")); @@ -182,7 +187,10 @@ fn staged_runtime_publication_is_allowlisted_atomic_and_fail_closed() { .map(|entry| entry.file_name().to_string_lossy().into_owned()) .filter(|name| name.starts_with('.')) .collect::>(); - assert!(leftovers.is_empty(), "temporary runtime files remain: {leftovers:?}"); + assert!( + leftovers.is_empty(), + "temporary runtime files remain: {leftovers:?}" + ); let allowed = Command::new("python3") .arg(&gate) From d6434065d871650ed0e7264979351d3e673763ed Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Tue, 7 Jul 2026 22:01:28 +0700 Subject: [PATCH 36/64] format explicit inspector boundary test --- .../tests/explicit_config_boundary.rs | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/crates/rigos-xmrig/tests/explicit_config_boundary.rs b/crates/rigos-xmrig/tests/explicit_config_boundary.rs index 8c1c8e26..5c664ffb 100644 --- a/crates/rigos-xmrig/tests/explicit_config_boundary.rs +++ b/crates/rigos-xmrig/tests/explicit_config_boundary.rs @@ -40,7 +40,11 @@ fn explicit_public_config_wins_when_runtime_uses_xmrig_short_config_option() { "Name:\txmrig\nUid:\t1000 1000 1000 1000\n", ) .unwrap(); - fs::write(pid_dir.join("cgroup"), "0::/system.slice/rigos-miner.service\n").unwrap(); + fs::write( + pid_dir.join("cgroup"), + "0::/system.slice/rigos-miner.service\n", + ) + .unwrap(); fs::write( pid_dir.join("stat"), "42 (xmrig) S 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 100 0\n", @@ -63,12 +67,17 @@ fn explicit_public_config_wins_when_runtime_uses_xmrig_short_config_option() { let snapshot = result.value.unwrap(); assert!(snapshot.running); assert_eq!(snapshot.config.path, Some(expected_path)); - assert!(matches!(snapshot.config.parse_state, ConfigParseState::Valid)); + assert!(matches!( + snapshot.config.parse_state, + ConfigParseState::Valid + )); assert_eq!(snapshot.config.algorithm.as_deref(), Some("rx/0")); assert_eq!(snapshot.config.thread_hint, Some(2)); assert_eq!(snapshot.config.huge_pages_requested, Some(true)); assert_eq!(snapshot.config.pools, vec!["pool.test:1"]); - assert!(!serde_json::to_string(&snapshot) - .unwrap() - .contains("PRIVATE_SENTINEL")); + assert!( + !serde_json::to_string(&snapshot) + .unwrap() + .contains("PRIVATE_SENTINEL") + ); } From e4ad431042a8c4f88ca596a65687cd5de3a3ec94 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Tue, 7 Jul 2026 22:03:51 +0700 Subject: [PATCH 37/64] verify Hive Exit runtime authority in image --- scripts/verify-usb-appliance.sh | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/scripts/verify-usb-appliance.sh b/scripts/verify-usb-appliance.sh index 812f8ed5..1e5cf261 100755 --- a/scripts/verify-usb-appliance.sh +++ b/scripts/verify-usb-appliance.sh @@ -82,10 +82,17 @@ unsquashfs -no-progress -d "$temporary/root" "$temporary/a/live/filesystem.squas etc/systemd/system/rigos-firstboot.service \ etc/systemd/system/rigos-hugepages.service \ etc/systemd/system/rigos-miner.service \ + etc/systemd/system/rigos-miner.service.d/runtime-render.conf \ + etc/systemd/system/rigos-miner.service.d/stability.conf \ + etc/systemd/system/rigos-miner-health.service \ + etc/systemd/system/rigos-miner-health.timer \ + etc/systemd/system/rigos-runtime-render.service \ etc/systemd/system/rigos-profile-apply.service \ usr/bin/python3 usr/bin/python3.11 \ 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/xmrig usr/local/sbin/rigosctl usr/local/sbin/rigos-firstboot usr/local/sbin/rigos-recovery-access usr/local/sbin/rigos-state-orchestrate \ + 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-gate 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' @@ -93,6 +100,8 @@ 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" +sh -n "$temporary/root/usr/lib/rigos/rigos-runtime-publish" python3 "$script_dir/verify-systemd-ordering.py" "$temporary/root/etc/systemd/system" rigosctl_path="$(PATH="$temporary/root/usr/local/sbin:$temporary/root/usr/bin" command -v rigosctl)" [[ "$rigosctl_path" == "$temporary/root/usr/local/sbin/rigosctl" && -x "$rigosctl_path" ]] || die 'rigosctl is not executable in the appliance PATH' @@ -120,6 +129,20 @@ strings "$temporary/root/usr/lib/rigos/rigos-performance" | grep -F 'rigos.perfo if strings "$temporary/root/usr/lib/rigos/rigos-performance" | grep -F 'sysctl' >/dev/null; then die 'performance authority shells out to sysctl'; fi if strings "$temporary/root/usr/lib/rigos/rigos-performance" | grep -Ei '(/dev/sd|/dev/nvme|cpu model)' >/dev/null; then die 'performance authority contains hardware-name or internal-disk targeting'; fi grep -Fq 'ExecCondition=/usr/lib/rigos/rigos-miner-gate' "$temporary/root/etc/systemd/system/rigos-miner.service" || die 'miner safety gate is missing' +[[ -x "$temporary/root/usr/lib/rigos/rigos-runtime-render" ]] || die 'legacy runtime renderer is missing' +[[ -x "$temporary/root/usr/lib/rigos/rigos-runtime-publish" ]] || die 'runtime publication authority is missing' +grep -Fq 'ExecStart=/usr/lib/rigos/rigos-runtime-publish' "$temporary/root/etc/systemd/system/rigos-runtime-render.service" || die 'runtime publication authority is not wired' +grep -Fq 'ExecCondition=+/usr/lib/rigos/rigos-runtime-publish' "$temporary/root/etc/systemd/system/rigos-miner.service.d/runtime-render.conf" || die 'miner does not republish runtime truth before start' +grep -Fq 'ExecCondition=/usr/lib/rigos/rigos-runtime-gate' "$temporary/root/etc/systemd/system/rigos-miner.service.d/runtime-render.conf" || die 'runtime gate is missing from miner override' +grep -Fq 'ExecStart=/usr/lib/rigos/xmrig -c /run/rigos/xmrig.json' "$temporary/root/etc/systemd/system/rigos-miner.service.d/runtime-render.conf" || die 'managed miner does not use the short private runtime config option' +grep -Fq 'construction: "allowlist"' "$temporary/root/usr/lib/rigos/rigos-runtime-publish" || die 'public runtime allowlist marker is missing' +grep -Fq '.render-stage.XXXXXX' "$temporary/root/usr/lib/rigos/rigos-runtime-publish" || die 'private runtime staging directory is missing' +grep -Fq -- '--xmrig-config /run/rigos/xmrig-public.json' "$temporary/root/usr/local/bin/rigosd" || die 'rigosd does not default to the public runtime view' +grep -Fq -- '--xmrig-config /run/rigos/xmrig-public.json' "$temporary/root/usr/local/bin/rigosctl" || die 'rigosctl does not default to the public runtime view' +[[ -x "$temporary/root/usr/lib/rigos/rigos-miner-health" ]] || die 'miner health observer is missing' +grep -Fq 'OnUnitActiveSec=1min' "$temporary/root/etc/systemd/system/rigos-miner-health.timer" || die 'miner health timer cadence is missing' +grep -Fq 'Restart=on-failure' "$temporary/root/etc/systemd/system/rigos-miner.service.d/stability.conf" || die 'bounded miner restart policy is missing' +grep -Fq 'StartLimitBurst=5' "$temporary/root/etc/systemd/system/rigos-miner.service.d/stability.conf" || die 'miner crash-loop ceiling is missing' [[ -f "$temporary/root/etc/systemd/system/rigos-profile-apply.service" ]] || die 'profile apply service is missing' grep -Fq 'ExecCondition=/usr/lib/rigos/rigos-config needs-activation' "$temporary/root/etc/systemd/system/rigos-firstboot.service" || die 'first boot activation gate is missing' grep -Fq 'ExecStart=/usr/local/sbin/rigos-recovery-access' "$temporary/root/etc/systemd/system/rigos-recovery-access.service" || die 'local recovery access phase is missing' From 9de4763b471e0cd43336afd2bbf17a013f1b97e7 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Tue, 7 Jul 2026 22:04:52 +0700 Subject: [PATCH 38/64] clippy clean runtime publication fixture --- crates/rigos-config/tests/hive_exit_runtime_publish.rs | 2 +- 1 file changed, 1 insertion(+), 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 9fb67014..56f757bf 100644 --- a/crates/rigos-config/tests/hive_exit_runtime_publish.rs +++ b/crates/rigos-config/tests/hive_exit_runtime_publish.rs @@ -139,7 +139,7 @@ fn staged_runtime_publication_is_allowlisted_atomic_and_fail_closed() { assert_eq!(public["threads"], 2); assert_eq!(public["cpu"]["max-threads-hint"], 100); assert_eq!(public["cpu"]["rx"], serde_json::json!([-1, -1])); - assert_eq!(public["randomx"]["huge-pages"], true); + assert!(public["randomx"]["huge-pages"] == true); assert_eq!(public["pools"][0]["url"], "pool.test:1"); assert_eq!(public["rigos-public-view"]["construction"], "allowlist"); let public_text = serde_json::to_string(&public).unwrap(); From 706f6bdcfdbfbb400093139adf44c64a2d1fccba Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Tue, 7 Jul 2026 22:06:03 +0700 Subject: [PATCH 39/64] clippy clean explicit inspector boundary --- crates/rigos-xmrig/tests/explicit_config_boundary.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/crates/rigos-xmrig/tests/explicit_config_boundary.rs b/crates/rigos-xmrig/tests/explicit_config_boundary.rs index 5c664ffb..ae7a854d 100644 --- a/crates/rigos-xmrig/tests/explicit_config_boundary.rs +++ b/crates/rigos-xmrig/tests/explicit_config_boundary.rs @@ -2,7 +2,6 @@ use rigos_machine::MachineContext; use rigos_miner::MinerBackend; use rigos_xmrig::{ConfigParseState, XmrigBackend}; use std::fs; -use std::path::PathBuf; use std::time::{SystemTime, UNIX_EPOCH}; #[test] @@ -55,7 +54,7 @@ fn explicit_public_config_wins_when_runtime_uses_xmrig_short_config_option() { let expected_path = public.to_string_lossy().into_owned(); let backend = XmrigBackend { explicit_executable: None, - explicit_config: Some(PathBuf::from(&public)), + explicit_config: Some(public.clone()), probe_version: false, }; let result = backend.discover(&MachineContext { From f99cb68cbe6d54cc015e2b44119fdf9a6f1183de Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Tue, 7 Jul 2026 22:07:01 +0700 Subject: [PATCH 40/64] remove boolean comparison lint --- crates/rigos-config/tests/hive_exit_runtime_publish.rs | 2 +- 1 file changed, 1 insertion(+), 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 56f757bf..47f42069 100644 --- a/crates/rigos-config/tests/hive_exit_runtime_publish.rs +++ b/crates/rigos-config/tests/hive_exit_runtime_publish.rs @@ -139,7 +139,7 @@ fn staged_runtime_publication_is_allowlisted_atomic_and_fail_closed() { assert_eq!(public["threads"], 2); assert_eq!(public["cpu"]["max-threads-hint"], 100); assert_eq!(public["cpu"]["rx"], serde_json::json!([-1, -1])); - assert!(public["randomx"]["huge-pages"] == true); + 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"); let public_text = serde_json::to_string(&public).unwrap(); From e0df53bfb4ac2cbf3fcdff2fa9429753172c35a4 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Tue, 7 Jul 2026 22:07:34 +0700 Subject: [PATCH 41/64] test Hive Exit image verifier coverage --- .../tests/hive_exit_image_verifier.rs | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 crates/rigos-config/tests/hive_exit_image_verifier.rs diff --git a/crates/rigos-config/tests/hive_exit_image_verifier.rs b/crates/rigos-config/tests/hive_exit_image_verifier.rs new file mode 100644 index 00000000..24fc9dd3 --- /dev/null +++ b/crates/rigos-config/tests/hive_exit_image_verifier.rs @@ -0,0 +1,35 @@ +use std::fs; +use std::path::PathBuf; + +fn repo_path(path: &str) -> PathBuf { + PathBuf::from(env!("CARGO_MANIFEST_DIR")) + .join("../..") + .join(path) +} + +#[test] +fn image_verifier_requires_runtime_authority_and_stability_bytes() { + let verifier = fs::read_to_string(repo_path("scripts/verify-usb-appliance.sh")).unwrap(); + + for required in [ + "usr/lib/rigos/rigos-runtime-publish", + "usr/lib/rigos/rigos-miner-health", + "usr/local/bin/rigosd", + "usr/local/bin/rigosctl", + "etc/systemd/system/rigos-runtime-render.service", + "etc/systemd/system/rigos-miner.service.d/runtime-render.conf", + "etc/systemd/system/rigos-miner.service.d/stability.conf", + "etc/systemd/system/rigos-miner-health.timer", + "ExecStart=/usr/lib/rigos/rigos-runtime-publish", + "ExecCondition=+/usr/lib/rigos/rigos-runtime-publish", + "ExecStart=/usr/lib/rigos/xmrig -c /run/rigos/xmrig.json", + "--xmrig-config /run/rigos/xmrig-public.json", + "construction: \"allowlist\"", + "StartLimitBurst=5", + ] { + assert!( + verifier.contains(required), + "image verifier is missing contract: {required}" + ); + } +} From 120d5be653789e156476507bc0a6c213d59cb569 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Tue, 7 Jul 2026 22:09:13 +0700 Subject: [PATCH 42/64] stability serialize runtime publication authority --- .../usr/lib/rigos/rigos-runtime-authority | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 build/usb/includes.chroot/usr/lib/rigos/rigos-runtime-authority diff --git a/build/usb/includes.chroot/usr/lib/rigos/rigos-runtime-authority b/build/usb/includes.chroot/usr/lib/rigos/rigos-runtime-authority new file mode 100644 index 00000000..7cd01f5f --- /dev/null +++ b/build/usb/includes.chroot/usr/lib/rigos/rigos-runtime-authority @@ -0,0 +1,31 @@ +#!/bin/sh +set -eu + +runtime=${RIGOS_RUNTIME_PATH:-/run/rigos} +publisher=${RIGOS_RUNTIME_PUBLISHER:-/usr/lib/rigos/rigos-runtime-publish} +mkdir -p "$runtime" +chmod 0755 "$runtime" + +lock="$runtime/.runtime-publish.lock" +exec 9>"$lock" +chmod 0600 "$lock" +if ! flock -x -w 30 9; then + echo 'rigos-runtime-authority: publication lock timeout' >&2 + exit 75 +fi + +cleanup_stale() { + find -P "$runtime" -mindepth 1 -maxdepth 1 -type d \ + -name '.render-stage.*' -exec rm -rf -- {} + + find -P "$runtime" -mindepth 1 -maxdepth 1 -type f \ + \( -name '.xmrig-public.*' \ + -o -name '.runtime-status.*' \ + -o -name '.xmrig-runtime.*' \) \ + -delete +} + +cleanup_stale +status=0 +"$publisher" || status=$? +cleanup_stale +exit "$status" From 389d732ee6542ad4a9eb0f69af4c60a9ac453a5e Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Tue, 7 Jul 2026 22:09:47 +0700 Subject: [PATCH 43/64] stability serialize runtime authority service --- .../etc/systemd/system/rigos-runtime-render.service | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/usb/includes.chroot/etc/systemd/system/rigos-runtime-render.service b/build/usb/includes.chroot/etc/systemd/system/rigos-runtime-render.service index 06b7d29f..cbf8f72a 100644 --- a/build/usb/includes.chroot/etc/systemd/system/rigos-runtime-render.service +++ b/build/usb/includes.chroot/etc/systemd/system/rigos-runtime-render.service @@ -7,7 +7,7 @@ ConditionPathExists=/var/lib/rigos/current [Service] Type=oneshot -ExecStart=/usr/lib/rigos/rigos-runtime-publish +ExecStart=/usr/lib/rigos/rigos-runtime-authority NoNewPrivileges=yes PrivateTmp=yes ProtectHome=yes From c5c022c33cb27598935c0a442f19216d1462fc81 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Tue, 7 Jul 2026 22:10:28 +0700 Subject: [PATCH 44/64] stability serialize miner runtime publication --- .../systemd/system/rigos-miner.service.d/runtime-render.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/usb/includes.chroot/etc/systemd/system/rigos-miner.service.d/runtime-render.conf b/build/usb/includes.chroot/etc/systemd/system/rigos-miner.service.d/runtime-render.conf index a9f754a2..3b94d5ff 100644 --- a/build/usb/includes.chroot/etc/systemd/system/rigos-miner.service.d/runtime-render.conf +++ b/build/usb/includes.chroot/etc/systemd/system/rigos-miner.service.d/runtime-render.conf @@ -5,7 +5,7 @@ ConditionPathExists= ConditionPathExists=/var/lib/rigos/current [Service] -ExecCondition=+/usr/lib/rigos/rigos-runtime-publish +ExecCondition=+/usr/lib/rigos/rigos-runtime-authority ExecCondition=/usr/lib/rigos/rigos-runtime-gate ExecStart= ExecStart=/usr/lib/rigos/xmrig -c /run/rigos/xmrig.json From 2a3f597b179238ffd79f725bf9f11259c18ea94b Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Tue, 7 Jul 2026 22:13:39 +0700 Subject: [PATCH 45/64] stability make runtime authority executable --- build/usb/includes.chroot/usr/lib/rigos/rigos-runtime-authority | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 build/usb/includes.chroot/usr/lib/rigos/rigos-runtime-authority diff --git a/build/usb/includes.chroot/usr/lib/rigos/rigos-runtime-authority b/build/usb/includes.chroot/usr/lib/rigos/rigos-runtime-authority old mode 100644 new mode 100755 From fbe9dfb86e898eefd5f581e352fae53aaaf70aff Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Tue, 7 Jul 2026 22:15:12 +0700 Subject: [PATCH 46/64] test serialized runtime authority wiring --- crates/rigos-config/tests/recovery_access.rs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/crates/rigos-config/tests/recovery_access.rs b/crates/rigos-config/tests/recovery_access.rs index 61924961..fd56a8ba 100644 --- a/crates/rigos-config/tests/recovery_access.rs +++ b/crates/rigos-config/tests/recovery_access.rs @@ -163,7 +163,17 @@ fn alpha8_appliance_wiring_is_explicit() { "build/usb/includes.chroot/etc/systemd/system/rigos-runtime-render.service", )) .expect("read runtime authority service"); - assert!(runtime_service.contains("ExecStart=/usr/lib/rigos/rigos-runtime-publish")); + 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; + assert_ne!(mode.mode() & 0o111, 0); + } let miner = fs::read_to_string(repo_path( "build/usb/includes.chroot/etc/systemd/system/rigos-miner.service.d/runtime-render.conf", @@ -171,7 +181,7 @@ fn alpha8_appliance_wiring_is_explicit() { .expect("read miner runtime override"); assert!(miner.contains("Requires=rigos-runtime-render.service")); assert!(miner.contains("ConditionPathExists=/var/lib/rigos/current")); - assert!(miner.contains("ExecCondition=+/usr/lib/rigos/rigos-runtime-publish")); + assert!(miner.contains("ExecCondition=+/usr/lib/rigos/rigos-runtime-authority")); assert!(miner.contains("ExecCondition=/usr/lib/rigos/rigos-runtime-gate")); assert!(miner.contains("ExecStart=/usr/lib/rigos/xmrig -c /run/rigos/xmrig.json")); assert!(!miner.contains("--config=/run/rigos/xmrig.json")); From 94b97b0eab0a72430ca2121ffd1bf041ce4ec616 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Tue, 7 Jul 2026 22:17:44 +0700 Subject: [PATCH 47/64] verify serialized runtime authority in image --- scripts/verify-usb-appliance.sh | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/scripts/verify-usb-appliance.sh b/scripts/verify-usb-appliance.sh index 1e5cf261..8cf73ebe 100755 --- a/scripts/verify-usb-appliance.sh +++ b/scripts/verify-usb-appliance.sh @@ -90,7 +90,7 @@ unsquashfs -no-progress -d "$temporary/root" "$temporary/a/live/filesystem.squas etc/systemd/system/rigos-profile-apply.service \ usr/bin/python3 usr/bin/python3.11 \ 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-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/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 @@ -102,6 +102,7 @@ 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" 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" rigosctl_path="$(PATH="$temporary/root/usr/local/sbin:$temporary/root/usr/bin" command -v rigosctl)" [[ "$rigosctl_path" == "$temporary/root/usr/local/sbin/rigosctl" && -x "$rigosctl_path" ]] || die 'rigosctl is not executable in the appliance PATH' @@ -130,11 +131,13 @@ if strings "$temporary/root/usr/lib/rigos/rigos-performance" | grep -F 'sysctl' if strings "$temporary/root/usr/lib/rigos/rigos-performance" | grep -Ei '(/dev/sd|/dev/nvme|cpu model)' >/dev/null; then die 'performance authority contains hardware-name or internal-disk targeting'; fi grep -Fq 'ExecCondition=/usr/lib/rigos/rigos-miner-gate' "$temporary/root/etc/systemd/system/rigos-miner.service" || die 'miner safety gate is missing' [[ -x "$temporary/root/usr/lib/rigos/rigos-runtime-render" ]] || die 'legacy runtime renderer is missing' -[[ -x "$temporary/root/usr/lib/rigos/rigos-runtime-publish" ]] || die 'runtime publication authority is missing' -grep -Fq 'ExecStart=/usr/lib/rigos/rigos-runtime-publish' "$temporary/root/etc/systemd/system/rigos-runtime-render.service" || die 'runtime publication authority is not wired' -grep -Fq 'ExecCondition=+/usr/lib/rigos/rigos-runtime-publish' "$temporary/root/etc/systemd/system/rigos-miner.service.d/runtime-render.conf" || die 'miner does not republish runtime truth before start' +[[ -x "$temporary/root/usr/lib/rigos/rigos-runtime-publish" ]] || die 'runtime allowlist publisher is missing' +[[ -x "$temporary/root/usr/lib/rigos/rigos-runtime-authority" ]] || die 'serialized runtime authority is missing' +grep -Fq 'ExecStart=/usr/lib/rigos/rigos-runtime-authority' "$temporary/root/etc/systemd/system/rigos-runtime-render.service" || die 'serialized runtime authority is not wired' +grep -Fq 'ExecCondition=+/usr/lib/rigos/rigos-runtime-authority' "$temporary/root/etc/systemd/system/rigos-miner.service.d/runtime-render.conf" || die 'miner does not serialize runtime publication before start' grep -Fq 'ExecCondition=/usr/lib/rigos/rigos-runtime-gate' "$temporary/root/etc/systemd/system/rigos-miner.service.d/runtime-render.conf" || die 'runtime gate is missing from miner override' grep -Fq 'ExecStart=/usr/lib/rigos/xmrig -c /run/rigos/xmrig.json' "$temporary/root/etc/systemd/system/rigos-miner.service.d/runtime-render.conf" || die 'managed miner does not use the short private runtime config option' +grep -Fq 'flock -x -w 30' "$temporary/root/usr/lib/rigos/rigos-runtime-authority" || die 'runtime publication lock is missing' grep -Fq 'construction: "allowlist"' "$temporary/root/usr/lib/rigos/rigos-runtime-publish" || die 'public runtime allowlist marker is missing' grep -Fq '.render-stage.XXXXXX' "$temporary/root/usr/lib/rigos/rigos-runtime-publish" || die 'private runtime staging directory is missing' grep -Fq -- '--xmrig-config /run/rigos/xmrig-public.json' "$temporary/root/usr/local/bin/rigosd" || die 'rigosd does not default to the public runtime view' From dea78e92bc43e899572c0cfce787fa37b91e4b3c Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Tue, 7 Jul 2026 22:18:28 +0700 Subject: [PATCH 48/64] test serialized runtime image verification --- crates/rigos-config/tests/hive_exit_image_verifier.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/crates/rigos-config/tests/hive_exit_image_verifier.rs b/crates/rigos-config/tests/hive_exit_image_verifier.rs index 24fc9dd3..61794f02 100644 --- a/crates/rigos-config/tests/hive_exit_image_verifier.rs +++ b/crates/rigos-config/tests/hive_exit_image_verifier.rs @@ -13,6 +13,7 @@ fn image_verifier_requires_runtime_authority_and_stability_bytes() { for required in [ "usr/lib/rigos/rigos-runtime-publish", + "usr/lib/rigos/rigos-runtime-authority", "usr/lib/rigos/rigos-miner-health", "usr/local/bin/rigosd", "usr/local/bin/rigosctl", @@ -20,10 +21,11 @@ fn image_verifier_requires_runtime_authority_and_stability_bytes() { "etc/systemd/system/rigos-miner.service.d/runtime-render.conf", "etc/systemd/system/rigos-miner.service.d/stability.conf", "etc/systemd/system/rigos-miner-health.timer", - "ExecStart=/usr/lib/rigos/rigos-runtime-publish", - "ExecCondition=+/usr/lib/rigos/rigos-runtime-publish", + "ExecStart=/usr/lib/rigos/rigos-runtime-authority", + "ExecCondition=+/usr/lib/rigos/rigos-runtime-authority", "ExecStart=/usr/lib/rigos/xmrig -c /run/rigos/xmrig.json", "--xmrig-config /run/rigos/xmrig-public.json", + "flock -x -w 30", "construction: \"allowlist\"", "StartLimitBurst=5", ] { From 9ee224f7373ff82cad560ac88eeceaff91478b8d Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Tue, 7 Jul 2026 22:23:40 +0700 Subject: [PATCH 49/64] test Hive Exit shell authority syntax --- .../tests/hive_exit_shell_syntax.rs | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 crates/rigos-config/tests/hive_exit_shell_syntax.rs diff --git a/crates/rigos-config/tests/hive_exit_shell_syntax.rs b/crates/rigos-config/tests/hive_exit_shell_syntax.rs new file mode 100644 index 00000000..dabea7db --- /dev/null +++ b/crates/rigos-config/tests/hive_exit_shell_syntax.rs @@ -0,0 +1,23 @@ +use std::path::PathBuf; +use std::process::Command; + +fn repo_path(path: &str) -> PathBuf { + PathBuf::from(env!("CARGO_MANIFEST_DIR")) + .join("../..") + .join(path) +} + +#[test] +fn runtime_authority_shells_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", + ] { + let status = Command::new("sh") + .arg("-n") + .arg(repo_path(path)) + .status() + .unwrap(); + assert!(status.success(), "shell syntax failed: {path}"); + } +} From 4a4f9f4a052d1be6943e19f47dc8cdadfbfe3698 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Tue, 7 Jul 2026 22:43:49 +0700 Subject: [PATCH 50/64] format runtime authority path assertion --- crates/rigos-config/tests/recovery_access.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/crates/rigos-config/tests/recovery_access.rs b/crates/rigos-config/tests/recovery_access.rs index fd56a8ba..79e156b2 100644 --- a/crates/rigos-config/tests/recovery_access.rs +++ b/crates/rigos-config/tests/recovery_access.rs @@ -165,9 +165,7 @@ 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 authority = repo_path("build/usb/includes.chroot/usr/lib/rigos/rigos-runtime-authority"); let mode = fs::metadata(authority).unwrap().permissions(); #[cfg(unix)] { From e8d31f85e75bf155ea618dab30fa1333a8ecd8b0 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Tue, 7 Jul 2026 23:18:24 +0700 Subject: [PATCH 51/64] stability enforce LF for appliance scripts --- .gitattributes | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/.gitattributes b/.gitattributes index f210b0cb..da10239b 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,7 +1,18 @@ * text=auto *.sh text eol=lf +*.py text eol=lf *.rs text eol=lf *.toml text eol=lf *.json text eol=lf *.md text eol=lf +*.service text eol=lf +*.timer text eol=lf +*.conf text eol=lf *.ps1 text eol=crlf + +build/usb/hooks/* 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-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 685843b95d6f15d0ca42573a8739f848c4ad6ac1 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Tue, 7 Jul 2026 23:19:00 +0700 Subject: [PATCH 52/64] stability normalize runtime publisher LF --- .../usr/lib/rigos/rigos-runtime-publish | 11 ++++++++++- 1 file changed, 10 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 d7bb471c..4ea3da50 100644 --- a/build/usb/includes.chroot/usr/lib/rigos/rigos-runtime-publish +++ b/build/usb/includes.chroot/usr/lib/rigos/rigos-runtime-publish @@ -1,4 +1,5 @@ #!/bin/sh +# Repository contract: LF line endings are required for WSL and appliance execution. set -eu runtime=${RIGOS_RUNTIME_PATH:-/run/rigos} @@ -7,7 +8,13 @@ mkdir -p "$runtime" chmod 0755 "$runtime" stage=$(mktemp -d "$runtime/.render-stage.XXXXXX") chmod 0700 "$stage" +public_tmp= +status_tmp= +config_tmp= cleanup() { + [ -z "$public_tmp" ] || rm -f "$public_tmp" + [ -z "$status_tmp" ] || rm -f "$status_tmp" + [ -z "$config_tmp" ] || rm -f "$config_tmp" rm -rf "$stage" } trap cleanup EXIT HUP INT TERM @@ -29,7 +36,6 @@ profile=$(jq -r '.profile // empty' "$stage/runtime-config-status.json") public_tmp=$(mktemp "$runtime/.xmrig-public.XXXXXX") status_tmp=$(mktemp "$runtime/.runtime-status.XXXXXX") config_tmp=$(mktemp "$runtime/.xmrig-runtime.XXXXXX") -trap 'rm -f "$public_tmp" "$status_tmp" "$config_tmp"; cleanup' EXIT HUP INT TERM jq \ --arg algorithm "$algorithm" \ @@ -94,6 +100,9 @@ sync -f "$config_tmp" sync -f "$public_tmp" sync -f "$status_tmp" mv -f "$config_tmp" "$runtime/xmrig.json" +config_tmp= mv -f "$public_tmp" "$runtime/xmrig-public.json" +public_tmp= mv -f "$status_tmp" "$runtime/runtime-config-status.json" +status_tmp= sync -f "$runtime" From 9c216d883b8f284061e9c5b65df71b5da2f67981 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Tue, 7 Jul 2026 23:19:11 +0700 Subject: [PATCH 53/64] stability normalize runtime authority LF --- build/usb/includes.chroot/usr/lib/rigos/rigos-runtime-authority | 1 + 1 file changed, 1 insertion(+) diff --git a/build/usb/includes.chroot/usr/lib/rigos/rigos-runtime-authority b/build/usb/includes.chroot/usr/lib/rigos/rigos-runtime-authority index 7cd01f5f..aa09747b 100755 --- a/build/usb/includes.chroot/usr/lib/rigos/rigos-runtime-authority +++ b/build/usb/includes.chroot/usr/lib/rigos/rigos-runtime-authority @@ -1,4 +1,5 @@ #!/bin/sh +# Repository contract: LF line endings are required for WSL and appliance execution. set -eu runtime=${RIGOS_RUNTIME_PATH:-/run/rigos} From ebbca7dfd01de82c9bf3aea2481be38a3aac7b52 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Tue, 7 Jul 2026 23:19:23 +0700 Subject: [PATCH 54/64] test LF shell authority contract --- crates/rigos-config/tests/hive_exit_shell_syntax.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/crates/rigos-config/tests/hive_exit_shell_syntax.rs b/crates/rigos-config/tests/hive_exit_shell_syntax.rs index dabea7db..49a4288b 100644 --- a/crates/rigos-config/tests/hive_exit_shell_syntax.rs +++ b/crates/rigos-config/tests/hive_exit_shell_syntax.rs @@ -1,3 +1,4 @@ +use std::fs; use std::path::PathBuf; use std::process::Command; @@ -8,14 +9,20 @@ fn repo_path(path: &str) -> PathBuf { } #[test] -fn runtime_authority_shells_parse_cleanly() { +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", ] { + let full_path = repo_path(path); + let bytes = fs::read(&full_path).unwrap(); + assert!( + !bytes.contains(&b'\r'), + "shell authority contains CR/CRLF line endings: {path}" + ); let status = Command::new("sh") .arg("-n") - .arg(repo_path(path)) + .arg(&full_path) .status() .unwrap(); assert!(status.success(), "shell syntax failed: {path}"); From cc99d8b7aaf3d6fc939a69961a79517e2999d658 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Tue, 7 Jul 2026 23:48:39 +0700 Subject: [PATCH 55/64] use absolute shell path in runtime publication test --- crates/rigos-config/tests/hive_exit_runtime_publish.rs | 2 +- 1 file changed, 1 insertion(+), 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 47f42069..822e6a2a 100644 --- a/crates/rigos-config/tests/hive_exit_runtime_publish.rs +++ b/crates/rigos-config/tests/hive_exit_runtime_publish.rs @@ -98,7 +98,7 @@ fn staged_runtime_publication_is_allowlisted_atomic_and_fail_closed() { "jq is required by runtime publication authority" ); - let result = Command::new("sh") + let result = Command::new("/bin/sh") .arg(&publisher) .env("RIGOS_STATE_PATH", &state) .env("RIGOS_RUNTIME_PATH", &runtime) From 004eaebeef9b55297c38284aad7842fc0277e881 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Tue, 7 Jul 2026 23:48:49 +0700 Subject: [PATCH 56/64] use absolute shell path in syntax test --- crates/rigos-config/tests/hive_exit_shell_syntax.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/rigos-config/tests/hive_exit_shell_syntax.rs b/crates/rigos-config/tests/hive_exit_shell_syntax.rs index 49a4288b..f8087c5e 100644 --- a/crates/rigos-config/tests/hive_exit_shell_syntax.rs +++ b/crates/rigos-config/tests/hive_exit_shell_syntax.rs @@ -20,7 +20,7 @@ fn runtime_authority_shells_are_lf_and_parse_cleanly() { !bytes.contains(&b'\r'), "shell authority contains CR/CRLF line endings: {path}" ); - let status = Command::new("sh") + let status = Command::new("/bin/sh") .arg("-n") .arg(&full_path) .status() From 5ea69b7cb6163d840ccd420768ace591088b23ea Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 00:53:40 +0700 Subject: [PATCH 57/64] include jq 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 85b9c79b..c1477137 100644 --- a/build/usb/package-lists/rigos.list.chroot +++ b/build/usb/package-lists/rigos.list.chroot @@ -3,6 +3,7 @@ curl e2fsprogs fdisk gdisk +jq live-boot live-config linux-image-amd64 From 62e66d16fc6fbca773fff83926c2dbfc1c7f4eb0 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 00:54:02 +0700 Subject: [PATCH 58/64] fail closed on absolute jq runtime --- .../usr/lib/rigos/rigos-runtime-publish | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) 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 4ea3da50..c0aa5740 100644 --- a/build/usb/includes.chroot/usr/lib/rigos/rigos-runtime-publish +++ b/build/usb/includes.chroot/usr/lib/rigos/rigos-runtime-publish @@ -4,6 +4,11 @@ set -eu runtime=${RIGOS_RUNTIME_PATH:-/run/rigos} renderer=${RIGOS_RUNTIME_RENDERER:-/usr/lib/rigos/rigos-runtime-render} +jq_bin=${RIGOS_JQ:-/usr/bin/jq} +if [ ! -x "$jq_bin" ]; then + echo "rigos-runtime-publish: required jq runtime is missing: $jq_bin" >&2 + exit 127 +fi mkdir -p "$runtime" chmod 0755 "$runtime" stage=$(mktemp -d "$runtime/.render-stage.XXXXXX") @@ -21,23 +26,23 @@ trap cleanup EXIT HUP INT TERM RIGOS_RUNTIME_PATH="$stage" "$renderer" -jq -e ' +"$jq_bin" -e ' .schema == "rigos.runtime-config-status/v1" and .outcome == "ready" and (.revision | type == "string") and (.algorithm | type == "string") ' "$stage/runtime-config-status.json" >/dev/null -algorithm=$(jq -r '.algorithm' "$stage/runtime-config-status.json") -revision=$(jq -r '.revision' "$stage/runtime-config-status.json") -thread_count=$(jq -r '.exact_threads // empty' "$stage/runtime-config-status.json") -profile=$(jq -r '.profile // empty' "$stage/runtime-config-status.json") +algorithm=$("$jq_bin" -r '.algorithm' "$stage/runtime-config-status.json") +revision=$("$jq_bin" -r '.revision' "$stage/runtime-config-status.json") +thread_count=$("$jq_bin" -r '.exact_threads // empty' "$stage/runtime-config-status.json") +profile=$("$jq_bin" -r '.profile // empty' "$stage/runtime-config-status.json") public_tmp=$(mktemp "$runtime/.xmrig-public.XXXXXX") status_tmp=$(mktemp "$runtime/.runtime-status.XXXXXX") config_tmp=$(mktemp "$runtime/.xmrig-runtime.XXXXXX") -jq \ +"$jq_bin" \ --arg algorithm "$algorithm" \ --arg revision "$revision" \ --arg profile "$profile" \ @@ -85,7 +90,7 @@ jq \ end ' "$stage/xmrig.json" >"$public_tmp" -jq '. + { +"$jq_bin" '. + { identity_redacted_public_view: true, public_view_construction: "allowlist" }' "$stage/runtime-config-status.json" >"$status_tmp" From b437d029375f4cb01affbb7b2efe3a92350e7eaa Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 00:55:01 +0700 Subject: [PATCH 59/64] verify jq inside appliance squashfs --- scripts/verify-usb-appliance.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/scripts/verify-usb-appliance.sh b/scripts/verify-usb-appliance.sh index 8cf73ebe..6fab56fe 100755 --- a/scripts/verify-usb-appliance.sh +++ b/scripts/verify-usb-appliance.sh @@ -88,7 +88,7 @@ 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/python3 usr/bin/python3.11 \ + usr/bin/jq usr/bin/python3 usr/bin/python3.11 \ 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/local/bin/rigosd usr/local/bin/rigosctl \ @@ -96,6 +96,7 @@ unsquashfs -no-progress -d "$temporary/root" "$temporary/a/live/filesystem.squas 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' 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" @@ -138,6 +139,7 @@ grep -Fq 'ExecCondition=+/usr/lib/rigos/rigos-runtime-authority' "$temporary/roo grep -Fq 'ExecCondition=/usr/lib/rigos/rigos-runtime-gate' "$temporary/root/etc/systemd/system/rigos-miner.service.d/runtime-render.conf" || die 'runtime gate is missing from miner override' grep -Fq 'ExecStart=/usr/lib/rigos/xmrig -c /run/rigos/xmrig.json' "$temporary/root/etc/systemd/system/rigos-miner.service.d/runtime-render.conf" || die 'managed miner does not use the short private runtime config option' grep -Fq 'flock -x -w 30' "$temporary/root/usr/lib/rigos/rigos-runtime-authority" || die 'runtime publication lock is missing' +grep -Fq 'jq_bin=${RIGOS_JQ:-/usr/bin/jq}' "$temporary/root/usr/lib/rigos/rigos-runtime-publish" || die 'runtime publisher does not use the absolute jq dependency' grep -Fq 'construction: "allowlist"' "$temporary/root/usr/lib/rigos/rigos-runtime-publish" || die 'public runtime allowlist marker is missing' grep -Fq '.render-stage.XXXXXX' "$temporary/root/usr/lib/rigos/rigos-runtime-publish" || die 'private runtime staging directory is missing' grep -Fq -- '--xmrig-config /run/rigos/xmrig-public.json' "$temporary/root/usr/local/bin/rigosd" || die 'rigosd does not default to the public runtime view' From 1bfd02a460598f95ee4381a4b9f0510f6257713a Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 00:55:18 +0700 Subject: [PATCH 60/64] test jq appliance dependency contract --- crates/rigos-config/tests/hive_exit_image_verifier.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/crates/rigos-config/tests/hive_exit_image_verifier.rs b/crates/rigos-config/tests/hive_exit_image_verifier.rs index 61794f02..28400005 100644 --- a/crates/rigos-config/tests/hive_exit_image_verifier.rs +++ b/crates/rigos-config/tests/hive_exit_image_verifier.rs @@ -10,8 +10,18 @@ fn repo_path(path: &str) -> PathBuf { #[test] fn image_verifier_requires_runtime_authority_and_stability_bytes() { let verifier = fs::read_to_string(repo_path("scripts/verify-usb-appliance.sh")).unwrap(); + let packages = + fs::read_to_string(repo_path("build/usb/package-lists/rigos.list.chroot")).unwrap(); + + assert!( + packages.lines().any(|line| line.trim() == "jq"), + "appliance package list is missing jq" + ); for required in [ + "usr/bin/jq", + "jq runtime dependency is missing from the appliance", + "jq_bin=${RIGOS_JQ:-/usr/bin/jq}", "usr/lib/rigos/rigos-runtime-publish", "usr/lib/rigos/rigos-runtime-authority", "usr/lib/rigos/rigos-miner-health", From 732164021d450f5ab7986bfa3a1f3307a81b67e8 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 00:56:03 +0700 Subject: [PATCH 61/64] test missing jq fails before publication --- .../tests/hive_exit_runtime_publish.rs | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/crates/rigos-config/tests/hive_exit_runtime_publish.rs b/crates/rigos-config/tests/hive_exit_runtime_publish.rs index 822e6a2a..55462e35 100644 --- a/crates/rigos-config/tests/hive_exit_runtime_publish.rs +++ b/crates/rigos-config/tests/hive_exit_runtime_publish.rs @@ -217,3 +217,31 @@ fn staged_runtime_publication_is_allowlisted_atomic_and_fail_closed() { let _ = fs::remove_dir_all(root); } + +#[test] +fn missing_jq_is_rejected_before_runtime_staging() { + let unique = SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap() + .as_nanos(); + let root = std::env::temp_dir().join(format!("rigos-runtime-missing-jq-{unique}")); + let runtime = root.join("run"); + fs::create_dir_all(&runtime).unwrap(); + + let publisher = repo_path("build/usb/includes.chroot/usr/lib/rigos/rigos-runtime-publish"); + let missing_jq = root.join("missing-jq"); + let output = Command::new("/bin/sh") + .arg(&publisher) + .env("RIGOS_RUNTIME_PATH", &runtime) + .env("RIGOS_JQ", &missing_jq) + .output() + .unwrap(); + + assert_eq!(output.status.code(), Some(127)); + let stderr = String::from_utf8(output.stderr).unwrap(); + assert!(stderr.contains("required jq runtime is missing")); + assert!(stderr.contains(missing_jq.to_str().unwrap())); + assert_eq!(fs::read_dir(&runtime).unwrap().count(), 0); + + let _ = fs::remove_dir_all(root); +} From e86c2a5cbfff3d8ab51e4b686518e98c46e1c289 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 01:01:45 +0700 Subject: [PATCH 62/64] normalize appliance package list bytes --- 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 c1477137..fc7df3aa 100644 --- a/build/usb/package-lists/rigos.list.chroot +++ b/build/usb/package-lists/rigos.list.chroot @@ -1,3 +1,4 @@ +# Runtime dependencies required by boot-time RIGOS authorities. ca-certificates curl e2fsprogs From 11471b95e367adca74c915235b65ecfb8ee7f7e8 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 01:02:08 +0700 Subject: [PATCH 63/64] test package list LF contract --- crates/rigos-config/tests/hive_exit_image_verifier.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/crates/rigos-config/tests/hive_exit_image_verifier.rs b/crates/rigos-config/tests/hive_exit_image_verifier.rs index 28400005..309650ba 100644 --- a/crates/rigos-config/tests/hive_exit_image_verifier.rs +++ b/crates/rigos-config/tests/hive_exit_image_verifier.rs @@ -10,8 +10,13 @@ fn repo_path(path: &str) -> PathBuf { #[test] fn image_verifier_requires_runtime_authority_and_stability_bytes() { let verifier = fs::read_to_string(repo_path("scripts/verify-usb-appliance.sh")).unwrap(); - let packages = - fs::read_to_string(repo_path("build/usb/package-lists/rigos.list.chroot")).unwrap(); + let package_path = repo_path("build/usb/package-lists/rigos.list.chroot"); + let package_bytes = fs::read(&package_path).unwrap(); + assert!( + !package_bytes.contains(&b'\r'), + "appliance package list contains CR/CRLF line endings" + ); + let packages = String::from_utf8(package_bytes).unwrap(); assert!( packages.lines().any(|line| line.trim() == "jq"), From 223794509e82d5dedda79da87a11ed2941c16c34 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Wed, 8 Jul 2026 01:03:19 +0700 Subject: [PATCH 64/64] enforce LF for RIGOS package manifest --- .gitattributes | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitattributes b/.gitattributes index da10239b..b2ec61b1 100644 --- a/.gitattributes +++ b/.gitattributes @@ -11,6 +11,7 @@ *.ps1 text eol=crlf 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-runtime-* text eol=lf