···18181919- [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).
20202121+- [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).
2222+2123## Backward Incompatibilities {#sec-release-24.05-incompatibilities}
22242325<!-- To avoid merge conflicts, consider adding your item at an arbitrary place in the list instead. -->
···3941 non-child processes. This means you will not be able to attach gdb to an
4042 existing process, but will need to start that process from gdb (so it is a
4143 child). Or you can set `boot.kernel.sysctl."kernel.yama.ptrace_scope"` to 0.
4444+4545+- Gitea 1.21 upgrade has several breaking changes, including:
4646+ - Custom themes and other assets that were previously stored in `custom/public/*` now belong in `custom/public/assets/*`
4747+ - 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.
42484349- 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).
···11+{ config
22+, pkgs
33+, lib
44+, ...
55+}:
66+77+let
88+ cfg = config.services.ayatana-indicators;
99+in
1010+{
1111+ options.services.ayatana-indicators = {
1212+ enable = lib.mkEnableOption (lib.mdDoc ''
1313+ Ayatana Indicators, a continuation of Canonical's Application Indicators
1414+ '');
1515+1616+ packages = lib.mkOption {
1717+ type = lib.types.listOf lib.types.package;
1818+ default = [ ];
1919+ example = lib.literalExpression "with pkgs; [ ayatana-indicator-messages ]";
2020+ description = lib.mdDoc ''
2121+ List of packages containing Ayatana Indicator services
2222+ that should be brought up by the SystemD "ayatana-indicators" user target.
2323+2424+ Packages specified here must have passthru.ayatana-indicators set correctly.
2525+2626+ If, how, and where these indicators are displayed will depend on your DE.
2727+ '';
2828+ };
2929+ };
3030+3131+ config = lib.mkIf cfg.enable {
3232+ environment = {
3333+ systemPackages = cfg.packages;
3434+3535+ pathsToLink = [
3636+ "/share/ayatana"
3737+ ];
3838+ };
3939+4040+ # libayatana-common's ayatana-indicators.target with explicit Wants & Before to bring up requested indicator services
4141+ systemd.user.targets."ayatana-indicators" =
4242+ let
4343+ indicatorServices = lib.lists.flatten
4444+ (map
4545+ (pkg:
4646+ (map (ind: "${ind}.service") pkg.passthru.ayatana-indicators))
4747+ cfg.packages);
4848+ in
4949+ {
5050+ description = "Target representing the lifecycle of the Ayatana Indicators. Each indicator should be bound to it in its individual service file";
5151+ partOf = [ "graphical-session.target" ];
5252+ wants = indicatorServices;
5353+ before = indicatorServices;
5454+ };
5555+ };
5656+5757+ meta.maintainers = with lib.maintainers; [ OPNA2608 ];
5858+}
+51
nixos/modules/system/boot/clevis.md
···11+# Clevis {#module-boot-clevis}
22+33+[Clevis](https://github.com/latchset/clevis)
44+is a framework for automated decryption of resources.
55+Clevis allows for secure unattended disk decryption during boot, using decryption policies that must be satisfied for the data to decrypt.
66+77+88+## Create a JWE file containing your secret {#module-boot-clevis-create-secret}
99+1010+The first step is to embed your secret in a [JWE](https://en.wikipedia.org/wiki/JSON_Web_Encryption) file.
1111+JWE files have to be created through the clevis command line. 3 types of policies are supported:
1212+1313+1) TPM policies
1414+1515+Secrets are pinned against the presence of a TPM2 device, for example:
1616+```
1717+echo hi | clevis encrypt tpm2 '{}' > hi.jwe
1818+```
1919+2) Tang policies
2020+2121+Secrets are pinned against the presence of a Tang server, for example:
2222+```
2323+echo hi | clevis encrypt tang '{"url": "http://tang.local"}' > hi.jwe
2424+```
2525+2626+3) Shamir Secret Sharing
2727+2828+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:
2929+```
3030+echo hi | clevis encrypt sss \
3131+'{"t": 2, "pins": {"tpm2": {"pcr_ids": "0"}, "tang": {"url": "http://tang.local"}}}' \
3232+> hi.jwe
3333+```
3434+3535+For more complete documentation on how to generate a secret with clevis, see the [clevis documentation](https://github.com/latchset/clevis).
3636+3737+3838+## Activate unattended decryption of a resource at boot {#module-boot-clevis-activate}
3939+4040+In order to activate unattended decryption of a resource at boot, enable the `clevis` module:
4141+4242+```
4343+boot.initrd.clevis.enable = true;
4444+```
4545+4646+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.
4747+```
4848+boot.initrd.clevis.devices."/dev/nvme0n1p1".secretFile = ./nvme0n1p1.jwe;
4949+```
5050+5151+Only `bcachefs`, `zfs` and `luks` encrypted devices are supported at this time.
+107
nixos/modules/system/boot/clevis.nix
···11+{ config, lib, pkgs, ... }:
22+33+with lib;
44+55+let
66+ cfg = config.boot.initrd.clevis;
77+ systemd = config.boot.initrd.systemd;
88+ supportedFs = [ "zfs" "bcachefs" ];
99+in
1010+{
1111+ meta.maintainers = with maintainers; [ julienmalka camillemndn ];
1212+ meta.doc = ./clevis.md;
1313+1414+ options = {
1515+ boot.initrd.clevis.enable = mkEnableOption (lib.mdDoc "Clevis in initrd");
1616+1717+1818+ boot.initrd.clevis.package = mkOption {
1919+ type = types.package;
2020+ default = pkgs.clevis;
2121+ defaultText = "pkgs.clevis";
2222+ description = lib.mdDoc "Clevis package";
2323+ };
2424+2525+ boot.initrd.clevis.devices = mkOption {
2626+ description = "Encrypted devices that need to be unlocked at boot using Clevis";
2727+ default = { };
2828+ type = types.attrsOf (types.submodule ({
2929+ options.secretFile = mkOption {
3030+ description = lib.mdDoc "Clevis JWE file used to decrypt the device at boot, in concert with the chosen pin (one of TPM2, Tang server, or SSS).";
3131+ type = types.path;
3232+ };
3333+ }));
3434+ };
3535+3636+ boot.initrd.clevis.useTang = mkOption {
3737+ description = "Whether the Clevis JWE file used to decrypt the devices uses a Tang server as a pin.";
3838+ default = false;
3939+ type = types.bool;
4040+ };
4141+4242+ };
4343+4444+ config = mkIf cfg.enable {
4545+4646+ # Implementation of clevis unlocking for the supported filesystems are located directly in the respective modules.
4747+4848+4949+ assertions = (attrValues (mapAttrs
5050+ (device: _: {
5151+ assertion = (any (fs: fs.device == device && (elem fs.fsType supportedFs)) config.system.build.fileSystems) || (hasAttr device config.boot.initrd.luks.devices);
5252+ message = ''
5353+ No filesystem or LUKS device with the name ${device} is declared in your configuration.'';
5454+ })
5555+ cfg.devices));
5656+5757+5858+ warnings =
5959+ if cfg.useTang && !config.boot.initrd.network.enable && !config.boot.initrd.systemd.network.enable
6060+ then [ "In order to use a Tang pinned secret you must configure networking in initrd" ]
6161+ else [ ];
6262+6363+ boot.initrd = {
6464+ extraUtilsCommands = mkIf (!systemd.enable) ''
6565+ copy_bin_and_libs ${pkgs.jose}/bin/jose
6666+ copy_bin_and_libs ${pkgs.curl}/bin/curl
6767+ copy_bin_and_libs ${pkgs.bash}/bin/bash
6868+6969+ copy_bin_and_libs ${pkgs.tpm2-tools}/bin/.tpm2-wrapped
7070+ mv $out/bin/{.tpm2-wrapped,tpm2}
7171+ cp {${pkgs.tpm2-tss},$out}/lib/libtss2-tcti-device.so.0
7272+7373+ copy_bin_and_libs ${cfg.package}/bin/.clevis-wrapped
7474+ mv $out/bin/{.clevis-wrapped,clevis}
7575+7676+ for BIN in ${cfg.package}/bin/clevis-decrypt*; do
7777+ copy_bin_and_libs $BIN
7878+ done
7979+8080+ for BIN in $out/bin/clevis{,-decrypt{,-null,-tang,-tpm2}}; do
8181+ sed -i $BIN -e 's,${pkgs.bash},,' -e 's,${pkgs.coreutils},,'
8282+ done
8383+8484+ sed -i $out/bin/clevis-decrypt-tpm2 -e 's,tpm2_,tpm2 ,'
8585+ '';
8686+8787+ secrets = lib.mapAttrs' (name: value: nameValuePair "/etc/clevis/${name}.jwe" value.secretFile) cfg.devices;
8888+8989+ systemd = {
9090+ extraBin = mkIf systemd.enable {
9191+ clevis = "${cfg.package}/bin/clevis";
9292+ curl = "${pkgs.curl}/bin/curl";
9393+ };
9494+9595+ storePaths = mkIf systemd.enable [
9696+ cfg.package
9797+ "${pkgs.jose}/bin/jose"
9898+ "${pkgs.curl}/bin/curl"
9999+ "${pkgs.tpm2-tools}/bin/tpm2_createprimary"
100100+ "${pkgs.tpm2-tools}/bin/tpm2_flushcontext"
101101+ "${pkgs.tpm2-tools}/bin/tpm2_load"
102102+ "${pkgs.tpm2-tools}/bin/tpm2_unseal"
103103+ ];
104104+ };
105105+ };
106106+ };
107107+}
···11+import ./make-test-python.nix ({ pkgs, lib, ... }: let
22+ user = "alice";
33+in {
44+ name = "ayatana-indicators";
55+66+ meta = {
77+ maintainers = with lib.maintainers; [ OPNA2608 ];
88+ };
99+1010+ nodes.machine = { config, ... }: {
1111+ imports = [
1212+ ./common/auto.nix
1313+ ./common/user-account.nix
1414+ ];
1515+1616+ test-support.displayManager.auto = {
1717+ enable = true;
1818+ inherit user;
1919+ };
2020+2121+ services.xserver = {
2222+ enable = true;
2323+ desktopManager.mate.enable = true;
2424+ displayManager.defaultSession = lib.mkForce "mate";
2525+ };
2626+2727+ services.ayatana-indicators = {
2828+ enable = true;
2929+ packages = with pkgs; [
3030+ ayatana-indicator-messages
3131+ ];
3232+ };
3333+3434+ # Services needed by some indicators
3535+ services.accounts-daemon.enable = true; # messages
3636+ };
3737+3838+ # 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?
3939+ testScript = { nodes, ... }: let
4040+ runCommandPerIndicatorService = command: lib.strings.concatMapStringsSep "\n" command nodes.machine.systemd.user.targets."ayatana-indicators".wants;
4141+ in ''
4242+ start_all()
4343+ machine.wait_for_x()
4444+4545+ # Desktop environment should reach graphical-session.target
4646+ machine.wait_for_unit("graphical-session.target", "${user}")
4747+4848+ # MATE relies on XDG autostart to bring up the indicators.
4949+ # Not sure *when* XDG autostart fires them up, and awaiting pgrep success seems to misbehave?
5050+ machine.sleep(10)
5151+5252+ # Now check if all indicators were brought up successfully, and kill them for later
5353+ '' + (runCommandPerIndicatorService (service: let serviceExec = builtins.replaceStrings [ "." ] [ "-" ] service; in ''
5454+ machine.succeed("pgrep -f ${serviceExec}")
5555+ machine.succeed("pkill -f ${serviceExec}")
5656+ '')) + ''
5757+5858+ # 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.
5959+ # Mate currently doesn't do this, so start it manually for checking (https://github.com/mate-desktop/mate-indicator-applet/issues/63)
6060+ machine.systemctl("start ayatana-indicators.target", "${user}")
6161+ machine.wait_for_unit("ayatana-indicators.target", "${user}")
6262+6363+ # Let all indicator services do their startups, potential post-launch crash & restart cycles so we can properly check for failures
6464+ # Not sure if there's a better way of awaiting this without false-positive potential
6565+ machine.sleep(10)
6666+6767+ # Now check if all indicator services were brought up successfully
6868+ '' + runCommandPerIndicatorService (service: ''
6969+ machine.wait_for_unit("${service}", "${user}")
7070+ '');
7171+})