refactor(artifacts): extract resolve_artifact_path to shared module

Move artifact path validation + symlink-escape check out of the
admin-gated download endpoint into decnet/artifacts/paths.py so the
TTP EmailLifter can disk-reach .eml files at tag-time without
duplicating regex/root logic (DEBT-047).

The router now catches ArtifactPathError and re-raises HTTPException(400);
behavior is unchanged.
This commit is contained in:
2026-05-02 20:02:47 -04:00
parent cdbb3d3571
commit 7036a86e76
6 changed files with 186 additions and 49 deletions

View File

@@ -23,9 +23,10 @@ def artifacts_root(tmp_path, monkeypatch):
(root / _DECKY / "ssh").mkdir(parents=True)
(root / _DECKY / "ssh" / _VALID_STORED_AS).write_bytes(_PAYLOAD)
# Patch the module-level constant (captured at import time).
from decnet.web.router.artifacts import api_get_artifact
monkeypatch.setattr(api_get_artifact, "ARTIFACTS_ROOT", root)
# Patch the canonical module-level constant. Both the router and
# the EmailLifter resolve through decnet.artifacts.paths.
from decnet.artifacts import paths as artifact_paths
monkeypatch.setattr(artifact_paths, "ARTIFACTS_ROOT", root)
return root
@@ -137,8 +138,8 @@ async def test_smtp_service_serves_from_smtp_subdir(
(root / _DECKY / "smtp").mkdir(parents=True)
eml = "2026-04-18T02:22:56Z_abc123def456_msg.eml"
(root / _DECKY / "smtp" / eml).write_bytes(b"From: a\r\n\r\nhi")
from decnet.web.router.artifacts import api_get_artifact
monkeypatch.setattr(api_get_artifact, "ARTIFACTS_ROOT", root)
from decnet.artifacts import paths as artifact_paths
monkeypatch.setattr(artifact_paths, "ARTIFACTS_ROOT", root)
res = await client.get(
f"/api/v1/artifacts/{_DECKY}/{eml}?service=smtp",
headers={"Authorization": f"Bearer {auth_token}"},