from pathlib import Path import pytest from l4d2host.paths import ( get_left4me_root, overlay_path, validate_instance_name, validate_overlay_ref, ) def test_get_left4me_root_defaults_to_var_lib_left4me(monkeypatch: pytest.MonkeyPatch) -> None: monkeypatch.delenv("LEFT4ME_ROOT", raising=False) assert get_left4me_root() == Path("/var/lib/left4me") def test_get_left4me_root_uses_env(monkeypatch: pytest.MonkeyPatch, tmp_path: Path) -> None: monkeypatch.setenv("LEFT4ME_ROOT", str(tmp_path)) assert get_left4me_root() == tmp_path def test_get_left4me_root_rejects_relative_env(monkeypatch: pytest.MonkeyPatch) -> None: monkeypatch.setenv("LEFT4ME_ROOT", "var/lib/left4me") with pytest.raises(ValueError): get_left4me_root() @pytest.mark.parametrize("raw", ["", " "]) def test_get_left4me_root_rejects_empty_env(monkeypatch: pytest.MonkeyPatch, raw: str) -> None: monkeypatch.setenv("LEFT4ME_ROOT", raw) with pytest.raises(ValueError): get_left4me_root() @pytest.mark.parametrize("ref", ["standard", "competitive/base", "users/42/custom"]) def test_validate_overlay_ref_accepts_safe_refs(ref: str) -> None: assert validate_overlay_ref(ref) == ref @pytest.mark.parametrize( "ref", ["", "/tmp/bad", "../bad", "bad/../evil", "bad//evil", " bad", "bad ", ".", "bad/./evil"], ) def test_validate_overlay_ref_rejects_unsafe_refs(ref: str) -> None: with pytest.raises(ValueError): validate_overlay_ref(ref) @pytest.mark.parametrize("name", ["srv1", "alpha", "my-server", "srv_01", "a", "a" * 64]) def test_validate_instance_name_accepts_safe_names(name: str) -> None: assert validate_instance_name(name) == name @pytest.mark.parametrize( "name", [ "", " ", "..", ".", "../foo", "foo/..", "foo/bar", "foo\\bar", " foo", "foo ", "Foo", "foo bar", "foo$", "-foo", "_foo", "foo@bar", "a" * 65, ], ) def test_validate_instance_name_rejects_unsafe_names(name: str) -> None: with pytest.raises(ValueError): validate_instance_name(name) def test_overlay_path_resolves_under_root(tmp_path: Path) -> None: assert overlay_path("standard", root=tmp_path) == tmp_path / "overlays" / "standard" def test_overlay_path_rejects_symlink_escape(tmp_path: Path) -> None: outside = tmp_path / "outside" outside.mkdir() overlays = tmp_path / "overlays" overlays.mkdir() (overlays / "escape").symlink_to(outside) with pytest.raises(ValueError): overlay_path("escape", root=tmp_path)