···58 serviceConfig = {
59 ExecStart = (
60 lib.concatStringsSep " " [
00000000061 "${cfg.package}/bin/matter-server"
62 "--port"
63 (toString cfg.port)
···68 "--log-level"
69 "${cfg.logLevel}"
70 "${lib.escapeShellArgs cfg.extraArgs}"
071 ]
72 );
73 # Start with a clean root filesystem, and allowlist what the container
74 # is permitted to access.
75- TemporaryFileSystem = "/";
00076 # Allowlist /nix/store (to allow the binary to find its dependencies)
77 # and dbus.
78- ReadOnlyPaths = "/nix/store /run/dbus";
79 # Let systemd manage `/var/lib/matter-server` for us inside the
80 # ephemeral TemporaryFileSystem.
81 StateDirectory = storageDir;
82- # `python-matter-server` writes to /data even when a storage-path is
83- # specified. This bind-mount points /data at the systemd-managed
84- # /var/lib/matter-server, so all files get dropped into the state
85- # directory.
86- BindPaths = "${storagePath}:/data";
8788 # Hardening bits
89 AmbientCapabilities = "";
···58 serviceConfig = {
59 ExecStart = (
60 lib.concatStringsSep " " [
61+ # `python-matter-server` writes to /data even when a storage-path
62+ # is specified. This symlinks /data at the systemd-managed
63+ # /var/lib/matter-server, so all files get dropped into the state
64+ # directory.
65+ "${pkgs.bash}/bin/sh"
66+ "-c"
67+ "'"
68+ "${pkgs.coreutils}/bin/ln -s %S/matter-server/ %t/matter-server/root/data"
69+ "&&"
70 "${cfg.package}/bin/matter-server"
71 "--port"
72 (toString cfg.port)
···77 "--log-level"
78 "${cfg.logLevel}"
79 "${lib.escapeShellArgs cfg.extraArgs}"
80+ "'"
81 ]
82 );
83 # Start with a clean root filesystem, and allowlist what the container
84 # is permitted to access.
85+ # See https://discourse.nixos.org/t/hardening-systemd-services/17147/14.
86+ RuntimeDirectory = [ "matter-server/root" ];
87+ RootDirectory = "%t/matter-server/root";
88+89 # Allowlist /nix/store (to allow the binary to find its dependencies)
90 # and dbus.
91+ BindReadOnlyPaths = "/nix/store /run/dbus";
92 # Let systemd manage `/var/lib/matter-server` for us inside the
93 # ephemeral TemporaryFileSystem.
94 StateDirectory = storageDir;
000009596 # Hardening bits
97 AmbientCapabilities = "";
+19-17
nixos/tests/matter-server.nix
···8 {
9 name = "matter-server";
10 meta.maintainers = with lib.maintainers; [ leonm1 ];
01112 nodes = {
13 machine =
···2223 testScript = # python
24 ''
000025 start_all()
2627- machine.wait_for_unit("matter-server.service")
28- machine.wait_for_open_port(1234)
2930- with subtest("Check websocket server initialized"):
31- output = machine.succeed("echo \"\" | ${pkgs.websocat}/bin/websocat ws://localhost:1234/ws")
32- machine.log(output)
33-34- assert '"sdk_version": "${chipVersion}"' in output, (
35- 'CHIP version \"${chipVersion}\" not present in websocket message'
36- )
3738- assert '"fabric_id": 1' in output, (
39- "fabric_id not propagated to server"
40- )
4142- with subtest("Check storage directory is created"):
43- machine.succeed("ls /var/lib/matter-server/chip.json")
4445- with subtest("Check systemd hardening"):
46- _, output = machine.execute("systemd-analyze security matter-server.service | grep -v '✓'")
47- machine.log(output)
48 '';
49 }
50)
···8 {
9 name = "matter-server";
10 meta.maintainers = with lib.maintainers; [ leonm1 ];
11+ meta.timeout = 120; # Timeout after two minutes
1213 nodes = {
14 machine =
···2324 testScript = # python
25 ''
26+ @polling_condition
27+ def matter_server_running():
28+ machine.succeed("systemctl status matter-server")
29+30 start_all()
3132+ machine.wait_for_unit("matter-server.service", timeout=20)
33+ machine.wait_for_open_port(1234, timeout=20)
3435+ with matter_server_running: # type: ignore[union-attr]
36+ with subtest("Check websocket server initialized"):
37+ output = machine.succeed("echo \"\" | ${pkgs.websocat}/bin/websocat ws://localhost:1234/ws")
38+ machine.log(output)
0003940+ assert '"fabric_id": 1' in output, (
41+ "fabric_id not propagated to server"
42+ )
4344+ with subtest("Check storage directory is created"):
45+ machine.succeed("ls /var/lib/matter-server/chip.json")
4647+ with subtest("Check systemd hardening"):
48+ _, output = machine.execute("systemd-analyze security matter-server.service | grep -v '✓'")
49+ machine.log(output)
50 '';
51 }
52)