installer-iso: give the auto-install service the full system PATH

The staged installer booted, the auto-install service picked up terra's host
key and removed its temporary UEFI entry — then died before running anything:

  env: 'bash': No such file or directory   (status 127)

The service ran with the restricted PATH a `path = [...]` list produces, which
has no bash — so `./scripts/deploy`'s `#!/usr/bin/env bash` shebang could not
resolve, let alone the nix / nixos-install / git / sudo it then calls.

Point the unit's PATH at /run/current-system/sw/bin (+ /run/wrappers/bin for
sudo), which carries the whole installer toolset. mkForce because NixOS
otherwise derives environment.PATH from `path` and that line would win. HOME
moves into the same environment attr.

Verified: environment renders {HOME=/root,
PATH=/run/current-system/sw/bin:/run/wrappers/bin}, and sw/bin contains bash,
nix, nixos-install, git, sudo, efibootmgr, mount, grep, sed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-24 11:21:13 +02:00
co-authored by Claude Opus 4.8
parent f675c628a8
commit 2543a1246b
+19 -9
View File
@@ -199,7 +199,7 @@
inherit system; inherit system;
modules = [ modules = [
(nixpkgs + "/nixos/modules/installer/cd-dvd/installation-cd-minimal.nix") (nixpkgs + "/nixos/modules/installer/cd-dvd/installation-cd-minimal.nix")
({ pkgs, ... }: { ({ pkgs, lib, ... }: {
services.openssh.enable = true; services.openssh.enable = true;
services.openssh.settings.PermitRootLogin = "prohibit-password"; services.openssh.settings.PermitRootLogin = "prohibit-password";
users.users.root.openssh.authorizedKeys.keys = [ users.users.root.openssh.authorizedKeys.keys = [
@@ -265,15 +265,25 @@
after = [ "homelab-checkout.service" ]; after = [ "homelab-checkout.service" ];
requires = [ "homelab-checkout.service" ]; requires = [ "homelab-checkout.service" ];
wantedBy = [ "multi-user.target" ]; wantedBy = [ "multi-user.target" ];
path = [ pkgs.gnugrep pkgs.gnused pkgs.util-linux pkgs.coreutils pkgs.git pkgs.efibootmgr ];
serviceConfig.Type = "oneshot"; serviceConfig.Type = "oneshot";
# systemd does NOT set $HOME for a system service without User= # Full system PATH, not the restricted default a `path = [...]`
# (systemd.exec(5): SetLoginEnvironment= "defaults to true if # produces: this unit execs `./scripts/deploy`, whose
# User=, DynamicUser= or PAMName= are set, false otherwise"), and # `#!/usr/bin/env bash` needs bash, and which then reaches for
# scripts/deploy runs under `set -u`. Without this the whole # nix / nixos-install / git / sudo / efibootmgr. The default
# unattended run died on the bare $HOME expansion with an # service PATH gave "env: 'bash': No such file or directory"
# "unbound variable" that reads like a bug in the script. # (status 127) before the script even started.
serviceConfig.Environment = "HOME=/root"; # /run/current-system/sw/bin carries all of it on the installer;
# /run/wrappers/bin for sudo. mkForce because NixOS otherwise
# derives environment.PATH from `path` and that line would win.
#
# HOME too: systemd sets no $HOME for a service without User=
# (systemd.exec(5): SetLoginEnvironment= defaults false), and
# scripts/deploy runs under `set -u`, so a bare $HOME aborted the
# whole run with an "unbound variable" that read like a bug.
environment = {
HOME = "/root";
PATH = lib.mkForce "/run/current-system/sw/bin:/run/wrappers/bin";
};
script = '' script = ''
cfg=$(grep -o 'homelab\.install=[^ ]*' /proc/cmdline | cut -d= -f2 || true) cfg=$(grep -o 'homelab\.install=[^ ]*' /proc/cmdline | cut -d= -f2 || true)
if [ -z "$cfg" ]; then if [ -z "$cfg" ]; then