diff options
Diffstat (limited to 'nixos')
48 files changed, 967 insertions, 231 deletions
diff --git a/nixos/doc/manual/installation/installing-usb.section.md b/nixos/doc/manual/installation/installing-usb.section.md index adfe22ea2f00e..3b9e2f492f04d 100644 --- a/nixos/doc/manual/installation/installing-usb.section.md +++ b/nixos/doc/manual/installation/installing-usb.section.md @@ -35,7 +35,7 @@ select the image, select the USB flash drive and click "Write". 4. Then use the `dd` utility to write the image to the USB flash drive. ```ShellSession - sudo dd if=<path-to-image> of=/dev/sdX bs=4M conv=fsync + sudo dd bs=4M conv=fsync oflag=direct status=progress if=<path-to-image> of=/dev/sdX ``` ## Creating bootable USB flash drive from a Terminal on macOS {#sec-booting-from-usb-macos} diff --git a/nixos/doc/manual/release-notes/rl-2405.section.md b/nixos/doc/manual/release-notes/rl-2405.section.md index 89419068742fb..c075149a0e5d5 100644 --- a/nixos/doc/manual/release-notes/rl-2405.section.md +++ b/nixos/doc/manual/release-notes/rl-2405.section.md @@ -65,8 +65,11 @@ The pre-existing [services.ankisyncd](#opt-services.ankisyncd.enable) has been m - `paperless`' `services.paperless.extraConfig` setting has been removed and converted to the freeform type and option named `services.paperless.settings`. -- `mkosi` was updated to v19. Parts of the user interface have changed. Consult the - [release notes](https://github.com/systemd/mkosi/releases/tag/v19) for a list of changes. +- The legacy and long deprecated systemd target `network-interfaces.target` has been removed. Use `network.target` instead. + +- `mkosi` was updated to v20. Parts of the user interface have changed. Consult the + release notes of [v19](https://github.com/systemd/mkosi/releases/tag/v19) and + [v20](https://github.com/systemd/mkosi/releases/tag/v20) for a list of changes. - `services.nginx` will no longer advertise HTTP/3 availability automatically. This must now be manually added, preferably to each location block. Example: @@ -82,6 +85,12 @@ The pre-existing [services.ankisyncd](#opt-services.ankisyncd.enable) has been m ``` - The `kanata` package has been updated to v1.5.0, which includes [breaking changes](https://github.com/jtroo/kanata/releases/tag/v1.5.0). +- The `craftos-pc` package has been updated to v2.8, which includes [breaking changes](https://github.com/MCJack123/craftos2/releases/tag/v2.8). + - Files are now handled in binary mode; this could break programs with embedded UTF-8 characters. + - The ROM was updated to match ComputerCraft version v1.109.2. + - The bundled Lua was updated to Lua v5.2, which includes breaking changes. See the [Lua manual](https://www.lua.org/manual/5.2/manual.html#8) for more information. + - The WebSocket API [was rewritten](https://github.com/MCJack123/craftos2/issues/337), which introduced breaking changes. + - The latest available version of Nextcloud is v28 (available as `pkgs.nextcloud28`). The installation logic is as follows: - If [`services.nextcloud.package`](#opt-services.nextcloud.package) is specified explicitly, this package will be installed (**recommended**) - If [`system.stateVersion`](#opt-system.stateVersion) is >=24.05, `pkgs.nextcloud28` will be installed by default. @@ -185,5 +194,7 @@ The pre-existing [services.ankisyncd](#opt-services.ankisyncd.enable) has been m replaces the need for the `extraPackages` option, this option will be deprecated in future releases. +- The `mpich` package expression now requires `withPm` to be a list, e.g. `"hydra:gforker"` becomes `[ "hydra" "gforker" ]`. + - QtMultimedia has changed its default backend to `QT_MEDIA_BACKEND=ffmpeg` (previously `gstreamer` on Linux or `darwin` on MacOS). The previous native backends remain available but are now minimally maintained. Refer to [upstream documentation](https://doc.qt.io/qt-6/qtmultimedia-index.html#ffmpeg-as-the-default-backend) for further details about each platform. diff --git a/nixos/lib/make-single-disk-zfs-image.nix b/nixos/lib/make-single-disk-zfs-image.nix index a3564f9a8b68e..585fa93b7fa0f 100644 --- a/nixos/lib/make-single-disk-zfs-image.nix +++ b/nixos/lib/make-single-disk-zfs-image.nix @@ -21,6 +21,9 @@ , # size of the FAT partition, in megabytes. bootSize ? 1024 + , # memory allocated for virtualized build instance + memSize ? 1024 + , # The size of the root partition, in megabytes. rootSize ? 2048 @@ -230,7 +233,7 @@ let ).runInLinuxVM ( pkgs.runCommand name { - memSize = 1024; + inherit memSize; QEMU_OPTS = "-drive file=$rootDiskImage,if=virtio,cache=unsafe,werror=report"; preVM = '' PATH=$PATH:${pkgs.qemu_kvm}/bin diff --git a/nixos/lib/make-squashfs.nix b/nixos/lib/make-squashfs.nix index 4b6b567399484..f28e2c6715805 100644 --- a/nixos/lib/make-squashfs.nix +++ b/nixos/lib/make-squashfs.nix @@ -14,6 +14,7 @@ let pseudoFilesArgs = lib.concatMapStrings (f: ''-p "${f}" '') pseudoFiles; + compFlag = if comp == null then "-no-compression" else "-comp ${comp}"; in stdenv.mkDerivation { name = "${fileName}.img"; @@ -39,7 +40,7 @@ stdenv.mkDerivation { # Generate the squashfs image. mksquashfs nix-path-registration $(cat $closureInfo/store-paths) $out ${pseudoFilesArgs} \ - -no-hardlinks ${lib.optionalString noStrip "-no-strip"} -keep-as-directory -all-root -b 1048576 -comp ${comp} \ + -no-hardlinks ${lib.optionalString noStrip "-no-strip"} -keep-as-directory -all-root -b 1048576 ${compFlag} \ -processors $NIX_BUILD_CORES ''; } diff --git a/nixos/maintainers/scripts/openstack/openstack-image-zfs.nix b/nixos/maintainers/scripts/openstack/openstack-image-zfs.nix index 936dcee12949e..60f0535854dd5 100644 --- a/nixos/maintainers/scripts/openstack/openstack-image-zfs.nix +++ b/nixos/maintainers/scripts/openstack/openstack-image-zfs.nix @@ -20,6 +20,12 @@ in default = "nixos-openstack-image-${config.system.nixos.label}-${pkgs.stdenv.hostPlatform.system}"; }; + ramMB = mkOption { + type = types.int; + default = 1024; + description = lib.mdDoc "RAM allocation for build VM"; + }; + sizeMB = mkOption { type = types.int; default = 8192; @@ -64,7 +70,7 @@ in includeChannel = copyChannel; bootSize = 1000; - + memSize = cfg.ramMB; rootSize = cfg.sizeMB; rootPoolProperties = { ashift = 12; diff --git a/nixos/modules/installer/cd-dvd/installation-cd-minimal.nix b/nixos/modules/installer/cd-dvd/installation-cd-minimal.nix index 29afdd4710917..1932f90d4c360 100644 --- a/nixos/modules/installer/cd-dvd/installation-cd-minimal.nix +++ b/nixos/modules/installer/cd-dvd/installation-cd-minimal.nix @@ -18,7 +18,7 @@ # not including it may cause annoying cache misses in the case of the NixOS manual. documentation.doc.enable = lib.mkOverride 500 true; - fonts.fontconfig.enable = lib.mkForce false; + fonts.fontconfig.enable = lib.mkOverride 500 false; - isoImage.edition = lib.mkForce "minimal"; + isoImage.edition = lib.mkOverride 500 "minimal"; } diff --git a/nixos/modules/installer/cd-dvd/iso-image.nix b/nixos/modules/installer/cd-dvd/iso-image.nix index 0b5135c088eaf..6adb94e09aff3 100644 --- a/nixos/modules/installer/cd-dvd/iso-image.nix +++ b/nixos/modules/installer/cd-dvd/iso-image.nix @@ -512,9 +512,10 @@ in + lib.optionalString isAarch "-Xbcj arm" + lib.optionalString (isPower && is32bit && isBigEndian) "-Xbcj powerpc" + lib.optionalString (isSparc) "-Xbcj sparc"; - type = lib.types.str; + type = lib.types.nullOr lib.types.str; description = lib.mdDoc '' Compression settings to use for the squashfs nix store. + `null` disables compression. ''; example = "zstd -Xcompression-level 6"; }; diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index 4e3ce4d088968..e6fffd4716de9 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -1044,6 +1044,7 @@ ./services/networking/ntopng.nix ./services/networking/ntp/chrony.nix ./services/networking/ntp/ntpd.nix + ./services/networking/ntp/ntpd-rs.nix ./services/networking/ntp/openntpd.nix ./services/networking/nullidentdmod.nix ./services/networking/nylon.nix diff --git a/nixos/modules/programs/starship.nix b/nixos/modules/programs/starship.nix index bec3900496fd9..34f6f0882c617 100644 --- a/nixos/modules/programs/starship.nix +++ b/nixos/modules/programs/starship.nix @@ -1,13 +1,21 @@ { config, lib, pkgs, ... }: -with lib; - let cfg = config.programs.starship; settingsFormat = pkgs.formats.toml { }; - settingsFile = settingsFormat.generate "starship.toml" cfg.settings; + userSettingsFile = settingsFormat.generate "starship.toml" cfg.settings; + + settingsFile = if cfg.presets == [] then userSettingsFile else pkgs.runCommand "starship.toml" + { + nativeBuildInputs = [ pkgs.yq ]; + } '' + tomlq -s -t 'reduce .[] as $item ({}; . * $item)' \ + ${lib.concatStringsSep " " (map (f: "${pkgs.starship}/share/starship/presets/${f}.toml") cfg.presets)} \ + ${userSettingsFile} \ + > $out + ''; initOption = if cfg.interactiveOnly then @@ -18,19 +26,28 @@ let in { options.programs.starship = { - enable = mkEnableOption (lib.mdDoc "the Starship shell prompt"); + enable = lib.mkEnableOption (lib.mdDoc "the Starship shell prompt"); - interactiveOnly = mkOption { + interactiveOnly = lib.mkOption { default = true; example = false; - type = types.bool; + type = lib.types.bool; description = lib.mdDoc '' Whether to enable starship only when the shell is interactive. Some plugins require this to be set to false to function correctly. ''; }; - settings = mkOption { + presets = lib.mkOption { + default = [ ]; + example = [ "nerd-font-symbols" ]; + type = with lib.types; listOf str; + description = lib.mdDoc '' + Presets files to be merged with settings in order. + ''; + }; + + settings = lib.mkOption { inherit (settingsFormat) type; default = { }; description = lib.mdDoc '' @@ -41,7 +58,7 @@ in }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { programs.bash.${initOption} = '' if [[ $TERM != "dumb" ]]; then # don't set STARSHIP_CONFIG automatically if there's a user-specified diff --git a/nixos/modules/services/admin/pgadmin.nix b/nixos/modules/services/admin/pgadmin.nix index 3d820db59f4cb..ceb5655dc562f 100644 --- a/nixos/modules/services/admin/pgadmin.nix +++ b/nixos/modules/services/admin/pgadmin.nix @@ -44,12 +44,19 @@ in initialPasswordFile = mkOption { description = lib.mdDoc '' - Initial password file for the pgAdmin account. + Initial password file for the pgAdmin account. Minimum length by default is 6. + Please see `services.pgadmin.minimumPasswordLength`. NOTE: Should be string not a store path, to prevent the password from being world readable ''; type = types.path; }; + minimumPasswordLength = mkOption { + description = lib.mdDoc "Minimum length of the password"; + type = types.int; + default = 6; + }; + emailServer = { enable = mkOption { description = lib.mdDoc '' @@ -116,6 +123,7 @@ in services.pgadmin.settings = { DEFAULT_SERVER_PORT = cfg.port; + PASSWORD_LENGTH_MIN = cfg.minimumPasswordLength; SERVER_MODE = true; UPGRADE_CHECK_ENABLED = false; } // (optionalAttrs cfg.openFirewall { @@ -141,6 +149,14 @@ in preStart = '' # NOTE: this is idempotent (aka running it twice has no effect) + # Check here for password length to prevent pgadmin from starting + # and presenting a hard to find error message + # see https://github.com/NixOS/nixpkgs/issues/270624 + PW_LENGTH=$(wc -m < ${escapeShellArg cfg.initialPasswordFile}) + if [ $PW_LENGTH -lt ${toString cfg.minimumPasswordLength} ]; then + echo "Password must be at least ${toString cfg.minimumPasswordLength} characters long" + exit 1 + fi ( # Email address: echo ${escapeShellArg cfg.initialEmail} diff --git a/nixos/modules/services/databases/influxdb.nix b/nixos/modules/services/databases/influxdb.nix index 34b4139e7c580..adb212ab08d0d 100644 --- a/nixos/modules/services/databases/influxdb.nix +++ b/nixos/modules/services/databases/influxdb.nix @@ -161,6 +161,7 @@ in ExecStart = ''${cfg.package}/bin/influxd -config "${configFile}"''; User = cfg.user; Group = cfg.group; + Restart = "on-failure"; }; postStart = let diff --git a/nixos/modules/services/hardware/pcscd.nix b/nixos/modules/services/hardware/pcscd.nix index a9e4998efe37a..b0a493c23899c 100644 --- a/nixos/modules/services/hardware/pcscd.nix +++ b/nixos/modules/services/hardware/pcscd.nix @@ -16,9 +16,6 @@ let in { - - ###### interface - options.services.pcscd = { enable = mkEnableOption (lib.mdDoc "PCSC-Lite daemon"); @@ -46,10 +43,7 @@ in }; }; - ###### implementation - config = mkIf config.services.pcscd.enable { - environment.etc."reader.conf".source = cfgFile; environment.systemPackages = [ package ]; @@ -61,7 +55,6 @@ in systemd.services.pcscd = { environment.PCSCLITE_HP_DROPDIR = pluginEnv; - restartTriggers = [ "/etc/reader.conf" ]; # If the cfgFile is empty and not specified (in which case the default # /etc/reader.conf is assumed), pcscd will happily start going through the diff --git a/nixos/modules/services/mail/nullmailer.nix b/nixos/modules/services/mail/nullmailer.nix index f6befe246b12a..4fd0026dbe4eb 100644 --- a/nixos/modules/services/mail/nullmailer.nix +++ b/nixos/modules/services/mail/nullmailer.nix @@ -120,7 +120,7 @@ with lib; }; maxpause = mkOption { - type = types.nullOr types.str; + type = with types; nullOr (oneOf [ str int ]); default = null; description = lib.mdDoc '' The maximum time to pause between successive queue runs, in seconds. @@ -138,7 +138,7 @@ with lib; }; pausetime = mkOption { - type = types.nullOr types.str; + type = with types; nullOr (oneOf [ str int ]); default = null; description = lib.mdDoc '' The minimum time to pause between successive queue runs when there @@ -168,7 +168,7 @@ with lib; }; sendtimeout = mkOption { - type = types.nullOr types.str; + type = with types; nullOr (oneOf [ str int ]); default = null; description = lib.mdDoc '' The time to wait for a remote module listed above to complete sending @@ -194,7 +194,7 @@ with lib; environment = { systemPackages = [ pkgs.nullmailer ]; etc = let - validAttrs = filterAttrs (name: value: value != null) cfg.config; + validAttrs = lib.mapAttrs (_: toString) (filterAttrs (_: value: value != null) cfg.config); in (foldl' (as: name: as // { "nullmailer/${name}".text = validAttrs.${name}; }) {} (attrNames validAttrs)) // optionalAttrs (cfg.remotesFile != null) { "nullmailer/remotes".source = cfg.remotesFile; }; diff --git a/nixos/modules/services/mail/roundcube.nix b/nixos/modules/services/mail/roundcube.nix index c35ece8362f67..c883c143e5234 100644 --- a/nixos/modules/services/mail/roundcube.nix +++ b/nixos/modules/services/mail/roundcube.nix @@ -102,6 +102,12 @@ in apply = configuredMaxAttachmentSize: "${toString (configuredMaxAttachmentSize * 1.3)}M"; }; + configureNginx = lib.mkOption { + type = lib.types.bool; + default = true; + description = lib.mdDoc "Configure nginx as a reverse proxy for roundcube."; + }; + extraConfig = mkOption { type = types.lines; default = ""; @@ -142,26 +148,39 @@ in ${cfg.extraConfig} ''; - services.nginx = { + services.nginx = lib.mkIf cfg.configureNginx { enable = true; virtualHosts = { ${cfg.hostName} = { forceSSL = mkDefault true; enableACME = mkDefault true; + root = cfg.package; locations."/" = { - root = cfg.package; index = "index.php"; + priority = 1100; extraConfig = '' - location ~* \.php(/|$) { - fastcgi_split_path_info ^(.+\.php)(/.+)$; - fastcgi_pass unix:${fpm.socket}; - - fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; - fastcgi_param PATH_INFO $fastcgi_path_info; - - include ${config.services.nginx.package}/conf/fastcgi_params; - include ${pkgs.nginx}/conf/fastcgi.conf; - } + add_header Cache-Control 'public, max-age=604800, must-revalidate'; + ''; + }; + locations."~ ^/(SQL|bin|config|logs|temp|vendor)/" = { + priority = 3110; + extraConfig = '' + return 404; + ''; + }; + locations."~ ^/(CHANGELOG.md|INSTALL|LICENSE|README.md|SECURITY.md|UPGRADING|composer.json|composer.lock)" = { + priority = 3120; + extraConfig = '' + return 404; + ''; + }; + locations."~* \\.php(/|$)" = { + priority = 3130; + extraConfig = '' + fastcgi_pass unix:${fpm.socket}; + fastcgi_param PATH_INFO $fastcgi_path_info; + fastcgi_split_path_info ^(.+\.php)(/.+)$; + include ${config.services.nginx.package}/conf/fastcgi.conf; ''; }; }; diff --git a/nixos/modules/services/misc/ntfy-sh.nix b/nixos/modules/services/misc/ntfy-sh.nix index 98134e94eeede..b8b0772401156 100644 --- a/nixos/modules/services/misc/ntfy-sh.nix +++ b/nixos/modules/services/misc/ntfy-sh.nix @@ -79,12 +79,6 @@ in cache-file = mkDefault "/var/lib/ntfy-sh/cache-file.db"; }; - systemd.tmpfiles.rules = [ - "f ${cfg.settings.auth-file} 0600 ${cfg.user} ${cfg.group} - -" - "d ${cfg.settings.attachment-cache-dir} 0700 ${cfg.user} ${cfg.group} - -" - "f ${cfg.settings.cache-file} 0600 ${cfg.user} ${cfg.group} - -" - ]; - systemd.services.ntfy-sh = { description = "Push notifications server"; diff --git a/nixos/modules/services/network-filesystems/kubo.nix b/nixos/modules/services/network-filesystems/kubo.nix index 126e0902d5b4a..10162c1633e7b 100644 --- a/nixos/modules/services/network-filesystems/kubo.nix +++ b/nixos/modules/services/network-filesystems/kubo.nix @@ -52,7 +52,7 @@ let multiaddrsToListenStreams = addrIn: let - addrs = if builtins.typeOf addrIn == "list" + addrs = if builtins.isList addrIn then addrIn else [ addrIn ]; unfilteredResult = map multiaddrToListenStream addrs; in @@ -60,7 +60,7 @@ let multiaddrsToListenDatagrams = addrIn: let - addrs = if builtins.typeOf addrIn == "list" + addrs = if builtins.isList addrIn then addrIn else [ addrIn ]; unfilteredResult = map multiaddrToListenDatagram addrs; in @@ -99,7 +99,12 @@ in services.kubo = { - enable = mkEnableOption (lib.mdDoc "Interplanetary File System (WARNING: may cause severe network degradation)"); + enable = mkEnableOption (lib.mdDoc '' + the Interplanetary File System (WARNING: may cause severe network degradation). + NOTE: after enabling this option and rebuilding your system, you need to log out + and back in for the `IPFS_PATH` environment variable to be present in your shell. + Until you do that, the CLI tools won't be able to talk to the daemon by default + ''); package = mkPackageOption pkgs "kubo" { }; @@ -274,8 +279,8 @@ in { assertion = !((lib.versionAtLeast cfg.package.version "0.21") && (builtins.hasAttr "Experimental" cfg.settings) && (builtins.hasAttr "AcceleratedDHTClient" cfg.settings.Experimental)); message = '' - The `services.kubo.settings.Experimental.AcceleratedDHTClient` option was renamed to `services.kubo.settings.Routing.AcceleratedDHTClient` in Kubo 0.21. - ''; + The `services.kubo.settings.Experimental.AcceleratedDHTClient` option was renamed to `services.kubo.settings.Routing.AcceleratedDHTClient` in Kubo 0.21. + ''; } ]; diff --git a/nixos/modules/services/networking/dhcpcd.nix b/nixos/modules/services/networking/dhcpcd.nix index 8b6d3fc55f3e4..2b59352ac616b 100644 --- a/nixos/modules/services/networking/dhcpcd.nix +++ b/nixos/modules/services/networking/dhcpcd.nix @@ -98,7 +98,7 @@ let # anything ever again ("couldn't resolve ..., giving up on # it"), so we silently lose time synchronisation. This also # applies to openntpd. - /run/current-system/systemd/bin/systemctl try-reload-or-restart ntpd.service openntpd.service chronyd.service || true + /run/current-system/systemd/bin/systemctl try-reload-or-restart ntpd.service openntpd.service chronyd.service ntpd-rs.service || true fi ${cfg.runHook} diff --git a/nixos/modules/services/networking/miniupnpd.nix b/nixos/modules/services/networking/miniupnpd.nix index 64aacaf350404..116298dc6b1db 100644 --- a/nixos/modules/services/networking/miniupnpd.nix +++ b/nixos/modules/services/networking/miniupnpd.nix @@ -13,8 +13,17 @@ let listening_ip=${range} '') cfg.internalIPs} + ${lib.optionalString (firewall == "nftables") '' + upnp_table_name=miniupnpd + upnp_nat_table_name=miniupnpd + ''} + ${cfg.appendConfig} ''; + firewall = if config.networking.nftables.enable then "nftables" else "iptables"; + miniupnpd = pkgs.miniupnpd.override { inherit firewall; }; + firewallScripts = lib.optionals (firewall == "iptables") + ([ "iptables"] ++ lib.optional (config.networking.enableIPv6) "ip6tables"); in { options = { @@ -57,20 +66,50 @@ in }; config = mkIf cfg.enable { - networking.firewall.extraCommands = '' - ${pkgs.bash}/bin/bash -x ${pkgs.miniupnpd}/etc/miniupnpd/iptables_init.sh -i ${cfg.externalInterface} - ''; + networking.firewall.extraCommands = lib.mkIf (firewallScripts != []) (builtins.concatStringsSep "\n" (map (fw: '' + EXTIF=${cfg.externalInterface} ${pkgs.bash}/bin/bash -x ${miniupnpd}/etc/miniupnpd/${fw}_init.sh + '') firewallScripts)); + + networking.firewall.extraStopCommands = lib.mkIf (firewallScripts != []) (builtins.concatStringsSep "\n" (map (fw: '' + EXTIF=${cfg.externalInterface} ${pkgs.bash}/bin/bash -x ${miniupnpd}/etc/miniupnpd/${fw}_removeall.sh + '') firewallScripts)); - networking.firewall.extraStopCommands = '' - ${pkgs.bash}/bin/bash -x ${pkgs.miniupnpd}/etc/miniupnpd/iptables_removeall.sh -i ${cfg.externalInterface} - ''; + networking.nftables = lib.mkIf (firewall == "nftables") { + # see nft_init in ${miniupnpd-nftables}/etc/miniupnpd + tables.miniupnpd = { + family = "inet"; + # The following is omitted because it's expected that the firewall is to be responsible for it. + # + # chain forward { + # type filter hook forward priority filter; policy drop; + # jump miniupnpd + # } + # + # Otherwise, it quickly gets ugly with (potentially) two forward chains with "policy drop". + # This means the chain "miniupnpd" never actually gets triggered and is simply there to satisfy + # miniupnpd. If you're doing it yourself (without networking.firewall), the easiest way to get + # it to work is adding a rule "ct status dnat accept" - this is what networking.firewall does. + # If you don't want to simply accept forwarding for all "ct status dnat" packets, override + # upnp_table_name with whatever your table is, create a chain "miniupnpd" in your table and + # jump into it from your forward chain. + content = '' + chain miniupnpd {} + chain prerouting_miniupnpd { + type nat hook prerouting priority dstnat; policy accept; + } + chain postrouting_miniupnpd { + type nat hook postrouting priority srcnat; policy accept; + } + ''; + }; + }; systemd.services.miniupnpd = { description = "MiniUPnP daemon"; after = [ "network.target" ]; wantedBy = [ "multi-user.target" ]; serviceConfig = { - ExecStart = "${pkgs.miniupnpd}/bin/miniupnpd -f ${configFile}"; + ExecStart = "${miniupnpd}/bin/miniupnpd -f ${configFile}"; PIDFile = "/run/miniupnpd.pid"; Type = "forking"; }; diff --git a/nixos/modules/services/networking/networkmanager.nix b/nixos/modules/services/networking/networkmanager.nix index d32712c8243d7..c96439cf2641a 100644 --- a/nixos/modules/services/networking/networkmanager.nix +++ b/nixos/modules/services/networking/networkmanager.nix @@ -565,7 +565,10 @@ in wantedBy = [ "network-online.target" ]; }; - systemd.services.ModemManager.aliases = [ "dbus-org.freedesktop.ModemManager1.service" ]; + systemd.services.ModemManager = { + aliases = [ "dbus-org.freedesktop.ModemManager1.service" ]; + path = lib.optionals (cfg.fccUnlockScripts != []) [ pkgs.libqmi pkgs.libmbim ]; + }; systemd.services.NetworkManager-dispatcher = { wantedBy = [ "network.target" ]; diff --git a/nixos/modules/services/networking/ntp/ntpd-rs.nix b/nixos/modules/services/networking/ntp/ntpd-rs.nix new file mode 100644 index 0000000000000..a10b570f30bcd --- /dev/null +++ b/nixos/modules/services/networking/ntp/ntpd-rs.nix @@ -0,0 +1,89 @@ +{ lib, config, pkgs, ... }: + +let + cfg = config.services.ntpd-rs; + format = pkgs.formats.toml { }; + configFile = format.generate "ntpd-rs.toml" cfg.settings; +in +{ + options.services.ntpd-rs = { + enable = lib.mkEnableOption "Network Time Service (ntpd-rs)"; + metrics.enable = lib.mkEnableOption "ntpd-rs Prometheus Metrics Exporter"; + + package = lib.mkPackageOption pkgs "ntpd-rs" { }; + + useNetworkingTimeServers = lib.mkOption { + type = lib.types.bool; + default = true; + description = lib.mdDoc '' + Use source time servers from {var}`networking.timeServers` in config. + ''; + }; + + settings = lib.mkOption { + type = lib.types.submodule { + freeformType = format.type; + }; + default = { }; + description = lib.mdDoc '' + Settings to write to {file}`ntp.toml` + + See <https://docs.ntpd-rs.pendulum-project.org/man/ntp.toml.5> + for more information about available options. + ''; + }; + }; + + config = lib.mkIf cfg.enable { + assertions = [ + { + assertion = !config.services.timesyncd.enable; + message = '' + `ntpd-rs` is not compatible with `services.timesyncd`. Please disable one of them. + ''; + } + ]; + + environment.systemPackages = [ cfg.package ]; + systemd.packages = [ cfg.package ]; + + services.timesyncd.enable = false; + systemd.services.systemd-timedated.environment = { + SYSTEMD_TIMEDATED_NTP_SERVICES = "ntpd-rs.service"; + }; + + services.ntpd-rs.settings = { + observability = { + observation-path = lib.mkDefault "/var/run/ntpd-rs/observe"; + }; + source = lib.mkIf cfg.useNetworkingTimeServers (map + (ts: { + mode = "server"; + address = ts; + }) + config.networking.timeServers); + }; + + systemd.services.ntpd-rs = { + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + User = ""; + Group = ""; + DynamicUser = true; + ExecStart = [ "" "${lib.makeBinPath [ cfg.package ]}/ntp-daemon --config=${configFile}" ]; + }; + }; + + systemd.services.ntp-rs-metrics = lib.mkIf cfg.metrics.enable { + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + User = ""; + Group = ""; + DynamicUser = true; + ExecStart = [ "" "${lib.makeBinPath [ cfg.package ]}/bin/ntp-metrics-exporter --config=${configFile}" ]; + }; + }; + }; + + meta.maintainers = with lib.maintainers; [ fpletz ]; +} diff --git a/nixos/modules/services/networking/xrdp.nix b/nixos/modules/services/networking/xrdp.nix index 3b674840b936b..7e6634cd239aa 100644 --- a/nixos/modules/services/networking/xrdp.nix +++ b/nixos/modules/services/networking/xrdp.nix @@ -4,14 +4,17 @@ with lib; let cfg = config.services.xrdp; + confDir = pkgs.runCommand "xrdp.conf" { preferLocalBuild = true; } '' - mkdir $out + mkdir -p $out - cp ${cfg.package}/etc/xrdp/{km-*,xrdp,sesman,xrdp_keyboard}.ini $out + cp -r ${cfg.package}/etc/xrdp/* $out + chmod -R +w $out cat > $out/startwm.sh <<EOF #!/bin/sh . /etc/profile + ${lib.optionalString cfg.audio.enable "${cfg.audio.package}/libexec/pulsaudio-xrdp-module/pulseaudio_xrdp_init"} ${cfg.defaultWindowManager} EOF chmod +x $out/startwm.sh @@ -25,13 +28,17 @@ let substituteInPlace $out/sesman.ini \ --replace LogFile=xrdp-sesman.log LogFile=/dev/null \ - --replace EnableSyslog=1 EnableSyslog=0 + --replace EnableSyslog=1 EnableSyslog=0 \ + --replace startwm.sh $out/startwm.sh \ + --replace reconnectwm.sh $out/reconnectwm.sh \ # Ensure that clipboard works for non-ASCII characters sed -i -e '/.*SessionVariables.*/ a\ LANG=${config.i18n.defaultLocale}\ LOCALE_ARCHIVE=${config.i18n.glibcLocales}/lib/locale/locale-archive ' $out/sesman.ini + + ${cfg.extraConfDirCommands} ''; in { @@ -44,7 +51,12 @@ in enable = mkEnableOption (lib.mdDoc "xrdp, the Remote Desktop Protocol server"); - package = mkPackageOption pkgs "xrdp" { }; + package = mkPackageOptionMD pkgs "xrdp" { }; + + audio = { + enable = mkEnableOption (lib.mdDoc "audio support for xrdp sessions. So far it only works with PulseAudio sessions on the server side. No PipeWire support yet"); + package = mkPackageOptionMD pkgs "pulseaudio-module-xrdp" {}; + }; port = mkOption { type = types.port; @@ -93,86 +105,117 @@ in confDir = mkOption { type = types.path; default = confDir; - defaultText = literalMD "generated from configuration"; - description = lib.mdDoc "The location of the config files for xrdp."; + internal = true; + description = lib.mdDoc '' + Configuration directory of xrdp and sesman. + + Changes to this must be made through extraConfDirCommands. + ''; + readOnly = true; + }; + + extraConfDirCommands = mkOption { + type = types.str; + default = ""; + description = lib.mdDoc '' + Extra commands to run on the default confDir derivation. + ''; + example = '' + substituteInPlace $out/sesman.ini \ + --replace LogLevel=INFO LogLevel=DEBUG \ + --replace LogFile=/dev/null LogFile=/var/log/xrdp.log + ''; }; }; }; - ###### implementation - config = mkIf cfg.enable { + config = lib.mkMerge [ + (mkIf cfg.audio.enable { + environment.systemPackages = [ cfg.audio.package ]; # needed for autostart - networking.firewall.allowedTCPPorts = mkIf cfg.openFirewall [ cfg.port ]; + hardware.pulseaudio.extraModules = [ cfg.audio.package ]; + }) - # xrdp can run X11 program even if "services.xserver.enable = false" - xdg = { - autostart.enable = true; - menus.enable = true; - mime.enable = true; - icons.enable = true; - }; + (mkIf cfg.enable { - fonts.enableDefaultPackages = mkDefault true; - - systemd = { - services.xrdp = { - wantedBy = [ "multi-user.target" ]; - after = [ "network.target" ]; - description = "xrdp daemon"; - requires = [ "xrdp-sesman.service" ]; - preStart = '' - # prepare directory for unix sockets (the sockets will be owned by loggedinuser:xrdp) - mkdir -p /tmp/.xrdp || true - chown xrdp:xrdp /tmp/.xrdp - chmod 3777 /tmp/.xrdp - - # generate a self-signed certificate - if [ ! -s ${cfg.sslCert} -o ! -s ${cfg.sslKey} ]; then - mkdir -p $(dirname ${cfg.sslCert}) || true - mkdir -p $(dirname ${cfg.sslKey}) || true - ${pkgs.openssl.bin}/bin/openssl req -x509 -newkey rsa:2048 -sha256 -nodes -days 365 \ - -subj /C=US/ST=CA/L=Sunnyvale/O=xrdp/CN=www.xrdp.org \ - -config ${cfg.package}/share/xrdp/openssl.conf \ - -keyout ${cfg.sslKey} -out ${cfg.sslCert} - chown root:xrdp ${cfg.sslKey} ${cfg.sslCert} - chmod 440 ${cfg.sslKey} ${cfg.sslCert} - fi - if [ ! -s /run/xrdp/rsakeys.ini ]; then - mkdir -p /run/xrdp - ${cfg.package}/bin/xrdp-keygen xrdp /run/xrdp/rsakeys.ini - fi - ''; - serviceConfig = { - User = "xrdp"; - Group = "xrdp"; - PermissionsStartOnly = true; - ExecStart = "${cfg.package}/bin/xrdp --nodaemon --port ${toString cfg.port} --config ${cfg.confDir}/xrdp.ini"; - }; + networking.firewall.allowedTCPPorts = mkIf cfg.openFirewall [ cfg.port ]; + + # xrdp can run X11 program even if "services.xserver.enable = false" + xdg = { + autostart.enable = true; + menus.enable = true; + mime.enable = true; + icons.enable = true; }; - services.xrdp-sesman = { - wantedBy = [ "multi-user.target" ]; - after = [ "network.target" ]; - description = "xrdp session manager"; - restartIfChanged = false; # do not restart on "nixos-rebuild switch". like "display-manager", it can have many interactive programs as children - serviceConfig = { - ExecStart = "${cfg.package}/bin/xrdp-sesman --nodaemon --config ${cfg.confDir}/sesman.ini"; - ExecStop = "${pkgs.coreutils}/bin/kill -INT $MAINPID"; + fonts.enableDefaultPackages = mkDefault true; + + environment.etc."xrdp".source = "${confDir}/*"; + + systemd = { + services.xrdp = { + wantedBy = [ "multi-user.target" ]; + after = [ "network.target" ]; + description = "xrdp daemon"; + requires = [ "xrdp-sesman.service" ]; + preStart = '' + # prepare directory for unix sockets (the sockets will be owned by loggedinuser:xrdp) + mkdir -p /tmp/.xrdp || true + chown xrdp:xrdp /tmp/.xrdp + chmod 3777 /tmp/.xrdp + + # generate a self-signed certificate + if [ ! -s ${cfg.sslCert} -o ! -s ${cfg.sslKey} ]; then + mkdir -p $(dirname ${cfg.sslCert}) || true + mkdir -p $(dirname ${cfg.sslKey}) || true + ${lib.getExe pkgs.openssl} req -x509 -newkey rsa:2048 -sha256 -nodes -days 365 \ + -subj /C=US/ST=CA/L=Sunnyvale/O=xrdp/CN=www.xrdp.org \ + -config ${cfg.package}/share/xrdp/openssl.conf \ + -keyout ${cfg.sslKey} -out ${cfg.sslCert} + chown root:xrdp ${cfg.sslKey} ${cfg.sslCert} + chmod 440 ${cfg.sslKey} ${cfg.sslCert} + fi + if [ ! -s /run/xrdp/rsakeys.ini ]; then + mkdir -p /run/xrdp + ${pkgs.xrdp}/bin/xrdp-keygen xrdp /run/xrdp/rsakeys.ini + fi + ''; + serviceConfig = { + User = "xrdp"; + Group = "xrdp"; + PermissionsStartOnly = true; + ExecStart = "${pkgs.xrdp}/bin/xrdp --nodaemon --port ${toString cfg.port} --config ${confDir}/xrdp.ini"; + }; + }; + + services.xrdp-sesman = { + wantedBy = [ "multi-user.target" ]; + after = [ "network.target" ]; + description = "xrdp session manager"; + restartIfChanged = false; # do not restart on "nixos-rebuild switch". like "display-manager", it can have many interactive programs as children + serviceConfig = { + ExecStart = "${pkgs.xrdp}/bin/xrdp-sesman --nodaemon --config ${confDir}/sesman.ini"; + ExecStop = "${pkgs.coreutils}/bin/kill -INT $MAINPID"; + }; }; + }; - }; + users.users.xrdp = { + description = "xrdp daemon user"; + isSystemUser = true; + group = "xrdp"; + }; + users.groups.xrdp = {}; - users.users.xrdp = { - description = "xrdp daemon user"; - isSystemUser = true; - group = "xrdp"; - }; - users.groups.xrdp = {}; + security.pam.services.xrdp-sesman = { + allowNullPassword = true; + startSession = true; + }; - security.pam.services.xrdp-sesman = { allowNullPassword = true; startSession = true; }; - }; + }) + ]; } diff --git a/nixos/modules/services/system/kerberos/heimdal.nix b/nixos/modules/services/system/kerberos/heimdal.nix index 4789e4790b4bc..ecafc92766704 100644 --- a/nixos/modules/services/system/kerberos/heimdal.nix +++ b/nixos/modules/services/system/kerberos/heimdal.nix @@ -35,7 +35,7 @@ in mkdir -m 0755 -p ${stateDir} ''; serviceConfig.ExecStart = - "${kerberos}/libexec/heimdal/kadmind --config-file=/etc/heimdal-kdc/kdc.conf"; + "${kerberos}/libexec/kadmind --config-file=/etc/heimdal-kdc/kdc.conf"; restartTriggers = [ kdcConfFile ]; }; @@ -46,7 +46,7 @@ in mkdir -m 0755 -p ${stateDir} ''; serviceConfig.ExecStart = - "${kerberos}/libexec/heimdal/kdc --config-file=/etc/heimdal-kdc/kdc.conf"; + "${kerberos}/libexec/kdc --config-file=/etc/heimdal-kdc/kdc.conf"; restartTriggers = [ kdcConfFile ]; }; @@ -56,7 +56,7 @@ in preStart = '' mkdir -m 0755 -p ${stateDir} ''; - serviceConfig.ExecStart = "${kerberos}/libexec/heimdal/kpasswdd"; + serviceConfig.ExecStart = "${kerberos}/libexec/kpasswdd"; restartTriggers = [ kdcConfFile ]; }; diff --git a/nixos/modules/services/web-apps/c2fmzq-server.nix b/nixos/modules/services/web-apps/c2fmzq-server.nix index 2749c2a5a87aa..87938fe160e14 100644 --- a/nixos/modules/services/web-apps/c2fmzq-server.nix +++ b/nixos/modules/services/web-apps/c2fmzq-server.nix @@ -6,8 +6,12 @@ let cfg = config.services.c2fmzq-server; argsFormat = { - type = with lib.types; nullOr (oneOf [ bool int str ]); - generate = lib.cli.toGNUCommandLineShell { }; + type = with lib.types; attrsOf (nullOr (oneOf [ bool int str ])); + generate = lib.cli.toGNUCommandLineShell { + mkBool = k: v: [ + "--${k}=${if v then "true" else "false"}" + ]; + }; }; in { options.services.c2fmzq-server = { diff --git a/nixos/modules/services/web-apps/miniflux.nix b/nixos/modules/services/web-apps/miniflux.nix index a500008fc7925..1a5b7d0c24e9b 100644 --- a/nixos/modules/services/web-apps/miniflux.nix +++ b/nixos/modules/services/web-apps/miniflux.nix @@ -21,10 +21,10 @@ in package = mkPackageOption pkgs "miniflux" { }; config = mkOption { - type = types.attrsOf types.str; + type = with types; attrsOf (oneOf [ str int ]); example = literalExpression '' { - CLEANUP_FREQUENCY = "48"; + CLEANUP_FREQUENCY = 48; LISTEN_ADDR = "localhost:8080"; } ''; @@ -51,12 +51,11 @@ in }; config = mkIf cfg.enable { - services.miniflux.config = { LISTEN_ADDR = mkDefault defaultAddress; DATABASE_URL = "user=miniflux host=/run/postgresql dbname=miniflux"; - RUN_MIGRATIONS = "1"; - CREATE_ADMIN = "1"; + RUN_MIGRATIONS = 1; + CREATE_ADMIN = 1; }; services.postgresql = { @@ -90,7 +89,7 @@ in User = "miniflux"; DynamicUser = true; RuntimeDirectory = "miniflux"; - RuntimeDirectoryMode = "0700"; + RuntimeDirectoryMode = "0750"; EnvironmentFile = cfg.adminCredentialsFile; # Hardening CapabilityBoundingSet = [ "" ]; @@ -117,7 +116,7 @@ in UMask = "0077"; }; - environment = cfg.config; + environment = lib.mapAttrs (_: toString) cfg.config; }; environment.systemPackages = [ cfg.package ]; diff --git a/nixos/modules/services/web-apps/nextcloud.nix b/nixos/modules/services/web-apps/nextcloud.nix index 39f4e8f11620c..38c51251aac1f 100644 --- a/nixos/modules/services/web-apps/nextcloud.nix +++ b/nixos/modules/services/web-apps/nextcloud.nix @@ -107,31 +107,10 @@ let in { imports = [ - (mkRemovedOptionModule [ "services" "nextcloud" "config" "adminpass" ] '' - Please use `services.nextcloud.config.adminpassFile' instead! - '') - (mkRemovedOptionModule [ "services" "nextcloud" "config" "dbpass" ] '' - Please use `services.nextcloud.config.dbpassFile' instead! - '') - (mkRemovedOptionModule [ "services" "nextcloud" "nginx" "enable" ] '' - The nextcloud module supports `nginx` as reverse-proxy by default and doesn't - support other reverse-proxies officially. - - However it's possible to use an alternative reverse-proxy by - - * disabling nginx - * setting `listen.owner` & `listen.group` in the phpfpm-pool to a different value - - Further details about this can be found in the `Nextcloud`-section of the NixOS-manual - (which can be opened e.g. by running `nixos-help`). - '') (mkRemovedOptionModule [ "services" "nextcloud" "enableBrokenCiphersForSSE" ] '' This option has no effect since there's no supported Nextcloud version packaged here using OpenSSL for RC4 SSE. '') - (mkRemovedOptionModule [ "services" "nextcloud" "disableImagemagick" ] '' - Use services.nextcloud.enableImagemagick instead. - '') (mkRemovedOptionModule [ "services" "nextcloud" "config" "dbport" ] '' Add port to services.nextcloud.config.dbhost instead. '') diff --git a/nixos/modules/services/web-apps/outline.nix b/nixos/modules/services/web-apps/outline.nix index d97b45d624187..702755dfa2ab8 100644 --- a/nixos/modules/services/web-apps/outline.nix +++ b/nixos/modules/services/web-apps/outline.nix @@ -586,6 +586,37 @@ in ensureDatabases = [ "outline" ]; }; + # Outline is unable to create the uuid-ossp extension when using postgresql 12, in later version this + # extension can be created without superuser permission. This services therefor this extension before + # outline starts and postgresql 12 is using on the host. + # + # Can be removed after postgresql 12 is dropped from nixos. + systemd.services.outline-postgresql = + let + pgsql = config.services.postgresql; + in + lib.mkIf (cfg.databaseUrl == "local" && pgsql.package == pkgs.postgresql_12) { + after = [ "postgresql.service" ]; + bindsTo = [ "postgresql.service" ]; + wantedBy = [ "outline.service" ]; + partOf = [ "outline.service" ]; + path = [ + pgsql.package + ]; + script = '' + set -o errexit -o pipefail -o nounset -o errtrace + shopt -s inherit_errexit + + psql outline -tAc 'CREATE EXTENSION IF NOT EXISTS "uuid-ossp"' + ''; + + serviceConfig = { + User = pgsql.superUser; + Type = "oneshot"; + RemainAfterExit = true; + }; + }; + services.redis.servers.outline = lib.mkIf (cfg.redisUrl == "local") { enable = true; user = config.services.outline.user; diff --git a/nixos/modules/services/x11/desktop-managers/plasma5.nix b/nixos/modules/services/x11/desktop-managers/plasma5.nix index e0227f93e2f25..fc9de2500ba46 100644 --- a/nixos/modules/services/x11/desktop-managers/plasma5.nix +++ b/nixos/modules/services/x11/desktop-managers/plasma5.nix @@ -26,10 +26,8 @@ let emptyValue.value = {}; }; - libsForQt5 = pkgs.plasma5Packages; - inherit (libsForQt5) kdeGear kdeFrameworks plasma5; inherit (lib) - getBin optionalAttrs optionalString literalExpression + getBin optionalAttrs literalExpression mkRemovedOptionModule mkRenamedOptionModule mkDefault mkIf mkMerge mkOption mkPackageOption types; @@ -65,7 +63,7 @@ let # recognize that software that has been removed. rm -fv $HOME/.cache/ksycoca* - ${libsForQt5.kservice}/bin/kbuildsycoca5 + ${pkgs.plasma5Packages.kservice}/bin/kbuildsycoca5 ''; set_XDG_CONFIG_HOME = '' @@ -176,20 +174,19 @@ in owner = "root"; group = "root"; capabilities = "cap_sys_nice+ep"; - source = "${getBin plasma5.kwin}/bin/kwin_wayland"; + source = "${getBin pkgs.plasma5Packages.kwin}/bin/kwin_wayland"; }; } // optionalAttrs (!cfg.runUsingSystemd) { start_kdeinit = { setuid = true; owner = "root"; group = "root"; - source = "${getBin libsForQt5.kinit}/libexec/kf5/start_kdeinit"; + source = "${getBin pkgs.plasma5Packages.kinit}/libexec/kf5/start_kdeinit"; }; }; environment.systemPackages = - with libsForQt5; - with plasma5; with kdeGear; with kdeFrameworks; + with pkgs.plasma5Packages; let requiredPackages = [ frameworkintegration @@ -284,8 +281,8 @@ in ++ utils.removePackagesByName optionalPackages config.environment.plasma5.excludePackages # Phonon audio backend - ++ lib.optional (cfg.phononBackend == "gstreamer") libsForQt5.phonon-backend-gstreamer - ++ lib.optional (cfg.phononBackend == "vlc") libsForQt5.phonon-backend-vlc + ++ lib.optional (cfg.phononBackend == "gstreamer") pkgs.plasma5Packages.phonon-backend-gstreamer + ++ lib.optional (cfg.phononBackend == "vlc") pkgs.plasma5Packages.phonon-backend-vlc # Optional hardware support features ++ lib.optionals config.hardware.bluetooth.enable [ bluedevil bluez-qt pkgs.openobex pkgs.obexftp ] @@ -301,7 +298,7 @@ in # Extra services for D-Bus activation services.dbus.packages = [ - plasma5.kactivitymanagerd + pkgs.plasma5Packages.kactivitymanagerd ]; environment.pathsToLink = [ @@ -334,7 +331,7 @@ in serif = [ "Noto Serif" ]; }; - programs.ssh.askPassword = mkDefault "${plasma5.ksshaskpass.out}/bin/ksshaskpass"; + programs.ssh.askPassword = mkDefault "${pkgs.plasma5Packages.ksshaskpass.out}/bin/ksshaskpass"; # Enable helpful DBus services. services.accounts-daemon.enable = true; @@ -372,8 +369,8 @@ in }; xdg.portal.enable = true; - xdg.portal.extraPortals = [ plasma5.xdg-desktop-portal-kde ]; - xdg.portal.configPackages = mkDefault [ plasma5.xdg-desktop-portal-kde ]; + xdg.portal.extraPortals = [ pkgs.plasma5Packages.xdg-desktop-portal-kde ]; + xdg.portal.configPackages = mkDefault [ pkgs.plasma5Packages.xdg-desktop-portal-kde ]; # xdg-desktop-portal-kde expects PipeWire to be running. # This does not, by default, replace PulseAudio. services.pipewire.enable = mkDefault true; @@ -404,15 +401,14 @@ in '' ]; - services.xserver.displayManager.sessionPackages = [ pkgs.libsForQt5.plasma5.plasma-workspace ]; + services.xserver.displayManager.sessionPackages = [ pkgs.plasma5Packages.plasma-workspace ]; # Default to be `plasma` (X11) instead of `plasmawayland`, since plasma wayland currently has # many tiny bugs. # See: https://github.com/NixOS/nixpkgs/issues/143272 services.xserver.displayManager.defaultSession = mkDefault "plasma"; environment.systemPackages = - with libsForQt5; - with plasma5; with kdeGear; with kdeFrameworks; + with pkgs.plasma5Packages; let requiredPackages = [ ksystemstats @@ -448,7 +444,7 @@ in script = '' ${set_XDG_CONFIG_HOME} - ${kdeFrameworks.kconfig}/bin/kwriteconfig5 \ + ${pkgs.plasma5Packages.kconfig}/bin/kwriteconfig5 \ --file startkderc --group General --key systemdBoot ${lib.boolToString cfg.runUsingSystemd} ''; }; @@ -476,8 +472,7 @@ in ]; environment.systemPackages = - with libsForQt5; - with plasma5; with kdeApplications; with kdeFrameworks; + with pkgs.plasma5Packages; [ # Basic packages without which Plasma Mobile fails to work properly. plasma-mobile @@ -536,7 +531,7 @@ in }; }; - services.xserver.displayManager.sessionPackages = [ pkgs.libsForQt5.plasma5.plasma-mobile ]; + services.xserver.displayManager.sessionPackages = [ pkgs.plasma5Packages.plasma-mobile ]; }) # Plasma Bigscreen diff --git a/nixos/modules/services/x11/display-managers/default.nix b/nixos/modules/services/x11/display-managers/default.nix index 16a7ff1a4bd5e..3e2d5780a5cb1 100644 --- a/nixos/modules/services/x11/display-managers/default.nix +++ b/nixos/modules/services/x11/display-managers/default.nix @@ -514,7 +514,7 @@ in # Make xsessions and wayland sessions available in XDG_DATA_DIRS # as some programs have behavior that depends on them being present - environment.sessionVariables.XDG_DATA_DIRS = [ + environment.sessionVariables.XDG_DATA_DIRS = lib.mkIf (cfg.displayManager.sessionPackages != [ ]) [ "${cfg.displayManager.sessionData.desktops}/share" ]; }; diff --git a/nixos/modules/system/boot/systemd.nix b/nixos/modules/system/boot/systemd.nix index 87333999313e4..c3902007906ad 100644 --- a/nixos/modules/system/boot/systemd.nix +++ b/nixos/modules/system/boot/systemd.nix @@ -451,6 +451,21 @@ in cfg.services ); + assertions = concatLists ( + mapAttrsToList + (name: service: + map (message: { + assertion = false; + inherit message; + }) (concatLists [ + (optional ((builtins.elem "network-interfaces.target" service.after) || (builtins.elem "network-interfaces.target" service.wants)) + "Service '${name}.service' is using the deprecated target network-interfaces.target, which no longer exists. Using network.target is recommended instead." + ) + ]) + ) + cfg.services + ); + system.build.units = cfg.units; system.nssModules = [ cfg.package.out ]; diff --git a/nixos/modules/system/boot/systemd/repart.nix b/nixos/modules/system/boot/systemd/repart.nix index 5ac2ace56ba02..3be744acd0b3b 100644 --- a/nixos/modules/system/boot/systemd/repart.nix +++ b/nixos/modules/system/boot/systemd/repart.nix @@ -83,6 +83,9 @@ in } ]; + # systemd-repart uses loopback devices for partition creation + boot.initrd.availableKernelModules = lib.optional initrdCfg.enable "loop"; + boot.initrd.systemd = lib.mkIf initrdCfg.enable { additionalUpstreamUnits = [ "systemd-repart.service" diff --git a/nixos/modules/system/boot/systemd/sysupdate.nix b/nixos/modules/system/boot/systemd/sysupdate.nix index b1914a9c4e767..cab35ddf270cb 100644 --- a/nixos/modules/system/boot/systemd/sysupdate.nix +++ b/nixos/modules/system/boot/systemd/sysupdate.nix @@ -71,7 +71,7 @@ in type = with lib.types; attrsOf format.type; default = { }; example = { - "10-uki.conf" = { + "10-uki" = { Transfer = { ProtectVersion = "%A"; }; diff --git a/nixos/modules/tasks/filesystems/zfs.nix b/nixos/modules/tasks/filesystems/zfs.nix index bc8b8fdf8144f..b289d2151eb79 100644 --- a/nixos/modules/tasks/filesystems/zfs.nix +++ b/nixos/modules/tasks/filesystems/zfs.nix @@ -108,12 +108,12 @@ let getKeyLocations = pool: if isBool cfgZfs.requestEncryptionCredentials then { hasKeys = cfgZfs.requestEncryptionCredentials; - command = "${cfgZfs.package}/sbin/zfs list -rHo name,keylocation,keystatus ${pool}"; + command = "${cfgZfs.package}/sbin/zfs list -rHo name,keylocation,keystatus -t volume,filesystem ${pool}"; } else let keys = filter (x: datasetToPool x == pool) cfgZfs.requestEncryptionCredentials; in { hasKeys = keys != []; - command = "${cfgZfs.package}/sbin/zfs list -Ho name,keylocation,keystatus ${toString keys}"; + command = "${cfgZfs.package}/sbin/zfs list -Ho name,keylocation,keystatus -t volume,filesystem ${toString keys}"; }; createImportService = { pool, systemd, force, prefix ? "" }: diff --git a/nixos/modules/tasks/network-interfaces-scripted.nix b/nixos/modules/tasks/network-interfaces-scripted.nix index e1ac7f24cb320..2f2d282fbefb4 100644 --- a/nixos/modules/tasks/network-interfaces-scripted.nix +++ b/nixos/modules/tasks/network-interfaces-scripted.nix @@ -70,7 +70,8 @@ let deviceDependency = dev: # Use systemd service if we manage device creation, else # trust udev when not in a container - if (hasAttr dev (filterAttrs (k: v: v.virtual) cfg.interfaces)) || + if (dev == null || dev == "lo") then [] + else if (hasAttr dev (filterAttrs (k: v: v.virtual) cfg.interfaces)) || (hasAttr dev cfg.bridges) || (hasAttr dev cfg.bonds) || (hasAttr dev cfg.macvlans) || @@ -78,7 +79,7 @@ let (hasAttr dev cfg.vlans) || (hasAttr dev cfg.vswitches) then [ "${dev}-netdev.service" ] - else optional (dev != null && dev != "lo" && !config.boot.isContainer) (subsystemDevice dev); + else optional (!config.boot.isContainer) (subsystemDevice dev); hasDefaultGatewaySet = (cfg.defaultGateway != null && cfg.defaultGateway.address != "") || (cfg.enableIPv6 && cfg.defaultGateway6 != null && cfg.defaultGateway6.address != ""); diff --git a/nixos/modules/tasks/network-interfaces.nix b/nixos/modules/tasks/network-interfaces.nix index 2b2d24a64cb20..ca0b219b3c93d 100644 --- a/nixos/modules/tasks/network-interfaces.nix +++ b/nixos/modules/tasks/network-interfaces.nix @@ -1449,16 +1449,6 @@ in listToAttrs ]; - # The network-interfaces target is kept for backwards compatibility. - # New modules must NOT use it. - systemd.targets.network-interfaces = - { description = "All Network Interfaces (deprecated)"; - wantedBy = [ "network.target" ]; - before = [ "network.target" ]; - after = [ "network-pre.target" ]; - unitConfig.X-StopOnReconfiguration = true; - }; - systemd.services = { network-local-commands = { description = "Extra networking commands."; diff --git a/nixos/modules/tasks/trackpoint.nix b/nixos/modules/tasks/trackpoint.nix index 317613b847927..b3f6f32eaa473 100644 --- a/nixos/modules/tasks/trackpoint.nix +++ b/nixos/modules/tasks/trackpoint.nix @@ -88,7 +88,7 @@ with lib; serviceConfig.Type = "oneshot"; serviceConfig.RemainAfterExit = true; serviceConfig.ExecStart = '' - ${config.systemd.package}/bin/udevadm trigger --attr-match=name="${cfg.device} + ${config.systemd.package}/bin/udevadm trigger --attr-match=name="${cfg.device}" ''; }; }) diff --git a/nixos/modules/virtualisation/libvirtd.nix b/nixos/modules/virtualisation/libvirtd.nix index e195ff937d68e..217242a8fbd22 100644 --- a/nixos/modules/virtualisation/libvirtd.nix +++ b/nixos/modules/virtualisation/libvirtd.nix @@ -116,6 +116,15 @@ let QEMU's swtpm options. ''; }; + + vhostUserPackages = mkOption { + type = types.listOf types.package; + default = [ ]; + example = lib.literalExpression "[ pkgs.virtiofsd ]"; + description = lib.mdDoc '' + Packages containing out-of-tree vhost-user drivers. + ''; + }; }; }; @@ -502,6 +511,14 @@ in # https://libvirt.org/daemons.html#monolithic-systemd-integration systemd.sockets.libvirtd.wantedBy = [ "sockets.target" ]; + systemd.tmpfiles.rules = let + vhostUserCollection = pkgs.buildEnv { + name = "vhost-user"; + paths = cfg.qemu.vhostUserPackages; + pathsToLink = [ "/share/qemu/vhost-user" ]; + }; + in [ "L+ /var/lib/qemu/vhost-user - - - - ${vhostUserCollection}/share/qemu/vhost-user" ]; + security.polkit = { enable = true; extraConfig = '' diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix index be394c19ebef0..63e957eace88d 100644 --- a/nixos/tests/all-tests.nix +++ b/nixos/tests/all-tests.nix @@ -583,6 +583,7 @@ in { nginx = handleTest ./nginx.nix {}; nginx-auth = handleTest ./nginx-auth.nix {}; nginx-etag = handleTest ./nginx-etag.nix {}; + nginx-etag-compression = handleTest ./nginx-etag-compression.nix {}; nginx-globalredirect = handleTest ./nginx-globalredirect.nix {}; nginx-http3 = handleTest ./nginx-http3.nix {}; nginx-modsecurity = handleTest ./nginx-modsecurity.nix {}; @@ -604,6 +605,7 @@ in { nixos-generate-config = handleTest ./nixos-generate-config.nix {}; nixos-rebuild-install-bootloader = handleTestOn ["x86_64-linux"] ./nixos-rebuild-install-bootloader.nix {}; nixos-rebuild-specialisations = handleTestOn ["x86_64-linux"] ./nixos-rebuild-specialisations.nix {}; + nixos-rebuild-target-host = handleTest ./nixos-rebuild-target-host.nix {}; nixpkgs = pkgs.callPackage ../modules/misc/nixpkgs/test.nix { inherit evalMinimalConfig; }; nixseparatedebuginfod = handleTest ./nixseparatedebuginfod.nix {}; node-red = handleTest ./node-red.nix {}; @@ -617,6 +619,8 @@ in { nscd = handleTest ./nscd.nix {}; nsd = handleTest ./nsd.nix {}; ntfy-sh = handleTest ./ntfy-sh.nix {}; + ntfy-sh-migration = handleTest ./ntfy-sh-migration.nix {}; + ntpd-rs = handleTest ./ntpd-rs.nix {}; nzbget = handleTest ./nzbget.nix {}; nzbhydra2 = handleTest ./nzbhydra2.nix {}; oh-my-zsh = handleTest ./oh-my-zsh.nix {}; @@ -910,7 +914,8 @@ in { unbound = handleTest ./unbound.nix {}; unifi = handleTest ./unifi.nix {}; unit-php = handleTest ./web-servers/unit-php.nix {}; - upnp = handleTest ./upnp.nix {}; + upnp.iptables = handleTest ./upnp.nix { useNftables = false; }; + upnp.nftables = handleTest ./upnp.nix { useNftables = true; }; uptermd = handleTest ./uptermd.nix {}; uptime-kuma = handleTest ./uptime-kuma.nix {}; usbguard = handleTest ./usbguard.nix {}; @@ -953,6 +958,7 @@ in { xmonad-xdg-autostart = handleTest ./xmonad-xdg-autostart.nix {}; xpadneo = handleTest ./xpadneo.nix {}; xrdp = handleTest ./xrdp.nix {}; + xrdp-with-audio-pulseaudio = handleTest ./xrdp-with-audio-pulseaudio.nix {}; xscreensaver = handleTest ./xscreensaver.nix {}; xss-lock = handleTest ./xss-lock.nix {}; xterm = handleTest ./xterm.nix {}; diff --git a/nixos/tests/c2fmzq.nix b/nixos/tests/c2fmzq.nix index d8ec816c7d29c..0dd89f6881dd9 100644 --- a/nixos/tests/c2fmzq.nix +++ b/nixos/tests/c2fmzq.nix @@ -9,6 +9,10 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: { passphraseFile = builtins.toFile "pwfile" "hunter2"; # don't do this on real deployments settings = { verbose = 3; # debug + # make sure multiple freeform options evaluate + allow-new-accounts = true; + auto-approve-new-accounts = true; + licenses = false; }; }; environment = { @@ -71,5 +75,8 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: { with subtest("Test that PWA is served"): msg = machine.succeed("curl -sSfL http://localhost:8080") assert "c2FmZQ" in msg, f"Could not find 'c2FmZQ' in the output:\n{msg}" + + with subtest("A setting with false value is properly passed"): + machine.succeed("systemctl show -p ExecStart --value c2fmzq-server.service | grep -F -- '--licenses=false'"); ''; }) diff --git a/nixos/tests/nginx-etag-compression.nix b/nixos/tests/nginx-etag-compression.nix new file mode 100644 index 0000000000000..67493ae299841 --- /dev/null +++ b/nixos/tests/nginx-etag-compression.nix @@ -0,0 +1,45 @@ +import ./make-test-python.nix { + name = "nginx-etag-compression"; + + nodes.machine = { pkgs, lib, ... }: { + services.nginx = { + enable = true; + recommendedGzipSettings = true; + virtualHosts.default = { + root = pkgs.runCommandLocal "testdir" {} '' + mkdir "$out" + cat > "$out/index.html" <<EOF + Hello, world! + Hello, world! + Hello, world! + Hello, world! + Hello, world! + Hello, world! + Hello, world! + Hello, world! + EOF + ${pkgs.gzip}/bin/gzip -k "$out/index.html" + ''; + }; + }; + }; + + testScript = { nodes, ... }: '' + machine.wait_for_unit("nginx") + machine.wait_for_open_port(80) + + etag_plain = machine.succeed("curl -s -w'%header{etag}' -o/dev/null -H 'Accept-encoding:' http://127.0.0.1/") + etag_gzip = machine.succeed("curl -s -w'%header{etag}' -o/dev/null -H 'Accept-encoding:gzip' http://127.0.0.1/") + + with subtest("different representations have different etags"): + assert etag_plain != etag_gzip, f"etags should differ: {etag_plain} == {etag_gzip}" + + with subtest("etag for uncompressed response is reproducible"): + etag_plain_repeat = machine.succeed("curl -s -w'%header{etag}' -o/dev/null -H 'Accept-encoding:' http://127.0.0.1/") + assert etag_plain == etag_plain_repeat, f"etags should be the same: {etag_plain} != {etag_plain_repeat}" + + with subtest("etag for compressed response is reproducible"): + etag_gzip_repeat = machine.succeed("curl -s -w'%header{etag}' -o/dev/null -H 'Accept-encoding:gzip' http://127.0.0.1/") + assert etag_gzip == etag_gzip_repeat, f"etags should be the same: {etag_gzip} != {etag_gzip_repeat}" + ''; +} diff --git a/nixos/tests/nixos-rebuild-target-host.nix b/nixos/tests/nixos-rebuild-target-host.nix new file mode 100644 index 0000000000000..8d60b788abf38 --- /dev/null +++ b/nixos/tests/nixos-rebuild-target-host.nix @@ -0,0 +1,136 @@ +import ./make-test-python.nix ({ pkgs, ... }: { + name = "nixos-rebuild-target-host"; + + nodes = { + deployer = { lib, ... }: let + inherit (import ./ssh-keys.nix pkgs) snakeOilPrivateKey snakeOilPublicKey; + in { + imports = [ ../modules/profiles/installation-device.nix ]; + + nix.settings = { + substituters = lib.mkForce [ ]; + hashed-mirrors = null; + connect-timeout = 1; + }; + + environment.systemPackages = [ pkgs.passh ]; + + system.includeBuildDependencies = true; + + virtualisation = { + cores = 2; + memorySize = 2048; + }; + + system.build.privateKey = snakeOilPrivateKey; + system.build.publicKey = snakeOilPublicKey; + }; + + target = { nodes, lib, ... }: let + targetConfig = { + documentation.enable = false; + services.openssh.enable = true; + + users.users.root.openssh.authorizedKeys.keys = [ nodes.deployer.system.build.publicKey ]; + users.users.alice.openssh.authorizedKeys.keys = [ nodes.deployer.system.build.publicKey ]; + users.users.bob.openssh.authorizedKeys.keys = [ nodes.deployer.system.build.publicKey ]; + + users.users.alice.extraGroups = [ "wheel" ]; + users.users.bob.extraGroups = [ "wheel" ]; + + # Disable sudo for root to ensure sudo isn't called without `--use-remote-sudo` + security.sudo.extraRules = lib.mkForce [ + { groups = [ "wheel" ]; commands = [ { command = "ALL"; } ]; } + { users = [ "alice" ]; commands = [ { command = "ALL"; options = [ "NOPASSWD" ]; } ]; } + ]; + + nix.settings.trusted-users = [ "@wheel" ]; + }; + in { + imports = [ ./common/user-account.nix ]; + + config = lib.mkMerge [ + targetConfig + { + system.build = { + inherit targetConfig; + }; + + networking.hostName = "target"; + } + ]; + }; + }; + + testScript = { nodes, ... }: + let + sshConfig = builtins.toFile "ssh.conf" '' + UserKnownHostsFile=/dev/null + StrictHostKeyChecking=no + ''; + + targetConfigJSON = pkgs.writeText "target-configuration.json" + (builtins.toJSON nodes.target.system.build.targetConfig); + + targetNetworkJSON = pkgs.writeText "target-network.json" + (builtins.toJSON nodes.target.system.build.networkConfig); + + configFile = hostname: pkgs.writeText "configuration.nix" '' + { lib, modulesPath, ... }: { + imports = [ + (modulesPath + "/virtualisation/qemu-vm.nix") + (modulesPath + "/testing/test-instrumentation.nix") + (modulesPath + "/../tests/common/user-account.nix") + (lib.modules.importJSON ./target-configuration.json) + (lib.modules.importJSON ./target-network.json) + ./hardware-configuration.nix + ]; + + boot.loader.grub = { + enable = true; + device = "/dev/vda"; + forceInstall = true; + }; + + # this will be asserted + networking.hostName = "${hostname}"; + } + ''; + in + '' + start_all() + target.wait_for_open_port(22) + + deployer.wait_until_succeeds("ping -c1 target") + deployer.succeed("install -Dm 600 ${nodes.deployer.system.build.privateKey} ~root/.ssh/id_ecdsa") + deployer.succeed("install ${sshConfig} ~root/.ssh/config") + + target.succeed("nixos-generate-config") + deployer.succeed("scp alice@target:/etc/nixos/hardware-configuration.nix /root/hardware-configuration.nix") + + deployer.copy_from_host("${configFile "config-1-deployed"}", "/root/configuration-1.nix") + deployer.copy_from_host("${configFile "config-2-deployed"}", "/root/configuration-2.nix") + deployer.copy_from_host("${configFile "config-3-deployed"}", "/root/configuration-3.nix") + deployer.copy_from_host("${targetNetworkJSON}", "/root/target-network.json") + deployer.copy_from_host("${targetConfigJSON}", "/root/target-configuration.json") + + # Ensure sudo is disabled for root + target.fail("sudo true") + + # This test also ensures that sudo is not called without --use-remote-sudo + with subtest("Deploy to root@target"): + deployer.succeed("nixos-rebuild switch -I nixos-config=/root/configuration-1.nix --target-host root@target &>/dev/console") + target_hostname = deployer.succeed("ssh alice@target cat /etc/hostname").rstrip() + assert target_hostname == "config-1-deployed", f"{target_hostname=}" + + with subtest("Deploy to alice@target with passwordless sudo"): + deployer.succeed("nixos-rebuild switch -I nixos-config=/root/configuration-2.nix --target-host alice@target --use-remote-sudo &>/dev/console") + target_hostname = deployer.succeed("ssh alice@target cat /etc/hostname").rstrip() + assert target_hostname == "config-2-deployed", f"{target_hostname=}" + + with subtest("Deploy to bob@target with password based sudo"): + deployer.succeed("passh -c 3 -C -p ${nodes.target.users.users.bob.password} -P \"\[sudo\] password\" nixos-rebuild switch -I nixos-config=/root/configuration-3.nix --target-host bob@target --use-remote-sudo &>/dev/console") + target_hostname = deployer.succeed("ssh alice@target cat /etc/hostname").rstrip() + assert target_hostname == "config-3-deployed", f"{target_hostname=}" + ''; +}) diff --git a/nixos/tests/ntfy-sh-migration.nix b/nixos/tests/ntfy-sh-migration.nix new file mode 100644 index 0000000000000..de6660052d679 --- /dev/null +++ b/nixos/tests/ntfy-sh-migration.nix @@ -0,0 +1,77 @@ +# the ntfy-sh module was switching to DynamicUser=true. this test assures that +# the migration does not break existing setups. +# +# this test works doing a migration and asserting ntfy-sh runs properly. first, +# ntfy-sh is configured to use a static user and group. then ntfy-sh is +# started and tested. after that, ntfy-sh is shut down and a systemd drop +# in configuration file is used to upate the service configuration to use +# DynamicUser=true. then the ntfy-sh is started again and tested. + +import ./make-test-python.nix { + name = "ntfy-sh"; + + nodes.machine = { + lib, + pkgs, + ... + }: { + environment.etc."ntfy-sh-dynamic-user.conf".text = '' + [Service] + Group=new-ntfy-sh + User=new-ntfy-sh + DynamicUser=true + ''; + + services.ntfy-sh.enable = true; + services.ntfy-sh.settings.base-url = "http://localhost:2586"; + + systemd.services.ntfy-sh.serviceConfig = { + DynamicUser = lib.mkForce false; + ExecStartPre = [ + "${pkgs.coreutils}/bin/id" + "${pkgs.coreutils}/bin/ls -lahd /var/lib/ntfy-sh/" + "${pkgs.coreutils}/bin/ls -lah /var/lib/ntfy-sh/" + ]; + Group = lib.mkForce "old-ntfy-sh"; + User = lib.mkForce "old-ntfy-sh"; + }; + + users.users.old-ntfy-sh = { + isSystemUser = true; + group = "old-ntfy-sh"; + }; + + users.groups.old-ntfy-sh = {}; + }; + + testScript = '' + import json + + msg = "Test notification" + + def test_ntfysh(): + machine.wait_for_unit("ntfy-sh.service") + machine.wait_for_open_port(2586) + + machine.succeed(f"curl -d '{msg}' localhost:2586/test") + + text = machine.succeed("curl -s localhost:2586/test/json?poll=1") + for line in text.splitlines(): + notif = json.loads(line) + assert msg == notif["message"], "Wrong message" + + machine.succeed("ntfy user list") + + machine.wait_for_unit("multi-user.target") + + test_ntfysh() + + machine.succeed("systemctl stop ntfy-sh.service") + machine.succeed("mkdir -p /run/systemd/system/ntfy-sh.service.d") + machine.succeed("cp /etc/ntfy-sh-dynamic-user.conf /run/systemd/system/ntfy-sh.service.d/dynamic-user.conf") + machine.succeed("systemctl daemon-reload") + machine.succeed("systemctl start ntfy-sh.service") + + test_ntfysh() + ''; +} diff --git a/nixos/tests/ntpd-rs.nix b/nixos/tests/ntpd-rs.nix new file mode 100644 index 0000000000000..2901be5235208 --- /dev/null +++ b/nixos/tests/ntpd-rs.nix @@ -0,0 +1,49 @@ +import ./make-test-python.nix ({ lib, ... }: +{ + name = "ntpd-rs"; + + meta = { + maintainers = with lib.maintainers; [ fpletz ]; + }; + + nodes = { + client = { + services.ntpd-rs = { + enable = true; + metrics.enable = true; + useNetworkingTimeServers = false; + settings = { + source = [ + { + mode = "server"; + address = "server"; + } + ]; + synchronization = { + minimum-agreeing-sources = 1; + }; + }; + }; + }; + server = { + networking.firewall.allowedUDPPorts = [ 123 ]; + services.ntpd-rs = { + enable = true; + metrics.enable = true; + settings = { + server = [ + { listen = "[::]:123"; } + ]; + }; + }; + }; + }; + + testScript = { nodes, ... }: '' + start_all() + server.wait_for_unit('multi-user.target') + client.wait_for_unit('multi-user.target') + server.succeed('systemctl is-active ntpd-rs.service') + client.succeed('systemctl is-active ntpd-rs.service') + ''; +}) diff --git a/nixos/tests/pantheon.nix b/nixos/tests/pantheon.nix index be1351283d99a..69a28c397bedc 100644 --- a/nixos/tests/pantheon.nix +++ b/nixos/tests/pantheon.nix @@ -26,6 +26,7 @@ import ./make-test-python.nix ({ pkgs, lib, ...} : with subtest("Test we can see usernames in elementary-greeter"): machine.wait_for_text("${user.description}") + machine.wait_until_succeeds("pgrep -f io.elementary.greeter-compositor") # OCR was struggling with this one. # machine.wait_for_text("${bob.description}") # Ensure the password box is focused by clicking it. @@ -39,21 +40,29 @@ import ./make-test-python.nix ({ pkgs, lib, ...} : machine.wait_for_x() machine.wait_for_file("${user.home}/.Xauthority") machine.succeed("xauth merge ${user.home}/.Xauthority") + machine.wait_until_succeeds('journalctl -t gnome-session-binary --grep "Entering running state"') with subtest("Check that logging in has given the user ownership of devices"): machine.succeed("getfacl -p /dev/snd/timer | grep -q ${user.name}") - with subtest("Check if pantheon session components actually start"): - machine.wait_until_succeeds("pgrep gala") - machine.wait_for_window("gala") - machine.wait_until_succeeds("pgrep -f io.elementary.wingpanel") - machine.wait_for_window("io.elementary.wingpanel") - machine.wait_until_succeeds("pgrep plank") - machine.wait_for_window("plank") - machine.wait_until_succeeds("pgrep -f gsd-media-keys") + with subtest("Check if Pantheon components actually start"): + for i in ["gala", "io.elementary.wingpanel", "plank", "gsd-media-keys", "io.elementary.desktop.agent-polkit"]: + machine.wait_until_succeeds(f"pgrep -f {i}") + for i in ["gala", "io.elementary.wingpanel", "plank"]: + machine.wait_for_window(i) machine.wait_for_unit("bamfdaemon.service", "${user.name}") machine.wait_for_unit("io.elementary.files.xdg-desktop-portal.service", "${user.name}") + with subtest("Check if various environment variables are set"): + cmd = "xargs --null --max-args=1 echo < /proc/$(pgrep -xf /run/current-system/sw/bin/gala)/environ" + machine.succeed(f"{cmd} | grep 'XDG_CURRENT_DESKTOP' | grep 'Pantheon'") + # Hopefully from the sessionPath option. + machine.succeed(f"{cmd} | grep 'XDG_DATA_DIRS' | grep 'gsettings-schemas/pantheon-agent-geoclue2'") + # Hopefully from login shell. + machine.succeed(f"{cmd} | grep '__NIXOS_SET_ENVIRONMENT_DONE' | grep '1'") + # See elementary-session-settings packaging. + machine.succeed(f"{cmd} | grep 'XDG_CONFIG_DIRS' | grep 'elementary-default-settings'") + with subtest("Open elementary videos"): machine.execute("su - ${user.name} -c 'DISPLAY=:0 io.elementary.videos >&2 &'") machine.sleep(2) @@ -61,6 +70,7 @@ import ./make-test-python.nix ({ pkgs, lib, ...} : machine.wait_for_text("No Videos Open") with subtest("Open elementary calendar"): + machine.wait_until_succeeds("pgrep -f evolution-calendar-factory") machine.execute("su - ${user.name} -c 'DISPLAY=:0 io.elementary.calendar >&2 &'") machine.sleep(2) machine.wait_for_window("io.elementary.calendar") @@ -75,6 +85,14 @@ import ./make-test-python.nix ({ pkgs, lib, ...} : machine.execute("su - ${user.name} -c 'DISPLAY=:0 io.elementary.terminal >&2 &'") machine.wait_for_window("io.elementary.terminal") + with subtest("Trigger multitasking view"): + cmd = "dbus-send --session --dest=org.pantheon.gala --print-reply /org/pantheon/gala org.pantheon.gala.PerformAction int32:1" + env = "DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/${toString user.uid}/bus DISPLAY=:0" + machine.succeed(f"su - ${user.name} -c '{env} {cmd}'") + machine.sleep(3) + machine.screenshot("multitasking") + machine.succeed(f"su - ${user.name} -c '{env} {cmd}'") + with subtest("Check if gala has ever coredumped"): machine.fail("coredumpctl --json=short | grep gala") # So you can see the dock in the below screenshot. diff --git a/nixos/tests/pgadmin4.nix b/nixos/tests/pgadmin4.nix index 3ee7ed19fa1c5..407e4592ef5f7 100644 --- a/nixos/tests/pgadmin4.nix +++ b/nixos/tests/pgadmin4.nix @@ -4,31 +4,49 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: name = "pgadmin4"; meta.maintainers = with lib.maintainers; [ mkg20001 gador ]; - nodes.machine = { pkgs, ... }: { + nodes = { + machine = { pkgs, ... }: { - imports = [ ./common/user-account.nix ]; + imports = [ ./common/user-account.nix ]; - environment.systemPackages = with pkgs; [ - wget - curl - pgadmin4-desktopmode - ]; + environment.systemPackages = with pkgs; [ + wget + curl + pgadmin4-desktopmode + ]; - services.postgresql = { - enable = true; - authentication = '' - host all all localhost trust - ''; + services.postgresql = { + enable = true; + authentication = '' + host all all localhost trust + ''; + }; + + services.pgadmin = { + port = 5051; + enable = true; + initialEmail = "bruh@localhost.de"; + initialPasswordFile = pkgs.writeText "pw" "bruh2012!"; + }; }; + machine2 = { pkgs, ... }: { + + imports = [ ./common/user-account.nix ]; + + services.postgresql = { + enable = true; + }; - services.pgadmin = { - port = 5051; - enable = true; - initialEmail = "bruh@localhost.de"; - initialPasswordFile = pkgs.writeText "pw" "bruh2012!"; + services.pgadmin = { + enable = true; + initialEmail = "bruh@localhost.de"; + initialPasswordFile = pkgs.writeText "pw" "bruh2012!"; + minimumPasswordLength = 12; + }; }; }; + testScript = '' with subtest("Check pgadmin module"): machine.wait_for_unit("postgresql") @@ -49,5 +67,9 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: machine.wait_until_succeeds("curl -sS localhost:5050") machine.wait_until_succeeds("curl -sS localhost:5050/browser/ | grep \"<title>pgAdmin 4</title>\" > /dev/null") machine.succeed("wget -nv --level=1 --spider --recursive localhost:5050/browser") + + with subtest("Check pgadmin minimum password length"): + machine2.wait_for_unit("postgresql") + machine2.wait_for_console_text("Password must be at least 12 characters long") ''; }) diff --git a/nixos/tests/prowlarr.nix b/nixos/tests/prowlarr.nix index af669afd57004..663743546459f 100644 --- a/nixos/tests/prowlarr.nix +++ b/nixos/tests/prowlarr.nix @@ -11,6 +11,8 @@ import ./make-test-python.nix ({ lib, ... }: testScript = '' machine.wait_for_unit("prowlarr.service") machine.wait_for_open_port(9696) - machine.succeed("curl --fail http://localhost:9696/") + response = machine.succeed("curl --fail http://localhost:9696/") + assert '<title>Prowlarr</title>' in response, "Login page didn't load successfully" + machine.succeed("[ -d /var/lib/prowlarr ]") ''; }) diff --git a/nixos/tests/spark/default.nix b/nixos/tests/spark/default.nix index eed7db35bf4f1..034e9711bed52 100644 --- a/nixos/tests/spark/default.nix +++ b/nixos/tests/spark/default.nix @@ -10,7 +10,7 @@ let sparkCluster = testSparkCluster args; passthru.override = args': testsForPackage (args // args'); }; - testSparkCluster = { sparkPackage, ... }: pkgs.nixosTest ({ + testSparkCluster = { sparkPackage, ... }: pkgs.testers.nixosTest ({ name = "spark"; nodes = { diff --git a/nixos/tests/upnp.nix b/nixos/tests/upnp.nix index af7cc1fe24130..5e135267403bd 100644 --- a/nixos/tests/upnp.nix +++ b/nixos/tests/upnp.nix @@ -5,7 +5,7 @@ # this succeeds an external client will try to connect to the port # mapping. -import ./make-test-python.nix ({ pkgs, ... }: +import ./make-test-python.nix ({ pkgs, useNftables, ... }: let internalRouterAddress = "192.168.3.1"; @@ -27,6 +27,7 @@ in networking.nat.enable = true; networking.nat.internalInterfaces = [ "eth2" ]; networking.nat.externalInterface = "eth1"; + networking.nftables.enable = useNftables; networking.firewall.enable = true; networking.firewall.trustedInterfaces = [ "eth2" ]; networking.interfaces.eth1.ipv4.addresses = [ @@ -82,7 +83,7 @@ in # Wait for network and miniupnpd. router.wait_for_unit("network-online.target") # $router.wait_for_unit("nat") - router.wait_for_unit("firewall.service") + router.wait_for_unit("${if useNftables then "nftables" else "firewall"}.service") router.wait_for_unit("miniupnpd") client1.wait_for_unit("network-online.target") diff --git a/nixos/tests/xrdp-with-audio-pulseaudio.nix b/nixos/tests/xrdp-with-audio-pulseaudio.nix new file mode 100644 index 0000000000000..27da7c457c493 --- /dev/null +++ b/nixos/tests/xrdp-with-audio-pulseaudio.nix @@ -0,0 +1,97 @@ +import ./make-test-python.nix ({ pkgs, ...} : { + # How to interactively test this module if the audio actually works + + # - nix run .#pulseaudio-module-xrdp.tests.xrdp-with-audio-pulseaudio.driverInteractive + # - test_script() # launches the terminal and the tests itself + # - server.send_monitor_command("hostfwd_add tcp::3389-:3389") # forward the RDP port to the host + # - Connect with the RDP client you like (ex: Remmina) + # - Don't forget to enable audio support. In remmina: Advanced -> Audio output mode to Local (default is Off) + # - Open a browser or something that plays sound. Ex: chromium + + name = "xrdp-with-audio-pulseaudio"; + meta = with pkgs.lib.maintainers; { + maintainers = [ lucasew ]; + }; + + nodes = { + server = { pkgs, ... }: { + imports = [ ./common/user-account.nix ]; + + environment.etc."xrdp/test.txt".text = "Shouldn't conflict"; + + services.xrdp.enable = true; + services.xrdp.audio.enable = true; + services.xrdp.defaultWindowManager = "${pkgs.xterm}/bin/xterm"; + + hardware.pulseaudio = { + enable = true; + }; + + systemd.user.services.pactl-list = { + script = '' + while [ ! -S /tmp/.xrdp/xrdp_chansrv_audio_in_socket_* ]; do + sleep 1 + done + sleep 1 + ${pkgs.pulseaudio}/bin/pactl list + echo Source: + ${pkgs.pulseaudio}/bin/pactl get-default-source | tee /tmp/pulseaudio-source + echo Sink: + ${pkgs.pulseaudio}/bin/pactl get-default-sink | tee /tmp/pulseaudio-sink + + ''; + wantedBy = [ "default.target" ]; + }; + + networking.firewall.allowedTCPPorts = [ 3389 ]; + }; + + client = { pkgs, ... }: { + imports = [ ./common/x11.nix ./common/user-account.nix ]; + test-support.displayManager.auto.user = "alice"; + + environment.systemPackages = [ pkgs.freerdp ]; + + services.xrdp.enable = true; + services.xrdp.audio.enable = true; + services.xrdp.defaultWindowManager = "${pkgs.icewm}/bin/icewm"; + + hardware.pulseaudio = { + enable = true; + }; + }; + }; + + testScript = { nodes, ... }: let + user = nodes.client.config.users.users.alice; + in '' + start_all() + + client.wait_for_x() + client.wait_for_file("${user.home}/.Xauthority") + client.succeed("xauth merge ${user.home}/.Xauthority") + + client.sleep(5) + + client.execute("xterm >&2 &") + client.sleep(1) + + client.send_chars("xfreerdp /cert-tofu /w:640 /h:480 /v:127.0.0.1 /u:${user.name} /p:${user.password} /sound\n") + + client.sleep(10) + + client.succeed("[ -S /tmp/.xrdp/xrdp_chansrv_audio_in_socket_* ]") # checks if it's a socket + client.sleep(5) + client.screenshot("localrdp") + + client.execute("xterm >&2 &") + client.sleep(1) + client.send_chars("xfreerdp /cert-tofu /w:640 /h:480 /v:server /u:${user.name} /p:${user.password} /sound\n") + client.sleep(10) + + server.succeed("[ -S /tmp/.xrdp/xrdp_chansrv_audio_in_socket_* ]") # checks if it's a socket + server.succeed('[ "$(cat /tmp/pulseaudio-source)" == "xrdp-source" ]') + server.succeed('[ "$(cat /tmp/pulseaudio-sink)" == "xrdp-sink" ]') + client.screenshot("remoterdp") + ''; +}) |