···1819- [Anki Sync Server](https://docs.ankiweb.net/sync-server.html), the official sync server built into recent versions of Anki. Available as [services.anki-sync-server](#opt-services.anki-sync-server.enable).
200021## Backward Incompatibilities {#sec-release-24.05-incompatibilities}
2223<!-- To avoid merge conflicts, consider adding your item at an arbitrary place in the list instead. -->
···39 non-child processes. This means you will not be able to attach gdb to an
40 existing process, but will need to start that process from gdb (so it is a
41 child). Or you can set `boot.kernel.sysctl."kernel.yama.ptrace_scope"` to 0.
00004243- The `hardware.pulseaudio` module now sets permission of pulse user home directory to 755 when running in "systemWide" mode. It fixes [issue 114399](https://github.com/NixOS/nixpkgs/issues/114399).
···1819- [Anki Sync Server](https://docs.ankiweb.net/sync-server.html), the official sync server built into recent versions of Anki. Available as [services.anki-sync-server](#opt-services.anki-sync-server.enable).
2021+- [Clevis](https://github.com/latchset/clevis), a pluggable framework for automated decryption, used to unlock encrypted devices in initrd. Available as [boot.initrd.clevis.enable](#opt-boot.initrd.clevis.enable).
22+23## Backward Incompatibilities {#sec-release-24.05-incompatibilities}
2425<!-- To avoid merge conflicts, consider adding your item at an arbitrary place in the list instead. -->
···41 non-child processes. This means you will not be able to attach gdb to an
42 existing process, but will need to start that process from gdb (so it is a
43 child). Or you can set `boot.kernel.sysctl."kernel.yama.ptrace_scope"` to 0.
44+45+- Gitea 1.21 upgrade has several breaking changes, including:
46+ - Custom themes and other assets that were previously stored in `custom/public/*` now belong in `custom/public/assets/*`
47+ - New instances of Gitea using MySQL now ignore the `[database].CHARSET` config option and always use the `utf8mb4` charset, existing instances should migrate via the `gitea doctor convert` CLI command.
4849- The `hardware.pulseaudio` module now sets permission of pulse user home directory to 755 when running in "systemWide" mode. It fixes [issue 114399](https://github.com/NixOS/nixpkgs/issues/114399).
···1+# Clevis {#module-boot-clevis}
2+3+[Clevis](https://github.com/latchset/clevis)
4+is a framework for automated decryption of resources.
5+Clevis allows for secure unattended disk decryption during boot, using decryption policies that must be satisfied for the data to decrypt.
6+7+8+## Create a JWE file containing your secret {#module-boot-clevis-create-secret}
9+10+The first step is to embed your secret in a [JWE](https://en.wikipedia.org/wiki/JSON_Web_Encryption) file.
11+JWE files have to be created through the clevis command line. 3 types of policies are supported:
12+13+1) TPM policies
14+15+Secrets are pinned against the presence of a TPM2 device, for example:
16+```
17+echo hi | clevis encrypt tpm2 '{}' > hi.jwe
18+```
19+2) Tang policies
20+21+Secrets are pinned against the presence of a Tang server, for example:
22+```
23+echo hi | clevis encrypt tang '{"url": "http://tang.local"}' > hi.jwe
24+```
25+26+3) Shamir Secret Sharing
27+28+Using Shamir's Secret Sharing ([sss](https://en.wikipedia.org/wiki/Shamir%27s_secret_sharing)), secrets are pinned using a combination of the two preceding policies. For example:
29+```
30+echo hi | clevis encrypt sss \
31+'{"t": 2, "pins": {"tpm2": {"pcr_ids": "0"}, "tang": {"url": "http://tang.local"}}}' \
32+> hi.jwe
33+```
34+35+For more complete documentation on how to generate a secret with clevis, see the [clevis documentation](https://github.com/latchset/clevis).
36+37+38+## Activate unattended decryption of a resource at boot {#module-boot-clevis-activate}
39+40+In order to activate unattended decryption of a resource at boot, enable the `clevis` module:
41+42+```
43+boot.initrd.clevis.enable = true;
44+```
45+46+Then, specify the device you want to decrypt using a given clevis secret. Clevis will automatically try to decrypt the device at boot and will fallback to interactive unlocking if the decryption policy is not fulfilled.
47+```
48+boot.initrd.clevis.devices."/dev/nvme0n1p1".secretFile = ./nvme0n1p1.jwe;
49+```
50+51+Only `bcachefs`, `zfs` and `luks` encrypted devices are supported at this time.
···57 # bcachefs does not support mounting devices with colons in the path, ergo we don't (see #49671)
58 firstDevice = fs: lib.head (lib.splitString ":" fs.device);
5960- openCommand = name: fs: ''
0000000061 tryUnlock ${name} ${firstDevice fs}
62 '';
63
···57 # bcachefs does not support mounting devices with colons in the path, ergo we don't (see #49671)
58 firstDevice = fs: lib.head (lib.splitString ":" fs.device);
5960+ openCommand = name: fs: if config.boot.initrd.clevis.enable && (lib.hasAttr (firstDevice fs) config.boot.initrd.clevis.devices) then ''
61+ if clevis decrypt < /etc/clevis/${firstDevice fs}.jwe | bcachefs unlock ${firstDevice fs}
62+ then
63+ printf "unlocked ${name} using clevis\n"
64+ else
65+ printf "falling back to interactive unlocking...\n"
66+ tryUnlock ${name} ${firstDevice fs}
67+ fi
68+ '' else ''
69 tryUnlock ${name} ${firstDevice fs}
70 '';
71
+11-2
nixos/modules/tasks/filesystems/zfs.nix
···17 cfgZED = config.services.zfs.zed;
1819 selectModulePackage = package: config.boot.kernelPackages.${package.kernelModuleAttribute};
00020 inInitrd = any (fs: fs == "zfs") config.boot.initrd.supportedFilesystems;
21 inSystem = any (fs: fs == "zfs") config.boot.supportedFilesystems;
22···120 # but don't *require* it, because mounts shouldn't be killed if it's stopped.
121 # In the future, hopefully someone will complete this:
122 # https://github.com/zfsonlinux/zfs/pull/4943
123- wants = [ "systemd-udev-settle.service" ];
124 after = [
125 "systemd-udev-settle.service"
126 "systemd-modules-load.service"
127 "systemd-ask-password-console.service"
128- ];
129 requiredBy = getPoolMounts prefix pool ++ [ "zfs-import.target" ];
130 before = getPoolMounts prefix pool ++ [ "zfs-import.target" ];
131 unitConfig = {
···154 poolImported "${pool}" || poolImport "${pool}" # Try one last time, e.g. to import a degraded pool.
155 fi
156 if poolImported "${pool}"; then
000157 ${optionalString keyLocations.hasKeys ''
158 ${keyLocations.command} | while IFS=$'\t' read ds kl ks; do
159 {
···623 fi
624 poolImported "${pool}" || poolImport "${pool}" # Try one last time, e.g. to import a degraded pool.
625 fi
000626 ${if isBool cfgZfs.requestEncryptionCredentials
627 then optionalString cfgZfs.requestEncryptionCredentials ''
628 zfs load-key -a
···17 cfgZED = config.services.zfs.zed;
1819 selectModulePackage = package: config.boot.kernelPackages.${package.kernelModuleAttribute};
20+ clevisDatasets = map (e: e.device) (filter (e: (hasAttr e.device config.boot.initrd.clevis.devices) && e.fsType == "zfs" && (fsNeededForBoot e)) config.system.build.fileSystems);
21+22+23 inInitrd = any (fs: fs == "zfs") config.boot.initrd.supportedFilesystems;
24 inSystem = any (fs: fs == "zfs") config.boot.supportedFilesystems;
25···123 # but don't *require* it, because mounts shouldn't be killed if it's stopped.
124 # In the future, hopefully someone will complete this:
125 # https://github.com/zfsonlinux/zfs/pull/4943
126+ wants = [ "systemd-udev-settle.service" ] ++ optional (config.boot.initrd.clevis.useTang) "network-online.target";
127 after = [
128 "systemd-udev-settle.service"
129 "systemd-modules-load.service"
130 "systemd-ask-password-console.service"
131+ ] ++ optional (config.boot.initrd.clevis.useTang) "network-online.target";
132 requiredBy = getPoolMounts prefix pool ++ [ "zfs-import.target" ];
133 before = getPoolMounts prefix pool ++ [ "zfs-import.target" ];
134 unitConfig = {
···157 poolImported "${pool}" || poolImport "${pool}" # Try one last time, e.g. to import a degraded pool.
158 fi
159 if poolImported "${pool}"; then
160+ ${concatMapStringsSep "\n" (elem: "clevis decrypt < /etc/clevis/${elem}.jwe | zfs load-key ${elem} || true ") (filter (p: (elemAt (splitString "/" p) 0) == pool) clevisDatasets)}
161+162+163 ${optionalString keyLocations.hasKeys ''
164 ${keyLocations.command} | while IFS=$'\t' read ds kl ks; do
165 {
···629 fi
630 poolImported "${pool}" || poolImport "${pool}" # Try one last time, e.g. to import a degraded pool.
631 fi
632+633+ ${concatMapStringsSep "\n" (elem: "clevis decrypt < /etc/clevis/${elem}.jwe | zfs load-key ${elem}") (filter (p: (elemAt (splitString "/" p) 0) == pool) clevisDatasets)}
634+635 ${if isBool cfgZfs.requestEncryptionCredentials
636 then optionalString cfgZfs.requestEncryptionCredentials ''
637 zfs load-key -a
···1+import ./make-test-python.nix ({ pkgs, lib, ... }: let
2+ user = "alice";
3+in {
4+ name = "ayatana-indicators";
5+6+ meta = {
7+ maintainers = with lib.maintainers; [ OPNA2608 ];
8+ };
9+10+ nodes.machine = { config, ... }: {
11+ imports = [
12+ ./common/auto.nix
13+ ./common/user-account.nix
14+ ];
15+16+ test-support.displayManager.auto = {
17+ enable = true;
18+ inherit user;
19+ };
20+21+ services.xserver = {
22+ enable = true;
23+ desktopManager.mate.enable = true;
24+ displayManager.defaultSession = lib.mkForce "mate";
25+ };
26+27+ services.ayatana-indicators = {
28+ enable = true;
29+ packages = with pkgs; [
30+ ayatana-indicator-messages
31+ ];
32+ };
33+34+ # Services needed by some indicators
35+ services.accounts-daemon.enable = true; # messages
36+ };
37+38+ # TODO session indicator starts up in a semi-broken state, but works fine after a restart. maybe being started before graphical session is truly up & ready?
39+ testScript = { nodes, ... }: let
40+ runCommandPerIndicatorService = command: lib.strings.concatMapStringsSep "\n" command nodes.machine.systemd.user.targets."ayatana-indicators".wants;
41+ in ''
42+ start_all()
43+ machine.wait_for_x()
44+45+ # Desktop environment should reach graphical-session.target
46+ machine.wait_for_unit("graphical-session.target", "${user}")
47+48+ # MATE relies on XDG autostart to bring up the indicators.
49+ # Not sure *when* XDG autostart fires them up, and awaiting pgrep success seems to misbehave?
50+ machine.sleep(10)
51+52+ # Now check if all indicators were brought up successfully, and kill them for later
53+ '' + (runCommandPerIndicatorService (service: let serviceExec = builtins.replaceStrings [ "." ] [ "-" ] service; in ''
54+ machine.succeed("pgrep -f ${serviceExec}")
55+ machine.succeed("pkill -f ${serviceExec}")
56+ '')) + ''
57+58+ # Ayatana target is the preferred way of starting up indicators on SystemD session, the graphical session is responsible for starting this if it supports them.
59+ # Mate currently doesn't do this, so start it manually for checking (https://github.com/mate-desktop/mate-indicator-applet/issues/63)
60+ machine.systemctl("start ayatana-indicators.target", "${user}")
61+ machine.wait_for_unit("ayatana-indicators.target", "${user}")
62+63+ # Let all indicator services do their startups, potential post-launch crash & restart cycles so we can properly check for failures
64+ # Not sure if there's a better way of awaiting this without false-positive potential
65+ machine.sleep(10)
66+67+ # Now check if all indicator services were brought up successfully
68+ '' + runCommandPerIndicatorService (service: ''
69+ machine.wait_for_unit("${service}", "${user}")
70+ '');
71+})
···2021buildGoModule rec {
22 pname = "gitea";
23- version = "1.20.5";
2425 # not fetching directly from the git repo, because that lacks several vendor files for the web UI
26 src = fetchurl {
27 url = "https://dl.gitea.com/gitea/${version}/gitea-src-${version}.tar.gz";
28- hash = "sha256-cH/AHsFXOdvfSfj9AZUd3l/RlYE06o1ByZu0vvGQuXw=";
29 };
3031 vendorHash = null;
···2021buildGoModule rec {
22 pname = "gitea";
23+ version = "1.21.1";
2425 # not fetching directly from the git repo, because that lacks several vendor files for the web UI
26 src = fetchurl {
27 url = "https://dl.gitea.com/gitea/${version}/gitea-src-${version}.tar.gz";
28+ hash = "sha256-5WEHUMQsQNgrglS+xJ4IWHUl0a6RLLPyx0l+ECJ4R9g=";
29 };
3031 vendorHash = null;
+2
pkgs/build-support/fetchtorrent/default.nix
···14, recursiveHash ? true
15, postFetch ? ""
16, postUnpack ? ""
017}:
18let
19 afterSuccess = writeShellScript "fetch-bittorrent-done.sh" ''
···30 jsonConfig = (formats.json {}).generate "jsonConfig" config;
31in
32runCommand name {
033 nativeBuildInputs = [ cacert ] ++ (if (backend == "transmission" ) then [ transmission_noSystemd ] else if (backend == "rqbit") then [ rqbit ] else throw "rqbit or transmission are the only available backends for fetchtorrent");
34 outputHashAlgo = if hash != "" then null else "sha256";
35 outputHash = hash;
···14, recursiveHash ? true
15, postFetch ? ""
16, postUnpack ? ""
17+, meta ? {}
18}:
19let
20 afterSuccess = writeShellScript "fetch-bittorrent-done.sh" ''
···31 jsonConfig = (formats.json {}).generate "jsonConfig" config;
32in
33runCommand name {
34+ inherit meta;
35 nativeBuildInputs = [ cacert ] ++ (if (backend == "transmission" ) then [ transmission_noSystemd ] else if (backend == "rqbit") then [ rqbit ] else throw "rqbit or transmission are the only available backends for fetchtorrent");
36 outputHashAlgo = if hash != "" then null else "sha256";
37 outputHash = hash;