nixos/tests/installer: add grubCryptodiskLegacyBios and unbreak fullDiskEncryption

grubCryptodiskLegacyBios covers boot.loader.grub.enableCryptodisk on legacy
BIOS: GRUB itself decrypts /boot, entering the LUKS passphrase interactively,
and stage 1 then unlocks the root device with a keyfile embedded via
boot.initrd.secrets. Using a keyfile avoids a second, interactive passphrase
prompt in the initrd, whose wording differs between the scripted and systemd
stage 1 implementations, so the test passes under both (installer and
installer-systemd-stage-1).

fullDiskEncryption was marked broken. On the target boot GRUB's EFI
keyboard input appears to drop characters when the passphrase is typed at
the default speed, producing an "Invalid passphrase" error, so the disk
never unlocked. Type the passphrase more slowly and unbreak the test.

Assisted-by: Claude Opus 4.8
This commit is contained in:
Tom Fitzhenry
2026-07-22 11:34:12 +00:00
parent 889571cf97
commit 36a72f6f00
+47 -1
View File
@@ -1467,7 +1467,6 @@ in
# Full disk encryption (root, kernel and initrd encrypted) using GRUB, GPT/UEFI,
# LVM-on-LUKS and a keyfile in initrd.secrets to enter the passphrase once
fullDiskEncryption = makeInstallerTest "fullDiskEncryption" {
broken = true;
createPartitions = ''
installer.succeed(
"flock /dev/vda parted --script /dev/vda -- mklabel gpt"
@@ -1508,6 +1507,53 @@ in
'';
enableOCR = true;
postBootCommands = ''
target.wait_for_text("Enter passphrase for")
# GRUB's EFI keyboard input appears to drop characters when typed at the
# default speed (producing an "Invalid passphrase" error), so type slowly.
target.send_chars("supersecret\n", 0.2)
'';
};
# Root, kernel and initrd encrypted using GRUB cryptodisk, MBR/legacy BIOS,
# plain LUKS and a keyfile in initrd.secrets to enter the passphrase once
grubCryptodiskLegacyBios = makeInstallerTest "grubCryptodiskLegacyBios" {
meta.maintainers = [ maintainers.tomfitzhenry ];
createPartitions = ''
installer.succeed(
"flock /dev/vda parted --script /dev/vda -- mklabel msdos mkpart primary ext4 1MiB -1GiB mkpart primary linux-swap -1GiB 100%",
"udevadm settle",
"echo -n supersecret | cryptsetup luksFormat -q --pbkdf-force-iterations 1000 --type luks1 /dev/vda1 -",
"echo -n supersecret | cryptsetup luksOpen /dev/vda1 cryptroot",
"mkfs.ext4 -L nixos /dev/mapper/cryptroot",
"mkswap -L swap /dev/vda2",
"swapon -L swap",
"mount LABEL=nixos /mnt",
"mkdir -p /mnt/etc/nixos",
# Add a keyfile so stage 1 can unlock the root device without a second,
# interactive prompt. This keeps the test independent of the stage 1
# implementation, which matters because the scripted and systemd
# initrds word their passphrase prompts differently. Only GRUB (which
# is stage 1 independent) then prompts interactively.
"dd if=/dev/urandom of=/mnt/etc/nixos/luks.key bs=256 count=1",
"echo -n supersecret | cryptsetup luksAddKey -q --pbkdf-force-iterations 1000 --key-file - /dev/vda1 /mnt/etc/nixos/luks.key",
)
'';
bootLoader = "grub";
# GRUB draws its cryptodisk passphrase prompt on the console terminal
# without a trailing newline, so the line-based wait_for_console_text can
# never observe it. Use OCR (wait_for_text) to read it off the screen.
enableOCR = true;
extraConfig = ''
boot.loader.grub.enableCryptodisk = true;
boot.initrd.secrets."/luks.key" = "/etc/nixos/luks.key";
boot.initrd.luks.devices.cryptroot = {
device = lib.mkForce "/dev/vda1";
keyFile = "/luks.key";
};
'';
postBootCommands = ''
# GRUB has to unlock the disk to read /boot before it can boot the kernel;
# stage 1 then unlocks the root device with the embedded keyfile.
target.wait_for_text("Enter passphrase for")
target.send_chars("supersecret\n")
'';