diff --git a/src/ssh_guard.py b/src/ssh_guard.py index 1974922..41e443e 100644 --- a/src/ssh_guard.py +++ b/src/ssh_guard.py @@ -71,12 +71,14 @@ def parse_config(path: Path, visited: set[Path] | None = None) -> dict[str, str] if normalized == "match": break if normalized == "include": - pattern = Path(value.strip()) - if not pattern.is_absolute(): - pattern = path.parent / pattern - for included in sorted(pattern.parent.glob(pattern.name)): - for child_key, child_value in parse_config(included, visited).items(): - settings.setdefault(child_key, child_value) + # One Include line may list several space-separated paths, read in order. + for item in value.split(): + pattern = Path(item) + if not pattern.is_absolute(): + pattern = path.parent / pattern + for included in sorted(pattern.parent.glob(pattern.name)): + for child_key, child_value in parse_config(included, visited).items(): + settings.setdefault(child_key, child_value) continue settings.setdefault(normalized, value.strip().lower()) return settings diff --git a/tests/test_ssh_guard.py b/tests/test_ssh_guard.py index fc35a5e..cc46108 100644 --- a/tests/test_ssh_guard.py +++ b/tests/test_ssh_guard.py @@ -18,6 +18,15 @@ def test_tab_and_equals_separators(self): config.write_text("PermitRootLogin\tno\nPasswordAuthentication=no\nX11Forwarding = no\n", encoding="utf-8") self.assertEqual(parse_config(config), {"permitrootlogin": "no", "passwordauthentication": "no", "x11forwarding": "no"}) + def test_include_reads_every_listed_path(self): + with tempfile.TemporaryDirectory() as directory: + root = Path(directory) + (root / "a.conf").write_text("PermitRootLogin no\n", encoding="utf-8") + (root / "b.conf").write_text("PasswordAuthentication no\n", encoding="utf-8") + config = root / "sshd_config" + config.write_text("Include a.conf b.conf\n", encoding="utf-8") + self.assertEqual(parse_config(config), {"permitrootlogin": "no", "passwordauthentication": "no"}) + def test_effective_output_and_audit(self): settings = parse_effective_output("permitrootlogin no\npasswordauthentication no\nmaxauthtries 3\n") findings = {item.key: item for item in audit(settings)}