about summary refs log tree commit diff
path: root/nixos
diff options
context:
space:
mode:
Diffstat (limited to 'nixos')
-rw-r--r--nixos/doc/manual/release-notes/rl-1909.section.md2
-rw-r--r--nixos/doc/manual/release-notes/rl-2405.section.md17
-rw-r--r--nixos/lib/test-driver/test_driver/machine.py2
-rw-r--r--nixos/lib/testing/meta.nix7
-rw-r--r--nixos/modules/module-list.nix1
-rw-r--r--nixos/modules/services/backup/borgbackup.nix3
-rw-r--r--nixos/modules/services/matrix/mautrix-meta.nix2
-rw-r--r--nixos/modules/services/monitoring/nezha-agent.nix103
-rw-r--r--nixos/modules/services/networking/mihomo.nix8
-rw-r--r--nixos/modules/services/web-apps/hledger-web.nix45
-rw-r--r--nixos/modules/services/x11/desktop-managers/pantheon.nix16
-rw-r--r--nixos/modules/testing/test-instrumentation.nix2
-rw-r--r--nixos/modules/virtualisation/nixos-containers.nix5
-rw-r--r--nixos/modules/virtualisation/qemu-vm.nix9
-rw-r--r--nixos/tests/all-tests.nix1
-rw-r--r--nixos/tests/containers-require-bind-mounts.nix35
-rw-r--r--nixos/tests/hledger-web.nix2
-rw-r--r--nixos/tests/installer.nix403
-rw-r--r--nixos/tests/pantheon.nix2
-rw-r--r--nixos/tests/switch-test.nix16
20 files changed, 400 insertions, 281 deletions
diff --git a/nixos/doc/manual/release-notes/rl-1909.section.md b/nixos/doc/manual/release-notes/rl-1909.section.md
index 2bd04f8dd40a3..49fc98c313ac3 100644
--- a/nixos/doc/manual/release-notes/rl-1909.section.md
+++ b/nixos/doc/manual/release-notes/rl-1909.section.md
@@ -230,7 +230,7 @@ When upgrading from a previous release, please be aware of the following incompa
 
 - The `documentation` module gained an option named `documentation.nixos.includeAllModules` which makes the generated configuration.nix 5 manual page include all options from all NixOS modules included in a given `configuration.nix` configuration file. Currently, it is set to `false` by default as enabling it frequently prevents evaluation. But the plan is to eventually have it set to `true` by default. Please set it to `true` now in your `configuration.nix` and fix all the bugs it uncovers.
 
-- The `vlc` package gained support for Chromecast streaming, enabled by default. TCP port 8010 must be open for it to work, so something like `networking.firewall.allowedTCPPorts = [ 8010 ];` may be required in your configuration. Also consider enabling [ Accelerated Video Playback](https://nixos.wiki/wiki/Accelerated_Video_Playback) for better transcoding performance.
+- The `vlc` package gained support for Chromecast streaming, enabled by default. TCP port 8010 must be open for it to work, so something like `networking.firewall.allowedTCPPorts = [ 8010 ];` may be required in your configuration. Also consider enabling [ Accelerated Video Playback](https://wiki.nixos.org/wiki/Accelerated_Video_Playback) for better transcoding performance.
 
 - The following changes apply if the `stateVersion` is changed to 19.09 or higher. For `stateVersion = "19.03"` or lower the old behavior is preserved.
 
diff --git a/nixos/doc/manual/release-notes/rl-2405.section.md b/nixos/doc/manual/release-notes/rl-2405.section.md
index 2f75ebfa4050c..5e103d323f9de 100644
--- a/nixos/doc/manual/release-notes/rl-2405.section.md
+++ b/nixos/doc/manual/release-notes/rl-2405.section.md
@@ -98,7 +98,7 @@ Use `services.pipewire.extraConfig` or `services.pipewire.configPackages` for Pi
 
 - [ollama](https://ollama.ai), server for running large language models locally.
 
-- [Mihomo](https://github.com/MetaCubeX/mihomo), a rule-based proxy in Go. Available as [services.mihomo.enable](#opt-services.mihomo.enable).
+- [Mihomo](https://github.com/MetaCubeX/mihomo/tree/Alpha), a rule-based proxy in Go. Available as [services.mihomo.enable](#opt-services.mihomo.enable).
 
 - [hebbot](https://github.com/haecker-felix/hebbot), a Matrix bot to generate "This Week in X" like blog posts. Available as [services.hebbot](#opt-services.hebbot.enable).
 
@@ -176,6 +176,8 @@ The pre-existing [services.ankisyncd](#opt-services.ankisyncd.enable) has been m
 
 - `unrar` was updated to v7. See [changelog](https://www.rarlab.com/unrar7notes.htm) for more information.
 
+- `git-town` was updated from version `11` to `13`. See the [changelog](https://github.com/git-town/git-town/blob/main/CHANGELOG.md#1300-2024-03-22) for breaking changes.
+
 - `k9s` was updated to v0.31. There have been various breaking changes in the config file format,
   check out the changelog of [v0.29](https://github.com/derailed/k9s/releases/tag/v0.29.0),
   [v0.30](https://github.com/derailed/k9s/releases/tag/v0.30.0) and
@@ -285,12 +287,21 @@ The pre-existing [services.ankisyncd](#opt-services.ankisyncd.enable) has been m
 
 - The `cudaPackages` package scope has been updated to `cudaPackages_12`.
 
+- The `halloy` package was updated past 2024.5 which introduced a breaking change by switching the config format from YAML to TOML. See https://github.com/squidowl/halloy/releases/tag/2024.5 for details.
+
 - Ada packages (libraries and tools) have been moved into the `gnatPackages` scope. `gnatPackages` uses the default GNAT compiler, `gnat12Packages` and `gnat13Packages` use the respective matching compiler version.
 
 - `spark2014` has been renamed to `gnatprove`. A version of `gnatprove` matching different GNAT versions is available from the different `gnatPackages` sets.
 
 - `services.resolved.fallbackDns` can now be used to disable the upstream fallback servers entirely by setting it to an empty list. To get the previous behaviour of the upstream defaults set it to null, the new default, instead.
 
+- `services.hledger-web.capabilities` options has been replaced by a new option `services.hledger-web.allow`.
+
+  - `allow = "view"` means `capabilities = { view = true; }`;
+  - `allow = "add"` means `capabilities = { view = true; add = true; }`;
+  - `allow = "edit"` means `capabilities = { view = true; add = true; edit = true }`;
+  - `allow = "sandstorm"` reads permissions from the `X-Sandstorm-Permissions` request header.
+
 - `xxd` has been moved from `vim` default output to its own output to reduce closure size. The canonical way to reference it across all platforms is `unixtools.xxd`.
 
 - The `stalwart-mail` package has been updated to v0.5.3, which includes [breaking changes](https://github.com/stalwartlabs/mail-server/blob/v0.5.3/UPGRADING.md).
@@ -372,12 +383,14 @@ The pre-existing [services.ankisyncd](#opt-services.ankisyncd.enable) has been m
   This means that configuration now has to be done using [environment variables](https://hexdocs.pm/livebook/readme.html#environment-variables) instead of command line arguments.
   This has the further implication that the `livebook` service configuration has changed:
 
-  - The `erlang_node_short_name`, `erlang_node_name`, `port` and `options` configuration parameters are gone, and have been replaced with an `environment` parameter.
+- The `erlang_node_short_name`, `erlang_node_name`, `port` and `options` configuration parameters are gone, and have been replaced with an `environment` parameter.
     Use the appropriate [environment variables](https://hexdocs.pm/livebook/readme.html#environment-variables) inside `environment` to configure the service instead.
 
 - The `crystal` package has been updated to 1.11.x, which has some breaking changes.
   Refer to crystal's changelog for more information. ([v1.10](https://github.com/crystal-lang/crystal/blob/master/CHANGELOG.md#1100-2023-10-09), [v1.11](https://github.com/crystal-lang/crystal/blob/master/CHANGELOG.md#1110-2024-01-08))
 
+- The `erlang-ls` package no longer ships the `els_dap` binary as of v0.51.0.
+
 ## Other Notable Changes {#sec-release-24.05-notable-changes}
 
 <!-- To avoid merge conflicts, consider adding your item at an arbitrary place in the list instead. -->
diff --git a/nixos/lib/test-driver/test_driver/machine.py b/nixos/lib/test-driver/test_driver/machine.py
index c117aab7c4011..652cc600fad59 100644
--- a/nixos/lib/test-driver/test_driver/machine.py
+++ b/nixos/lib/test-driver/test_driver/machine.py
@@ -165,8 +165,6 @@ class StartCommand:
         )
         if not allow_reboot:
             qemu_opts += " -no-reboot"
-        # TODO: qemu script already catpures this env variable, legacy?
-        qemu_opts += " " + os.environ.get("QEMU_OPTS", "")
 
         return (
             f"{self._cmd}"
diff --git a/nixos/lib/testing/meta.nix b/nixos/lib/testing/meta.nix
index 8d053ce86d888..529fe714fcf6c 100644
--- a/nixos/lib/testing/meta.nix
+++ b/nixos/lib/testing/meta.nix
@@ -34,6 +34,13 @@ in
               Sets the [`meta.broken`](https://nixos.org/manual/nixpkgs/stable/#var-meta-broken) attribute on the [{option}`test`](#test-opt-test) derivation.
             '';
           };
+          platforms = lib.mkOption {
+            type = types.listOf types.raw;
+            default = lib.platforms.linux;
+            description = ''
+              Sets the [`meta.platforms`](https://nixos.org/manual/nixpkgs/stable/#var-meta-platforms) attribute on the [{option}`test`](#test-opt-test) derivation.
+            '';
+          };
         };
       };
       default = {};
diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix
index d4e0e689e28cd..b361e9ee5e41d 100644
--- a/nixos/modules/module-list.nix
+++ b/nixos/modules/module-list.nix
@@ -842,6 +842,7 @@
   ./services/monitoring/munin.nix
   ./services/monitoring/nagios.nix
   ./services/monitoring/netdata.nix
+  ./services/monitoring/nezha-agent.nix
   ./services/monitoring/ocsinventory-agent.nix
   ./services/monitoring/opentelemetry-collector.nix
   ./services/monitoring/osquery.nix
diff --git a/nixos/modules/services/backup/borgbackup.nix b/nixos/modules/services/backup/borgbackup.nix
index 6f4455d3be605..ad6194f8262ae 100644
--- a/nixos/modules/services/backup/borgbackup.nix
+++ b/nixos/modules/services/backup/borgbackup.nix
@@ -147,6 +147,9 @@ let
     let
       settings = { inherit (cfg) user group; };
     in lib.nameValuePair "borgbackup-job-${name}" ({
+      # Create parent dirs separately, to ensure correct ownership.
+      "${config.users.users."${cfg.user}".home}/.config".d = settings;
+      "${config.users.users."${cfg.user}".home}/.cache".d = settings;
       "${config.users.users."${cfg.user}".home}/.config/borg".d = settings;
       "${config.users.users."${cfg.user}".home}/.cache/borg".d = settings;
     } // optionalAttrs (isLocalPath cfg.repo && !cfg.removableDevice) {
diff --git a/nixos/modules/services/matrix/mautrix-meta.nix b/nixos/modules/services/matrix/mautrix-meta.nix
index b8a5cdc72065b..f0905c3af1297 100644
--- a/nixos/modules/services/matrix/mautrix-meta.nix
+++ b/nixos/modules/services/matrix/mautrix-meta.nix
@@ -302,7 +302,7 @@ in {
   };
 
   config = lib.mkMerge [
-    (lib.mkIf (enabledInstances != []) {
+    (lib.mkIf (enabledInstances != {}) {
       assertions = lib.mkMerge (lib.attrValues (lib.mapAttrs (name: cfg: [
         {
           assertion = cfg.settings.homeserver.domain != "" && cfg.settings.homeserver.address != "";
diff --git a/nixos/modules/services/monitoring/nezha-agent.nix b/nixos/modules/services/monitoring/nezha-agent.nix
new file mode 100644
index 0000000000000..ef6878798f377
--- /dev/null
+++ b/nixos/modules/services/monitoring/nezha-agent.nix
@@ -0,0 +1,103 @@
+{
+  config,
+  lib,
+  pkgs,
+  ...
+}:
+let
+  cfg = config.services.nezha-agent;
+in
+{
+  meta = {
+    maintainers = with lib.maintainers; [ moraxyc ];
+  };
+  options = {
+    services.nezha-agent = {
+      enable = lib.mkEnableOption (lib.mdDoc "Agent of Nezha Monitoring");
+
+      package = lib.mkPackageOption pkgs "nezha-agent" { };
+      debug = lib.mkEnableOption (lib.mdDoc "verbose log");
+      tls = lib.mkOption {
+        type = lib.types.bool;
+        default = false;
+        description = lib.mdDoc ''
+          Enable SSL/TLS encryption.
+        '';
+      };
+      disableCommandExecute = lib.mkOption {
+        type = lib.types.bool;
+        default = true;
+        description = lib.mdDoc ''
+          Disable executing the command from dashboard.
+        '';
+      };
+      skipConnection = lib.mkOption {
+        type = lib.types.bool;
+        default = false;
+        description = lib.mdDoc ''
+          Do not monitor the number of connections.
+        '';
+      };
+      skipProcess = lib.mkOption {
+        type = lib.types.bool;
+        default = false;
+        description = lib.mdDoc ''
+          Do not monitor the number of processes.
+        '';
+      };
+      reportDelay = lib.mkOption {
+        type = lib.types.enum [ 1 2 3 4 ];
+        default = 1;
+        description = lib.mdDoc ''
+          The interval between system status reportings.
+          The value must be an integer from 1 to 4
+        '';
+      };
+      passwordFile = lib.mkOption {
+        type = with lib.types; nullOr str;
+        default = null;
+        description = lib.mdDoc ''
+          Path to the file contained the password from dashboard.
+        '';
+      };
+      server = lib.mkOption {
+        type = lib.types.str;
+        description = lib.mdDoc ''
+          Address to the dashboard
+        '';
+      };
+    };
+  };
+
+  config = lib.mkIf cfg.enable {
+    systemd.packages = [ cfg.package ];
+
+    systemd.services.nezha-agent = {
+      serviceConfig = {
+        ProtectSystem = "full";
+        PrivateDevices = "yes";
+        PrivateTmp = "yes";
+        NoNewPrivileges = true;
+      };
+      path = [ cfg.package ];
+      startLimitIntervalSec = 10;
+      startLimitBurst = 3;
+      script = lib.concatStringsSep " " (
+        [
+          "${cfg.package}/bin/agent"
+          "--disable-auto-update"
+          "--disable-force-update"
+          "--password $(cat ${cfg.passwordFile})"
+        ]
+        ++ lib.optional cfg.debug "--debug"
+        ++ lib.optional cfg.disableCommandExecute "--disable-command-execute"
+        ++ lib.optional (cfg.reportDelay != null) "--report-delay ${toString cfg.reportDelay}"
+        ++ lib.optional (cfg.server != null) "--server ${cfg.server}"
+        ++ lib.optional cfg.skipConnection "--skip-conn"
+        ++ lib.optional cfg.skipProcess "--skip-procs"
+        ++ lib.optional cfg.tls "--tls"
+      );
+      wantedBy = [ "multi-user.target" ];
+    };
+  };
+}
diff --git a/nixos/modules/services/networking/mihomo.nix b/nixos/modules/services/networking/mihomo.nix
index ae700603b5290..312530caeaade 100644
--- a/nixos/modules/services/networking/mihomo.nix
+++ b/nixos/modules/services/networking/mihomo.nix
@@ -12,7 +12,7 @@ let
 in
 {
   options.services.mihomo = {
-    enable = lib.mkEnableOption "Mihomo, A rule-based proxy in Go.";
+    enable = lib.mkEnableOption "Mihomo, A rule-based proxy in Go";
 
     package = lib.mkPackageOption pkgs "mihomo" { };
 
@@ -28,14 +28,14 @@ in
       description = ''
         Local web interface to use.
 
-        You can also use the following website, just in case:
+        You can also use the following website:
         - metacubexd:
           - https://d.metacubex.one
           - https://metacubex.github.io/metacubexd
           - https://metacubexd.pages.dev
         - yacd:
           - https://yacd.haishan.me
-        - clash-dashboard (buggy):
+        - clash-dashboard:
           - https://clash.razord.top
       '';
     };
@@ -49,7 +49,7 @@ in
     tunMode = lib.mkEnableOption ''
       necessary permission for Mihomo's systemd service for TUN mode to function properly.
 
-      Keep in mind, that you still need to enable TUN mode manually in Mihomo's configuration.
+      Keep in mind, that you still need to enable TUN mode manually in Mihomo's configuration
     '';
   };
 
diff --git a/nixos/modules/services/web-apps/hledger-web.nix b/nixos/modules/services/web-apps/hledger-web.nix
index be8ecc645e59c..2e888d081a9f9 100644
--- a/nixos/modules/services/web-apps/hledger-web.nix
+++ b/nixos/modules/services/web-apps/hledger-web.nix
@@ -26,28 +26,17 @@ in {
       '';
     };
 
-    capabilities = {
-      view = mkOption {
-        type = types.bool;
-        default = true;
-        description = lib.mdDoc ''
-          Enable the view capability.
-        '';
-      };
-      add = mkOption {
-        type = types.bool;
-        default = false;
-        description = lib.mdDoc ''
-          Enable the add capability.
-        '';
-      };
-      manage = mkOption {
-        type = types.bool;
-        default = false;
-        description = lib.mdDoc ''
-          Enable the manage capability.
-        '';
-      };
+    allow = mkOption {
+      type = types.enum [ "view" "add" "edit" "sandstorm" ];
+      default = "view";
+      description = lib.mdDoc ''
+        User's access level for changing data.
+
+        * view: view only permission.
+        * add: view and add permissions.
+        * edit: view, add, and edit permissions.
+        * sandstorm: permissions from the `X-Sandstorm-Permissions` request header.
+      '';
     };
 
     stateDir = mkOption {
@@ -89,6 +78,11 @@ in {
 
   };
 
+  imports = [
+    (mkRemovedOptionModule [ "services" "hledger-web" "capabilities" ]
+      "This option has been replaced by new option `services.hledger-web.allow`.")
+  ];
+
   config = mkIf cfg.enable {
 
     users.users.hledger = {
@@ -102,16 +96,11 @@ in {
     users.groups.hledger = {};
 
     systemd.services.hledger-web = let
-      capabilityString = with cfg.capabilities; concatStringsSep "," (
-        (optional view "view")
-        ++ (optional add "add")
-        ++ (optional manage "manage")
-      );
       serverArgs = with cfg; escapeShellArgs ([
         "--serve"
         "--host=${host}"
         "--port=${toString port}"
-        "--capabilities=${capabilityString}"
+        "--allow=${allow}"
         (optionalString (cfg.baseUrl != null) "--base-url=${cfg.baseUrl}")
         (optionalString (cfg.serveApi) "--serve-api")
       ] ++ (map (f: "--file=${stateDir}/${f}") cfg.journalFiles)
diff --git a/nixos/modules/services/x11/desktop-managers/pantheon.nix b/nixos/modules/services/x11/desktop-managers/pantheon.nix
index 2cfdc69b86e06..b9ca6bd4ba8d3 100644
--- a/nixos/modules/services/x11/desktop-managers/pantheon.nix
+++ b/nixos/modules/services/x11/desktop-managers/pantheon.nix
@@ -190,22 +190,6 @@ in
         "org.gnome.SettingsDaemon.XSettings.service"
       ];
 
-      # https://github.com/elementary/gala/issues/1826#issuecomment-1890461298
-      systemd.user.services."io.elementary.gala.daemon@" = {
-        unitConfig = {
-          Description = "Gala Daemon";
-          BindsTo = "io.elementary.gala@.service";
-          After = "io.elementary.gala@.service";
-        };
-
-        serviceConfig = {
-          Type = "dbus";
-          BusName = "org.pantheon.gala.daemon";
-          ExecStart = "${pkgs.pantheon.gala}/bin/gala-daemon";
-          Slice = "session.slice";
-        };
-      };
-
       # Global environment
       environment.systemPackages = (with pkgs.pantheon; [
         elementary-session-settings
diff --git a/nixos/modules/testing/test-instrumentation.nix b/nixos/modules/testing/test-instrumentation.nix
index 50a54a006415d..b07433f5c18fd 100644
--- a/nixos/modules/testing/test-instrumentation.nix
+++ b/nixos/modules/testing/test-instrumentation.nix
@@ -170,7 +170,7 @@ in
       # thing, but for VM tests it should provide a bit more
       # determinism (e.g. if the VM runs at lower speed, then
       # timeouts in the VM should also be delayed).
-      "clock=acpi_pm"
+      "clocksource=acpi_pm"
     ];
 
     # `xwininfo' is used by the test driver to query open windows.
diff --git a/nixos/modules/virtualisation/nixos-containers.nix b/nixos/modules/virtualisation/nixos-containers.nix
index 5db3a336f85d5..bde1ff9eeb98d 100644
--- a/nixos/modules/virtualisation/nixos-containers.nix
+++ b/nixos/modules/virtualisation/nixos-containers.nix
@@ -834,7 +834,10 @@ in
               script = startScript containerConfig;
               postStart = postStartScript containerConfig;
               serviceConfig = serviceDirectives containerConfig;
-              unitConfig.RequiresMountsFor = lib.optional (!containerConfig.ephemeral) "${stateDirectory}/%i";
+              unitConfig.RequiresMountsFor = lib.optional (!containerConfig.ephemeral) "${stateDirectory}/%i"
+                ++ builtins.map
+                  (d: if d.hostPath != null then d.hostPath else d.mountPoint)
+                  (builtins.attrValues cfg.bindMounts);
               environment.root = if containerConfig.ephemeral then "/run/nixos-containers/%i" else "${stateDirectory}/%i";
             } // (
             optionalAttrs containerConfig.autoStart
diff --git a/nixos/modules/virtualisation/qemu-vm.nix b/nixos/modules/virtualisation/qemu-vm.nix
index b5a8b08eee70d..a8e5db4f8a5ba 100644
--- a/nixos/modules/virtualisation/qemu-vm.nix
+++ b/nixos/modules/virtualisation/qemu-vm.nix
@@ -186,7 +186,7 @@ let
         NIX_EFI_VARS=$(readlink -f "''${NIX_EFI_VARS:-${config.system.name}-efi-vars.fd}")
         # VM needs writable EFI vars
         if ! test -e "$NIX_EFI_VARS"; then
-        ${if cfg.useBootLoader then
+        ${if cfg.efi.keepVariables then
             # We still need the EFI var from the make-disk-image derivation
             # because our "switch-to-configuration" process might
             # write into it and we want to keep this data.
@@ -905,6 +905,13 @@ in
             Defaults to OVMF.
           '';
       };
+
+      keepVariables = mkOption {
+        type = types.bool;
+        default = cfg.useBootLoader;
+        defaultText = literalExpression "cfg.useBootLoader";
+        description = "Whether to keep EFI variable values from the generated system image";
+      };
     };
 
     virtualisation.tpm = {
diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix
index bc586a6092712..c5af2ce1fccbc 100644
--- a/nixos/tests/all-tests.nix
+++ b/nixos/tests/all-tests.nix
@@ -219,6 +219,7 @@ in {
   containers-physical_interfaces = handleTest ./containers-physical_interfaces.nix {};
   containers-portforward = handleTest ./containers-portforward.nix {};
   containers-reloadable = handleTest ./containers-reloadable.nix {};
+  containers-require-bind-mounts = handleTest ./containers-require-bind-mounts.nix {};
   containers-restart_networking = handleTest ./containers-restart_networking.nix {};
   containers-tmpfs = handleTest ./containers-tmpfs.nix {};
   containers-unified-hierarchy = handleTest ./containers-unified-hierarchy.nix {};
diff --git a/nixos/tests/containers-require-bind-mounts.nix b/nixos/tests/containers-require-bind-mounts.nix
new file mode 100644
index 0000000000000..5f986fd3e2803
--- /dev/null
+++ b/nixos/tests/containers-require-bind-mounts.nix
@@ -0,0 +1,35 @@
+import ./make-test-python.nix ({ lib, ... }: {
+  name = "containers-require-bind-mounts";
+  meta.maintainers = with lib.maintainers; [ kira-bruneau ];
+
+  nodes.machine = {
+    containers.require-bind-mounts = {
+      bindMounts = { "/srv/data" = {}; };
+      config = {};
+    };
+
+    virtualisation.fileSystems = {
+      "/srv/data" = {
+        fsType = "tmpfs";
+        options = [ "noauto" ];
+      };
+    };
+  };
+
+  testScript = ''
+    machine.wait_for_unit("default.target")
+
+    assert "require-bind-mounts" in machine.succeed("nixos-container list")
+    assert "down" in machine.succeed("nixos-container status require-bind-mounts")
+    assert "inactive" in machine.fail("systemctl is-active srv-data.mount")
+
+    with subtest("bind mount host paths must be mounted to run container"):
+      machine.succeed("nixos-container start require-bind-mounts")
+      assert "up" in machine.succeed("nixos-container status require-bind-mounts")
+      assert "active" in machine.succeed("systemctl status srv-data.mount")
+
+      machine.succeed("systemctl stop srv-data.mount")
+      assert "down" in machine.succeed("nixos-container status require-bind-mounts")
+      assert "inactive" in machine.fail("systemctl is-active srv-data.mount")
+    '';
+})
diff --git a/nixos/tests/hledger-web.nix b/nixos/tests/hledger-web.nix
index f8919f7d4bd06..09941ca5c517c 100644
--- a/nixos/tests/hledger-web.nix
+++ b/nixos/tests/hledger-web.nix
@@ -19,7 +19,7 @@ rec {
         host = "127.0.0.1";
         port = 5000;
         enable = true;
-        capabilities.manage = true;
+        allow = "edit";
       };
       networking.firewall.allowedTCPPorts = [ config.services.hledger-web.port ];
       systemd.services.hledger-web.preStart = ''
diff --git a/nixos/tests/installer.nix b/nixos/tests/installer.nix
index 1de886d6a0d19..7e835041eb39f 100644
--- a/nixos/tests/installer.nix
+++ b/nixos/tests/installer.nix
@@ -51,7 +51,7 @@ let
           boot.loader.systemd-boot.enable = true;
         ''}
 
-        boot.initrd.secrets."/etc/secret" = ./secret;
+        boot.initrd.secrets."/etc/secret" = "/etc/nixos/secret";
 
         ${optionalString clevisTest ''
           boot.kernelParams = [ "console=tty0" "ip=192.168.1.1:::255.255.255.0::eth1:none" ];
@@ -80,39 +80,24 @@ let
   # a test script fragment `createPartitions', which must create
   # partitions and filesystems.
   testScriptFun = { bootLoader, createPartitions, grubDevice, grubUseEfi, grubIdentifier
-                  , postInstallCommands, preBootCommands, postBootCommands, extraConfig
+                  , postInstallCommands, postBootCommands, extraConfig
                   , testSpecialisationConfig, testFlakeSwitch, clevisTest, clevisFallbackTest
                   , disableFileSystems
                   }:
     let
-      qemu-common = import ../lib/qemu-common.nix { inherit (pkgs) lib pkgs; };
-      isEfi = bootLoader == "systemd-boot" || (bootLoader == "grub" && grubUseEfi);
-      qemu = qemu-common.qemuBinary pkgs.qemu_test;
-    in if !isEfi && !pkgs.stdenv.hostPlatform.isx86 then ''
-      machine.succeed("true")
-    '' else ''
+      startTarget = ''
+        ${optionalString clevisTest "tpm.start()"}
+        target.start()
+        ${postBootCommands}
+        target.wait_for_unit("multi-user.target")
+      '';
+    in ''
+      ${optionalString clevisTest ''
       import os
       import subprocess
 
       tpm_folder = os.environ['NIX_BUILD_TOP']
 
-      startcommand = "${qemu} -m 2048"
-
-      ${optionalString clevisTest ''
-        startcommand += f" -chardev socket,id=chrtpm,path={tpm_folder}/swtpm-sock -tpmdev emulator,id=tpm0,chardev=chrtpm -device tpm-tis,tpmdev=tpm0"
-        startcommand += " -device virtio-net-pci,netdev=vlan1,mac=52:54:00:12:11:02 -netdev vde,id=vlan1,sock=\"$QEMU_VDE_SOCKET_1\""
-      ''}
-      ${optionalString isEfi ''
-        startcommand +=" -drive if=pflash,format=raw,unit=0,readonly=on,file=${pkgs.OVMF.firmware} -drive if=pflash,format=raw,unit=1,readonly=on,file=${pkgs.OVMF.variables}"
-      ''}
-
-      image_dir = machine.state_dir
-      disk_image = os.path.join(image_dir, "machine.qcow2")
-      startcommand += f" -drive file={disk_image},if=virtio,werror=report"
-
-      def create_machine_named(name):
-          return create_machine(startcommand, name=name)
-
       class Tpm:
             def __init__(self):
                 self.start()
@@ -143,30 +128,31 @@ let
       os.mkdir(f"{tpm_folder}/swtpm")
       tpm = Tpm()
       tpm.check()
+      ''}
 
-      start_all()
+      installer.start()
       ${optionalString clevisTest ''
+      tang.start()
       tang.wait_for_unit("sockets.target")
       tang.systemctl("start network-online.target")
       tang.wait_for_unit("network-online.target")
-      machine.systemctl("start network-online.target")
-      machine.wait_for_unit("network-online.target")
+      installer.systemctl("start network-online.target")
+      installer.wait_for_unit("network-online.target")
       ''}
-      machine.wait_for_unit("multi-user.target")
-
+      installer.wait_for_unit("multi-user.target")
 
       with subtest("Assert readiness of login prompt"):
-          machine.succeed("echo hello")
+          installer.succeed("echo hello")
 
       with subtest("Wait for hard disks to appear in /dev"):
-          machine.succeed("udevadm settle")
+          installer.succeed("udevadm settle")
 
       ${createPartitions}
 
       with subtest("Create the NixOS configuration"):
-          machine.succeed("nixos-generate-config ${optionalString disableFileSystems "--no-filesystems"} --root /mnt")
-          machine.succeed("cat /mnt/etc/nixos/hardware-configuration.nix >&2")
-          machine.copy_from_host(
+          installer.succeed("nixos-generate-config ${optionalString disableFileSystems "--no-filesystems"} --root /mnt")
+          installer.succeed("cat /mnt/etc/nixos/hardware-configuration.nix >&2")
+          installer.copy_from_host(
               "${ makeConfig {
                     inherit bootLoader grubDevice grubIdentifier
                             grubUseEfi extraConfig clevisTest;
@@ -174,13 +160,13 @@ let
               }",
               "/mnt/etc/nixos/configuration.nix",
           )
-          machine.copy_from_host("${pkgs.writeText "secret" "secret"}", "/mnt/etc/nixos/secret")
+          installer.copy_from_host("${pkgs.writeText "secret" "secret"}", "/mnt/etc/nixos/secret")
 
       ${optionalString clevisTest ''
         with subtest("Create the Clevis secret with Tang"):
-             machine.systemctl("start network-online.target")
-             machine.wait_for_unit("network-online.target")
-             machine.succeed('echo -n password | clevis encrypt sss \'{"t": 2, "pins": {"tpm2": {}, "tang": {"url": "http://192.168.1.2"}}}\' -y > /mnt/etc/nixos/clevis-secret.jwe')''}
+             installer.systemctl("start network-online.target")
+             installer.wait_for_unit("network-online.target")
+             installer.succeed('echo -n password | clevis encrypt sss \'{"t": 2, "pins": {"tpm2": {}, "tang": {"url": "http://192.168.1.2"}}}\' -y > /mnt/etc/nixos/clevis-secret.jwe')''}
 
       ${optionalString clevisFallbackTest ''
         with subtest("Shutdown Tang to check fallback to interactive prompt"):
@@ -188,13 +174,13 @@ let
       ''}
 
       with subtest("Perform the installation"):
-          machine.succeed("nixos-install < /dev/null >&2")
+          installer.succeed("nixos-install < /dev/null >&2")
 
       with subtest("Do it again to make sure it's idempotent"):
-          machine.succeed("nixos-install < /dev/null >&2")
+          installer.succeed("nixos-install < /dev/null >&2")
 
       with subtest("Check that we can build things in nixos-enter"):
-          machine.succeed(
+          installer.succeed(
               """
               nixos-enter -- nix-build --option substitute false -E 'derivation {
                   name = "t";
@@ -209,48 +195,48 @@ let
       ${postInstallCommands}
 
       with subtest("Shutdown system after installation"):
-          machine.succeed("umount -R /mnt")
-          machine.succeed("sync")
-          machine.shutdown()
+          installer.succeed("umount -R /mnt")
+          installer.succeed("sync")
+          installer.shutdown()
 
-      # Now see if we can boot the installation.
-      machine = create_machine_named("boot-after-install")
+      # We're actually the same machine, just booting differently this time.
+      target.state_dir = installer.state_dir
 
-      # For example to enter LUKS passphrase.
-      ${preBootCommands}
+      # Now see if we can boot the installation.
+      ${startTarget}
 
       with subtest("Assert that /boot get mounted"):
-          machine.wait_for_unit("local-fs.target")
+          target.wait_for_unit("local-fs.target")
           ${if bootLoader == "grub"
-              then ''machine.succeed("test -e /boot/grub")''
-              else ''machine.succeed("test -e /boot/loader/loader.conf")''
+              then ''target.succeed("test -e /boot/grub")''
+              else ''target.succeed("test -e /boot/loader/loader.conf")''
           }
 
       with subtest("Check whether /root has correct permissions"):
-          assert "700" in machine.succeed("stat -c '%a' /root")
+          assert "700" in target.succeed("stat -c '%a' /root")
 
       with subtest("Assert swap device got activated"):
           # uncomment once https://bugs.freedesktop.org/show_bug.cgi?id=86930 is resolved
-          machine.wait_for_unit("swap.target")
-          machine.succeed("cat /proc/swaps | grep -q /dev")
+          target.wait_for_unit("swap.target")
+          target.succeed("cat /proc/swaps | grep -q /dev")
 
       with subtest("Check that the store is in good shape"):
-          machine.succeed("nix-store --verify --check-contents >&2")
+          target.succeed("nix-store --verify --check-contents >&2")
 
       with subtest("Check whether the channel works"):
-          machine.succeed("nix-env -iA nixos.procps >&2")
-          assert ".nix-profile" in machine.succeed("type -tP ps | tee /dev/stderr")
+          target.succeed("nix-env -iA nixos.procps >&2")
+          assert ".nix-profile" in target.succeed("type -tP ps | tee /dev/stderr")
 
       with subtest(
           "Check that the daemon works, and that non-root users can run builds "
           "(this will build a new profile generation through the daemon)"
       ):
-          machine.succeed("su alice -l -c 'nix-env -iA nixos.procps' >&2")
+          target.succeed("su alice -l -c 'nix-env -iA nixos.procps' >&2")
 
       with subtest("Configure system with writable Nix store on next boot"):
           # we're not using copy_from_host here because the installer image
           # doesn't know about the host-guest sharing mechanism.
-          machine.copy_from_host_via_shell(
+          target.copy_from_host_via_shell(
               "${ makeConfig {
                     inherit bootLoader grubDevice grubIdentifier
                             grubUseEfi extraConfig clevisTest;
@@ -261,25 +247,23 @@ let
           )
 
       with subtest("Check whether nixos-rebuild works"):
-          machine.succeed("nixos-rebuild switch >&2")
+          target.succeed("nixos-rebuild switch >&2")
 
       # FIXME: Nix 2.4 broke nixos-option, someone has to fix it.
       # with subtest("Test nixos-option"):
-      #     kernel_modules = machine.succeed("nixos-option boot.initrd.kernelModules")
+      #     kernel_modules = target.succeed("nixos-option boot.initrd.kernelModules")
       #     assert "virtio_console" in kernel_modules
       #     assert "List of modules" in kernel_modules
       #     assert "qemu-guest.nix" in kernel_modules
 
-      machine.shutdown()
+      target.shutdown()
 
       # Check whether a writable store build works
-      machine = create_machine_named("rebuild-switch")
-      ${preBootCommands}
-      machine.wait_for_unit("multi-user.target")
+      ${startTarget}
 
       # we're not using copy_from_host here because the installer image
       # doesn't know about the host-guest sharing mechanism.
-      machine.copy_from_host_via_shell(
+      target.copy_from_host_via_shell(
           "${ makeConfig {
                 inherit bootLoader grubDevice grubIdentifier
                 grubUseEfi extraConfig clevisTest;
@@ -288,73 +272,62 @@ let
           }",
           "/etc/nixos/configuration.nix",
       )
-      machine.succeed("nixos-rebuild boot >&2")
-      machine.shutdown()
+      target.succeed("nixos-rebuild boot >&2")
+      target.shutdown()
 
-      # And just to be sure, check that the machine still boots after
-      # "nixos-rebuild switch".
-      machine = create_machine_named("boot-after-rebuild-switch")
-      ${preBootCommands}
-      machine.wait_for_unit("network.target")
+      # And just to be sure, check that the target still boots after "nixos-rebuild switch".
+      ${startTarget}
+      target.wait_for_unit("network.target")
 
       # Sanity check, is it the configuration.nix we generated?
-      hostname = machine.succeed("hostname").strip()
+      hostname = target.succeed("hostname").strip()
       assert hostname == "thatworked"
 
-      ${postBootCommands}
-      machine.shutdown()
+      target.shutdown()
 
       # Tests for validating clone configuration entries in grub menu
     ''
     + optionalString testSpecialisationConfig ''
-      # Reboot Machine
-      machine = create_machine_named("clone-default-config")
-      ${preBootCommands}
-      machine.wait_for_unit("multi-user.target")
+      # Reboot target
+      ${startTarget}
 
       with subtest("Booted configuration name should be 'Home'"):
           # This is not the name that shows in the grub menu.
           # The default configuration is always shown as "Default"
-          machine.succeed("cat /run/booted-system/configuration-name >&2")
-          assert "Home" in machine.succeed("cat /run/booted-system/configuration-name")
+          target.succeed("cat /run/booted-system/configuration-name >&2")
+          assert "Home" in target.succeed("cat /run/booted-system/configuration-name")
 
       with subtest("We should **not** find a file named /etc/gitconfig"):
-          machine.fail("test -e /etc/gitconfig")
+          target.fail("test -e /etc/gitconfig")
 
       with subtest("Set grub to boot the second configuration"):
-          machine.succeed("grub-reboot 1")
+          target.succeed("grub-reboot 1")
 
-      ${postBootCommands}
-      machine.shutdown()
+      target.shutdown()
 
-      # Reboot Machine
-      machine = create_machine_named("clone-alternate-config")
-      ${preBootCommands}
+      # Reboot target
+      ${startTarget}
 
-      machine.wait_for_unit("multi-user.target")
       with subtest("Booted configuration name should be Work"):
-          machine.succeed("cat /run/booted-system/configuration-name >&2")
-          assert "Work" in machine.succeed("cat /run/booted-system/configuration-name")
+          target.succeed("cat /run/booted-system/configuration-name >&2")
+          assert "Work" in target.succeed("cat /run/booted-system/configuration-name")
 
       with subtest("We should find a file named /etc/gitconfig"):
-          machine.succeed("test -e /etc/gitconfig")
+          target.succeed("test -e /etc/gitconfig")
 
-      ${postBootCommands}
-      machine.shutdown()
+      target.shutdown()
     ''
     + optionalString testFlakeSwitch ''
-      ${preBootCommands}
-      machine.start()
+      ${startTarget}
 
       with subtest("Configure system with flake"):
         # TODO: evaluate as user?
-        machine.succeed("""
+        target.succeed("""
           mkdir /root/my-config
           mv /etc/nixos/hardware-configuration.nix /root/my-config/
-          mv /etc/nixos/secret /root/my-config/
           rm /etc/nixos/configuration.nix
         """)
-        machine.copy_from_host_via_shell(
+        target.copy_from_host_via_shell(
           "${makeConfig {
                inherit bootLoader grubDevice grubIdentifier grubUseEfi extraConfig clevisTest;
                forceGrubReinstallCount = 1;
@@ -362,11 +335,11 @@ let
             }}",
           "/root/my-config/configuration.nix",
         )
-        machine.copy_from_host_via_shell(
+        target.copy_from_host_via_shell(
           "${./installer/flake.nix}",
           "/root/my-config/flake.nix",
         )
-        machine.succeed("""
+        target.succeed("""
           # for some reason the image does not have `pkgs.path`, so
           # we use readlink to find a Nixpkgs source.
           pkgs=$(readlink -f /nix/var/nix/profiles/per-user/root/channels)/nixos
@@ -378,36 +351,32 @@ let
         """)
 
       with subtest("Switch to flake based config"):
-        machine.succeed("nixos-rebuild switch --flake /root/my-config#xyz")
-
-      ${postBootCommands}
-      machine.shutdown()
+        target.succeed("nixos-rebuild switch --flake /root/my-config#xyz")
 
-      ${preBootCommands}
-      machine.start()
+      target.shutdown()
 
-      machine.wait_for_unit("multi-user.target")
+      ${startTarget}
 
       with subtest("nix-channel command is not available anymore"):
-        machine.succeed("! which nix-channel")
+        target.succeed("! which nix-channel")
 
       # Note that the channel profile is still present on disk, but configured
       # not to be used.
       with subtest("builtins.nixPath is now empty"):
-        machine.succeed("""
+        target.succeed("""
           [[ "[ ]" == "$(nix-instantiate builtins.nixPath --eval --expr)" ]]
         """)
 
       with subtest("<nixpkgs> does not resolve"):
-        machine.succeed("""
+        target.succeed("""
           ! nix-instantiate '<nixpkgs>' --eval --expr
         """)
 
       with subtest("Evaluate flake config in fresh env without nix-channel"):
-        machine.succeed("nixos-rebuild switch --flake /root/my-config#xyz")
+        target.succeed("nixos-rebuild switch --flake /root/my-config#xyz")
 
       with subtest("Evaluate flake config in fresh env without channel profiles"):
-        machine.succeed("""
+        target.succeed("""
           (
             exec 1>&2
             rm -v /root/.nix-channels
@@ -415,16 +384,15 @@ let
             rm -vrf /nix/var/nix/profiles/per-user/root/channels*
           )
         """)
-        machine.succeed("nixos-rebuild switch --flake /root/my-config#xyz")
+        target.succeed("nixos-rebuild switch --flake /root/my-config#xyz")
 
-      ${postBootCommands}
-      machine.shutdown()
+      target.shutdown()
     '';
 
 
   makeInstallerTest = name:
     { createPartitions
-    , postInstallCommands ? "", preBootCommands ? "", postBootCommands ? ""
+    , postInstallCommands ? "", postBootCommands ? ""
     , extraConfig ? ""
     , extraInstallerConfig ? {}
     , bootLoader ? "grub" # either "grub" or "systemd-boot"
@@ -436,18 +404,39 @@ let
     , clevisFallbackTest ? false
     , disableFileSystems ? false
     }:
-    makeTest {
+    let
+      isEfi = bootLoader == "systemd-boot" || (bootLoader == "grub" && grubUseEfi);
+    in makeTest {
       inherit enableOCR;
       name = "installer-" + name;
       meta = {
         # put global maintainers here, individuals go into makeInstallerTest fkt call
         maintainers = (meta.maintainers or []);
+        # non-EFI tests can only run on x86
+        platforms = if isEfi then platforms.linux else [ "x86_64-linux" "i686-linux" ];
       };
-      nodes = {
+      nodes = let
+        commonConfig = {
+          # builds stuff in the VM, needs more juice
+          virtualisation.diskSize = 8 * 1024;
+          virtualisation.cores = 8;
+          virtualisation.memorySize = 2048;
+
+          # both installer and target need to use the same drive
+          virtualisation.diskImage = "./target.qcow2";
 
-        # The configuration of the machine used to run "nixos-install".
-        machine = { pkgs, ... }: {
+          # and the same TPM options
+          virtualisation.qemu.options = mkIf (clevisTest) [
+            "-chardev socket,id=chrtpm,path=$NIX_BUILD_TOP/swtpm-sock"
+            "-tpmdev emulator,id=tpm0,chardev=chrtpm"
+            "-device tpm-tis,tpmdev=tpm0"
+          ];
+        };
+      in {
+        # The configuration of the system used to run "nixos-install".
+        installer = {
           imports = [
+            commonConfig
             ../modules/profiles/installation-device.nix
             ../modules/profiles/base.nix
             extraInstallerConfig
@@ -458,11 +447,6 @@ let
           # root filesystem.
           virtualisation.fileSystems."/".autoFormat = systemdStage1;
 
-          # builds stuff in the VM, needs more juice
-          virtualisation.diskSize = 8 * 1024;
-          virtualisation.cores = 8;
-          virtualisation.memorySize = 2048;
-
           boot.initrd.systemd.enable = systemdStage1;
 
           # Use a small /dev/vdb as the root disk for the
@@ -470,17 +454,6 @@ let
           # the same during and after installation.
           virtualisation.emptyDiskImages = [ 512 ];
           virtualisation.rootDevice = "/dev/vdb";
-          virtualisation.bootLoaderDevice = "/dev/vda";
-          virtualisation.qemu.diskInterface = "virtio";
-          virtualisation.qemu.options = mkIf (clevisTest) [
-            "-chardev socket,id=chrtpm,path=$NIX_BUILD_TOP/swtpm-sock"
-            "-tpmdev emulator,id=tpm0,chardev=chrtpm"
-            "-device tpm-tis,tpmdev=tpm0"
-          ];
-          # We don't want to have any networking in the guest apart from the clevis tests.
-          virtualisation.vlans = mkIf (!clevisTest) [];
-
-          boot.loader.systemd-boot.enable = mkIf (bootLoader == "systemd-boot") true;
 
           hardware.enableAllFirmware = mkForce false;
 
@@ -520,7 +493,13 @@ let
           in [
             (pkgs.grub2.override { inherit zfsSupport; })
             (pkgs.grub2_efi.override { inherit zfsSupport; })
-          ]) ++ optionals clevisTest [ pkgs.klibc ];
+          ])
+          ++ optionals (bootLoader == "systemd-boot") [
+            pkgs.zstd.bin
+            pkgs.mypy
+            pkgs.bootspec
+          ]
+          ++ optionals clevisTest [ pkgs.klibc ];
 
           nix.settings = {
             substituters = mkForce [];
@@ -529,6 +508,18 @@ let
           };
         };
 
+        target = {
+          imports = [ commonConfig ];
+          virtualisation.useBootLoader = true;
+          virtualisation.useEFIBoot = isEfi;
+          virtualisation.useDefaultFilesystems = false;
+          virtualisation.efi.keepVariables = false;
+
+          virtualisation.fileSystems."/" = {
+            device = "/dev/disk/by-label/this-is-not-real-and-will-never-be-used";
+            fsType = "ext4";
+          };
+        };
       } // optionalAttrs clevisTest {
         tang = {
           services.tang = {
@@ -541,7 +532,7 @@ let
       };
 
       testScript = testScriptFun {
-        inherit bootLoader createPartitions postInstallCommands preBootCommands postBootCommands
+        inherit bootLoader createPartitions postInstallCommands postBootCommands
                 grubDevice grubIdentifier grubUseEfi extraConfig
                 testSpecialisationConfig testFlakeSwitch clevisTest clevisFallbackTest
                 disableFileSystems;
@@ -550,7 +541,7 @@ let
 
     makeLuksRootTest = name: luksFormatOpts: makeInstallerTest name {
       createPartitions = ''
-        machine.succeed(
+        installer.succeed(
             "flock /dev/vda parted --script /dev/vda -- mklabel msdos"
             + " mkpart primary ext2 1M 100MB"  # /boot
             + " mkpart primary linux-swap 100M 1024M"
@@ -572,10 +563,9 @@ let
         boot.kernelParams = lib.mkAfter [ "console=tty0" ];
       '';
       enableOCR = true;
-      preBootCommands = ''
-        machine.start()
-        machine.wait_for_text("[Pp]assphrase for")
-        machine.send_chars("supersecret\n")
+      postBootCommands = ''
+        target.wait_for_text("[Pp]assphrase for")
+        target.send_chars("supersecret\n")
       '';
     };
 
@@ -583,7 +573,7 @@ let
   # one big filesystem partition.
   simple-test-config = {
     createPartitions = ''
-      machine.succeed(
+      installer.succeed(
           "flock /dev/vda parted --script /dev/vda -- mklabel msdos"
           + " mkpart primary linux-swap 1M 1024M"
           + " mkpart primary ext2 1024M -1s",
@@ -602,7 +592,7 @@ let
 
   simple-uefi-grub-config = {
     createPartitions = ''
-      machine.succeed(
+      installer.succeed(
           "flock /dev/vda parted --script /dev/vda -- mklabel gpt"
           + " mkpart ESP fat32 1M 100MiB"  # /boot
           + " set 1 boot on"
@@ -656,7 +646,7 @@ let
       environment.systemPackages = with pkgs; [ keyutils clevis ];
     };
     createPartitions = ''
-      machine.succeed(
+      installer.succeed(
         "flock /dev/vda parted --script /dev/vda -- mklabel msdos"
         + " mkpart primary ext2 1M 100MB"
         + " mkpart primary linux-swap 100M 1024M"
@@ -680,13 +670,9 @@ let
       # not know the UUID in advance.
       fileSystems."/" = lib.mkForce { device = "/dev/vda3"; fsType = "bcachefs"; };
     '';
-    preBootCommands = ''
-      tpm = Tpm()
-      tpm.check()
-    '' + optionalString fallback ''
-      machine.start()
-      machine.wait_for_text("enter passphrase for")
-      machine.send_chars("password\n")
+    postBootCommands = optionalString fallback ''
+      target.wait_for_text("enter passphrase for")
+      target.send_chars("password\n")
     '';
   };
 
@@ -698,7 +684,7 @@ let
       environment.systemPackages = with pkgs; [ clevis ];
     };
     createPartitions = ''
-      machine.succeed(
+      installer.succeed(
         "flock /dev/vda parted --script /dev/vda -- mklabel msdos"
         + " mkpart primary ext2 1M 100MB"
         + " mkpart primary linux-swap 100M 1024M"
@@ -719,17 +705,13 @@ let
     extraConfig = ''
       boot.initrd.clevis.devices."crypt-root".secretFile = "/etc/nixos/clevis-secret.jwe";
     '';
-    preBootCommands = ''
-      tpm = Tpm()
-      tpm.check()
-    '' + optionalString fallback ''
-      machine.start()
+    postBootCommands = optionalString fallback ''
       ${if systemdStage1 then ''
-      machine.wait_for_text("Please enter")
+      target.wait_for_text("Please enter")
       '' else ''
-      machine.wait_for_text("Passphrase for")
+      target.wait_for_text("Passphrase for")
       ''}
-      machine.send_chars("password\n")
+      target.send_chars("password\n")
     '';
   };
 
@@ -742,7 +724,7 @@ let
       environment.systemPackages = with pkgs; [ clevis ];
     };
     createPartitions = ''
-      machine.succeed(
+      installer.succeed(
         "flock /dev/vda parted --script /dev/vda -- mklabel msdos"
         + " mkpart primary ext2 1M 100MB"
         + " mkpart primary linux-swap 100M 1024M"
@@ -770,17 +752,13 @@ let
       boot.zfs.devNodes = "/dev/disk/by-uuid/";
       networking.hostId = "00000000";
     '';
-    preBootCommands = ''
-      tpm = Tpm()
-      tpm.check()
-    '' + optionalString fallback ''
-      machine.start()
+    postBootCommands = optionalString fallback ''
       ${if systemdStage1 then ''
-      machine.wait_for_text("Enter key for rpool/root")
+      target.wait_for_text("Enter key for rpool/root")
       '' else ''
-      machine.wait_for_text("Key load error")
+      target.wait_for_text("Key load error")
       ''}
-      machine.send_chars("password\n")
+      target.send_chars("password\n")
     '';
   };
 
@@ -801,7 +779,7 @@ in {
   # Simple GPT/UEFI configuration using systemd-boot with 3 partitions: ESP, swap & root filesystem
   simpleUefiSystemdBoot = makeInstallerTest "simpleUefiSystemdBoot" {
     createPartitions = ''
-      machine.succeed(
+      installer.succeed(
           "flock /dev/vda parted --script /dev/vda -- mklabel gpt"
           + " mkpart ESP fat32 1M 100MiB"  # /boot
           + " set 1 boot on"
@@ -828,7 +806,7 @@ in {
   # Same as the previous, but now with a separate /boot partition.
   separateBoot = makeInstallerTest "separateBoot" {
     createPartitions = ''
-      machine.succeed(
+      installer.succeed(
           "flock /dev/vda parted --script /dev/vda -- mklabel msdos"
           + " mkpart primary ext2 1M 100MB"  # /boot
           + " mkpart primary linux-swap 100MB 1024M"
@@ -848,7 +826,7 @@ in {
   # Same as the previous, but with fat32 /boot.
   separateBootFat = makeInstallerTest "separateBootFat" {
     createPartitions = ''
-      machine.succeed(
+      installer.succeed(
           "flock /dev/vda parted --script /dev/vda -- mklabel msdos"
           + " mkpart primary ext2 1M 100MB"  # /boot
           + " mkpart primary linux-swap 100MB 1024M"
@@ -880,7 +858,7 @@ in {
     '';
 
     createPartitions = ''
-      machine.succeed(
+      installer.succeed(
           "flock /dev/vda parted --script /dev/vda -- mklabel msdos"
           + " mkpart primary ext2 1M 256MB"   # /boot
           + " mkpart primary linux-swap 256MB 1280M"
@@ -932,8 +910,8 @@ in {
     # umount & export bpool before shutdown
     # this is a fix for "cannot import 'bpool': pool was previously in use from another system."
     postInstallCommands = ''
-      machine.succeed("umount /mnt/boot")
-      machine.succeed("zpool export bpool")
+      installer.succeed("umount /mnt/boot")
+      installer.succeed("zpool export bpool")
     '';
   };
 
@@ -954,7 +932,7 @@ in {
     '';
 
     createPartitions = ''
-      machine.succeed(
+      installer.succeed(
           "flock /dev/vda parted --script /dev/vda -- mklabel msdos"
           + " mkpart primary 1M 100MB"  # /boot
           + " mkpart primary linux-swap 100M 1024M"
@@ -980,7 +958,7 @@ in {
   # that contains the logical swap and root partitions.
   lvm = makeInstallerTest "lvm" {
     createPartitions = ''
-      machine.succeed(
+      installer.succeed(
           "flock /dev/vda parted --script /dev/vda -- mklabel msdos"
           + " mkpart primary 1M 2048M"  # PV1
           + " set 1 lvm on"
@@ -1013,7 +991,7 @@ in {
   # keyfile is configured
   encryptedFSWithKeyfile = makeInstallerTest "encryptedFSWithKeyfile" {
     createPartitions = ''
-      machine.succeed(
+      installer.succeed(
           "flock /dev/vda parted --script /dev/vda -- mklabel msdos"
           + " mkpart primary ext2 1M 100MB"  # /boot
           + " mkpart primary linux-swap 100M 1024M"
@@ -1052,7 +1030,7 @@ in {
   # LVM-on-LUKS and a keyfile in initrd.secrets to enter the passphrase once
   fullDiskEncryption = makeInstallerTest "fullDiskEncryption" {
     createPartitions = ''
-      machine.succeed(
+      installer.succeed(
           "flock /dev/vda parted --script /dev/vda -- mklabel gpt"
           + " mkpart ESP fat32 1M 100MiB"  # /boot/efi
           + " set 1 boot on"
@@ -1083,23 +1061,22 @@ in {
       boot.loader.grub.enableCryptodisk = true;
       boot.loader.efi.efiSysMountPoint = "/boot/efi";
 
-      boot.initrd.secrets."/luks.key" = ./luks.key;
+      boot.initrd.secrets."/luks.key" = "/etc/nixos/luks.key";
       boot.initrd.luks.devices.crypt =
         { device  = "/dev/vda2";
           keyFile = "/luks.key";
         };
     '';
     enableOCR = true;
-    preBootCommands = ''
-      machine.start()
-      machine.wait_for_text("Enter passphrase for")
-      machine.send_chars("supersecret\n")
+    postBootCommands = ''
+      target.wait_for_text("Enter passphrase for")
+      target.send_chars("supersecret\n")
     '';
   };
 
   swraid = makeInstallerTest "swraid" {
     createPartitions = ''
-      machine.succeed(
+      installer.succeed(
           "flock /dev/vda parted --script /dev/vda --"
           + " mklabel msdos"
           + " mkpart primary ext2 1M 100MB"  # /boot
@@ -1128,15 +1105,14 @@ in {
           "udevadm settle",
       )
     '';
-    preBootCommands = ''
-      machine.start()
-      machine.fail("dmesg | grep 'immediate safe mode'")
+    postBootCommands = ''
+      target.fail("dmesg | grep 'immediate safe mode'")
     '';
   };
 
   bcache = makeInstallerTest "bcache" {
     createPartitions = ''
-      machine.succeed(
+      installer.succeed(
           "flock /dev/vda parted --script /dev/vda --"
           + " mklabel msdos"
           + " mkpart primary ext2 1M 100MB"  # /boot
@@ -1165,7 +1141,7 @@ in {
     };
 
     createPartitions = ''
-      machine.succeed(
+      installer.succeed(
         "flock /dev/vda parted --script /dev/vda -- mklabel msdos"
         + " mkpart primary ext2 1M 100MB"          # /boot
         + " mkpart primary linux-swap 100M 1024M"  # swap
@@ -1197,18 +1173,17 @@ in {
     '';
 
     enableOCR = true;
-    preBootCommands = ''
-      machine.start()
+    postBootCommands = ''
       # Enter it wrong once
-      machine.wait_for_text("enter passphrase for ")
-      machine.send_chars("wrong\n")
+      target.wait_for_text("enter passphrase for ")
+      target.send_chars("wrong\n")
       # Then enter it right.
-      machine.wait_for_text("enter passphrase for ")
-      machine.send_chars("password\n")
+      target.wait_for_text("enter passphrase for ")
+      target.send_chars("password\n")
     '';
 
     createPartitions = ''
-      machine.succeed(
+      installer.succeed(
         "flock /dev/vda parted --script /dev/vda -- mklabel msdos"
         + " mkpart primary ext2 1M 100MB"          # /boot
         + " mkpart primary linux-swap 100M 1024M"  # swap
@@ -1235,7 +1210,7 @@ in {
     };
 
     createPartitions = ''
-      machine.succeed(
+      installer.succeed(
         "flock /dev/vda parted --script /dev/vda -- mklabel msdos"
         + " mkpart primary ext2 1M 100MB"          # /boot
         + " mkpart primary linux-swap 100M 1024M"  # swap
@@ -1256,7 +1231,7 @@ in {
   # Test using labels to identify volumes in grub
   simpleLabels = makeInstallerTest "simpleLabels" {
     createPartitions = ''
-      machine.succeed(
+      installer.succeed(
           "sgdisk -Z /dev/vda",
           "sgdisk -n 1:0:+1M -n 2:0:+1G -N 3 -t 1:ef02 -t 2:8200 -t 3:8300 -c 3:root /dev/vda",
           "mkswap /dev/vda2 -L swap",
@@ -1273,7 +1248,7 @@ in {
   simpleProvided = makeInstallerTest "simpleProvided" {
     createPartitions = ''
       uuid = "$(blkid -s UUID -o value /dev/vda2)"
-      machine.succeed(
+      installer.succeed(
           "sgdisk -Z /dev/vda",
           "sgdisk -n 1:0:+1M -n 2:0:+100M -n 3:0:+1G -N 4 -t 1:ef02 -t 2:8300 "
           + "-t 3:8200 -t 4:8300 -c 2:boot -c 4:root /dev/vda",
@@ -1282,9 +1257,9 @@ in {
           "mkfs.ext4 -L boot /dev/vda2",
           "mkfs.ext4 -L root /dev/vda4",
       )
-      machine.execute(f"ln -s ../../vda2 /dev/disk/by-uuid/{uuid}")
-      machine.execute("ln -s ../../vda4 /dev/disk/by-label/root")
-      machine.succeed(
+      installer.execute(f"ln -s ../../vda2 /dev/disk/by-uuid/{uuid}")
+      installer.execute("ln -s ../../vda4 /dev/disk/by-label/root")
+      installer.succeed(
           "mount /dev/disk/by-label/root /mnt",
           "mkdir /mnt/boot",
           f"mount /dev/disk/by-uuid/{uuid} /mnt/boot",
@@ -1296,7 +1271,7 @@ in {
   # Simple btrfs grub testing
   btrfsSimple = makeInstallerTest "btrfsSimple" {
     createPartitions = ''
-      machine.succeed(
+      installer.succeed(
           "sgdisk -Z /dev/vda",
           "sgdisk -n 1:0:+1M -n 2:0:+1G -N 3 -t 1:ef02 -t 2:8200 -t 3:8300 -c 3:root /dev/vda",
           "mkswap /dev/vda2 -L swap",
@@ -1310,7 +1285,7 @@ in {
   # Test to see if we can detect /boot and /nix on subvolumes
   btrfsSubvols = makeInstallerTest "btrfsSubvols" {
     createPartitions = ''
-      machine.succeed(
+      installer.succeed(
           "sgdisk -Z /dev/vda",
           "sgdisk -n 1:0:+1M -n 2:0:+1G -N 3 -t 1:ef02 -t 2:8200 -t 3:8300 -c 3:root /dev/vda",
           "mkswap /dev/vda2 -L swap",
@@ -1332,7 +1307,7 @@ in {
   # Test to see if we can detect default and aux subvolumes correctly
   btrfsSubvolDefault = makeInstallerTest "btrfsSubvolDefault" {
     createPartitions = ''
-      machine.succeed(
+      installer.succeed(
           "sgdisk -Z /dev/vda",
           "sgdisk -n 1:0:+1M -n 2:0:+1G -N 3 -t 1:ef02 -t 2:8200 -t 3:8300 -c 3:root /dev/vda",
           "mkswap /dev/vda2 -L swap",
@@ -1358,7 +1333,7 @@ in {
   # Test to see if we can deal with subvols that need to be escaped in fstab
   btrfsSubvolEscape = makeInstallerTest "btrfsSubvolEscape" {
     createPartitions = ''
-      machine.succeed(
+      installer.succeed(
           "sgdisk -Z /dev/vda",
           "sgdisk -n 1:0:+1M -n 2:0:+1G -N 3 -t 1:ef02 -t 2:8200 -t 3:8300 -c 3:root /dev/vda",
           "mkswap /dev/vda2 -L swap",
@@ -1385,7 +1360,7 @@ in {
 } // optionalAttrs systemdStage1 {
   stratisRoot = makeInstallerTest "stratisRoot" {
     createPartitions = ''
-      machine.succeed(
+      installer.succeed(
         "sgdisk --zap-all /dev/vda",
         "sgdisk --new=1:0:+100M --typecode=0:ef00 /dev/vda", # /boot
         "sgdisk --new=2:0:+1G --typecode=0:8200 /dev/vda", # swap
@@ -1428,7 +1403,7 @@ in {
   in makeInstallerTest "gptAutoRoot" {
     disableFileSystems = true;
     createPartitions = ''
-      machine.succeed(
+      installer.succeed(
         "sgdisk --zap-all /dev/vda",
         "sgdisk --new=1:0:+100M --typecode=0:ef00 /dev/vda", # /boot
         "sgdisk --new=2:0:+1G --typecode=0:8200 /dev/vda", # swap
diff --git a/nixos/tests/pantheon.nix b/nixos/tests/pantheon.nix
index 14f92fa3af4a2..f8de2eb8061d1 100644
--- a/nixos/tests/pantheon.nix
+++ b/nixos/tests/pantheon.nix
@@ -50,7 +50,7 @@ import ./make-test-python.nix ({ pkgs, lib, ...} :
             machine.wait_until_succeeds(f"pgrep -f {i}")
         for i in ["gala", "io.elementary.wingpanel", "plank"]:
             machine.wait_for_window(i)
-        for i in ["io.elementary.gala.daemon@x11.service", "bamfdaemon.service", "io.elementary.files.xdg-desktop-portal.service"]:
+        for i in ["bamfdaemon.service", "io.elementary.files.xdg-desktop-portal.service"]:
             machine.wait_for_unit(i, "${user.name}")
 
     with subtest("Check if various environment variables are set"):
diff --git a/nixos/tests/switch-test.nix b/nixos/tests/switch-test.nix
index 5ffdf180d5e3f..a57d66f82eac9 100644
--- a/nixos/tests/switch-test.nix
+++ b/nixos/tests/switch-test.nix
@@ -691,9 +691,9 @@ in {
     with subtest("continuing from an aborted switch"):
         # An aborted switch will write into a file what it tried to start
         # and a second switch should continue from this
-        machine.succeed("echo dbus.service > /run/nixos/start-list")
+        machine.succeed("echo dbus-broker.service > /run/nixos/start-list")
         out = switch_to_specialisation("${machine}", "modifiedSystemConf")
-        assert_contains(out, "starting the following units: dbus.service\n")
+        assert_contains(out, "starting the following units: dbus-broker.service\n")
 
     with subtest("fstab mounts"):
         switch_to_specialisation("${machine}", "")
@@ -732,7 +732,7 @@ in {
         out = switch_to_specialisation("${machine}", "")
         assert_contains(out, "stopping the following units: test.mount\n")
         assert_lacks(out, "NOT restarting the following changed units:")
-        assert_contains(out, "reloading the following units: dbus.service\n")
+        assert_contains(out, "reloading the following units: dbus-broker.service\n")
         assert_lacks(out, "\nrestarting the following units:")
         assert_lacks(out, "\nstarting the following units:")
         assert_lacks(out, "the following new units were started:")
@@ -740,7 +740,7 @@ in {
         out = switch_to_specialisation("${machine}", "storeMountModified")
         assert_lacks(out, "stopping the following units:")
         assert_contains(out, "NOT restarting the following changed units: -.mount")
-        assert_contains(out, "reloading the following units: dbus.service\n")
+        assert_contains(out, "reloading the following units: dbus-broker.service\n")
         assert_lacks(out, "\nrestarting the following units:")
         assert_lacks(out, "\nstarting the following units:")
         assert_lacks(out, "the following new units were started:")
@@ -751,7 +751,7 @@ in {
         out = switch_to_specialisation("${machine}", "swap")
         assert_lacks(out, "stopping the following units:")
         assert_lacks(out, "NOT restarting the following changed units:")
-        assert_contains(out, "reloading the following units: dbus.service\n")
+        assert_contains(out, "reloading the following units: dbus-broker.service\n")
         assert_lacks(out, "\nrestarting the following units:")
         assert_lacks(out, "\nstarting the following units:")
         assert_contains(out, "the following new units were started: swapfile.swap")
@@ -760,7 +760,7 @@ in {
         assert_contains(out, "stopping swap device: /swapfile")
         assert_lacks(out, "stopping the following units:")
         assert_lacks(out, "NOT restarting the following changed units:")
-        assert_contains(out, "reloading the following units: dbus.service\n")
+        assert_contains(out, "reloading the following units: dbus-broker.service\n")
         assert_lacks(out, "\nrestarting the following units:")
         assert_lacks(out, "\nstarting the following units:")
         assert_lacks(out, "the following new units were started:")
@@ -781,7 +781,7 @@ in {
         assert_lacks(out, "installing dummy bootloader")  # test does not install a bootloader
         assert_lacks(out, "stopping the following units:")
         assert_lacks(out, "NOT restarting the following changed units:")
-        assert_contains(out, "reloading the following units: dbus.service\n")  # huh
+        assert_contains(out, "reloading the following units: dbus-broker.service\n")  # huh
         assert_lacks(out, "\nrestarting the following units:")
         assert_lacks(out, "\nstarting the following units:")
         assert_contains(out, "the following new units were started: test.service\n")
@@ -858,7 +858,7 @@ in {
         assert_lacks(out, "installing dummy bootloader")  # test does not install a bootloader
         assert_lacks(out, "stopping the following units:")
         assert_lacks(out, "NOT restarting the following changed units:")
-        assert_contains(out, "reloading the following units: dbus.service\n")  # huh
+        assert_contains(out, "reloading the following units: dbus-broker.service\n")  # huh
         assert_lacks(out, "\nrestarting the following units:")
         assert_lacks(out, "\nstarting the following units:")
         assert_contains(out, "the following new units were started: test.service\n")