From 91c191dca488d7a4b7c3003eb4f95c51662408ed Mon Sep 17 00:00:00 2001 From: patrick brisbin Date: Thu, 30 May 2024 13:48:31 -0400 Subject: [PATCH 1/8] Add failing test for URI-encoded Scan URLs --- src/wiz-cli.test.ts | 19 +++++++++++++++++++ src/wiz-cli.ts | 24 ++++++++++++++++++++---- 2 files changed, 39 insertions(+), 4 deletions(-) create mode 100644 src/wiz-cli.test.ts diff --git a/src/wiz-cli.test.ts b/src/wiz-cli.test.ts new file mode 100644 index 0000000..588dcf0 --- /dev/null +++ b/src/wiz-cli.test.ts @@ -0,0 +1,19 @@ +import { parseScanId } from "./wiz-cli"; + +describe("parseScanId", () => { + it("parses un-encoded scan-id URLs", () => { + const scanId = parseScanId( + "https://app.wiz.io/findings/cicd-scans#~(cicd_scan~'abc123)", + ); + + expect(scanId).toBe("abc123"); + }); + + it("parses encoded scan-id URLs", () => { + const scanId = parseScanId( + "https://app.wiz.io/findings/cicd-scans#%7E%28cicd_scan%7E%27def456%29", + ); + + expect(scanId).toBe("def456"); + }); +}); diff --git a/src/wiz-cli.ts b/src/wiz-cli.ts index c9eb58e..b978348 100644 --- a/src/wiz-cli.ts +++ b/src/wiz-cli.ts @@ -38,10 +38,7 @@ class WizCLI { let scanId: string | null = null; const listener = (data: Buffer) => { - const match = data.toString().match(/cicd_scan~'([0-9a-f-]*)/); - if (match && match[1]) { - scanId = match[1]; - } + scanId = parseScanId(data.toString()); }; const ec = await exec.exec(this.wizcli, args, { @@ -76,6 +73,25 @@ export async function getWizCLI(credentials: WizCredentials): Promise { return new WizCLI(wizcli, credentials).auth(); } +const SCAN_REGEXES = [ + new RegExp("cicd_scan~'([0-9a-f-]*)"), +]; + +// exported for testing +export function parseScanId(str: string): string | null { + let scanId = null; + + SCAN_REGEXES.forEach((regex) => { + const match = str.match(regex); + + if (match && match[1]) { + scanId = match[1]; + } + }); + + return scanId; +} + function getWizInstallUrl(): string { switch (process.platform) { case "win32": From c2ce0955b52553a8a27e164eab9c174dc2435fb8 Mon Sep 17 00:00:00 2001 From: patrick brisbin Date: Thu, 30 May 2024 13:48:43 -0400 Subject: [PATCH 2/8] Parse Scan Ids even if URI-encoded Fixes #104. --- src/wiz-cli.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/wiz-cli.ts b/src/wiz-cli.ts index b978348..b90b079 100644 --- a/src/wiz-cli.ts +++ b/src/wiz-cli.ts @@ -38,7 +38,9 @@ class WizCLI { let scanId: string | null = null; const listener = (data: Buffer) => { - scanId = parseScanId(data.toString()); + if (!scanId) { + scanId = parseScanId(data.toString()); + } }; const ec = await exec.exec(this.wizcli, args, { @@ -75,6 +77,7 @@ export async function getWizCLI(credentials: WizCredentials): Promise { const SCAN_REGEXES = [ new RegExp("cicd_scan~'([0-9a-f-]*)"), + new RegExp("cicd_scan%7E%27([0-9a-f-]*)%29"), ]; // exported for testing From c639a6ad7b11dbc0b8876b3c3d5f3ea7bc8f009e Mon Sep 17 00:00:00 2001 From: patrick brisbin Date: Thu, 30 May 2024 13:49:56 -0400 Subject: [PATCH 3/8] Don't fail if unable to parse Scan Id --- src/main.ts | 2 +- src/wiz-cli.ts | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main.ts b/src/main.ts index a6032c4..4b32061 100644 --- a/src/main.ts +++ b/src/main.ts @@ -30,7 +30,7 @@ async function run() { const wizcli = await wc.getWizCLI(wizCredentials); const { scanId, scanPassed } = await wizcli.scan(image, customPolicies); - if (wizApiEndpointUrl) { + if (scanId && wizApiEndpointUrl) { try { const result = await sr.fetch( scanId, diff --git a/src/wiz-cli.ts b/src/wiz-cli.ts index b90b079..c6d8b84 100644 --- a/src/wiz-cli.ts +++ b/src/wiz-cli.ts @@ -1,9 +1,10 @@ +import * as core from "@actions/core"; import * as exec from "@actions/exec"; import * as tc from "@actions/tool-cache"; import type { WizCredentials } from "./wiz-config"; export type WizScanResult = { - scanId: string; + scanId: string | null; scanPassed: boolean; }; @@ -56,7 +57,7 @@ class WizCLI { } if (!scanId) { - throw new Error("Unable to parse Scan Id from report"); + core.warning("Unable to parse Scan Id from report"); } const scanPassed = ec === 0; From fc728ac136eb98ef24955f71604356bd5a871b81 Mon Sep 17 00:00:00 2001 From: patrick brisbin Date: Thu, 30 May 2024 13:50:15 -0400 Subject: [PATCH 4/8] Stop printout our own Scan Results URL The CLI itself has been fixed to emit URI-encoded URLs, so we don't need to do this ourselves. --- src/main.ts | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/src/main.ts b/src/main.ts index 4b32061..d753bfe 100644 --- a/src/main.ts +++ b/src/main.ts @@ -51,16 +51,10 @@ async function run() { } } - const resultUrlBase = "https://app.wiz.io/reports/cicd-scans"; - const resultUrlHash = fixedEncodeURIComponent(`~(cicd_scan~'${scanId})`); - const resultUrl = `${resultUrlBase}#${resultUrlHash}`; - if (scanPassed) { - core.info(`Scan passed: ${resultUrl}`); core.setOutput("scan-id", scanId); core.setOutput("scan-result", "success"); } else { - core.warning(`Scan failed: ${resultUrl}`); core.setOutput("scan-id", scanId); core.setOutput("scan-result", "failed"); @@ -83,11 +77,4 @@ async function run() { } } -// https://stackoverflow.com/a/62436236 -function fixedEncodeURIComponent(str: string): string { - return encodeURIComponent(str).replace(/[!'()*]/g, (c) => { - return "%" + c.charCodeAt(0).toString(16); - }); -} - run(); From ceda15ef3dd18d75e79366ab85581565a204fa00 Mon Sep 17 00:00:00 2001 From: patrick brisbin Date: Thu, 30 May 2024 13:52:18 -0400 Subject: [PATCH 5/8] Build --- dist/index.js | 39 +++++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/dist/index.js b/dist/index.js index e6a286a..0bac425 100644 --- a/dist/index.js +++ b/dist/index.js @@ -136,7 +136,7 @@ var sr = __importStar(__nccwpck_require__(6889)); var inputs_1 = __nccwpck_require__(6180); function run() { return __awaiter(this, void 0, void 0, function () { - var _a, wizClientId, wizClientSecret, wizApiEndpointUrl, wizApiIdP, image, customPolicies, pull, fail_1, wizCredentials, wizcli, _b, scanId, scanPassed, result, summary, error_1, resultUrlBase, resultUrlHash, resultUrl, error_2; + var _a, wizClientId, wizClientSecret, wizApiEndpointUrl, wizApiIdP, image, customPolicies, pull, fail_1, wizCredentials, wizcli, _b, scanId, scanPassed, result, summary, error_1, error_2; return __generator(this, function (_c) { switch (_c.label) { case 0: @@ -157,7 +157,7 @@ function run() { return [4, wizcli.scan(image, customPolicies)]; case 4: _b = _c.sent(), scanId = _b.scanId, scanPassed = _b.scanPassed; - if (!wizApiEndpointUrl) return [3, 9]; + if (!(scanId && wizApiEndpointUrl)) return [3, 9]; _c.label = 5; case 5: _c.trys.push([5, 8, , 9]); @@ -182,16 +182,11 @@ function run() { } return [3, 9]; case 9: - resultUrlBase = "https://app.wiz.io/reports/cicd-scans"; - resultUrlHash = fixedEncodeURIComponent("~(cicd_scan~'".concat(scanId, ")")); - resultUrl = "".concat(resultUrlBase, "#").concat(resultUrlHash); if (scanPassed) { - core.info("Scan passed: ".concat(resultUrl)); core.setOutput("scan-id", scanId); core.setOutput("scan-result", "success"); } else { - core.warning("Scan failed: ".concat(resultUrl)); core.setOutput("scan-id", scanId); core.setOutput("scan-result", "failed"); if (fail_1) { @@ -216,11 +211,6 @@ function run() { }); }); } -function fixedEncodeURIComponent(str) { - return encodeURIComponent(str).replace(/[!'()*]/g, function (c) { - return "%" + c.charCodeAt(0).toString(16); - }); -} run(); @@ -488,7 +478,8 @@ var __generator = (this && this.__generator) || function (thisArg, body) { } }; Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.getWizCLI = void 0; +exports.parseScanId = exports.getWizCLI = void 0; +var core = __importStar(__nccwpck_require__(2186)); var exec = __importStar(__nccwpck_require__(1514)); var tc = __importStar(__nccwpck_require__(7784)); var WizCLI = (function () { @@ -526,10 +517,7 @@ var WizCLI = (function () { args = ["docker", "scan", "--image", image, "--no-style"].concat(policies ? ["--policy", policies] : []); scanId = null; listener = function (data) { - var match = data.toString().match(/cicd_scan~'([0-9a-f-]*)/); - if (match && match[1]) { - scanId = match[1]; - } + scanId = parseScanId(data.toString()); }; return [4, exec.exec(this.wizcli, args, { ignoreReturnCode: true, @@ -544,7 +532,7 @@ var WizCLI = (function () { throw new Error("wiz scan errored, status: ".concat(ec)); } if (!scanId) { - throw new Error("Unable to parse Scan Id from report"); + core.warning("Unable to parse Scan Id from report"); } scanPassed = ec === 0; return [2, { @@ -576,6 +564,21 @@ function getWizCLI(credentials) { }); } exports.getWizCLI = getWizCLI; +var SCAN_REGEXES = [ + new RegExp("cicd_scan~'([0-9a-f-]*)"), + new RegExp("cicd_scan%7E%27([0-9a-f-]*)%29"), +]; +function parseScanId(str) { + var scanId = null; + SCAN_REGEXES.forEach(function (regex) { + var match = str.match(regex); + if (match && match[1]) { + scanId = match[1]; + } + }); + return scanId; +} +exports.parseScanId = parseScanId; function getWizInstallUrl() { switch (process.platform) { case "win32": From 6f3dda2d3b8c7c833d024d41f65de2550675898e Mon Sep 17 00:00:00 2001 From: patrick brisbin Date: Thu, 30 May 2024 13:52:28 -0400 Subject: [PATCH 6/8] Add scan-id verification on CI --- .github/workflows/example.yaml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/workflows/example.yaml b/.github/workflows/example.yaml index 981bd08..2dfa189 100644 --- a/.github/workflows/example.yaml +++ b/.github/workflows/example.yaml @@ -26,6 +26,13 @@ jobs: fail: false pull: true + - name: Verify Scan Id + run: | + if [[ -z "${{ steps.scan.outputs.scan-id }}" ]]; then + echo "Scan step should've set a scan-id, it did not" >&2 + exit 1 + fi + - name: Verify scan result run: | result=${{ steps.scan.outputs.scan-result }} From 9ce37e02130c164d726cd4f6e888cdcc5a339bed Mon Sep 17 00:00:00 2001 From: patrick brisbin Date: Thu, 30 May 2024 14:08:59 -0400 Subject: [PATCH 7/8] Use more specific regex for Scan Ids --- src/wiz-cli.test.ts | 8 ++++---- src/wiz-cli.ts | 19 ++++--------------- 2 files changed, 8 insertions(+), 19 deletions(-) diff --git a/src/wiz-cli.test.ts b/src/wiz-cli.test.ts index 588dcf0..901486f 100644 --- a/src/wiz-cli.test.ts +++ b/src/wiz-cli.test.ts @@ -3,17 +3,17 @@ import { parseScanId } from "./wiz-cli"; describe("parseScanId", () => { it("parses un-encoded scan-id URLs", () => { const scanId = parseScanId( - "https://app.wiz.io/findings/cicd-scans#~(cicd_scan~'abc123)", + "https://app.wiz.io/findings/cicd-scans#~(cicd_scan~'8221aac6-eae9-4867-bbb6-91fbd1092f45)", ); - expect(scanId).toBe("abc123"); + expect(scanId).toBe("8221aac6-eae9-4867-bbb6-91fbd1092f45"); }); it("parses encoded scan-id URLs", () => { const scanId = parseScanId( - "https://app.wiz.io/findings/cicd-scans#%7E%28cicd_scan%7E%27def456%29", + "https://app.wiz.io/findings/cicd-scans#%7E%28cicd_scan%7E%278221aac6-eae9-4867-bbb6-91fbd1092f45%29", ); - expect(scanId).toBe("def456"); + expect(scanId).toBe("8221aac6-eae9-4867-bbb6-91fbd1092f45"); }); }); diff --git a/src/wiz-cli.ts b/src/wiz-cli.ts index c6d8b84..bde0991 100644 --- a/src/wiz-cli.ts +++ b/src/wiz-cli.ts @@ -76,24 +76,13 @@ export async function getWizCLI(credentials: WizCredentials): Promise { return new WizCLI(wizcli, credentials).auth(); } -const SCAN_REGEXES = [ - new RegExp("cicd_scan~'([0-9a-f-]*)"), - new RegExp("cicd_scan%7E%27([0-9a-f-]*)%29"), -]; +// Example: "8221aac6-eae9-4867-bbb6-91fbd1092f45" +const SCAN_ID_FORMAT = new RegExp("[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}"); // exported for testing export function parseScanId(str: string): string | null { - let scanId = null; - - SCAN_REGEXES.forEach((regex) => { - const match = str.match(regex); - - if (match && match[1]) { - scanId = match[1]; - } - }); - - return scanId; + const match = str.match(SCAN_ID_FORMAT); + return match ? match[0] : null; } function getWizInstallUrl(): string { From 79d95776f565b22e333245bcc11b26fb348b829f Mon Sep 17 00:00:00 2001 From: patrick brisbin Date: Thu, 30 May 2024 14:31:59 -0400 Subject: [PATCH 8/8] Build --- dist/index.js | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/dist/index.js b/dist/index.js index 0bac425..9726b3d 100644 --- a/dist/index.js +++ b/dist/index.js @@ -517,7 +517,9 @@ var WizCLI = (function () { args = ["docker", "scan", "--image", image, "--no-style"].concat(policies ? ["--policy", policies] : []); scanId = null; listener = function (data) { - scanId = parseScanId(data.toString()); + if (!scanId) { + scanId = parseScanId(data.toString()); + } }; return [4, exec.exec(this.wizcli, args, { ignoreReturnCode: true, @@ -564,19 +566,10 @@ function getWizCLI(credentials) { }); } exports.getWizCLI = getWizCLI; -var SCAN_REGEXES = [ - new RegExp("cicd_scan~'([0-9a-f-]*)"), - new RegExp("cicd_scan%7E%27([0-9a-f-]*)%29"), -]; +var SCAN_ID_FORMAT = new RegExp("[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}"); function parseScanId(str) { - var scanId = null; - SCAN_REGEXES.forEach(function (regex) { - var match = str.match(regex); - if (match && match[1]) { - scanId = match[1]; - } - }); - return scanId; + var match = str.match(SCAN_ID_FORMAT); + return match ? match[0] : null; } exports.parseScanId = parseScanId; function getWizInstallUrl() {