Skip to content

Commit c9a5e0c

Browse files
committed
docs(readme): update documentation
1 parent 50f924d commit c9a5e0c

File tree

1 file changed

+133
-95
lines changed

1 file changed

+133
-95
lines changed

README.md

Lines changed: 133 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ The aim is to help engineering teams:
88
- Deliver software faster and more safely
99
- Follow consistent engineering practices that scale across NHS products
1010

11-
Whether you're a developer, tester, or tech lead, this repository shows how you can go from _commitversiondeployrelease_ without ever losing confidence in what's running in production.
11+
Whether you're a developer, tester, or tech lead, this repository shows how you can go from _CommitVersionBuildScan → Attest → Sign → Publish → Deploy → Release_ without ever losing confidence in what's running in production.
1212

1313
This approach also lays the foundation for [feature toggling](https://github.com/NHSDigital/software-engineering-quality-framework/blob/main/practices/feature-toggling.md) where new functionality is deployed but not immediately exposed to users. Versioning provides the traceability and control needed to manage these toggled changes safely, allowing teams to ship small, reversible updates, test them in production, and enable them gradually when ready.
1414

@@ -34,12 +34,6 @@ This aligns directly with NHS ongoing work to strengthen the security posture of
3434
- [Prerequisites](#prerequisites)
3535
- [GitHub App setup](#github-app-setup)
3636
- [Bot setup for commit signing](#bot-setup-for-commit-signing)
37-
- [Secure by design](#secure-by-design)
38-
- [SBOM generation and CVE scanning](#sbom-generation-and-cve-scanning)
39-
- [SBOM generation](#sbom-generation)
40-
- [CVE scanning](#cve-scanning)
41-
- [Container image signing](#container-image-signing)
42-
- [Build provenance attestation](#build-provenance-attestation)
4337
- [Design decisions and rationale](#design-decisions-and-rationale)
4438
- [🧩 Why use a GitHub App Token instead of a Personal Access Token (PAT)](#-why-use-a-github-app-token-instead-of-a-personal-access-token-pat)
4539
- [🔐 Why the signing key belongs to a bot, not the App](#-why-the-signing-key-belongs-to-a-bot-not-the-app)
@@ -49,6 +43,13 @@ This aligns directly with NHS ongoing work to strengthen the security posture of
4943
- [Why this pattern works](#why-this-pattern-works)
5044
- [Alternative patterns considered](#alternative-patterns-considered)
5145
- [Detailed configuration](#detailed-configuration)
46+
- [Secure by design versioning (release)](#secure-by-design-versioning-release)
47+
- [SBOM generation and CVE scanning](#sbom-generation-and-cve-scanning)
48+
- [SBOM generation](#sbom-generation)
49+
- [CVE scanning](#cve-scanning)
50+
- [Container image signing](#container-image-signing)
51+
- [Build provenance attestation](#build-provenance-attestation)
52+
- [End-to-End flow](#end-to-end-flow)
5253
- [How to use this repository](#how-to-use-this-repository)
5354
- [Adding a new feature](#adding-a-new-feature)
5455
- [How Conventional Commits affect versioning](#how-conventional-commits-affect-versioning)
@@ -199,94 +200,6 @@ Steps:
199200

200201
After that, all commits made by the workflow will appear as _"Verified ✅"_ on GitHub.
201202

202-
## Secure by design
203-
204-
### SBOM generation and CVE scanning
205-
206-
As part of its secure software supply-chain workflow, this repository automatically generates a Software Bill of Materials (SBOM) and performs vulnerability scanning against each released container image. These steps provide transparency into dependencies and help identify potential risks early in the delivery process.
207-
208-
#### SBOM generation
209-
210-
The SBOM is produced using Anchore Syft, which analyses the container image and lists all components, packages, and licences present. It is exported in the CycloneDX JSON format, an open, machine-readable standard widely used across industry and supported for artefact provenance.
211-
212-
Each SBOM:
213-
214-
- Captures the full dependency graph of the built image
215-
- Includes component names, versions, and licence metadata
216-
- Is stored as a workflow artefact for traceability and audit purposes
217-
218-
You can manually inspect or reuse the generated SBOM from the workflow artefacts, or upload it to internal analysis tools.
219-
220-
Example local generation:
221-
222-
```bash
223-
syft ghcr.io/{{ repository }}:{{ tag }} -o cyclonedx-json > sbom.cdx.json
224-
```
225-
226-
#### CVE scanning
227-
228-
Immediately after SBOM generation, the workflow runs Anchore Grype to scan for known vulnerabilities (CVEs). This ensures that any outdated or insecure components are surfaced before deployment.
229-
230-
The scan:
231-
232-
- Uses the SBOM as input, guaranteeing alignment with the built artefact
233-
- Reports vulnerabilities with severity, package name, and fixed version (if available)
234-
- Fails the workflow only for severe, fixable vulnerabilities (configurable via `severity-cutoff` and `only-fixed` options)
235-
236-
Example local scan:
237-
238-
```bash
239-
grype sbom:sbom.cdx.json --only-fixed --fail-on medium
240-
```
241-
242-
Benefits
243-
244-
- Transparency, provides a full inventory of what's inside each image
245-
- Early risk detection, identifies CVEs before they reach runtime
246-
- Compliance, aligns with NHS Secure by Design and OpenSSF best practices
247-
- Traceability, complements provenance attestations and image signing
248-
249-
The combination of SBOM generation and CVE scanning forms a foundational layer of continuous assurance, enabling teams to understand, trust, and maintain the security of every artefact they ship.
250-
251-
### Container image signing
252-
253-
In addition to commit signing, this repository also demonstrates how to sign and verify container images using Sigstore Cosign. Cosign provides cryptographic assurance that every published image originates from a trusted workflow and has not been altered after build. Each image pushed to the GitHub Container Registry (GHCR) is automatically signed as part of the release workflow. This produces tamper-evident OCI artefacts stored alongside the image, allowing anyone to independently verify its provenance. There are the following benefits:
254-
255-
- End-to-end provenance, extends the trusted chain of custody from commit to container
256-
- Tamper evidence, every signature includes cryptographic metadata that cannot be forged or moved between images
257-
- Transparency, the signature is also recorded in the public Sigstore Rekor transparency log for immutable auditability
258-
- Alignment with NHS Secure by Design, strengthens cyber resilience by ensuring only verified and trusted artefacts reach production
259-
260-
To verify a signed image:
261-
262-
```bash
263-
cosign verify --key cosign.pub ghcr.io/{{ repository }}:{{ tag }}
264-
```
265-
266-
The output confirms that:
267-
268-
- the signature matches the published public key,
269-
- the digest corresponds to the exact build produced by the workflow, and
270-
- the signature is recorded in the transparency log if enabled.
271-
272-
This ensures that every deployment can be proven authentic and traceable, a core requirement for secure software supply-chain assurance within NHS.
273-
274-
### Build provenance attestation
275-
276-
To further strengthen software supply-chain assurance, this repository also demonstrates how to generate and publish build provenance attestations using the `actions/attest-build-provenance`
277-
GitHub Action. Provenance describes what was built, how, and by whom - providing cryptographic evidence that each artefact (for example, a container image) was produced by a trusted workflow. When enabled in the workflow, GitHub automatically creates an attestation record linked to the image digest. This record is cryptographically signed using the repository's OpenID Connect (OIDC) identity and stored securely within GitHub's Attestation store. Here are the benefits:
278-
279-
- Verified origin, attests that an artefact was built by a specific repository and workflow run
280-
- Tamper resistance, signed using GitHub's OIDC token, ensuring authenticity and integrity
281-
- Auditable provenance, metadata such as build parameters, commit SHA, and workflow run ID are recorded immutably
282-
- Supply-chain compliance, aligns with [SLSA Level 2+](https://slsa.dev/spec/v1.0/levels) provenance standards
283-
284-
The workflow must request `id-token: write` and `attestations: write` permissions to create attestations. Provenance always references the immutable image digest (sha256:...), not version tags, to ensure traceability. Attestations can be viewed and verified with the GitHub CLI:
285-
286-
```bash
287-
cosign verify-attestation --key cosign.pub ghcr.io/{{ repository }}@sha256:{{ digest }}
288-
```
289-
290203
## Design decisions and rationale
291204

292205
These explanations are meant to help you and me to understand _why_ each part of this setup exists, so none of us has to guess later.
@@ -394,6 +307,131 @@ Other semver-valid formats such as `1.2.3+api` or `api_v1.2.3` were evaluated, b
394307

395308
This _"flat registry with tagged components"_ model scales cleanly across repositories while remaining compliant with GitHub's authentication and namespace rules. It also provides a consistent, human-readable way to publish and manage multiple container images under one project.
396309

310+
## Secure by design versioning (release)
311+
312+
### SBOM generation and CVE scanning
313+
314+
As part of its secure software supply-chain workflow, this repository automatically generates a Software Bill of Materials (SBOM) and performs vulnerability scanning against each released container image. These steps provide transparency into dependencies and help identify potential risks early in the delivery process.
315+
316+
#### SBOM generation
317+
318+
The SBOM is produced using Anchore Syft, which analyses the container image and lists all components, packages, and licences present. It is exported in the CycloneDX JSON format, an open, machine-readable standard widely used across industry and supported for artefact provenance.
319+
320+
Each SBOM:
321+
322+
- Captures the full dependency graph of the built image
323+
- Includes component names, versions, and licence metadata
324+
- Is stored as a workflow artefact for traceability and audit purposes
325+
326+
You can manually inspect or reuse the generated SBOM from the workflow artefacts, or upload it to internal analysis tools.
327+
328+
Example local generation:
329+
330+
```bash
331+
syft ghcr.io/{{ repository }}:{{ tag }} -o cyclonedx-json > sbom.cdx.json
332+
```
333+
334+
#### CVE scanning
335+
336+
Immediately after SBOM generation, the workflow runs Anchore Grype to scan for known vulnerabilities (CVEs). This ensures that any outdated or insecure components are surfaced before deployment.
337+
338+
The scan:
339+
340+
- Uses the SBOM as input, guaranteeing alignment with the built artefact
341+
- Reports vulnerabilities with severity, package name, and fixed version (if available)
342+
- Fails the workflow only for severe, fixable vulnerabilities (configurable via `severity-cutoff` and `only-fixed` options)
343+
344+
Example local scan:
345+
346+
```bash
347+
grype sbom:sbom.cdx.json --only-fixed --fail-on medium
348+
```
349+
350+
Benefits
351+
352+
- Transparency, provides a full inventory of what's inside each image
353+
- Early risk detection, identifies CVEs before they reach runtime
354+
- Compliance, aligns with NHS Secure by Design and OpenSSF best practices
355+
- Traceability, complements provenance attestations and image signing
356+
357+
The combination of SBOM generation and CVE scanning forms a foundational layer of continuous assurance, enabling teams to understand, trust, and maintain the security of every artefact they ship.
358+
359+
### Container image signing
360+
361+
In addition to commit signing, this repository also demonstrates how to sign and verify container images using Sigstore Cosign. Cosign provides cryptographic assurance that every published image originates from a trusted workflow and has not been altered after build. Each image pushed to the GitHub Container Registry (GHCR) is automatically signed as part of the release workflow. This produces tamper-evident OCI artefacts stored alongside the image, allowing anyone to independently verify its provenance. There are the following benefits:
362+
363+
- End-to-end provenance, extends the trusted chain of custody from commit to container
364+
- Tamper evidence, every signature includes cryptographic metadata that cannot be forged or moved between images
365+
- Transparency, the signature is also recorded in the public Sigstore Rekor transparency log for immutable auditability
366+
- Alignment with NHS Secure by Design, strengthens cyber resilience by ensuring only verified and trusted artefacts reach production
367+
368+
To verify a signed image:
369+
370+
```bash
371+
cosign verify --key cosign.pub ghcr.io/{{ repository }}:{{ tag }}
372+
```
373+
374+
The output confirms that:
375+
376+
- the signature matches the published public key,
377+
- the digest corresponds to the exact build produced by the workflow, and
378+
- the signature is recorded in the transparency log if enabled.
379+
380+
This ensures that every deployment can be proven authentic and traceable, a core requirement for secure software supply-chain assurance within NHS.
381+
382+
### Build provenance attestation
383+
384+
To further strengthen software supply-chain assurance, this repository also demonstrates how to generate and publish build provenance attestations using the `actions/attest-build-provenance`
385+
GitHub Action. Provenance describes what was built, how, and by whom - providing cryptographic evidence that each artefact (for example, a container image) was produced by a trusted workflow. When enabled in the workflow, GitHub automatically creates an attestation record linked to the image digest. This record is cryptographically signed using the repository's OpenID Connect (OIDC) identity and stored securely within GitHub's Attestation store. Here are the benefits:
386+
387+
- Verified origin, attests that an artefact was built by a specific repository and workflow run
388+
- Tamper resistance, signed using GitHub's OIDC token, ensuring authenticity and integrity
389+
- Auditable provenance, metadata such as build parameters, commit SHA, and workflow run ID are recorded immutably
390+
- Supply-chain compliance, aligns with [SLSA Level 2+](https://slsa.dev/spec/v1.0/levels) provenance standards
391+
392+
The workflow must request `id-token: write` and `attestations: write` permissions to create attestations. Provenance always references the immutable image digest (sha256:...), not version tags, to ensure traceability. Attestations can be viewed and verified with the GitHub CLI:
393+
394+
```bash
395+
cosign verify-attestation --key cosign.pub ghcr.io/{{ repository }}@sha256:{{ digest }}
396+
```
397+
398+
### End-to-End flow
399+
400+
| **Stage** | **Description** | **Tooling / Action** | **Outcome** |
401+
| ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------- | --------------------------------------------------------------------------- |
402+
| **Commit** | Engineer merges a Conventional Commit to `main` or rather creates a Pull Request to accomplish it. The release bot signs commits automatically | GitHub App + GPG | Verified ✅ signed commit with authorship traceability |
403+
| **Version** | Semantic version is calculated automatically based on commit messages | `semantic-release` | Predictable versioning (`v1.2.3`), changelog, and tag created |
404+
| **Build** | Application is packaged into a container image | OCI container (aka Docker) | Deterministic image tagged `app-<version>` and `app-latest` |
405+
| **Scan** | Generate SBOM and CVE scan before release | Syft + Grype | CycloneDX SBOM + CVE visibility for compliance and early risk detection |
406+
| **Attest** | Generate build provenance attestation linking code, build, and artefact digest | `actions/attest-build-provenance` | Cryptographically signed 🔏 provenance record stored in GitHub Attestations |
407+
| **Sign** | Sign container image and record signature in the transparency log | Sigstore Cosign + Rekor | Tamper-evident signature proving authenticity and integrity |
408+
| **Publish** | Push signed, attested image to registry and update release notes | GitHub Releases + GHCR | Trusted artefact available for downstream consumption |
409+
| **Deploy** | Change integrated with downstream environments up to production | GitHub Action (continuous deployment) | TBC |
410+
| **Release** | Feature enabled to the end user | OpenFeature (feature toggling) | TBC |
411+
412+
```mermaid
413+
flowchart LR
414+
A[Commit] --> B[Version]
415+
B --> C[Build]
416+
C --> D[Scan]
417+
D --> E[Attest]
418+
E --> F[Sign]
419+
F --> G[Publish]
420+
G --> H[Deploy]
421+
H --> I[Release]
422+
423+
%% Styling
424+
classDef core fill:#1f77b4,stroke:#0e3553,stroke-width:1px,color:#fff
425+
classDef sec fill:#2ca02c,stroke:#124d12,stroke-width:1px,color:#fff
426+
classDef audit fill:#ff7f0e,stroke:#663c00,stroke-width:1px,color:#fff
427+
classDef release fill:#9467bd,stroke:#3d2a5e,stroke-width:1px,color:#fff
428+
429+
class A,B,C core
430+
class D,E,F sec
431+
class G,H audit
432+
class I release
433+
```
434+
397435
## How to use this repository
398436

399437
### Adding a new feature

0 commit comments

Comments
 (0)