diff options
Diffstat (limited to 'nixos')
-rw-r--r-- | nixos/doc/manual/release-notes/rl-2405.section.md | 2 | ||||
-rw-r--r-- | nixos/modules/config/no-x-libs.nix | 3 | ||||
-rw-r--r-- | nixos/modules/services/networking/adguardhome.nix | 122 | ||||
-rw-r--r-- | nixos/modules/system/boot/loader/systemd-boot/systemd-boot.nix | 4 | ||||
-rw-r--r-- | nixos/tests/adguardhome.nix | 85 | ||||
-rw-r--r-- | nixos/tests/all-tests.nix | 1 | ||||
-rw-r--r-- | nixos/tests/swayfx.nix | 207 |
7 files changed, 327 insertions, 97 deletions
diff --git a/nixos/doc/manual/release-notes/rl-2405.section.md b/nixos/doc/manual/release-notes/rl-2405.section.md index 68577cb9d7c9b..85243cb068356 100644 --- a/nixos/doc/manual/release-notes/rl-2405.section.md +++ b/nixos/doc/manual/release-notes/rl-2405.section.md @@ -341,7 +341,7 @@ The pre-existing [services.ankisyncd](#opt-services.ankisyncd.enable) has been m - `optparse-bash` is now dropped due to upstream inactivity. Alternatives available in Nixpkgs include [`argc`](https://github.com/sigoden/argc), [`argbash`](https://github.com/matejak/argbash), [`bashly`](https://github.com/DannyBen/bashly) and [`gum`](https://github.com/charmbracelet/gum), to name a few. -- `kanata` package has been updated to v1.5.0, which includes [breaking changes](https://github.com/jtroo/kanata/releases/tag/v1.5.0). +- `kanata` package has been updated to v1.6.0, which includes breaking changes. Check out the changelog of [v1.5.0](https://github.com/jtroo/kanata/releases/tag/v1.5.0) and [v1.6.0](https://github.com/jtroo/kanata/releases/tag/v1.6.0) for details. - `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. diff --git a/nixos/modules/config/no-x-libs.nix b/nixos/modules/config/no-x-libs.nix index c9a133d0558a5..b811823d698a1 100644 --- a/nixos/modules/config/no-x-libs.nix +++ b/nixos/modules/config/no-x-libs.nix @@ -31,8 +31,11 @@ with lib; cairo = super.cairo.override { x11Support = false; }; dbus = super.dbus.override { x11Support = false; }; fastfetch = super.fastfetch.override { vulkanSupport = false; waylandSupport = false; x11Support = false; }; + ffmpeg = super.ffmpeg.override { ffmpegVariant = "headless"; }; ffmpeg_4 = super.ffmpeg_4.override { ffmpegVariant = "headless"; }; ffmpeg_5 = super.ffmpeg_5.override { ffmpegVariant = "headless"; }; + ffmpeg_6 = super.ffmpeg_6.override { ffmpegVariant = "headless"; }; + ffmpeg_7 = super.ffmpeg_7.override { ffmpegVariant = "headless"; }; # dep of graphviz, libXpm is optional for Xpm support gd = super.gd.override { withXorg = false; }; ghostscript = super.ghostscript.override { cupsSupport = false; x11Support = false; }; diff --git a/nixos/modules/services/networking/adguardhome.nix b/nixos/modules/services/networking/adguardhome.nix index 6958bcccf54cf..df9927351edc3 100644 --- a/nixos/modules/services/networking/adguardhome.nix +++ b/nixos/modules/services/networking/adguardhome.nix @@ -4,6 +4,7 @@ with lib; let cfg = config.services.adguardhome; + settingsFormat = pkgs.formats.yaml { }; args = concatStringsSep " " ([ "--no-check-update" @@ -12,27 +13,33 @@ let "--config /var/lib/AdGuardHome/AdGuardHome.yaml" ] ++ cfg.extraArgs); - configFile = pkgs.writeTextFile { - name = "AdGuardHome.yaml"; - text = builtins.toJSON cfg.settings; - checkPhase = "${pkgs.adguardhome}/bin/adguardhome -c $out --check-config"; - }; - defaultBindPort = 3000; - -in -{ - - imports = - let cfgPath = [ "services" "adguardhome" ]; - in - [ - (mkRenamedOptionModuleWith { sinceRelease = 2211; from = cfgPath ++ [ "host" ]; to = cfgPath ++ [ "settings" "bind_host" ]; }) - (mkRenamedOptionModuleWith { sinceRelease = 2211; from = cfgPath ++ [ "port" ]; to = cfgPath ++ [ "settings" "bind_port" ]; }) - ]; - + settings = if (cfg.settings != null) then + cfg.settings // (if cfg.settings.schema_version < 23 then { + bind_host = cfg.host; + bind_port = cfg.port; + } else { + http.address = "${cfg.host}:${toString cfg.port}"; + }) + else + null; + + configFile = + (settingsFormat.generate "AdGuardHome.yaml" settings).overrideAttrs (_: { + checkPhase = "${cfg.package}/bin/adguardhome -c $out --check-config"; + }); +in { options.services.adguardhome = with types; { enable = mkEnableOption "AdGuard Home network-wide ad blocker"; + package = mkOption { + type = package; + default = pkgs.adguardhome; + defaultText = literalExpression "pkgs.adguardhome"; + description = '' + The package that runs adguardhome. + ''; + }; + openFirewall = mkOption { default = false; type = bool; @@ -43,8 +50,8 @@ in }; allowDHCP = mkOption { - default = cfg.settings.dhcp.enabled or false; - defaultText = literalExpression ''config.services.adguardhome.settings.dhcp.enabled or false''; + default = settings.dhcp.enabled or false; + defaultText = literalExpression "config.services.adguardhome.settings.dhcp.enabled or false"; type = bool; description = '' Allows AdGuard Home to open raw sockets (`CAP_NET_RAW`), which is @@ -65,32 +72,34 @@ in ''; }; + host = mkOption { + default = "0.0.0.0"; + type = str; + description = '' + Host address to bind HTTP server to. + ''; + }; + + port = mkOption { + default = 3000; + type = port; + description = '' + Port to serve HTTP pages on. + ''; + }; + settings = mkOption { default = null; type = nullOr (submodule { - freeformType = (pkgs.formats.yaml { }).type; + freeformType = settingsFormat.type; options = { schema_version = mkOption { - default = pkgs.adguardhome.schema_version; - defaultText = literalExpression "pkgs.adguardhome.schema_version"; + default = cfg.package.schema_version; + defaultText = literalExpression "cfg.package.schema_version"; type = int; description = '' Schema version for the configuration. - Defaults to the `schema_version` supplied by `pkgs.adguardhome`. - ''; - }; - bind_host = mkOption { - default = "0.0.0.0"; - type = str; - description = '' - Host address to bind HTTP server to. - ''; - }; - bind_port = mkOption { - default = defaultBindPort; - type = port; - description = '' - Port to serve HTTP pages on. + Defaults to the `schema_version` supplied by `cfg.package`. ''; }; }; @@ -107,7 +116,7 @@ in Set this to `null` (default) for a non-declarative configuration without any Nix-supplied values. - Declarative configurations are supplied with a default `schema_version`, `bind_host`, and `bind_port`. + Declarative configurations are supplied with a default `schema_version`, and `http.address`. ::: ''; }; @@ -124,17 +133,25 @@ in config = mkIf cfg.enable { assertions = [ { - assertion = cfg.settings != null -> cfg.mutableSettings - || (hasAttrByPath [ "dns" "bind_host" ] cfg.settings) - || (hasAttrByPath [ "dns" "bind_hosts" ] cfg.settings); - message = - "AdGuard setting dns.bind_host or dns.bind_hosts needs to be configured for a minimal working configuration"; + assertion = cfg.settings != null + -> !(hasAttrByPath [ "bind_host" ] cfg.settings); + message = "AdGuard option `settings.bind_host' has been superseded by `services.adguardhome.host'"; + } + { + assertion = cfg.settings != null + -> !(hasAttrByPath [ "bind_port" ] cfg.settings); + message = "AdGuard option `settings.bind_host' has been superseded by `services.adguardhome.port'"; + } + { + assertion = settings != null -> cfg.mutableSettings + || hasAttrByPath [ "dns" "bootstrap_dns" ] settings; + message = "AdGuard setting dns.bootstrap_dns needs to be configured for a minimal working configuration"; } { - assertion = cfg.settings != null -> cfg.mutableSettings - || hasAttrByPath [ "dns" "bootstrap_dns" ] cfg.settings; - message = - "AdGuard setting dns.bootstrap_dns needs to be configured for a minimal working configuration"; + assertion = settings != null -> cfg.mutableSettings + || hasAttrByPath [ "dns" "bootstrap_dns" ] settings + && isList settings.dns.bootstrap_dns; + message = "AdGuard setting dns.bootstrap_dns needs to be a list"; } ]; @@ -147,7 +164,7 @@ in StartLimitBurst = 10; }; - preStart = optionalString (cfg.settings != null) '' + preStart = optionalString (settings != null) '' if [ -e "$STATE_DIRECTORY/AdGuardHome.yaml" ] \ && [ "${toString cfg.mutableSettings}" = "1" ]; then # Writing directly to AdGuardHome.yaml results in empty file @@ -161,8 +178,9 @@ in serviceConfig = { DynamicUser = true; - ExecStart = "${pkgs.adguardhome}/bin/adguardhome ${args}"; - AmbientCapabilities = [ "CAP_NET_BIND_SERVICE" ] ++ optionals cfg.allowDHCP [ "CAP_NET_RAW" ]; + ExecStart = "${cfg.package}/bin/adguardhome ${args}"; + AmbientCapabilities = [ "CAP_NET_BIND_SERVICE" ] + ++ optionals cfg.allowDHCP [ "CAP_NET_RAW" ]; Restart = "always"; RestartSec = 10; RuntimeDirectory = "AdGuardHome"; @@ -170,6 +188,6 @@ in }; }; - networking.firewall.allowedTCPPorts = mkIf cfg.openFirewall [ cfg.settings.bind_port or defaultBindPort ]; + networking.firewall.allowedTCPPorts = mkIf cfg.openFirewall [ cfg.port ]; }; } diff --git a/nixos/modules/system/boot/loader/systemd-boot/systemd-boot.nix b/nixos/modules/system/boot/loader/systemd-boot/systemd-boot.nix index 02540c362d318..cee8663f0040e 100644 --- a/nixos/modules/system/boot/loader/systemd-boot/systemd-boot.nix +++ b/nixos/modules/system/boot/loader/systemd-boot/systemd-boot.nix @@ -10,7 +10,9 @@ let # We check the source code in a derivation that does not depend on the # system configuration so that most users don't have to redo the check and require # the necessary dependencies. - checkedSource = pkgs.runCommand "systemd-boot" { } '' + checkedSource = pkgs.runCommand "systemd-boot" { + preferLocalBuild = true; + } '' install -m755 -D ${./systemd-boot-builder.py} $out ${lib.getExe pkgs.buildPackages.mypy} \ --no-implicit-optional \ diff --git a/nixos/tests/adguardhome.nix b/nixos/tests/adguardhome.nix index 80613ce825340..005d54e17dfdc 100644 --- a/nixos/tests/adguardhome.nix +++ b/nixos/tests/adguardhome.nix @@ -2,41 +2,39 @@ name = "adguardhome"; nodes = { - nullConf = { ... }: { services.adguardhome = { enable = true; }; }; + nullConf = { services.adguardhome.enable = true; }; - emptyConf = { lib, ... }: { + emptyConf = { services.adguardhome = { enable = true; + + settings = { }; + }; + }; + + schemaVersionBefore23 = { + services.adguardhome = { + enable = true; + + settings.schema_version = 20; }; }; - declarativeConf = { ... }: { + declarativeConf = { services.adguardhome = { enable = true; mutableSettings = false; - settings = { - schema_version = 0; - dns = { - bind_host = "0.0.0.0"; - bootstrap_dns = "127.0.0.1"; - }; - }; + settings.dns.bootstrap_dns = [ "127.0.0.1" ]; }; }; - mixedConf = { ... }: { + mixedConf = { services.adguardhome = { enable = true; mutableSettings = true; - settings = { - schema_version = 0; - dns = { - bind_host = "0.0.0.0"; - bootstrap_dns = "127.0.0.1"; - }; - }; + settings.dns.bootstrap_dns = [ "127.0.0.1" ]; }; }; @@ -70,11 +68,7 @@ allowDHCP = true; mutableSettings = false; settings = { - schema_version = 0; - dns = { - bind_host = "0.0.0.0"; - bootstrap_dns = "127.0.0.1"; - }; + dns.bootstrap_dns = [ "127.0.0.1" ]; dhcp = { # This implicitly enables CAP_NET_RAW enabled = true; @@ -104,33 +98,38 @@ testScript = '' with subtest("Minimal (settings = null) config test"): - nullConf.wait_for_unit("adguardhome.service") + nullConf.wait_for_unit("adguardhome.service") + nullConf.wait_for_open_port(3000) with subtest("Default config test"): - emptyConf.wait_for_unit("adguardhome.service") - emptyConf.wait_for_open_port(3000) + emptyConf.wait_for_unit("adguardhome.service") + emptyConf.wait_for_open_port(3000) + + with subtest("Default schema_version 23 config test"): + schemaVersionBefore23.wait_for_unit("adguardhome.service") + schemaVersionBefore23.wait_for_open_port(3000) with subtest("Declarative config test, DNS will be reachable"): - declarativeConf.wait_for_unit("adguardhome.service") - declarativeConf.wait_for_open_port(53) - declarativeConf.wait_for_open_port(3000) + declarativeConf.wait_for_unit("adguardhome.service") + declarativeConf.wait_for_open_port(53) + declarativeConf.wait_for_open_port(3000) with subtest("Mixed config test, check whether merging works"): - mixedConf.wait_for_unit("adguardhome.service") - mixedConf.wait_for_open_port(53) - mixedConf.wait_for_open_port(3000) - # Test whether merging works properly, even if nothing is changed - mixedConf.systemctl("restart adguardhome.service") - mixedConf.wait_for_unit("adguardhome.service") - mixedConf.wait_for_open_port(3000) + mixedConf.wait_for_unit("adguardhome.service") + mixedConf.wait_for_open_port(53) + mixedConf.wait_for_open_port(3000) + # Test whether merging works properly, even if nothing is changed + mixedConf.systemctl("restart adguardhome.service") + mixedConf.wait_for_unit("adguardhome.service") + mixedConf.wait_for_open_port(3000) with subtest("Testing successful DHCP start"): - dhcpConf.wait_for_unit("adguardhome.service") - client.systemctl("start network-online.target") - client.wait_for_unit("network-online.target") - # Test IP assignment via DHCP - dhcpConf.wait_until_succeeds("ping -c 5 10.0.10.100") - # Test hostname resolution over DHCP-provided DNS - dhcpConf.wait_until_succeeds("ping -c 5 client.lan") + dhcpConf.wait_for_unit("adguardhome.service") + client.systemctl("start network-online.target") + client.wait_for_unit("network-online.target") + # Test IP assignment via DHCP + dhcpConf.wait_until_succeeds("ping -c 5 10.0.10.100") + # Test hostname resolution over DHCP-provided DNS + dhcpConf.wait_until_succeeds("ping -c 5 client.lan") ''; } diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix index 2c9d1aa568bf2..6ef1d8d537980 100644 --- a/nixos/tests/all-tests.nix +++ b/nixos/tests/all-tests.nix @@ -867,6 +867,7 @@ in { swap-partition = handleTest ./swap-partition.nix {}; swap-random-encryption = handleTest ./swap-random-encryption.nix {}; sway = handleTest ./sway.nix {}; + swayfx = handleTest ./swayfx.nix {}; switchTest = handleTest ./switch-test.nix {}; sympa = handleTest ./sympa.nix {}; syncthing = handleTest ./syncthing.nix {}; diff --git a/nixos/tests/swayfx.nix b/nixos/tests/swayfx.nix new file mode 100644 index 0000000000000..77844ec80ae1d --- /dev/null +++ b/nixos/tests/swayfx.nix @@ -0,0 +1,207 @@ +import ./make-test-python.nix ( + { pkgs, lib, ... }: + { + name = "swayfx"; + meta = { + maintainers = with lib.maintainers; [ eclairevoyant ]; + }; + + # testScriptWithTypes:49: error: Cannot call function of unknown type + # (machine.succeed if succeed else machine.execute)( + # ^ + # Found 1 error in 1 file (checked 1 source file) + skipTypeCheck = true; + + nodes.machine = + { config, ... }: + { + # Automatically login on tty1 as a normal user: + imports = [ ./common/user-account.nix ]; + services.getty.autologinUser = "alice"; + + environment = { + # For glinfo and wayland-info: + systemPackages = with pkgs; [ + mesa-demos + wayland-utils + alacritty + ]; + # Use a fixed SWAYSOCK path (for swaymsg): + variables = { + "SWAYSOCK" = "/tmp/sway-ipc.sock"; + # TODO: Investigate if we can get hardware acceleration to work (via + # virtio-gpu and Virgil). We currently have to use the Pixman software + # renderer since the GLES2 renderer doesn't work inside the VM (even + # with WLR_RENDERER_ALLOW_SOFTWARE): + # "WLR_RENDERER_ALLOW_SOFTWARE" = "1"; + "WLR_RENDERER" = "pixman"; + }; + # For convenience: + shellAliases = { + test-x11 = "glinfo | tee /tmp/test-x11.out && touch /tmp/test-x11-exit-ok"; + test-wayland = "wayland-info | tee /tmp/test-wayland.out && touch /tmp/test-wayland-exit-ok"; + }; + + # To help with OCR: + etc."xdg/foot/foot.ini".text = lib.generators.toINI { } { + main = { + font = "inconsolata:size=14"; + }; + colors = rec { + foreground = "000000"; + background = "ffffff"; + regular2 = foreground; + }; + }; + + etc."gpg-agent.conf".text = '' + pinentry-timeout 86400 + ''; + }; + + fonts.packages = [ pkgs.inconsolata ]; + + # Automatically configure and start Sway when logging in on tty1: + programs.bash.loginShellInit = '' + if [ "$(tty)" = "/dev/tty1" ]; then + set -e + + mkdir -p ~/.config/sway + sed s/Mod4/Mod1/ /etc/sway/config > ~/.config/sway/config + + sway --validate + sway && touch /tmp/sway-exit-ok + fi + ''; + + programs.sway = { + enable = true; + package = pkgs.swayfx.override { isNixOS = true; }; + }; + + # To test pinentry via gpg-agent: + programs.gnupg.agent.enable = true; + + # Need to switch to a different GPU driver than the default one (-vga std) so that Sway can launch: + virtualisation.qemu.options = [ "-vga none -device virtio-gpu-pci" ]; + }; + + testScript = + { nodes, ... }: + '' + import shlex + import json + + q = shlex.quote + NODE_GROUPS = ["nodes", "floating_nodes"] + + + def swaymsg(command: str = "", succeed=True, type="command"): + assert command != "" or type != "command", "Must specify command or type" + shell = q(f"swaymsg -t {q(type)} -- {q(command)}") + with machine.nested( + f"sending swaymsg {shell!r}" + " (allowed to fail)" * (not succeed) + ): + ret = (machine.succeed if succeed else machine.execute)( + f"su - alice -c {shell}" + ) + + # execute also returns a status code, but disregard. + if not succeed: + _, ret = ret + + if not succeed and not ret: + return None + + parsed = json.loads(ret) + return parsed + + + def walk(tree): + yield tree + for group in NODE_GROUPS: + for node in tree.get(group, []): + yield from walk(node) + + + def wait_for_window(pattern): + def func(last_chance): + nodes = (node["name"] for node in walk(swaymsg(type="get_tree"))) + + if last_chance: + nodes = list(nodes) + machine.log(f"Last call! Current list of windows: {nodes}") + + return any(pattern in name for name in nodes) + + retry(func) + + start_all() + machine.wait_for_unit("multi-user.target") + + # To check the version: + print(machine.succeed("sway --version")) + + # Wait for Sway to complete startup: + machine.wait_for_file("/run/user/1000/wayland-1") + machine.wait_for_file("/tmp/sway-ipc.sock") + + # Test XWayland (foot does not support X): + swaymsg("exec WINIT_UNIX_BACKEND=x11 WAYLAND_DISPLAY= alacritty") + wait_for_window("alice@machine") + machine.send_chars("test-x11\n") + machine.wait_for_file("/tmp/test-x11-exit-ok") + print(machine.succeed("cat /tmp/test-x11.out")) + machine.copy_from_vm("/tmp/test-x11.out") + machine.screenshot("alacritty_glinfo") + machine.succeed("pkill alacritty") + + # Start a terminal (foot) on workspace 3: + machine.send_key("alt-3") + machine.sleep(3) + machine.send_key("alt-ret") + wait_for_window("alice@machine") + machine.send_chars("test-wayland\n") + machine.wait_for_file("/tmp/test-wayland-exit-ok") + print(machine.succeed("cat /tmp/test-wayland.out")) + machine.copy_from_vm("/tmp/test-wayland.out") + machine.screenshot("foot_wayland_info") + machine.send_key("alt-shift-q") + machine.wait_until_fails("pgrep foot") + + # Test gpg-agent starting pinentry-gnome3 via D-Bus (tests if + # $WAYLAND_DISPLAY is correctly imported into the D-Bus user env): + swaymsg("exec mkdir -p ~/.gnupg") + swaymsg("exec cp /etc/gpg-agent.conf ~/.gnupg") + + swaymsg("exec DISPLAY=INVALID gpg --no-tty --yes --quick-generate-key test", succeed=False) + machine.wait_until_succeeds("pgrep --exact gpg") + wait_for_window("gpg") + machine.succeed("pgrep --exact gpg") + machine.screenshot("gpg_pinentry") + machine.send_key("alt-shift-q") + machine.wait_until_fails("pgrep --exact gpg") + + # Test swaynag: + def get_height(): + return [node['rect']['height'] for node in walk(swaymsg(type="get_tree")) if node['focused']][0] + + before = get_height() + machine.send_key("alt-shift-e") + retry(lambda _: get_height() < before) + machine.screenshot("sway_exit") + + swaymsg("exec swaylock") + machine.wait_until_succeeds("pgrep -x swaylock") + machine.sleep(3) + machine.send_chars("${nodes.machine.config.users.users.alice.password}") + machine.send_key("ret") + machine.wait_until_fails("pgrep -x swaylock") + + # Exit Sway and verify process exit status 0: + swaymsg("exit", succeed=False) + machine.wait_until_fails("pgrep -x sway") + machine.wait_for_file("/tmp/sway-exit-ok") + ''; + } +) |