Files
strix/tests/test_local_sources.py
T

198 lines
6.2 KiB
Python

"""Tests for local-source collection and mount policy in interface.utils."""
from __future__ import annotations
from pathlib import Path
from typing import Any
import pytest
from strix.interface.utils import (
check_mountable_dir,
collect_local_sources,
dedupe_local_targets,
infer_target_type,
read_target_list_file,
)
def _local_target(target_path: str) -> dict[str, Any]:
return {
"type": "local_code",
"details": {"target_path": target_path, "workspace_subdir": "repo"},
"original": target_path,
}
def test_collect_local_sources_protects_the_users_own_git() -> None:
sources = collect_local_sources([_local_target("/code")])
assert sources == [
{"source_path": "/code", "workspace_subdir": "repo", "protect_metadata": True}
]
def test_collect_local_sources_leaves_a_clone_writable() -> None:
repo = {
"type": "repository",
"details": {"cloned_repo_path": "/clone", "workspace_subdir": "clone"},
}
sources = collect_local_sources([repo])
assert sources == [
{"source_path": "/clone", "workspace_subdir": "clone", "protect_metadata": False}
]
def test_check_mountable_dir_accepts_a_project_dir(tmp_path: Path) -> None:
check_mountable_dir(tmp_path)
def test_check_mountable_dir_rejects_missing_path(tmp_path: Path) -> None:
with pytest.raises(ValueError, match="not an existing directory"):
check_mountable_dir(tmp_path / "nope")
def test_check_mountable_dir_rejects_filesystem_root() -> None:
with pytest.raises(ValueError, match="Refusing to mount"):
check_mountable_dir(Path("/"))
def test_check_mountable_dir_rejects_home(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
home = tmp_path / "home"
home.mkdir()
monkeypatch.setenv("HOME", str(home))
monkeypatch.setattr(Path, "home", classmethod(lambda _cls: home))
with pytest.raises(ValueError, match="Refusing to mount"):
check_mountable_dir(home)
def test_check_mountable_dir_rejects_system_root() -> None:
etc = Path("/etc")
if not etc.is_dir():
pytest.skip("no /etc on this platform")
with pytest.raises(ValueError, match="Refusing to mount"):
check_mountable_dir(etc)
def test_check_mountable_dir_rejects_the_shared_home_root() -> None:
home_root = Path("/home")
if not home_root.is_dir():
pytest.skip("no /home on this platform")
with pytest.raises(ValueError, match="Refusing to mount"):
check_mountable_dir(home_root)
def test_check_mountable_dir_matches_forbidden_names_case_insensitively(tmp_path: Path) -> None:
ssh_dir = tmp_path / ".SSH"
ssh_dir.mkdir()
with pytest.raises(ValueError, match="holds credentials"):
check_mountable_dir(ssh_dir)
def test_check_mountable_dir_rejects_credential_dirs(tmp_path: Path) -> None:
ssh_dir = tmp_path / ".ssh"
ssh_dir.mkdir()
with pytest.raises(ValueError, match="holds credentials"):
check_mountable_dir(ssh_dir)
def test_check_mountable_dir_rejects_credential_subdirs(tmp_path: Path) -> None:
keys = tmp_path / ".ssh" / "keys"
keys.mkdir(parents=True)
with pytest.raises(ValueError, match="holds credentials"):
check_mountable_dir(keys)
def test_check_mountable_dir_rejects_system_subdirs() -> None:
system_subdir = next((p for p in (Path("/etc/ssl"), Path("/usr/bin")) if p.is_dir()), None)
if system_subdir is None:
pytest.skip("no system subdirectory on this platform")
with pytest.raises(ValueError, match="Refusing to mount"):
check_mountable_dir(system_subdir)
def test_check_mountable_dir_accepts_a_project_under_the_home_root(
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
) -> None:
project = tmp_path / "home" / "dev" / "project"
project.mkdir(parents=True)
monkeypatch.setattr(Path, "home", classmethod(lambda _cls: tmp_path / "home" / "dev"))
check_mountable_dir(project)
def test_infer_target_type_applies_the_mount_policy() -> None:
with pytest.raises(ValueError, match="Refusing to mount"):
infer_target_type("/etc")
def test_read_target_list_file_strips_blank_lines(tmp_path: Path) -> None:
target_list = tmp_path / "targets.txt"
target_list.write_text(
"\n https://test1.com/ \n\nhttp://test2.com:5789/\n \n",
encoding="utf-8",
)
assert read_target_list_file(str(target_list)) == [
"https://test1.com/",
"http://test2.com:5789/",
]
def test_read_target_list_file_ignores_comment_lines(tmp_path: Path) -> None:
target_list = tmp_path / "targets.txt"
target_list.write_text(
"# production targets\nhttps://test1.com/\n # staging targets\nhttp://test2.com:5789/\n",
encoding="utf-8",
)
assert read_target_list_file(str(target_list)) == [
"https://test1.com/",
"http://test2.com:5789/",
]
def test_read_target_list_file_rejects_empty_file(tmp_path: Path) -> None:
target_list = tmp_path / "targets.txt"
target_list.write_text(" \n# no targets yet\n\n", encoding="utf-8")
with pytest.raises(ValueError, match="is empty"):
read_target_list_file(str(target_list))
def test_read_target_list_file_rejects_missing_path(tmp_path: Path) -> None:
with pytest.raises(ValueError, match="not an existing file"):
read_target_list_file(str(tmp_path / "missing.txt"))
def test_read_target_list_file_rejects_non_utf8_file(tmp_path: Path) -> None:
target_list = tmp_path / "targets.txt"
target_list.write_bytes(b"https://test1.com/\xff\n")
with pytest.raises(ValueError, match="must be valid UTF-8 text"):
read_target_list_file(str(target_list))
@pytest.mark.parametrize("empty", ["", " "])
def test_read_target_list_file_rejects_empty_path(empty: str) -> None:
with pytest.raises(ValueError, match="must not be empty"):
read_target_list_file(empty)
def test_dedupe_keeps_distinct_targets_in_order() -> None:
targets = [
_local_target("/a"),
{"type": "web_application", "details": {"target_url": "https://x"}},
_local_target("/b"),
]
assert dedupe_local_targets(targets) == targets
def test_dedupe_collapses_the_same_path() -> None:
assert dedupe_local_targets([_local_target("/repo"), _local_target("/repo")]) == [
_local_target("/repo")
]