From a3d4baad773e4a6d6da77e5d085e6459f3ef5379 Mon Sep 17 00:00:00 2001 From: "Burfeind, Jan-Niklas" Date: Fri, 20 Feb 2026 14:43:08 +0100 Subject: [PATCH 1/3] labgrid.coordinator.service: Provide the service based on the example in contrib/ in the project repo. Provide three new options: - enable (default: False) - debug (default: False) - bindAddress (default: 0.0.0.0) - package (default: python313Packages.labgrid) - port (default: 22408) Co-authored-by: Rouven Czerwinski --- nixos/modules/module-list.nix | 1 + .../development/labgrid/coordinator.nix | 96 +++++++++++++++++++ 2 files changed, 97 insertions(+) create mode 100644 nixos/modules/services/development/labgrid/coordinator.nix diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index 8ea3e232594a..ff6978d5b751 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -604,6 +604,7 @@ ./services/development/hoogle.nix ./services/development/jupyter/default.nix ./services/development/jupyterhub/default.nix + ./services/development/labgrid/coordinator.nix ./services/development/livebook.nix ./services/development/lorri.nix ./services/development/nixseparatedebuginfod2.nix diff --git a/nixos/modules/services/development/labgrid/coordinator.nix b/nixos/modules/services/development/labgrid/coordinator.nix new file mode 100644 index 000000000000..472d631b7bed --- /dev/null +++ b/nixos/modules/services/development/labgrid/coordinator.nix @@ -0,0 +1,96 @@ +{ + config, + pkgs, + lib, + ... +}: + +let + cfg = config.services.labgrid.coordinator; +in +{ + meta = { + maintainers = with lib.maintainers; [ + aiyion + emantor + ]; + }; + + options = { + services.labgrid.coordinator = { + bindAddress = lib.mkOption { + default = "0.0.0.0"; + type = lib.types.str; + description = "Bind address for the labgrid coordinator."; + }; + + debug = lib.mkOption { + default = false; + type = with lib.types; bool; + description = '' + Whether to enable debug mode. + ''; + }; + + enable = lib.mkEnableOption "Labgrid Coordinator"; + + openFirewall = lib.mkOption { + default = false; + type = with lib.types; bool; + description = '' + Whether to automatically open the coordinator listen port in the firewall. + ''; + }; + + package = lib.mkPackageOption pkgs [ "python3Packages" "labgrid" ] { }; + + port = lib.mkOption { + default = 20408; + type = lib.types.port; + description = "Coordinator port to bind to."; + }; + }; + }; + + config = lib.mkIf cfg.enable { + networking.firewall.allowedTCPPorts = lib.mkIf cfg.openFirewall [ cfg.port ]; + + systemd.services.labgrid-coordinator = { + after = [ "network-online.target" ]; + description = "Labgrid Coordinator"; + serviceConfig = { + Environment = ''"PYTHONUNBUFFERED=1"''; + ExecStart = "${lib.getBin cfg.package}/bin/labgrid-coordinator ${lib.optionalString cfg.debug "--debug"} --listen ${cfg.bindAddress}:${toString cfg.port}"; + Restart = "on-failure"; + DynamicUser = "yes"; + StateDirectory = "labgrid-coordinator"; + WorkingDirectory = "/var/lib/labgrid-coordinator"; + CapabilityBoundingSet = ""; + LockPersonality = true; + MemoryDenyWriteExecute = true; + PrivateDevices = true; + PrivateUsers = true; + ProcSubset = "pid"; + ProtectClock = true; + ProtectControlGroups = true; + ProtectHome = true; + ProtectHostname = true; + ProtectKernelLogs = true; + ProtectKernelModules = true; + ProtectKernelTunables = true; + ProtectProc = "invisible"; + RestrictRealtime = true; + RestrictAddressFamilies = "AF_INET AF_INET6"; + RestrictNamespaces = true; + SystemCallArchitectures = "native"; + SystemCallFilter = [ + "@system-service" + "~@privileged" + "~@resources" + ]; + }; + wantedBy = [ "multi-user.target" ]; + wants = [ "network-online.target" ]; + }; + }; +} From 336b6be1476abc05b56c198f9b344b6c653c912d Mon Sep 17 00:00:00 2001 From: Rouven Czerwinski Date: Sat, 21 Feb 2026 00:14:29 +0100 Subject: [PATCH 2/3] nixosTests.labgrid: init Co-authored-by: Burfeind, Jan-Niklas --- nixos/tests/all-tests.nix | 1 + nixos/tests/labgrid.nix | 61 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+) create mode 100644 nixos/tests/labgrid.nix diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix index 763441391abb..f145d3a75554 100644 --- a/nixos/tests/all-tests.nix +++ b/nixos/tests/all-tests.nix @@ -853,6 +853,7 @@ in inherit runTest; inherit (pkgs) lib; }; + labgrid = runTest ./labgrid.nix; lact = runTest ./lact.nix; ladybird = runTest ./ladybird.nix; languagetool = runTest ./languagetool.nix; diff --git a/nixos/tests/labgrid.nix b/nixos/tests/labgrid.nix new file mode 100644 index 000000000000..d92639fefa4b --- /dev/null +++ b/nixos/tests/labgrid.nix @@ -0,0 +1,61 @@ +{ pkgs, ... }: +{ + name = "Labgrid"; + meta.maintainers = with pkgs.lib.maintainers; [ + aiyion + emantor + ]; + + nodes.coordinator = + { pkgs, ... }: + { + services.labgrid.coordinator.enable = true; + services.labgrid.coordinator.openFirewall = true; + }; + + nodes.client = + { pkgs, ... }: + { + environment.variables = { + LG_COORDINATOR = "coordinator:20408"; + }; + environment.systemPackages = [ pkgs.python3Packages.labgrid ]; + }; + + testScript = + { nodes, ... }: + #python + '' + def assert_contains(haystack, needle): + if needle not in haystack: + print("The haystack that will cause the following exception is:") + print("---") + print(haystack) + print("---") + raise Exception(f"Expected string '{needle}' was not found") + + with subtest("Wait for coordinator startup"): + coordinator.start() + coordinator.wait_for_unit("labgrid-coordinator.service") + coordinator.wait_for_open_port(20408) + + with subtest("Connect from client"): + client.start() + out = client.succeed("labgrid-client resources") + + with subtest("Create place"): + client.succeed("labgrid-client -p testplace create") + out = client.succeed("labgrid-client places") + assert_contains(out, "testplace") + # Give the coordinator enough time to persist place creation + coordinator.wait_until_succeeds("grep -q testplace /var/lib/labgrid-coordinator/places.yaml") + + with subtest("Test coordinator persistence"): + coordinator.shutdown() + coordinator.start() + coordinator.wait_for_unit("labgrid-coordinator.service") + coordinator.wait_for_open_port(20408) + out = client.succeed("labgrid-client places") + assert_contains(out, "testplace") + ''; +} From ad603b16de0a867412a3fc58d51e71a6a0f4fdaa Mon Sep 17 00:00:00 2001 From: "Burfeind, Jan-Niklas" Date: Mon, 2 Mar 2026 11:52:16 +0100 Subject: [PATCH 3/3] nixosTests.labgrid: Add systemd hardening test to prevent unnoticed degradation. The limit '11' matches the current exposure level '1.1'. --- nixos/tests/labgrid.nix | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/nixos/tests/labgrid.nix b/nixos/tests/labgrid.nix index d92639fefa4b..1b405dc0c51c 100644 --- a/nixos/tests/labgrid.nix +++ b/nixos/tests/labgrid.nix @@ -57,5 +57,10 @@ coordinator.wait_for_open_port(20408) out = client.succeed("labgrid-client places") assert_contains(out, "testplace") + + with subtest("Check systemd hardening does not degrade unnoticed"): + exact_threshold = 11 + out = coordinator.fail(f"systemd-analyze security labgrid-coordinator.service --threshold={exact_threshold-1}") + out = coordinator.succeed(f"systemd-analyze security labgrid-coordinator.service --threshold={exact_threshold}") ''; }