generated from ministryofjustice/template-repository
-
Notifications
You must be signed in to change notification settings - Fork 0
167 lines (148 loc) · 6.8 KB
/
security.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
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: Add new line to .trivyignore files
# to ensure files exist, and they can be merged correctly by Trivy
run: |
echo >> .trivyignore
echo >> projects/${{ matrix.project }}/.trivyignore
- name: Scan image
uses: aquasecurity/trivy-action@18f2510ee396bbf400402947b394f2dd8c87dbb0 # v0.29.0
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
env:
TRIVY_DB_REPOSITORY: public.ecr.aws/aquasecurity/trivy-db:2,ghcr.io/aquasecurity/trivy-db:2
TRIVY_JAVA_DB_REPOSITORY: public.ecr.aws/aquasecurity/trivy-java-db:1,ghcr.io/aquasecurity/trivy-java-db:1
- 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@18f2510ee396bbf400402947b394f2dd8c87dbb0 # v0.29.0
with:
image-ref: 'ghcr.io/ministryofjustice/hmpps-probation-integration-services/${{ matrix.project }}:latest'
ignore-unfixed: true
severity: 'CRITICAL,HIGH'
format: 'json'
output: 'trivy.json'
trivyignores: '.trivyignore,projects/${{ matrix.project }}/.trivyignore'
env:
TRIVY_DB_REPOSITORY: public.ecr.aws/aquasecurity/trivy-db:2,ghcr.io/aquasecurity/trivy-db:2
TRIVY_JAVA_DB_REPOSITORY: public.ecr.aws/aquasecurity/trivy-java-db:1,ghcr.io/aquasecurity/trivy-java-db:1
- name: Output results
run: |
jq -c '{"${{ matrix.project }}": .Results[].Vulnerabilities | select(. != null) | flatten}' trivy.json | tee results.json
env:
GITHUB_TOKEN: ${{ github.token }}
- uses: actions/upload-artifact@v4
with:
name: trivy-results-${{ matrix.project }}
path: results.json
trivy-merge:
runs-on: ubuntu-latest
needs:
- trivy-scan
steps:
- uses: actions/checkout@v4
- uses: actions/download-artifact@v4
with:
pattern: trivy-results-*
path: results
- name: Merge results
run: |
find results -maxdepth 2 -name results.json -exec cat {} \; | jq -c --slurp 'map(to_entries | map(.key as $matrix_key | .value | map_values({($matrix_key): .}))) | flatten | reduce .[] as $item ({}; . * $item)' | tee results.json
- name: Create GitHub issues
run: |
jq -c 'to_entries | map((.value // empty) + {Projects: [.key]})
| 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* ")))})
| .[]' < results.json \
| while read -r vulnerability; do
title=$(jq -r '.Title' <<< "$vulnerability")
jq -r '.Body' <<< "$vulnerability" | tee "${title}-body.json"
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-file "${title}-body.json"
else
gh issue create --title "$title" --body-file "${title}-body.json" --label 'dependencies,security'
fi
done
env:
GITHUB_TOKEN: ${{ github.token }}
- name: Close GitHub issues
run: |
openissues="$(gh issue list --state open --label dependencies --label security | awk '{print $3}')"
scanresults="$(jq -r -c 'with_entries(select(.value != null)) | .[].VulnerabilityID' < results.json | 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 }}
- name: Fail job if any vulnerabilities are found
run: if [ "$(jq '. | with_entries(select(.value != null)) | length' < results.json)" != 0 ]; then exit 1; fi
veracode-scan:
runs-on: ubuntu-latest
needs:
- get-projects
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/setup-gradle
with:
cache-encryption-key: ${{ secrets.GRADLE_ENCRYPTION_KEY }}
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 }}