Skip to content

Commit 3a2e362

Browse files
committed
Document and present Phase 6 reporting
1 parent 6f9ae31 commit 3a2e362

13 files changed

Lines changed: 313 additions & 29 deletions

ARCHITECTURE.md

Lines changed: 61 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,11 @@ Browser → React UI (static files) → FastAPI → DockGuard → discovery adap
1414
validation request → approval → DockGuard → fixed HTTP recheck
1515
1616
intelligence packet → approval → configured model → advice
17+
18+
reporting snapshot → reports + manifest + DockPack
1719
```
1820

19-
Discovery goes through DockGuard to a target and records what it saw. Detection and correlation go the other way: they read stored state and write findings or relationship snapshots without ever reaching a target. Validation begins with a request that records intent only; a separately noted approval rechecks DockGuard and may send one fixed HTTP-origin probe. Optional intelligence creates an exact stored-data packet first, then a separate approval may send only that packet to the configured model provider. The provider receives no target or tool capability.
21+
Discovery goes through DockGuard to a target and records what it saw. Detection, correlation, and reporting go the other way: they read stored state and write findings, relationship snapshots, or portable reports without ever reaching a target. Validation begins with a request that records intent only; a separately noted approval rechecks DockGuard and may send one fixed HTTP-origin probe. Optional intelligence creates an exact stored-data packet first, then a separate approval may send only that packet to the configured model provider. The provider receives no target or tool capability. Reporting re-verifies retained artifacts and packages them locally without contacting a target or model.
2022

2123
The production image builds the React/Vite application and serves it as static content from the same FastAPI process that exposes `/api`. A named Docker volume holds SQLite at `/var/lib/reddock` and retained evidence at `/var/lib/reddock/evidence`. There is deliberately no reverse proxy, separate frontend service, queue, or remote dependency.
2224

@@ -33,6 +35,7 @@ The production image builds the React/Vite application and serves it as static c
3335
- `backend/app/validation/`: approval-gated validation orchestration and the fixed HTTP-origin profile.
3436
- `backend/app/correlation/`: stored-state correlation, fixed CWE mappings, and RedPath assembly.
3537
- `backend/app/intelligence/`: reviewed evidence packets, provider boundary, structured advice, and run orchestration.
38+
- `backend/app/reporting/`: deterministic snapshot assembly, report rendering, evidence verification, and DockPack packaging.
3639
- `backend/app/evidence.py`: the evidence store.
3740
- `backend/app/models.py` and `schemas.py`: persistence mappings and input/output contracts.
3841
- `frontend/src`: presentation and API client only.
@@ -115,6 +118,7 @@ prepare → execute → parse → normalize → artifacts
115118
- **FindingCorrelation** — a symmetric same-asset or related-asset link whose explanation carries both findings' supporting hashes.
116119
- **FrameworkMapping** — a fixed, versioned detector-rule classification under CWE. It is linked to a finding and its evidence hash but never changes that finding.
117120
- **IntelligenceRun** — one immutable reviewed packet and, after separate approval, one structured advice result. It binds provider identity, prompt version, approval note, timestamps, packet and result hashes, and failure state to the latest completed correlation snapshot.
121+
- **ReportRun** — one immutable, bounded snapshot of completed retained state. It records source counts and the SHA-256 values of the technical JSON, technical Markdown, executive Markdown, evidence manifest, and DockPack, plus failure and restart state.
118122
- **EvidenceRecord** — a hashed pointer to one retained discovery artifact.
119123

120124
**Observation ≠ Finding.** An observation says what happened; a finding says what it means. They remain separate rows, separate lifecycles and separate concepts: discovery alone never produces a finding, detection never edits an observation, and a finding that cites no observation is refused rather than stored. What Phase 2 adds is the arrow between them, not a merge.
@@ -216,6 +220,38 @@ count, and retained run count are bounded. Approval atomically claims one packet
216220
and re-verifies its prompt version and retained packet hash before transmission.
217221
See [ADR 0010](docs/adr/0010-intelligence-is-reviewable-advice.md).
218222

223+
## Reporting boundary
224+
225+
Reporting accepts an empty request and has no target, source selector, model,
226+
prompt, network, subprocess, output path, or archive-name surface:
227+
228+
```text
229+
completed Dockyard state + database-referenced evidence
230+
→ refuse active source runs
231+
→ enumerate bounded source artifacts
232+
→ resolve beneath RedLedger + re-verify every SHA-256
233+
→ freeze canonical snapshot
234+
→ render technical + executive reports
235+
→ build complete evidence manifest
236+
→ package deterministic DockPack
237+
→ retain + hash every output
238+
```
239+
240+
Discovery artifacts come from `EvidenceRecord`; later-phase artifacts come from
241+
the hashes on their completed run records. Validation manifests must describe
242+
the exact fixed raw artifact, and only completed intelligence advice joins the
243+
always-retained reviewed packet. No directory is scanned to discover extra
244+
files. Missing, changed, duplicated, unsafe, or oversized input fails the whole
245+
run rather than creating a partial export.
246+
247+
The snapshot excludes reporting history, so creating a report does not change
248+
the next report's source state. Source queries and evidence verification run
249+
inside one explicit SQLite transaction, so concurrent mutations wait until the
250+
snapshot is frozen. JSON is canonical, ZIP members are sorted, and
251+
timestamps, modes, and compression are fixed. Unchanged retained state produces
252+
byte-identical output. See [ADR 0011](docs/adr/0011-reporting-is-a-deterministic-snapshot.md)
253+
and the [DockPack format](docs/DOCKPACK.md).
254+
219255
## Evidence flow (RedLedger)
220256

221257
Every completed run writes through the same store:
@@ -249,15 +285,22 @@ evidence/<dockyard-id>/intelligence/<intelligence-run-id>/
249285
raw/advice.json schema-validated provider advice
250286
metadata.json provider identity, prompt version, approval, timestamps,
251287
packet and advice hashes
288+
289+
evidence/<dockyard-id>/reporting/<report-run-id>/
290+
normalized/result.json canonical technical snapshot used by every report
291+
technical.md evidence-oriented technical report
292+
executive.md bounded summary without an aggregate risk score
293+
raw/manifest.json complete source-artifact membership and SHA-256 values
294+
raw/dockpack.zip deterministic portable package containing all of the above
252295
```
253296

254297
Paths are built from integer identifiers, a fixed scope name and a validated artifact name, and the resolved destination is checked to be inside its run directory, so no operator input can direct a write elsewhere. Every artifact is SHA-256 hashed. Session material such as cookies is deliberately never retained, and detection has nothing raw to retain because it contacts nothing.
255298

256299
A finding is therefore checkable end to end. `FindingEvidence` names the observations it was drawn from; each of those names its discovery run and that run's hashed `EvidenceRecord`; the detection run records the hash of the normalized result the finding appears in. Which detector produced it, from what observation, during which run, and which hash verifies it are all answerable without leaving the database.
257300

258-
Detection, validation, and correlation artifact hashes are recorded as columns on their runs rather than as `evidence_records` rows, because that table's `discovery_run_id` is NOT NULL and keeping the evolution additive avoids relaxing it in place. Unifying them behind one table is the first job of a future versioned migration.
301+
Detection, validation, correlation, intelligence, and reporting artifact hashes are recorded as columns on their runs rather than as `evidence_records` rows, because that table's `discovery_run_id` is NOT NULL and keeping the evolution additive avoids relaxing it in place. Unifying them behind one table is the first job of a future versioned migration.
259302

260-
Portable exports still belong to later phases; the Phase 3 package is retained locally and is not an export format.
303+
A DockPack is the Phase 6 portable export. It includes the snapshot, both rendered reports, the evidence manifest, and exactly the verified artifacts referenced by the database. The validation package remains one source inside it rather than a competing export format.
261304

262305
## Trust boundaries
263306

@@ -275,6 +318,9 @@ Portable exports still belong to later phases; the Phase 3 package is retained l
275318
| API → intelligence runner | One Dockyard identifier and an empty create body; approval adds only a bounded note. Provider credentials and destinations never come from the API. |
276319
| Intelligence runner → model provider | Only the exact retained packet after approval and provider-identity recheck. The request has no tools or action channel; external endpoints require HTTPS and redirects are refused. |
277320
| Model provider → RedDock | Untrusted, size-bounded JSON. Schema, finding IDs, evidence hashes, and duplicates are validated before the advice is retained. |
321+
| API → reporting runner | One Dockyard identifier and an empty body. The runner reads retained state only and accepts no operator-selected path, source, target, or option. |
322+
| RedLedger → DockPack | Only database-referenced regular files whose resolved paths stay under the evidence root and whose bytes match retained SHA-256 values. Portable member names and total size are bounded. |
323+
| DockPack → operator | Potentially sensitive engagement data. The archive and its member manifest must be verified and handled under the engagement's access controls. |
278324
| RedDock → disk | Writes confined to the database file and the evidence root. |
279325

280326
## Concurrency and restart
@@ -294,6 +340,15 @@ one may be active at a time, a packet may contain 200 findings and 512 KiB, and
294340
provider response is capped at 1 MiB under a fixed 60-second timeout. Startup
295341
marks an interrupted send failed; there is no retry or background queue.
296342

343+
Reporting is synchronous under a single-process creation lock and captures its
344+
database inputs under one explicit transaction. It refuses a snapshot while
345+
discovery, detection, validation, or correlation is active, may retain at most
346+
200 report runs per Dockyard, includes at most 2,000 assets, 20,000 services,
347+
5,000 findings, 20,000 finding-evidence links, 500 validation rows, and 2,000
348+
evidence files, and caps a DockPack at 64 MiB. Query and streaming-read bounds
349+
apply before oversized inputs can be fully materialized. Startup marks an
350+
interrupted report failed and removes its partial reporting directory.
351+
297352
| Detection limit | Value | Why |
298353
| --- | --- | --- |
299354
| Assets per snapshot | 2 000 | A snapshot cannot grow without bound |
@@ -310,8 +365,9 @@ That constraint has already shaped a decision rather than merely being stated: d
310365

311366
## Deterministic core
312367

313-
Nothing in discovery, detection, validation, or correlation is AI-driven.
368+
Nothing in discovery, detection, validation, correlation, or reporting is AI-driven.
314369
Detectors remain deterministic rules over recorded data, and the same input
315-
produces the same findings. Phase 5 intelligence is an optional downstream
370+
produces the same findings; the same unchanged retained state produces the same
371+
report bytes. Phase 5 intelligence is an optional downstream
316372
advice view: it cannot become evidence, change a conclusion, invoke a tool, or
317373
widen scope. RedDock remains fully useful with no model provider configured.

CHANGELOG.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,33 @@
22

33
All notable changes to RedDock are documented here.
44

5+
## [0.7.0] — Phase 6 Reporting
6+
7+
### Added
8+
9+
- Deterministic technical and executive reports generated only from one Dockyard's retained database state and evidence
10+
- A SHA-256 evidence manifest binding the scope snapshot, finding claims, cited run IDs, and every included discovery, detection, validation, correlation, and completed-intelligence artifact
11+
- Portable DockPack ZIP exports containing the technical JSON and Markdown report, executive Markdown report, evidence manifest, and verified source artifacts
12+
- A Reporting workspace for snapshot generation, report history, technical/executive/manifest preview, and DockPack download
13+
- Additive `ReportRun` persistence, interrupted-run recovery, bounded export settings, API coverage, and ADR 0011
14+
- Interactive Swagger UI documentation called out in the roadmap and project presentation, with the OpenAPI 3.1 document available at `/openapi.json`
15+
16+
### Security
17+
18+
- Reporting accepts an empty request only: no target, model, prompt, output path, selector, command, URL, credential, or operator-supplied archive name crosses the boundary
19+
- A snapshot is refused while discovery, detection, validation, or correlation source work is active
20+
- Every source artifact is resolved beneath RedLedger, re-hashed before packaging, and assigned a fixed portable archive path; missing, changed, escaping, duplicated, or oversized input fails closed
21+
- Assets, services, findings, finding-evidence links, validation rows, evidence files, retained report runs, and total DockPack bytes are independently bounded before unbounded materialization
22+
- DockPack members are sorted with fixed timestamps and modes, so unchanged retained state produces byte-identical exports; downloads verify the retained artifact hash again
23+
- Database inputs are captured under one explicit consistent transaction, and restart recovery removes partial report directories containing sensitive material
24+
- Stored target and tool strings remain untrusted data and are rendered inside delimiter-safe literal Markdown code spans, including bare URLs and email addresses
25+
26+
### Testing
27+
28+
- Backend coverage for complete hash linkage, byte reproducibility, archive safety, Dockyard isolation, source tampering, missing evidence, active runs, download tampering, and Markdown neutralization
29+
- Frontend coverage for report generation, previews, manifest display, downloads, empty request bodies, and stale Dockyard response protection
30+
- The end-to-end Docker smoke test now creates two unchanged report snapshots and verifies identical hashes plus the downloaded DockPack bytes
31+
532
## [0.6.0] — Phase 5 Intelligence
633

734
### Added

CONTRIBUTING.md

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
# Contributing
22

3-
Thanks for helping build RedDock. Please keep contributions small, tested, and aligned with the safety model.
3+
RedDock is open source under the MIT License, but it does not currently accept
4+
unsolicited external pull requests. The safety model and phase boundaries are
5+
owner-directed and intentionally closed. Bug reports, design discussion, and
6+
responsible security disclosures remain welcome; accepted implementation work
7+
follows the checks and constraints below.
48

59
## Local checks
610

@@ -10,7 +14,7 @@ cd frontend && npm ci && npm run lint && npm run check && npm run test && npm ru
1014
docker compose build
1115
```
1216

13-
Backend development needs Python 3.13; running RedDock itself needs only Docker. To verify the full discovery and detection path end to end against loopback:
17+
Backend development needs Python 3.13; running RedDock itself needs only Docker. To verify the complete discovery-through-reporting path end to end against loopback:
1418

1519
```bash
1620
docker compose up -d --build && python scripts/smoke_test.py
@@ -21,8 +25,12 @@ docker compose up -d --build && python scripts/smoke_test.py
2125
- Do not add exploitation, credential attacks, active vulnerability testing, or autonomous execution without an approved phase and DockGuard design.
2226
- Every target must reach a tool through DockGuard. Never pass operator-supplied values to a subprocess as flags, and never build a command string.
2327
- An adapter records what was observed. A detector says what it means, from stored observations only: it may not open a socket, start a process or reach the database, and a finding it produces must cite the observations behind it.
28+
- A report reads retained state only. Do not add a target, arbitrary source selector, output path, network request, dynamic template, or executable archive member; every included source artifact must be database-referenced and hash-verified.
2429
- Do not inflate a rating. A missing hardening header is not a high, a version banner is not a vulnerability, and a CVE association is not a test result.
2530
- Preserve the API/domain/persistence/UI boundaries.
2631
- Add tests for observable behavior and update documentation when behavior changes.
2732
- Use clear names and explain non-obvious safety decisions.
2833

34+
Opening an issue or discussion does not authorize active testing against any
35+
system. Report suspected vulnerabilities through the private process described
36+
in [SECURITY.md](SECURITY.md), not in a public issue.

LICENSE

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
MIT License
22

3-
Copyright (c) 2026 RedDock contributors
3+
Copyright (c) 2026 Chris Hickman
44

55
Permission is hereby granted, free of charge, to any person obtaining a copy
66
of this software and associated documentation files (the "Software"), to deal
@@ -19,4 +19,3 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1919
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2020
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2121
SOFTWARE.
22-

0 commit comments

Comments
 (0)