From cd10db66a250e3ca391f2ffd7c7e4c7ed912195d Mon Sep 17 00:00:00 2001 From: alex Date: Sun, 2 Aug 2026 21:25:19 +0200 Subject: [PATCH] fix(deploy): allow systemd unit verification --- systemd/user/audio-control-deploy.service | 2 +- .../test_audio_control_deployment_contract.py | 27 +++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/systemd/user/audio-control-deploy.service b/systemd/user/audio-control-deploy.service index 4dcc860..68e0e09 100644 --- a/systemd/user/audio-control-deploy.service +++ b/systemd/user/audio-control-deploy.service @@ -17,7 +17,7 @@ ProtectControlGroups=yes ProtectKernelTunables=yes LockPersonality=yes RestrictSUIDSGID=yes -RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6 +RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6 AF_NETLINK UMask=0077 MemoryMax=536870912 CPUQuota=100% diff --git a/tests/test_audio_control_deployment_contract.py b/tests/test_audio_control_deployment_contract.py index 5197e7e..56997e8 100644 --- a/tests/test_audio_control_deployment_contract.py +++ b/tests/test_audio_control_deployment_contract.py @@ -4,6 +4,8 @@ ROOT = pathlib.Path(__file__).resolve().parents[1] INDEX_PATH = ROOT / "ui" / "index.html" +DEPLOY_UNIT_PATH = ROOT / "systemd" / "user" / "audio-control-deploy.service" +UI_UNIT_PATH = ROOT / "systemd" / "user" / "audio-control-ui-v1.service" LEGACY_INDEX_BLOB_SHA = "4a1e80316512a24f780359c8f7e45194226c4f88" DEPLOYMENT_CONTRACT_PATTERN = ( r' set[str]: + lines = [ + line + for line in path.read_text(encoding="utf-8").splitlines() + if line.startswith("RestrictAddressFamilies=") + ] + if len(lines) != 1: + raise AssertionError( + f"expected exactly one RestrictAddressFamilies line in {path.name}" + ) + return set(lines[0].split("=", 1)[1].split()) + + class AudioControlDeploymentContractTests(unittest.TestCase): def test_index_distinguishes_revision_bound_first_hop_from_legacy(self): payload = INDEX_PATH.read_bytes() @@ -22,6 +37,18 @@ def test_index_distinguishes_revision_bound_first_hop_from_legacy(self): self.assertNotEqual(git_blob, LEGACY_INDEX_BLOB_SHA) self.assertRegex(payload.decode("utf-8"), DEPLOYMENT_CONTRACT_PATTERN) + def test_deploy_unit_allows_only_required_address_families(self): + self.assertEqual( + address_families(DEPLOY_UNIT_PATH), + {"AF_UNIX", "AF_INET", "AF_INET6", "AF_NETLINK"}, + ) + + def test_ui_unit_does_not_gain_deploy_only_netlink_access(self): + self.assertEqual( + address_families(UI_UNIT_PATH), + {"AF_UNIX", "AF_INET"}, + ) + if __name__ == "__main__": unittest.main()