puncture/tests/test_master_asset_mapping.py

157 lines
4.9 KiB
Python

from pathlib import Path
from io import BytesIO
from puncture.web_app import create_app
def test_asset_mapping_status_red_and_glow(monkeypatch, tmp_path: Path) -> None:
asset_root = tmp_path / "assets"
asset_root.mkdir()
(asset_root / "a.txt").write_text("alpha", encoding="utf-8")
(asset_root / "b.txt").write_text("beta", encoding="utf-8")
monkeypatch.setenv("PUNCTURE_ASSET_ROOT", str(asset_root))
app = create_app()
client = app.test_client()
client.post(
"/assets/encrypt",
data={
"plaintext_relpath": "a.txt",
"provider_id": "42",
"file_time_id": "100",
"purpose": "a via p42",
},
)
client.post(
"/assets/encrypt",
data={
"plaintext_relpath": "a.txt",
"provider_id": "17",
"file_time_id": "200",
"purpose": "a via p17",
},
)
client.post(
"/assets/encrypt",
data={
"plaintext_relpath": "b.txt",
"provider_id": "42",
"file_time_id": "100",
"purpose": "b via p42",
},
)
# Puncture shared key (provider 42 / key 100) used by two files.
client.post("/puncture", data={"provider_id": "42", "file_time_id": "100"}, follow_redirects=True)
live = client.get("/api/live/state").get_json()
files = {row["plaintext_relpath"]: row for row in live["assets"]["asset_files"]}
file_a = files["a.txt"]
rows_a = {(r["provider_id"], r["file_time_id"]): r for r in file_a["mappings"]}
assert rows_a[(42, 100)]["show_red"] is True
assert rows_a[(42, 100)]["is_accessible"] is False
assert rows_a[(17, 200)]["show_glow"] is True
assert rows_a[(17, 200)]["is_accessible"] is True
file_b = files["b.txt"]
rows_b = {(r["provider_id"], r["file_time_id"]): r for r in file_b["mappings"]}
assert rows_b[(42, 100)]["show_red"] is True
assert rows_b[(42, 100)]["is_accessible"] is False
def test_remote_puncture_provider_endpoint_requires_token(monkeypatch, tmp_path: Path) -> None:
asset_root = tmp_path / "assets2"
asset_root.mkdir()
(asset_root / "c.txt").write_text("content", encoding="utf-8")
monkeypatch.setenv("PUNCTURE_ASSET_ROOT", str(asset_root))
monkeypatch.setenv("PUNCTURE_REMOTE_TOKEN", "tok")
app = create_app()
client = app.test_client()
# Derive once pre-kill to verify accessibility.
resp_pre = client.post(
"/derive",
data={"provider_id": "42", "file_time_id": "300", "purpose": "pre"},
follow_redirects=True,
)
assert b"Derive succeeded" in resp_pre.data
denied = client.post("/api/remote/puncture-provider", json={"provider_id": 42})
assert denied.status_code == 403
allowed = client.post(
"/api/remote/puncture-provider",
json={"provider_id": 42},
headers={"X-Puncture-Token": "tok"},
)
assert allowed.status_code == 200
assert allowed.get_json()["ok"] is True
resp_post = client.post(
"/derive",
data={"provider_id": "42", "file_time_id": "300", "purpose": "post"},
follow_redirects=True,
)
assert b"Derive blocked" in resp_post.data
def test_asset_page_can_encrypt_multiple_selected_files(monkeypatch, tmp_path: Path) -> None:
asset_root = tmp_path / "assets3"
asset_root.mkdir()
(asset_root / "f1.txt").write_text("f1", encoding="utf-8")
(asset_root / "f2.txt").write_text("f2", encoding="utf-8")
monkeypatch.setenv("PUNCTURE_ASSET_ROOT", str(asset_root))
app = create_app()
client = app.test_client()
client.post(
"/assets/encrypt",
data={
"plaintext_relpaths": ["f1.txt", "f2.txt"],
"provider_id": "42",
"file_time_id": "444",
"purpose": "batch",
},
follow_redirects=True,
)
ciphers = sorted(asset_root.glob("*.pke"))
assert len(ciphers) == 2
assert any(".enc.p42.k444.pke" in p.name for p in ciphers)
live = client.get("/api/live/state").get_json()
assert live["assets"]["mapping_count"] == 2
files = {row["plaintext_relpath"]: row for row in live["assets"]["asset_files"]}
assert "f1.txt" in files
assert "f2.txt" in files
def test_asset_upload_persists_cleartext_files(monkeypatch, tmp_path: Path) -> None:
asset_root = tmp_path / "assets4"
asset_root.mkdir()
monkeypatch.setenv("PUNCTURE_ASSET_ROOT", str(asset_root))
app = create_app()
client = app.test_client()
resp = client.post(
"/assets/upload",
data={
"target_subdir": "docs",
"files": [
(BytesIO(b"alpha"), "a.txt"),
(BytesIO(b"beta"), "b.txt"),
],
},
content_type="multipart/form-data",
follow_redirects=True,
)
assert resp.status_code == 200
assert (asset_root / "docs" / "a.txt").is_file()
assert (asset_root / "docs" / "b.txt").is_file()