Skip to content

PI-1877 Create initial project for manage-supervision-and-oasys (#3211) #592

PI-1877 Create initial project for manage-supervision-and-oasys (#3211)

PI-1877 Create initial project for manage-supervision-and-oasys (#3211) #592

Workflow file for this run

name: Security
on:
schedule:
- cron: "30 5 * * MON-FRI" # Every weekday at 05:30 UTC
workflow_dispatch:
push:
branches:
- main
paths:
- '**/.trivyignore'
jobs:
get-projects:
runs-on: ubuntu-latest
outputs:
projects: ${{ steps.get-projects.outputs.projects }}
steps:
- uses: actions/checkout@v4
- id: get-projects
run: echo "projects=$(find projects -mindepth 1 -maxdepth 1 -printf "%f\n" | jq --raw-input . | jq --slurp --compact-output .)" | tee -a "$GITHUB_OUTPUT"
trivy-scan:
runs-on: ubuntu-latest
needs:
- get-projects
strategy:
fail-fast: false
matrix:
project: ${{ fromJson(needs.get-projects.outputs.projects) }}
steps:
- uses: actions/checkout@v4
- name: Scan image
uses: aquasecurity/trivy-action@d43c1f16c00cfd3978dde6c07f4bbcf9eb6993ca # v0.16.1
with:
image-ref: 'ghcr.io/ministryofjustice/hmpps-probation-integration-services/${{ matrix.project }}:latest'
ignore-unfixed: true
severity: 'CRITICAL,HIGH'
exit-code: '0'
format: 'sarif'
output: 'trivy-results.sarif'
trivyignores: '.trivyignore,projects/${{ matrix.project }}/.trivyignore'
limit-severities-for-sarif: true
- name: Upload Trivy scan results to GitHub Security tab
uses: github/codeql-action/upload-sarif@v3
if: always()
with:
sarif_file: 'trivy-results.sarif'
- name: Get Trivy results
uses: aquasecurity/trivy-action@d43c1f16c00cfd3978dde6c07f4bbcf9eb6993ca # v0.16.1
with:
image-ref: 'ghcr.io/ministryofjustice/hmpps-probation-integration-services/${{ matrix.project }}:latest'
ignore-unfixed: true
severity: 'CRITICAL,HIGH'
format: 'json'
output: 'results.json'
trivyignores: '.trivyignore,projects/${{ matrix.project }}/.trivyignore'
- name: Output results
id: results
run: echo "vulnerabilities=$(jq -c '.Results[].Vulnerabilities | select(. != null) | flatten' results.json)" | tee -a "$GITHUB_OUTPUT"
env:
GITHUB_TOKEN: ${{ github.token }}
- name: Merge outputs
uses: cloudposse/github-action-matrix-outputs-write@928e2a2d3d6ae4eb94010827489805c17c81181f # v0.4.2
with:
matrix-step-name: trivy
matrix-key: ${{ matrix.project }}
outputs: |
vulnerabilities: ${{ steps.results.outputs.vulnerabilities }}
trivy-merge:
runs-on: ubuntu-latest
needs:
- trivy-scan
steps:
- uses: actions/checkout@v4
- uses: cloudposse/github-action-matrix-outputs-read@ea1c28d66c34b8400391ed74d510f66abc392d5e # v0.1.1
id: trivy
with:
matrix-step-name: trivy
- name: Create GitHub issues
run: |
echo "$result" | jq -c '[.vulnerabilities | to_entries[] | .key as $project | .value // empty | map(. + {Projects: [$project]})]
| flatten
| group_by(.VulnerabilityID)
| map(reduce .[] as $vuln (.[0] + {Locations:[]}; .Projects += $vuln.Projects | .Locations += [$vuln.PkgName + ":" + $vuln.InstalledVersion + " (" + $vuln.PkgPath + ")"]))
| map_values({Title: .VulnerabilityID, Body: ("### " + .Title + "\n" + .PrimaryURL + "\n>" + .Description + "\n#### Projects:\n* " + (.Projects | sort | unique | join("\n* ")) + "\n#### Locations:\n* `" + (.Locations | sort | unique | join("`\n* `")) + "`\n#### References:\n* " + (.References | sort | unique | join("\n* ")))})
| .[]' \
| while read -r vulnerability; do
title=$(echo "$vulnerability" | jq -r '.Title')
body=$(echo "$vulnerability" | jq -r '.Body')
existing=$(gh issue list --state open --label dependencies --label security --search "$title" --json 'number' --jq '.[].number' | head -n1)
if [ -n "$existing" ]; then
echo "Issue '$title' already exists, updating body..."
gh issue edit "$existing" --body "$body"
else
gh issue create --title "$title" --body "$body" --label 'dependencies,security'
fi
done
env:
GITHUB_TOKEN: ${{ github.token }}
result: ${{ steps.trivy.outputs.result }}
- name: Close GitHub issues
run: |
openissues="$(gh issue list --state open --label dependencies --label security | awk '{print $3}')"
scanresults="$(echo "$result" | jq -r -c '.vulnerabilities | with_entries(select(.value != null)) | .[][].VulnerabilityID' | sort -u)"
issuestoclose="$(comm -23 <(echo "$openissues" | sort -u) <(echo "$scanresults" | sort -u))" #print lines only present in first file
echo "openissues=$openissues"
echo "scanresults=$scanresults"
echo "issuestoclose=$issuestoclose"
for cve in $issuestoclose; do
echo "$cve is already resolved, removing matching issue..."
issuenumber=$(gh issue list --state open --label dependencies --label security --search "$cve" | awk '{print $1}')
echo "$issuenumber" | xargs -n1 gh issue close
done
env:
GITHUB_TOKEN: ${{ github.token }}
result: ${{ steps.trivy.outputs.result }}
- name: Fail job if any vulnerabilities are found
if: steps.trivy.outputs.result != '{}'
run: if [ "$(echo "$result" | jq '.vulnerabilities | with_entries(select(.value != null)) | length')" != 0 ]; then exit 1; fi
env:
result: ${{ steps.trivy.outputs.result }}
veracode-scan:
runs-on: ubuntu-latest
needs:
- get-projects
steps:
- uses: actions/checkout@v4
- uses: actions/setup-java@v4
with:
java-version: 21
distribution: temurin
- uses: gradle/actions/setup-gradle@v3
with:
cache-read-only: true
- name: Build jars
run: ./gradlew jar
- name: Package jars
run: find . -name '*.jar' | zip -r package.zip -@
- name: Upload to Veracode
uses: veracode/[email protected]
with:
appname: hmpps-probation-integration-services
createprofile: false
deleteincompletescan: 2 # force delete any incomplete scans
filepath: package.zip
vid: ${{ secrets.CYBERSECURITY_VERACODE_API_ID }}
vkey: ${{ secrets.CYBERSECURITY_VERACODE_API_KEY }}