summaryrefslogtreecommitdiffstats
path: root/nixos/tests/appliance-repart-image-verity-store.nix
blob: 46c4c10bfcf11618f787e2d105107d613b626bbf (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
# similar to the appliance-repart-image test but with a dm-verity
# protected nix store and tmpfs as rootfs
{ lib, ... }:

{
  name = "appliance-repart-image-verity-store";

  meta.maintainers = with lib.maintainers; [
    nikstur
    willibutz
  ];

  defaults =
    { config, lib, ... }:
    let
      inherit (config.image.repart.verityStore) partitionIds;
    in
    {
      imports = [ ../modules/image/repart.nix ];

      virtualisation.fileSystems = lib.mkVMOverride { };
      fileSystems = {
        "/" = {
          fsType = "tmpfs";
          options = [ "mode=0755" ];
        };
      };

      image.repart = {
        enable = true;

        verityStore = {
          enable = true;
          # by default the module works with systemd-boot, for simplicity this test directly boots the UKI
          ukiPath = "/EFI/BOOT/BOOT${lib.toUpper config.nixpkgs.hostPlatform.efiArch}.EFI";
        };

        name = "appliance-verity-store-image";

        partitions = {
          ${partitionIds.esp} = {
            # the UKI is injected into this partition by the verityStore module
            repartConfig = {
              Type = "esp";
              Format = "vfat";
              SizeMinBytes = if config.nixpkgs.hostPlatform.isx86_64 then "64M" else "96M";
            };
          };
        };
      };

      virtualisation = {
        directBoot.enable = false;
        mountHostNixStore = false;
        useEFIBoot = true;
      };

      boot = {
        loader.grub.enable = false;
        initrd.systemd.enable = true;
      };

      system.image.id = "nixos-appliance";

      # don't create /usr/bin/env
      # this would require some extra work on read-only /usr
      # and it is not a strict necessity
      system.activationScripts.usrbinenv = lib.mkForce "";
    };

  nodes.machine = {
    system.image.version = "1";
  };

  nodes.without-version = { };

  testScript =
    { nodes, ... }: # python
    ''
      import os
      import subprocess
      import tempfile

      def create_disk_image(qemu_img, backing_file):
        tmp = tempfile.NamedTemporaryFile()
        subprocess.run([
          qemu_img,
          "create",
          "-f",
          "qcow2",
          "-b",
          backing_file,
          "-F",
          "raw",
          tmp.name,
        ], check=True)
        return tmp

      def run_verity_tests(machine):
        with subtest("Running with volatile root"):
          machine.succeed("findmnt --kernel --type tmpfs /")

        with subtest("/nix/store is backed by dm-verity protected fs"):
          verity_info = machine.succeed("dmsetup info --target verity usr")
          assert "ACTIVE" in verity_info, f"unexpected verity info: {verity_info}"

          backing_device = machine.succeed("df --output=source /nix/store | tail -n1").strip()
          assert "/dev/mapper/usr" == backing_device, f"unexpected backing device: {backing_device}"

      tmp_disk_machine = create_disk_image(
        "${nodes.machine.virtualisation.qemu.package}/bin/qemu-img",
        "${nodes.machine.system.build.image}/${nodes.machine.image.filePath}",
      )
      os.environ['NIX_DISK_IMAGE'] = tmp_disk_machine.name
      machine.wait_for_unit("default.target")
      run_verity_tests(machine)
      with subtest("Image version is set"):
        machine.succeed("grep IMAGE_VERSION=1 /etc/os-release")

      tmp_disk_without_version = create_disk_image(
        "${nodes."without-version".virtualisation.qemu.package}/bin/qemu-img",
        "${nodes."without-version".system.build.image}/${nodes."without-version".image.filePath}",
      )
      os.environ['NIX_DISK_IMAGE'] = tmp_disk_without_version.name
      without_version.wait_for_unit("default.target")
      run_verity_tests(without_version)
      with subtest("Image version is not set"):
        without_version.fail('grep IMAGE_VERSION /etc/os-release')
    '';
}