Skip to content

Commit e1edcc1

Browse files
authored
Update CVE report and remove unnecessary package (#692)
- Removed `libdw-dev` package from Docker image, as this is only required for the build process. - Added nicely formatted CVE summary output to vulnerability scan workflow.
1 parent 1ca7866 commit e1edcc1

File tree

3 files changed

+138
-2
lines changed

3 files changed

+138
-2
lines changed

.github/workflows/reusable_cve_scan.yml

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ jobs:
5959
run: |
6060
python3 -m venv "${{ env.CVE_DIR }}/env"
6161
source "${{ env.CVE_DIR }}/env/bin/activate"
62-
pip install requests tqdm
62+
pip install requests tqdm rich
6363
6464
- name: Install Trivy
6565
if: ${{ inputs.run_trivy }}
@@ -191,6 +191,19 @@ jobs:
191191
name: ${{ inputs.image_type }}-${{ inputs.arch }}-cve-bin-tool-apt-summary
192192
path: "${{ env.CVE_DIR }}/cve-bin-tool-apt-summary.json"
193193

194+
- name: Combine Reports
195+
if: ${{ inputs.run_trivy || inputs.run_grype }}
196+
run: |
197+
source "${{ env.CVE_DIR }}/env/bin/activate"
198+
python3 scripts/combine_reports.py "${{ env.CVE_DIR }}/grype-summary.json" "${{ env.CVE_DIR }}/trivy-summary.json"
199+
200+
- name: Upload Combined Report Artifact
201+
if: ${{ inputs.run_trivy || inputs.run_grype }}
202+
uses: actions/upload-artifact@v4
203+
with:
204+
name: ${{ inputs.image_type }}-${{ inputs.arch }}-combined-report
205+
path: "${{ env.CVE_DIR }}/combined_report.txt"
206+
194207
- name: Send Slack Message
195208
if: ${{ inputs.send_slack_message && always() }}
196209
id: slack-message

scripts/combine_reports.py

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
import json
2+
from io import StringIO
3+
from rich.table import Table
4+
from rich.console import Console
5+
import argparse
6+
import os
7+
8+
9+
def read_json_file(filename):
10+
11+
if not os.path.exists(filename):
12+
return None
13+
14+
with open(filename, "r") as f:
15+
data = json.load(f)
16+
return data
17+
18+
19+
def extract_grype_data(data):
20+
if data is None:
21+
return []
22+
23+
matches = data["matches"]
24+
25+
out = []
26+
for match in matches:
27+
fixed = match["vulnerability"]["fix"]["versions"]
28+
if len(fixed) > 0:
29+
fixed = fixed[0]
30+
else:
31+
fixed = None
32+
out.append({
33+
"package": match["artifact"]["name"],
34+
"version": match["artifact"]["version"],
35+
"vulnerabilityID": match["vulnerability"]["id"],
36+
"type": match["artifact"]["type"],
37+
"fixed": fixed,
38+
"severity": match["vulnerability"]["severity"].capitalize(),
39+
})
40+
return out
41+
42+
43+
def extract_trivy_data(data):
44+
if data is None:
45+
return []
46+
47+
out = []
48+
results = data["Results"]
49+
for result in results:
50+
type = result["Type"]
51+
matches = result["Vulnerabilities"]
52+
for match in matches:
53+
out.append({
54+
"package": match["PkgName"],
55+
"version": match["InstalledVersion"],
56+
"vulnerabilityID": match["VulnerabilityID"],
57+
"type": type.replace("python-pkg", "python"),
58+
"fixed": None,
59+
"severity": match["Severity"].capitalize(),
60+
})
61+
return out
62+
63+
64+
def combine_reports(grype_data, trivy_data):
65+
out = grype_data.copy()
66+
67+
grype_keys = [(x["package"], x["version"], x["vulnerabilityID"]) for x in grype_data]
68+
trivy_keys = [(x["package"], x["version"], x["vulnerabilityID"]) for x in trivy_data]
69+
70+
for key, item in zip(trivy_keys, trivy_data):
71+
if key not in grype_keys:
72+
out.append(item)
73+
74+
# sort by package name
75+
out.sort(key=lambda x: x["package"])
76+
return out
77+
78+
79+
def format_table(data):
80+
table = Table(title="Vulnerabilities")
81+
table.add_column("Package", justify="left")
82+
table.add_column("Version", justify="left")
83+
table.add_column("VulnerabilityID", justify="left")
84+
table.add_column("Severity", justify="left")
85+
table.add_column("Type", justify="left")
86+
table.add_column("Fixed", justify="left")
87+
for item in data:
88+
table.add_row(
89+
item["package"],
90+
item["version"],
91+
item["vulnerabilityID"],
92+
item["severity"],
93+
item["type"],
94+
item["fixed"]
95+
)
96+
return table
97+
98+
99+
def save_table_to_file(table, filename):
100+
console = Console(file=StringIO(), width=None, force_terminal=False)
101+
console.print(table)
102+
output = console.file.getvalue()
103+
with open(filename, "w", encoding="utf-8") as f:
104+
f.write(output)
105+
106+
107+
def main():
108+
109+
parser = argparse.ArgumentParser()
110+
parser.add_argument("grype_file", type=str)
111+
parser.add_argument("trivy_file", type=str)
112+
args = parser.parse_args()
113+
114+
grype_data = extract_grype_data(read_json_file(args.grype_file))
115+
trivy_data = extract_trivy_data(read_json_file(args.trivy_file))
116+
combined_data = combine_reports(grype_data, trivy_data)
117+
table = format_table(combined_data)
118+
outdir = os.getenv("CVE_DIR", os.getcwd())
119+
save_table_to_file(table, f"{outdir}/combined_report.txt")
120+
121+
122+
if __name__ == "__main__":
123+
main()

scripts/install_runtime_requirements.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ rm packages-microsoft-prod.deb
5656
apt-get update
5757
ACCEPT_EULA=Y apt-get install -y msodbcsql18 unixodbc-dev
5858
apt-get install -y libcurl4 libpython${PY_VERSION} openssl python3 python3-pip python3-setuptools \
59-
adduser libgomp1 libaio1t64 libatomic1 libdw-dev --no-install-recommends
59+
adduser libgomp1 libaio1t64 libatomic1 --no-install-recommends
6060
ln -s /usr/bin/$(ls /usr/bin | grep perf) /usr/bin/perf
6161

6262
# In CI, we clean up the apt cache to save space in the Docker container.

0 commit comments

Comments
 (0)