Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions disk-deactivate/disk-deactivate.jq
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ def deactivate:
]
elif (.type | contains("raid")) then
[
"wipefs --all -f \(.path | shellquote)",
"mdadm --stop \(.name | shellquote)"
Copy link

Copilot AI Apr 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mdadm --stop is invoked with .name, but lsblk’s name field is typically not an absolute device path. This can make the stop command fail (and it also differs from other places in the repo that stop arrays via /dev/md/<name>). Prefer stopping the array via .path (or otherwise ensure an absolute /dev/... path is passed).

Suggested change
"mdadm --stop \(.name | shellquote)"
"mdadm --stop \(.path | shellquote)"

Copilot uses AI. Check for mistakes.
Comment on lines 61 to 64
Copy link

Copilot AI Apr 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change fixes a subtle teardown ordering bug (wipe md device signatures before stopping the array), but there’s no automated regression test ensuring destroyFormatMount actually forces a re-mkfs for filesystems on mdadm arrays (especially btrfs with backup superblocks). Consider adding a NixOS test that provisions btrfs-on-mdadm, runs destroy+recreate, and asserts the old btrfs signature/data is gone (i.e., mkfs is not skipped).

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added a NixOS test that ensures the expected behaviour. It does not use diskoLib.testLib.makeDiskoTest because that function does not test the unhappy-path possibility of files being left over from previous iterations.

]
else
Expand Down
130 changes: 130 additions & 0 deletions tests/mdadm-btrfs-wipe.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
{
pkgs,
...
}:
let
inherit (pkgs) lib;

diskoModule = ../module.nix;

diskoConfig = {
disko.devices.disk = {
main = {
device = "/dev/vdb";
type = "disk";
content = {
type = "gpt";
partitions = {
ESP = {
type = "EF00";
size = "500M";
content = {
type = "filesystem";
format = "vfat";
mountpoint = "/boot";
mountOptions = [ "umask=0077" ];
};
};
encryptedSwap = {
size = "100%";
content = {
type = "swap";
randomEncryption = true;
};
};
};
};
};
}
// (lib.genAttrs [ "pool1" "pool2" ] (name: {
type = "disk";
device =
{
pool1 = "/dev/vdc";
pool2 = "/dev/vdd";
}
.${name};
content = {
type = "gpt";
partitions.mdadm = {
size = "100%";
content = {
type = "mdraid";
name = "raid0";
};
};
};
}));

disko.devices.mdadm.raid0 = {
type = "mdadm";
level = 0;
content = {
type = "btrfs";
extraArgs = [ "-f" ];
mountpoint = "/";
};
};
};
in
pkgs.testers.runNixOSTest {
name = "disko-btrfs-mdadm-resurrection";

nodes.machine =
{ config, pkgs, ... }:
{
imports = [
diskoModule
diskoConfig
];

boot.loader.grub.devices = [ "/dev/null" ];

virtualisation.emptyDiskImages = [
4096
4096
4096
];
boot.swraid.enable = true;
environment.systemPackages = with pkgs; [
mdadm
btrfs-progs
cryptsetup
parted
];
};

testScript =
{ nodes, ... }:
let
inherit (nodes.machine.system.build) destroyScript formatScript mountScript;
in
''
machine.wait_for_unit("multi-user.target")

print("Running initial format and mount...")
machine.succeed("${formatScript}")
machine.succeed("${mountScript}")

print("Writing canary file...")
machine.succeed("echo 'I survived the wipe!' > /mnt/canary.txt")
machine.succeed("sync")

machine.succeed("umount -R /mnt")

print("Running the destroy script...")
machine.execute("${destroyScript}")

print("Attempting to reformat and remount...")
machine.execute("${formatScript}")
machine.execute("${mountScript}")

print("Checking if the canary file is still there...")
status, output = machine.execute("cat /mnt/canary.txt")

if status == 0 and "I survived the wipe!" in output:
raise Exception("The canary file survived the Disko wipe process!")
else:
print("Test passed: Data was successfully destroyed.")
'';
}
Loading