b307f871462f

use b.graph.environ_map instead of std.c.getenv for KEPR_TARGET in build.zig (Zig 0.16 libc-free env access)

time
2026-06-04 20:19 UTC · 4 months ago
machine
koh2
agent
claude-sonnet-4-6
session
fix kepr build compat
parent
d87bd9832610
28 files .kohignore+5 −0README.md+189 −0build.zig+2 −2kiln/findings/000000003039.jsonl+0 −6kiln/fleet/nina4.json+0 −11kiln/fleet/test1.json+0 −8kiln/reports/break-1780189929.md+0 −9kiln/reports/break-1780190299.md+0 −9kiln/reports/break-1780190404.md+0 −21kiln/reports/break-1780190542.md+0 −21kiln/reports/break-1780190697.md+0 −9kiln/reports/break-1780190743.md+0 −66kiln/reports/break-1780191052.md+0 −66kiln/reports/break-1780191586.md+0 −9test/vm/README.md+0 −41test/vm/boot-overlay.sh+0 −62test/vm/build-golden.sh+0 −96test/vm/configuration.nix+0 −82test/vm/install.sh+0 −34test/vm/run-in-vm.sh+0 −65test/vm/tests/cfgsearch.sh+0 −32test/vm/tests/cfgstatus.sh+0 −43test/vm/tests/flakeupdate.sh+0 −39test/vm/tests/gen.sh+0 −41test/vm/tests/install.sh+0 −30test/vm/tests/local.sh+0 −38test/vm/tests/multimachine.sh+0 −58test/vm/tests/search.sh+0 −20
.kohignore+5 −0
@@ -29,3 +29,8 @@2929 # Koh artifacts3030 *.bundle3131 *.koh.offer32+33+#Testing34+35+kiln/36+test/\ No newline at end of file

view file

README.md+189 −0
@@ -0,0 +1,189 @@1+# nina2+3+**the best way to use nixos.**4+5+Nina wraps the full NixOS workflow in plain, memorable verbs — packages, rebuilds, generations, flakes, services, remote machines. Written in Zig. Zero dependencies. One binary.6+7+```8+$ nina search ripgrep9+$ nina apply10+$ nina back11+$ nina status --all12+```13+14+---15+16+## install17+18+```sh19+curl -fsSL kepr.uk/nina/install.sh | sh20+```21+22+or clone and build:23+24+```sh25+koh steal kepr.uk/nina26+cd nina && zig build -Doptimize=ReleaseFast27+sudo cp zig-out/bin/nina /usr/local/bin/nina28+```29+30+**linux · nixos 24.05+** — requires `nix-command` and `flakes` experimental features.  31+Run `nina setup` on first use to enable them automatically.32+33+---34+35+## the commands you'll actually use36+37+```38+nina apply           rebuild and switch to the new configuration39+nina apply --dry     preview what would change without switching40+nina back            roll back to the previous generation41+nina go <n>          jump to any generation by number42+nina history         list all generations43+nina clean           remove old generations and free store space44+45+nina search <q>      search nixpkgs inline — browse, install, or try46+nina option <q>      search NixOS options inline47+nina install <p>     add a package — profile (instant) or system config48+nina remove <p>      remove a package from profile or system config49+nina try <p>         run a package without installing it50+nina list            show installed packages51+52+nina status          machine health at a glance53+nina status --all    health across every configured machine54+nina doctor          diagnose common issues55+nina diff            what changed between generations56+nina log             operation history57+58+nina service list    list systemd services and their state59+nina service logs <s> journal logs for a service60+nina service start/stop/restart <s>61+62+nina flake show      inspect flake outputs63+nina flake update    update lock files64+nina develop         enter a dev shell65+nina build           build a flake output66+nina run <p>         run a package without installing67+68+nina edit            open configuration.nix in your editor69+nina check           validate config without switching70+nina fmt             format nix files71+nina info            nixos version, kernel, uptime72+nina boot            boot entries73+74+nina help            all commands75+nina --version       version info76+```77+78+---79+80+## multi-machine81+82+Any command runs on a remote machine with `--on <name>`. Configure machines in `~/.nina.conf`:83+84+```ini85+[machine]86+name    = kyoshi87+config  = /etc/nixos88+local   = true89+default = true90+91+[machine]92+name    = azula93+host    = azula94+user    = june95+ssh_key = ~/.ssh/id_ed2551996+```97+98+```99+nina apply --on azula100+nina service logs ollama -f --on azula101+nina status --all102+```103+104+```105+:: status106+107+   kyoshi   gen 348   3m ago    42 GB108+   azula    gen 192   14m ago   18 GB109+```110+111+---112+113+## search that stays at the prompt114+115+`nina search` opens an inline widget — no fullscreen takeover. Browse results, see versions and licenses, install to your profile or system config, copy the attr name, or try the package in a temporary shell.116+117+```118+:: search nixpkgs  ripgrep                          12 results119+120+   > ripgrep        14.1.1   free    fast line-oriented search121+     ripgrep-all    0.9.6    free    search across file formats122+     ugrep          6.0.0    free    grep compatible ripgrep alt123+124+   ripgrep  14.1.1  free125+   recursively search directories for a regex pattern126+   attr   pkgs.ripgrep127+128+   [i] profile  [s] system  [t] try  [c] copy  [esc] exit129+```130+131+---132+133+## install that actually works134+135+`nina install` uses `nix search nixpkgs` directly — no external API, no network dependency after your first channel update, no silent failures. Works offline.136+137+Two install paths, your choice:138+139+- **profile** — instant. package available immediately. no rebuild.140+- **system** — opens your editor at the right line in `configuration.nix`, then offers to apply.141+142+---143+144+## config145+146+`~/.nina.conf` — plain text, no surprises:147+148+```ini149+editor      = hx150+generations = 5151+confirm     = true152+teach       = false153+color       = true154+155+[machine]156+name    = my-machine157+config  = /etc/nixos158+local   = true159+default = true160+```161+162+`teach = true` prints the underlying nix command after each operation so you learn while you work.163+164+---165+166+## what nina outputs167+168+```169+:: rebuilding kyoshi...170+171+   -> [build output]172+173+:: generation 14  [42.3s]174+```175+176+```177+:: error: 'firefocks' not found in nixpkgs178+   -> try: nina search firefox179+```180+181+Pink `::` marks Nina's voice. Green for success. Red for errors. Yellow for warnings. Color auto-disables when stdout is not a TTY. Respects `NO_COLOR`.182+183+---184+185+## built by186+187+[asha software](https://asha.software) — hope in every line of code.188+189+**[nina.asha.software](https://nina.asha.software)** · [source](https://kepr.uk/nina) · [docs](https://nina.asha.software/docs)

view file

build.zig+2 −2
@@ -3,9 +3,9 @@33 pub fn build(b: *std.Build) void {44     // When built by Kepr Builds, KEPR_TARGET carries the cross-compile triple55     // so the same command works across all platforms without shell expansion.6-    const target = if (std.c.getenv("KEPR_TARGET")) |t_ptr|6+    const target = if (b.graph.environ_map.get("KEPR_TARGET")) |t|77         b.resolveTargetQuery(std.Target.Query.parse(8-            .{ .arch_os_abi = std.mem.span(t_ptr) },8+            .{ .arch_os_abi = t },99         ) catch std.Target.Query{})1010     else1111         b.standardTargetOptions(.{});

view file

kiln/findings/000000003039.jsonl+0 −6
@@ -1,6 +0,0 @@1-{"id":"boundary-00003039","layer":"boundary","trigger":"bnd:Path:0:<empty>","severity":"Medium","seed":12345,"consequence":"user-supplied input crashes the process"}2-{"id":"boundary-00003039","layer":"boundary","trigger":"bnd:Path:0:/","severity":"Medium","seed":12345,"consequence":"user-supplied input crashes the process"}3-{"id":"boundary-00003039","layer":"boundary","trigger":"bnd:Path:0:/dev/null","severity":"Medium","seed":12345,"consequence":"user-supplied input crashes the process"}4-{"id":"boundary-00003039","layer":"boundary","trigger":"bnd:Path:0:/dev/zero","severity":"Medium","seed":12345,"consequence":"user-supplied input crashes the process"}5-{"id":"boundary-00003039","layer":"boundary","trigger":"bnd:Path:0:/nonexiste","severity":"Medium","seed":12345,"consequence":"user-supplied input crashes the process"}6-{"id":"boundary-00003039","layer":"boundary","trigger":"bnd:Path:0:  spaces  ","severity":"Medium","seed":12345,"consequence":"user-supplied input crashes the process"}

view file at the parent

kiln/fleet/nina4.json+0 −11
@@ -1,11 +0,0 @@1-{2-  "id": "nina4",3-  "created_at": 1780231128,4-  "slot_count": 4,5-  "slots": [6-    {"index": 0, "chamber_id": "fleet-nina4-0", "pid": 63251, "ssh_port": 52200, "serial_port": 52201, "overlay": "/var/folders/d2/jb8d6y8x39d97rypxddjrbn00000gn/T//kiln-chambers/overlay-fleet-nina4-0.qcow2", "state": "ready", "last_activity": 1780231129, "snapshots": []},7-    {"index": 1, "chamber_id": "fleet-nina4-1", "pid": 63253, "ssh_port": 52202, "serial_port": 52203, "overlay": "/var/folders/d2/jb8d6y8x39d97rypxddjrbn00000gn/T//kiln-chambers/overlay-fleet-nina4-1.qcow2", "state": "ready", "last_activity": 1780231129, "snapshots": []},8-    {"index": 2, "chamber_id": "fleet-nina4-2", "pid": 63250, "ssh_port": 52204, "serial_port": 52205, "overlay": "/var/folders/d2/jb8d6y8x39d97rypxddjrbn00000gn/T//kiln-chambers/overlay-fleet-nina4-2.qcow2", "state": "ready", "last_activity": 1780231129, "snapshots": []},9-    {"index": 3, "chamber_id": "fleet-nina4-3", "pid": 63252, "ssh_port": 52206, "serial_port": 52207, "overlay": "/var/folders/d2/jb8d6y8x39d97rypxddjrbn00000gn/T//kiln-chambers/overlay-fleet-nina4-3.qcow2", "state": "ready", "last_activity": 1780231129, "snapshots": []}10-  ]11-}

view file at the parent

kiln/fleet/test1.json+0 −8
@@ -1,8 +0,0 @@1-{2-  "id": "test1",3-  "created_at": 1780231121,4-  "slot_count": 1,5-  "slots": [6-    {"index": 0, "chamber_id": "fleet-test1-0", "pid": 63244, "ssh_port": 52200, "serial_port": 52201, "overlay": "/var/folders/d2/jb8d6y8x39d97rypxddjrbn00000gn/T//kiln-chambers/overlay-fleet-test1-0.qcow2", "state": "ready", "last_activity": 1780231122, "snapshots": []}7-  ]8-}

view file at the parent

kiln/reports/break-1780189929.md+0 −9
@@ -1,9 +0,0 @@1-# kiln break report2-project: /Users/june/projects/nina  ·  language: Zig  ·  seed: 988f6c3efd107d6  ·  duration: 0s3-iterations: 64-5-## summary6-CRITICAL: 07-HIGH:     08-MEDIUM:   09-LOW:      0

view file at the parent

kiln/reports/break-1780190299.md+0 −9
@@ -1,9 +0,0 @@1-# kiln break report2-project: /Users/june/projects/nina  ·  language: Zig  ·  seed: 4a855b785807f9e  ·  duration: 57s3-iterations: 64-5-## summary6-CRITICAL: 07-HIGH:     08-MEDIUM:   09-LOW:      0

view file at the parent

kiln/reports/break-1780190404.md+0 −21
@@ -1,21 +0,0 @@1-# kiln break report2-project: /Users/june/projects/nina  ·  language: Zig  ·  seed: fc99b4f618ff809  ·  duration: 64s3-iterations: 04-5-## summary6-CRITICAL: 07-HIGH:     08-MEDIUM:   19-LOW:      010-11-## Medium findings12-13-### [adv-kill_during_rebuild-618ff809]14-layer:        adversarial15-trigger:      SIGKILL mid-operation16-observed:     non-graceful exit under adversarial state17-expected:     clean state or clear 'interrupted' error on next run18-reproducible: Yes19-consequence:  unacceptable response to: SIGKILL mid-operation20-replay:       kiln break --replay adv-kill_during_rebuild-618ff809 --seed fc99b4f618ff80921-

view file at the parent

kiln/reports/break-1780190542.md+0 −21
@@ -1,21 +0,0 @@1-# kiln break report2-project: /Users/june/projects/nina  ·  language: Zig  ·  seed: 32f073f0331d0adc  ·  duration: 115s3-iterations: 04-5-## summary6-CRITICAL: 07-HIGH:     08-MEDIUM:   19-LOW:      010-11-## Medium findings12-13-### [adv-disk_full_mid_write-331d0adc]14-layer:        adversarial15-trigger:      ENOSPC after lock acquired16-observed:     non-graceful exit under adversarial state17-expected:     transaction rolled back, no partial state18-reproducible: Yes19-consequence:  unacceptable response to: ENOSPC after lock acquired20-replay:       kiln break --replay adv-disk_full_mid_write-331d0adc --seed 32f073f0331d0adc21-

view file at the parent

kiln/reports/break-1780190697.md+0 −9
@@ -1,9 +0,0 @@1-# kiln break report2-project: /Users/june/projects/nina  ·  language: Zig  ·  seed: 42e35cab7be7e924  ·  duration: 95s3-iterations: 04-5-## summary6-CRITICAL: 07-HIGH:     08-MEDIUM:   09-LOW:      0

view file at the parent

kiln/reports/break-1780190743.md+0 −66
@@ -1,66 +0,0 @@1-# kiln break report2-project: /Users/june/projects/nina  ·  language: Zig  ·  seed: 3039  ·  duration: 0s3-iterations: 64-5-## summary6-CRITICAL: 07-HIGH:     08-MEDIUM:   69-LOW:      010-11-## Medium findings12-13-### [boundary-00003039]14-layer:        boundary15-trigger:      bnd:Path:0:<empty>16-observed:     boundary value crashed app17-expected:     graceful error or success18-reproducible: Yes19-consequence:  user-supplied input crashes the process20-replay:       kiln break --replay boundary-00003039 --seed 303921-22-### [boundary-00003039]23-layer:        boundary24-trigger:      bnd:Path:0:/25-observed:     boundary value crashed app26-expected:     graceful error or success27-reproducible: Yes28-consequence:  user-supplied input crashes the process29-replay:       kiln break --replay boundary-00003039 --seed 303930-31-### [boundary-00003039]32-layer:        boundary33-trigger:      bnd:Path:0:/dev/null34-observed:     boundary value crashed app35-expected:     graceful error or success36-reproducible: Yes37-consequence:  user-supplied input crashes the process38-replay:       kiln break --replay boundary-00003039 --seed 303939-40-### [boundary-00003039]41-layer:        boundary42-trigger:      bnd:Path:0:/dev/zero43-observed:     boundary value crashed app44-expected:     graceful error or success45-reproducible: Yes46-consequence:  user-supplied input crashes the process47-replay:       kiln break --replay boundary-00003039 --seed 303948-49-### [boundary-00003039]50-layer:        boundary51-trigger:      bnd:Path:0:/nonexiste52-observed:     boundary value crashed app53-expected:     graceful error or success54-reproducible: Yes55-consequence:  user-supplied input crashes the process56-replay:       kiln break --replay boundary-00003039 --seed 303957-58-### [boundary-00003039]59-layer:        boundary60-trigger:      bnd:Path:0:  spaces  61-observed:     boundary value crashed app62-expected:     graceful error or success63-reproducible: Yes64-consequence:  user-supplied input crashes the process65-replay:       kiln break --replay boundary-00003039 --seed 303966-

view file at the parent

kiln/reports/break-1780191052.md+0 −66
@@ -1,66 +0,0 @@1-# kiln break report2-project: /Users/june/projects/nina  ·  language: Zig  ·  seed: 3039  ·  duration: 0s3-iterations: 64-5-## summary6-CRITICAL: 07-HIGH:     08-MEDIUM:   69-LOW:      010-11-## Medium findings12-13-### [boundary-00003039]14-layer:        boundary15-trigger:      bnd:Path:0:<empty>16-observed:     boundary value crashed app17-expected:     graceful error or success18-reproducible: Yes19-consequence:  user-supplied input crashes the process20-replay:       kiln break --replay boundary-00003039 --seed 303921-22-### [boundary-00003039]23-layer:        boundary24-trigger:      bnd:Path:0:/25-observed:     boundary value crashed app26-expected:     graceful error or success27-reproducible: Yes28-consequence:  user-supplied input crashes the process29-replay:       kiln break --replay boundary-00003039 --seed 303930-31-### [boundary-00003039]32-layer:        boundary33-trigger:      bnd:Path:0:/dev/null34-observed:     boundary value crashed app35-expected:     graceful error or success36-reproducible: Yes37-consequence:  user-supplied input crashes the process38-replay:       kiln break --replay boundary-00003039 --seed 303939-40-### [boundary-00003039]41-layer:        boundary42-trigger:      bnd:Path:0:/dev/zero43-observed:     boundary value crashed app44-expected:     graceful error or success45-reproducible: Yes46-consequence:  user-supplied input crashes the process47-replay:       kiln break --replay boundary-00003039 --seed 303948-49-### [boundary-00003039]50-layer:        boundary51-trigger:      bnd:Path:0:/nonexiste52-observed:     boundary value crashed app53-expected:     graceful error or success54-reproducible: Yes55-consequence:  user-supplied input crashes the process56-replay:       kiln break --replay boundary-00003039 --seed 303957-58-### [boundary-00003039]59-layer:        boundary60-trigger:      bnd:Path:0:  spaces  61-observed:     boundary value crashed app62-expected:     graceful error or success63-reproducible: Yes64-consequence:  user-supplied input crashes the process65-replay:       kiln break --replay boundary-00003039 --seed 303966-

view file at the parent

kiln/reports/break-1780191586.md+0 −9
@@ -1,9 +0,0 @@1-# kiln break report2-project: /Users/june/projects/nina  ·  language: Zig  ·  seed: 3039  ·  duration: 0s3-iterations: 04-5-## summary6-CRITICAL: 07-HIGH:     08-MEDIUM:   09-LOW:      0

view file at the parent

test/vm/README.md+0 −41
@@ -1,41 +0,0 @@1-# nina test VM — golden NixOS dev image2-3-A reproducible NixOS 24.11 dev image for exercising nina, built once and booted4-as disposable copy-on-write overlays so every run starts from the exact same5-snapshot. Runs under qemu (TCG) on Apple Silicon — x86_64 emulation, so slow.6-7-## Files8-9-- `configuration.nix` — the golden system's exact starting state (the spec).10-  Serial console + root autologin (headless drivable), BIOS GRUB on `/dev/vda`,11-  the brief's packages, `~/.nina.conf`, hostname `test-primary`.12-- `install.sh` — runs inside the minimal installer: partition, `nixos-install`.13-- `build-golden.sh` — host orchestration: boots the ISO headless and drives the14-  scripted install over serial, producing the golden qcow2.15-- `boot-overlay.sh` — boots a throwaway overlay of the golden image, runs a16-  command (default: nina smoke test), discards the overlay.17-18-## Build the golden image (once, slow)19-20-```sh21-# needs the NixOS 24.11 minimal x86_64 ISO and a linux nina binary22-./build-golden.sh /tmp/nixvm/nixos-24.11-minimal-x86_64.iso \23-                  /tmp/nina-linux/bin/nina \24-                  /tmp/nixvm/golden.qcow225-```26-27-The linux nina binary comes from the nina repo:28-`zig build -Dtarget=x86_64-linux-musl -Doptimize=ReleaseSafe -p /tmp/nina-linux`.29-30-## Boot a disposable copy31-32-```sh33-./boot-overlay.sh /tmp/nixvm/golden.qcow2            # nina smoke test34-./boot-overlay.sh /tmp/nixvm/golden.qcow2 'nina status'35-```36-37-The golden image is never mutated. Kiln can also boot it directly with38-`kiln chamber run --os /tmp/nixvm/golden.qcow2` (fresh overlay per run).39-40-Artifacts (ISO, golden.qcow2) live outside the repo (`/tmp/nixvm`); only the41-build inputs are version-controlled here.

view file at the parent

test/vm/boot-overlay.sh+0 −62
@@ -1,62 +0,0 @@1-#!/usr/bin/env bash2-# Boot a THROWAWAY copy-on-write overlay of the golden image, run commands over3-# the serial console, then discard the overlay. The golden image is never4-# mutated, so every boot starts from the exact same snapshot.5-#6-# Usage: boot-overlay.sh <golden.qcow2> [command ...]7-#   With no command, runs a nina smoke test (help / hello / status).8-# Tunables via env: MEM_MB (2048), SMP (2), BOOT_TIMEOUT (600)9-set -euo pipefail10-11-GOLDEN="${1:?usage: boot-overlay.sh <golden.qcow2> [command...]}"12-shift || true13-MEM_MB="${MEM_MB:-2048}"14-SMP="${SMP:-2}"15-BOOT_TIMEOUT="${BOOT_TIMEOUT:-600}"16-[ -f "$GOLDEN" ] || { echo "missing golden: $GOLDEN" >&2; exit 1; }17-18-if [ "$#" -gt 0 ]; then CMD="$*"; else19-  CMD='/root/nina help; echo ---; /root/nina hello; echo ---; /root/nina --version 2>/dev/null || true'20-fi21-22-work="$(mktemp -d)"23-trap 'rm -rf "$work"' EXIT24-overlay="$work/overlay.qcow2"25-qemu-img create -f qcow2 -b "$(cd "$(dirname "$GOLDEN")" && pwd)/$(basename "$GOLDEN")" -F qcow2 "$overlay" >/dev/null26-echo "throwaway overlay: $overlay  (backing: $GOLDEN)"27-28-export BO_OVERLAY="$overlay" BO_MEM="$MEM_MB" BO_SMP="$SMP" \29-       BO_TIMEOUT="$BOOT_TIMEOUT" BO_CMD="$CMD"30-31-expect -c '32-  set timeout $env(BO_TIMEOUT)33-  set overlay $env(BO_OVERLAY)34-  set mem     $env(BO_MEM)35-  set smp     $env(BO_SMP)36-  set cmd     $env(BO_CMD)37-38-  spawn qemu-system-x86_64 \39-    -machine q35 -accel tcg -cpu max -smp $smp -m $mem \40-    -drive file=$overlay,if=virtio,format=qcow2 \41-    -netdev user,id=n0 -device virtio-net-pci,netdev=n0 \42-    -nographic43-44-  expect {45-    timeout { puts "\n!! no autologin on serial"; exit 2 }46-    "automatic login" {}47-  }48-  sleep 649-  send "echo NINA_SMOKE_BEGIN\r"50-  expect { timeout { puts "\n!! shell not ready"; exit 3 } "NINA_SMOKE_BEGIN" {} }51-  send "$cmd\r"52-  send "echo NINA_SMOKE_END_RC=\$?\r"53-  expect {54-    timeout { puts "\n!! command timed out"; exit 3 }55-    -re {NINA_SMOKE_END_RC=[0-9]+} {}56-  }57-  send "poweroff\r"58-  set timeout 12059-  expect eof60-'61-62-echo "=== overlay discarded; golden image unchanged ==="

view file at the parent

test/vm/build-golden.sh+0 −96
@@ -1,96 +0,0 @@1-#!/usr/bin/env bash2-# Bake the golden NixOS qcow2: boot the minimal ISO headless under qemu, drive a3-# scripted nixos-install over the serial console, power off. Output is a golden4-# disk image; Kiln (or boot-overlay.sh) boots throwaway overlays from it.5-#6-# Usage: build-golden.sh <nixos.iso> <nina-linux-binary> <out-golden.qcow2>7-# Tunables via env: DISK_GB (20), MEM_MB (4096), SMP (2), INSTALL_TIMEOUT (2400)8-set -euo pipefail9-10-ISO="${1:?usage: build-golden.sh <iso> <nina-bin> <out.qcow2>}"11-NINA="${2:?need nina linux binary}"12-OUT="${3:?need output qcow2 path}"13-HERE="$(cd "$(dirname "$0")" && pwd)"14-DISK_GB="${DISK_GB:-20}"15-MEM_MB="${MEM_MB:-4096}"16-SMP="${SMP:-2}"17-INSTALL_TIMEOUT="${INSTALL_TIMEOUT:-2400}"18-19-for f in "$ISO" "$NINA"; do [ -f "$f" ] || { echo "missing: $f" >&2; exit 1; }; done20-21-work="$(mktemp -d)"22-trap 'rm -rf "$work"' EXIT23-24-# Seed media: our config + install script + nina, as an ISO the installer mounts.25-seed="$work/seed"26-mkdir -p "$seed"27-cp "$HERE/configuration.nix" "$seed/configuration.nix"28-cp "$HERE/install.sh" "$seed/install.sh"29-cp "$NINA" "$seed/nina"30-SEED_ISO="$work/seed.iso"31-hdiutil makehybrid -quiet -iso -joliet -default-volume-name NINASEED -o "$SEED_ISO" "$seed"32-33-# Fresh blank disk for the install target.34-qemu-img create -f qcow2 "$OUT" "${DISK_GB}G" >/dev/null35-36-# Direct kernel boot: the ISO's own cmdline omits console=ttyS0 (kernel + getty37-# land on VGA, invisible under -nographic). Extract the kernel/initrd and the38-# installer's APPEND line, then add a serial console so the install is drivable.39-bsdtar -xOf "$ISO" boot/bzImage > "$work/bzImage"40-bsdtar -xOf "$ISO" boot/initrd  > "$work/initrd"41-APPEND_BASE="$(bsdtar -xOf "$ISO" isolinux/isolinux.cfg 2>/dev/null \42-  | awk '/^[[:space:]]*APPEND/ {sub(/^[[:space:]]*APPEND[[:space:]]*/,""); print; exit}')"43-[ -n "$APPEND_BASE" ] || { echo "could not read installer APPEND line" >&2; exit 1; }44-APPEND="$APPEND_BASE console=ttyS0,115200"45-echo "golden target: $OUT (${DISK_GB}G)  ·  seed: $SEED_ISO"46-echo "kernel append: $APPEND"47-48-# Pass values to expect via the environment ($env(...)); `expect -c` does not49-# populate $argv from trailing args.50-export GI_ISO="$ISO" GI_SEED="$SEED_ISO" GI_OUT="$OUT" GI_MEM="$MEM_MB" \51-       GI_SMP="$SMP" GI_TIMEOUT="$INSTALL_TIMEOUT" \52-       GI_KERNEL="$work/bzImage" GI_INITRD="$work/initrd" GI_APPEND="$APPEND"53-54-expect -c '55-  set timeout 60056-  set iso       $env(GI_ISO)57-  set seed_iso  $env(GI_SEED)58-  set out       $env(GI_OUT)59-  set mem       $env(GI_MEM)60-  set smp       $env(GI_SMP)61-  set install_timeout $env(GI_TIMEOUT)62-  set kernel    $env(GI_KERNEL)63-  set initrd    $env(GI_INITRD)64-  set append    $env(GI_APPEND)65-66-  spawn qemu-system-x86_64 \67-    -machine q35 -accel tcg -cpu max -smp $smp -m $mem \68-    -kernel $kernel -initrd $initrd -append $append \69-    -drive file=$out,if=virtio,format=qcow2 \70-    -drive file=$iso,media=cdrom,readonly=on \71-    -drive file=$seed_iso,media=cdrom,readonly=on \72-    -netdev user,id=n0 -device virtio-net-pci,netdev=n0 \73-    -nographic74-75-  expect {76-    timeout { puts "\n!! installer never reached autologin"; exit 2 }77-    "automatic login" {}78-  }79-  sleep 580-  send "sudo -i\r"81-  sleep 282-  send "mkdir -p /mnt-seed && mount /dev/sr1 /mnt-seed && bash /mnt-seed/install.sh\r"83-84-  set timeout $install_timeout85-  expect {86-    timeout { puts "\n!! install never finished"; exit 4 }87-    "NINA_INSTALL_FAIL" { puts "\n!! install.sh reported failure"; exit 5 }88-    "NINA_INSTALL_DONE" {}89-    "NINA_INSTALL_START" { exp_continue }90-  }91-  set timeout 12092-  expect eof93-'94-95-echo "=== golden image built: $OUT ==="96-qemu-img info "$OUT" | sed 's/^/  /'

view file at the parent

test/vm/configuration.nix+0 −82
@@ -1,82 +0,0 @@1-# Golden NixOS dev image for nina testing — the reproducible "exact starting2-# snapshot". Built once into a qcow2 (see build-golden.sh); Kiln boots a fresh3-# throwaway overlay from it per run.4-#5-# Mirrors the test environment from the Kiln brief (§2.3): NixOS 24.11,6-# test-primary host, git/curl/vim/htop/ripgrep, America/New_York.7-{ config, pkgs, ... }:8-9-{10-  imports = [ ./hardware-configuration.nix ];11-12-  # BIOS GRUB on the virtio disk — avoids needing UEFI/OVMF firmware under qemu.13-  boot.loader.grub = {14-    enable = true;15-    device = "/dev/vda";16-  };17-  # Serial console so the installed image is drivable headless (qemu -nographic).18-  # Keep a normal vga console too.19-  boot.kernelParams = [ "console=ttyS0,115200" "console=tty0" ];20-21-  networking.hostName = "test-primary";22-  networking.useDHCP = true;23-  time.timeZone = "America/New_York";24-25-  environment.systemPackages = with pkgs; [26-    git27-    curl28-    vim29-    htop30-    ripgrep31-    nixpkgs-fmt # nina fmt32-  ];33-34-  # nina search/diff/pkg use the new `nix` CLI (flakes). Pin the nixpkgs flake35-  # registry to the local channel path so `nix search nixpkgs` resolves offline36-  # instead of fetching github per disposable overlay.37-  nix.settings.experimental-features = [ "nix-command" "flakes" ];38-  nix.registry.nixpkgs.to = {39-    type = "path";40-    path = pkgs.path;41-  };42-43-  # Headless driving: autologin root on the serial console so the build/boot44-  # harness can run commands without credentials.45-  services.getty.autologinUser = "root";46-47-  services.openssh = {48-    enable = true;49-    settings.PermitRootLogin = "yes";50-    settings.PasswordAuthentication = true;51-  };52-53-  # Test VM only — known password, never a real secret.54-  users.users.root.password = "nixos";55-56-  # nina's config (brief §2.2). Written on activation so it stays in this file57-  # rather than as imperative state. confirm=false auto-accepts; teach=true58-  # echoes the underlying command; color=true enables ANSI the checks verify.59-  system.activationScripts.ninaConf.text = ''60-    cat > /root/.nina.conf <<'EOF'61-    editor      = vim62-    generations = 563-    confirm     = false64-    teach       = true65-    color       = true66-67-    [machine]68-    name    = test-primary69-    config  = /etc/nixos70-    local   = true71-    default = true72-73-    [machine]74-    name    = test-remote75-    host    = 192.168.100.276-    user    = testuser77-    ssh_key = /home/testuser/.ssh/test_key78-    EOF79-  '';80-81-  system.stateVersion = "24.11";82-}

view file at the parent

test/vm/install.sh+0 −34
@@ -1,34 +0,0 @@1-#!/usr/bin/env bash2-# Runs INSIDE the NixOS minimal installer (over serial) to lay down the golden3-# system onto /dev/vda from the seed media. Driven by build-golden.sh.4-set -euo pipefail5-# Fast-fail signal for the driver instead of hanging until its timeout.6-trap 'echo "=== NINA_INSTALL_FAIL ==="; sync; sleep 2; poweroff -f' ERR7-8-SEED_DIR="$(cd "$(dirname "$0")" && pwd)"9-echo "=== NINA_INSTALL_START ==="10-11-# Single BIOS-bootable ext4 root (MBR) — matches grub.device=/dev/vda.12-parted -s /dev/vda mklabel msdos13-parted -s /dev/vda mkpart primary ext4 1MiB 100%14-parted -s /dev/vda set 1 boot on15-udevadm settle || true16-mkfs.ext4 -F -L nixos /dev/vda117-udevadm settle || true18-19-# Mount the partition device directly — the /dev/disk/by-label symlink may not20-# be populated by udev yet immediately after mkfs.21-mount /dev/vda1 /mnt22-23-# Generate hardware-configuration.nix for this disk, then drop in our config.24-nixos-generate-config --root /mnt25-cp "$SEED_DIR/configuration.nix" /mnt/etc/nixos/configuration.nix26-27-# Bake the injected nina binary (prove-the-loop: absolute-path /root/nina).28-install -Dm755 "$SEED_DIR/nina" /mnt/root/nina29-30-nixos-install --no-root-passwd --root /mnt31-32-echo "=== NINA_INSTALL_DONE ==="33-sync34-poweroff

view file at the parent

test/vm/run-in-vm.sh+0 −65
@@ -1,65 +0,0 @@1-#!/usr/bin/env bash2-# Run a test script inside a throwaway overlay of the golden image, injecting a3-# fresh nina binary so we test the latest build without rebaking the golden.4-# The script's serial output is captured (this command's stdout); the overlay is5-# discarded afterward, leaving the golden untouched.6-#7-# Usage: run-in-vm.sh <golden.qcow2> <nina-linux-binary> <test-script.sh>8-# Tunables via env: MEM_MB (2048), SMP (2), RUN_TIMEOUT (1800)9-set -euo pipefail10-11-GOLDEN="${1:?usage: run-in-vm.sh <golden.qcow2> <nina-bin> <test-script>}"12-NINA="${2:?need nina binary}"13-SCRIPT="${3:?need test script}"14-MEM_MB="${MEM_MB:-2048}"15-SMP="${SMP:-2}"16-RUN_TIMEOUT="${RUN_TIMEOUT:-1800}"17-for f in "$GOLDEN" "$NINA" "$SCRIPT"; do [ -f "$f" ] || { echo "missing: $f" >&2; exit 1; }; done18-19-work="$(mktemp -d)"20-trap 'rm -rf "$work"' EXIT21-seed="$work/seed"; mkdir -p "$seed"22-cp "$NINA" "$seed/nina"23-cp "$SCRIPT" "$seed/runtest.sh"24-SEED_ISO="$work/seed.iso"25-hdiutil makehybrid -quiet -iso -joliet -default-volume-name NINASEED -o "$SEED_ISO" "$seed"26-27-overlay="$work/overlay.qcow2"28-qemu-img create -f qcow2 -b "$(cd "$(dirname "$GOLDEN")" && pwd)/$(basename "$GOLDEN")" -F qcow2 "$overlay" >/dev/null29-echo "throwaway overlay: $overlay  (backing: $GOLDEN)"30-31-export RV_OVERLAY="$overlay" RV_SEED="$SEED_ISO" RV_MEM="$MEM_MB" RV_SMP="$SMP" RV_TIMEOUT="$RUN_TIMEOUT"32-33-expect -c '34-  set timeout 60035-  set overlay $env(RV_OVERLAY)36-  set seed    $env(RV_SEED)37-  set mem     $env(RV_MEM)38-  set smp     $env(RV_SMP)39-  set runto   $env(RV_TIMEOUT)40-41-  spawn qemu-system-x86_64 \42-    -machine q35 -accel tcg -cpu max -smp $smp -m $mem \43-    -drive file=$overlay,if=virtio,format=qcow2 \44-    -drive file=$seed,media=cdrom,readonly=on \45-    -netdev user,id=n0 -device virtio-net-pci,netdev=n0 \46-    -nographic47-48-  expect {49-    timeout { puts "\n!! no autologin on serial"; exit 2 }50-    "automatic login" {}51-  }52-  sleep 653-  send "mkdir -p /mnt-seed && mount /dev/sr0 /mnt-seed && install -m755 /mnt-seed/nina /root/nina && echo KILN_RUN_BEGIN\r"54-  expect { timeout { puts "\n!! seed/nina setup failed"; exit 3 } "KILN_RUN_BEGIN" {} }55-  send "sh /mnt-seed/runtest.sh; echo KILN_RUN_END_RC=\$?\r"56-  set timeout $runto57-  expect {58-    timeout { puts "\n!! test script timed out"; exit 4 }59-    -re {KILN_RUN_END_RC=[0-9]+} {}60-  }61-  send "poweroff\r"62-  set timeout 12063-  expect eof64-'65-echo "=== overlay discarded; golden unchanged ==="

view file at the parent

test/vm/tests/cfgsearch.sh+0 −32
@@ -1,32 +0,0 @@1-#!/usr/bin/env sh2-# Run 2 for the previously-failing G-06/G-07 commands (fmt, doctor, diff) now that3-# the golden ships nixpkgs-fmt + enables nix-command/flakes, plus G-04 search.4-set -u5-N=/root/nina6-7-echo "KILN_CS2_BEGIN"8-9-# Second generation so diff has something to compare.10-sed -i 's| ./hardware-configuration.nix | ./hardware-configuration.nix ./genmarker.nix |' /etc/nixos/configuration.nix11-printf '{ ... }: { environment.etc."nina-gen".text = "Y"; }\n' > /etc/nixos/genmarker.nix12-$N apply >/dev/null 2>&1; echo "setup apply rc=$?"13-14-echo "### G-06 T-084 nina fmt (expect :: done, exit 0)"15-$N fmt; echo "FMT_RC=$?"16-echo "### G-06 T-085 nina fmt --check (expect ok, exit 0)"17-$N fmt --check; echo "FMTCHK_RC=$?"18-19-echo "### G-07 T-094 nina doctor (expect config syntax ok now)"20-$N doctor; echo "DOCTOR_RC=$?"21-22-echo "### G-07 T-091 nina diff (expect closure changes, no nix-command error)"23-$N diff; echo "DIFF_RC=$?"24-25-echo "### G-04 T-040 nina search firefox (expect firefox + version)"26-$N search firefox; echo "SEARCH_FF_RC=$?"27-echo "### G-04 T-041 nina search ripgrep"28-$N search ripgrep; echo "SEARCH_RG_RC=$?"29-echo "### G-04 T-055 nina search nonexistent (expect clean no-results, no crash)"30-$N search xyzzy-nope-abc123; echo "SEARCH_NONE_RC=$?"31-32-echo "KILN_CS2_END"

view file at the parent

test/vm/tests/cfgstatus.sh+0 −43
@@ -1,43 +0,0 @@1-#!/usr/bin/env sh2-# G-06 (config: check/fmt) + G-07 (status/info/doctor/boot/log/diff) validation,3-# run inside the VM on the current golden (no flakes/formatter needed except fmt,4-# which is expected to surface a missing-tool finding). Creates one extra5-# generation so diff/history have something to compare.6-set -u7-N=/root/nina8-9-echo "KILN_CS_BEGIN"10-11-# Make a 2nd generation so diff/log have content.12-sed -i 's| ./hardware-configuration.nix | ./hardware-configuration.nix ./genmarker.nix |' /etc/nixos/configuration.nix13-printf '{ ... }: { environment.etc."nina-gen".text = "X"; }\n' > /etc/nixos/genmarker.nix14-$N apply >/dev/null 2>&1; echo "setup apply rc=$?"15-16-echo "### G-06 T-082 nina check (valid config; expect :: ok, exit 0)"17-$N check; echo "CHECK_RC=$?"18-19-echo "### G-06 T-084 nina fmt (expect format /etc/nixos/configuration.nix)"20-$N fmt; echo "FMT_RC=$?"21-22-echo "### G-06 T-085 nina fmt --check (expect ok after fmt)"23-$N fmt --check; echo "FMTCHK_RC=$?"24-25-echo "### G-07 T-090 nina status"26-$N status; echo "STATUS_RC=$?"27-28-echo "### G-07 T-096 nina info (expect nixos version, kernel, uptime)"29-$N info; echo "INFO_RC=$?"30-31-echo "### G-07 T-094 nina doctor"32-$N doctor; echo "DOCTOR_RC=$?"33-34-echo "### G-07 T-097 nina boot (expect boot entries, current marked)"35-$N boot; echo "BOOT_RC=$?"36-37-echo "### G-07 T-093 nina log (expect operation history)"38-$N log; echo "LOG_RC=$?"39-40-echo "### G-07 T-091 nina diff (expect gen N -> N+1 changes)"41-$N diff; echo "DIFF_RC=$?"42-43-echo "KILN_CS_END"

view file at the parent

test/vm/tests/flakeupdate.sh+0 −39
@@ -1,39 +0,0 @@1-#!/usr/bin/env sh2-# G-08 update + G-10 flakes/build/run/repl/develop. Flake ops run in a fresh3-# flake dir. repl/develop are interactive (nix repl / nix shell) — `</dev/null`4-# feeds EOF so they exit. develop uses a `run` subcommand (nina develop run CMD),5-# not --run.6-set -u7-N=/root/nina8-9-echo "KILN_FLAKE_BEGIN"10-11-echo "### G-08 T-100 nina update (nix-channel --update; network)"12-$N update </dev/null; echo "UPDATE_RC=$?"13-14-mkdir -p /root/tf && cd /root/tf || exit 915-echo "### G-10 T-120 nina flake init (expect flake.nix)"16-$N flake init </dev/null; echo "FLAKEINIT_RC=$?"; echo "flake.nix: $(ls flake.nix 2>/dev/null || echo MISSING)"17-18-echo "### G-10 T-123 nina flake show"19-$N flake show </dev/null; echo "FLAKESHOW_RC=$?"20-21-echo "### G-10 T-122 nina flake check"22-$N flake check </dev/null; echo "FLAKECHECK_RC=$?"23-24-echo "### G-10 T-121 nina flake update (expect flake.lock)"25-$N flake update </dev/null; echo "FLAKEUPD_RC=$?"; echo "flake.lock: $(ls flake.lock 2>/dev/null || echo MISSING)"26-27-echo "### G-10 T-125 nina build (expect result symlink)"28-$N build </dev/null; echo "BUILD_RC=$?"; echo "result: $(ls -l result 2>/dev/null | awk '{print $NF}' || echo MISSING)"29-30-echo "### G-10 T-126 nina run nixpkgs#hello (expect Hello, world!)"31-$N run nixpkgs#hello </dev/null; echo "RUN_RC=$?"32-33-echo "### G-10 T-128 nina repl (EOF exits)"34-$N repl </dev/null; echo "REPL_RC=$?"35-36-echo "### G-10 T-130 nina develop run 'echo devshell-ok'"37-$N develop run 'echo devshell-ok' </dev/null; echo "DEVRUN_RC=$?"38-39-echo "KILN_FLAKE_END"

view file at the parent

test/vm/tests/gen.sh+0 −41
@@ -1,41 +0,0 @@1-#!/usr/bin/env sh2-# G-01/G-02/G-03 generations validation, run inside the VM. Creates distinct3-# system generations by changing the config between applies (a tiny /etc file via4-# an imported module), then exercises history/current/back/go/clean. Prints5-# nina's output beside ground-truth system-profile state for host-side judging.6-set -u7-N=/root/nina8-9-sysgens() { nix-env -p /nix/var/nix/profiles/system --list-generations 2>/dev/null | wc -l | tr -d ' '; }10-syscur()  { readlink /nix/var/nix/profiles/system | sed -n 's/.*system-\([0-9][0-9]*\)-link/\1/p'; }11-mkgen()   { printf '{ ... }: { environment.etc."nina-gen".text = "%s"; }\n' "$1" > /etc/nixos/genmarker.nix; }12-13-echo "KILN_GEN_TEST_BEGIN"14-15-# Import a marker module so each content change yields a new system generation.16-sed -i 's| ./hardware-configuration.nix | ./hardware-configuration.nix ./genmarker.nix |' /etc/nixos/configuration.nix17-echo "imports now: $(grep -o 'imports = .*];' /etc/nixos/configuration.nix)"18-echo "GROUND before: sysgens=$(sysgens) syscur=$(syscur)"19-20-echo "### G-01 apply x3 with config changes (expect generations to increment)"21-mkgen A; $N apply; echo "APPLY_A_RC=$?"; echo "GROUND: sysgens=$(sysgens) syscur=$(syscur)"22-mkgen B; $N apply; echo "APPLY_B_RC=$?"; echo "GROUND: sysgens=$(sysgens) syscur=$(syscur)"23-mkgen C; $N apply; echo "APPLY_C_RC=$?"; echo "GROUND: sysgens=$(sysgens) syscur=$(syscur)"24-25-echo "### T-015 nina history (expect all system generations, current marked)"26-$N history; echo "HIST_RC=$?"27-28-echo "### T-017 nina gen current (expect = $(syscur))"29-$N gen current; echo "GENCUR_RC=$?"30-31-echo "### T-010 nina back (expect syscur decrements by 1)"32-$N back; echo "BACK_RC=$?"; echo "GROUND after back: syscur=$(syscur)"33-34-echo "### T-012 nina go <newest> (return forward)"35-NEWEST=$(nix-env -p /nix/var/nix/profiles/system --list-generations | awk '{print $1}' | sort -n | tail -1)36-$N go "$NEWEST"; echo "GO_RC=$?"; echo "GROUND after go $NEWEST: syscur=$(syscur)"37-38-echo "### T-030 nina clean (keep 5; expect exit 0, no duration error)"39-$N clean; echo "CLEAN_RC=$?"; echo "GROUND after clean: sysgens=$(sysgens)"40-41-echo "KILN_GEN_TEST_END"

view file at the parent

test/vm/tests/install.sh+0 −30
@@ -1,30 +0,0 @@1-#!/usr/bin/env sh2-# G-05 install/remove/try. nina install reads a profile/system choice from stdin3-# and defaults to PROFILE install on EOF, so `</dev/null` drives it4-# non-interactively. install runs `nix search` first (memory-heavy → needs5-# MEM_MB>=6144). Uses ripgrep (already in the system closure → no rebuild) and6-# hello (tiny); firefox/etc. would work but are slow under TCG. The 's' system7-# path opens an editor and is intentionally not exercised.8-set -u9-N=/root/nina10-11-echo "KILN_G05_BEGIN"12-13-echo "### T-071 nina install ripgrep (profile; stdin EOF -> default profile)"14-$N install ripgrep </dev/null; echo "INSTALL_RG_RC=$?"15-echo "rg in profile: $(ls /root/.nix-profile/bin/rg 2>/dev/null || echo MISSING)"16-17-echo "### nina profile list (expect ripgrep present)"18-$N profile list </dev/null; echo "PROFLIST_RC=$?"19-20-echo "### T-074 nina remove ripgrep (profile)"21-$N remove ripgrep </dev/null; echo "REMOVE_RC=$?"22-echo "rg after remove: $(ls /root/.nix-profile/bin/rg 2>/dev/null || echo GONE)"23-24-echo "### T-076 nina try hello (nix shell; stdin EOF exits the shell)"25-$N try hello </dev/null; echo "TRY_RC=$?"26-27-echo "### T-072 nina install nonexistent (expect 'not found', exit 1)"28-$N install xyzzy-nope-abc123 </dev/null; echo "INSTALL_NONE_RC=$?"29-30-echo "KILN_G05_END"

view file at the parent

test/vm/tests/local.sh+0 −38
@@ -1,38 +0,0 @@1-#!/usr/bin/env sh2-# G-05 (list) + G-09 (services) + G-11 (store/channel/profile/pkg/hash) — the3-# non-interactive local commands. install/remove/try are interactive (prompt or4-# spawn a shell) and are validated separately. `service logs` must use --last5-# (bare logs follows with journalctl -f and would hang).6-set -u7-N=/root/nina8-9-echo "KILN_LOCAL_BEGIN"10-11-echo "### G-05 T-077 nina list (expect baseline packages)"12-$N list </dev/null; echo "LIST_RC=$?"13-14-echo "### G-09 T-110 nina service list (expect sshd active)"15-$N service list </dev/null; echo "SVCLIST_RC=$?"16-echo "### G-09 T-111 nina service status sshd"17-$N service status sshd </dev/null; echo "SVCSTATUS_RC=$?"18-echo "### G-09 T-113 nina service restart sshd"19-$N service restart sshd </dev/null; echo "SVCRESTART_RC=$?"20-echo "### G-09 T-115 nina service logs sshd --last 10"21-$N service logs sshd --last 10 </dev/null; echo "SVCLOGS_RC=$?"22-23-echo "### G-11 T-140 nina store info"24-$N store info </dev/null; echo "STOREINFO_RC=$?"25-echo "### G-11 T-143 nina store path ripgrep"26-$N store path ripgrep </dev/null; echo "STOREPATH_RC=$?"27-echo "### G-11 T-144 nina channel list"28-$N channel list </dev/null; echo "CHANNEL_RC=$?"29-echo "### G-11 T-145 nina profile list"30-$N profile list </dev/null; echo "PROFILE_RC=$?"31-echo "### G-11 T-148 nina pkg size ripgrep"32-$N pkg size ripgrep </dev/null; echo "PKGSIZE_RC=$?"33-echo "### G-11 T-150 nina hash <file>"34-echo hello > /tmp/h; $N hash /tmp/h </dev/null; echo "HASH_RC=$?"35-echo "### G-11 T-142 nina store gc"36-$N store gc </dev/null; echo "STOREGC_RC=$?"37-38-echo "KILN_LOCAL_END"

view file at the parent

test/vm/tests/multimachine.sh+0 −58
@@ -1,58 +0,0 @@1-#!/usr/bin/env sh2-# G-12 multi-machine ROUTING validation via SSH-to-self: test-remote points at3-# 127.0.0.1, so `--on test-remote` exercises nina's full SSH routing (build ssh4-# argv, connect, run remotely, parse output) and `status --all` aggregation.5-# CAVEAT: test-remote IS this machine, so this validates the --on plumbing, NOT6-# physical isolation (separate generation counts need two real networked VMs).7-set -u8-N=/root/nina9-10-echo "KILN_MM_BEGIN"11-12-mkdir -p /root/.ssh && chmod 700 /root/.ssh13-ssh-keygen -t ed25519 -N '' -f /root/.ssh/id_test </dev/null >/dev/null 2>&114-cat /root/.ssh/id_test.pub >> /root/.ssh/authorized_keys15-chmod 600 /root/.ssh/authorized_keys16-17-cat > /root/.nina.conf <<EOF18-editor      = vim19-generations = 520-confirm     = false21-teach       = true22-color       = true23-24-[machine]25-name    = test-primary26-config  = /etc/nixos27-local   = true28-default = true29-30-[machine]31-name    = test-remote32-host    = 127.0.0.133-user    = root34-ssh_key = /root/.ssh/id_test35-EOF36-37-echo "### T-153 nina hello (test-primary local, test-remote ssh)"38-$N hello </dev/null; echo "HELLO_RC=$?"39-40-echo "### T-160 nina status --all (both machines in table)"41-$N status --all </dev/null; echo "STATUSALL_RC=$?"42-43-echo "### T-164 nina history --on test-remote (via ssh)"44-$N history --on test-remote </dev/null; echo "HISTREMOTE_RC=$?"45-46-echo "### T-166 nina service list --on test-remote (via ssh)"47-$N service list --on test-remote </dev/null; echo "SVCREMOTE_RC=$?"48-49-echo "### T-165 nina doctor --on test-remote (via ssh)"50-$N doctor --on test-remote </dev/null; echo "DOCTORREMOTE_RC=$?"51-52-echo "### T-162 nina apply --on test-remote (ssh -> nixos-rebuild switch on self)"53-$N apply --on test-remote </dev/null; echo "APPLYREMOTE_RC=$?"54-55-echo "### T-167 nina status --on ghost-machine (expect error)"56-$N status --on ghost-machine </dev/null; echo "GHOST_RC=$?"57-58-echo "KILN_MM_END"

view file at the parent

test/vm/tests/search.sh+0 −20
@@ -1,20 +0,0 @@1-#!/usr/bin/env sh2-# G-04 search validation. `nix search nixpkgs` evaluates all of nixpkgs and is3-# memory-hungry — run this with a larger MEM_MB (see run-in-vm.sh) than the4-# brief's 2 GB, which OOMs.5-set -u6-N=/root/nina7-8-echo "KILN_SEARCH_BEGIN"9-free -m | head -210-11-echo "### T-040 nina search firefox (expect firefox + version + description)"12-$N search firefox </dev/null; echo "SEARCH_FF_RC=$?"13-14-echo "### T-041 nina search ripgrep"15-$N search ripgrep </dev/null; echo "SEARCH_RG_RC=$?"16-17-echo "### T-055 nina search nonexistent (expect clean no-results, no crash)"18-$N search xyzzy-nope-abc123 </dev/null; echo "SEARCH_NONE_RC=$?"19-20-echo "KILN_SEARCH_END"

view file at the parent