feat(web): transcripts API + repository lookups

Adds get_attacker_transcripts (mirror of artifacts for session_recorded
logs) and get_session_log for sid→shard resolution. New
/api/v1/transcripts/{decky}/{sid}?offset=&limit= pages asciinema events
out of the shared JSONL day-shard via an mtime-keyed byte-offset index
— never scans the whole shard per request. New
/api/v1/attackers/{uuid}/transcripts lists sessions for drilldown. Both
endpoints admin-gated.
This commit is contained in:
2026-04-21 23:06:39 -04:00
parent a58d42e492
commit 6e522c5a55
7 changed files with 291 additions and 0 deletions

View File

@@ -38,6 +38,8 @@ class DummyRepo(BaseRepository):
async def update_user_role(self, u, r): await super().update_user_role(u, r)
async def purge_logs_and_bounties(self): await super().purge_logs_and_bounties()
async def get_attacker_artifacts(self, uuid): await super().get_attacker_artifacts(uuid)
async def get_attacker_transcripts(self, uuid): await super().get_attacker_transcripts(uuid)
async def get_session_log(self, sid): await super().get_session_log(sid)
@pytest.mark.asyncio
async def test_base_repo_coverage():
@@ -75,6 +77,8 @@ async def test_base_repo_coverage():
await dr.update_user_role("a", "admin")
await dr.purge_logs_and_bounties()
await dr.get_attacker_artifacts("a")
await dr.get_attacker_transcripts("a")
await dr.get_session_log("a")
# Swarm methods: default NotImplementedError on BaseRepository. Covering
# them here keeps the coverage contract honest for the swarm CRUD surface.