From ff939040bbaee5f6bc6fd78bfa741eb02635ec06 Mon Sep 17 00:00:00 2001 From: a-kenji Date: Mon, 5 May 2025 13:02:18 +0200 Subject: [PATCH] modules/wifi: migrate to clanServices --- clanServices/flake-module.nix | 1 + clanServices/wifi/default.nix | 110 ++++++++++++++++++ clanServices/wifi/flake-module.nix | 39 +++++++ clanServices/wifi/tests/eval-tests.nix | 58 +++++++++ clanServices/wifi/tests/vm/default.nix | 43 +++++++ .../wifi/tests/vm/sops/machines/test/key.json | 6 + .../tests/vm/sops/secrets/test-age.key/secret | 15 +++ .../vm/sops/secrets/test-age.key/users/admin | 1 + .../wifi/tests/vm/sops/users/admin/key.json | 4 + .../shared/iwd.one/password/machines/test | 1 + .../vm/vars/shared/iwd.one/password/secret | 19 +++ .../vars/shared/iwd.one/password/users/admin | 1 + .../vm/vars/shared/iwd.one/ssid/machines/test | 1 + .../tests/vm/vars/shared/iwd.one/ssid/secret | 19 +++ .../vm/vars/shared/iwd.one/ssid/users/admin | 1 + 15 files changed, 319 insertions(+) create mode 100644 clanServices/wifi/default.nix create mode 100644 clanServices/wifi/flake-module.nix create mode 100644 clanServices/wifi/tests/eval-tests.nix create mode 100644 clanServices/wifi/tests/vm/default.nix create mode 100755 clanServices/wifi/tests/vm/sops/machines/test/key.json create mode 100644 clanServices/wifi/tests/vm/sops/secrets/test-age.key/secret create mode 120000 clanServices/wifi/tests/vm/sops/secrets/test-age.key/users/admin create mode 100644 clanServices/wifi/tests/vm/sops/users/admin/key.json create mode 120000 clanServices/wifi/tests/vm/vars/shared/iwd.one/password/machines/test create mode 100644 clanServices/wifi/tests/vm/vars/shared/iwd.one/password/secret create mode 120000 clanServices/wifi/tests/vm/vars/shared/iwd.one/password/users/admin create mode 120000 clanServices/wifi/tests/vm/vars/shared/iwd.one/ssid/machines/test create mode 100644 clanServices/wifi/tests/vm/vars/shared/iwd.one/ssid/secret create mode 120000 clanServices/wifi/tests/vm/vars/shared/iwd.one/ssid/users/admin diff --git a/clanServices/flake-module.nix b/clanServices/flake-module.nix index 720739d03..bb9ea9dc4 100644 --- a/clanServices/flake-module.nix +++ b/clanServices/flake-module.nix @@ -2,6 +2,7 @@ { imports = [ ./hello-world/flake-module.nix + ./wifi/flake-module.nix ]; clan.modules = { diff --git a/clanServices/wifi/default.nix b/clanServices/wifi/default.nix new file mode 100644 index 000000000..03773bf56 --- /dev/null +++ b/clanServices/wifi/default.nix @@ -0,0 +1,110 @@ +{ packages }: +{ lib, ... }: +{ + _class = "clan.service"; + manifest.name = "wifi"; + + roles.default = { + interface = { + options.networks = lib.mkOption { + visible = false; + type = lib.types.attrsOf ( + lib.types.submodule ( + { ... }: + { + options = { + enable = lib.mkOption { + type = lib.types.bool; + default = true; + description = "Enable this wifi network"; + }; + autoConnect = lib.mkOption { + type = lib.types.bool; + default = true; + description = "Automatically try to join this wifi network"; + }; + }; + } + ) + ); + default = { }; + description = "Wifi networks to predefine"; + }; + + }; + perInstance = + { settings, ... }: + { + nixosModule = + { config, pkgs, ... }: + let + secret_path = + network_name: config.clan.core.vars.generators."iwd.${network_name}".files.password.path; + ssid_path = network_name: config.clan.core.vars.generators."iwd.${network_name}".files.ssid.path; + secret_generator = name: value: { + name = "iwd.${name}"; + value = { + prompts.ssid.type = "line"; + prompts.ssid.persist = true; + prompts.password.type = "hidden"; + prompts.password.persist = true; + share = true; + }; + }; + in + { + clan.core.vars.generators = lib.mapAttrs' secret_generator settings.networks; + + systemd.services.iwd.partOf = [ "nixos-activation.service" ]; + + /* + script that generates iwd config files inside /var/lib/iwd/clan and symlinks + them to /var/lib/iwd. + */ + systemd.services.iwd.serviceConfig.ExecStartPre = pkgs.writeShellScript "clan-iwd-setup" '' + set -e + + rm -rf /var/lib/iwd/clan + mkdir -p /var/lib/iwd/clan + + # remove all existing symlinks in /var/lib/iwd + ${pkgs.findutils}/bin/find /var/lib/iwd -type l -exec rm {} \; + + ${toString ( + lib.mapAttrsToList (name: network: '' + passwd=$(cat "${secret_path name}") + ssid=$(cat "${ssid_path name}") + echo " + [Settings] + autoConnect=${if network.autoConnect then "true" else "false"} + [Security] + Passphrase=$passwd + " > "/var/lib/iwd/clan/$ssid.psk" + '') settings.networks + )} + + # link all files in /var/lib/iwd/clan to /var/lib/iwd + ${pkgs.findutils}/bin/find /var/lib/iwd/clan -type f -exec ln -s {} /var/lib/iwd \; + ''; + # disable wpa supplicant + networking.wireless.enable = false; + + # Set the network manager backend to iwd + networking.networkmanager.wifi.backend = "iwd"; + + # Use iwd instead of wpa_supplicant. It has a user friendly CLI + networking.wireless.iwd = { + enable = true; + settings = { + Network = { + EnableIPv6 = true; + RoutePriorityOffset = 300; + }; + Settings.autoConnect = true; + }; + }; + }; + }; + }; + +} diff --git a/clanServices/wifi/flake-module.nix b/clanServices/wifi/flake-module.nix new file mode 100644 index 000000000..c5fb3f643 --- /dev/null +++ b/clanServices/wifi/flake-module.nix @@ -0,0 +1,39 @@ +{ + self, + inputs, + lib, + ... +}: +let + module = lib.modules.importApply ./default.nix { + inherit (self) packages; + }; +in +{ + clan.inventory.modules = { + wifi = module; + }; + clan.modules = { + wifi = module; + }; + perSystem = + { pkgs, ... }: + { + /** + 1. Prepare the test vars + nix run .#generate-test-vars -- clanServices/hello-world/tests/vm hello-service + + 2. To run the test + nix build .#checks.x86_64-linux.hello-service + */ + checks = + # Currently we don't support nixos-integration tests on darwin + lib.optionalAttrs (pkgs.stdenv.isLinux) { + wifi-service = import ./tests/vm/default.nix { + inherit module; + inherit self inputs pkgs; + clanLib = self.clanLib; + }; + }; + }; +} diff --git a/clanServices/wifi/tests/eval-tests.nix b/clanServices/wifi/tests/eval-tests.nix new file mode 100644 index 000000000..fa50c589f --- /dev/null +++ b/clanServices/wifi/tests/eval-tests.nix @@ -0,0 +1,58 @@ +{ + module, + clanLib, + ... +}: +let + testFlake = clanLib.buildClan { + # Point to the folder of the module + # TODO: make this optional in buildClan + directory = ./..; + + # Create some test machines + machines.jon = { + nixpkgs.hostPlatform = "x86_64-linux"; + }; + machines.sara = { + nixpkgs.hostPlatform = "x86_64-linux"; + }; + + # Register the module for the test + inventory.modules.wifi = module; + + # Use the module in the test + inventory.instances = { + "default" = { + module.name = "wifi"; + roles.default.tags.all = { }; + roles.default.settings.networks.one = { }; + roles.default.settings.networks.two = { }; + }; + }; + }; + # NOTE: + # If you wonder why 'self-zerotier-redux': + # A local module has prefix 'self', otherwise it is the name of the 'input' + # The rest is the name of the service as in the instance 'module.name'; + # + # -> ${module.input}-${module.name} + # In this case it is 'self-zerotier-redux' + # This is usually only used internally, but we can use it to test the evaluation of service module in isolation + # evaluatedService = + # testFlake.clanInternals.inventoryClass.distributedServices.importedModulesEvaluated.self-zerotier-redux.config; +in +{ + test_simple = { + inherit testFlake; + + expr = + testFlake.clanInternals.inventoryClass.distributedServices.importedModulesEvaluated.self-wifi.config; + expected = 1; + + # expr = { + # }; + # expected = { + # + # }; + }; +} diff --git a/clanServices/wifi/tests/vm/default.nix b/clanServices/wifi/tests/vm/default.nix new file mode 100644 index 000000000..a20339e66 --- /dev/null +++ b/clanServices/wifi/tests/vm/default.nix @@ -0,0 +1,43 @@ +{ + pkgs, + self, + clanLib, + module, + ... +}: +clanLib.test.makeTestClan { + inherit pkgs self; + useContainers = false; + nixosTest = ( + { ... }: + { + name = "wifi"; + + clan = { + directory = ./.; + inventory = { + modules."@clan/wifi" = module; + + machines.test = { }; + + instances = { + wg-test-one = { + module.name = "@clan/wifi"; + + roles.default.machines = { + test.settings.networks.one = { }; + }; + }; + }; + }; + }; + + testScript = '' + start_all() + test.wait_for_unit("iwd.service") + psk = test.succeed("cat /var/lib/iwd/ssid-one.psk") + assert "password-eins" in psk, "Password is incorrect" + ''; + } + ); +} diff --git a/clanServices/wifi/tests/vm/sops/machines/test/key.json b/clanServices/wifi/tests/vm/sops/machines/test/key.json new file mode 100755 index 000000000..9c54c8f3f --- /dev/null +++ b/clanServices/wifi/tests/vm/sops/machines/test/key.json @@ -0,0 +1,6 @@ +[ + { + "publickey": "age1aex07l3uafv5hdr0h2707jgfsxcu7yhlc7glw3qu26xzn3m9nazsu47jzs", + "type": "age" + } +] diff --git a/clanServices/wifi/tests/vm/sops/secrets/test-age.key/secret b/clanServices/wifi/tests/vm/sops/secrets/test-age.key/secret new file mode 100644 index 000000000..e3b47d868 --- /dev/null +++ b/clanServices/wifi/tests/vm/sops/secrets/test-age.key/secret @@ -0,0 +1,15 @@ +{ + "data": "ENC[AES256_GCM,data:l5kJU4j1D/4TcPT0Ea0c1X3FWRbHCLCnWy22xeEWseBKnd5R8cEPAYflw+xqGNKpDpQOb0K5XCfA5+CFFXyl0oXEnmnIDDCmtqk=,iv:6cF445KqSJiaTfQ+eNqKH4dAFiIaqdSqt1alF80GpFU=,tag:4Fz+MtxiLmV31Nn6NUVAzg==,type:str]", + "sops": { + "age": [ + { + "recipient": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg", + "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBsOVlvZVdoWDBpNEdRb0U1\nRVRpS0xhaElYVUg1OUJWUlF5a3A1ZWUxeGxJClVjNDNsM2xXWDhsMktYOU1pdUZD\nY3VFeVowbDFmR2dFY2NUc3pEOGFUUU0KLS0tIE9pT0xZMFdwRU5VekNNWmpKQWNh\naTk2eGhGL3QvSlBLOUpJdFJaMnUzVkkKQT3KVYLG3HD9cbLzG46wI5ipxzjLfM8W\nwHezTfnVL9UUztHapdqu2uM2cZjjdGcsacvOCacfxLWzE+7Uk0RMGQ==\n-----END AGE ENCRYPTED FILE-----\n" + } + ], + "lastmodified": "2025-05-05T10:34:16Z", + "mac": "ENC[AES256_GCM,data:VfRQvyeeEAhQzTcG//spQm4VDYKY/aldO46CWx6QhW945H/2PP1OyNehT2PjjHArVy6HzZeLMb1E2tQHEemPvi4F4jjAqeA+SgnwNKEClYcIF021eaPZDeWbxo8MxQcy0QbRH6Aimihyr4GjAb+cYBm43DAgWCG9q9kHKCk7dts=,iv:eyWHtaGAB+/2Vwkq4tYKei60LGSatRM4FSOI0YUddyY=,tag:ElOBNQ5Hf1sTefzYYN3JoA==,type:str]", + "unencrypted_suffix": "_unencrypted", + "version": "3.10.2" + } +} diff --git a/clanServices/wifi/tests/vm/sops/secrets/test-age.key/users/admin b/clanServices/wifi/tests/vm/sops/secrets/test-age.key/users/admin new file mode 120000 index 000000000..9e21a9938 --- /dev/null +++ b/clanServices/wifi/tests/vm/sops/secrets/test-age.key/users/admin @@ -0,0 +1 @@ +../../../users/admin \ No newline at end of file diff --git a/clanServices/wifi/tests/vm/sops/users/admin/key.json b/clanServices/wifi/tests/vm/sops/users/admin/key.json new file mode 100644 index 000000000..e408aa96b --- /dev/null +++ b/clanServices/wifi/tests/vm/sops/users/admin/key.json @@ -0,0 +1,4 @@ +{ + "publickey": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg", + "type": "age" +} diff --git a/clanServices/wifi/tests/vm/vars/shared/iwd.one/password/machines/test b/clanServices/wifi/tests/vm/vars/shared/iwd.one/password/machines/test new file mode 120000 index 000000000..8adbdc900 --- /dev/null +++ b/clanServices/wifi/tests/vm/vars/shared/iwd.one/password/machines/test @@ -0,0 +1 @@ +../../../../../sops/machines/test \ No newline at end of file diff --git a/clanServices/wifi/tests/vm/vars/shared/iwd.one/password/secret b/clanServices/wifi/tests/vm/vars/shared/iwd.one/password/secret new file mode 100644 index 000000000..dfe07be21 --- /dev/null +++ b/clanServices/wifi/tests/vm/vars/shared/iwd.one/password/secret @@ -0,0 +1,19 @@ +{ + "data": "ENC[AES256_GCM,data:C0x458T590iWSMBl6w==,iv:K0WawWV9fJbyFg9cD3H0htMAvxSqxVp2spdzNcVUSuI=,tag:Hb1+WGgM12UItrqjx04UdA==,type:str]", + "sops": { + "age": [ + { + "recipient": "age1aex07l3uafv5hdr0h2707jgfsxcu7yhlc7glw3qu26xzn3m9nazsu47jzs", + "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAxOEdHODRlRDFxRVMxSTNG\nazhkaXA3cGhBdUtqNExkZFFrcHlLOFQ1dFZNCndkc0tzZ29sYlB6KzBBZXpWN1hT\nRUl6c0dUY3NXNUVSd1Ixdk5UdkY5cE0KLS0tIDZCeldabUtieUtjUDJsV1BvMEhV\nNmQwcW5pZmx2cjFWWlRJMmY5b1JjQmsKqlFegGpY3zqHXa/qlSKEIQQ4nY/NPwL+\n3NzE2Voon6YLhrYNJAv8YndM5GMiIWQQim3suqdcq5KIRQshhO1x8g==\n-----END AGE ENCRYPTED FILE-----\n" + }, + { + "recipient": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg", + "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB0NUFKdGIrM2NOWUx6M0Fl\naUp0K3Y5cEVON1haMkpiQ0kydXVvcWQ1WVVJCnl4bTN5Nk5kdjJ6ejB0NkE2aFJJ\nZlJjQzk4MjB1TmlNT0d6VmVScWVCcHMKLS0tIE1mWi9LMkNwc0pGZ3grTWdCTENC\nb1ZOYk41YStYYWJad2hHN2t5ODNQcjgKKP82jzHVDp53eRXg7yX6JgrWtJwcGbWj\nKCacNw6rRpdLOJDRea2uW3kHEVJz1L+T7EALRK9o59DxJfiQvjC/yw==\n-----END AGE ENCRYPTED FILE-----\n" + } + ], + "lastmodified": "2025-05-05T10:35:08Z", + "mac": "ENC[AES256_GCM,data:XseZIImMQW4D9YhLmDbMkQiJqX+hQNEMAo8kTUgFE0AQy+72A6IT6kI5C7NnlvRAQmhc2KxtbooFLlYW2OR3cb7M0xCEZPYv76l/j6HXhYpBxuWbJsSz0htkm09OYFfYIpg4AEHXOt3TBJyzK9BWD5RX0Jwgp5x8ZxYxZKP1Zks=,iv:/5ZQ+Bp3mzcfe/OsHn4nToC412fNpiatvrdB/JBhIhM=,tag:I4duVl5DcTGABhBg2nTLnQ==,type:str]", + "unencrypted_suffix": "_unencrypted", + "version": "3.10.2" + } +} diff --git a/clanServices/wifi/tests/vm/vars/shared/iwd.one/password/users/admin b/clanServices/wifi/tests/vm/vars/shared/iwd.one/password/users/admin new file mode 120000 index 000000000..f14859ae0 --- /dev/null +++ b/clanServices/wifi/tests/vm/vars/shared/iwd.one/password/users/admin @@ -0,0 +1 @@ +../../../../../sops/users/admin \ No newline at end of file diff --git a/clanServices/wifi/tests/vm/vars/shared/iwd.one/ssid/machines/test b/clanServices/wifi/tests/vm/vars/shared/iwd.one/ssid/machines/test new file mode 120000 index 000000000..8adbdc900 --- /dev/null +++ b/clanServices/wifi/tests/vm/vars/shared/iwd.one/ssid/machines/test @@ -0,0 +1 @@ +../../../../../sops/machines/test \ No newline at end of file diff --git a/clanServices/wifi/tests/vm/vars/shared/iwd.one/ssid/secret b/clanServices/wifi/tests/vm/vars/shared/iwd.one/ssid/secret new file mode 100644 index 000000000..950fd61f3 --- /dev/null +++ b/clanServices/wifi/tests/vm/vars/shared/iwd.one/ssid/secret @@ -0,0 +1,19 @@ +{ + "data": "ENC[AES256_GCM,data:YisL0uMSKSU=,iv:TWLcznbWfuIPrtYzIqhE+iqa+6jSLatSV51nxapwPow=,tag:fThlc6jY12C/cOFGXbStlg==,type:str]", + "sops": { + "age": [ + { + "recipient": "age1aex07l3uafv5hdr0h2707jgfsxcu7yhlc7glw3qu26xzn3m9nazsu47jzs", + "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBudldzU1YrczMxK2RmZHlG\nTTdDZkVCbGhWek43TmRUTTc2NzA1VFN6VmhJCnpEencxSnZVOG83QVY2R1pRek0v\naHNuMzBCWVNGTGNrME8xd0hGaEx1SmcKLS0tIHRRN1BJZE5SZWFXYTlNSEVvekxI\nYlRoWHJ1UFBoSWxJQmd5ZWVIQVNjT0EKhO1ax3q+cIF2YyXJCGg00Zwl4A+ae9gF\n0Ta3aZy6QnHrzOcMGA2HYiefoVvPDlU5zkxjwvxtOZt6TmulumpzBw==\n-----END AGE ENCRYPTED FILE-----\n" + }, + { + "recipient": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg", + "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBJYUV3VXByVWFRaVNWQ0pt\ncG81RWFVbFh5SWFKS09xZlV0UGNaZWtDd1U4CmNYaUk3djRhYlBrSnllekk5RGtz\nUU95N1loS0dwbkRvaCt4NW55Rk12V1UKLS0tIDl6QjIxRC9BNmJBYi9BdGhybFcy\nTzVLdG9WcnkwbDZoaWJUTzM1b1dmbmsKzdOOKpZAAJwFc525IZ69RbmAMk79Pt6W\nzGs4qf0xBocYzF0G3kmt8ki8Nvvh5IWvpkIb+NTaQZAPhKNcSmBlzA==\n-----END AGE ENCRYPTED FILE-----\n" + } + ], + "lastmodified": "2025-05-05T10:35:08Z", + "mac": "ENC[AES256_GCM,data:rv26UZhuyEouasJF1mY71df+7izOCw7dCqG/KjuUogtzt102NAawu4q7jF7j3Xi09cZKTmGllZD6L+R/8cpQ4l6R1JlBI6nbjKPFc4UNMNizW5U4KKHq0ApG9CVWiCDOdlH4Fiqa6vkZQw2dHyTAg5eHYiHtg7wuoiWlF4XnkP8=,iv:/yq+JlMCc1EQkj05Y1D6V4f64Whh+US9YEKOSb08xmI=,tag:jMYqXiDChLYnv3P1+bi3Bw==,type:str]", + "unencrypted_suffix": "_unencrypted", + "version": "3.10.2" + } +} diff --git a/clanServices/wifi/tests/vm/vars/shared/iwd.one/ssid/users/admin b/clanServices/wifi/tests/vm/vars/shared/iwd.one/ssid/users/admin new file mode 120000 index 000000000..f14859ae0 --- /dev/null +++ b/clanServices/wifi/tests/vm/vars/shared/iwd.one/ssid/users/admin @@ -0,0 +1 @@ +../../../../../sops/users/admin \ No newline at end of file