summary refs log tree commit diff
path: root/nixos
diff options
context:
space:
mode:
Diffstat (limited to 'nixos')
-rw-r--r--nixos/doc/manual/from_md/release-notes/rl-2211.section.xml46
-rw-r--r--nixos/doc/manual/release-notes/rl-2211.section.md12
-rw-r--r--nixos/lib/utils.nix14
-rw-r--r--nixos/modules/config/pulseaudio.nix3
-rw-r--r--nixos/modules/hardware/video/uvcvideo/uvcdynctrl-udev-rules.nix4
-rw-r--r--nixos/modules/installer/cd-dvd/installation-cd-graphical-base.nix4
-rw-r--r--nixos/modules/module-list.nix2
-rw-r--r--nixos/modules/profiles/base.nix6
-rw-r--r--nixos/modules/programs/mininet.nix2
-rw-r--r--nixos/modules/programs/ssh.nix1
-rw-r--r--nixos/modules/security/acme/default.nix8
-rw-r--r--nixos/modules/security/acme/doc.xml11
-rw-r--r--nixos/modules/services/audio/mopidy.nix2
-rw-r--r--nixos/modules/services/backup/borgbackup.nix2
-rw-r--r--nixos/modules/services/continuous-integration/github-runner.nix81
-rw-r--r--nixos/modules/services/continuous-integration/hydra/default.nix2
-rw-r--r--nixos/modules/services/hardware/fwupd.nix37
-rw-r--r--nixos/modules/services/hardware/udev.nix6
-rw-r--r--nixos/modules/services/matrix/dendrite.nix19
-rw-r--r--nixos/modules/services/misc/etebase-server.nix2
-rw-r--r--nixos/modules/services/misc/gitlab.nix99
-rw-r--r--nixos/modules/services/misc/gitolite.nix10
-rw-r--r--nixos/modules/services/networking/coturn.nix7
-rw-r--r--nixos/modules/services/networking/firefox-syncserver.nix9
-rw-r--r--nixos/modules/services/networking/iwd.nix2
-rw-r--r--nixos/modules/services/networking/jitsi-videobridge.nix2
-rw-r--r--nixos/modules/services/networking/knot.nix2
-rw-r--r--nixos/modules/services/networking/mullvad-vpn.nix2
-rw-r--r--nixos/modules/services/networking/pptpd.nix2
-rw-r--r--nixos/modules/services/networking/tinc.nix2
-rw-r--r--nixos/modules/services/networking/tmate-ssh-server.nix122
-rw-r--r--nixos/modules/services/networking/xl2tpd.nix2
-rw-r--r--nixos/modules/services/security/endlessh-go.nix138
-rw-r--r--nixos/modules/services/security/privacyidea.nix94
-rw-r--r--nixos/modules/services/web-apps/mediawiki.nix2
-rw-r--r--nixos/modules/system/boot/systemd/initrd.nix2
-rw-r--r--nixos/modules/tasks/filesystems/jfs.nix2
-rw-r--r--nixos/modules/virtualisation/azure-agent.nix2
-rw-r--r--nixos/modules/virtualisation/virtualbox-host.nix20
-rw-r--r--nixos/release-combined.nix14
-rw-r--r--nixos/release-small.nix82
-rw-r--r--nixos/release.nix4
-rw-r--r--nixos/tests/acme.nix60
-rw-r--r--nixos/tests/all-tests.nix7
-rw-r--r--nixos/tests/endlessh-go.nix58
-rw-r--r--nixos/tests/hydra/common.nix2
-rw-r--r--nixos/tests/kubernetes/base.nix2
-rw-r--r--nixos/tests/paperless.nix8
-rw-r--r--nixos/tests/pulseaudio.nix25
-rw-r--r--nixos/tests/retroarch.nix4
-rw-r--r--nixos/tests/seafile.nix12
-rw-r--r--nixos/tests/spark/default.nix1
-rw-r--r--nixos/tests/sssd-ldap.nix7
-rw-r--r--nixos/tests/systemd-initrd-modprobe.nix17
-rw-r--r--nixos/tests/systemd-networkd-ipv6-prefix-delegation.nix123
-rw-r--r--nixos/tests/systemd-oomd.nix55
-rw-r--r--nixos/tests/tmate-ssh-server.nix73
-rw-r--r--nixos/tests/tracee.nix46
58 files changed, 1146 insertions, 239 deletions
diff --git a/nixos/doc/manual/from_md/release-notes/rl-2211.section.xml b/nixos/doc/manual/from_md/release-notes/rl-2211.section.xml
index 582b1715d1a..e105d689864 100644
--- a/nixos/doc/manual/from_md/release-notes/rl-2211.section.xml
+++ b/nixos/doc/manual/from_md/release-notes/rl-2211.section.xml
@@ -270,6 +270,13 @@
       </listitem>
       <listitem>
         <para>
+          <link xlink:href="https://github.com/shizunge/endlessh-go">endlessh-go</link>,
+          an SSH tarpit that exposes Prometheus metrics. Available as
+          <link linkend="opt-services.endlessh-go.enable">services.endlessh-go</link>.
+        </para>
+      </listitem>
+      <listitem>
+        <para>
           <link xlink:href="https://netbird.io">netbird</link>, a zero
           configuration VPN. Available as
           <link xlink:href="options.html#opt-services.netbird.enable">services.netbird</link>.
@@ -322,6 +329,15 @@
       </listitem>
       <listitem>
         <para>
+          <link xlink:href="https://github.com/tmate-io/tmate-ssh-server">tmate-ssh-server</link>,
+          server side part of
+          <link xlink:href="https://tmate.io/">tmate</link>. Available
+          as
+          <link linkend="opt-services.tmate-ssh-server.enable">services.tmate-ssh-server</link>.
+        </para>
+      </listitem>
+      <listitem>
+        <para>
           <link xlink:href="https://www.grafana.com/oss/tempo/">Grafana
           Tempo</link>, a distributed tracing store. Available as
           <link linkend="opt-services.tempo.enable">services.tempo</link>.
@@ -474,6 +490,16 @@
       </listitem>
       <listitem>
         <para>
+          The <literal>p4</literal> package now only includes the
+          open-source Perforce Helix Core command-line client and APIs.
+          It no longer installs the unfree Helix Core Server binaries
+          <literal>p4d</literal>, <literal>p4broker</literal>, and
+          <literal>p4p</literal>. To install the Helix Core Server
+          binaries, use the <literal>p4d</literal> package instead.
+        </para>
+      </listitem>
+      <listitem>
+        <para>
           The <literal>coq</literal> package and versioned variants
           starting at <literal>coq_8_14</literal> no longer include
           CoqIDE, which is now available through
@@ -492,7 +518,9 @@
       <listitem>
         <para>
           <literal>pkgs.cosign</literal> does not provide the
-          <literal>cosigned</literal> binary anymore.
+          <literal>cosigned</literal> binary anymore. The
+          <literal>sget</literal> binary has been moved into its own
+          package.
         </para>
       </listitem>
       <listitem>
@@ -529,6 +557,16 @@
       </listitem>
       <listitem>
         <para>
+          <literal>teleport</literal> has been upgraded to major version
+          10. Please see upstream
+          <link xlink:href="https://goteleport.com/docs/ver/10.0/management/operations/upgrading/">upgrade
+          instructions</link> and
+          <link xlink:href="https://goteleport.com/docs/ver/10.0/changelog/#1000">release
+          notes</link>.
+        </para>
+      </listitem>
+      <listitem>
+        <para>
           lemmy module option
           <literal>services.lemmy.settings.database.createLocally</literal>
           moved to
@@ -589,6 +627,12 @@
       </listitem>
       <listitem>
         <para>
+          The default <literal>kops</literal> version is now 1.25.1 and
+          support for 1.22 and older has been dropped.
+        </para>
+      </listitem>
+      <listitem>
+        <para>
           <literal>k3s</literal> no longer supports docker as runtime
           due to upstream dropping support.
         </para>
diff --git a/nixos/doc/manual/release-notes/rl-2211.section.md b/nixos/doc/manual/release-notes/rl-2211.section.md
index 3e38f85b8f1..43e28836a4e 100644
--- a/nixos/doc/manual/release-notes/rl-2211.section.md
+++ b/nixos/doc/manual/release-notes/rl-2211.section.md
@@ -95,6 +95,8 @@ In addition to numerous new and upgraded packages, this release has the followin
 
 - [alps](https://git.sr.ht/~migadu/alps), a simple and extensible webmail. Available as [services.alps](#opt-services.alps.enable).
 
+- [endlessh-go](https://github.com/shizunge/endlessh-go), an SSH tarpit that exposes Prometheus metrics. Available as [services.endlessh-go](#opt-services.endlessh-go.enable).
+
 - [netbird](https://netbird.io), a zero configuration VPN.
   Available as [services.netbird](options.html#opt-services.netbird.enable).
 
@@ -110,6 +112,8 @@ In addition to numerous new and upgraded packages, this release has the followin
 
 - [go-autoconfig](https://github.com/L11R/go-autoconfig), IMAP/SMTP autodiscover server. Available as [services.go-autoconfig](#opt-services.go-autoconfig.enable).
 
+- [tmate-ssh-server](https://github.com/tmate-io/tmate-ssh-server), server side part of [tmate](https://tmate.io/). Available as [services.tmate-ssh-server](#opt-services.tmate-ssh-server.enable).
+
 - [Grafana Tempo](https://www.grafana.com/oss/tempo/), a distributed tracing store. Available as [services.tempo](#opt-services.tempo.enable).
 
 - [AusweisApp2](https://www.ausweisapp.bund.de/), the authentication software for the German ID card. Available as [programs.ausweisapp](#opt-programs.ausweisapp.enable).
@@ -158,6 +162,8 @@ Available as [services.patroni](options.html#opt-services.patroni.enable).
 - `services.hbase` has been renamed to `services.hbase-standalone`.
   For production HBase clusters, use `services.hadoop.hbase` instead.
 
+- The `p4` package now only includes the open-source Perforce Helix Core command-line client and APIs. It no longer installs the unfree Helix Core Server binaries `p4d`, `p4broker`, and `p4p`. To install the Helix Core Server binaries, use the `p4d` package instead.
+
 - The `coq` package and versioned variants starting at `coq_8_14` no
   longer include CoqIDE, which is now available through
   `coqPackages.coqide`. It is still possible to get CoqIDE as part of
@@ -167,7 +173,7 @@ Available as [services.patroni](options.html#opt-services.patroni.enable).
 - PHP 7.4 is no longer supported due to upstream not supporting this
   version for the entire lifecycle of the 22.11 release.
 
-- `pkgs.cosign` does not provide the `cosigned` binary anymore.
+- `pkgs.cosign` does not provide the `cosigned` binary anymore. The `sget` binary has been moved into its own package.
 
 - Emacs now uses the Lucid toolkit by default instead of GTK because of stability and compatibility issues.
   Users who still wish to remain using GTK can do so by using `emacs-gtk`.
@@ -178,6 +184,8 @@ Available as [services.patroni](options.html#opt-services.patroni.enable).
 
 - dd-agent package removed along with the `services.dd-agent` module, due to the project being deprecated in favor of `datadog-agent`,  which is available via the `services.datadog-agent` module.
 
+- `teleport` has been upgraded to major version 10. Please see upstream [upgrade instructions](https://goteleport.com/docs/ver/10.0/management/operations/upgrading/) and [release notes](https://goteleport.com/docs/ver/10.0/changelog/#1000).
+
 - lemmy module option `services.lemmy.settings.database.createLocally`
   moved to `services.lemmy.database.createLocally`.
 
@@ -198,6 +206,8 @@ Available as [services.patroni](options.html#opt-services.patroni.enable).
   Use `configure.packages` instead.
 - Neovim can not be configured with plug anymore (still works for vim).
 
+- The default `kops` version is now 1.25.1 and support for 1.22 and older has been dropped.
+
 - `k3s` no longer supports docker as runtime due to upstream dropping support.
 
 - `k3s` supports `clusterInit` option, and it is enabled by default, for servers.
diff --git a/nixos/lib/utils.nix b/nixos/lib/utils.nix
index d7671a37499..f646f70323e 100644
--- a/nixos/lib/utils.nix
+++ b/nixos/lib/utils.nix
@@ -102,7 +102,11 @@ rec {
         if item ? ${attr} then
           nameValuePair prefix item.${attr}
         else if isAttrs item then
-          map (name: recurse (prefix + "." + name) item.${name}) (attrNames item)
+          map (name:
+            let
+              escapedName = ''"${replaceChars [''"'' "\\"] [''\"'' "\\\\"] name}"'';
+            in
+              recurse (prefix + "." + escapedName) item.${name}) (attrNames item)
         else if isList item then
           imap0 (index: item: recurse (prefix + "[${toString index}]") item) item
         else
@@ -182,13 +186,13 @@ rec {
                 '')
                (attrNames secrets))
     + "\n"
-    + "${pkgs.jq}/bin/jq >'${output}' '"
-    + concatStringsSep
+    + "${pkgs.jq}/bin/jq >'${output}' "
+    + lib.escapeShellArg (concatStringsSep
       " | "
       (imap1 (index: name: ''${name} = $ENV.secret${toString index}'')
-             (attrNames secrets))
+             (attrNames secrets)))
     + ''
-      ' <<'EOF'
+       <<'EOF'
       ${builtins.toJSON set}
       EOF
       (( ! $inherit_errexit_enabled )) && shopt -u inherit_errexit
diff --git a/nixos/modules/config/pulseaudio.nix b/nixos/modules/config/pulseaudio.nix
index 3e969991f8f..80ff6c1aabf 100644
--- a/nixos/modules/config/pulseaudio.nix
+++ b/nixos/modules/config/pulseaudio.nix
@@ -102,7 +102,7 @@ in {
           each user that tries to use the sound system. The server runs
           with user privileges. If true, one system-wide PulseAudio
           server is launched on boot, running as the user "pulse", and
-          only users in the "audio" group will have access to the server.
+          only users in the "pulse-access" group will have access to the server.
           Please read the PulseAudio documentation for more details.
 
           Don't enable this option unless you know what you are doing.
@@ -310,6 +310,7 @@ in {
       };
 
       users.groups.pulse.gid = gid;
+      users.groups.pulse-access = {};
 
       systemd.services.pulseaudio = {
         description = "PulseAudio System-Wide Server";
diff --git a/nixos/modules/hardware/video/uvcvideo/uvcdynctrl-udev-rules.nix b/nixos/modules/hardware/video/uvcvideo/uvcdynctrl-udev-rules.nix
index a808429c999..8dadbd53b98 100644
--- a/nixos/modules/hardware/video/uvcvideo/uvcdynctrl-udev-rules.nix
+++ b/nixos/modules/hardware/video/uvcvideo/uvcdynctrl-udev-rules.nix
@@ -23,8 +23,10 @@ in
 runCommand "uvcdynctrl-udev-rules-${version}"
 {
   inherit dataPath;
-  buildInputs = [
+  nativeBuildInputs = [
     makeWrapper
+  ];
+  buildInputs = [
     libwebcam
   ];
   dontPatchELF = true;
diff --git a/nixos/modules/installer/cd-dvd/installation-cd-graphical-base.nix b/nixos/modules/installer/cd-dvd/installation-cd-graphical-base.nix
index c5976166fb3..4a00c52916f 100644
--- a/nixos/modules/installer/cd-dvd/installation-cd-graphical-base.nix
+++ b/nixos/modules/installer/cd-dvd/installation-cd-graphical-base.nix
@@ -38,9 +38,9 @@ with lib;
   # VM guest additions to improve host-guest interaction
   services.spice-vdagentd.enable = true;
   services.qemuGuest.enable = true;
-  virtualisation.vmware.guest.enable = true;
+  virtualisation.vmware.guest.enable = pkgs.stdenv.hostPlatform.isx86;
   virtualisation.hypervGuest.enable = true;
-  services.xe-guest-utilities.enable = true;
+  services.xe-guest-utilities.enable = pkgs.stdenv.hostPlatform.isx86;
   # The VirtualBox guest additions rely on an out-of-tree kernel module
   # which lags behind kernel releases, potentially causing broken builds.
   virtualisation.virtualbox.guest.enable = false;
diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix
index c2545016707..494df03e3a3 100644
--- a/nixos/modules/module-list.nix
+++ b/nixos/modules/module-list.nix
@@ -960,6 +960,7 @@
   ./services/networking/tinc.nix
   ./services/networking/tinydns.nix
   ./services/networking/tftpd.nix
+  ./services/networking/tmate-ssh-server.nix
   ./services/networking/trickster.nix
   ./services/networking/tox-bootstrapd.nix
   ./services/networking/tox-node.nix
@@ -1003,6 +1004,7 @@
   ./services/security/certmgr.nix
   ./services/security/cfssl.nix
   ./services/security/clamav.nix
+  ./services/security/endlessh-go.nix
   ./services/security/fail2ban.nix
   ./services/security/fprintd.nix
   ./services/security/haka.nix
diff --git a/nixos/modules/profiles/base.nix b/nixos/modules/profiles/base.nix
index 33dd80d7c5a..c415ca85743 100644
--- a/nixos/modules/profiles/base.nix
+++ b/nixos/modules/profiles/base.nix
@@ -1,7 +1,7 @@
 # This module defines the software packages included in the "minimal"
 # installation CD.  It might be useful elsewhere.
 
-{ lib, pkgs, ... }:
+{ config, lib, pkgs, ... }:
 
 {
   # Include some utilities that are useful for installing or repairing
@@ -51,7 +51,9 @@
   ];
 
   # Include support for various filesystems.
-  boot.supportedFilesystems = [ "btrfs" "reiserfs" "vfat" "f2fs" "xfs" "zfs" "ntfs" "cifs" ];
+  boot.supportedFilesystems =
+    [ "btrfs" "reiserfs" "vfat" "f2fs" "xfs" "ntfs" "cifs" ] ++
+    lib.optional (lib.meta.availableOn pkgs.stdenv.hostPlatform config.boot.zfs.package) "zfs";
 
   # Configure host id for ZFS to work
   networking.hostId = lib.mkDefault "8425e349";
diff --git a/nixos/modules/programs/mininet.nix b/nixos/modules/programs/mininet.nix
index 0b7e82cc5bd..02272729d23 100644
--- a/nixos/modules/programs/mininet.nix
+++ b/nixos/modules/programs/mininet.nix
@@ -14,7 +14,7 @@ let
   pyEnv = pkgs.python.withPackages(ps: [ ps.mininet-python ]);
 
   mnexecWrapped = pkgs.runCommand "mnexec-wrapper"
-    { buildInputs = [ pkgs.makeWrapper pkgs.pythonPackages.wrapPython ]; }
+    { nativeBuildInputs = [ pkgs.makeWrapper pkgs.pythonPackages.wrapPython ]; }
     ''
       makeWrapper ${pkgs.mininet}/bin/mnexec \
         $out/bin/mnexec \
diff --git a/nixos/modules/programs/ssh.nix b/nixos/modules/programs/ssh.nix
index 865c0becdbc..36b724e04bd 100644
--- a/nixos/modules/programs/ssh.nix
+++ b/nixos/modules/programs/ssh.nix
@@ -14,6 +14,7 @@ let
     ''
       #! ${pkgs.runtimeShell} -e
       export DISPLAY="$(systemctl --user show-environment | ${pkgs.gnused}/bin/sed 's/^DISPLAY=\(.*\)/\1/; t; d')"
+      export WAYLAND_DISPLAY="$(systemctl --user show-environment | ${pkgs.gnused}/bin/sed 's/^WAYLAND_DISPLAY=\(.*\)/\1/; t; d')"
       exec ${askPassword} "$@"
     '';
 
diff --git a/nixos/modules/security/acme/default.nix b/nixos/modules/security/acme/default.nix
index 377b543c581..e9299fb1b3a 100644
--- a/nixos/modules/security/acme/default.nix
+++ b/nixos/modules/security/acme/default.nix
@@ -190,7 +190,7 @@ let
     );
     renewOpts = escapeShellArgs (
       commonOpts
-      ++ [ "renew" ]
+      ++ [ "renew" "--no-random-sleep" ]
       ++ optionals data.ocspMustStaple [ "--must-staple" ]
       ++ data.extraLegoRenewFlags
     );
@@ -223,9 +223,9 @@ let
         # have many certificates, the renewals are distributed over
         # the course of the day to avoid rate limits.
         AccuracySec = "${toString (_24hSecs / numCerts)}s";
-
         # Skew randomly within the day, per https://letsencrypt.org/docs/integration-guide/.
         RandomizedDelaySec = "24h";
+        FixedRandomDelay = true;
       };
     };
 
@@ -325,6 +325,7 @@ let
         '');
       } // optionalAttrs (data.listenHTTP != null && toInt (elemAt (splitString ":" data.listenHTTP) 1) < 1024) {
         CapabilityBoundingSet = [ "CAP_NET_BIND_SERVICE" ];
+        AmbientCapabilities = [ "CAP_NET_BIND_SERVICE" ];
       };
 
       # Working directory will be /tmp
@@ -376,7 +377,8 @@ let
 
         # Check if we can renew.
         # We can only renew if the list of domains has not changed.
-        if cmp -s domainhash.txt certificates/domainhash.txt && [ -e 'certificates/${keyName}.key' -a -e 'certificates/${keyName}.crt' -a -n "$(ls -1 accounts)" ]; then
+        # We also need an account key. Avoids #190493
+        if cmp -s domainhash.txt certificates/domainhash.txt && [ -e 'certificates/${keyName}.key' -a -e 'certificates/${keyName}.crt' -a -n "$(find accounts -name '${data.email}.key')" ]; then
 
           # Even if a cert is not expired, it may be revoked by the CA.
           # Try to renew, and silently fail if the cert is not expired.
diff --git a/nixos/modules/security/acme/doc.xml b/nixos/modules/security/acme/doc.xml
index 4817f7a7fc6..1439594a5ac 100644
--- a/nixos/modules/security/acme/doc.xml
+++ b/nixos/modules/security/acme/doc.xml
@@ -237,8 +237,8 @@ services.bind = {
 
 <programlisting>
 systemd.services.dns-rfc2136-conf = {
-  requiredBy = ["acme-example.com.service", "bind.service"];
-  before = ["acme-example.com.service", "bind.service"];
+  requiredBy = ["acme-example.com.service" "bind.service"];
+  before = ["acme-example.com.service" "bind.service"];
   unitConfig = {
     ConditionPathExists = "!/var/lib/secrets/dnskeys.conf";
   };
@@ -249,18 +249,19 @@ systemd.services.dns-rfc2136-conf = {
   path = [ pkgs.bind ];
   script = ''
     mkdir -p /var/lib/secrets
+    chmod 755 /var/lib/secrets
     tsig-keygen rfc2136key.example.com &gt; /var/lib/secrets/dnskeys.conf
     chown named:root /var/lib/secrets/dnskeys.conf
     chmod 400 /var/lib/secrets/dnskeys.conf
 
-    # Copy the secret value from the dnskeys.conf, and put it in
-    # RFC2136_TSIG_SECRET below
+    # extract secret value from the dnskeys.conf
+    while read x y; do if [ "$x" = "secret" ]; then secret="''${y:1:''${#y}-3}"; fi; done &lt; /var/lib/secrets/dnskeys.conf
 
     cat &gt; /var/lib/secrets/certs.secret &lt;&lt; EOF
     RFC2136_NAMESERVER='127.0.0.1:53'
     RFC2136_TSIG_ALGORITHM='hmac-sha256.'
     RFC2136_TSIG_KEY='rfc2136key.example.com'
-    RFC2136_TSIG_SECRET='your secret key'
+    RFC2136_TSIG_SECRET='$secret'
     EOF
     chmod 400 /var/lib/secrets/certs.secret
   '';
diff --git a/nixos/modules/services/audio/mopidy.nix b/nixos/modules/services/audio/mopidy.nix
index 50ee9a82451..40e8679f53d 100644
--- a/nixos/modules/services/audio/mopidy.nix
+++ b/nixos/modules/services/audio/mopidy.nix
@@ -14,7 +14,7 @@ let
     name = "mopidy-with-extensions-${mopidy.version}";
     paths = closePropagation cfg.extensionPackages;
     pathsToLink = [ "/${mopidyPackages.python.sitePackages}" ];
-    buildInputs = [ makeWrapper ];
+    nativeBuildInputs = [ makeWrapper ];
     postBuild = ''
       makeWrapper ${mopidy}/bin/mopidy $out/bin/mopidy \
         --prefix PYTHONPATH : $out/${mopidyPackages.python.sitePackages}
diff --git a/nixos/modules/services/backup/borgbackup.nix b/nixos/modules/services/backup/borgbackup.nix
index f02e15f2b98..7b29eb41e72 100644
--- a/nixos/modules/services/backup/borgbackup.nix
+++ b/nixos/modules/services/backup/borgbackup.nix
@@ -116,7 +116,7 @@ let
       original, name, set ? {}
     }:
     pkgs.runCommand "${name}-wrapper" {
-      buildInputs = [ pkgs.makeWrapper ];
+      nativeBuildInputs = [ pkgs.makeWrapper ];
     } (with lib; ''
       makeWrapper "${original}" "$out/bin/${name}" \
         ${concatStringsSep " \\\n " (mapAttrsToList (name: value: ''--set ${name} "${value}"'') set)}
diff --git a/nixos/modules/services/continuous-integration/github-runner.nix b/nixos/modules/services/continuous-integration/github-runner.nix
index 9abe13a89af..2ece75722a1 100644
--- a/nixos/modules/services/continuous-integration/github-runner.nix
+++ b/nixos/modules/services/continuous-integration/github-runner.nix
@@ -200,46 +200,65 @@ in
 
               ${lines}
             '';
-            currentConfigPath = "$STATE_DIRECTORY/.nixos-current-config.json";
             runnerRegistrationConfig = getAttrs [ "name" "tokenFile" "url" "runnerGroup" "extraLabels" "ephemeral" ] cfg;
             newConfigPath = builtins.toFile "${svcName}-config.json" (builtins.toJSON runnerRegistrationConfig);
-            newConfigTokenFilename = ".new-token";
+            currentConfigPath = "$STATE_DIRECTORY/.nixos-current-config.json";
+            newConfigTokenPath= "$STATE_DIRECTORY/.new-token";
+            currentConfigTokenPath = "$STATE_DIRECTORY/${currentConfigTokenFilename}";
+
             runnerCredFiles = [
               ".credentials"
               ".credentials_rsaparams"
               ".runner"
             ];
             unconfigureRunner = writeScript "unconfigure" ''
-              differs=
-
-              if [[ "$(ls -A "$STATE_DIRECTORY")" ]]; then
-                # State directory is not empty
-                # Set `differs = 1` if current and new runner config differ or if `currentConfigPath` does not exist
-                ${pkgs.diffutils}/bin/diff -q '${newConfigPath}' "${currentConfigPath}" >/dev/null 2>&1 || differs=1
-                # Also trigger a registration if the token content changed
-                ${pkgs.diffutils}/bin/diff -q \
-                  "$STATE_DIRECTORY"/${currentConfigTokenFilename} \
-                  ${escapeShellArg cfg.tokenFile} \
-                  >/dev/null 2>&1 || differs=1
-                # If .credentials does not exist, assume a previous run de-registered the runner on stop (ephemeral mode)
-                [[ ! -f "$STATE_DIRECTORY/.credentials" ]] && differs=1
-              fi
-
-              if [[ -n "$differs" ]]; then
-                echo "Config has changed, removing old runner state."
-                # In ephemeral mode, the runner deletes the `.credentials` file after de-registering it with GitHub
-                [[ -f "$STATE_DIRECTORY/.credentials" ]] && echo "The old runner will still appear in the GitHub Actions UI." \
-                  "You have to remove it manually."
-                find "$STATE_DIRECTORY/" -mindepth 1 -delete
-
+              copy_tokens() {
                 # Copy the configured token file to the state dir and allow the service user to read the file
-                install --mode=666 ${escapeShellArg cfg.tokenFile} "$STATE_DIRECTORY/${newConfigTokenFilename}"
+                install --mode=666 ${escapeShellArg cfg.tokenFile} "${newConfigTokenPath}"
                 # Also copy current file to allow for a diff on the next start
-                install --mode=600 ${escapeShellArg cfg.tokenFile} "$STATE_DIRECTORY/${currentConfigTokenFilename}"
+                install --mode=600 ${escapeShellArg cfg.tokenFile} "${currentConfigTokenPath}"
+              }
+
+              clean_state() {
+                find "$STATE_DIRECTORY/" -mindepth 1 -delete
+                copy_tokens
+              }
+
+              diff_config() {
+                changed=0
+
+                # Check for module config changes
+                [[ -f "${currentConfigPath}" ]] \
+                  && ${pkgs.diffutils}/bin/diff -q '${newConfigPath}' "${currentConfigPath}" >/dev/null 2>&1 \
+                  || changed=1
+
+                # Also check the content of the token file
+                [[ -f "${currentConfigTokenPath}" ]] \
+                  && ${pkgs.diffutils}/bin/diff -q "${currentConfigTokenPath}" ${escapeShellArg cfg.tokenFile} >/dev/null 2>&1 \
+                  || changed=1
+
+                # If the config has changed, remove old state and copy tokens
+                if [[ "$changed" -eq 1 ]]; then
+                  echo "Config has changed, removing old runner state."
+                  echo "The old runner will still appear in the GitHub Actions UI." \
+                       "You have to remove it manually."
+                  clean_state
+                fi
+              }
+
+              if [[ "${optionalString cfg.ephemeral "1"}" ]]; then
+                # In ephemeral mode, we always want to start with a clean state
+                clean_state
+              elif [[ "$(ls -A "$STATE_DIRECTORY")" ]]; then
+                # There are state files from a previous run; diff them to decide if we need a new registration
+                diff_config
+              else
+                # The state directory is entirely empty which indicates a first start
+                copy_tokens
               fi
             '';
             configureRunner = writeScript "configure" ''
-              if [[ -e "$STATE_DIRECTORY/${newConfigTokenFilename}" ]]; then
+              if [[ -e "${newConfigTokenPath}" ]]; then
                 echo "Configuring GitHub Actions Runner"
 
                 args=(
@@ -256,7 +275,7 @@ in
 
                 # If the token file contains a PAT (i.e., it starts with "ghp_"), we have to use the --pat option,
                 # if it is not a PAT, we assume it contains a registration token and use the --token option
-                token=$(<"$STATE_DIRECTORY/${newConfigTokenFilename}")
+                token=$(<"${newConfigTokenPath}")
                 if [[ "$token" =~ ^ghp_* ]]; then
                   args+=(--pat "$token")
                 else
@@ -271,7 +290,7 @@ in
                 rm    -rf "$STATE_DIRECTORY/_diag/"
 
                 # Cleanup token from config
-                rm "$STATE_DIRECTORY/${newConfigTokenFilename}"
+                rm "${newConfigTokenPath}"
 
                 # Symlink to new config
                 ln -s '${newConfigPath}' "${currentConfigPath}"
@@ -305,8 +324,8 @@ in
         WorkingDirectory = runtimeDir;
 
         InaccessiblePaths = [
-          # Token file path given in the configuration
-          cfg.tokenFile
+          # Token file path given in the configuration, if visible to the service
+          "-${cfg.tokenFile}"
           # Token file in the state directory
           "${stateDir}/${currentConfigTokenFilename}"
         ];
diff --git a/nixos/modules/services/continuous-integration/hydra/default.nix b/nixos/modules/services/continuous-integration/hydra/default.nix
index 8b5c1228c52..71147957504 100644
--- a/nixos/modules/services/continuous-integration/hydra/default.nix
+++ b/nixos/modules/services/continuous-integration/hydra/default.nix
@@ -42,7 +42,7 @@ let
     makeWrapperArgs = concatStringsSep " " (mapAttrsToList (key: value: "--set \"${key}\" \"${value}\"") hydraEnv);
   in pkgs.buildEnv rec {
     name = "hydra-env";
-    buildInputs = [ pkgs.makeWrapper ];
+    nativeBuildInputs = [ pkgs.makeWrapper ];
     paths = [ cfg.package ];
 
     postBuild = ''
diff --git a/nixos/modules/services/hardware/fwupd.nix b/nixos/modules/services/hardware/fwupd.nix
index 2249f866803..98f837bd782 100644
--- a/nixos/modules/services/hardware/fwupd.nix
+++ b/nixos/modules/services/hardware/fwupd.nix
@@ -33,18 +33,26 @@ let
       mkEtcFile = p: nameValuePair (mkName p) { source = p; };
     in listToAttrs (map mkEtcFile cfg.extraTrustedKeys);
 
-  # We cannot include the file in $out and rely on filesInstalledToEtc
-  # to install it because it would create a cyclic dependency between
-  # the outputs. We also need to enable the remote,
-  # which should not be done by default.
-  testRemote = if cfg.enableTestRemote then {
-    "fwupd/remotes.d/fwupd-tests.conf" = {
-      source = pkgs.runCommand "fwupd-tests-enabled.conf" {} ''
+  enableRemote = base: remote: {
+    "fwupd/remotes.d/${remote}.conf" = {
+      source = pkgs.runCommand "${remote}-enabled.conf" {} ''
         sed "s,^Enabled=false,Enabled=true," \
-        "${cfg.package.installedTests}/etc/fwupd/remotes.d/fwupd-tests.conf" > "$out"
+        "${base}/etc/fwupd/remotes.d/${remote}.conf" > "$out"
       '';
     };
-  } else {};
+  };
+  remotes = (foldl'
+    (configFiles: remote: configFiles // (enableRemote cfg.package remote))
+    {}
+    cfg.extraRemotes
+  ) // (
+    # We cannot include the file in $out and rely on filesInstalledToEtc
+    # to install it because it would create a cyclic dependency between
+    # the outputs. We also need to enable the remote,
+    # which should not be done by default.
+    if cfg.enableTestRemote then (enableRemote cfg.package.installedTests "fwupd-tests") else {}
+  );
+
 in {
 
   ###### interface
@@ -86,6 +94,15 @@ in {
         '';
       };
 
+      extraRemotes = mkOption {
+        type = with types; listOf str;
+        default = [];
+        example = [ "lvfs-testing" ];
+        description = lib.mdDoc ''
+          Enables extra remotes in fwupd. See `/etc/fwupd/remotes.d`.
+        '';
+      };
+
       enableTestRemote = mkOption {
         type = types.bool;
         default = false;
@@ -119,7 +136,7 @@ in {
     environment.systemPackages = [ cfg.package ];
 
     # customEtc overrides some files from the package
-    environment.etc = originalEtc // customEtc // extraTrustedKeys // testRemote;
+    environment.etc = originalEtc // customEtc // extraTrustedKeys // remotes;
 
     services.dbus.packages = [ cfg.package ];
 
diff --git a/nixos/modules/services/hardware/udev.nix b/nixos/modules/services/hardware/udev.nix
index fa9d06b441a..4b962da0c03 100644
--- a/nixos/modules/services/hardware/udev.nix
+++ b/nixos/modules/services/hardware/udev.nix
@@ -171,10 +171,10 @@ let
       mv etc/udev/hwdb.bin $out
     '';
 
-  compressFirmware = if config.boot.kernelPackages.kernelAtLeast "5.3" then
-    pkgs.compressFirmwareXz
+  compressFirmware = firmware: if (config.boot.kernelPackages.kernelAtLeast "5.3" && (firmware.compressFirmware or true)) then
+    pkgs.compressFirmwareXz firmware
   else
-    id;
+    id firmware;
 
   # Udev has a 512-character limit for ENV{PATH}, so create a symlink
   # tree to work around this.
diff --git a/nixos/modules/services/matrix/dendrite.nix b/nixos/modules/services/matrix/dendrite.nix
index 9279af246f4..a5fea3da484 100644
--- a/nixos/modules/services/matrix/dendrite.nix
+++ b/nixos/modules/services/matrix/dendrite.nix
@@ -195,6 +195,25 @@ in
             '';
           };
         };
+        options.sync_api.search = {
+          enable = lib.mkEnableOption (lib.mdDoc "Dendrite's full-text search engine");
+          index_path = lib.mkOption {
+            type = lib.types.str;
+            default = "${workingDir}/searchindex";
+            description = lib.mdDoc ''
+              The path the search index will be created in.
+            '';
+          };
+          language = lib.mkOption {
+            type = lib.types.str;
+            default = "en";
+            description = lib.mdDoc ''
+              The language most likely to be used on the server - used when indexing, to
+              ensure the returned results match expectations. A full list of possible languages
+              can be found at https://github.com/blevesearch/bleve/tree/master/analysis/lang
+            '';
+          };
+        };
         options.user_api = {
           account_database = {
             connection_string = lib.mkOption {
diff --git a/nixos/modules/services/misc/etebase-server.nix b/nixos/modules/services/misc/etebase-server.nix
index 76c7c6596c8..c3723d18814 100644
--- a/nixos/modules/services/misc/etebase-server.nix
+++ b/nixos/modules/services/misc/etebase-server.nix
@@ -162,7 +162,7 @@ in
 
     environment.systemPackages = with pkgs; [
       (runCommand "etebase-server" {
-        buildInputs = [ makeWrapper ];
+        nativeBuildInputs = [ makeWrapper ];
       } ''
         makeWrapper ${pythonEnv}/bin/etebase-server \
           $out/bin/etebase-server \
diff --git a/nixos/modules/services/misc/gitlab.nix b/nixos/modules/services/misc/gitlab.nix
index e5de3a2b6ad..4988517a9b6 100644
--- a/nixos/modules/services/misc/gitlab.nix
+++ b/nixos/modules/services/misc/gitlab.nix
@@ -6,6 +6,9 @@ let
   cfg = config.services.gitlab;
   opt = options.services.gitlab;
 
+  toml = pkgs.formats.toml {};
+  yaml = pkgs.formats.yaml {};
+
   ruby = cfg.packages.gitlab.ruby;
 
   postgresqlPackage = if config.services.postgresql.enable then
@@ -89,17 +92,18 @@ let
     repos_path = "${cfg.statePath}/repositories";
     secret_file = "${cfg.statePath}/gitlab_shell_secret";
     log_file = "${cfg.statePath}/log/gitlab-shell.log";
-    redis = {
-      bin = "${pkgs.redis}/bin/redis-cli";
-      host = "127.0.0.1";
-      port = config.services.redis.servers.gitlab.port;
-      database = 0;
-      namespace = "resque:gitlab";
-    };
   };
 
   redisConfig.production.url = cfg.redisUrl;
 
+  cableYml = yaml.generate "cable.yml" {
+    production = {
+      adapter = "redis";
+      url = cfg.redisUrl;
+      channel_prefix = "gitlab_production";
+    };
+  };
+
   pagesArgs = [
     "-pages-domain" gitlabConfig.production.pages.host
     "-pages-root" "${gitlabConfig.production.shared.path}/pages"
@@ -188,16 +192,27 @@ let
     MALLOC_ARENA_MAX = "2";
   } // cfg.extraEnv;
 
+  runtimeDeps = with pkgs; [
+    nodejs
+    gzip
+    git
+    gnutar
+    postgresqlPackage
+    coreutils
+    procps
+    findutils # Needed for gitlab:cleanup:orphan_job_artifact_files
+  ];
+
   gitlab-rake = pkgs.stdenv.mkDerivation {
     name = "gitlab-rake";
-    buildInputs = [ pkgs.makeWrapper ];
+    nativeBuildInputs = [ pkgs.makeWrapper ];
     dontBuild = true;
     dontUnpack = true;
     installPhase = ''
       mkdir -p $out/bin
       makeWrapper ${cfg.packages.gitlab.rubyEnv}/bin/rake $out/bin/gitlab-rake \
           ${concatStrings (mapAttrsToList (name: value: "--set ${name} '${value}' ") gitlabEnv)} \
-          --set PATH '${lib.makeBinPath [ pkgs.nodejs pkgs.gzip pkgs.git pkgs.gnutar postgresqlPackage pkgs.coreutils pkgs.procps ]}:$PATH' \
+          --set PATH '${lib.makeBinPath runtimeDeps}:$PATH' \
           --set RAKEOPT '-f ${cfg.packages.gitlab}/share/gitlab/Rakefile' \
           --chdir '${cfg.packages.gitlab}/share/gitlab'
      '';
@@ -205,14 +220,14 @@ let
 
   gitlab-rails = pkgs.stdenv.mkDerivation {
     name = "gitlab-rails";
-    buildInputs = [ pkgs.makeWrapper ];
+    nativeBuildInputs = [ pkgs.makeWrapper ];
     dontBuild = true;
     dontUnpack = true;
     installPhase = ''
       mkdir -p $out/bin
       makeWrapper ${cfg.packages.gitlab.rubyEnv}/bin/rails $out/bin/gitlab-rails \
           ${concatStrings (mapAttrsToList (name: value: "--set ${name} '${value}' ") gitlabEnv)} \
-          --set PATH '${lib.makeBinPath [ pkgs.nodejs pkgs.gzip pkgs.git pkgs.gnutar postgresqlPackage pkgs.coreutils pkgs.procps ]}:$PATH' \
+          --set PATH '${lib.makeBinPath runtimeDeps}:$PATH' \
           --chdir '${cfg.packages.gitlab}/share/gitlab'
      '';
   };
@@ -468,9 +483,9 @@ in {
 
       redisUrl = mkOption {
         type = types.str;
-        default = "redis://localhost:${toString config.services.redis.servers.gitlab.port}/";
-        defaultText = literalExpression ''redis://localhost:''${toString config.services.redis.servers.gitlab.port}/'';
-        description = lib.mdDoc "Redis URL for all GitLab services except gitlab-shell";
+        default = "unix:/run/gitlab/redis.sock";
+        example = "redis://localhost:6379/";
+        description = lib.mdDoc "Redis URL for all GitLab services.";
       };
 
       extraGitlabRb = mkOption {
@@ -867,8 +882,41 @@ in {
         };
       };
 
+      workhorse.config = mkOption {
+        type = toml.type;
+        default = {};
+        example = literalExpression ''
+          {
+            object_storage.provider = "AWS";
+            object_storage.s3 = {
+              aws_access_key_id = "AKIAXXXXXXXXXXXXXXXX";
+              aws_secret_access_key = { _secret = "/var/keys/aws_secret_access_key"; };
+            };
+          };
+        '';
+        description = lib.mdDoc ''
+          Configuration options to add to Workhorse's configuration
+          file.
+
+          See
+          <https://gitlab.com/gitlab-org/gitlab/-/blob/master/workhorse/config.toml.example>
+          and
+          <https://docs.gitlab.com/ee/development/workhorse/configuration.html>
+          for examples and option documentation.
+
+          Options containing secret data should be set to an attribute
+          set containing the attribute `_secret` - a string pointing
+          to a file containing the value the option should be set
+          to. See the example to get a better picture of this: in the
+          resulting configuration file, the
+          `object_storage.s3.aws_secret_access_key` key will be set to
+          the contents of the {file}`/var/keys/aws_secret_access_key`
+          file.
+        '';
+      };
+
       extraConfig = mkOption {
-        type = types.attrs;
+        type = yaml.type;
         default = {};
         example = literalExpression ''
           {
@@ -972,8 +1020,9 @@ in {
     # Redis is required for the sidekiq queue runner.
     services.redis.servers.gitlab = {
       enable = mkDefault true;
-      port = mkDefault 31636;
-      bind = mkDefault "127.0.0.1";
+      user = mkDefault cfg.user;
+      unixSocket = mkDefault "/run/gitlab/redis.sock";
+      unixSocketPerm = mkDefault 770;
     };
 
     # We use postgres as the main data store.
@@ -1062,6 +1111,7 @@ in {
     # Ensure Docker Registry launches after the certificate generation job
     systemd.services.docker-registry = optionalAttrs cfg.registry.enable {
       wants = [ "gitlab-registry-cert.service" ];
+      after = [ "gitlab-registry-cert.service" ];
     };
 
     # Enable Docker Registry, if GitLab-Container Registry is enabled
@@ -1115,6 +1165,7 @@ in {
       "d ${gitlabConfig.production.shared.path}/lfs-objects 0750 ${cfg.user} ${cfg.group} -"
       "d ${gitlabConfig.production.shared.path}/packages 0750 ${cfg.user} ${cfg.group} -"
       "d ${gitlabConfig.production.shared.path}/pages 0750 ${cfg.user} ${cfg.group} -"
+      "d ${gitlabConfig.production.shared.path}/registry 0750 ${cfg.user} ${cfg.group} -"
       "d ${gitlabConfig.production.shared.path}/terraform_state 0750 ${cfg.user} ${cfg.group} -"
       "L+ /run/gitlab/config - - - - ${cfg.statePath}/config"
       "L+ /run/gitlab/log - - - - ${cfg.statePath}/log"
@@ -1168,6 +1219,7 @@ in {
           cp -rf --no-preserve=mode ${cfg.packages.gitlab}/share/gitlab/config.dist/* ${cfg.statePath}/config
           cp -rf --no-preserve=mode ${cfg.packages.gitlab}/share/gitlab/db/* ${cfg.statePath}/db
           ln -sf ${extraGitlabRb} ${cfg.statePath}/config/initializers/extra-gitlab.rb
+          ln -sf ${cableYml} ${cfg.statePath}/config/cable.yml
 
           ${cfg.packages.gitlab-shell}/bin/install
 
@@ -1357,6 +1409,7 @@ in {
       wantedBy = [ "gitlab.target" ];
       partOf = [ "gitlab.target" ];
       path = with pkgs; [
+        remarshal
         exiftool
         gitPackage
         gnutar
@@ -1371,6 +1424,17 @@ in {
         TimeoutSec = "infinity";
         Restart = "on-failure";
         WorkingDirectory = gitlabEnv.HOME;
+        ExecStartPre = pkgs.writeShellScript "gitlab-workhorse-pre-start" ''
+          set -o errexit -o pipefail -o nounset
+          shopt -s dotglob nullglob inherit_errexit
+
+          ${utils.genJqSecretsReplacementSnippet
+              cfg.workhorse.config
+              "${cfg.statePath}/config/gitlab-workhorse.json"}
+
+          json2toml "${cfg.statePath}/config/gitlab-workhorse.json" "${cfg.statePath}/config/gitlab-workhorse.toml"
+          rm "${cfg.statePath}/config/gitlab-workhorse.json"
+        '';
         ExecStart =
           "${cfg.packages.gitlab-workhorse}/bin/workhorse "
           + "-listenUmask 0 "
@@ -1378,6 +1442,7 @@ in {
           + "-listenAddr /run/gitlab/gitlab-workhorse.socket "
           + "-authSocket ${gitlabSocket} "
           + "-documentRoot ${cfg.packages.gitlab}/share/gitlab/public "
+          + "-config ${cfg.statePath}/config/gitlab-workhorse.toml "
           + "-secretPath ${cfg.statePath}/.gitlab_workhorse_secret";
       };
     };
diff --git a/nixos/modules/services/misc/gitolite.nix b/nixos/modules/services/misc/gitolite.nix
index 88b9ac4a0a3..012abda2d76 100644
--- a/nixos/modules/services/misc/gitolite.nix
+++ b/nixos/modules/services/misc/gitolite.nix
@@ -101,6 +101,14 @@ in
         '';
       };
 
+      description = mkOption {
+        type = types.str;
+        default = "Gitolite user";
+        description = lib.mdDoc ''
+          Gitolite user account's description.
+        '';
+      };
+
       group = mkOption {
         type = types.str;
         default = "gitolite";
@@ -145,7 +153,7 @@ in
     '';
 
     users.users.${cfg.user} = {
-      description     = "Gitolite user";
+      description     = cfg.description;
       home            = cfg.dataDir;
       uid             = config.ids.uids.gitolite;
       group           = cfg.group;
diff --git a/nixos/modules/services/networking/coturn.nix b/nixos/modules/services/networking/coturn.nix
index 4d83d2d48e3..2f34a72377c 100644
--- a/nixos/modules/services/networking/coturn.nix
+++ b/nixos/modules/services/networking/coturn.nix
@@ -335,9 +335,10 @@ in {
         preStart = ''
           cat ${configFile} > ${runConfig}
           ${optionalString (cfg.static-auth-secret-file != null) ''
-            STATIC_AUTH_SECRET="$(head -n1 ${cfg.static-auth-secret-file} || :)"
-            sed -e "s,#static-auth-secret#,$STATIC_AUTH_SECRET,g" \
-              -i ${runConfig}
+            ${pkgs.replace-secret}/bin/replace-secret \
+              "#static-auth-secret#" \
+              ${cfg.static-auth-secret-file} \
+              ${runConfig}
           '' }
           chmod 640 ${runConfig}
         '';
diff --git a/nixos/modules/services/networking/firefox-syncserver.nix b/nixos/modules/services/networking/firefox-syncserver.nix
index fa8e4fcaed2..d7d5df59a4e 100644
--- a/nixos/modules/services/networking/firefox-syncserver.nix
+++ b/nixos/modules/services/networking/firefox-syncserver.nix
@@ -19,6 +19,9 @@ let
       fxa_email_domain = "api.accounts.firefox.com";
       fxa_oauth_server_url = "https://oauth.accounts.firefox.com/v1";
       run_migrations = true;
+      # if JWK caching is not enabled the token server must verify tokens
+      # using the fxa api, on a thread pool with a static size.
+      additional_blocking_threads_for_fxa_requests = 10;
     } // lib.optionalAttrs cfg.singleNode.enable {
       # Single-node mode is likely to be used on small instances with little
       # capacity. The default value (0.1) can only ever release capacity when
@@ -309,11 +312,7 @@ in
         enableACME = cfg.singleNode.enableTLS;
         forceSSL = cfg.singleNode.enableTLS;
         locations."/" = {
-          proxyPass = "http://localhost:${toString cfg.settings.port}";
-          # source mentions that this header should be set
-          extraConfig = ''
-            add_header X-Content-Type-Options nosniff;
-          '';
+          proxyPass = "http://127.0.0.1:${toString cfg.settings.port}";
         };
       };
     };
diff --git a/nixos/modules/services/networking/iwd.nix b/nixos/modules/services/networking/iwd.nix
index 526e6ab0a7a..a9908b01a58 100644
--- a/nixos/modules/services/networking/iwd.nix
+++ b/nixos/modules/services/networking/iwd.nix
@@ -67,5 +67,5 @@ in
     };
   };
 
-  meta.maintainers = with lib.maintainers; [ mic92 dtzWill ];
+  meta.maintainers = with lib.maintainers; [ dtzWill ];
 }
diff --git a/nixos/modules/services/networking/jitsi-videobridge.nix b/nixos/modules/services/networking/jitsi-videobridge.nix
index 4455b7bcee4..eefaa70604c 100644
--- a/nixos/modules/services/networking/jitsi-videobridge.nix
+++ b/nixos/modules/services/networking/jitsi-videobridge.nix
@@ -70,7 +70,7 @@ in
       description = lib.mdDoc ''
         Videobridge configuration.
 
-        See <https://github.com/jitsi/jitsi-videobridge/blob/master/src/main/resources/reference.conf>
+        See <https://github.com/jitsi/jitsi-videobridge/blob/master/jvb/src/main/resources/reference.conf>
         for default configuration with comments.
       '';
     };
diff --git a/nixos/modules/services/networking/knot.nix b/nixos/modules/services/networking/knot.nix
index de238112826..ee7ea83456d 100644
--- a/nixos/modules/services/networking/knot.nix
+++ b/nixos/modules/services/networking/knot.nix
@@ -18,7 +18,7 @@ let
 
   knot-cli-wrappers = pkgs.stdenv.mkDerivation {
     name = "knot-cli-wrappers";
-    buildInputs = [ pkgs.makeWrapper ];
+    nativeBuildInputs = [ pkgs.makeWrapper ];
     buildCommand = ''
       mkdir -p $out/bin
       makeWrapper ${cfg.package}/bin/knotc "$out/bin/knotc" \
diff --git a/nixos/modules/services/networking/mullvad-vpn.nix b/nixos/modules/services/networking/mullvad-vpn.nix
index ca60682b4b8..42d55056084 100644
--- a/nixos/modules/services/networking/mullvad-vpn.nix
+++ b/nixos/modules/services/networking/mullvad-vpn.nix
@@ -39,7 +39,7 @@ with lib;
       startLimitBurst = 5;
       startLimitIntervalSec = 20;
       serviceConfig = {
-        ExecStart = "${pkgs.mullvad-vpn}/bin/mullvad-daemon -v --disable-stdout-timestamps";
+        ExecStart = "${pkgs.mullvad}/bin/mullvad-daemon -v --disable-stdout-timestamps";
         Restart = "always";
         RestartSec = 1;
       };
diff --git a/nixos/modules/services/networking/pptpd.nix b/nixos/modules/services/networking/pptpd.nix
index 2f206e813a5..703dda99803 100644
--- a/nixos/modules/services/networking/pptpd.nix
+++ b/nixos/modules/services/networking/pptpd.nix
@@ -82,7 +82,7 @@ with lib;
       ppp-pptpd-wrapped = pkgs.stdenv.mkDerivation {
         name         = "ppp-pptpd-wrapped";
         phases       = [ "installPhase" ];
-        buildInputs  = with pkgs; [ makeWrapper ];
+        nativeBuildInputs  = with pkgs; [ makeWrapper ];
         installPhase = ''
           mkdir -p $out/bin
           makeWrapper ${pkgs.ppp}/bin/pppd $out/bin/pppd \
diff --git a/nixos/modules/services/networking/tinc.nix b/nixos/modules/services/networking/tinc.nix
index 1f93d82f96e..09b23a60a4a 100644
--- a/nixos/modules/services/networking/tinc.nix
+++ b/nixos/modules/services/networking/tinc.nix
@@ -410,7 +410,7 @@ in
     environment.systemPackages = let
       cli-wrappers = pkgs.stdenv.mkDerivation {
         name = "tinc-cli-wrappers";
-        buildInputs = [ pkgs.makeWrapper ];
+        nativeBuildInputs = [ pkgs.makeWrapper ];
         buildCommand = ''
           mkdir -p $out/bin
           ${concatStringsSep "\n" (mapAttrsToList (network: data:
diff --git a/nixos/modules/services/networking/tmate-ssh-server.nix b/nixos/modules/services/networking/tmate-ssh-server.nix
new file mode 100644
index 00000000000..1b8f6662ef4
--- /dev/null
+++ b/nixos/modules/services/networking/tmate-ssh-server.nix
@@ -0,0 +1,122 @@
+{ config, lib, pkgs, ... }:
+with lib;
+let
+  cfg = config.services.tmate-ssh-server;
+
+  defaultKeysDir = "/etc/tmate-ssh-server-keys";
+  edKey = "${defaultKeysDir}/ssh_host_ed25519_key";
+  rsaKey = "${defaultKeysDir}/ssh_host_rsa_key";
+
+  keysDir =
+    if cfg.keysDir == null
+    then defaultKeysDir
+    else cfg.keysDir;
+
+  domain = config.networking.domain;
+in
+{
+  options.services.tmate-ssh-server = {
+    enable = mkEnableOption (mdDoc "tmate ssh server");
+
+    package = mkOption {
+      type = types.package;
+      description = mdDoc "The package containing tmate-ssh-server";
+      defaultText = literalExpression "pkgs.tmate-ssh-server";
+      default = pkgs.tmate-ssh-server;
+    };
+
+    host = mkOption {
+      type = types.str;
+      description = mdDoc "External host name";
+      defaultText = lib.literalExpression "config.networking.domain or config.networking.hostName ";
+      default =
+        if domain == null then
+          config.networking.hostName
+        else
+          domain;
+    };
+
+    port = mkOption {
+      type = types.port;
+      description = mdDoc "Listen port for the ssh server";
+      default = 2222;
+    };
+
+    openFirewall = mkOption {
+      type = types.bool;
+      default = true;
+      description = mdDoc "Whether to automatically open the specified ports in the firewall.";
+    };
+
+    advertisedPort = mkOption {
+      type = types.port;
+      description = mdDoc "External port advertised to clients";
+    };
+
+    keysDir = mkOption {
+      type = with types; nullOr str;
+      description = mdDoc "Directory containing ssh keys, defaulting to auto-generation";
+      default = null;
+    };
+  };
+
+  config = mkIf cfg.enable {
+
+    networking.firewall.allowedTCPPorts = optionals cfg.openFirewall [ cfg.port ];
+
+    services.tmate-ssh-server = {
+      advertisedPort = mkDefault cfg.port;
+    };
+
+    environment.systemPackages =
+      let
+        tmate-config = pkgs.writeText "tmate.conf"
+          ''
+            set -g tmate-server-host "${cfg.host}"
+            set -g tmate-server-port ${toString cfg.port}
+            set -g tmate-server-ed25519-fingerprint "@ed25519_fingerprint@"
+            set -g tmate-server-rsa-fingerprint "@rsa_fingerprint@"
+          '';
+      in
+      [
+        (pkgs.writeShellApplication {
+          name = "tmate-client-config";
+          runtimeInputs = with pkgs;[ openssh coreutils sd ];
+          text = ''
+            RSA_SIG="$(ssh-keygen -l -E SHA256 -f "${keysDir}/ssh_host_rsa_key.pub" | cut -d ' ' -f 2)"
+            ED25519_SIG="$(ssh-keygen -l -E SHA256 -f "${keysDir}/ssh_host_ed25519_key.pub" | cut -d ' ' -f 2)"
+            sd -sp '@ed25519_fingerprint@' "$ED25519_SIG" ${tmate-config} | \
+              sd -sp '@rsa_fingerprint@' "$RSA_SIG"
+          '';
+        })
+      ];
+
+    systemd.services.tmate-ssh-server = {
+      description = "tmate SSH Server";
+      after = [ "network.target" ];
+      wantedBy = [ "multi-user.target" ];
+      serviceConfig = {
+        ExecStart = "${cfg.package}/bin/tmate-ssh-server -h ${cfg.host} -p ${toString cfg.port} -q ${toString cfg.advertisedPort} -k ${keysDir}";
+      };
+      preStart = mkIf (cfg.keysDir == null) ''
+        if [[ ! -d ${defaultKeysDir} ]]
+        then
+          mkdir -p ${defaultKeysDir}
+        fi
+        if [[ ! -f ${edKey} ]]
+        then
+          ${pkgs.openssh}/bin/ssh-keygen -t ed25519 -f ${edKey} -N ""
+        fi
+        if [[ ! -f ${rsaKey} ]]
+        then
+          ${pkgs.openssh}/bin/ssh-keygen -t rsa -f ${rsaKey} -N ""
+        fi
+      '';
+    };
+  };
+
+  meta = {
+    maintainers = with maintainers; [ jlesquembre ];
+  };
+
+}
diff --git a/nixos/modules/services/networking/xl2tpd.nix b/nixos/modules/services/networking/xl2tpd.nix
index 8f710bca322..7d259570761 100644
--- a/nixos/modules/services/networking/xl2tpd.nix
+++ b/nixos/modules/services/networking/xl2tpd.nix
@@ -84,7 +84,7 @@ with lib;
       xl2tpd-ppp-wrapped = pkgs.stdenv.mkDerivation {
         name         = "xl2tpd-ppp-wrapped";
         phases       = [ "installPhase" ];
-        buildInputs  = with pkgs; [ makeWrapper ];
+        nativeBuildInputs  = with pkgs; [ makeWrapper ];
         installPhase = ''
           mkdir -p $out/bin
 
diff --git a/nixos/modules/services/security/endlessh-go.nix b/nixos/modules/services/security/endlessh-go.nix
new file mode 100644
index 00000000000..61cca553173
--- /dev/null
+++ b/nixos/modules/services/security/endlessh-go.nix
@@ -0,0 +1,138 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.services.endlessh-go;
+in
+{
+  options.services.endlessh-go = {
+    enable = mkEnableOption (mdDoc "endlessh-go service");
+
+    listenAddress = mkOption {
+      type = types.str;
+      default = "0.0.0.0";
+      example = "[::]";
+      description = mdDoc ''
+        Interface address to bind the endlessh-go daemon to SSH connections.
+      '';
+    };
+
+    port = mkOption {
+      type = types.port;
+      default = 2222;
+      example = 22;
+      description = mdDoc ''
+        Specifies on which port the endlessh-go daemon listens for SSH
+        connections.
+
+        Setting this to `22` may conflict with {option}`services.openssh`.
+      '';
+    };
+
+    prometheus = {
+      enable = mkEnableOption (mdDoc "Prometheus integration");
+
+      listenAddress = mkOption {
+        type = types.str;
+        default = "0.0.0.0";
+        example = "[::]";
+        description = mdDoc ''
+          Interface address to bind the endlessh-go daemon to answer Prometheus
+          queries.
+        '';
+      };
+
+      port = mkOption {
+        type = types.port;
+        default = 2112;
+        example = 9119;
+        description = mdDoc ''
+          Specifies on which port the endlessh-go daemon listens for Prometheus
+          queries.
+        '';
+      };
+    };
+
+    extraOptions = mkOption {
+      type = with types; listOf str;
+      default = [ ];
+      example = [ "-conn_type=tcp4" "-max_clients=8192" ];
+      description = mdDoc ''
+        Additional command line options to pass to the endlessh-go daemon.
+      '';
+    };
+
+    openFirewall = mkOption {
+      type = types.bool;
+      default = false;
+      description = lib.mdDoc ''
+        Whether to open a firewall port for the SSH listener.
+      '';
+    };
+  };
+
+  config = mkIf cfg.enable {
+    systemd.services.endlessh-go = {
+      description = "SSH tarpit";
+      requires = [ "network.target" ];
+      wantedBy = [ "multi-user.target" ];
+      serviceConfig =
+        let
+          needsPrivileges = cfg.port < 1024 || cfg.prometheus.port < 1024;
+          capabilities = [ "" ] ++ optionals needsPrivileges [ "CAP_NET_BIND_SERVICE" ];
+          rootDirectory = "/run/endlessh-go";
+        in
+        {
+          Restart = "always";
+          ExecStart = with cfg; concatStringsSep " " ([
+            "${pkgs.endlessh-go}/bin/endlessh-go"
+            "-logtostderr"
+            "-host=${listenAddress}"
+            "-port=${toString port}"
+          ] ++ optionals prometheus.enable [
+            "-enable_prometheus"
+            "-prometheus_host=${prometheus.listenAddress}"
+            "-prometheus_port=${toString prometheus.port}"
+          ] ++ extraOptions);
+          DynamicUser = true;
+          RootDirectory = rootDirectory;
+          BindReadOnlyPaths = [ builtins.storeDir ];
+          InaccessiblePaths = [ "-+${rootDirectory}" ];
+          RuntimeDirectory = baseNameOf rootDirectory;
+          RuntimeDirectoryMode = "700";
+          AmbientCapabilities = capabilities;
+          CapabilityBoundingSet = capabilities;
+          UMask = "0077";
+          LockPersonality = true;
+          MemoryDenyWriteExecute = true;
+          NoNewPrivileges = true;
+          PrivateDevices = true;
+          PrivateTmp = true;
+          PrivateUsers = !needsPrivileges;
+          ProtectClock = true;
+          ProtectControlGroups = true;
+          ProtectHome = true;
+          ProtectHostname = true;
+          ProtectKernelLogs = true;
+          ProtectKernelModules = true;
+          ProtectKernelTunables = true;
+          ProtectSystem = "strict";
+          ProtectProc = "noaccess";
+          ProcSubset = "pid";
+          RemoveIPC = true;
+          RestrictAddressFamilies = [ "AF_INET" "AF_INET6" ];
+          RestrictNamespaces = true;
+          RestrictRealtime = true;
+          RestrictSUIDSGID = true;
+          SystemCallArchitectures = "native";
+          SystemCallFilter = [ "@system-service" "~@resources" "~@privileged" ];
+        };
+    };
+
+    networking.firewall.allowedTCPPorts = with cfg;
+      optionals openFirewall [ port prometheus.port ];
+  };
+
+  meta.maintainers = with maintainers; [ azahi ];
+}
diff --git a/nixos/modules/services/security/privacyidea.nix b/nixos/modules/services/security/privacyidea.nix
index 5cd338ebf7f..e446e606cad 100644
--- a/nixos/modules/services/security/privacyidea.nix
+++ b/nixos/modules/services/security/privacyidea.nix
@@ -61,6 +61,12 @@ let
       (flip mapAttrs cfg.ldap-proxy.settings
         (const (mapAttrs (const renderValue)))));
 
+  privacyidea-token-janitor = pkgs.writeShellScriptBin "privacyidea-token-janitor" ''
+    exec -a privacyidea-token-janitor \
+      /run/wrappers/bin/sudo -u ${cfg.user} \
+      env PRIVACYIDEA_CONFIGFILE=${cfg.stateDir}/privacyidea.cfg \
+      ${penv}/bin/privacyidea-token-janitor $@
+  '';
 in
 
 {
@@ -178,6 +184,42 @@ in
         description = lib.mdDoc "Group account under which PrivacyIDEA runs.";
       };
 
+      tokenjanitor = {
+        enable = mkEnableOption (lib.mdDoc "automatic runs of the token janitor");
+        interval = mkOption {
+          default = "quarterly";
+          type = types.str;
+          description = lib.mdDoc ''
+            Interval in which the cleanup program is supposed to run.
+            See {manpage}`systemd.time(7)` for further information.
+          '';
+        };
+        action = mkOption {
+          type = types.enum [ "delete" "mark" "disable" "unassign" ];
+          description = lib.mdDoc ''
+            Which action to take for matching tokens.
+          '';
+        };
+        unassigned = mkOption {
+          default = false;
+          type = types.bool;
+          description = lib.mdDoc ''
+            Whether to search for **unassigned** tokens
+            and apply [](#opt-services.privacyidea.tokenjanitor.action)
+            onto them.
+          '';
+        };
+        orphaned = mkOption {
+          default = true;
+          type = types.bool;
+          description = lib.mdDoc ''
+            Whether to search for **orphaned** tokens
+            and apply [](#opt-services.privacyidea.tokenjanitor.action)
+            onto them.
+          '';
+        };
+      };
+
       ldap-proxy = {
         enable = mkEnableOption (lib.mdDoc "PrivacyIDEA LDAP Proxy");
 
@@ -228,10 +270,60 @@ in
 
     (mkIf cfg.enable {
 
-      environment.systemPackages = [ pkgs.privacyidea ];
+      assertions = [
+        {
+          assertion = cfg.tokenjanitor.enable -> (cfg.tokenjanitor.orphaned || cfg.tokenjanitor.unassigned);
+          message = ''
+            privacyidea-token-janitor has no effect if neither orphaned nor unassigned tokens
+            are to be searched.
+          '';
+        }
+      ];
+
+      environment.systemPackages = [ pkgs.privacyidea (hiPrio privacyidea-token-janitor) ];
 
       services.postgresql.enable = mkDefault true;
 
+      systemd.services.privacyidea-tokenjanitor = mkIf cfg.tokenjanitor.enable {
+        environment.PRIVACYIDEA_CONFIGFILE = "${cfg.stateDir}/privacyidea.cfg";
+        path = [ penv ];
+        serviceConfig = {
+          CapabilityBoundingSet = [ "" ];
+          ExecStart = "${pkgs.writeShellScript "pi-token-janitor" ''
+            ${optionalString cfg.tokenjanitor.orphaned ''
+              echo >&2 "Removing orphaned tokens..."
+              privacyidea-token-janitor find \
+                --orphaned true \
+                --action ${cfg.tokenjanitor.action}
+            ''}
+            ${optionalString cfg.tokenjanitor.unassigned ''
+              echo >&2 "Removing unassigned tokens..."
+              privacyidea-token-janitor find \
+                --assigned false \
+                --action ${cfg.tokenjanitor.action}
+            ''}
+          ''}";
+          Group = cfg.group;
+          LockPersonality = true;
+          MemoryDenyWriteExecute = true;
+          ProtectHome = true;
+          ProtectHostname = true;
+          ProtectKernelLogs = true;
+          ProtectKernelModules = true;
+          ProtectKernelTunables = true;
+          ProtectSystem = "strict";
+          ReadWritePaths = cfg.stateDir;
+          Type = "oneshot";
+          User = cfg.user;
+          WorkingDirectory = cfg.stateDir;
+        };
+      };
+      systemd.timers.privacyidea-tokenjanitor = mkIf cfg.tokenjanitor.enable {
+        wantedBy = [ "timers.target" ];
+        timerConfig.OnCalendar = cfg.tokenjanitor.interval;
+        timerConfig.Persistent = true;
+      };
+
       systemd.services.privacyidea = let
         piuwsgi = pkgs.writeText "uwsgi.json" (builtins.toJSON {
           uwsgi = {
diff --git a/nixos/modules/services/web-apps/mediawiki.nix b/nixos/modules/services/web-apps/mediawiki.nix
index a32db718848..e332847f5a2 100644
--- a/nixos/modules/services/web-apps/mediawiki.nix
+++ b/nixos/modules/services/web-apps/mediawiki.nix
@@ -35,7 +35,7 @@ let
   };
 
   mediawikiScripts = pkgs.runCommand "mediawiki-scripts" {
-    buildInputs = [ pkgs.makeWrapper ];
+    nativeBuildInputs = [ pkgs.makeWrapper ];
     preferLocalBuild = true;
   } ''
     mkdir -p $out/bin
diff --git a/nixos/modules/system/boot/systemd/initrd.nix b/nixos/modules/system/boot/systemd/initrd.nix
index e843214f855..03f94c426cb 100644
--- a/nixos/modules/system/boot/systemd/initrd.nix
+++ b/nixos/modules/system/boot/systemd/initrd.nix
@@ -372,6 +372,8 @@ in {
         "/etc/os-release".source = config.boot.initrd.osRelease;
         "/etc/initrd-release".source = config.boot.initrd.osRelease;
 
+      } // optionalAttrs (config.environment.etc ? "modprobe.d/nixos.conf") {
+        "/etc/modprobe.d/nixos.conf".source = config.environment.etc."modprobe.d/nixos.conf".source;
       };
 
       storePaths = [
diff --git a/nixos/modules/tasks/filesystems/jfs.nix b/nixos/modules/tasks/filesystems/jfs.nix
index 700f05af2be..6d80c4c657d 100644
--- a/nixos/modules/tasks/filesystems/jfs.nix
+++ b/nixos/modules/tasks/filesystems/jfs.nix
@@ -12,7 +12,7 @@ in
 
     boot.initrd.kernelModules = mkIf inInitrd [ "jfs" ];
 
-    boot.initrd.extraUtilsCommands = mkIf (inInitrd && !boot.initrd.systemd.enable) ''
+    boot.initrd.extraUtilsCommands = mkIf (inInitrd && !config.boot.initrd.systemd.enable) ''
       copy_bin_and_libs ${pkgs.jfsutils}/sbin/fsck.jfs
     '';
   };
diff --git a/nixos/modules/virtualisation/azure-agent.nix b/nixos/modules/virtualisation/azure-agent.nix
index 31047c4ddc0..abe6455a1a6 100644
--- a/nixos/modules/virtualisation/azure-agent.nix
+++ b/nixos/modules/virtualisation/azure-agent.nix
@@ -17,7 +17,7 @@ let
 
     patches = [ ./azure-agent-entropy.patch ];
 
-    buildInputs = [ makeWrapper python pythonPackages.wrapPython ];
+    nativeBuildInputs = [ makeWrapper python pythonPackages.wrapPython ];
     runtimeDeps = [ findutils gnugrep gawk coreutils openssl openssh
                     nettools # for hostname
                     procps # for pidof
diff --git a/nixos/modules/virtualisation/virtualbox-host.nix b/nixos/modules/virtualisation/virtualbox-host.nix
index 5a2ec4939d9..b1565a09682 100644
--- a/nixos/modules/virtualisation/virtualbox-host.nix
+++ b/nixos/modules/virtualisation/virtualbox-host.nix
@@ -104,16 +104,18 @@ in
         group = "vboxusers";
         setuid = true;
       };
+      executables = [
+        "VBoxHeadless"
+        "VBoxNetAdpCtl"
+        "VBoxNetDHCP"
+        "VBoxNetNAT"
+        "VBoxVolInfo"
+      ] ++ (lib.optionals (!cfg.headless) [
+        "VBoxSDL"
+        "VirtualBoxVM"
+      ]);
     in mkIf cfg.enableHardening
-      (builtins.listToAttrs (map (x: { name = x; value = mkSuid x; }) [
-      "VBoxHeadless"
-      "VBoxNetAdpCtl"
-      "VBoxNetDHCP"
-      "VBoxNetNAT"
-      "VBoxSDL"
-      "VBoxVolInfo"
-      "VirtualBoxVM"
-    ]));
+      (builtins.listToAttrs (map (x: { name = x; value = mkSuid x; }) executables));
 
     users.groups.vboxusers.gid = config.ids.gids.vboxusers;
 
diff --git a/nixos/release-combined.nix b/nixos/release-combined.nix
index e8677f7e1e9..a11ee31ab8d 100644
--- a/nixos/release-combined.nix
+++ b/nixos/release-combined.nix
@@ -4,8 +4,8 @@
 
 { nixpkgs ? { outPath = (import ../lib).cleanSource ./..; revCount = 56789; shortRev = "gfedcba"; }
 , stableBranch ? false
-, supportedSystems ? [ "x86_64-linux" ]
-, limitedSupportedSystems ? [ "i686-linux" "aarch64-linux" ]
+, supportedSystems ? [ "aarch64-linux" "x86_64-linux" ]
+, limitedSupportedSystems ? [ "i686-linux" ]
 }:
 
 let
@@ -50,17 +50,17 @@ in rec {
         (onFullSupported "nixos.dummy")
         (onAllSupported "nixos.iso_minimal")
         (onSystems ["x86_64-linux" "aarch64-linux"] "nixos.amazonImage")
-        (onSystems ["x86_64-linux"] "nixos.iso_plasma5")
-        (onSystems ["x86_64-linux"] "nixos.iso_gnome")
+        (onFullSupported "nixos.iso_plasma5")
+        (onFullSupported "nixos.iso_gnome")
         (onFullSupported "nixos.manual")
         (onSystems ["x86_64-linux"] "nixos.ova")
         (onSystems ["aarch64-linux"] "nixos.sd_image")
         (onSystems ["x86_64-linux"] "nixos.tests.boot.biosCdrom")
         (onSystems ["x86_64-linux"] "nixos.tests.boot.biosUsb")
         (onFullSupported "nixos.tests.boot-stage1")
-        (onSystems ["x86_64-linux"] "nixos.tests.boot.uefiCdrom")
-        (onSystems ["x86_64-linux"] "nixos.tests.boot.uefiUsb")
-        (onSystems ["x86_64-linux"] "nixos.tests.chromium")
+        (onFullSupported "nixos.tests.boot.uefiCdrom")
+        (onFullSupported "nixos.tests.boot.uefiUsb")
+        (onFullSupported "nixos.tests.chromium")
         (onFullSupported "nixos.tests.containers-imperative")
         (onFullSupported "nixos.tests.containers-ip")
         (onSystems ["x86_64-linux"] "nixos.tests.docker")
diff --git a/nixos/release-small.nix b/nixos/release-small.nix
index 8367610fb7f..1719d6738c5 100644
--- a/nixos/release-small.nix
+++ b/nixos/release-small.nix
@@ -4,7 +4,7 @@
 
 { nixpkgs ? { outPath = (import ../lib).cleanSource ./..; revCount = 56789; shortRev = "gfedcba"; }
 , stableBranch ? false
-, supportedSystems ? [ "x86_64-linux" ] # no i686-linux
+, supportedSystems ? [ "aarch64-linux" "x86_64-linux" ] # no i686-linux
 }:
 
 let
@@ -53,7 +53,8 @@ in rec {
       };
       boot = {
         inherit (nixos'.tests.boot)
-          biosCdrom;
+          biosCdrom
+          uefiCdrom;
       };
     };
   };
@@ -83,45 +84,56 @@ in rec {
       vim;
   };
 
-  tested = pkgs.releaseTools.aggregate {
+  tested = let
+    onSupported = x: map (system: "${x}.${system}") supportedSystems;
+    onSystems = systems: x: map (system: "${x}.${system}")
+      (pkgs.lib.intersectLists systems supportedSystems);
+  in pkgs.releaseTools.aggregate {
     name = "nixos-${nixos.channel.version}";
     meta = {
       description = "Release-critical builds for the NixOS channel";
       maintainers = [ lib.maintainers.eelco ];
     };
-    constituents =
-      [ "nixos.channel"
-        "nixos.dummy.x86_64-linux"
-        "nixos.iso_minimal.x86_64-linux"
-        "nixos.amazonImage.x86_64-linux"
-        "nixos.manual.x86_64-linux"
-        "nixos.tests.boot.biosCdrom.x86_64-linux"
-        "nixos.tests.containers-imperative.x86_64-linux"
-        "nixos.tests.containers-ip.x86_64-linux"
-        "nixos.tests.firewall.x86_64-linux"
-        "nixos.tests.installer.lvm.x86_64-linux"
-        "nixos.tests.installer.separateBoot.x86_64-linux"
-        "nixos.tests.installer.simple.x86_64-linux"
-        "nixos.tests.ipv6.x86_64-linux"
-        "nixos.tests.login.x86_64-linux"
-        "nixos.tests.misc.x86_64-linux"
-        "nixos.tests.nat.firewall-conntrack.x86_64-linux"
-        "nixos.tests.nat.firewall.x86_64-linux"
-        "nixos.tests.nat.standalone.x86_64-linux"
-        # fails with kernel >= 5.15 https://github.com/NixOS/nixpkgs/pull/152505#issuecomment-1005049314
-        #"nixos.tests.nfs3.simple.x86_64-linux"
-        "nixos.tests.openssh.x86_64-linux"
-        "nixos.tests.php.fpm.x86_64-linux"
-        "nixos.tests.php.pcre.x86_64-linux"
-        "nixos.tests.predictable-interface-names.predictable.x86_64-linux"
-        "nixos.tests.predictable-interface-names.predictableNetworkd.x86_64-linux"
-        "nixos.tests.predictable-interface-names.unpredictable.x86_64-linux"
-        "nixos.tests.predictable-interface-names.unpredictableNetworkd.x86_64-linux"
-        "nixos.tests.proxy.x86_64-linux"
-        "nixos.tests.simple.x86_64-linux"
-        "nixpkgs.jdk.x86_64-linux"
+    constituents = lib.flatten [
+      [
+        "nixos.channel"
         "nixpkgs.tarball"
-      ];
+      ]
+      (map (onSystems [ "x86_64-linux" ]) [
+        "nixos.tests.boot.biosCdrom"
+        "nixos.tests.installer.lvm"
+        "nixos.tests.installer.separateBoot"
+        "nixos.tests.installer.simple"
+      ])
+      (map onSupported [
+        "nixos.dummy"
+        "nixos.iso_minimal"
+        "nixos.amazonImage"
+        "nixos.manual"
+        "nixos.tests.boot.uefiCdrom"
+        "nixos.tests.containers-imperative"
+        "nixos.tests.containers-ip"
+        "nixos.tests.firewall"
+        "nixos.tests.ipv6"
+        "nixos.tests.login"
+        "nixos.tests.misc"
+        "nixos.tests.nat.firewall-conntrack"
+        "nixos.tests.nat.firewall"
+        "nixos.tests.nat.standalone"
+        # fails with kernel >= 5.15 https://github.com/NixOS/nixpkgs/pull/152505#issuecomment-1005049314
+        #"nixos.tests.nfs3.simple"
+        "nixos.tests.openssh"
+        "nixos.tests.php.fpm"
+        "nixos.tests.php.pcre"
+        "nixos.tests.predictable-interface-names.predictable"
+        "nixos.tests.predictable-interface-names.predictableNetworkd"
+        "nixos.tests.predictable-interface-names.unpredictable"
+        "nixos.tests.predictable-interface-names.unpredictableNetworkd"
+        "nixos.tests.proxy"
+        "nixos.tests.simple"
+        "nixpkgs.jdk"
+      ])
+    ];
   };
 
 }
diff --git a/nixos/release.nix b/nixos/release.nix
index 4f27e5dbb21..919aa86a2d6 100644
--- a/nixos/release.nix
+++ b/nixos/release.nix
@@ -169,13 +169,13 @@ in rec {
     inherit system;
   });
 
-  iso_plasma5 = forMatchingSystems [ "x86_64-linux" ] (system: makeIso {
+  iso_plasma5 = forMatchingSystems supportedSystems (system: makeIso {
     module = ./modules/installer/cd-dvd/installation-cd-graphical-calamares-plasma5.nix;
     type = "plasma5";
     inherit system;
   });
 
-  iso_gnome = forMatchingSystems [ "x86_64-linux" ] (system: makeIso {
+  iso_gnome = forMatchingSystems supportedSystems (system: makeIso {
     module = ./modules/installer/cd-dvd/installation-cd-graphical-calamares-gnome.nix;
     type = "gnome";
     inherit system;
diff --git a/nixos/tests/acme.nix b/nixos/tests/acme.nix
index d3a436080eb..d540bc6ec31 100644
--- a/nixos/tests/acme.nix
+++ b/nixos/tests/acme.nix
@@ -41,6 +41,16 @@
     inherit documentRoot;
   };
 
+  simpleConfig = {
+    security.acme = {
+      certs."http.example.test" = {
+        listenHTTP = ":80";
+      };
+    };
+
+    networking.firewall.allowedTCPPorts = [ 80 ];
+  };
+
   # Base specialisation config for testing general ACME features
   webserverBasicConfig = {
     services.nginx.enable = true;
@@ -173,6 +183,26 @@ in {
       services.nginx.logError = "stderr info";
 
       specialisation = {
+        # Tests HTTP-01 verification using Lego's built-in web server
+        http01lego.configuration = simpleConfig;
+
+        renew.configuration = lib.mkMerge [
+          simpleConfig
+          {
+            # Pebble provides 5 year long certs,
+            # needs to be higher than that to test renewal
+            security.acme.certs."http.example.test".validMinDays = 9999;
+          }
+        ];
+
+        # Tests that account creds can be safely changed.
+        accountchange.configuration = lib.mkMerge [
+          simpleConfig
+          {
+            security.acme.certs."http.example.test".email = "admin@example.test";
+          }
+        ];
+
         # First derivation used to test general ACME features
         general.configuration = { ... }: let
           caDomain = nodes.acme.test-support.acme.caDomain;
@@ -446,7 +476,35 @@ in {
 
       download_ca_certs(client)
 
-      # Perform general tests first
+      # Perform http-01 w/ lego test first
+      with subtest("Can request certificate with Lego's built in web server"):
+          switch_to(webserver, "http01lego")
+          webserver.wait_for_unit("acme-finished-http.example.test.target")
+          check_fullchain(webserver, "http.example.test")
+          check_issuer(webserver, "http.example.test", "pebble")
+
+      # Perform renewal test
+      with subtest("Can renew certificates when they expire"):
+          hash = webserver.succeed("sha256sum /var/lib/acme/http.example.test/cert.pem")
+          switch_to(webserver, "renew")
+          webserver.wait_for_unit("acme-finished-http.example.test.target")
+          check_fullchain(webserver, "http.example.test")
+          check_issuer(webserver, "http.example.test", "pebble")
+          hash_after = webserver.succeed("sha256sum /var/lib/acme/http.example.test/cert.pem")
+          assert hash != hash_after
+
+      # Perform account change test
+      with subtest("Handles email change correctly"):
+          hash = webserver.succeed("sha256sum /var/lib/acme/http.example.test/cert.pem")
+          switch_to(webserver, "accountchange")
+          webserver.wait_for_unit("acme-finished-http.example.test.target")
+          check_fullchain(webserver, "http.example.test")
+          check_issuer(webserver, "http.example.test", "pebble")
+          hash_after = webserver.succeed("sha256sum /var/lib/acme/http.example.test/cert.pem")
+          # Has to do a full run to register account, which creates new certs.
+          assert hash != hash_after
+
+      # Perform general tests
       switch_to(webserver, "general")
 
       with subtest("Can request certificate with HTTP-01 challenge"):
diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix
index 8ec73cc05c8..3b697139dc8 100644
--- a/nixos/tests/all-tests.nix
+++ b/nixos/tests/all-tests.nix
@@ -119,7 +119,7 @@ in {
   certmgr = handleTest ./certmgr.nix {};
   cfssl = handleTestOn ["x86_64-linux"] ./cfssl.nix {};
   charliecloud = handleTest ./charliecloud.nix {};
-  chromium = (handleTestOn ["x86_64-linux"] ./chromium.nix {}).stable or {};
+  chromium = (handleTestOn ["aarch64-linux" "x86_64-linux"] ./chromium.nix {}).stable or {};
   cinnamon = handleTest ./cinnamon.nix {};
   cjdns = handleTest ./cjdns.nix {};
   clickhouse = handleTest ./clickhouse.nix {};
@@ -180,6 +180,7 @@ in {
   ejabberd = handleTest ./xmpp/ejabberd.nix {};
   elk = handleTestOn ["x86_64-linux"] ./elk.nix {};
   emacs-daemon = handleTest ./emacs-daemon.nix {};
+  endlessh-go = handleTest ./endlessh-go.nix {};
   engelsystem = handleTest ./engelsystem.nix {};
   enlightenment = handleTest ./enlightenment.nix {};
   env = handleTest ./env.nix {};
@@ -597,6 +598,7 @@ in {
   systemd-initrd-btrfs-raid = handleTest ./systemd-initrd-btrfs-raid.nix {};
   systemd-initrd-luks-keyfile = handleTest ./systemd-initrd-luks-keyfile.nix {};
   systemd-initrd-luks-password = handleTest ./systemd-initrd-luks-password.nix {};
+  systemd-initrd-modprobe = handleTest ./systemd-initrd-modprobe.nix {};
   systemd-initrd-shutdown = handleTest ./systemd-shutdown.nix { systemdStage1 = true; };
   systemd-initrd-simple = handleTest ./systemd-initrd-simple.nix {};
   systemd-initrd-swraid = handleTest ./systemd-initrd-swraid.nix {};
@@ -625,12 +627,15 @@ in {
   tinc = handleTest ./tinc {};
   tinydns = handleTest ./tinydns.nix {};
   tinywl = handleTest ./tinywl.nix {};
+  tmate-ssh-server = handleTest ./tmate-ssh-server.nix { };
   tomcat = handleTest ./tomcat.nix {};
   tor = handleTest ./tor.nix {};
   # traefik test relies on docker-containers
   traefik = handleTestOn ["x86_64-linux"] ./traefik.nix {};
   trafficserver = handleTest ./trafficserver.nix {};
   transmission = handleTest ./transmission.nix {};
+  # tracee requires bpf
+  tracee = handleTestOn ["x86_64-linux"] ./tracee.nix {};
   trezord = handleTest ./trezord.nix {};
   trickster = handleTest ./trickster.nix {};
   trilium-server = handleTestOn ["x86_64-linux"] ./trilium-server.nix {};
diff --git a/nixos/tests/endlessh-go.nix b/nixos/tests/endlessh-go.nix
new file mode 100644
index 00000000000..b261dbf1c56
--- /dev/null
+++ b/nixos/tests/endlessh-go.nix
@@ -0,0 +1,58 @@
+import ./make-test-python.nix ({ lib, pkgs, ... }:
+{
+  name = "endlessh-go";
+  meta.maintainers = with lib.maintainers; [ azahi ];
+
+  nodes = {
+    server = { ... }: {
+      services.endlessh-go = {
+        enable = true;
+        prometheus.enable = true;
+        openFirewall = true;
+      };
+
+      specialisation = {
+        unprivileged.configuration = {
+          services.endlessh-go = {
+            port = 2222;
+            prometheus.port = 9229;
+          };
+        };
+
+        privileged.configuration = {
+          services.endlessh-go = {
+            port = 22;
+            prometheus.port = 92;
+          };
+        };
+      };
+    };
+
+    client = { pkgs, ... }: {
+      environment.systemPackages = with pkgs; [ curl netcat ];
+    };
+  };
+
+  testScript = ''
+    def activate_specialisation(name: str):
+        server.succeed(f"/run/booted-system/specialisation/{name}/bin/switch-to-configuration test >&2")
+
+    start_all()
+
+    with subtest("Unprivileged"):
+        activate_specialisation("unprivileged")
+        server.wait_for_unit("endlessh-go.service")
+        server.wait_for_open_port(2222)
+        server.wait_for_open_port(9229)
+        client.succeed("nc -dvW5 server 2222")
+        client.succeed("curl -kv server:9229/metrics")
+
+    with subtest("Privileged"):
+        activate_specialisation("privileged")
+        server.wait_for_unit("endlessh-go.service")
+        server.wait_for_open_port(22)
+        server.wait_for_open_port(92)
+        client.succeed("nc -dvW5 server 22")
+        client.succeed("curl -kv server:92/metrics")
+  '';
+})
diff --git a/nixos/tests/hydra/common.nix b/nixos/tests/hydra/common.nix
index fdf2b2c6f6d..2bce03418e1 100644
--- a/nixos/tests/hydra/common.nix
+++ b/nixos/tests/hydra/common.nix
@@ -16,7 +16,7 @@
     createTrivialProject = pkgs.stdenv.mkDerivation {
       name = "create-trivial-project";
       dontUnpack = true;
-      buildInputs = [ pkgs.makeWrapper ];
+      nativeBuildInputs = [ pkgs.makeWrapper ];
       installPhase = "install -m755 -D ${./create-trivial-project.sh} $out/bin/create-trivial-project.sh";
       postFixup = ''
         wrapProgram "$out/bin/create-trivial-project.sh" --prefix PATH ":" ${pkgs.lib.makeBinPath [ pkgs.curl ]} --set EXPR_PATH ${trivialJob}
diff --git a/nixos/tests/kubernetes/base.nix b/nixos/tests/kubernetes/base.nix
index d4410beb937..714ac3098c0 100644
--- a/nixos/tests/kubernetes/base.nix
+++ b/nixos/tests/kubernetes/base.nix
@@ -18,7 +18,7 @@ let
         ${master.ip}  api.${domain}
         ${concatMapStringsSep "\n" (machineName: "${machines.${machineName}.ip}  ${machineName}.${domain}") (attrNames machines)}
       '';
-      wrapKubectl = with pkgs; runCommand "wrap-kubectl" { buildInputs = [ makeWrapper ]; } ''
+      wrapKubectl = with pkgs; runCommand "wrap-kubectl" { nativeBuildInputs = [ makeWrapper ]; } ''
         mkdir -p $out/bin
         makeWrapper ${pkgs.kubernetes}/bin/kubectl $out/bin/kubectl --set KUBECONFIG "/etc/kubernetes/cluster-admin.kubeconfig"
       '';
diff --git a/nixos/tests/paperless.nix b/nixos/tests/paperless.nix
index 12883cd62c6..b97834835c2 100644
--- a/nixos/tests/paperless.nix
+++ b/nixos/tests/paperless.nix
@@ -40,5 +40,13 @@ import ./make-test-python.nix ({ lib, ... }: {
         docs = json.loads(machine.succeed("curl -u admin:admin -fs localhost:28981/api/documents/"))['results']
         assert "2005-10-16" in docs[0]['created']
         assert "2005-10-16" in docs[1]['created']
+
+    # Detects gunicorn issues, see PR #190888
+    with subtest("Document metadata can be accessed"):
+        metadata = json.loads(machine.succeed("curl -u admin:admin -fs localhost:28981/api/documents/1/metadata/"))
+        assert "original_checksum" in metadata
+
+        metadata = json.loads(machine.succeed("curl -u admin:admin -fs localhost:28981/api/documents/2/metadata/"))
+        assert "original_checksum" in metadata
   '';
 })
diff --git a/nixos/tests/pulseaudio.nix b/nixos/tests/pulseaudio.nix
index cfdc61bc6c2..dc8e33ccd55 100644
--- a/nixos/tests/pulseaudio.nix
+++ b/nixos/tests/pulseaudio.nix
@@ -1,10 +1,10 @@
 let
-  mkTest = { systemWide ? false }:
+  mkTest = { systemWide ? false , fullVersion ? false }:
     import ./make-test-python.nix ({ pkgs, lib, ... }:
       let
         testFile = pkgs.fetchurl {
           url =
-            "https://file-examples-com.github.io/uploads/2017/11/file_example_MP3_700KB.mp3";
+            "https://file-examples.com/storage/fe5947fd2362fc197a3c2df/2017/11/file_example_MP3_700KB.mp3";
           hash = "sha256-+iggJW8s0/LfA/okfXsB550/55Q0Sq3OoIzuBrzOPJQ=";
         };
 
@@ -22,7 +22,7 @@ let
           testPlay32 = { inherit (pkgs.pkgsi686Linux) sox alsa-utils; };
         };
       in {
-        name = "pulseaudio${lib.optionalString systemWide "-systemWide"}";
+        name = "pulseaudio${lib.optionalString fullVersion "Full"}${lib.optionalString systemWide "-systemWide"}";
         meta = with pkgs.lib.maintainers; {
           maintainers = [ synthetica ] ++ pkgs.pulseaudio.meta.maintainers;
         };
@@ -35,12 +35,14 @@ let
               enable = true;
               support32Bit = true;
               inherit systemWide;
+            } // lib.optionalAttrs fullVersion {
+              package = pkgs.pulseaudioFull;
             };
 
             environment.systemPackages = [ testers.testPlay pkgs.pavucontrol ]
               ++ lib.optional pkgs.stdenv.isx86_64 testers.testPlay32;
           } // lib.optionalAttrs systemWide {
-            users.users.alice.extraGroups = [ "audio" ];
+            users.users.alice.extraGroups = [ "pulse-access" ];
             systemd.services.pulseaudio.wantedBy = [ "multi-user.target" ];
           };
 
@@ -58,14 +60,21 @@ let
           ''}
           machine.screenshot("testPlay")
 
+          ${lib.optionalString (!systemWide) ''
+            machine.send_chars("pacmd info && touch /tmp/pacmd_success\n")
+            machine.wait_for_file("/tmp/pacmd_success")
+          ''}
+
           # Pavucontrol only loads when Pulseaudio is running. If it isn't, the
-          # text "Playback" (one of the tabs) will never show.
+          # text "Dummy Output" (sound device name) will never show.
           machine.send_chars("pavucontrol\n")
-          machine.wait_for_text("Playback")
+          machine.wait_for_text("Dummy Output")
           machine.screenshot("Pavucontrol")
         '';
       });
 in builtins.mapAttrs (key: val: mkTest val) {
-  user = { systemWide = false; };
-  system = { systemWide = true; };
+  user = { systemWide = false; fullVersion = false; };
+  system = { systemWide = true; fullVersion = false; };
+  userFull = { systemWide = false; fullVersion = true; };
+  systemFull = { systemWide = true; fullVersion = true; };
 }
diff --git a/nixos/tests/retroarch.nix b/nixos/tests/retroarch.nix
index c506ed02da8..f4bf232ea72 100644
--- a/nixos/tests/retroarch.nix
+++ b/nixos/tests/retroarch.nix
@@ -2,7 +2,7 @@ import ./make-test-python.nix ({ pkgs, ... }:
 
   {
     name = "retroarch";
-    meta = with pkgs.lib.maintainers; { maintainers = [ j0hax ]; };
+    meta = with pkgs.lib; { maintainers = teams.libretro.members ++ [ maintainers.j0hax ]; };
 
     nodes.machine = { ... }:
 
@@ -11,7 +11,7 @@ import ./make-test-python.nix ({ pkgs, ... }:
         services.xserver.enable = true;
         services.xserver.desktopManager.retroarch = {
           enable = true;
-          package = pkgs.retroarchFull;
+          package = pkgs.retroarchBare;
         };
         services.xserver.displayManager = {
           sddm.enable = true;
diff --git a/nixos/tests/seafile.nix b/nixos/tests/seafile.nix
index 6eec8b1fbe5..78e735f4fed 100644
--- a/nixos/tests/seafile.nix
+++ b/nixos/tests/seafile.nix
@@ -79,18 +79,14 @@ import ./make-test-python.nix ({ pkgs, ... }:
               f"seaf-cli download -l {libid} -s http://server -u admin\@example.com -p seafile_password -d . >&2"
           )
 
-          client1.sleep(3)
-
-          client1.succeed("seaf-cli status |grep synchronized >&2")
+          client1.wait_until_succeeds("seaf-cli status |grep synchronized >&2")
 
           client1.succeed("ls -la >&2")
           client1.succeed("ls -la test01 >&2")
 
           client1.execute("echo bla > test01/first_file")
 
-          client1.sleep(2)
-
-          client1.succeed("seaf-cli status |grep synchronized >&2")
+          client1.wait_until_succeeds("seaf-cli status |grep synchronized >&2")
 
       with subtest("client2 sync"):
           client2.wait_for_unit("default.target")
@@ -110,9 +106,7 @@ import ./make-test-python.nix ({ pkgs, ... }:
               f"seaf-cli download -l {libid} -s http://server -u admin\@example.com -p seafile_password -d . >&2"
           )
 
-          client2.sleep(3)
-
-          client2.succeed("seaf-cli status |grep synchronized >&2")
+          client2.wait_until_succeeds("seaf-cli status |grep synchronized >&2")
 
           client2.succeed("ls -la test01 >&2")
 
diff --git a/nixos/tests/spark/default.nix b/nixos/tests/spark/default.nix
index 025c5a5222e..462f0d23a40 100644
--- a/nixos/tests/spark/default.nix
+++ b/nixos/tests/spark/default.nix
@@ -7,6 +7,7 @@ import ../make-test-python.nix ({...}: {
         enable = true;
         master = "master:7077";
       };
+      virtualisation.memorySize = 2048;
     };
     master = { config, pkgs, ... }: {
       services.spark.master = {
diff --git a/nixos/tests/sssd-ldap.nix b/nixos/tests/sssd-ldap.nix
index 27dce6ceb98..ff83e96068a 100644
--- a/nixos/tests/sssd-ldap.nix
+++ b/nixos/tests/sssd-ldap.nix
@@ -91,6 +91,11 @@ in import ./make-test-python.nix ({pkgs, ...}: {
     machine.start()
     machine.wait_for_unit("openldap.service")
     machine.wait_for_unit("sssd.service")
-    machine.succeed("getent passwd ${testUser}")
+    result = machine.execute("getent passwd ${testUser}")
+    if result[0] == 0:
+      assert "${testUser}" in result[1]
+    else:
+      machine.wait_for_console_text("Backend is online")
+      machine.succeed("getent passwd ${testUser}")
   '';
 })
diff --git a/nixos/tests/systemd-initrd-modprobe.nix b/nixos/tests/systemd-initrd-modprobe.nix
new file mode 100644
index 00000000000..bf635a10d0e
--- /dev/null
+++ b/nixos/tests/systemd-initrd-modprobe.nix
@@ -0,0 +1,17 @@
+import ./make-test-python.nix ({ lib, pkgs, ... }: {
+  name = "systemd-initrd-modprobe";
+
+  nodes.machine = { pkgs, ... }: {
+    boot.initrd.systemd.enable = true;
+    boot.initrd.kernelModules = [ "loop" ]; # Load module in initrd.
+    boot.extraModprobeConfig = ''
+      options loop max_loop=42
+    '';
+  };
+
+  testScript = ''
+    machine.wait_for_unit("multi-user.target")
+    max_loop = machine.succeed("cat /sys/module/loop/parameters/max_loop")
+    assert int(max_loop) == 42, "Parameter should be respected for initrd kernel modules"
+  '';
+})
diff --git a/nixos/tests/systemd-networkd-ipv6-prefix-delegation.nix b/nixos/tests/systemd-networkd-ipv6-prefix-delegation.nix
index 37a89fc21e4..bf5049251c7 100644
--- a/nixos/tests/systemd-networkd-ipv6-prefix-delegation.nix
+++ b/nixos/tests/systemd-networkd-ipv6-prefix-delegation.nix
@@ -7,10 +7,10 @@
 # - VLAN 1 is the connection between the ISP and the router
 # - VLAN 2 is the connection between the router and the client
 
-import ./make-test-python.nix ({pkgs, ...}: {
+import ./make-test-python.nix ({ pkgs, lib, ... }: {
   name = "systemd-networkd-ipv6-prefix-delegation";
-  meta = with pkgs.lib.maintainers; {
-    maintainers = [ andir ];
+  meta = with lib.maintainers; {
+    maintainers = [ andir hexa ];
   };
   nodes = {
 
@@ -22,26 +22,38 @@ import ./make-test-python.nix ({pkgs, ...}: {
     #
     # Note: On the ISPs device we don't really care if we are using networkd in
     # this example. That being said we can't use it (yet) as networkd doesn't
-    # implement the serving side of DHCPv6. We will use ISC's well aged dhcpd6
-    # for that task.
+    # implement the serving side of DHCPv6. We will use ISC Kea for that task.
     isp = { lib, pkgs, ... }: {
       virtualisation.vlans = [ 1 ];
       networking = {
         useDHCP = false;
         firewall.enable = false;
-        interfaces.eth1.ipv4.addresses = lib.mkForce []; # no need for legacy IP
-        interfaces.eth1.ipv6.addresses = lib.mkForce [
-          { address = "2001:DB8::1"; prefixLength = 64; }
-        ];
+        interfaces.eth1 = lib.mkForce {}; # Don't use scripted networking
+      };
+
+      systemd.network = {
+        enable = true;
+
+        networks = {
+          "eth1" = {
+            matchConfig.Name = "eth1";
+            address = [
+              "2001:DB8::1/64"
+            ];
+            networkConfig.IPForward = true;
+          };
+        };
       };
 
       # Since we want to program the routes that we delegate to the "customer"
-      # into our routing table we must give dhcpd the required privs.
-      systemd.services.dhcpd6.serviceConfig.AmbientCapabilities =
-        [ "CAP_NET_ADMIN" ];
+      # into our routing table we must provide kea with the required capability.
+      systemd.services.kea-dhcp6-server.serviceConfig = {
+        AmbientCapabilities = [ "CAP_NET_ADMIN" ];
+        CapabilityBoundingSet = [ "CAP_NET_ADMIN" ];
+      };
 
       services = {
-        # Configure the DHCPv6 server
+        # Configure the DHCPv6 server to hand out both IA_NA and IA_PD.
         #
         # We will hand out /48 prefixes from the subnet 2001:DB8:F000::/36.
         # That gives us ~8k prefixes. That should be enough for this test.
@@ -49,31 +61,70 @@ import ./make-test-python.nix ({pkgs, ...}: {
         # Since (usually) you will not receive a prefix with the router
         # advertisements we also hand out /128 leases from the range
         # 2001:DB8:0000:0000:FFFF::/112.
-        dhcpd6 = {
+        kea.dhcp6 = {
           enable = true;
-          interfaces = [ "eth1" ];
-          extraConfig = ''
-            subnet6 2001:DB8::/36 {
-              range6 2001:DB8:0000:0000:FFFF:: 2001:DB8:0000:0000:FFFF::FFFF;
-              prefix6 2001:DB8:F000:: 2001:DB8:FFFF:: /48;
-            }
-
-            # This is the secret sauce. We have to extract the prefix and the
-            # next hop when commiting the lease to the database.  dhcpd6
-            # (rightfully) has not concept of adding routes to the systems
-            # routing table. It really depends on the setup.
+          settings = {
+            interfaces-config.interfaces = [ "eth1" ];
+            subnet6 = [ {
+              interface = "eth1";
+              subnet = "2001:DB8:F::/36";
+              pd-pools = [ {
+                prefix = "2001:DB8:F::";
+                prefix-len = 36;
+                delegated-len = 48;
+              } ];
+              pools = [ {
+                pool = "2001:DB8:0000:0000:FFFF::-2001:DB8:0000:0000:FFFF::FFFF";
+              } ];
+            } ];
+
+            # This is the glue between Kea and the Kernel FIB. DHCPv6
+            # rightfully has no concept of setting up a route in your
+            # FIB. This step really depends on your setup.
             #
-            # In a production environment your DHCPv6 server is likely not the
-            # router. You might want to consider BGP, custom NetConf calls, …
-            # in those cases.
-            on commit {
-              set IP = pick-first-value(binary-to-ascii(16, 16, ":", substring(option dhcp6.ia-na, 16, 16)), "n/a");
-              set Prefix = pick-first-value(binary-to-ascii(16, 16, ":", suffix(option dhcp6.ia-pd, 16)), "n/a");
-              set PrefixLength = pick-first-value(binary-to-ascii(10, 8, ":", substring(suffix(option dhcp6.ia-pd, 17), 0, 1)), "n/a");
-              log(concat(IP, " ", Prefix, " ", PrefixLength));
-              execute("${pkgs.iproute2}/bin/ip", "-6", "route", "replace", concat(Prefix,"/",PrefixLength), "via", IP);
-            }
-          '';
+            # In a production environment your DHCPv6 server is likely
+            # not the router. You might want to consider BGP, NETCONF
+            # calls, … in those cases.
+            #
+            # In this example we use the run script hook, that lets use
+            # execute anything and passes information via the environment.
+            # https://kea.readthedocs.io/en/kea-2.2.0/arm/hooks.html#run-script-run-script-support-for-external-hook-scripts
+            hooks-libraries = [ {
+              library = "${pkgs.kea}/lib/kea/hooks/libdhcp_run_script.so";
+              parameters = {
+                name = pkgs.writeShellScript "kea-run-hooks" ''
+                  export PATH="${lib.makeBinPath (with pkgs; [ coreutils iproute2 ])}"
+
+                  set -euxo pipefail
+
+                  leases6_committed() {
+                    for i in $(seq $LEASES6_SIZE); do
+                      idx=$((i-1))
+                      prefix_var="LEASES6_AT''${idx}_ADDRESS"
+                      plen_var="LEASES6_AT''${idx}_PREFIX_LEN"
+
+                      ip -6 route replace ''${!prefix_var}/''${!plen_var} via $QUERY6_REMOTE_ADDR dev $QUERY6_IFACE_NAME
+                    done
+                  }
+
+                  unknown_handler() {
+                    echo "Unhandled function call ''${*}"
+                    exit 123
+                  }
+
+                  case "$1" in
+                      "leases6_committed")
+                          leases6_committed
+                          ;;
+                      *)
+                          unknown_handler "''${@}"
+                          ;;
+                  esac
+                '';
+                sync = false;
+              };
+            } ];
+          };
         };
 
         # Finally we have to set up the router advertisements. While we could be
diff --git a/nixos/tests/systemd-oomd.nix b/nixos/tests/systemd-oomd.nix
index f0b5a5f8e01..55c4c135000 100644
--- a/nixos/tests/systemd-oomd.nix
+++ b/nixos/tests/systemd-oomd.nix
@@ -3,35 +3,52 @@ import ./make-test-python.nix ({ pkgs, ... }:
 {
   name = "systemd-oomd";
 
+  # This test is a simplified version of systemd's testsuite-55.
+  # https://github.com/systemd/systemd/blob/v251/test/units/testsuite-55.sh
   nodes.machine = { pkgs, ... }: {
-    systemd.oomd.extraConfig.DefaultMemoryPressureDurationSec = "1s"; # makes the test faster
-    # Kill cgroups when more than 1% pressure is encountered
-    systemd.slices."-".sliceConfig = {
-      ManagedOOMMemoryPressure = "kill";
-      ManagedOOMMemoryPressureLimit = "1%";
+    # Limit VM resource usage.
+    virtualisation.memorySize = 1024;
+    systemd.oomd.extraConfig.DefaultMemoryPressureDurationSec = "1s";
+
+    systemd.slices.workload = {
+      description = "Test slice for memory pressure kills";
+      sliceConfig = {
+        MemoryAccounting = true;
+        ManagedOOMMemoryPressure = "kill";
+        ManagedOOMMemoryPressureLimit = "10%";
+      };
     };
-    # A service to bring the system under memory pressure
-    systemd.services.testservice = {
-      serviceConfig.ExecStart = "${pkgs.coreutils}/bin/tail /dev/zero";
+
+    systemd.services.testbloat = {
+      description = "Create a lot of memory pressure";
+      serviceConfig = {
+        Slice = "workload.slice";
+        MemoryHigh = "5M";
+        ExecStart = "${pkgs.coreutils}/bin/tail /dev/zero";
+      };
     };
-    # Do not kill the backdoor
-    systemd.services.backdoor.serviceConfig.ManagedOOMMemoryPressure = "auto";
 
-    virtualisation.memorySize = 1024;
+    systemd.services.testchill = {
+      description = "No memory pressure";
+      serviceConfig = {
+        Slice = "workload.slice";
+        MemoryHigh = "3M";
+        ExecStart = "${pkgs.coreutils}/bin/sleep infinity";
+      };
+    };
   };
 
   testScript = ''
-    # Start the system
+    # Start the system.
     machine.wait_for_unit("multi-user.target")
     machine.succeed("oomctl")
 
-    # Bring the system into memory pressure
-    machine.succeed("echo 0 > /proc/sys/vm/panic_on_oom")  # NixOS tests kill the VM when the OOM killer is invoked - override this
-    machine.succeed("systemctl start testservice")
+    machine.succeed("systemctl start testchill.service")
+    with subtest("OOMd should kill the bad service"):
+        machine.fail("systemctl start --wait testbloat.service")
+        assert machine.get_unit_info("testbloat.service")["Result"] == "oom-kill"
 
-    # Wait for oomd to kill something
-    # Matches these lines:
-    # systemd-oomd[508]: Killed /system.slice/systemd-udevd.service due to memory pressure for / being 3.26% > 1.00% for > 1s with reclaim activity
-    machine.wait_until_succeeds("journalctl -b | grep -q 'due to memory pressure for'")
+    with subtest("Service without memory pressure should be untouched"):
+        machine.require_unit_state("testchill.service", "active")
   '';
 })
diff --git a/nixos/tests/tmate-ssh-server.nix b/nixos/tests/tmate-ssh-server.nix
new file mode 100644
index 00000000000..e7f94db9bfc
--- /dev/null
+++ b/nixos/tests/tmate-ssh-server.nix
@@ -0,0 +1,73 @@
+import ./make-test-python.nix ({ pkgs, lib, ... }:
+let
+  inherit (import ./ssh-keys.nix pkgs)
+    snakeOilPrivateKey snakeOilPublicKey;
+
+  setUpPrivateKey = name: ''
+    ${name}.succeed(
+        "mkdir -p /root/.ssh",
+        "chown 700 /root/.ssh",
+        "cat '${snakeOilPrivateKey}' > /root/.ssh/id_snakeoil",
+        "chown 600 /root/.ssh/id_snakeoil",
+    )
+    ${name}.wait_for_file("/root/.ssh/id_snakeoil")
+  '';
+
+  sshOpts = "-oStrictHostKeyChecking=no -oUserKnownHostsFile=/dev/null -oIdentityFile=/root/.ssh/id_snakeoil";
+
+in
+{
+  name = "tmate-ssh-server";
+  nodes =
+    {
+      server = { ... }: {
+        services.tmate-ssh-server = {
+          enable = true;
+          port = 2223;
+        };
+      };
+      client = { ... }: {
+        environment.systemPackages = [ pkgs.tmate ];
+        services.openssh.enable = true;
+        users.users.root.openssh.authorizedKeys.keys = [ snakeOilPublicKey ];
+      };
+      client2 = { ... }: {
+        environment.systemPackages = [ pkgs.openssh ];
+      };
+    };
+  testScript = ''
+    start_all()
+
+    server.wait_for_unit("tmate-ssh-server.service")
+    server.wait_for_open_port(2223)
+    server.wait_for_file("/etc/tmate-ssh-server-keys/ssh_host_ed25519_key.pub")
+    server.wait_for_file("/etc/tmate-ssh-server-keys/ssh_host_rsa_key.pub")
+    server.succeed("tmate-client-config > /tmp/tmate.conf")
+    server.wait_for_file("/tmp/tmate.conf")
+
+    ${setUpPrivateKey "server"}
+    client.wait_for_unit("sshd.service")
+    client.wait_for_open_port(22)
+    server.succeed("scp ${sshOpts} /tmp/tmate.conf client:/tmp/tmate.conf")
+
+    client.wait_for_file("/tmp/tmate.conf")
+    client.send_chars("root\n")
+    client.sleep(2)
+    client.send_chars("tmate -f /tmp/tmate.conf\n")
+    client.sleep(2)
+    client.send_chars("q")
+    client.sleep(2)
+    client.send_chars("tmate display -p '#{tmate_ssh}' > /tmp/ssh_command\n")
+    client.wait_for_file("/tmp/ssh_command")
+    ssh_cmd = client.succeed("cat /tmp/ssh_command")
+
+    client2.succeed("mkdir -p ~/.ssh; ssh-keyscan -p 2223 server > ~/.ssh/known_hosts")
+    client2.send_chars("root\n")
+    client2.sleep(2)
+    client2.send_chars(ssh_cmd.strip() + "\n")
+    client2.sleep(2)
+    client2.send_chars("touch /tmp/client_2\n")
+
+    client.wait_for_file("/tmp/client_2")
+  '';
+})
diff --git a/nixos/tests/tracee.nix b/nixos/tests/tracee.nix
new file mode 100644
index 00000000000..26d0ada931b
--- /dev/null
+++ b/nixos/tests/tracee.nix
@@ -0,0 +1,46 @@
+import ./make-test-python.nix ({ pkgs, ... }: {
+  name = "tracee-integration";
+  nodes = {
+    machine = { config, pkgs, ... }: {
+      # EventFilters/trace_only_events_from_new_containers requires docker
+      # podman with docker compat will suffice
+      virtualisation.podman.enable = true;
+      virtualisation.podman.dockerCompat = true;
+
+      environment.systemPackages = [
+        # build the go integration tests as a binary
+        (pkgs.tracee.overrideAttrs (oa: {
+          pname = oa.pname + "-integration";
+          patches = oa.patches or [] ++ [
+            # change the prefix from /usr/bin to /run to find nix processes
+            ../../pkgs/tools/security/tracee/test-EventFilters-prefix-nix-friendly.patch
+            # skip magic_write test that currently fails
+            ../../pkgs/tools/security/tracee/test-EventFilters-magic_write-skip.patch
+          ];
+          buildPhase = ''
+            runHook preBuild
+            # just build the static lib we need for the go test binary
+            make $makeFlags ''${enableParallelBuilding:+-j$NIX_BUILD_CORES -l$NIX_BUILD_CORES} bpf-core ./dist/btfhub ./dist/libbpf/libbpf.a
+            # then compile the tests to be ran later
+            CGO_CFLAGS="-I$PWD/dist/libbpf" CGO_LDFLAGS="-lelf -lz $PWD/dist/libbpf/libbpf.a" go test -tags core,ebpf,integration -p 1 -c -o $GOPATH/tracee-integration ./tests/integration/...
+            runHook postBuild
+          '';
+          doCheck = false;
+          installPhase = ''
+            mkdir -p $out/bin
+            cp $GOPATH/tracee-integration $out/bin
+          '';
+          doInstallCheck = false;
+        }))
+      ];
+    };
+  };
+
+  testScript = ''
+    with subtest("run integration tests"):
+      # EventFilters/trace_only_events_from_new_containers also requires a container called "alpine"
+      machine.succeed('tar cv -C ${pkgs.pkgsStatic.busybox} . | podman import - alpine --change ENTRYPOINT=sleep')
+
+      print(machine.succeed('TRC_BIN="${pkgs.tracee}" tracee-integration -test.v'))
+  '';
+})