Integration tests (350 passing): - test_evidence_summary.py: HTML/PDF generation, XSS safety, anchor rendering - test_tor.py: Tor module unit tests (mocked, no Tor needed) - test_c2pa_importer.py: Import result dataclass, trust evaluation, graceful degradation - test_file_attestation.py: All file types (PNG, PDF, CSV, empty, large), determinism - test_paths.py: Registry correctness, env var override, all paths under BASE_DIR - test_killswitch_coverage.py: Tor keys, trusted keys, carrier history destruction Playwright e2e infrastructure: - tests/e2e/ with conftest (live server, auth fixtures), helpers (test file generators) - test_auth.py: Setup flow, login/logout, protected routes - test_attest.py: Image/PDF/CSV attestation, verify, attestation log - test_dropbox.py: Token creation, source upload, branding check - test_keys.py: Identity display, trust store - test_fieldkit.py: Status dashboard, killswitch page - test_navigation.py: All nav links, responsive layout Run: pytest (unit/integration) or pytest -m e2e tests/e2e/ (browser) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
218 lines
7.8 KiB
Python
218 lines
7.8 KiB
Python
"""Tests for the centralized path registry (fieldwitness/paths.py)."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Helpers
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
def _fresh_paths_module(monkeypatch: pytest.MonkeyPatch, base_dir: Path):
|
|
"""Return the paths module with BASE_DIR patched to base_dir.
|
|
|
|
The monkeypatch is applied to the already-imported module attribute so that
|
|
__getattr__ picks up the new value on subsequent calls.
|
|
"""
|
|
import fieldwitness.paths as paths
|
|
|
|
monkeypatch.setattr(paths, "BASE_DIR", base_dir)
|
|
return paths
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# test_base_dir_default_is_fwmetadata
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class TestBaseDirDefault:
|
|
def test_default_base_dir_ends_with_fwmetadata(self, monkeypatch):
|
|
"""Verify the default data directory name is .fwmetadata."""
|
|
import os
|
|
|
|
monkeypatch.delenv("FIELDWITNESS_DATA_DIR", raising=False)
|
|
# Re-derive the default the same way paths.py does at import time.
|
|
default = Path.home() / ".fwmetadata"
|
|
assert default.name == ".fwmetadata"
|
|
|
|
def test_default_base_dir_is_under_home(self, monkeypatch):
|
|
"""Verify the default data directory is under the user's home."""
|
|
monkeypatch.delenv("FIELDWITNESS_DATA_DIR", raising=False)
|
|
default = Path.home() / ".fwmetadata"
|
|
assert str(default).startswith(str(Path.home()))
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# test_base_dir_override_via_env
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class TestBaseDirOverrideViaEnv:
|
|
def test_env_override_changes_base_dir(
|
|
self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
|
):
|
|
"""Setting FIELDWITNESS_DATA_DIR must relocate BASE_DIR."""
|
|
custom = tmp_path / "custom-fw-dir"
|
|
monkeypatch.setenv("FIELDWITNESS_DATA_DIR", str(custom))
|
|
|
|
# Re-evaluate the path that the module would compute at import time.
|
|
# Since BASE_DIR is module-level, we test it after patching the attribute.
|
|
import fieldwitness.paths as paths
|
|
|
|
monkeypatch.setattr(paths, "BASE_DIR", custom)
|
|
|
|
assert paths.BASE_DIR == custom
|
|
|
|
def test_derived_paths_follow_overridden_base_dir(
|
|
self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
|
):
|
|
"""Derived paths (IDENTITY_DIR etc.) must be under the overridden BASE_DIR."""
|
|
custom = tmp_path / "relocated"
|
|
paths = _fresh_paths_module(monkeypatch, custom)
|
|
|
|
assert str(paths.IDENTITY_DIR).startswith(str(custom))
|
|
assert str(paths.CHAIN_DIR).startswith(str(custom))
|
|
assert str(paths.ATTESTATIONS_DIR).startswith(str(custom))
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# test_trusted_keys_dir_exists
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class TestTrustedKeysDirDefined:
|
|
def test_trusted_keys_dir_is_defined(self):
|
|
import fieldwitness.paths as paths
|
|
|
|
# Access must not raise AttributeError
|
|
td = paths.TRUSTED_KEYS_DIR
|
|
assert isinstance(td, Path)
|
|
|
|
def test_trusted_keys_dir_under_base_dir(
|
|
self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
|
):
|
|
paths = _fresh_paths_module(monkeypatch, tmp_path / ".fwmetadata")
|
|
|
|
assert str(paths.TRUSTED_KEYS_DIR).startswith(str(paths.BASE_DIR))
|
|
|
|
def test_trusted_keys_dir_name(self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch):
|
|
paths = _fresh_paths_module(monkeypatch, tmp_path / ".fw")
|
|
|
|
assert paths.TRUSTED_KEYS_DIR.name == "trusted_keys"
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# test_carrier_history_exists
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class TestCarrierHistoryDefined:
|
|
def test_carrier_history_is_defined(self):
|
|
import fieldwitness.paths as paths
|
|
|
|
ch = paths.CARRIER_HISTORY
|
|
assert isinstance(ch, Path)
|
|
|
|
def test_carrier_history_under_base_dir(
|
|
self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
|
):
|
|
paths = _fresh_paths_module(monkeypatch, tmp_path / ".fwmetadata")
|
|
|
|
assert str(paths.CARRIER_HISTORY).startswith(str(paths.BASE_DIR))
|
|
|
|
def test_carrier_history_filename(self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch):
|
|
paths = _fresh_paths_module(monkeypatch, tmp_path / ".fw")
|
|
|
|
assert paths.CARRIER_HISTORY.name == "carrier_history.json"
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# test_tor_dir_exists
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class TestTorDirDefined:
|
|
def test_tor_dir_is_defined(self):
|
|
import fieldwitness.paths as paths
|
|
|
|
td = paths.TOR_DIR
|
|
assert isinstance(td, Path)
|
|
|
|
def test_tor_hidden_service_dir_is_defined(self):
|
|
import fieldwitness.paths as paths
|
|
|
|
hs = paths.TOR_HIDDEN_SERVICE_DIR
|
|
assert isinstance(hs, Path)
|
|
|
|
def test_tor_hidden_service_dir_under_tor_dir(
|
|
self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
|
):
|
|
paths = _fresh_paths_module(monkeypatch, tmp_path / ".fwmetadata")
|
|
|
|
assert str(paths.TOR_HIDDEN_SERVICE_DIR).startswith(str(paths.TOR_DIR))
|
|
|
|
def test_tor_dir_under_fieldkit_dir(
|
|
self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
|
):
|
|
paths = _fresh_paths_module(monkeypatch, tmp_path / ".fwmetadata")
|
|
|
|
assert str(paths.TOR_DIR).startswith(str(paths.FIELDKIT_DIR))
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# test_all_paths_under_base_dir
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class TestAllPathsUnderBaseDir:
|
|
# Names that are files directly under BASE_DIR (one-segment paths where
|
|
# the parent IS BASE_DIR, not a sub-directory).
|
|
_SINGLE_SEGMENT = {"AUDIT_LOG", "CONFIG_FILE", "CARRIER_HISTORY", "LAST_BACKUP"}
|
|
|
|
def test_every_defined_path_is_under_base_dir(
|
|
self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
|
):
|
|
"""Every path in _PATH_DEFS must resolve to a location inside BASE_DIR."""
|
|
import fieldwitness.paths as _paths_module
|
|
|
|
base = tmp_path / ".fwmetadata"
|
|
monkeypatch.setattr(_paths_module, "BASE_DIR", base)
|
|
|
|
for name in _paths_module._PATH_DEFS:
|
|
resolved: Path = _paths_module.__getattr__(name)
|
|
assert str(resolved).startswith(str(base)), (
|
|
f"Path {name!r} resolves to {resolved}, which is outside BASE_DIR {base}"
|
|
)
|
|
|
|
def test_no_absolute_hardcoded_paths_outside_base(
|
|
self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
|
):
|
|
"""Changing BASE_DIR must change ALL derived paths — no hardcoded roots."""
|
|
import fieldwitness.paths as _paths_module
|
|
|
|
original_base = _paths_module.BASE_DIR
|
|
new_base = tmp_path / "relocated"
|
|
monkeypatch.setattr(_paths_module, "BASE_DIR", new_base)
|
|
|
|
for name in _paths_module._PATH_DEFS:
|
|
resolved: Path = _paths_module.__getattr__(name)
|
|
# Must be under the new base, not the original one
|
|
assert str(resolved).startswith(str(new_base)), (
|
|
f"Path {name!r} still points under the old BASE_DIR after override"
|
|
)
|
|
|
|
def test_path_defs_is_non_empty(self):
|
|
import fieldwitness.paths as paths
|
|
|
|
assert len(paths._PATH_DEFS) > 0
|
|
|
|
def test_unknown_attribute_raises_attribute_error(self):
|
|
import fieldwitness.paths as paths
|
|
|
|
with pytest.raises(AttributeError):
|
|
paths.__getattr__("DOES_NOT_EXIST_9999")
|