Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 8 additions & 6 deletions src/ssh_guard.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
9 changes: 9 additions & 0 deletions tests/test_ssh_guard.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)}
Expand Down
Loading