#423: Download marking for leak tracing — pseudonymous marks, Trace tab, legality docs #444

Merged
Cordy merged 9 commits from download-marks-423 into main 2026-09-07 00:43:25 +00:00
Owner

Implements #423 per the approved rev-2 mockup and the legality research posted to the issue.

Backend (TDD, witnessed compile-red on the runner): new internal/marks package — append-only JSONL ledger with a per-store HMAC secret and audit-coupled retention; CAIRNMARK1.<id>.<sig> tokens carrying a random id and its signature but never identity; O(1)-memory seek-preserving marking of PDF (trailing comment), Office zips (EOCD comment), PNG (tEXt before IEND) and JPEG (COM after SOI), with the original served untouched whenever a container does not validate. Storage decorator above audit marks authenticated reads only. Settings gain markDownloads (off by default, gated on the audit toggle at runtime). API: GET /api/v1/admin/audit/marks and POST /api/v1/admin/audit/trace (extract → verify → ledger lookup, audited as mark-trace; new marks verb group in the registry).

Frontend: nested settings toggle with honest description + amber legal line; Trace tab present only while marking is enabled or historic marks remain traceable; drop zone → four result cards (hit / pruned ledger / foreign signature / no mark), hit card links to Query prefilled with the path and states the evidence-not-verdict caveat. i18n ×4.

Docs: docs/handbook/leak-tracing.md with the per-country legality table (research snapshot 2026-09-07) and a model user notice; ARCHITECTURE decorator entry; CHANGELOG v0.6.137.

Design decisions recorded in the issue on close: no per-download audit verb (ledger is the record), no content hash in v1, Stat not wrapped (sync-size caveat documented).

Implements #423 per the approved rev-2 mockup and the legality research posted to the issue. **Backend (TDD, witnessed compile-red on the runner):** new `internal/marks` package — append-only JSONL ledger with a per-store HMAC secret and audit-coupled retention; `CAIRNMARK1.<id>.<sig>` tokens carrying a random id and its signature but never identity; O(1)-memory seek-preserving marking of PDF (trailing comment), Office zips (EOCD comment), PNG (tEXt before IEND) and JPEG (COM after SOI), with the original served untouched whenever a container does not validate. Storage decorator above audit marks authenticated reads only. Settings gain `markDownloads` (off by default, gated on the audit toggle at runtime). API: `GET /api/v1/admin/audit/marks` and `POST /api/v1/admin/audit/trace` (extract → verify → ledger lookup, audited as `mark-trace`; new `marks` verb group in the registry). **Frontend:** nested settings toggle with honest description + amber legal line; Trace tab present only while marking is enabled or historic marks remain traceable; drop zone → four result cards (hit / pruned ledger / foreign signature / no mark), hit card links to Query prefilled with the path and states the evidence-not-verdict caveat. i18n ×4. **Docs:** `docs/handbook/leak-tracing.md` with the per-country legality table (research snapshot 2026-09-07) and a model user notice; ARCHITECTURE decorator entry; CHANGELOG v0.6.137. Design decisions recorded in the issue on close: no per-download audit verb (ledger is the record), no content hash in v1, Stat not wrapped (sync-size caveat documented).
Compile-red against main: the marks package does not exist. Every marked
output must remain a valid file of its format (archive/zip, image/png,
image/jpeg still parse it), carry a findable HMAC-signed pseudonymous
token, seek correctly (WebDAV range requests), and the ledger must map
the id back to the download across a store reopen. A foreign server's
token is found but reports an invalid signature.
internal/marks: append-only JSONL ledger (audit-coupled retention, per-store HMAC secret), CAIRNMARK1 tokens carrying a random id and its signature but never identity, and O(1)-memory seekable marking of PDF (post-EOF comment), Office zips (EOCD comment), PNG (tEXt before IEND) and JPEG (COM after SOI) - a container the embedder refuses is served untouched, and marked outputs stay valid files (proven by archive/zip, image/png, image/jpeg in the red tests). Storage decorator above audit marks authenticated reads only; settings gain markDownloads, gated on the audit toggle at runtime. API: GET /admin/audit/marks (tab visibility) and POST /admin/audit/trace (extract + verify + ledger lookup, audited as mark-trace; registered in the verb registry under the new marks group).

TDD: marks package witnessed compile-red on the runner; format-validity, seek, ledger-persistence and foreign-signature tests all green after splice.
Settings: 'Mark downloads for leak tracing' nested under the audit toggle, off by default, with an honest description and an amber legal line pointing at the handbook's per-country table. Audit page: a Trace tab that exists only while marking is enabled or historic marks remain traceable; drop a leaked file and the server names the one download it originates from - downloaded-by, path, mark id, plus a link that prefills Query with the path for the full candidate list. The hit card says out loud what a trace does not prove (compromised credentials or device produce the same trace) - evidence, not verdict. Foreign-signature and pruned-ledger results get their own cards. i18n x4.

Rev-2 mockup approved 2026-09-07.
#423: CHANGELOG v0.6.137 + ARCHITECTURE marks-decorator entry
All checks were successful
ci / test-and-build (pull_request) Successful in 44s
fbf9f63fd3
Cordy merged commit 3e7b4fbdc9 into main 2026-09-07 00:43:25 +00:00
Cordy deleted branch download-marks-423 2026-09-07 00:43:27 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: Cordy/Cairn#444
No description provided.