Skip to content

Commit 8795601

Browse files
Ibraheem OlasupoIbraheem Olasupo
authored andcommitted
Implement milestone 9 vulnerability lifecycle and exception governance
1 parent 88d82b2 commit 8795601

102 files changed

Lines changed: 7903 additions & 126 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
name: Vulnerability Lifecycle
2+
3+
on:
4+
pull_request:
5+
branches: ["main"]
6+
push:
7+
branches: ["main"]
8+
9+
permissions:
10+
contents: read
11+
12+
concurrency:
13+
group: vulnerability-lifecycle-${{ github.workflow }}-${{ github.ref }}
14+
cancel-in-progress: true
15+
16+
jobs:
17+
lifecycle:
18+
runs-on: ubuntu-24.04
19+
timeout-minutes: 15
20+
steps:
21+
# actions/checkout v4.2.2
22+
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
23+
24+
# actions/setup-python v5.6.0
25+
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065
26+
with:
27+
python-version: "3.11"
28+
cache: "pip"
29+
30+
- name: Install dependencies
31+
run: |
32+
python -m pip install --upgrade pip==25.1.1
33+
python -m pip install -e ".[dev]"
34+
35+
- name: Source evidence verification
36+
run: make verify-findings-evidence verify-release-evidence
37+
38+
- name: Lifecycle governance tests
39+
run: pytest tests/security/test_lifecycle_governance.py -q
40+
41+
- name: Vulnerability lifecycle
42+
run: make lifecycle-full

CONTRIBUTING.md

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

3-
This portfolio repository is a local demonstration of a secure product foundation. Contributions should preserve the delivered milestone boundaries and avoid adding cloud deployment, formal exception workflow or vulnerability-management operations before their roadmap milestone.
3+
This portfolio repository is a local demonstration of a secure product foundation. Contributions should preserve the delivered milestone boundaries and avoid adding cloud deployment, production vulnerability-management operations or Security Champions workflow before their roadmap milestone.
44

55
## Local Checks
66

@@ -12,6 +12,7 @@ make appsec-fast
1212
make dynamic-fast
1313
make findings-full
1414
make release-full
15+
make lifecycle-full
1516
```
1617

1718
Use deterministic synthetic data only. Do not add real patient, NHS, genomic, credential, or cloud account data.
@@ -27,3 +28,4 @@ Use deterministic synthetic data only. Do not add real patient, NHS, genomic, cr
2728
- Do not add broad scanner suppressions. Use `security/config/suppressions.yaml` with an owner, expiry and exact path or rule scope.
2829
- Keep findings IDs deterministic and avoid absolute local paths, raw JWTs, private keys or real data in canonical findings outputs.
2930
- Keep release-gate evidence deterministic. Use `make release-gate-enforce` only when you intentionally want enforcement exit codes; evidence-mode release targets must still run for block and conditional decisions.
31+
- Keep lifecycle evidence deterministic. Scanner suppressions may inform lifecycle records, but only security exceptions under `config/lifecycle/` and `outputs/security/lifecycle/` may support risk acceptance or deferral.

Makefile

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
.PHONY: setup install format format-check lint type-check test test-coverage auth-test api-security-test terraform-fmt terraform-fmt-check terraform-init terraform-validate terraform-test infrastructure-test infrastructure-evidence verify-infrastructure-evidence infrastructure-report security-tools secrets-scan sast sast-semgrep sast-bandit semgrep-test sca dependency-audit sbom verify-sbom iac-scan checkov-scan container-build-security container-scan appsec-fast appsec-full appsec-evidence verify-appsec-evidence appsec-report dynamic-tools dynamic-server-start dynamic-server-wait dynamic-server-stop schemathesis-test api-schema-security-test zap-baseline zap-api-scan auth-boundary-test authorisation-boundary-test object-access-test input-mutation-test security-header-test cors-test resource-consumption-test audit-dynamic-test dast dynamic-evidence verify-dynamic-evidence dynamic-report dynamic-fast dynamic-full findings-normalise findings-deduplicate findings-enrich findings-validate findings-evidence verify-findings-evidence findings-report findings-full release-policy-validate release-gate-evaluate release-gate-enforce release-evidence verify-release-evidence release-report release-full pre-commit-install pre-commit-run quality run docker-build docker-run threat-model-validate threat-model-evidence verify-threat-model-evidence threat-model-report api-security-evidence verify-api-security-evidence api-security-report dev-token-researcher dev-token-approver dev-token-auditor clean
1+
.PHONY: setup install format format-check lint type-check test test-coverage auth-test api-security-test terraform-fmt terraform-fmt-check terraform-init terraform-validate terraform-test infrastructure-test infrastructure-evidence verify-infrastructure-evidence infrastructure-report security-tools secrets-scan sast sast-semgrep sast-bandit semgrep-test sca dependency-audit sbom verify-sbom iac-scan checkov-scan container-build-security container-scan appsec-fast appsec-full appsec-evidence verify-appsec-evidence appsec-report dynamic-tools dynamic-server-start dynamic-server-wait dynamic-server-stop schemathesis-test api-schema-security-test zap-baseline zap-api-scan auth-boundary-test authorisation-boundary-test object-access-test input-mutation-test security-header-test cors-test resource-consumption-test audit-dynamic-test dast dynamic-evidence verify-dynamic-evidence dynamic-report dynamic-fast dynamic-full findings-normalise findings-deduplicate findings-enrich findings-validate findings-evidence verify-findings-evidence findings-report findings-full release-policy-validate release-gate-evaluate release-gate-enforce release-evidence verify-release-evidence release-report release-full lifecycle-policy-validate lifecycle-initialise lifecycle-validate lifecycle-expiry lifecycle-evidence verify-lifecycle-evidence lifecycle-report lifecycle-full pre-commit-install pre-commit-run quality run docker-build docker-run threat-model-validate threat-model-evidence verify-threat-model-evidence threat-model-report api-security-evidence verify-api-security-evidence api-security-report dev-token-researcher dev-token-approver dev-token-auditor clean
22

33
PYTHON ?= python3
44
VENV ?= .venv
@@ -228,6 +228,29 @@ release-report:
228228
release-full:
229229
PYTHONPATH=src $(PYTHON) -m genomic_research_access_api.security.release full --timestamp 2026-01-01T00:00:00Z --as-of-date 2026-01-01 --environment dev
230230

231+
lifecycle-policy-validate:
232+
PYTHONPATH=src $(PYTHON) -m genomic_research_access_api.security.lifecycle validate
233+
234+
lifecycle-initialise:
235+
PYTHONPATH=src $(PYTHON) -m genomic_research_access_api.security.lifecycle initialise --timestamp 2026-01-01T00:00:00Z --as-of-date 2026-01-01
236+
237+
lifecycle-validate:
238+
PYTHONPATH=src $(PYTHON) -m genomic_research_access_api.security.lifecycle initialise --timestamp 2026-01-01T00:00:00Z --as-of-date 2026-01-01
239+
240+
lifecycle-expiry:
241+
PYTHONPATH=src $(PYTHON) -m genomic_research_access_api.security.lifecycle evaluate-expiry --timestamp 2026-01-01T00:00:00Z --as-of-date 2026-01-01
242+
243+
lifecycle-evidence:
244+
PYTHONPATH=src $(PYTHON) -m genomic_research_access_api.security.lifecycle generate-evidence --timestamp 2026-01-01T00:00:00Z --as-of-date 2026-01-01
245+
246+
verify-lifecycle-evidence:
247+
PYTHONPATH=src $(PYTHON) -m genomic_research_access_api.security.lifecycle verify-evidence
248+
249+
lifecycle-report:
250+
PYTHONPATH=src $(PYTHON) -m genomic_research_access_api.security.lifecycle generate-reports
251+
252+
lifecycle-full: verify-findings-evidence verify-release-evidence lifecycle-policy-validate lifecycle-initialise lifecycle-expiry lifecycle-validate lifecycle-evidence verify-lifecycle-evidence lifecycle-report
253+
231254
pre-commit-install:
232255
$(PYTHON) -m pip install pre-commit==3.8.0
233256
$(VENV)/bin/pre-commit install

README.md

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ It is not a production genomics platform.
88

99
It is not affiliated with or endorsed by Genomics England.
1010

11-
AWS infrastructure is provided as non-deployed Terraform. External identity-provider integration, cloud deployment, formal exception workflow and vulnerability-management operations are deferred to later milestones.
11+
AWS infrastructure is provided as non-deployed Terraform. External identity-provider integration, cloud deployment and Security Champions operations are deferred to later milestones.
1212

1313
## Problem Statement
1414

@@ -32,6 +32,8 @@ Milestone 7 adds canonical findings normalisation and risk enrichment across thr
3232

3333
Milestone 8 adds risk-based release gates over the Milestone 7 canonical findings. It produces deterministic release decisions, rule evaluations, approval requirements, action lists, risk summaries and reports. Evidence generation succeeds for blocked and conditional decisions; enforcement is a separate command. It does not deploy, push containers, create AWS resources, or implement a formal exception workflow.
3434

35+
Milestone 9 adds deterministic vulnerability lifecycle and exception governance over canonical findings and release outputs. It produces a vulnerability register, lifecycle history, security exception register, expiry reports, verification evidence, audit reports and a pinned lifecycle workflow. It does not start Security Champions, deploy, push containers, create AWS resources, commit or push.
36+
3537
## Milestone 1 Scope
3638

3739
Implemented:
@@ -125,6 +127,22 @@ Implemented as local release-assurance policy and evidence:
125127

126128
Not implemented in Milestone 8: formal exception workflow, deployment approval system, vulnerability lifecycle ownership process, artefact signing/provenance, AWS deployment, container push or production release automation.
127129

130+
## Milestone 9 Scope
131+
132+
Implemented as local governance, evidence and reports:
133+
134+
- Controlled vulnerability lifecycle states and transition policy.
135+
- Deterministic vulnerability register generated from canonical findings.
136+
- Role-based history entries without personal actor identifiers.
137+
- Verification-before-closure enforcement.
138+
- False-positive governance with rationale and evidence.
139+
- Formal time-bound security exceptions for risk acceptance and deferral.
140+
- Exception expiry, expiring-soon and expired-exception outputs.
141+
- Lifecycle evidence manifest with deterministic checksums.
142+
- Lifecycle Markdown reports and a pinned CI workflow.
143+
144+
Not implemented in Milestone 9: Security Champions, production ticketing integration, deployment approvals, artefact signing/provenance, AWS deployment, container push or production vulnerability-management operations.
145+
128146
## API Capabilities
129147

130148
- `GET /health`
@@ -204,6 +222,14 @@ Open `http://127.0.0.1:8000/docs` for FastAPI's local OpenAPI UI.
204222
- `make release-report`: generate release-assurance Markdown reports.
205223
- `make release-full`: generate, verify and report release-assurance evidence.
206224
- `make release-gate-enforce`: enforce the current release decision and return nonzero for block or missing conditional approvals.
225+
- `make lifecycle-policy-validate`: validate lifecycle, transition, verification, exception, ownership and role policy.
226+
- `make lifecycle-initialise`: initialise the vulnerability register from canonical findings.
227+
- `make lifecycle-validate`: validate lifecycle records and exception references.
228+
- `make lifecycle-expiry`: evaluate exception expiry and lifecycle reactivation state.
229+
- `make lifecycle-evidence`: generate deterministic lifecycle evidence.
230+
- `make verify-lifecycle-evidence`: verify lifecycle evidence checksums and determinism.
231+
- `make lifecycle-report`: generate lifecycle governance reports.
232+
- `make lifecycle-full`: verify findings and release evidence, then run the full lifecycle workflow.
207233
- `make secrets-scan`: run Gitleaks via local binary or pinned container.
208234
- `make semgrep-test`: run Semgrep custom rule tests.
209235
- `make sast`: run Semgrep and Bandit.

SECURITY.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ If you identify a vulnerability or unsafe pattern in this demonstration code, op
66

77
Do not submit real patient data, NHS data, genomic data, credentials, cloud account identifiers, or sensitive operational details in reports.
88

9-
Current implemented security controls include local JWT authentication, role-based and object-level authorisation, threat-model validation, non-deployed Terraform reference controls, a Milestone 5 AppSec pipeline, Milestone 6 local dynamic API security validation, Milestone 7 canonical findings normalisation, and Milestone 8 local release-assurance gates.
9+
Current implemented security controls include local JWT authentication, role-based and object-level authorisation, threat-model validation, non-deployed Terraform reference controls, a Milestone 5 AppSec pipeline, Milestone 6 local dynamic API security validation, Milestone 7 canonical findings normalisation, Milestone 8 local release-assurance gates, and Milestone 9 vulnerability lifecycle and exception governance.
1010

1111
Run local security checks with:
1212

@@ -16,6 +16,7 @@ make appsec-fast
1616
make dynamic-fast
1717
make findings-full
1818
make release-full
19+
make lifecycle-full
1920
```
2021

21-
Docker-backed Gitleaks, Trivy, Schemathesis and ZAP scans require a running Docker daemon when native binaries or scanner containers are used. Dynamic scan targets must remain local-only. Do not treat local scanner, findings or release evidence as a production vulnerability-management programme, penetration test, formal exception workflow or deployment approval system.
22+
Docker-backed Gitleaks, Trivy, Schemathesis and ZAP scans require a running Docker daemon when native binaries or scanner containers are used. Dynamic scan targets must remain local-only. Do not treat local scanner, findings, release or lifecycle evidence as a production vulnerability-management programme, penetration test, deployment approval system or Security Champions programme.

config/lifecycle/actor-roles.yaml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"schema_version": "1.0",
3+
"roles": [
4+
"Product Security",
5+
"Application Engineering",
6+
"Platform Engineering",
7+
"Cloud Security",
8+
"Technical Owner",
9+
"Risk Owner",
10+
"Verifier"
11+
]
12+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{
2+
"schema_version": "1.0",
3+
"maximum_duration_days": {
4+
"critical": 14,
5+
"high": 30,
6+
"medium": 90,
7+
"low": 180,
8+
"informational": 180,
9+
"unknown": 90
10+
},
11+
"approval_roles": {
12+
"critical": ["Product Security", "Risk Owner", "Technical Owner"],
13+
"high": ["Product Security", "Risk Owner"],
14+
"medium": ["Product Security"],
15+
"low": ["Technical Owner"],
16+
"informational": ["Technical Owner"],
17+
"unknown": ["Product Security"]
18+
},
19+
"allowed_statuses": ["requested", "under_review", "approved", "rejected", "active", "expired", "revoked", "closed"],
20+
"allowed_decisions": ["approve", "reject", "revoke", "extend", "close"],
21+
"scope_required": true,
22+
"permanent_exceptions_allowed": false
23+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
{
2+
"schema_version": "1.0",
3+
"false_positive_selectors": [
4+
{
5+
"name": "local zap version notice",
6+
"source_tool": "zap",
7+
"normalised_severity": "low",
8+
"false_positive_reason": "Local scanner version notice is retained as source evidence but does not represent an application vulnerability.",
9+
"reviewer_role": "Product Security",
10+
"supporting_evidence": "outputs/security/dynamic/zap-summary.json"
11+
}
12+
],
13+
"risk_acceptance_selectors": [
14+
{
15+
"name": "no-fix runtime base dependency",
16+
"source_tool": "trivy",
17+
"normalised_severity": "high",
18+
"exception_kind": "active"
19+
},
20+
{
21+
"name": "reference infrastructure reviewed exception",
22+
"source_tool": "checkov",
23+
"normalised_severity": "high",
24+
"exception_kind": "expiring"
25+
},
26+
{
27+
"name": "expired reference infrastructure exception",
28+
"source_tool": "checkov",
29+
"normalised_severity": "high",
30+
"exception_kind": "expired"
31+
}
32+
]
33+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"schema_version": "1.0",
3+
"policy_version": "1.0",
4+
"default_initial_status": "triaged",
5+
"controlled_timestamp": "2026-01-01T00:00:00Z",
6+
"as_of_date": "2026-01-01",
7+
"deployment_status": "not_deployed",
8+
"due_soon_days": 7,
9+
"exception_expiring_soon_days": 14,
10+
"limitations": [
11+
"Portfolio demonstration policy, not Genomics England policy.",
12+
"Lifecycle records are local deterministic evidence, not a production ticketing system.",
13+
"Milestone 9 does not implement Security Champions, dashboards, external ticketing or deployment."
14+
]
15+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"schema_version": "1.0",
3+
"required_owner_fields": ["technical_owner", "risk_owner", "remediation_owner", "squad"],
4+
"critical_high_require_owner_before": ["assigned", "in_remediation"],
5+
"allowed_owners_source": "config/findings/ownership.yaml",
6+
"unowned_value": "unowned"
7+
}

0 commit comments

Comments
 (0)