From 852ba2240fb08fde73177e0a86ef326a832a4d14 Mon Sep 17 00:00:00 2001 From: beatzaplenty Date: Sun, 26 Jul 2026 06:40:54 +1000 Subject: [PATCH 1/2] fix(create-proxmox-resource): case-insensitive importdisk parse + warn on --disk-size for VMs qm importdisk in QEMU 11.x outputs lowercase "successfully imported disk as '...'" rather than the capitalised form the original grep expected. The case mismatch made disk_id always empty, which caused the script to exit 1 after qm create had already run -- leaving the VM with only an EFI disk, no scsi0, and boot order still set to net0. Fix by adding -i (case-insensitive) to the grep. Both the old capitalised format (where the disk id had an "unused0:" prefix inside the quotes) and the new lowercase format are handled correctly: the sed strip of unused0: is preserved for backward compatibility, and the regex result is identical either way. Also add an early warning when --disk-size is passed for --type vm: the flag is LXC-only for create mode and was silently ignored, leaving users expecting a different size than the proxmoxImageSize in variables.nix. Co-Authored-By: Claude Sonnet 4.6 --- scripts/proxmox/create-proxmox-resource.sh | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/scripts/proxmox/create-proxmox-resource.sh b/scripts/proxmox/create-proxmox-resource.sh index 6c9ce4e..34d99e6 100755 --- a/scripts/proxmox/create-proxmox-resource.sh +++ b/scripts/proxmox/create-proxmox-resource.sh @@ -302,6 +302,12 @@ platform_prefix="lxc" [[ -z "$cores" ]] && cores="$PROXMOX_DEFAULT_CORES" [[ -z "$memory" ]] && memory="$PROXMOX_DEFAULT_MEMORY_MB" +if [[ "$type" == "vm" && -n "$disk_size" ]]; then + echo "WARNING: --disk-size is LXC-only for create mode and is ignored for VMs." >&2 + echo " VM disk size comes from proxmoxImageSize in variables.nix (currently ${disk_size}G was requested)." >&2 + echo " To expand after creation, use: --modify --vmid --grow-disk " >&2 +fi + # --- discover / resolve the flake target from --host -------------------- # Emits "\t" pairs for every ${platform_prefix}-* flake # target -- the one source both --list and the --host lookup below read @@ -896,7 +902,7 @@ else else importdisk_output="$(ssh "$ssh_target" "${sudo_prefix} qm importdisk ${vmid} ${remote_path} ${storage}")" echo "$importdisk_output" - disk_id="$(echo "$importdisk_output" | grep -oP "(?<=Successfully imported disk as ')[^']+" | sed 's/^unused[0-9]*://')" + disk_id="$(echo "$importdisk_output" | grep -ioP "(?<=successfully imported disk as ')[^']+" | sed 's/^unused[0-9]*://')" if [[ -z "$disk_id" ]]; then echo "ERROR: couldn't parse the imported disk identifier from qm importdisk's output above." >&2 echo "The VM shell (${vmid}) and imported disk both exist -- finish attaching it by hand:" >&2 From dfa5452af5344596cffdae5a1d8181536a4141b1 Mon Sep 17 00:00:00 2001 From: beatzaplenty Date: Sun, 26 Jul 2026 07:36:06 +1000 Subject: [PATCH 2/2] fix(common): set mutableUsers = false to fix password setup on disk images MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When a proxmox-* disk image is built, activation runs during the image build without a valid sops age key (the SSH host key doesn't exist yet), so root and nixos land in /etc/shadow with locked '!' entries. With the default mutableUsers = true, update-users-groups.pl preserves existing shadow entries for accounts that already exist, so hashedPasswordFile is silently ignored on every subsequent boot — passwords are never fixed. Setting mutableUsers = false forces update-users-groups.pl to apply hashedPasswordFile unconditionally on every activation. On first real boot the sops-decrypted hash is now written regardless of whether the account already existed in shadow from the image build. Co-Authored-By: Claude Sonnet 4.6 Claude-Session: https://claude.ai/code/session_011uRcikkTp3D5VbXj2DwNpQ --- modules/common/configuration.nix | 42 +++++++++++++++++++------------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/modules/common/configuration.nix b/modules/common/configuration.nix index cb2a757..eba6347 100644 --- a/modules/common/configuration.nix +++ b/modules/common/configuration.nix @@ -61,24 +61,32 @@ !include ${config.sops.templates."nix-github-token.conf".path} ''; - #Set root password - users.users.root = { - hashedPasswordFile = config.sops.secrets."root-hashedPassword".path; - }; + users = { + # With mutableUsers = false, update-users-groups.pl enforces hashedPasswordFile + # on every activation regardless of whether the account already exists in + # /etc/shadow. The default (true) only applies hashedPasswordFile to newly- + # created accounts — which means a freshly-built proxmox disk image (where + # activation runs without a usable sops key, so both accounts land in shadow + # with ‘!’) will never have its passwords fixed by subsequent boots. + mutableUsers = false; - # Define a user account. Don't forget to set a password with ‘passwd’. - users.users.${vars.primaryUser} = { - isNormalUser = true; - extraGroups = [ "wheel" ]; # Enable ‘sudo’ for the user. - packages = with pkgs; [ - tree - ]; - hashedPasswordFile = config.sops.secrets."nixos-hashedPassword".path; - openssh.authorizedKeys.keys = [ - vars.adminSshKey - "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICMJhrfFayLBG+gWtO6oAvgambw5nWWgztiTFEaaaVRH debian@surface" - "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGygkCljN6uKpdJbHTOQtn8ZnH+wKXDLAwrDFbLrE/65 nixos@nixos" - ]; + users.root = { + hashedPasswordFile = config.sops.secrets."root-hashedPassword".path; + }; + + users.${vars.primaryUser} = { + isNormalUser = true; + extraGroups = [ "wheel" ]; # Enable ‘sudo’ for the user. + packages = with pkgs; [ + tree + ]; + hashedPasswordFile = config.sops.secrets."nixos-hashedPassword".path; + openssh.authorizedKeys.keys = [ + vars.adminSshKey + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICMJhrfFayLBG+gWtO6oAvgambw5nWWgztiTFEaaaVRH debian@surface" + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGygkCljN6uKpdJbHTOQtn8ZnH+wKXDLAwrDFbLrE/65 nixos@nixos" + ]; + }; };