Skip to content

Commit 3e6fbfb

Browse files
authored
Merge pull request #30 from homoluctus/feature/issue_option
Creating issue is optional
2 parents 1d7e70b + d334820 commit 3e6fbfb

File tree

8 files changed

+139
-48
lines changed

8 files changed

+139
-48
lines changed

.github/workflows/test.yml

Lines changed: 32 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -12,22 +12,6 @@ env:
1212
IMAGE_NAME: alpine:3.10.1
1313

1414
jobs:
15-
jest:
16-
name: Test with jest
17-
runs-on: ubuntu-18.04
18-
steps:
19-
- uses: actions/checkout@v1
20-
21-
- uses: actions/setup-node@v1
22-
with:
23-
node-version: '12.x'
24-
25-
- name: Install dependencies
26-
run: npm install
27-
28-
- name: Jest
29-
run: npm run test
30-
3115
test1:
3216
name: Test for with parameter
3317
runs-on: ubuntu-18.04
@@ -58,7 +42,7 @@ jobs:
5842
if: always()
5943
with:
6044
type: ${{ job.status }}
61-
job_name: ':ts: *test gitrivy*'
45+
job_name: ':ts: *test gitrivy (test1)*'
6246
channel: '#develop'
6347
url: ${{ secrets.SLACK_WEBHOOK }}
6448

@@ -91,6 +75,36 @@ jobs:
9175
if: always()
9276
with:
9377
type: ${{ job.status }}
94-
job_name: ':ts: *test gitrivy*'
78+
job_name: ':ts: *test gitrivy (test2)*'
79+
channel: '#develop'
80+
url: ${{ secrets.SLACK_WEBHOOK }}
81+
82+
test3:
83+
name: Test not to create issue
84+
runs-on: ubuntu-18.04
85+
steps:
86+
- uses: actions/checkout@v1
87+
88+
- name: Install dependencies
89+
run: npm install
90+
91+
# - name: Test
92+
# run: npm run test
93+
94+
- name: Build
95+
run: npm run build
96+
97+
- name: Pull docker image
98+
run: docker pull alpine:3.10.3
99+
100+
- uses: ./
101+
with:
102+
issue: 'false'
103+
104+
- uses: homoluctus/slatify@v1.9.0
105+
if: always()
106+
with:
107+
type: ${{ job.status }}
108+
job_name: ':ts: *test gitrivy (test3)*'
95109
channel: '#develop'
96110
url: ${{ secrets.SLACK_WEBHOOK }}

.github/workflows/unittest.yml

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
name: Unit Test
2+
3+
on:
4+
pull_request:
5+
paths:
6+
- 'src/**'
7+
- 'dist/**'
8+
- tsconfig.json
9+
- package*
10+
11+
jobs:
12+
jest:
13+
name: Test with jest
14+
runs-on: ubuntu-18.04
15+
steps:
16+
- uses: actions/checkout@v1
17+
18+
- uses: actions/setup-node@v1
19+
with:
20+
node-version: '12.x'
21+
22+
- name: Install dependencies
23+
run: npm install
24+
25+
- name: Jest
26+
run: npm run test

__tests__/trivy.test.ts

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -128,26 +128,55 @@ describe('Scan', () => {
128128
severity: 'HIGH,CRITICAL',
129129
vulnType: 'os,library',
130130
ignoreUnfixed: true,
131+
format: 'json',
131132
};
132-
const result: Vulnerability[] = Trivy.scan(trivyPath, image, options);
133+
const result: Vulnerability[] | string = Trivy.scan(
134+
trivyPath,
135+
image,
136+
options
137+
);
133138
expect(result.length).toBeGreaterThanOrEqual(1);
139+
expect(result).toBeInstanceOf(Object);
134140
});
135141

136142
test('without ignoreUnfixed', () => {
137143
const options: TrivyOption = {
138144
severity: 'HIGH,CRITICAL',
139145
vulnType: 'os,library',
140146
ignoreUnfixed: false,
147+
format: 'json',
141148
};
142-
const result: Vulnerability[] = Trivy.scan(trivyPath, image, options);
149+
const result: Vulnerability[] | string = Trivy.scan(
150+
trivyPath,
151+
image,
152+
options
153+
);
154+
expect(result.length).toBeGreaterThanOrEqual(1);
155+
expect(result).toBeInstanceOf(Object);
156+
});
157+
158+
test('with table format', () => {
159+
const options: TrivyOption = {
160+
severity: 'HIGH,CRITICAL',
161+
vulnType: 'os,library',
162+
ignoreUnfixed: false,
163+
format: 'table',
164+
};
165+
const result: Vulnerability[] | string = Trivy.scan(
166+
trivyPath,
167+
image,
168+
options
169+
);
143170
expect(result.length).toBeGreaterThanOrEqual(1);
171+
expect(result).toMatch(/alpine:3\.10/);
144172
});
145173

146174
test('with invalid severity', () => {
147175
const invalidOption: TrivyOption = {
148176
severity: 'INVALID',
149177
vulnType: 'os,library',
150178
ignoreUnfixed: true,
179+
format: 'json',
151180
};
152181
expect(() => {
153182
Trivy.scan(trivyPath, image, invalidOption);
@@ -159,6 +188,7 @@ describe('Scan', () => {
159188
severity: 'HIGH',
160189
vulnType: 'INVALID',
161190
ignoreUnfixed: true,
191+
format: 'json',
162192
};
163193
expect(() => {
164194
Trivy.scan(trivyPath, image, invalidOption);

action.yml

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,6 @@ name: 'Trivy Action'
22
description: 'Scan docker image vulnerability using Trivy and create GitHub Issue'
33
author: 'homoluctus'
44
inputs:
5-
token:
6-
description: 'GitHub access token'
7-
required: true
85
trivy_version:
96
description: 'Trivy version'
107
default: 'latest'
@@ -24,6 +21,13 @@ inputs:
2421
description: 'Ignore unfixed vulnerabilities [true, false]'
2522
default: 'false'
2623
required: false
24+
issue:
25+
description: 'Decide whether to create a issue when vulnerabilities are found [true, false]'
26+
default: 'true'
27+
required: false
28+
token:
29+
description: 'GitHub access token used to create a issue'
30+
required: false
2731
issue_title:
2832
description: 'Issue title'
2933
default: 'Security Alert'

dist/index.js

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6572,28 +6572,35 @@ const issue_1 = __webpack_require__(163);
65726572
function run() {
65736573
return __awaiter(this, void 0, void 0, function* () {
65746574
try {
6575-
const token = core.getInput('token', { required: true });
65766575
const trivyVersion = core
65776576
.getInput('trivy_version')
65786577
.replace(/^v/, '');
65796578
const image = core.getInput('image') || process.env.IMAGE_NAME;
6579+
const issueFlag = core.getInput('issue').toLowerCase() == 'true';
65806580
if (image === undefined || image === '') {
65816581
throw new Error('Please specify scan target image name');
65826582
}
6583-
const trivyOptions = {
6583+
const trivyOption = {
65846584
severity: core.getInput('severity').replace(/\s+/g, ''),
65856585
vulnType: core.getInput('vuln_type').replace(/\s+/g, ''),
65866586
ignoreUnfixed: core.getInput('ignore_unfixed').toLowerCase() === 'true',
6587+
format: issueFlag ? 'json' : 'table',
65876588
};
65886589
const downloader = new trivy_1.Downloader();
65896590
const trivyCmdPath = yield downloader.download(trivyVersion);
6590-
const result = trivy_1.Trivy.scan(trivyCmdPath, image, trivyOptions);
6591+
const result = trivy_1.Trivy.scan(trivyCmdPath, image, trivyOption);
6592+
if (!issueFlag) {
6593+
core.info(`Not create a issue because issue parameter is false.
6594+
Vulnerabilities:
6595+
${result}`);
6596+
return;
6597+
}
65916598
const issueContent = trivy_1.Trivy.parse(result);
65926599
if (issueContent === '') {
65936600
core.info('Vulnerabilities were not found.\nYour maintenance looks good 👍');
65946601
return;
65956602
}
6596-
const issueOptions = {
6603+
const issueOption = {
65976604
title: core.getInput('issue_title'),
65986605
body: issueContent,
65996606
labels: core
@@ -6605,7 +6612,8 @@ function run() {
66056612
.replace(/\s+/g, '')
66066613
.split(','),
66076614
};
6608-
const output = yield issue_1.createIssue(token, issueOptions);
6615+
const token = core.getInput('token', { required: true });
6616+
const output = yield issue_1.createIssue(token, issueOption);
66096617
core.setOutput('html_url', output.htmlUrl);
66106618
core.setOutput('issue_number', output.issueNumber.toString());
66116619
}
@@ -13315,19 +13323,18 @@ class Trivy {
1331513323
'--vuln-type',
1331613324
option.vulnType,
1331713325
'--format',
13318-
'json',
13326+
option.format,
1331913327
'--quiet',
1332013328
'--no-progress',
1332113329
];
13322-
if (option.ignoreUnfixed) {
13330+
if (option.ignoreUnfixed)
1332313331
args.push('--ignore-unfixed');
13324-
}
1332513332
args.push(image);
1332613333
const result = child_process_1.spawnSync(trivyPath, args, {
1332713334
encoding: 'utf-8',
1332813335
});
1332913336
if (result.stdout && result.stdout.length > 0) {
13330-
const vulnerabilities = JSON.parse(result.stdout);
13337+
const vulnerabilities = option.format === 'json' ? JSON.parse(result.stdout) : result.stdout;
1333113338
if (vulnerabilities.length > 0) {
1333213339
return vulnerabilities;
1333313340
}
@@ -13359,7 +13366,6 @@ class Trivy {
1335913366
}
1336013367
issueContent += `${vulnTable}\n\n`;
1336113368
}
13362-
console.debug(issueContent);
1336313369
return issueContent;
1336413370
}
1336513371
static validateOption(option) {

src/index.ts

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,31 +10,42 @@ import {
1010

1111
async function run() {
1212
try {
13-
const token: string = core.getInput('token', { required: true });
1413
const trivyVersion: string = core
1514
.getInput('trivy_version')
1615
.replace(/^v/, '');
1716
const image: string | undefined =
1817
core.getInput('image') || process.env.IMAGE_NAME;
18+
const issueFlag: boolean = core.getInput('issue').toLowerCase() == 'true';
1919

2020
if (image === undefined || image === '') {
2121
throw new Error('Please specify scan target image name');
2222
}
2323

24-
const trivyOptions: TrivyOption = {
24+
const trivyOption: TrivyOption = {
2525
severity: core.getInput('severity').replace(/\s+/g, ''),
2626
vulnType: core.getInput('vuln_type').replace(/\s+/g, ''),
2727
ignoreUnfixed: core.getInput('ignore_unfixed').toLowerCase() === 'true',
28+
format: issueFlag ? 'json' : 'table',
2829
};
2930

3031
const downloader = new Downloader();
3132
const trivyCmdPath: string = await downloader.download(trivyVersion);
32-
const result: Vulnerability[] = Trivy.scan(
33+
const result: Vulnerability[] | string = Trivy.scan(
3334
trivyCmdPath,
3435
image,
35-
trivyOptions
36+
trivyOption
3637
);
37-
const issueContent: string = Trivy.parse(result);
38+
39+
if (!issueFlag) {
40+
core.info(
41+
`Not create a issue because issue parameter is false.
42+
Vulnerabilities:
43+
${result}`
44+
);
45+
return;
46+
}
47+
48+
const issueContent: string = Trivy.parse(result as Vulnerability[]);
3849

3950
if (issueContent === '') {
4051
core.info(
@@ -43,7 +54,7 @@ async function run() {
4354
return;
4455
}
4556

46-
const issueOptions: IssueOption = {
57+
const issueOption: IssueOption = {
4758
title: core.getInput('issue_title'),
4859
body: issueContent,
4960
labels: core
@@ -55,7 +66,8 @@ async function run() {
5566
.replace(/\s+/g, '')
5667
.split(','),
5768
};
58-
const output: IssueResponse = await createIssue(token, issueOptions);
69+
const token: string = core.getInput('token', { required: true });
70+
const output: IssueResponse = await createIssue(token, issueOption);
5971
core.setOutput('html_url', output.htmlUrl);
6072
core.setOutput('issue_number', output.issueNumber.toString());
6173
} catch (error) {

src/interface.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ export interface TrivyOption {
1414
severity: string;
1515
vulnType: string;
1616
ignoreUnfixed: boolean;
17+
format: string;
1718
}
1819

1920
export interface Vulnerability {

src/trivy.ts

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ export class Trivy {
123123
trivyPath: string,
124124
image: string,
125125
option: TrivyOption
126-
): Vulnerability[] {
126+
): Vulnerability[] | string {
127127
Trivy.validateOption(option);
128128

129129
const args: string[] = [
@@ -132,22 +132,21 @@ export class Trivy {
132132
'--vuln-type',
133133
option.vulnType,
134134
'--format',
135-
'json',
135+
option.format,
136136
'--quiet',
137137
'--no-progress',
138138
];
139139

140-
if (option.ignoreUnfixed) {
141-
args.push('--ignore-unfixed');
142-
}
143-
140+
if (option.ignoreUnfixed) args.push('--ignore-unfixed');
144141
args.push(image);
142+
145143
const result: SpawnSyncReturns<string> = spawnSync(trivyPath, args, {
146144
encoding: 'utf-8',
147145
});
148146

149147
if (result.stdout && result.stdout.length > 0) {
150-
const vulnerabilities: Vulnerability[] = JSON.parse(result.stdout);
148+
const vulnerabilities: Vulnerability[] | string =
149+
option.format === 'json' ? JSON.parse(result.stdout) : result.stdout;
151150
if (vulnerabilities.length > 0) {
152151
return vulnerabilities;
153152
}
@@ -185,7 +184,6 @@ export class Trivy {
185184
}
186185
issueContent += `${vulnTable}\n\n`;
187186
}
188-
console.debug(issueContent);
189187
return issueContent;
190188
}
191189

0 commit comments

Comments
 (0)