Skip to content

Commit 763018a

Browse files
ps-ekzantow
andauthored
feat: add support for cyclonedx and cyclonedx-json output-formats (#396)
Signed-off-by: Piotr Solarczyk <[email protected]> Signed-off-by: Keith Zantow <[email protected]> Co-authored-by: Keith Zantow <[email protected]>
1 parent e374579 commit 763018a

File tree

7 files changed

+106
-13
lines changed

7 files changed

+106
-13
lines changed

.gitignore

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,4 @@ typings/
119119
/grype-db
120120

121121
# Action temporary files
122-
results.sarif
123-
vulnerabilities.json
124-
results.json
122+
/results.*

README.md

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ The inputs `image`, `path`, and `sbom` are mutually exclusive to specify the sou
127127
| `registry-username` | The registry username to use when authenticating to an external registry | |
128128
| `registry-password` | The registry password to use when authenticating to an external registry | |
129129
| `fail-build` | Fail the build if a vulnerability is found with a higher severity. That severity defaults to `medium` and can be set with `severity-cutoff`. | `true` |
130-
| `output-format` | Set the output parameter after successful action execution. Valid choices are `json`, `sarif`, and `table`, where `table` output will print to the console instead of generating a file. | `sarif` |
130+
| `output-format` | Set the output parameter after successful action execution. Valid choices are `json`, `sarif`, `cyclonedx-xml`, `cyclonedx-json`, and `table`; where `table` output will also display in the logs. | `sarif` |
131131
| `output-file` | File to output the Grype scan results to. Defaults to a file in the system temp directory, available in the action outputs | |
132132
| `severity-cutoff` | Optionally specify the minimum vulnerability severity to trigger a failure. Valid choices are "negligible", "low", "medium", "high" and "critical". Any vulnerability with a severity less than this value will lead to a "warning" result. Default is "medium". | `medium` |
133133
| `only-fixed` | Specify whether to only report vulnerabilities that have a fix available. | `false` |
@@ -139,10 +139,12 @@ The inputs `image`, `path`, and `sbom` are mutually exclusive to specify the sou
139139

140140
### Action Outputs
141141

142-
| Output Name | Description | Type |
143-
| ----------- | ------------------------------------------------------------ | ------ |
144-
| `sarif` | Path to the SARIF report file, if `output-format` is `sarif` | string |
145-
| `json` | Path to the report file , if `output-format` is `json` | string |
142+
| Output Name | Description | Type |
143+
|------------------|--------------------------------------------------------------------------------|--------|
144+
| `sarif` | Path to the SARIF report file, if `output-format` is `sarif` | string |
145+
| `json` | Path to the report file , if `output-format` is `json` | string |
146+
| `cyclonedx-xml` | Path to the CycloneDX report file, if `output-format` is `cyclonedx` | string |
147+
| `cyclonedx-json` | Path to the CycloneDX JSON report file, if `output-format` is `cyclonedx-json` | string |
146148

147149
### Example Workflows
148150

action.yml

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ inputs:
1818
required: false
1919
default: "true"
2020
output-format:
21-
description: 'Set the output parameter after successful action execution. Valid choices are "json", "sarif", and "table".'
21+
description: 'Set the output parameter after successful action execution. Valid choices are "json", "sarif", "cyclonedx", "cyclonedx-json" and "table".'
2222
required: false
2323
default: "sarif"
2424
output-file:
@@ -51,9 +51,13 @@ inputs:
5151
required: false
5252
outputs:
5353
sarif:
54-
description: "Path to a SARIF report file for the image"
54+
description: "Path to a SARIF report file for the scan"
5555
json:
56-
description: "Path to a JSON report file for the image"
56+
description: "Path to a JSON report file for the scan"
57+
cyclonedx-xml:
58+
description: "Path to a CycloneDX XML report file for the scan"
59+
cyclonedx-json:
60+
description: "Path to a CycloneDX JSON report file for the scan"
5761
runs:
5862
using: "node20"
5963
main: "dist/index.js"

dist/index.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -329,7 +329,13 @@ async function runScan({
329329
}
330330

331331
const SEVERITY_LIST = ["negligible", "low", "medium", "high", "critical"];
332-
const FORMAT_LIST = ["sarif", "json", "table"];
332+
const FORMAT_LIST = [
333+
"sarif",
334+
"json",
335+
"table",
336+
"cyclonedx-xml",
337+
"cyclonedx-json",
338+
];
333339
let cmdArgs = [];
334340

335341
if (core.isDebug()) {

index.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -315,7 +315,13 @@ async function runScan({
315315
}
316316

317317
const SEVERITY_LIST = ["negligible", "low", "medium", "high", "critical"];
318-
const FORMAT_LIST = ["sarif", "json", "table"];
318+
const FORMAT_LIST = [
319+
"sarif",
320+
"json",
321+
"table",
322+
"cyclonedx-xml",
323+
"cyclonedx-json",
324+
];
319325
let cmdArgs = [];
320326

321327
if (core.isDebug()) {

tests/action.test.js

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,37 @@ describe("Github action", () => {
9090
expect(outputs["json"]).toBeFalsy();
9191
});
9292

93+
it("runs with cyclonedx-xml output", async () => {
94+
const outputs = mockIO({
95+
image: "",
96+
path: "tests/fixtures/npm-project",
97+
"fail-build": "true",
98+
"output-format": "cyclonedx-xml",
99+
"output-file": "./results.cdx.xml",
100+
"severity-cutoff": "medium",
101+
"add-cpes-if-none": "true",
102+
});
103+
104+
await run();
105+
106+
expect(outputs["cyclonedx-xml"]).toBe("./results.cdx.xml");
107+
});
108+
109+
it("runs with cyclonedx-json output", async () => {
110+
const outputs = mockIO({
111+
image: "",
112+
path: "tests/fixtures/npm-project",
113+
"fail-build": "true",
114+
"output-format": "cyclonedx-json",
115+
"severity-cutoff": "medium",
116+
"add-cpes-if-none": "true",
117+
});
118+
119+
await run();
120+
121+
expect(outputs["cyclonedx-json"]).toBeDefined();
122+
});
123+
93124
it("runs with environment variables", async () => {
94125
mockIO({
95126
path: "tests/fixtures/npm-project",

tests/grype_command.test.js

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,52 @@ describe("Grype command args", () => {
3030
]);
3131
});
3232

33+
it("is invoked with cyclonedx output", async () => {
34+
const args = await mockRun({
35+
source: "dir:.",
36+
"fail-build": "false",
37+
"output-file": "the-output-file",
38+
"output-format": "cyclonedx-xml",
39+
"severity-cutoff": "high",
40+
version: "0.6.0",
41+
"only-fixed": "false",
42+
"add-cpes-if-none": "false",
43+
"by-cve": "false",
44+
});
45+
expect(args).toEqual([
46+
"-o",
47+
"cyclonedx-xml",
48+
"--file",
49+
"the-output-file",
50+
"--fail-on",
51+
"high",
52+
"dir:.",
53+
]);
54+
});
55+
56+
it("is invoked with cyclonedx-json output", async () => {
57+
const args = await mockRun({
58+
source: "dir:.",
59+
"fail-build": "false",
60+
"output-file": "the-output-file",
61+
"output-format": "cyclonedx-json",
62+
"severity-cutoff": "high",
63+
version: "0.6.0",
64+
"only-fixed": "false",
65+
"add-cpes-if-none": "false",
66+
"by-cve": "false",
67+
});
68+
expect(args).toEqual([
69+
"-o",
70+
"cyclonedx-json",
71+
"--file",
72+
"the-output-file",
73+
"--fail-on",
74+
"high",
75+
"dir:.",
76+
]);
77+
});
78+
3379
it("is invoked with values", async () => {
3480
const args = await mockRun({
3581
image: "asdf",

0 commit comments

Comments
 (0)