Decisions
ADR-0028: Proven's code is security-reviewed as a whole, in pieces, each piece one trust boundary
Status: accepted · Date: 2026-10-23
Decided by: the owner · Written by: the advisor (claude-code, claude-opus-5-5), 2026-10-23
Follows: ADR-0005, ADR-0007, ADR-0025, ADR-0026
Trigger: the owner, 23 October: "Maybe start a systematic security review? We do it in pieces, but a whole one."
Context
Each change to Proven gets two independent reviews of its diff. By the second build day the code held over twenty packages written by several executors, and no review had looked at it as a whole. Proven runs code from the change it reviews, holds keys, asks models about untrusted text and posts to pull requests, so a property can be broken by the way the pieces fit together without any one diff breaking it.
Decision
- The code is reviewed as a whole, in nine pieces, each one boundary where something untrusted meets something Proven protects: tools first; the Prover's container; secrets; the reviewed repository as input; evidence queries; models; output and CI; the lab and the images; data on disk. Their properties are listed in SECURITY_REVIEW.md.
- Pieces 0, 1 and 2 go first, then two or three a day.
- Each piece gets two independent reviews by different models, phrased as the property that must hold and the proof expected, never as an attack.
- A weakness becomes a fix in the train that owns the code, proved by a test that fails before and passes after.
- Two public documents at the repository's root:
SECURITY.md(what the product protects and how, and how to report a vulnerability) andSECURITY_REVIEW.md(this process and each piece's status). - A weakness is published only after its fix is merged.
Consequences
- The judges can read what Proven protects, how it was checked, and what was fixed.
- Review seats spend part of the build week on the pieces; fixes compete with features for executor time.
SECURITY.mdmust follow the code: a protection it describes is one that is onmain, or it says it is not yet.