Commit graph

2 commits

Author SHA1 Message Date
b7b985d96d Implement hosted Breach/Compliance Record publication (WP-0006-T09)
migrations/0004_breach_records.sql models a case's lifecycle as
append-only events (alleged/cured/determined/terminated) grouped by
case_id rather than one mutable row - resolution is always a new,
later event, never an edit. A CHECK constraint makes the
anonymized-default rule (License V1C1 §7.4) a database fact:
named_entitlement_holder can be set if and only if anonymized = false.

src/target_revenue/breach_record.py's publish_breach_event() enforces
per-Licensor phase ownership and rejects named-disclosure requests
that don't also set named_disclosure_authorized_under_cua: true - the
Trust Service records the Licensor's assertion that the CUA's naming
clause authorizes it, it never verifies the underlying CUA text
itself. Signs every event with the same instance Ed25519 key already
used for Ledger entries and Attestations.

Adds POST/GET /phases/{id}/breach-records. Guarded the .registry
import behind a lazy in-function import (matching attestation.py's
TYPE_CHECKING pattern) so tests/test_breach_record.py (7 tests) runs
under plain system Python with no psycopg dependency. 5 new
Docker-gated tests cover the default-anonymized lifecycle, the
named-disclosure authorization gate, cross-Licensor rejection,
signature verification, and DB-level UPDATE/DELETE rejection.

This closes WP-0006 again - all 9 tasks done.
2026-07-29 22:23:41 +02:00
ee4cf14cbc Define and implement multi-repo onboarding mechanism (WP-0006-T07)
specs/TrustServiceOnboarding.md defines the mechanism: a Phase Manifest
file is committed to the declaring repo (durable, independently
foldable forever) and separately registered with the hosted service;
once registered, the Ledger's live authoritative copy is the hosted
service only, not a second competing file. Licensor token bootstrapping
is explicitly out of scope here (a WP-0008-T01 governance action).

scripts/trf_onboard.py: a dependency-light CLI (stdlib urllib +
target_revenue.validation only, no FastAPI/psycopg needed to onboard a
Phase) with validate/register-phase/append-entry/status subcommands.
The Licensor token is read only from a named environment variable,
never accepted as a literal argument.

tests/test_trf_onboard.py (4 tests, no network/Docker) proves
invalid-manifest and missing-token-env cases fail before any HTTP
attempt, by monkeypatching the request function to raise if called.
tests/test_onboarding_hosted.py (1 Docker-gated test) runs an actual
uvicorn server on a real socket and drives the full
register -> append -> status round trip through the CLI as an external
repo would invoke it.
2026-07-29 22:00:34 +02:00