Skip to content

Support trivy template option #88

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Jun 3, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .prettierrc.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
semi: true
singleQuote: true
trailingComma: es5
trailingComma: none
parser": typescript
bracketSpacing: true
14 changes: 6 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,7 @@ If vulnerabilities are found by Trivy, it creates the following GitHub Issue.

![image](./assets/img/issue.png)

## Usage

### Inputs
## Inputs

|Parameter|Required|Default Value|Description|
|:--:|:--:|:--:|:--|
Expand All @@ -22,21 +20,21 @@ If vulnerabilities are found by Trivy, it creates the following GitHub Issue.
|severity|False|HIGH,CRITICAL|Severities of vulnerabilities (separated by commma)|
|vuln_type|False|os,library|Scan target are os and / or library (separated by commma)|
|ignore_unfixed|False|false|Ignore unfixed vulnerabilities<br>Please specify `true` or `false`|
|issue|False|true|Decide whether creating issue when vulnerabilities are found by trivy.<br>Please specify `true` or `false`|
|token|True if issue parameter is true else False|N/A|GitHub Access Token.<br>${{ secrets.GITHUB_TOKEN }} is recommended.|
|template|False|N/A|Trivy --template option<br>By default, it uses src/template/default.tpl which is based on [contrib/html.tpl](https://github.com/aquasecurity/trivy/blob/main/contrib/html.tpl)<br>reference: [Report Formats - Trivy](https://aquasecurity.github.io/trivy/v0.18.3/examples/report/#template)|
|token|True|N/A|GitHub Access Token.<br>${{ secrets.GITHUB_TOKEN }} is recommended.|
|issue_title|False|Security Alert|Issue title|
|issue_label|False|trivy,vulnerability|Issue label (separated by commma)|
|issue_assignee|False|N/A|Issue assignee (separated by commma)|
|fail_on_vulnerabilities|False|false|Whether the action should fail if any vulnerabilities were found.|

### Outputs
## Outputs

|Parameter|Description|
|:--:|:--|
|html_url|The URL to view the issue|
|issue_number|The created issue number|

## Example Workflow
## Example

Detect your docker image vulnerability everyday at 9:00 (UTC).

Expand All @@ -55,7 +53,7 @@ jobs:
- name: Pull docker image
run: docker pull sample

- uses: lazy-actions/gitrivy@main
- uses: lazy-actions/gitrivy@v2
with:
token: ${{ secrets.GITHUB_TOKEN }}
image: sample
Expand Down
20 changes: 20 additions & 0 deletions __tests__/downloader.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,3 +97,23 @@ describe('Trivy command', () => {
expect(result).toBeFalsy();
});
});

describe('Exists trivy command', () => {
beforeAll(() => {
fs.writeFileSync('./trivy', '');
});

afterAll(() => {
removeTrivyCmd('.');
});

test('exists', () => {
const result = downloader.trivyExists('.');
expect(result).toBeTruthy();
});

test('does not exist', () => {
const result = downloader.trivyExists('src');
expect(result).toBeFalsy();
});
});
201 changes: 13 additions & 188 deletions __tests__/trivy.test.ts
Original file line number Diff line number Diff line change
@@ -1,35 +1,15 @@
import * as fs from 'fs';
import * as path from 'path';
import { Downloader } from '../src/downloader';
import { Trivy } from '../src/trivy';
import { Vulnerability, TrivyOption } from '../src/interface';
import { scan } from '../src/trivy';
import { TrivyOption } from '../src/interface';
import { removeTrivyCmd } from './helper';

const downloader = new Downloader();
const trivy = new Trivy();

describe('Trivy command', () => {
beforeAll(() => {
fs.writeFileSync('./trivy', '');
});

afterAll(() => {
removeTrivyCmd('.');
});

test('exists', () => {
const result = downloader.trivyExists('.');
expect(result).toBeTruthy();
});

test('does not exist', () => {
const result = downloader.trivyExists('src');
expect(result).toBeFalsy();
});
});
const template = path.join(__dirname, '../src/template/default.tpl');

describe('Trivy scan', () => {
let trivyPath: string;
const image: string = 'alpine:3.10';
const image = 'knqyf263/vuln-image';

beforeAll(async () => {
trivyPath = !downloader.trivyExists(__dirname)
Expand All @@ -46,58 +26,32 @@ describe('Trivy scan', () => {
severity: 'HIGH,CRITICAL',
vulnType: 'os,library',
ignoreUnfixed: true,
format: 'json',
template
};
const result: Vulnerability[] | string = trivy.scan(
trivyPath,
image,
option
);
const result = scan(trivyPath, image, option) as string;
expect(result.length).toBeGreaterThanOrEqual(1);
expect(result).toBeInstanceOf(Object);
});

test('without ignoreUnfixed', () => {
const option: TrivyOption = {
severity: 'HIGH,CRITICAL',
vulnType: 'os,library',
ignoreUnfixed: false,
format: 'json',
template
};
const result: Vulnerability[] | string = trivy.scan(
trivyPath,
image,
option
);
const result: string = scan(trivyPath, image, option) as string;
expect(result.length).toBeGreaterThanOrEqual(1);
expect(result).toBeInstanceOf(Object);
});

test('with table format', () => {
const option: TrivyOption = {
severity: 'HIGH,CRITICAL',
vulnType: 'os,library',
ignoreUnfixed: false,
format: 'table',
};
const result: Vulnerability[] | string = trivy.scan(
trivyPath,
image,
option
);
expect(result.length).toBeGreaterThanOrEqual(1);
expect(result).toMatch(/alpine:3\.10/);
});

test('with invalid severity', () => {
const invalidOption: TrivyOption = {
severity: 'INVALID',
vulnType: 'os,library',
ignoreUnfixed: true,
format: 'json',
template
};
expect(() => {
trivy.scan(trivyPath, image, invalidOption);
scan(trivyPath, image, invalidOption);
}).toThrowError('Trivy option error: INVALID is unknown severity');
});

Expand All @@ -106,139 +60,10 @@ describe('Trivy scan', () => {
severity: 'HIGH',
vulnType: 'INVALID',
ignoreUnfixed: true,
format: 'json',
template
};
expect(() => {
trivy.scan(trivyPath, image, invalidOption);
scan(trivyPath, image, invalidOption);
}).toThrowError('Trivy option error: INVALID is unknown vuln-type');
});
});

describe('Parse', () => {
const image: string = 'alpine:3.10';

test('the result without vulnerabilities', () => {
const vulnerabilities: Vulnerability[] = [
{
Target: 'alpine:3.10 (alpine 3.10.3)',
Vulnerabilities: null,
},
];
const result = trivy.parse(image, vulnerabilities);
expect(result).toBe('');
});

test('the result including vulnerabilities', () => {
const vulnerabilities: Vulnerability[] = [
{
Target: 'alpine:3.9 (alpine 3.9.4)',
Vulnerabilities: [
{
VulnerabilityID: 'CVE-2019-14697',
PkgName: 'musl',
InstalledVersion: '1.1.20-r4',
FixedVersion: '1.1.20-r5',
Description:
"musl libc through 1.1.23 has an x87 floating-point stack adjustment imbalance, related to the math/i386/ directory. In some cases, use of this library could introduce out-of-bounds writes that are not present in an application's source code.",
Severity: 'HIGH',
References: [
'http://www.openwall.com/lists/oss-security/2019/08/06/4',
'https://www.openwall.com/lists/musl/2019/08/06/1',
],
},
{
VulnerabilityID: 'CVE-2019-1549',
PkgName: 'openssl',
InstalledVersion: '1.1.1b-r1',
FixedVersion: '1.1.1d-r0',
Title: 'openssl: information disclosure in fork()',
Description:
'OpenSSL 1.1.1 introduced a rewritten random number generator (RNG). This was intended to include protection in the event of a fork() system call in order to ensure that the parent and child processes did not share the same RNG state. However this protection was not being used in the default case. A partial mitigation for this issue is that the output from a high precision timer is mixed into the RNG state so the likelihood of a parent and child process sharing state is significantly reduced. If an application already calls OPENSSL_init_crypto() explicitly using OPENSSL_INIT_ATFORK then this problem does not occur at all. Fixed in OpenSSL 1.1.1d (Affected 1.1.1-1.1.1c).',
Severity: 'MEDIUM',
References: [
'https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-1549',
'https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff;h=1b0fe00e2704b5e20334a16d3c9099d1ba2ef1be',
'https://lists.fedoraproject.org/archives/list/[email protected]/message/GY6SNRJP2S7Y42GIIDO3HXPNMDYN2U3A/',
'https://security.netapp.com/advisory/ntap-20190919-0002/',
'https://support.f5.com/csp/article/K44070243',
'https://www.openssl.org/news/secadv/20190910.txt',
],
},
],
},
];
const result = trivy.parse(image, vulnerabilities);
expect(result).toMatch(
/\|Title\|Severity\|CVE\|Package Name\|Installed Version\|Fixed Version\|References\|/
);
expect(result).toContain(image);
});
});

describe('Validate trivy option', () => {
test('with a valid severity', () => {
const options: string[] = ['HIGH'];
const result = trivy['validateSeverity'](options);
expect(result).toBeTruthy();
});

test('with two valid severities', () => {
const options: string[] = ['HIGH', 'CRITICAL'];
const result = trivy['validateSeverity'](options);
expect(result).toBeTruthy();
});

test('with an invalid severity', () => {
const options: string[] = ['INVALID'];
expect(() => {
trivy['validateSeverity'](options);
}).toThrowError('Trivy option error: INVALID is unknown severity');
});

test('with two invalid severities', () => {
const options: string[] = ['INVALID', 'ERROR'];
expect(() => {
trivy['validateSeverity'](options);
}).toThrowError('Trivy option error: INVALID,ERROR is unknown severity');
});

test('with an invalid and a valid severities', () => {
const options: string[] = ['INVALID', 'HIGH'];
expect(() => {
trivy['validateSeverity'](options);
}).toThrowError('Trivy option error: INVALID,HIGH is unknown severity');
});

test('with a valid vuln-type', () => {
const options: string[] = ['os'];
const result = trivy['validateVulnType'](options);
expect(result).toBeTruthy();
});

test('with two valid vuln-types', () => {
const options: string[] = ['os', 'library'];
const result = trivy['validateVulnType'](options);
expect(result).toBeTruthy();
});

test('with an invalid vuln-type', () => {
const options: string[] = ['INVALID'];
expect(() => {
trivy['validateVulnType'](options);
}).toThrowError('Trivy option error: INVALID is unknown vuln-type');
});

test('with two invalid vuln-types', () => {
const options: string[] = ['INVALID', 'ERROR'];
expect(() => {
trivy['validateVulnType'](options);
}).toThrowError('Trivy option error: INVALID,ERROR is unknown vuln-type');
});

test('with a valid and an invalid vuln-types', () => {
const options: string[] = ['INVALID', 'os'];
expect(() => {
trivy['validateVulnType'](options);
}).toThrowError('Trivy option error: INVALID,os is unknown vuln-type');
});
});
12 changes: 0 additions & 12 deletions __tests__/utils.test.ts

This file was deleted.

9 changes: 4 additions & 5 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,12 @@ inputs:
description: 'Ignore unfixed vulnerabilities [true, false]'
default: 'false'
required: false
issue:
description: 'Decide whether to create a issue when vulnerabilities are found [true, false]'
default: 'true'
required: false
template:
description: 'Trivy --template option'
required: false
token:
description: 'GitHub access token used to create a issue'
required: false
required: true
issue_title:
description: 'Issue title'
default: 'Security Alert'
Expand Down
Loading