"""Behavioral branch coverage for dedicated node-account privilege audits.""" from __future__ import annotations import os import struct import sys from types import SimpleNamespace import pytest from testing.tests.test_hermes_node_account_support import _load def _audit_module(): hardening = _load() return sys.modules[hardening.audit_membership.__module__] def test_member_parser_handles_empty_valid_malformed_and_duplicates(): module = _audit_module() assert module._members("", "group") == set() assert module._members("one,two", "group") == {"one", "two"} for value in ("one,", " one", "one,one"): with pytest.raises(module.HardeningError): module._members(value, "group") def test_membership_audit_accepts_unrelated_records_and_rejects_account(): module = _audit_module() module.audit_membership( "hermes-agent", [["disk", "x", "6", "atlas"]], [["disk", "!", "atlas", ""]] ) with pytest.raises(module.HardeningError, match="supplementary"): module.audit_membership( "hermes-agent", [["disk", "x", "6", "hermes-agent"]], [] ) with pytest.raises(module.HardeningError, match="gshadow"): module.audit_membership("hermes-agent", [], [["disk", "!", "hermes-agent", ""]]) @pytest.mark.parametrize("kind", ["mode", "symlink"]) def test_policy_files_reject_unsafe_directories(tmp_path, kind): module = _audit_module() host_etc = tmp_path / "etc" host_etc.mkdir() root = host_etc / "sudoers.d" if kind == "mode": root.mkdir(mode=0o777) root.chmod(0o777) else: target = tmp_path / "target" target.mkdir() root.symlink_to(target) with pytest.raises(module.HardeningError, match="unsafe sudo/polkit"): module._policy_files(host_etc, tmp_path / "share", os.getuid()) def test_policy_file_count_is_bounded(tmp_path): module = _audit_module() root = tmp_path / "etc/sudoers.d" root.mkdir(parents=True) for index in range(257): (root / str(index)).write_text("# safe\n", encoding="utf-8") with pytest.raises(module.HardeningError, match="too many"): module._policy_files(tmp_path / "etc", tmp_path / "share", os.getuid()) def _acl(*entries): return struct.pack("