E05: Security Control Catalogue¶
Goal: A governed, versioned, machine-readable control catalogue that drives evaluation.
F01: Catalogue as code¶
E05-F01-S01: Catalogue review and v0.2 · M · Phase 0¶
- See E01-F01-S02 (Board approval). Engineering side: incorporate amendments, keep the validator green.
E05-F01-S02: Validator and renderer in CI · M · Phase 1¶
- Story: As the catalogue owner, I want every catalogue/config PR validated and the rendered catalogue kept in sync, so that broken or unsatisfiable controls never merge.
- Technical:
tools/catalogue/validate.py --checkin CI. Extend checks toconfig/risk-model.yaml(expression syntax via the CEL parser),config/profiles/<profile>/classification.yamland trusted producers. - AC: A PR introducing an unknown evidence type, unknown SAMM stream or unreachable confidence fails CI with a clear message. A stale rendered doc fails CI.
- Tests: Negative fixtures for each check.
- Stage 1 progress: IMPLEMENTED for the catalogue (48 controls validate; it caught a real modelling error in threat-model evidence). Config validation IMPLEMENTED in
tools/config/validate.py(trusted producers, SAMM targets, exception policy, classification, risk model, licence policy, maturity bands, ASVS applicability, templates, OpenAPI). Risk-model expression compilation pending E13-F01-S01.
F02: Catalogue loading¶
E05-F02-S01: Load catalogue and config into config_versions · M · Phase 1¶
- Story: As the evaluator, I need the active catalogue and config versions loaded by git SHA, so that every evaluation is reproducible.
- Technical: Loader job reads files at a release SHA →
config_versions(content hash),controls,control_framework_mappings,control_applicability. Activation is an explicit step (one active per kind). - AC: Loading the same SHA twice is a no-op. Activation is audited. Evaluations reference
catalogue_version_id. - Security: Runtime edits are impossible (no API to edit controls). Only the loader writes these tables (T-12).
- Tests: Loader idempotency. Activation constraint (
config_versions_one_active).
E05-F02-S02: Observe mode and grace periods · M · Phase 4¶
- Story: As the Board, I want new or tightened mandatory controls to start in observe mode for ≥ 30 days, so that teams see impact before it counts.
- AC: Controls flagged
observe_untilproduce states withobserve_mode=true, are excluded from maturity and gap findings, and are visibly labelled in the UI.
F03: Control gap findings¶
E05-F03-S01: Create control_gap findings after the grace period · M · Phase 4¶
- Story: As AppSec lead, I want mandatory controls failing beyond the grace period to become findings, so that gaps enter the same SLA and ticket flow as vulnerabilities.
- AC: Fingerprint
gap|app|control|scope. One finding per gap (dedup). Auto-closes when the control is satisfied (closure evidence = the satisfying evaluation). Respects active exceptions. - Tests: Lifecycle tests including flapping (satisfied → not → satisfied) without duplicate findings.
E05-F03-S02: Applicability engine · M · Phase 4¶
- Story: As the evaluator, I need to know which controls apply to an app (tier × conditions), so that teams are not asked for irrelevant controls.
- AC: The conditions vocabulary (control framework section 4) is derived from profile + detection. Unknown conditions fail the catalogue validator. The applicability explanation is shown per control.