Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
8fc8c13
sbom configuration
koppuravuris Sep 17, 2025
f5cde73
sonar security warning fix new
koppuravuris Sep 17, 2025
6ee9ef8
Merge pull request #526 from NHSDigital/APM-6390
koppuravuris Sep 18, 2025
6301787
Added new SBOM config for generation all 3 reports
saptarshimandal1 Oct 2, 2025
08d643e
Merge pull request #527 from NHSDigital/feature/APM-6390
saptarshimandal1 Oct 2, 2025
e7ae503
Renamed SBOM readme
CLJ2006 Oct 8, 2025
4dd1844
Merge pull request #528 from NHSDigital/APM-6390--Rename-SBPM-readme
CLJ2006 Oct 8, 2025
108396a
Updated the ansible playbook to use the navtive docker cli commands
sathiya-nhs Nov 19, 2025
9abc559
Merge pull request #530 from NHSDigital/APIM-Pipeline-fix
sathiya-nhs Nov 19, 2025
89338bd
added python script file.
raghuramg753 Dec 2, 2025
81a04df
updated the scripts location.
raghuramg753 Dec 3, 2025
2ea1cea
added list repo.
raghuramg753 Dec 3, 2025
a280fef
updated ls.
raghuramg753 Dec 3, 2025
b0d6f84
updated python executation.
raghuramg753 Dec 3, 2025
24a75ef
updated script file location.
raghuramg753 Dec 3, 2025
6c54c3d
updated the base directory.
raghuramg753 Dec 3, 2025
8dd35f7
updated path.
raghuramg753 Dec 3, 2025
6fafe3b
Corrected the path.
raghuramg753 Dec 3, 2025
5cac8f5
updated path.
raghuramg753 Dec 3, 2025
03dfc94
updated the step.
raghuramg753 Dec 3, 2025
5a39eed
updated the path.
raghuramg753 Dec 3, 2025
accd0ed
modified the azure template.
raghuramg753 Dec 3, 2025
a39fc12
Updated the script path.
raghuramg753 Dec 3, 2025
fab20e5
Updated pythonscript loc.
raghuramg753 Dec 4, 2025
b42140b
Updated script.
raghuramg753 Dec 4, 2025
5b493e6
updated location.
raghuramg753 Dec 4, 2025
97445af
updated python loc,
raghuramg753 Dec 4, 2025
731cfe7
added debug logs.
raghuramg753 Dec 4, 2025
ed829bc
updated the python location.
raghuramg753 Dec 4, 2025
1603608
added debug.
raghuramg753 Dec 4, 2025
a532141
added local debug.
raghuramg753 Dec 4, 2025
4c7bcae
loc updated.
raghuramg753 Dec 4, 2025
ee4ccee
updated script loc.
raghuramg753 Dec 5, 2025
c2dca69
added echo
raghuramg753 Dec 5, 2025
26983aa
updated python loc.
raghuramg753 Dec 5, 2025
a060048
added pip commands
raghuramg753 Dec 5, 2025
7b71309
updated python script.
raghuramg753 Dec 5, 2025
a0b3578
updated yaml to add input params for python scripts.
raghuramg753 Dec 5, 2025
870cac8
added repo name in copy spec script.
raghuramg753 Dec 5, 2025
fe2ad79
added log to check working dir.
raghuramg753 Dec 5, 2025
461395b
updated build.
raghuramg753 Dec 5, 2025
24dc3d0
updated spec .json path
raghuramg753 Dec 5, 2025
fe1c126
updated args.
raghuramg753 Dec 5, 2025
5806e1f
updated input to python scripts.
raghuramg753 Dec 5, 2025
f9f7659
updated script and yaml.
raghuramg753 Dec 5, 2025
3788e55
updated the python script..
raghuramg753 Dec 5, 2025
7b87858
added location.
raghuramg753 Dec 5, 2025
cd0f5ff
fixed cmd error.
raghuramg753 Dec 5, 2025
f5ba2f1
updated the json dir..
raghuramg753 Dec 5, 2025
54d5c96
added deploy service.
raghuramg753 Dec 5, 2025
3758a92
changed the loc.
raghuramg753 Dec 8, 2025
789e869
added debug paths.
raghuramg753 Dec 8, 2025
590e4f7
added the working directory.
raghuramg753 Dec 8, 2025
8563a29
updated working directory.
raghuramg753 Dec 8, 2025
fbadda4
updated python script.
raghuramg753 Dec 8, 2025
f7a0e55
updated python scripts.
raghuramg753 Dec 8, 2025
c5cbd28
updated script..
raghuramg753 Dec 8, 2025
8f4f511
updated yaml...
raghuramg753 Dec 8, 2025
e902485
s3 bucket name updated.
raghuramg753 Dec 8, 2025
a5096a5
removed parameter.
raghuramg753 Dec 8, 2025
39323e3
added the deploy-service
raghuramg753 Dec 8, 2025
96ba32c
Merge remote-tracking branch 'origin/edge' into task-5686
raghuramg753 Dec 16, 2025
1543ca2
removed spec copy.
raghuramg753 Dec 23, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 58 additions & 0 deletions .github/SBOM-README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# SBOM & Vulnerability Scanning Automation

This repository uses GitHub Actions to automatically generate a Software Bill of Materials (SBOM), scan for vulnerabilities, and produce package inventory reports.

All reports are named with the repository name for easy identification.

## Features

SBOM Generation: Uses Syft to generate an SPDX JSON SBOM.
SBOM Merging: Merges SBOMs for multiple tools if needed.
SBOM to CSV: Converts SBOM JSON to a CSV report.
Vulnerability Scanning: Uses Grype to scan the SBOM for vulnerabilities and outputs a CSV report.
Package Inventory: Extracts a simple package list (name, type, version) as a CSV.
Artifacts: All reports are uploaded as workflow artifacts with the repository name in the filename.

## Workflow Overview

The main workflow is defined in .github/workflows/sbom.yml

## Scripts

scripts/create-sbom.sh
Generates an SBOM for the repo and for specified tools, merging them as needed.
scripts/update-sbom.py
Merges additional SBOMs into the main SBOM.
.github/scripts/sbom_json_to_csv.py
Converts the SBOM JSON to a detailed CSV report.
.github/scripts/grype_json_to_csv.py
Converts Grype’s vulnerability scan JSON output to a CSV report.
Output columns: REPO, NAME, INSTALLED, FIXED-IN, TYPE, VULNERABILITY, SEVERITY
.github/scripts/sbom_packages_to_csv.py
Extracts a simple package inventory from the SBOM.
Output columns: name, type, version

## Example Reports

Vulnerability Report
grype-report-[RepoName].csv
REPO,NAME,INSTALLED,FIXED-IN,TYPE,VULNERABILITY,SEVERITY
my-repo,Flask,2.1.2,,library,CVE-2022-12345,High
...

Package Inventory
sbom-packages-[RepoName].csv
name,type,version
Flask,library,2.1.2
Jinja2,library,3.1.2
...

## Usage

Push to main branch or run the workflow manually.
Download artifacts from the workflow run summary.

## Customization

Add more tools to scripts/create-sbom.sh as needed.
Modify scripts to adjust report formats or add more metadata.
28 changes: 28 additions & 0 deletions .github/scripts/grype_json_to_csv.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import json
import csv
import sys

input_file = sys.argv[1] if len(sys.argv) > 1 else "grype-report.json"
output_file = sys.argv[2] if len(sys.argv) > 2 else "grype-report.csv"

with open(input_file, "r", encoding="utf-8") as f:
data = json.load(f)

columns = ["NAME", "INSTALLED", "FIXED-IN", "TYPE", "VULNERABILITY", "SEVERITY"]

with open(output_file, "w", newline="", encoding="utf-8") as csvfile:
writer = csv.DictWriter(csvfile, fieldnames=columns)
writer.writeheader()
for match in data.get("matches", []):
pkg = match.get("artifact", {})
vuln = match.get("vulnerability", {})
row = {
"NAME": pkg.get("name", ""),
"INSTALLED": pkg.get("version", ""),
"FIXED-IN": vuln.get("fix", {}).get("versions", [""])[0] if vuln.get("fix", {}).get("versions") else "",
"TYPE": pkg.get("type", ""),
"VULNERABILITY": vuln.get("id", ""),
"SEVERITY": vuln.get("severity", ""),
}
writer.writerow(row)
print(f"CSV export complete: {output_file}")
78 changes: 78 additions & 0 deletions .github/scripts/sbom_json_to_csv.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import json
import csv
import sys
# from pathlib import Path
from tabulate import tabulate

input_file = sys.argv[1] if len(sys.argv) > 1 else "sbom.json"
output_file = sys.argv[2] if len(sys.argv) > 2 else "sbom.csv"

with open(input_file, "r", encoding="utf-8") as f:
sbom = json.load(f)

packages = sbom.get("packages", [])

columns = [
"name",
"versionInfo",
"type",
"supplier",
"downloadLocation",
"licenseConcluded",
"licenseDeclared",
"externalRefs"
]


def get_type(pkg):
spdxid = pkg.get("SPDXID", "")
if "-" in spdxid:
parts = spdxid.split("-")
if len(parts) > 2:
return parts[2]
refs = pkg.get("externalRefs", [])
for ref in refs:
if ref.get("referenceType") == "purl":
return ref.get("referenceLocator", "").split("/")[0]
return ""


def get_external_refs(pkg):
refs = pkg.get("externalRefs", [])
return ";".join([ref.get("referenceLocator", "") for ref in refs])


with open(output_file, "w", newline="", encoding="utf-8") as csvfile:
writer = csv.DictWriter(csvfile, fieldnames=columns)
writer.writeheader()
for pkg in packages:
row = {
"name": pkg.get("name", ""),
"versionInfo": pkg.get("versionInfo", ""),
"type": get_type(pkg),
"supplier": pkg.get("supplier", ""),
"downloadLocation": pkg.get("downloadLocation", ""),
"licenseConcluded": pkg.get("licenseConcluded", ""),
"licenseDeclared": pkg.get("licenseDeclared", ""),
"externalRefs": get_external_refs(pkg)
}
writer.writerow(row)

print(f"CSV export complete: {output_file}")


with open("sbom_table.txt", "w", encoding="utf-8") as f:
table = []
for pkg in packages:
row = [
pkg.get("name", ""),
pkg.get("versionInfo", ""),
get_type(pkg),
pkg.get("supplier", ""),
pkg.get("downloadLocation", ""),
pkg.get("licenseConcluded", ""),
pkg.get("licenseDeclared", ""),
get_external_refs(pkg)
]
table.append(row)
f.write(tabulate(table, columns, tablefmt="grid"))
28 changes: 28 additions & 0 deletions .github/scripts/sbom_packages_to_csv.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import json
import csv
import sys
import os

input_file = sys.argv[1] if len(sys.argv) > 1 else "sbom.json"
repo_name = sys.argv[2] if len(sys.argv) > 2 else os.getenv("GITHUB_REPOSITORY", "unknown-repo").split("/")[-1]
output_file = f"sbom-packages-{repo_name}.csv"

with open(input_file, "r", encoding="utf-8") as f:
sbom = json.load(f)

packages = sbom.get("packages", [])

columns = ["name", "type", "version"]

with open(output_file, "w", newline="", encoding="utf-8") as csvfile:
writer = csv.DictWriter(csvfile, fieldnames=columns)
writer.writeheader()
for pkg in packages:
row = {
"name": pkg.get("name", ""),
"type": pkg.get("type", ""),
"version": pkg.get("versionInfo", "")
}
writer.writerow(row)

print(f"Package list CSV generated: {output_file}")
110 changes: 110 additions & 0 deletions .github/workflows/sbom.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
name: SBOM Vulnerability Scanning

on:
workflow_dispatch:
inputs:
environment:
description: "Run SBOM check"
required: true
type: choice
options:
- yes
- no

env:
SYFT_VERSION: "1.27.1"
TF_VERSION: "1.12.2"

jobs:
deploy:
name: Software Bill of Materials
runs-on: ubuntu-latest
permissions:
actions: read
contents: write
steps:
- name: Checkout
uses: actions/checkout@v5

- name: Setup Python 3.13
uses: actions/setup-python@v5
with:
python-version: "3.13"

- name: Setup Terraform
uses: hashicorp/setup-terraform@b9cd54a3c349d3f38e8881555d616ced269862dd

- uses: terraform-linters/setup-tflint@ae78205cfffec9e8d93fd2b3115c7e9d3166d4b6
name: Setup TFLint

- name: Set architecture variable
id: os-arch
run: |
case "${{ runner.arch }}" in
X64) ARCH="amd64" ;;
ARM64) ARCH="arm64" ;;
esac
echo "arch=${ARCH}" >> $GITHUB_OUTPUT

- name: Download and setup Syft
run: |
DOWNLOAD_URL="https://github.com/anchore/syft/releases/download/v${{ env.SYFT_VERSION }}/syft_${{ env.SYFT_VERSION }}_linux_${{ steps.os-arch.outputs.arch }}.tar.gz"
echo "Downloading: ${DOWNLOAD_URL}"

curl -L -o syft.tar.gz "${DOWNLOAD_URL}"
tar -xzf syft.tar.gz
chmod +x syft

# Add to PATH for subsequent steps
echo "$(pwd)" >> $GITHUB_PATH

- name: Create SBOM
run: bash scripts/create-sbom.sh terraform python tflint

- name: Convert SBOM JSON to CSV
run: |
pip install --upgrade pip
pip install tabulate
REPO_NAME=$(basename $GITHUB_REPOSITORY)
python .github/scripts/sbom_json_to_csv.py sbom.json SBOM_${REPO_NAME}.csv

- name: Upload SBOM CSV as artifact
uses: actions/upload-artifact@v4
with:
name: sbom-csv
path: SBOM_${{ github.event.repository.name }}.csv

- name: Install Grype
run: |
curl -sSfL https://raw.githubusercontent.com/anchore/grype/main/install.sh | sh -s -- -b /usr/local/bin

- name: Scan SBOM for Vulnerabilities (JSON)
run: |
grype sbom:sbom.json -o json > grype-report.json



- name: Convert Grype JSON to CSV
run: |
pip install --upgrade pip
REPO_NAME=$(basename $GITHUB_REPOSITORY)
python .github/scripts/grype_json_to_csv.py grype-report.json grype-report-${REPO_NAME}.csv


- name: Upload Vulnerability Report
uses: actions/upload-artifact@v4
with:
name: grype-report
path: grype-report-${{ github.event.repository.name }}.csv

- name: Generate Package Inventory CSV
run: |
pip install --upgrade pip
REPO_NAME=$(basename $GITHUB_REPOSITORY)
python .github/scripts/sbom_packages_to_csv.py sbom.json $REPO_NAME

- name: Upload Package Inventory CSV
uses: actions/upload-artifact@v4
with:
name: sbom-packages
path: sbom-packages-${{ github.event.repository.name }}.csv
32 changes: 17 additions & 15 deletions ansible/roles/build-ecs-proxies/tasks/build-container.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,24 @@
changed_when: no

- name: pull latest if exists - to ensure cache {{ item }}
docker_image:
name: "{{ ecr_registry }}/{{ item }}:{{ describe_images.stdout }}"
source: pull
ansible.builtin.command:
cmd: "docker pull {{ ecr_registry }}/{{ item }}:{{ describe_images.stdout }}"
when: describe_images.stdout != 'None'
ignore_errors: true
no_log: true

- name: build and push ecr image {{ item }}
docker_image:
name: "{{ image_name }}"
build:
path: "{{ base_dir }}/{{ images_map[item].path }}"
dockerfile: "{{ base_dir }}/{{ images_map[item].dockerfile }}"
pull: yes
network: host
source: build
force_source: yes
push: yes
timeout: 300
- name: build ecr image {{ item }}
ansible.builtin.command:
cmd: >
docker build
-t {{ image_name }}
-f {{ base_dir }}/{{ images_map[item].dockerfile }}
{{ base_dir }}/{{ images_map[item].path }}
--network host --pull
register: build_result
ignore_errors: false

- name: push ecr image {{ item }}
ansible.builtin.command:
cmd: "docker push {{ image_name }}"
when: build_result.rc == 0
2 changes: 1 addition & 1 deletion azure/common/deploy-stage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ stages:
fi
displayName: Check supplied names against API registry
continueOnError: true

- template: '../templates/deploy-service.yml'
parameters:
service_name: ${{ parameters.service_name }}
Expand Down
2 changes: 1 addition & 1 deletion azure/templates/deploy-service.yml
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,7 @@ steps:
export PULL_REQUEST="${{ parameters.pr_label }}"
make --no-print-directory -C $(UTILS_DIR)/ansible deploy-manifest
displayName: 'Deploy Manifest'

- ${{ if parameters.proxy_path }}:
- bash: |
set -euo pipefail
Expand Down
Loading