Control Framework¶
| Status | IMPLEMENTED: 48 controls, catalogue 0.1.0. The catalogue is a default: review and adapt it with your control owner, usually the AppSec lead |
| Source of truth | catalogue/controls/controls.yaml → rendered as control-catalogue.md |
| Related | SAMM/ASVS mapping, Evidence model, ADR-002, ADR-003, ADR-004 |
1. Design principle¶
CONTROL → TEST → EVIDENCE → RISK → REMEDIATION → RE-TEST
Every control answers: "How will the organisation prove that this control is actually operating?" The answer is in each control's
prooffield and is checked by the validator: a control whose required evidence confidence cannot be produced by its evidence types fails CI.
2. Layered model¶
Frameworks are not implemented directly. They are mapped onto one internal control catalogue, so overlapping requirements are implemented and evidenced once.
┌─────────────── Framework layer (OFFICIAL — referenced, never rewritten) ───────────────┐
│ OWASP SAMM 2.0 activity ASVS 5.0 requirement NIST SSDF task CSF 2.0 sub │
└───────────────▲───────────────────────▲────────────────────▲──────────────────▲────────┘
│ maps to (many-to-many, with "contributes to" semantics) │
┌───────────────┴──────────── Internal control (ORGANISATION-SPECIFIC) ─────────┴───────┐
│ ASC-BLD-01 "SAST executes on every change to the default branch" │
│ · applicability (tier × conditions) · objective type · owner · exception rules │
└───────────────────────────────────────────┬───────────────────────────────────────────┘
│ assessed by
┌───────────────────────────────────────────▼───────────────────────────────────────────┐
│ Technical requirement + Test = evaluator rule (versioned code) + params │
│ scan_executed@1 {language_coverage: all_detected, query_suite: security-extended} │
└───────────────────────────────────────────┬───────────────────────────────────────────┘
│ consumes
┌───────────────────────────────────────────▼───────────────────────────────────────────┐
│ Evidence (typed, confidence-graded, fresh/expired, hash-linked to raw artefact) │
└───────────────────────────────────────────┬───────────────────────────────────────────┘
│ produces
┌───────────────────────────────────────────▼───────────────────────────────────────────┐
│ Control state (per app × control × scope) ──▶ gap = finding (type: control_gap) │
│ Scan results ──▶ findings ──▶ risk priority ──▶ ticket ──▶ remediation ──▶ re-scan │
└───────────────────────────────────────────────────────────────────────────────────────┘
Two separate questions, deliberately separated:
- Is the control operating? (e.g. SAST ran on HEAD with the right configuration.) This produces control state.
- What did it find, and is that being handled? This produces findings → risk → SLA, which feed outcome controls (ASC-VUL-*).
A scan that finds 40 vulnerabilities is a SAST control that is satisfied. Penalising detection teaches teams to stop detecting (TOM section 7).
3. Application classification model¶
Configuration: config/profiles/<profile>/classification.yaml. It is transparent and two-step:
- Floor rules. Any match sets a minimum tier. Example: internet-facing + special-category personal data → at least Tier 1.
- Points. Seven dimensions (data classification, personal data, exposure, user population, business criticality, privileged integration, regulatory) are summed and mapped to a tier by threshold.
Final tier = the more critical of the two. The computation (inputs, matched rules, points, model version) is stored and shown to the owner. Tier labels, thresholds and ASVS targets are configuration, not code. Downgrades below the computed tier need an approved override.
The tier drives: which controls are mandatory, recommended or n/a; per-tier thresholds (approvals, query suite, pen-test frequency); the minimum evidence confidence (e.g. Tier 1 threat-model review must be independent, M2); exception maximum duration and approver; and the risk-model impact base.
4. Control attributes¶
| Attribute | Meaning |
|---|---|
objective_type |
configuration: the setting is the control (branch rules). activity: something must execute (SAST). outcome: a measured result (SLA compliance). process: a human process occurred (architecture review). |
applicability.tiers |
mandatory / recommended / n/a per tier |
applicability.conditions |
Profile facts derived from discovery + application.yaml: has_source_code, has_iac, uses_dependencies, builds_or_deploys_containers, has_api, has_web_ui_or_api, deployed, has_cloud_scope, publishes_artifacts, has_workflows, has_third_party_services, deployed_via_github, has_sbom_capable_stack, lifecycle_retired |
assessment.mode |
automated: no human input. hybrid: automated evaluation of evidence that includes a human step. manual: human assessment recorded in the platform. |
assessment.min_confidence |
Lowest evidence confidence that can satisfy the control (scalar or per tier). See the evidence model. |
proof |
How operation is proven. Mandatory. |
exception |
Whether exceptions are allowed and their maximum duration per tier. Some controls (exposed secrets, malicious packages, registration) allow no exception. |
5. Control state model¶
Each (application, control, scope) has exactly one current state. Scope is usually a repository, sometimes an artifact or cloud scope; app-level state is the worst scope state, with per-scope drill-down.
| State | Meaning | Counts toward maturity? |
|---|---|---|
SATISFIED |
Fresh evidence at ≥ min confidence; rule passed | Yes |
PARTIAL |
Rule passed for some scopes or some criteria (e.g. 2 of 3 languages) | Pro-rata |
NOT_SATISFIED |
Fresh evidence shows the rule failed | No |
STALE |
Evidence exists but is expired or superseded | No |
NO_EVIDENCE |
No evidence of sufficient confidence | No |
EXCEPTED |
Active approved exception covers it | No (reported separately: an exception is a risk decision, not maturity) |
NOT_APPLICABLE |
The applicability rule says n/a, or an approved N/A justification exists | Excluded from the denominator |
ERROR |
The evaluator could not run (connector down) | Last known state shown, flagged |
Every transition is an append-only control_evaluations row: rule version, catalogue version, evidence IDs used, and a human-readable explanation, e.g. "NOT_SATISFIED: CodeQL analysis covers python, javascript; repository also contains go (detected 2026-10-01). Evidence EV-… commit 3f2a…".
Control gaps become findings. A mandatory control in NOT_SATISFIED, STALE or NO_EVIDENCE for more than its grace period (default 14 days after onboarding baseline) creates a finding of type control_gap. It enters the same risk, SLA and Jira pipeline as vulnerabilities.
6. Catalogue governance¶
| Aspect | Rule |
|---|---|
| Change process | PR to catalogue/ with CODEOWNERS = AppSec governance. CI runs tools/catalogue/validate.py --check. |
| Versioning | SemVer. Major: a new mandatory control or a stricter threshold (requires a comms plan and grace period). Minor: new recommended control or mapping. Patch: wording. |
| Grace periods | A new or stricter mandatory control starts in observe mode for ≥ 30 days. State is computed and shown but does not create findings or affect maturity. |
| Review | Every control is reviewed every review_months (default 12). The catalogue owner signs off annually. |
| Retirement | Controls are deprecated, never deleted. Historical evaluations keep their meaning. |
| Mapping integrity | SAMM streams and evidence types are validated against registries. ASVS chapter references now; requirement-level references after the official ASVS 5.0 import (E12). |
7. Official vs organisation-specific content¶
| Content | Classification | Handling |
|---|---|---|
| SAMM business functions, practices, streams, activity descriptions, questions | Official | Imported from the official model at a pinned version. Never paraphrased in the UI. |
| ASVS requirements and levels | Official | Imported from the official ASVS 5.0 release artefacts |
| SSDF tasks, CSF subcategories | Official | IDs only, linked to source |
| Control IDs, wording, thresholds, applicability, evidence rules, tiers, SLAs, risk model | Organisation-specific | This repository. Approved by the catalogue owner. |
| Mapping of internal controls to official items | Organisation-specific judgement | Each mapping means "provides evidence towards", never "fully satisfies" |