secunit_core/risks.rs
1//! Risk register: an append-only, hash-chained event log per risk, plus a
2//! derived `risks/index.json` cache.
3//!
4//! The register lives inside the store at `risks/<risk-id>/events.jsonl`
5//! (one immutable JSON Lines event per line) and is the authoritative
6//! source of a risk's state — current state is never stored, it is *folded*
7//! from the events. `index.json` is a regenerable projection, the same role
8//! `state.json` plays for runs. Full design in `docs/risks.md`; the on-disk
9//! contract in `docs/storage.md` (the "Risk register (`risks/`)" section).
10//!
11//! The integrity model mirrors evidence manifests:
12//!
13//! - Each event carries `prev_sha256`, the SHA-256 of the previous
14//! canonicalised line (compact JSON), forming a per-risk hash chain —
15//! exactly like `prior_run.manifest_sha256` chains manifests. Lines are
16//! only ever appended; corrections are new events, never edits.
17//! - `index.json` is mutable, outside the chain, and rebuilt from the logs
18//! with [`store::rebuild`].
19//!
20//! Module layout (mirrors `evidence`):
21//!
22//! - [`model`] — strongly-typed event envelope, payloads, and [`RiskState`].
23//! - [`fold`] — the deterministic left-fold and the status machine.
24//! - [`store`] — on-disk append protocol, id allocation, loading, and the
25//! index build/rebuild.
26
27pub mod fold;
28pub mod model;
29pub mod store;
30
31// Re-export the surface most callers (verify, CLI, GUI) want at
32// `secunit_core::risks::*` so they don't have to thread the submodule path.
33pub use fold::{fold, fold_at, validate_transition, TransitionError};
34pub use model::{
35 Agent, EventData, EventEnvelope, ExternalLink, FindingRef, RiskEvent, RiskState, Severity,
36 Status,
37};
38pub use store::{
39 append, build_index, build_index_lenient, load_events, load_register, open, rebuild, risk_ids,
40 verify_finding_ref, AppendOutcome, OpenOutcome, Register, RiskIndex, RiskIndexEntry,
41};