deploy: make the local reinstall path actually work, and fail closed

The `install <config> localhost` auto-path added in 0ea9020 could not have
completed. Fixed three blockers plus the guard that was silently not guarding.

Inside installer-iso the run died before doing anything:
  - systemd sets no $HOME for a service without User= (SetLoginEnvironment=
    defaults to false), and this script runs under `set -u`, so it aborted on
    the bare $HOME with "unbound variable". Added $KEYDIR + Environment=HOME.
  - the host key it needs to seed /etc/ssh isn't on the ISO at all — that is
    built from a public repo and carries no credentials on purpose. It now
    travels on the boot partition, located via homelab.keypart=<PARTUUID> on
    the kernel cmdline, and dies with the disko wipe minutes later. Without
    it sops can't decrypt on boot #1 and mutableUsers locks darman for good.
  - installation-cd-minimal leaves experimental-features unset, so both
    `nix run` and `nixos-install --flake` failed. (The nixos-images kexec
    installer sets them itself, which is why the same branch worked after
    kexec-local but not from the ISO.)

The staging-dir guard passed everything on btrfs: findmnt prints the
subvolume as /dev/sdb2[/@], lsblk can't open that, and an empty parent was
treated as "different disk" — so it allowed staging the iso on the very disk
disko then wiped. terra's current CachyOS root is exactly that layout. Now
uses --nofsroot, resolves EVERY whole-disk ancestor (LVM/RAID span several:
/mnt/ssd_01 -> sdd+sde), and treats "can't tell" as a hard error. btrfs
staging is refused outright — stage-1 mounts a btrfs volume's top level, so
an iso inside a subvolume is unreachable.

findiso= lost its leading slash whenever the staging mountpoint was /,
giving /findisovar/tmp/x.iso and an emergency shell after the reboot.

Also:
  - confirm before rebooting, like flash/kexec-local already do; --yes skips
    it and is what the ISO passes itself
  - $BOOT from `bootctl --print-boot-path`, not a hardcoded /boot
  - free-space checks on both target partitions before the ~1GB copy
  - `nix run .#disko` / `.#nixos-anywhere` from locked inputs instead of
    github:... master-of-the-day, resolved while a disk is being wiped
  - one_match warns instead of silently taking [0]; require_tracked covers
    every hosts/<config>/*.nix; flash traps its mount
  - drop nixos-images' `inputs.nixpkgs.follows` — that input doesn't exist,
    it only printed a warning on every nix command

Verified: the prepare path exercised under stubs against this box's real
disks (btrfs-on-OS-disk, tmpfs, LVM, subdirectory), shellcheck clean, all
six configs evaluate, checks.kexec-local still passes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-24 02:25:14 +02:00
co-authored by Claude Opus 4.8
parent 0ea90200b4
commit e538788907
5 changed files with 418 additions and 97 deletions
Generated
+77 -18
View File
@@ -179,9 +179,63 @@
"type": "github"
}
},
"nix-vm-test": {
"inputs": {
"nixpkgs": [
"nixos-anywhere",
"nixpkgs"
]
},
"locked": {
"lastModified": 1783265394,
"narHash": "sha256-cq4YfNFGYzp0NItZP8tEC7xUI8OSgY4fj75AU/NSaPM=",
"owner": "numtide",
"repo": "nix-vm-test",
"rev": "1a587212d2ac8b669c6c32499015f996506b6ba5",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "nix-vm-test",
"type": "github"
}
},
"nixos-anywhere": {
"inputs": {
"disko": [
"disko"
],
"nix-vm-test": "nix-vm-test",
"nixos-images": [
"nixos-images"
],
"nixos-stable": [
"nixpkgs"
],
"nixpkgs": [
"nixpkgs"
],
"treefmt-nix": "treefmt-nix"
},
"locked": {
"lastModified": 1784704708,
"narHash": "sha256-xuzg2Xfalr1X5ah5IPgqB8Vyif+2je1qkCtGxCB+rm0=",
"owner": "nix-community",
"repo": "nixos-anywhere",
"rev": "91fc9b70fc295258c366cce8627efb6f185fd9fb",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "nixos-anywhere",
"type": "github"
}
},
"nixos-images": {
"inputs": {
"nixos-stable": "nixos-stable",
"nixos-stable": [
"nixpkgs"
],
"nixos-unstable": "nixos-unstable"
},
"locked": {
@@ -198,23 +252,6 @@
"type": "github"
}
},
"nixos-stable": {
"locked": {
"lastModified": 1783389287,
"narHash": "sha256-0xIy4dVLqq47rA+mRy0hXDfjhQd4E5PoIns/RmB7nR4=",
"ref": "nixos-26.05",
"rev": "0ad6f47ea4fe188f4bc8f0380f93ae8523337c6c",
"shallow": true,
"type": "git",
"url": "https://github.com/NixOS/nixpkgs"
},
"original": {
"ref": "nixos-26.05",
"shallow": true,
"type": "git",
"url": "https://github.com/NixOS/nixpkgs"
}
},
"nixos-unstable": {
"locked": {
"lastModified": 1782175435,
@@ -421,6 +458,7 @@
"disko": "disko",
"home-manager": "home-manager",
"mediamanager-nix": "mediamanager-nix",
"nixos-anywhere": "nixos-anywhere",
"nixos-images": "nixos-images",
"nixpkgs": "nixpkgs_2",
"nixpkgs-unstable": "nixpkgs-unstable",
@@ -480,6 +518,27 @@
"url": "ssh://gitea@git.mgaction.town:2222/darman/TOME.git"
}
},
"treefmt-nix": {
"inputs": {
"nixpkgs": [
"nixos-anywhere",
"nixpkgs"
]
},
"locked": {
"lastModified": 1784369104,
"narHash": "sha256-47cxbcZODibHv3rELFQ9vZly0vUNkND/atn/U7HLeb0=",
"owner": "numtide",
"repo": "treefmt-nix",
"rev": "df3c0640565d04a0261253cdd89fce78ec50168a",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "treefmt-nix",
"type": "github"
}
},
"uv2nix": {
"inputs": {
"nixpkgs": [