This repository has been archived on 2026-06-22. You can view files and clone it, but you cannot make any changes to it's state, such as pushing and creating new issues, pull requests or comments.
enroll/tests/test_cache_security.py

138 lines
3.8 KiB
Python

from __future__ import annotations
import os
from pathlib import Path
import pytest
def test_ensure_dir_secure_refuses_symlink(tmp_path: Path):
from enroll.cache import _ensure_dir_secure
target = tmp_path / "target"
target.mkdir()
link = tmp_path / "link"
link.symlink_to(target, target_is_directory=True)
with pytest.raises(RuntimeError):
_ensure_dir_secure(link)
def test_ensure_dir_secure_ignores_chmod_failures(tmp_path: Path, monkeypatch):
from enroll.cache import _ensure_dir_secure
d = tmp_path / "d"
def boom(_path: str, _mode: int):
raise OSError("no")
monkeypatch.setattr(os, "chmod", boom)
# Should not raise.
_ensure_dir_secure(d)
assert d.exists() and d.is_dir()
def test_safe_component_returns_unknown_for_empty_string():
from enroll.cache import _safe_component
assert _safe_component("") == "unknown"
assert _safe_component(" ") == "unknown"
def test_safe_component_truncates_long_strings():
from enroll.cache import _safe_component
long_str = "a" * 100
result = _safe_component(long_str)
assert len(result) <= 64
def test_safe_component_replaces_special_chars():
from enroll.cache import _safe_component
result = _safe_component("hello world!")
assert result == "hello_world_"
def test_enroll_cache_dir_uses_xdg_cache_home(monkeypatch):
from enroll.cache import enroll_cache_dir
monkeypatch.setenv("XDG_CACHE_HOME", "/custom/cache")
result = enroll_cache_dir()
assert str(result) == "/custom/cache/enroll"
def test_harvest_cache_state_json_property():
from enroll.cache import HarvestCache
cache_dir = HarvestCache(dir=Path("/tmp/test"))
assert cache_dir.state_json == Path("/tmp/test/state.json")
def test_new_harvest_cache_dir_chmod_fails(tmp_path: Path, monkeypatch):
from enroll.cache import new_harvest_cache_dir
def fake_enroll_cache_dir():
return tmp_path / "enroll"
def fake_chmod(path, mode):
raise OSError("no")
monkeypatch.setattr("enroll.cache.enroll_cache_dir", fake_enroll_cache_dir)
monkeypatch.setattr(os, "chmod", fake_chmod)
# Should not raise even though chmod fails
cache = new_harvest_cache_dir(hint="test")
assert cache.dir.exists()
assert isinstance(cache.dir, Path)
def test_enroll_cache_dir_uses_default_when_xdg_not_set(monkeypatch):
from enroll.cache import enroll_cache_dir
# Remove XDG_CACHE_HOME if it exists
monkeypatch.delenv("XDG_CACHE_HOME", raising=False)
result = enroll_cache_dir()
assert str(result).endswith("/.local/cache/enroll")
def test_ensure_dir_secure_refuses_symlink_parent(tmp_path: Path):
from enroll.cache import _ensure_dir_secure
target = tmp_path / "target"
target.mkdir()
link = tmp_path / "link"
link.symlink_to(target, target_is_directory=True)
with pytest.raises(RuntimeError, match="symlink"):
_ensure_dir_secure(link / "enroll" / "harvest")
assert not (target / "enroll" / "harvest").exists()
def test_ensure_dir_secure_rejects_unsafe_root_parent(tmp_path: Path, monkeypatch):
from enroll.cache import _ensure_dir_secure
import enroll.harvest_safety as hs
untrusted = tmp_path / "untrusted"
untrusted.mkdir()
untrusted.chmod(0o777)
monkeypatch.setattr(hs, "_effective_uid", lambda: 0)
with pytest.raises(RuntimeError, match="not owned by root|writable by group/other"):
_ensure_dir_secure(untrusted / "cache")
def test_ensure_dir_secure_rejects_existing_file_when_not_root(
tmp_path: Path, monkeypatch
):
from enroll.cache import _ensure_dir_secure
import enroll.harvest_safety as hs
path = tmp_path / "cache"
path.write_text("not a dir", encoding="utf-8")
monkeypatch.setattr(hs, "_effective_uid", lambda: 1000)
with pytest.raises(RuntimeError, match="not a directory"):
_ensure_dir_secure(path)