From 713ce162304c24befec96f765dfe5eaabf8a5e67 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Thu, 9 Jul 2026 06:49:58 +0700 Subject: [PATCH 01/25] Add 2009-style firstboot whiptail wrapper --- .../usr/lib/rigos/rigos-firstboot-whiptail | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 build/usb/includes.chroot/usr/lib/rigos/rigos-firstboot-whiptail diff --git a/build/usb/includes.chroot/usr/lib/rigos/rigos-firstboot-whiptail b/build/usb/includes.chroot/usr/lib/rigos/rigos-firstboot-whiptail new file mode 100644 index 00000000..933cea07 --- /dev/null +++ b/build/usb/includes.chroot/usr/lib/rigos/rigos-firstboot-whiptail @@ -0,0 +1,29 @@ +#!/bin/sh +# RIGOS firstboot presentation wrapper. +# Keeps the configuration engine and dialog return-code contract unchanged. +set -eu + +TERM=${TERM:-linux} +export TERM + +NEWT_COLORS=${NEWT_COLORS:-'root=white,blue:border=blue,lightgray:window=black,lightgray:shadow=black,black:title=white,blue:button=black,lightgray:actbutton=white,blue:compactbutton=black,lightgray:checkbox=black,lightgray:actcheckbox=white,blue:entry=black,white:disentry=gray,lightgray:label=black,lightgray:listbox=black,lightgray:actlistbox=white,blue:sellistbox=black,cyan:actsellistbox=white,blue:textbox=black,lightgray:acttextbox=white,blue:helpline=white,blue:roottext=white,blue'} +export NEWT_COLORS + +backtitle=${RIGOS_FIRSTBOOT_BACKTITLE:-'RIGOS SYSTEM CONFIGURATION // LOCAL NODE SETUP // OFFLINE AUTHORITY'} + +case " $* " in + *' --menu '*) + set -- --ok-button SELECT --cancel-button BACK "$@" + ;; + *' --yesno '*) + set -- --yes-button APPLY --no-button BACK "$@" + ;; + *' --inputbox '*|*' --passwordbox '*) + set -- --ok-button NEXT --cancel-button BACK "$@" + ;; + *' --msgbox '*) + set -- --ok-button CONTINUE "$@" + ;; +esac + +exec /usr/bin/whiptail --backtitle "$backtitle" "$@" From 13220fc98a38e30fc0b3d8e0f62d339d39fdd600 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Thu, 9 Jul 2026 06:50:06 +0700 Subject: [PATCH 02/25] Wire firstboot console theme --- .../system/rigos-firstboot.service.d/2009-console-theme.conf | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 build/usb/includes.chroot/etc/systemd/system/rigos-firstboot.service.d/2009-console-theme.conf diff --git a/build/usb/includes.chroot/etc/systemd/system/rigos-firstboot.service.d/2009-console-theme.conf b/build/usb/includes.chroot/etc/systemd/system/rigos-firstboot.service.d/2009-console-theme.conf new file mode 100644 index 00000000..7c5a3fc4 --- /dev/null +++ b/build/usb/includes.chroot/etc/systemd/system/rigos-firstboot.service.d/2009-console-theme.conf @@ -0,0 +1,3 @@ +[Service] +Environment=RIGOS_WHIPTAIL=/usr/lib/rigos/rigos-firstboot-whiptail +Environment="RIGOS_FIRSTBOOT_BACKTITLE=RIGOS SYSTEM CONFIGURATION // LOCAL NODE SETUP // OFFLINE AUTHORITY" From bf9890c8111fc7eda8d75205b4783e0a527ee152 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Thu, 9 Jul 2026 06:50:17 +0700 Subject: [PATCH 03/25] Install firstboot theme wrapper as executable --- 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 acc1d24b..e944fc5a 100644 --- a/build/usb/hooks/010-rigos.chroot +++ b/build/usb/hooks/010-rigos.chroot @@ -9,7 +9,7 @@ install -d -m 0755 /usr/lib/rigos /usr/local/bin systemd-tmpfiles --create /usr/lib/tmpfiles.d/rigos.conf rm -f /etc/ssh/ssh_host_*_key /etc/ssh/ssh_host_*_key.pub -chmod 0755 /usr/local/bin/rigosd /usr/local/bin/rigosctl /usr/local/sbin/rigos-firstboot /usr/local/sbin/rigos-recovery-access /usr/local/sbin/rigos-state-orchestrate /usr/lib/rigos/rigos-miner-gate /usr/lib/rigos/rigos-miner-health /usr/lib/rigos/rigos-runtime-render /usr/lib/rigos/rigos-runtime-publish /usr/lib/rigos/rigos-runtime-gate /usr/lib/rigos/rigos-randomx-msr /usr/lib/rigos/rigos-ssh-hostkeys /usr/lib/rigos/rigos-state-init /usr/lib/rigos/rigos-state-ready /usr/lib/rigos/rigos-config /usr/lib/rigos/rigos-performance /usr/lib/rigos/rigos-lifecycle-cycles /usr/lib/rigos/rigos-identity-seed /usr/lib/rigos/xmrig +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-firstboot-whiptail /usr/lib/rigos/rigos-miner-gate /usr/lib/rigos/rigos-miner-health /usr/lib/rigos/rigos-runtime-render /usr/lib/rigos/rigos-runtime-publish /usr/lib/rigos/rigos-runtime-gate /usr/lib/rigos/rigos-randomx-msr /usr/lib/rigos/rigos-ssh-hostkeys /usr/lib/rigos/rigos-state-init /usr/lib/rigos/rigos-state-ready /usr/lib/rigos/rigos-config /usr/lib/rigos/rigos-performance /usr/lib/rigos/rigos-lifecycle-cycles /usr/lib/rigos/rigos-identity-seed /usr/lib/rigos/xmrig systemctl enable NetworkManager.service ssh.service rigos-state.service rigos-recovery-access.service rigos-state-ready.service rigos-ssh-hostkeys.service rigos-profile-apply.service rigos-runtime-render.service rigos-hugepages.service rigos-firstboot.service rigos-randomx-msr.service rigos-miner.service rigos-miner-health.timer tmp.mount systemctl disable ssh.socket 2>/dev/null || true systemctl disable apt-daily.timer apt-daily-upgrade.timer logrotate.timer fstrim.timer 2>/dev/null || true From 44a8b68a3a52201aef5c03487f2dc3d320c46042 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Thu, 9 Jul 2026 06:50:28 +0700 Subject: [PATCH 04/25] Add firstboot console theme wiring tests --- crates/rigos-config/tests/firstboot_theme.rs | 62 ++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 crates/rigos-config/tests/firstboot_theme.rs diff --git a/crates/rigos-config/tests/firstboot_theme.rs b/crates/rigos-config/tests/firstboot_theme.rs new file mode 100644 index 00000000..c2f82da9 --- /dev/null +++ b/crates/rigos-config/tests/firstboot_theme.rs @@ -0,0 +1,62 @@ +use std::fs; +use std::path::PathBuf; + +fn repo_file(path: &str) -> String { + let path = PathBuf::from(env!("CARGO_MANIFEST_DIR")) + .join("../..") + .join(path); + fs::read_to_string(&path) + .unwrap_or_else(|error| panic!("failed to read {}: {error}", path.display())) +} + +#[test] +fn firstboot_uses_the_dedicated_console_theme_wrapper() { + let drop_in = repo_file( + "build/usb/includes.chroot/etc/systemd/system/rigos-firstboot.service.d/2009-console-theme.conf", + ); + + assert!( + drop_in.contains( + "Environment=RIGOS_WHIPTAIL=/usr/lib/rigos/rigos-firstboot-whiptail" + ), + "firstboot must select the dedicated presentation wrapper" + ); + assert!( + drop_in.contains("RIGOS SYSTEM CONFIGURATION // LOCAL NODE SETUP // OFFLINE AUTHORITY"), + "firstboot must publish the static non-secret backtitle" + ); +} + +#[test] +fn firstboot_theme_is_ascii_and_preserves_whiptail_as_the_ui_engine() { + let wrapper = repo_file( + "build/usb/includes.chroot/usr/lib/rigos/rigos-firstboot-whiptail", + ); + + assert!(wrapper.is_ascii(), "console theme must remain ASCII-only"); + assert!(wrapper.contains("NEWT_COLORS=")); + assert!(wrapper.contains("root=white,blue")); + assert!(wrapper.contains("window=black,lightgray")); + assert!(wrapper.contains("actlistbox=white,blue")); + assert!(wrapper.contains("--backtitle")); + assert!(wrapper.contains("--ok-button SELECT --cancel-button BACK")); + assert!(wrapper.contains("--yes-button APPLY --no-button BACK")); + assert!(wrapper.contains("exec /usr/bin/whiptail")); + assert!( + !wrapper.contains("xterm") + && !wrapper.contains("Xorg") + && !wrapper.contains("wayland") + && !wrapper.contains("electron"), + "theme must not introduce a graphical runtime" + ); +} + +#[test] +fn image_hook_installs_the_theme_wrapper_as_executable() { + let hook = repo_file("build/usb/hooks/010-rigos.chroot"); + + assert!( + hook.contains("/usr/lib/rigos/rigos-firstboot-whiptail"), + "image construction must install the wrapper as executable" + ); +} From 7030f3ba8586e4fe3b7c54ac81182431049b49db Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Thu, 9 Jul 2026 07:08:07 +0700 Subject: [PATCH 05/25] Harden firstboot theme backend execution --- .../usr/lib/rigos/rigos-firstboot-whiptail | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/build/usb/includes.chroot/usr/lib/rigos/rigos-firstboot-whiptail b/build/usb/includes.chroot/usr/lib/rigos/rigos-firstboot-whiptail index 933cea07..529fa7d2 100644 --- a/build/usb/includes.chroot/usr/lib/rigos/rigos-firstboot-whiptail +++ b/build/usb/includes.chroot/usr/lib/rigos/rigos-firstboot-whiptail @@ -10,6 +10,12 @@ NEWT_COLORS=${NEWT_COLORS:-'root=white,blue:border=blue,lightgray:window=black,l export NEWT_COLORS backtitle=${RIGOS_FIRSTBOOT_BACKTITLE:-'RIGOS SYSTEM CONFIGURATION // LOCAL NODE SETUP // OFFLINE AUTHORITY'} +whiptail_real=${RIGOS_WHIPTAIL_REAL:-/usr/bin/whiptail} + +if [ ! -x "$whiptail_real" ]; then + echo "rigos-firstboot-whiptail: backend is not executable: $whiptail_real" >&2 + exit 127 +fi case " $* " in *' --menu '*) @@ -26,4 +32,4 @@ case " $* " in ;; esac -exec /usr/bin/whiptail --backtitle "$backtitle" "$@" +exec "$whiptail_real" --backtitle "$backtitle" "$@" From 47f10f21518b19e6178968cc02618cbda47d4e9b Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Thu, 9 Jul 2026 07:08:24 +0700 Subject: [PATCH 06/25] Update theme tests for backend hardening --- crates/rigos-config/tests/firstboot_theme.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/crates/rigos-config/tests/firstboot_theme.rs b/crates/rigos-config/tests/firstboot_theme.rs index c2f82da9..a4a7d952 100644 --- a/crates/rigos-config/tests/firstboot_theme.rs +++ b/crates/rigos-config/tests/firstboot_theme.rs @@ -41,7 +41,9 @@ fn firstboot_theme_is_ascii_and_preserves_whiptail_as_the_ui_engine() { assert!(wrapper.contains("--backtitle")); assert!(wrapper.contains("--ok-button SELECT --cancel-button BACK")); assert!(wrapper.contains("--yes-button APPLY --no-button BACK")); - assert!(wrapper.contains("exec /usr/bin/whiptail")); + assert!(wrapper.contains("RIGOS_WHIPTAIL_REAL:-/usr/bin/whiptail")); + assert!(wrapper.contains("exec \"$whiptail_real\"")); + assert!(wrapper.contains("backend is not executable")); assert!( !wrapper.contains("xterm") && !wrapper.contains("Xorg") From b98e9e5b8b680149e1fd2050b352b25dcee97d90 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Thu, 9 Jul 2026 07:08:56 +0700 Subject: [PATCH 07/25] Add behavioral firstboot theme wrapper test --- crates/rigos-config/tests/firstboot_theme.rs | 91 +++++++++++++++++++- 1 file changed, 88 insertions(+), 3 deletions(-) diff --git a/crates/rigos-config/tests/firstboot_theme.rs b/crates/rigos-config/tests/firstboot_theme.rs index a4a7d952..03d44ab5 100644 --- a/crates/rigos-config/tests/firstboot_theme.rs +++ b/crates/rigos-config/tests/firstboot_theme.rs @@ -1,10 +1,14 @@ use std::fs; use std::path::PathBuf; -fn repo_file(path: &str) -> String { - let path = PathBuf::from(env!("CARGO_MANIFEST_DIR")) +fn repo_path(path: &str) -> PathBuf { + PathBuf::from(env!("CARGO_MANIFEST_DIR")) .join("../..") - .join(path); + .join(path) +} + +fn repo_file(path: &str) -> String { + let path = repo_path(path); fs::read_to_string(&path) .unwrap_or_else(|error| panic!("failed to read {}: {error}", path.display())) } @@ -62,3 +66,84 @@ fn image_hook_installs_the_theme_wrapper_as_executable() { "image construction must install the wrapper as executable" ); } + +#[cfg(unix)] +#[test] +fn firstboot_theme_wrapper_maps_buttons_and_preserves_exit_status() { + use std::os::unix::fs::PermissionsExt; + use std::process::Command; + use std::time::{SystemTime, UNIX_EPOCH}; + + let nonce = SystemTime::now() + .duration_since(UNIX_EPOCH) + .expect("system clock is before Unix epoch") + .as_nanos(); + let temporary = std::env::temp_dir().join(format!( + "rigos-firstboot-theme-{}-{nonce}", + std::process::id() + )); + fs::create_dir_all(&temporary).expect("failed to create theme test directory"); + + let backend = temporary.join("fake-whiptail"); + let capture = temporary.join("arguments.txt"); + fs::write( + &backend, + "#!/bin/sh\nprintf '%s\\n' \"$@\" >\"$RIGOS_THEME_CAPTURE\"\nexit \"${RIGOS_THEME_EXIT:-0}\"\n", + ) + .expect("failed to write fake whiptail backend"); + let mut permissions = fs::metadata(&backend) + .expect("failed to stat fake whiptail backend") + .permissions(); + permissions.set_mode(0o755); + fs::set_permissions(&backend, permissions) + .expect("failed to make fake whiptail backend executable"); + + let wrapper = repo_path( + "build/usb/includes.chroot/usr/lib/rigos/rigos-firstboot-whiptail", + ); + let status = Command::new("sh") + .arg(&wrapper) + .args([ + "--title", + "RIGOS FIRST BOOT", + "--menu", + "Select Flight Sheet", + "20", + "76", + "2", + "manual", + "Configure manually", + "none", + "Leave mining unconfigured", + ]) + .env("RIGOS_WHIPTAIL_REAL", &backend) + .env("RIGOS_THEME_CAPTURE", &capture) + .env("RIGOS_THEME_EXIT", "7") + .env("RIGOS_FIRSTBOOT_BACKTITLE", "TEST BACKTITLE") + .status() + .expect("failed to execute firstboot theme wrapper"); + + assert_eq!(status.code(), Some(7), "wrapper must preserve backend exit status"); + + let arguments = fs::read_to_string(&capture) + .expect("fake whiptail backend did not capture arguments"); + let arguments: Vec<_> = arguments.lines().collect(); + assert_eq!( + &arguments[..8], + [ + "--backtitle", + "TEST BACKTITLE", + "--ok-button", + "SELECT", + "--cancel-button", + "BACK", + "--title", + "RIGOS FIRST BOOT", + ] + ); + assert!(arguments.windows(2).any(|pair| pair == ["--menu", "Select Flight Sheet"])); + assert!(arguments.windows(2).any(|pair| pair == ["manual", "Configure manually"])); + assert!(arguments.windows(2).any(|pair| pair == ["none", "Leave mining unconfigured"])); + + fs::remove_dir_all(&temporary).expect("failed to clean theme test directory"); +} From 2dc0b51160fe0b7ad0e5e45bd9f39d7a63b542ae Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Thu, 9 Jul 2026 07:09:05 +0700 Subject: [PATCH 08/25] Add local firstboot theme preview harness --- scripts/preview-firstboot-theme.sh | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 scripts/preview-firstboot-theme.sh diff --git a/scripts/preview-firstboot-theme.sh b/scripts/preview-firstboot-theme.sh new file mode 100644 index 00000000..5ab24c67 --- /dev/null +++ b/scripts/preview-firstboot-theme.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash +set -euo pipefail + +root=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd) +wrapper="$root/build/usb/includes.chroot/usr/lib/rigos/rigos-firstboot-whiptail" + +if [[ ! -f "$wrapper" ]]; then + echo "preview-firstboot-theme: wrapper is missing: $wrapper" >&2 + exit 1 +fi + +if [[ ! -x /usr/bin/whiptail ]]; then + echo "preview-firstboot-theme: /usr/bin/whiptail is not installed" >&2 + exit 127 +fi + +RIGOS_WHIPTAIL_REAL=/usr/bin/whiptail \ +RIGOS_FIRSTBOOT_BACKTITLE='RIGOS SYSTEM CONFIGURATION // LOCAL NODE SETUP // OFFLINE AUTHORITY' \ +sh "$wrapper" \ + --title 'RIGOS FIRST BOOT' \ + --menu $'SELECT FLIGHT SHEET\n\nChoose a local mining configuration source.\n[UP/DOWN] MOVE [ENTER] SELECT [ESC] BACK' \ + 20 76 6 \ + manual 'Configure this node manually' \ + none 'Leave mining unconfigured' \ + native:xmr 'Use native XMR flight sheet' \ + import:legacy 'Import an external flight sheet' From 3b868af7bc102cb2e214dc954767e241b2fd335a Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Thu, 9 Jul 2026 14:24:37 +0700 Subject: [PATCH 09/25] Add authoritative Linux source gate workflow --- .github/workflows/source-gate.yml | 60 +++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 .github/workflows/source-gate.yml diff --git a/.github/workflows/source-gate.yml b/.github/workflows/source-gate.yml new file mode 100644 index 00000000..98293b3a --- /dev/null +++ b/.github/workflows/source-gate.yml @@ -0,0 +1,60 @@ +name: RIGOS Source Gate + +on: + pull_request: + branches: + - performance/randomx-sustained-hash + - stability/hive-exit-gates + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: source-gate-${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +jobs: + verify: + name: Authoritative Linux source verification + runs-on: ubuntu-24.04 + timeout-minutes: 45 + + steps: + - name: Check out exact pull-request head + uses: actions/checkout@v4 + with: + persist-credentials: false + + - name: Install required host tools + run: | + set -euo pipefail + sudo apt-get update + sudo apt-get install --yes --no-install-recommends ripgrep + + - name: Install locked Rust toolchain + run: | + set -euo pipefail + rustup toolchain install 1.85.1 \ + --profile minimal \ + --component rustfmt \ + --component clippy + rustup override set 1.85.1 + rustc --version + cargo --version + cargo fmt --version + cargo clippy --version + + - name: Run authoritative RIGOS source gate + env: + CARGO_TERM_COLOR: always + run: | + set -euo pipefail + bash ./scripts/verify-wsl-entrypoint.sh "$GITHUB_WORKSPACE" + + - name: Record exact verified revision + if: always() + run: | + set -euo pipefail + printf 'RIGOS_VERIFIED_HEAD=%s\n' "$(git rev-parse HEAD)" + git status --short From 6bc5f6093f8247a3f7f06658acd92e137b4a3351 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Thu, 9 Jul 2026 14:25:43 +0700 Subject: [PATCH 10/25] Expand firstboot theme preview modes --- scripts/preview-firstboot-theme.sh | 84 ++++++++++++++++++++++++++---- 1 file changed, 74 insertions(+), 10 deletions(-) diff --git a/scripts/preview-firstboot-theme.sh b/scripts/preview-firstboot-theme.sh index 5ab24c67..255a3c6c 100644 --- a/scripts/preview-firstboot-theme.sh +++ b/scripts/preview-firstboot-theme.sh @@ -3,6 +3,7 @@ set -euo pipefail root=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd) wrapper="$root/build/usb/includes.chroot/usr/lib/rigos/rigos-firstboot-whiptail" +mode=${1:-menu} if [[ ! -f "$wrapper" ]]; then echo "preview-firstboot-theme: wrapper is missing: $wrapper" >&2 @@ -14,13 +15,76 @@ if [[ ! -x /usr/bin/whiptail ]]; then exit 127 fi -RIGOS_WHIPTAIL_REAL=/usr/bin/whiptail \ -RIGOS_FIRSTBOOT_BACKTITLE='RIGOS SYSTEM CONFIGURATION // LOCAL NODE SETUP // OFFLINE AUTHORITY' \ -sh "$wrapper" \ - --title 'RIGOS FIRST BOOT' \ - --menu $'SELECT FLIGHT SHEET\n\nChoose a local mining configuration source.\n[UP/DOWN] MOVE [ENTER] SELECT [ESC] BACK' \ - 20 76 6 \ - manual 'Configure this node manually' \ - none 'Leave mining unconfigured' \ - native:xmr 'Use native XMR flight sheet' \ - import:legacy 'Import an external flight sheet' +run_theme() { + set +e + RIGOS_WHIPTAIL_REAL=/usr/bin/whiptail \ + RIGOS_FIRSTBOOT_BACKTITLE='RIGOS SYSTEM CONFIGURATION // LOCAL NODE SETUP // OFFLINE AUTHORITY' \ + sh "$wrapper" "$@" + status=$? + set -e + printf 'RIGOS_THEME_PREVIEW_EXIT=%s\n' "$status" +} + +preview_menu() { + run_theme \ + --title 'RIGOS FIRST BOOT // FLIGHT CONTROL' \ + --menu $'SELECT FLIGHT SHEET\n\nChoose the local mining authority for this node.\n\n[UP/DOWN] MOVE [ENTER] SELECT [ESC] BACK' \ + 20 76 6 \ + manual 'Configure this node manually' \ + none 'Leave mining unconfigured' \ + native:xmr 'Use native XMR flight sheet' \ + import:legacy 'Import an external flight sheet' +} + +preview_confirm() { + run_theme \ + --title 'RIGOS FIRST BOOT // COMMIT AUTHORITY' \ + --yesno $'CONFIGURATION SUMMARY\n\nNode rig01\nFlight Sheet xmr\nAlgorithm rx/0\nThreads exact 2\nHuge Pages enabled\nStart Policy on boot\n\nApply this configuration to local persistent state?' \ + 20 76 +} + +preview_input() { + run_theme \ + --title 'RIGOS FIRST BOOT // NODE IDENTITY' \ + --inputbox $'NODE NAME\n\nEnter the local appliance name.\nAllowed: A-Z, a-z, 0-9 and hyphen.' \ + 14 72 'rig01' +} + +preview_message() { + run_theme \ + --title 'RIGOS FIRST BOOT // SYSTEM READY' \ + --msgbox $'CONFIGURATION COMMITTED\n\nPersistent state verified.\nRuntime config published.\nMiner activation requested.\n\nThe local console will now return to the system.' \ + 16 72 +} + +case "$mode" in + menu) + preview_menu + ;; + confirm) + preview_confirm + ;; + input) + preview_input + ;; + message) + preview_message + ;; + all) + preview_menu + preview_input + preview_confirm + preview_message + ;; + -h|--help) + cat <<'EOF' +usage: scripts/preview-firstboot-theme.sh [menu|input|confirm|message|all] + +Displays the RIGOS firstboot theme without reading or changing persistent state. +EOF + ;; + *) + echo "preview-firstboot-theme: unknown mode: $mode" >&2 + exit 64 + ;; +esac From 1752ab00d10c34e9308e3611b8647c14b2346f71 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Thu, 9 Jul 2026 14:26:05 +0700 Subject: [PATCH 11/25] Add read-only firstboot theme preview contracts --- .../tests/firstboot_theme_preview.rs | 60 +++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 crates/rigos-config/tests/firstboot_theme_preview.rs diff --git a/crates/rigos-config/tests/firstboot_theme_preview.rs b/crates/rigos-config/tests/firstboot_theme_preview.rs new file mode 100644 index 00000000..4180d74e --- /dev/null +++ b/crates/rigos-config/tests/firstboot_theme_preview.rs @@ -0,0 +1,60 @@ +use std::fs; +use std::path::PathBuf; + +fn preview_script() -> String { + let path = PathBuf::from(env!("CARGO_MANIFEST_DIR")) + .join("../..") + .join("scripts/preview-firstboot-theme.sh"); + fs::read_to_string(&path) + .unwrap_or_else(|error| panic!("failed to read {}: {error}", path.display())) +} + +#[test] +fn preview_covers_every_firstboot_dialog_class() { + let script = preview_script(); + + for required in [ + "preview_menu", + "preview_input", + "preview_confirm", + "preview_message", + "menu|input|confirm|message|all", + ] { + assert!( + script.contains(required), + "preview harness is missing required mode marker: {required}" + ); + } + + for required in ["--menu", "--inputbox", "--yesno", "--msgbox"] { + assert!( + script.contains(required), + "preview harness is missing dialog class: {required}" + ); + } +} + +#[test] +fn preview_is_read_only_and_does_not_touch_appliance_state() { + let script = preview_script(); + + for forbidden in [ + "/var/lib/rigos", + "systemctl", + "rigos-config", + "rigos-miner", + "rigos-randomx-msr", + "mount ", + "umount ", + "rm -rf", + "sudo ", + ] { + assert!( + !script.contains(forbidden), + "preview harness contains forbidden mutation surface: {forbidden}" + ); + } + + assert!(script.contains("RIGOS_WHIPTAIL_REAL=/usr/bin/whiptail")); + assert!(script.contains("RIGOS_THEME_PREVIEW_EXIT=")); +} From 490d1391bbd1d209194ddcd70d8984755012f23e Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Thu, 9 Jul 2026 14:26:20 +0700 Subject: [PATCH 12/25] Document firstboot console theme contract --- docs/developer/firstboot-theme.txt | 93 ++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 docs/developer/firstboot-theme.txt diff --git a/docs/developer/firstboot-theme.txt b/docs/developer/firstboot-theme.txt new file mode 100644 index 00000000..bae5b633 --- /dev/null +++ b/docs/developer/firstboot-theme.txt @@ -0,0 +1,93 @@ +RIGOS FIRSTBOOT CONSOLE THEME +============================= + +PURPOSE +------- + +Give the local first-boot selector the look of a late-2000s or early-2010s +firmware utility without adding a graphical desktop, browser, display server, +or background daemon. + +The theme is presentation only. Configuration, identity, persistent state, +miner, MSR, SSH, runtime publication, and activation behavior stay unchanged. + +VISUAL CONTRACT +--------------- + +Root background deep blue +Dialog window light gray / silver +Window border blue +Active row white on blue +Input field black on white +Shadow black +Backtitle static ASCII, no private values +Buttons SELECT BACK NEXT APPLY CONTINUE + +The source remains ASCII-only so it renders on the Linux console without a +Unicode-font dependency. + +ARCHITECTURE +------------ + +Firstboot still executes the Python workflow at: + + /usr/local/sbin/rigos-firstboot + +The service sets RIGOS_WHIPTAIL to: + + /usr/lib/rigos/rigos-firstboot-whiptail + +The wrapper exports NEWT_COLORS, adds a static backtitle, maps button labels, +and execs the existing /usr/bin/whiptail backend. Backend exit status and +selected values retain the original whiptail contract. + +PREVIEW +------- + +Run from a Linux or WSL checkout with whiptail installed: + + bash scripts/preview-firstboot-theme.sh menu + bash scripts/preview-firstboot-theme.sh input + bash scripts/preview-firstboot-theme.sh confirm + bash scripts/preview-firstboot-theme.sh message + bash scripts/preview-firstboot-theme.sh all + +The preview harness does not read or modify /var/lib/rigos and does not call +systemctl, the configuration engine, miner services, or MSR authority. + +VERIFICATION +------------ + +Targeted tests: + + cargo test --locked -p rigos-config --test firstboot_theme + cargo test --locked -p rigos-config --test firstboot_theme_preview + +Authoritative Linux source gate: + + bash scripts/verify-wsl-entrypoint.sh "$PWD" + +A PASS may only be claimed for the exact Git head printed by the gate. + +BRANCH BOUNDARY +--------------- + +UI work belongs on: + + ui/firstboot-2009-theme + +It is stacked on performance/randomx-sustained-hash only for review. Do not +merge it into PR #15 while the physical performance and endurance evidence is +still tied to the exact performance head. + +NON-GOALS +--------- + +No X11. +No Wayland. +No Electron. +No browser UI. +No framebuffer daemon. +No persistent-state format change. +No miner behavior change. +No image-release claim before source and image verification pass. From 777b48e29602f2bba56164a9ceab1455a0be5a95 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Thu, 9 Jul 2026 14:38:55 +0700 Subject: [PATCH 13/25] Enforce LF for firstboot runtime scripts --- .gitattributes | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitattributes b/.gitattributes index 3b002266..b7852997 100644 --- a/.gitattributes +++ b/.gitattributes @@ -15,6 +15,7 @@ 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-firstboot-* text eol=lf build/usb/includes.chroot/usr/lib/rigos/rigos-randomx-msr text eol=lf build/usb/includes.chroot/usr/lib/rigos/rigos-runtime-* text eol=lf build/usb/includes.chroot/usr/lib/rigos/rigos-miner-* text eol=lf From 6394d1ae39c15baa49f95b50ab8d2c0f7c186282 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Thu, 9 Jul 2026 14:40:20 +0700 Subject: [PATCH 14/25] Format firstboot theme tests --- crates/rigos-config/tests/firstboot_theme.rs | 40 ++++++++++++-------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/crates/rigos-config/tests/firstboot_theme.rs b/crates/rigos-config/tests/firstboot_theme.rs index 03d44ab5..e2c4b73f 100644 --- a/crates/rigos-config/tests/firstboot_theme.rs +++ b/crates/rigos-config/tests/firstboot_theme.rs @@ -20,9 +20,7 @@ fn firstboot_uses_the_dedicated_console_theme_wrapper() { ); assert!( - drop_in.contains( - "Environment=RIGOS_WHIPTAIL=/usr/lib/rigos/rigos-firstboot-whiptail" - ), + drop_in.contains("Environment=RIGOS_WHIPTAIL=/usr/lib/rigos/rigos-firstboot-whiptail"), "firstboot must select the dedicated presentation wrapper" ); assert!( @@ -33,9 +31,7 @@ fn firstboot_uses_the_dedicated_console_theme_wrapper() { #[test] fn firstboot_theme_is_ascii_and_preserves_whiptail_as_the_ui_engine() { - let wrapper = repo_file( - "build/usb/includes.chroot/usr/lib/rigos/rigos-firstboot-whiptail", - ); + let wrapper = repo_file("build/usb/includes.chroot/usr/lib/rigos/rigos-firstboot-whiptail"); assert!(wrapper.is_ascii(), "console theme must remain ASCII-only"); assert!(wrapper.contains("NEWT_COLORS=")); @@ -98,9 +94,7 @@ fn firstboot_theme_wrapper_maps_buttons_and_preserves_exit_status() { fs::set_permissions(&backend, permissions) .expect("failed to make fake whiptail backend executable"); - let wrapper = repo_path( - "build/usb/includes.chroot/usr/lib/rigos/rigos-firstboot-whiptail", - ); + let wrapper = repo_path("build/usb/includes.chroot/usr/lib/rigos/rigos-firstboot-whiptail"); let status = Command::new("sh") .arg(&wrapper) .args([ @@ -123,10 +117,14 @@ fn firstboot_theme_wrapper_maps_buttons_and_preserves_exit_status() { .status() .expect("failed to execute firstboot theme wrapper"); - assert_eq!(status.code(), Some(7), "wrapper must preserve backend exit status"); + assert_eq!( + status.code(), + Some(7), + "wrapper must preserve backend exit status" + ); - let arguments = fs::read_to_string(&capture) - .expect("fake whiptail backend did not capture arguments"); + let arguments = + fs::read_to_string(&capture).expect("fake whiptail backend did not capture arguments"); let arguments: Vec<_> = arguments.lines().collect(); assert_eq!( &arguments[..8], @@ -141,9 +139,21 @@ fn firstboot_theme_wrapper_maps_buttons_and_preserves_exit_status() { "RIGOS FIRST BOOT", ] ); - assert!(arguments.windows(2).any(|pair| pair == ["--menu", "Select Flight Sheet"])); - assert!(arguments.windows(2).any(|pair| pair == ["manual", "Configure manually"])); - assert!(arguments.windows(2).any(|pair| pair == ["none", "Leave mining unconfigured"])); + assert!( + arguments + .windows(2) + .any(|pair| pair == ["--menu", "Select Flight Sheet"]) + ); + assert!( + arguments + .windows(2) + .any(|pair| pair == ["manual", "Configure manually"]) + ); + assert!( + arguments + .windows(2) + .any(|pair| pair == ["none", "Leave mining unconfigured"]) + ); fs::remove_dir_all(&temporary).expect("failed to clean theme test directory"); } From 5359482a8f5c54d5338b68bb632b85516b96bdfd Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Thu, 9 Jul 2026 14:40:53 +0700 Subject: [PATCH 15/25] Lock firstboot wrapper LF contract in tests --- crates/rigos-config/tests/firstboot_theme.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/crates/rigos-config/tests/firstboot_theme.rs b/crates/rigos-config/tests/firstboot_theme.rs index e2c4b73f..d2fc7084 100644 --- a/crates/rigos-config/tests/firstboot_theme.rs +++ b/crates/rigos-config/tests/firstboot_theme.rs @@ -29,6 +29,18 @@ fn firstboot_uses_the_dedicated_console_theme_wrapper() { ); } +#[test] +fn firstboot_wrapper_is_pinned_to_lf_in_git() { + let attributes = repo_file(".gitattributes"); + + assert!( + attributes + .lines() + .any(|line| line == "build/usb/includes.chroot/usr/lib/rigos/rigos-firstboot-* text eol=lf"), + "firstboot runtime wrappers must remain LF on Windows and WSL checkouts" + ); +} + #[test] fn firstboot_theme_is_ascii_and_preserves_whiptail_as_the_ui_engine() { let wrapper = repo_file("build/usb/includes.chroot/usr/lib/rigos/rigos-firstboot-whiptail"); From 8f9c3c74dc6543c3ec119d8e8e29914845f380d1 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Thu, 9 Jul 2026 14:59:42 +0700 Subject: [PATCH 16/25] Remove synthetic separators from firstboot theme --- .../usb/includes.chroot/usr/lib/rigos/rigos-firstboot-whiptail | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/usb/includes.chroot/usr/lib/rigos/rigos-firstboot-whiptail b/build/usb/includes.chroot/usr/lib/rigos/rigos-firstboot-whiptail index 529fa7d2..ab6ad464 100644 --- a/build/usb/includes.chroot/usr/lib/rigos/rigos-firstboot-whiptail +++ b/build/usb/includes.chroot/usr/lib/rigos/rigos-firstboot-whiptail @@ -9,7 +9,7 @@ export TERM NEWT_COLORS=${NEWT_COLORS:-'root=white,blue:border=blue,lightgray:window=black,lightgray:shadow=black,black:title=white,blue:button=black,lightgray:actbutton=white,blue:compactbutton=black,lightgray:checkbox=black,lightgray:actcheckbox=white,blue:entry=black,white:disentry=gray,lightgray:label=black,lightgray:listbox=black,lightgray:actlistbox=white,blue:sellistbox=black,cyan:actsellistbox=white,blue:textbox=black,lightgray:acttextbox=white,blue:helpline=white,blue:roottext=white,blue'} export NEWT_COLORS -backtitle=${RIGOS_FIRSTBOOT_BACKTITLE:-'RIGOS SYSTEM CONFIGURATION // LOCAL NODE SETUP // OFFLINE AUTHORITY'} +backtitle=${RIGOS_FIRSTBOOT_BACKTITLE:-'RIGOS SETUP UTILITY LOCAL NODE CONFIGURATION'} whiptail_real=${RIGOS_WHIPTAIL_REAL:-/usr/bin/whiptail} if [ ! -x "$whiptail_real" ]; then From ba758be0665171eeb6436c2b6af4256e6805d245 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Thu, 9 Jul 2026 14:59:50 +0700 Subject: [PATCH 17/25] Use plain setup utility backtitle --- .../system/rigos-firstboot.service.d/2009-console-theme.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/usb/includes.chroot/etc/systemd/system/rigos-firstboot.service.d/2009-console-theme.conf b/build/usb/includes.chroot/etc/systemd/system/rigos-firstboot.service.d/2009-console-theme.conf index 7c5a3fc4..78da015e 100644 --- a/build/usb/includes.chroot/etc/systemd/system/rigos-firstboot.service.d/2009-console-theme.conf +++ b/build/usb/includes.chroot/etc/systemd/system/rigos-firstboot.service.d/2009-console-theme.conf @@ -1,3 +1,3 @@ [Service] Environment=RIGOS_WHIPTAIL=/usr/lib/rigos/rigos-firstboot-whiptail -Environment="RIGOS_FIRSTBOOT_BACKTITLE=RIGOS SYSTEM CONFIGURATION // LOCAL NODE SETUP // OFFLINE AUTHORITY" +Environment="RIGOS_FIRSTBOOT_BACKTITLE=RIGOS SETUP UTILITY LOCAL NODE CONFIGURATION" From aa5b548eb954f6528cc6297ce7ae2ce7df973e39 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Thu, 9 Jul 2026 15:00:03 +0700 Subject: [PATCH 18/25] Make firstboot preview read like a real setup utility --- scripts/preview-firstboot-theme.sh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/scripts/preview-firstboot-theme.sh b/scripts/preview-firstboot-theme.sh index 255a3c6c..19f154de 100644 --- a/scripts/preview-firstboot-theme.sh +++ b/scripts/preview-firstboot-theme.sh @@ -18,7 +18,7 @@ fi run_theme() { set +e RIGOS_WHIPTAIL_REAL=/usr/bin/whiptail \ - RIGOS_FIRSTBOOT_BACKTITLE='RIGOS SYSTEM CONFIGURATION // LOCAL NODE SETUP // OFFLINE AUTHORITY' \ + RIGOS_FIRSTBOOT_BACKTITLE='RIGOS SETUP UTILITY LOCAL NODE CONFIGURATION' \ sh "$wrapper" "$@" status=$? set -e @@ -27,8 +27,8 @@ run_theme() { preview_menu() { run_theme \ - --title 'RIGOS FIRST BOOT // FLIGHT CONTROL' \ - --menu $'SELECT FLIGHT SHEET\n\nChoose the local mining authority for this node.\n\n[UP/DOWN] MOVE [ENTER] SELECT [ESC] BACK' \ + --title 'FLIGHT SHEET SELECTION' \ + --menu $'SELECT FLIGHT SHEET\n\nChoose how this node should be configured.\n\n[UP/DOWN] MOVE [ENTER] SELECT [ESC] BACK' \ 20 76 6 \ manual 'Configure this node manually' \ none 'Leave mining unconfigured' \ @@ -38,21 +38,21 @@ preview_menu() { preview_confirm() { run_theme \ - --title 'RIGOS FIRST BOOT // COMMIT AUTHORITY' \ + --title 'COMMIT CONFIGURATION' \ --yesno $'CONFIGURATION SUMMARY\n\nNode rig01\nFlight Sheet xmr\nAlgorithm rx/0\nThreads exact 2\nHuge Pages enabled\nStart Policy on boot\n\nApply this configuration to local persistent state?' \ 20 76 } preview_input() { run_theme \ - --title 'RIGOS FIRST BOOT // NODE IDENTITY' \ + --title 'NODE IDENTITY' \ --inputbox $'NODE NAME\n\nEnter the local appliance name.\nAllowed: A-Z, a-z, 0-9 and hyphen.' \ 14 72 'rig01' } preview_message() { run_theme \ - --title 'RIGOS FIRST BOOT // SYSTEM READY' \ + --title 'SETUP COMPLETE' \ --msgbox $'CONFIGURATION COMMITTED\n\nPersistent state verified.\nRuntime config published.\nMiner activation requested.\n\nThe local console will now return to the system.' \ 16 72 } From 6aa4fb01c53339c0cbcdb7074ada6bc92fc72269 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Thu, 9 Jul 2026 15:00:28 +0700 Subject: [PATCH 19/25] Format theme tests and ban slash separators --- crates/rigos-config/tests/firstboot_theme.rs | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/crates/rigos-config/tests/firstboot_theme.rs b/crates/rigos-config/tests/firstboot_theme.rs index d2fc7084..2df186e4 100644 --- a/crates/rigos-config/tests/firstboot_theme.rs +++ b/crates/rigos-config/tests/firstboot_theme.rs @@ -1,6 +1,9 @@ use std::fs; use std::path::PathBuf; +const WRAPPER_PATH: &str = + "build/usb/includes.chroot/usr/lib/rigos/rigos-firstboot-whiptail"; + fn repo_path(path: &str) -> PathBuf { PathBuf::from(env!("CARGO_MANIFEST_DIR")) .join("../..") @@ -24,26 +27,30 @@ fn firstboot_uses_the_dedicated_console_theme_wrapper() { "firstboot must select the dedicated presentation wrapper" ); assert!( - drop_in.contains("RIGOS SYSTEM CONFIGURATION // LOCAL NODE SETUP // OFFLINE AUTHORITY"), + drop_in.contains("RIGOS SETUP UTILITY LOCAL NODE CONFIGURATION"), "firstboot must publish the static non-secret backtitle" ); + assert!( + !drop_in.contains("//"), + "setup utility titles must not use synthetic slash separators" + ); } #[test] fn firstboot_wrapper_is_pinned_to_lf_in_git() { let attributes = repo_file(".gitattributes"); + let required = + "build/usb/includes.chroot/usr/lib/rigos/rigos-firstboot-* text eol=lf"; assert!( - attributes - .lines() - .any(|line| line == "build/usb/includes.chroot/usr/lib/rigos/rigos-firstboot-* text eol=lf"), + attributes.lines().any(|line| line == required), "firstboot runtime wrappers must remain LF on Windows and WSL checkouts" ); } #[test] fn firstboot_theme_is_ascii_and_preserves_whiptail_as_the_ui_engine() { - let wrapper = repo_file("build/usb/includes.chroot/usr/lib/rigos/rigos-firstboot-whiptail"); + let wrapper = repo_file(WRAPPER_PATH); assert!(wrapper.is_ascii(), "console theme must remain ASCII-only"); assert!(wrapper.contains("NEWT_COLORS=")); @@ -56,6 +63,7 @@ fn firstboot_theme_is_ascii_and_preserves_whiptail_as_the_ui_engine() { assert!(wrapper.contains("RIGOS_WHIPTAIL_REAL:-/usr/bin/whiptail")); assert!(wrapper.contains("exec \"$whiptail_real\"")); assert!(wrapper.contains("backend is not executable")); + assert!(!wrapper.contains("//")); assert!( !wrapper.contains("xterm") && !wrapper.contains("Xorg") @@ -106,7 +114,7 @@ fn firstboot_theme_wrapper_maps_buttons_and_preserves_exit_status() { fs::set_permissions(&backend, permissions) .expect("failed to make fake whiptail backend executable"); - let wrapper = repo_path("build/usb/includes.chroot/usr/lib/rigos/rigos-firstboot-whiptail"); + let wrapper = repo_path(WRAPPER_PATH); let status = Command::new("sh") .arg(&wrapper) .args([ From b3900e2379984bbb9b3e4b5e7ccf52b4637b8639 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Thu, 9 Jul 2026 15:00:46 +0700 Subject: [PATCH 20/25] Ban slash separators from theme previews --- crates/rigos-config/tests/firstboot_theme_preview.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/crates/rigos-config/tests/firstboot_theme_preview.rs b/crates/rigos-config/tests/firstboot_theme_preview.rs index 4180d74e..91016fd7 100644 --- a/crates/rigos-config/tests/firstboot_theme_preview.rs +++ b/crates/rigos-config/tests/firstboot_theme_preview.rs @@ -32,6 +32,11 @@ fn preview_covers_every_firstboot_dialog_class() { "preview harness is missing dialog class: {required}" ); } + + assert!( + !script.contains("//"), + "preview titles must not use synthetic slash separators" + ); } #[test] From f2660f62c9cedfe8389f3d8e12bb65ea5aac33dd Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Thu, 9 Jul 2026 15:15:33 +0700 Subject: [PATCH 21/25] Match firstboot theme tests to rustfmt output --- crates/rigos-config/tests/firstboot_theme.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/crates/rigos-config/tests/firstboot_theme.rs b/crates/rigos-config/tests/firstboot_theme.rs index 2df186e4..47535c60 100644 --- a/crates/rigos-config/tests/firstboot_theme.rs +++ b/crates/rigos-config/tests/firstboot_theme.rs @@ -1,8 +1,7 @@ use std::fs; use std::path::PathBuf; -const WRAPPER_PATH: &str = - "build/usb/includes.chroot/usr/lib/rigos/rigos-firstboot-whiptail"; +const WRAPPER_PATH: &str = "build/usb/includes.chroot/usr/lib/rigos/rigos-firstboot-whiptail"; fn repo_path(path: &str) -> PathBuf { PathBuf::from(env!("CARGO_MANIFEST_DIR")) @@ -39,8 +38,7 @@ fn firstboot_uses_the_dedicated_console_theme_wrapper() { #[test] fn firstboot_wrapper_is_pinned_to_lf_in_git() { let attributes = repo_file(".gitattributes"); - let required = - "build/usb/includes.chroot/usr/lib/rigos/rigos-firstboot-* text eol=lf"; + let required = "build/usb/includes.chroot/usr/lib/rigos/rigos-firstboot-* text eol=lf"; assert!( attributes.lines().any(|line| line == required), From 951b95084d7930372c6dc080bac6eb3fc999b457 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Thu, 9 Jul 2026 15:24:20 +0700 Subject: [PATCH 22/25] Move firstboot wrapper behavior out of Rust crate tests --- crates/rigos-config/tests/firstboot_theme.rs | 95 -------------------- 1 file changed, 95 deletions(-) diff --git a/crates/rigos-config/tests/firstboot_theme.rs b/crates/rigos-config/tests/firstboot_theme.rs index 47535c60..1db399a6 100644 --- a/crates/rigos-config/tests/firstboot_theme.rs +++ b/crates/rigos-config/tests/firstboot_theme.rs @@ -80,98 +80,3 @@ fn image_hook_installs_the_theme_wrapper_as_executable() { "image construction must install the wrapper as executable" ); } - -#[cfg(unix)] -#[test] -fn firstboot_theme_wrapper_maps_buttons_and_preserves_exit_status() { - use std::os::unix::fs::PermissionsExt; - use std::process::Command; - use std::time::{SystemTime, UNIX_EPOCH}; - - let nonce = SystemTime::now() - .duration_since(UNIX_EPOCH) - .expect("system clock is before Unix epoch") - .as_nanos(); - let temporary = std::env::temp_dir().join(format!( - "rigos-firstboot-theme-{}-{nonce}", - std::process::id() - )); - fs::create_dir_all(&temporary).expect("failed to create theme test directory"); - - let backend = temporary.join("fake-whiptail"); - let capture = temporary.join("arguments.txt"); - fs::write( - &backend, - "#!/bin/sh\nprintf '%s\\n' \"$@\" >\"$RIGOS_THEME_CAPTURE\"\nexit \"${RIGOS_THEME_EXIT:-0}\"\n", - ) - .expect("failed to write fake whiptail backend"); - let mut permissions = fs::metadata(&backend) - .expect("failed to stat fake whiptail backend") - .permissions(); - permissions.set_mode(0o755); - fs::set_permissions(&backend, permissions) - .expect("failed to make fake whiptail backend executable"); - - let wrapper = repo_path(WRAPPER_PATH); - let status = Command::new("sh") - .arg(&wrapper) - .args([ - "--title", - "RIGOS FIRST BOOT", - "--menu", - "Select Flight Sheet", - "20", - "76", - "2", - "manual", - "Configure manually", - "none", - "Leave mining unconfigured", - ]) - .env("RIGOS_WHIPTAIL_REAL", &backend) - .env("RIGOS_THEME_CAPTURE", &capture) - .env("RIGOS_THEME_EXIT", "7") - .env("RIGOS_FIRSTBOOT_BACKTITLE", "TEST BACKTITLE") - .status() - .expect("failed to execute firstboot theme wrapper"); - - assert_eq!( - status.code(), - Some(7), - "wrapper must preserve backend exit status" - ); - - let arguments = - fs::read_to_string(&capture).expect("fake whiptail backend did not capture arguments"); - let arguments: Vec<_> = arguments.lines().collect(); - assert_eq!( - &arguments[..8], - [ - "--backtitle", - "TEST BACKTITLE", - "--ok-button", - "SELECT", - "--cancel-button", - "BACK", - "--title", - "RIGOS FIRST BOOT", - ] - ); - assert!( - arguments - .windows(2) - .any(|pair| pair == ["--menu", "Select Flight Sheet"]) - ); - assert!( - arguments - .windows(2) - .any(|pair| pair == ["manual", "Configure manually"]) - ); - assert!( - arguments - .windows(2) - .any(|pair| pair == ["none", "Leave mining unconfigured"]) - ); - - fs::remove_dir_all(&temporary).expect("failed to clean theme test directory"); -} From 2524971db4faaed267a93b02fedce972a80cb770 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Thu, 9 Jul 2026 15:24:36 +0700 Subject: [PATCH 23/25] Add shell behavioral verification for firstboot theme wrapper --- scripts/verify-firstboot-theme-wrapper.sh | 81 +++++++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 scripts/verify-firstboot-theme-wrapper.sh diff --git a/scripts/verify-firstboot-theme-wrapper.sh b/scripts/verify-firstboot-theme-wrapper.sh new file mode 100644 index 00000000..a390eca0 --- /dev/null +++ b/scripts/verify-firstboot-theme-wrapper.sh @@ -0,0 +1,81 @@ +#!/usr/bin/env bash +set -euo pipefail + +root=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd) +wrapper="$root/build/usb/includes.chroot/usr/lib/rigos/rigos-firstboot-whiptail" + +test -f "$wrapper" + +tmp=$(mktemp -d) +cleanup() { + rm -rf "$tmp" +} +trap cleanup EXIT HUP INT TERM + +backend="$tmp/fake-whiptail" +capture="$tmp/arguments.txt" +expected="$tmp/expected.txt" + +cat >"$backend" <<'EOF' +#!/bin/sh +printf '%s\n' "$@" >"$RIGOS_THEME_CAPTURE" +exit "${RIGOS_THEME_EXIT:-0}" +EOF +chmod 0755 "$backend" + +set +e +RIGOS_WHIPTAIL_REAL="$backend" \ +RIGOS_THEME_CAPTURE="$capture" \ +RIGOS_THEME_EXIT=7 \ +RIGOS_FIRSTBOOT_BACKTITLE='TEST BACKTITLE' \ +sh "$wrapper" \ + --title 'RIGOS FIRST BOOT' \ + --menu 'Select Flight Sheet' \ + 20 76 2 \ + manual 'Configure manually' \ + none 'Leave mining unconfigured' +status=$? +set -e + +if [[ "$status" -ne 7 ]]; then + echo "firstboot theme wrapper did not preserve backend exit status: $status" >&2 + exit 1 +fi + +cat >"$expected" <<'EOF' +--backtitle +TEST BACKTITLE +--ok-button +SELECT +--cancel-button +BACK +--title +RIGOS FIRST BOOT +--menu +Select Flight Sheet +20 +76 +2 +manual +Configure manually +none +Leave mining unconfigured +EOF + +if ! cmp -s "$expected" "$capture"; then + echo "firstboot theme wrapper changed argument order or values" >&2 + diff -u "$expected" "$capture" >&2 || true + exit 1 +fi + +set +e +RIGOS_WHIPTAIL_REAL="$tmp/missing-backend" sh "$wrapper" --msgbox test 8 40 >/dev/null 2>&1 +missing_status=$? +set -e + +if [[ "$missing_status" -ne 127 ]]; then + echo "firstboot theme wrapper did not fail closed for a missing backend: $missing_status" >&2 + exit 1 +fi + +echo "RIGOS firstboot theme wrapper verification passed" From e9f1bbe1ad1f8d28875f0f9e53f26e86485882f0 Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Thu, 9 Jul 2026 15:25:47 +0700 Subject: [PATCH 24/25] Run firstboot wrapper behavior in authoritative WSL gate --- scripts/verify-wsl-entrypoint.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/verify-wsl-entrypoint.sh b/scripts/verify-wsl-entrypoint.sh index 55090d9f..27e1693c 100644 --- a/scripts/verify-wsl-entrypoint.sh +++ b/scripts/verify-wsl-entrypoint.sh @@ -20,7 +20,7 @@ if [[ -f "$HOME/.cargo/env" ]]; then fi missing=0 -for tool in cargo rustc python3 bash sh git grep rg mktemp; do +for tool in cargo rustc python3 bash sh git grep rg mktemp cmp diff; do if ! command -v "$tool" >/dev/null 2>&1; then printf 'RIGOS_WSL_TOOL_MISSING=%s\n' "$tool" >&2 missing=1 @@ -55,3 +55,4 @@ export PYTHONDONTWRITEBYTECODE=1 printf 'RIGOS_WSL_REPO=%s\n' "$repo" printf 'RIGOS_WSL_CARGO=%s\n' "$(command -v cargo)" bash ./scripts/verify.sh +bash ./scripts/verify-firstboot-theme-wrapper.sh From fdce587592d36cde6eafc90cece7ba1693bddc7b Mon Sep 17 00:00:00 2001 From: DEADBYTE Date: Thu, 9 Jul 2026 15:26:14 +0700 Subject: [PATCH 25/25] Lock wrapper behavior verification into WSL authority --- crates/rigos-config/tests/firstboot_theme.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/crates/rigos-config/tests/firstboot_theme.rs b/crates/rigos-config/tests/firstboot_theme.rs index 1db399a6..6a494b4d 100644 --- a/crates/rigos-config/tests/firstboot_theme.rs +++ b/crates/rigos-config/tests/firstboot_theme.rs @@ -71,6 +71,17 @@ fn firstboot_theme_is_ascii_and_preserves_whiptail_as_the_ui_engine() { ); } +#[test] +fn authoritative_wsl_gate_runs_the_wrapper_behavior_test() { + let entrypoint = repo_file("scripts/verify-wsl-entrypoint.sh"); + let verifier = repo_file("scripts/verify-firstboot-theme-wrapper.sh"); + + assert!(entrypoint.contains("bash ./scripts/verify-firstboot-theme-wrapper.sh")); + assert!(verifier.contains("RIGOS firstboot theme wrapper verification passed")); + assert!(verifier.contains("RIGOS_THEME_EXIT=7")); + assert!(verifier.contains("missing-backend")); +} + #[test] fn image_hook_installs_the_theme_wrapper_as_executable() { let hook = repo_file("build/usb/hooks/010-rigos.chroot");