Add none as option for fail-on-severity

This commit is contained in:
tgrall
2023-03-17 21:11:39 +01:00
parent e3fb5152be
commit 621d03bf3a
7 changed files with 83 additions and 29 deletions

View File

@@ -68,7 +68,7 @@ Configure this action by either inlining these options in your workflow file, or
| Option | Usage | Possible values | Default value |
| ----------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------- | ------------- |
| `fail-on-severity` | Defines the threshold for the level of severity. The action will fail on any pull requests that introduce vulnerabilities of the specified severity level or higher. | `low`, `moderate`, `high`, `critical` | `low` |
| `fail-on-severity` | Defines the threshold for the level of severity. The action will fail on any pull requests that introduce vulnerabilities of the specified severity level or higher. | `low`, `moderate`, `high`, `critical`, `none`+ | `low` |
| `allow-licenses`* | Contains a list of allowed licenses. The action will fail on pull requests that introduce dependencies with licenses that do not match the list. | Any [SPDX-compliant identifier(s)](https://spdx.org/licenses/) | none |
| `deny-licenses`* | Contains a list of prohibited licenses. The action will fail on pull requests that introduce dependencies with licenses that match the list. | Any [SPDX-compliant identifier(s)](https://spdx.org/licenses/) | none |
| `fail-on-scopes`† | Contains a list of strings of the build environments you want to support. The action will fail on pull requests that introduce vulnerabilities in the scopes that match the list. | `runtime`, `development`, `unknown` | `runtime` |
@@ -82,6 +82,8 @@ Configure this action by either inlining these options in your workflow file, or
†will be supported with GitHub Enterprise Server 3.8
+when `fail-on-severity` is set to `none`, the action will not fail on any vulnerabilities or invalid licenses. This is useful if you want to use the action to generate a report of vulnerabilities and invalid licenses, but not fail the workflow.
### Inline Configuration
You can pass options to the Dependency Review GitHub Action using your workflow file.

View File

@@ -54,6 +54,13 @@ test('it reads custom configs', async () => {
expect(config.allow_licenses).toEqual(['BSD', 'GPL 2'])
})
test('it defaults to none severity', async () => {
setInput('fail-on-severity', 'none')
const config = await readConfig()
expect(config.fail_on_severity).toEqual('none')
})
test('it defaults to empty allow/deny lists ', async () => {
const config = await readConfig()

View File

@@ -7,7 +7,7 @@ inputs:
required: false
default: ${{ github.token }}
fail-on-severity:
description: Don't block PRs below this severity. Possible values are `low`, `moderate`, `high`, `critical`.
description: Don't block PRs below this severity. Possible values are `low`, `moderate`, `high`, `critical`, `none`.
required: false
default: 'low'
fail-on-scopes:

51
dist/index.js generated vendored
View File

@@ -462,7 +462,13 @@ function run() {
core.info('No Dependency Changes found. Skipping Dependency Review.');
return;
}
const minSeverity = config.fail_on_severity;
// config.fail_on_severity
const failOnSeverityParams = config.fail_on_severity;
const failOnVulnerability = (config.fail_on_severity != 'none');
let minSeverity = 'low';
if (failOnSeverityParams != 'none') {
minSeverity = failOnSeverityParams;
}
const scopedChanges = (0, filter_1.filterChangesByScopes)(config.fail_on_scopes, changes);
const filteredChanges = (0, filter_1.filterAllowedAdvisories)(config.allow_ghsas, scopedChanges);
const vulnerableChanges = (0, filter_1.filterChangesBySeverity)(minSeverity, filteredChanges).filter(change => change.change_type === 'added' &&
@@ -475,11 +481,11 @@ function run() {
summary.addSummaryToSummary(vulnerableChanges, invalidLicenseChanges, config);
if (config.vulnerability_check) {
summary.addChangeVulnerabilitiesToSummary(vulnerableChanges, minSeverity);
printVulnerabilitiesBlock(vulnerableChanges, minSeverity);
printVulnerabilitiesBlock(vulnerableChanges, minSeverity, failOnVulnerability);
}
if (config.license_check) {
summary.addLicensesToSummary(invalidLicenseChanges, config);
printLicensesBlock(invalidLicenseChanges);
printLicensesBlock(invalidLicenseChanges, failOnVulnerability);
}
summary.addScannedDependencies(changes);
printScannedDependencies(changes);
@@ -508,17 +514,24 @@ function run() {
}
});
}
function printVulnerabilitiesBlock(addedChanges, minSeverity) {
let failed = false;
function printVulnerabilitiesBlock(addedChanges, minSeverity, failOnVulnerability) {
let vulFound = false;
core.group('Vulnerabilities', () => __awaiter(this, void 0, void 0, function* () {
if (addedChanges.length > 0) {
for (const change of addedChanges) {
printChangeVulnerabilities(change);
}
failed = true;
vulFound = true;
}
if (failed) {
core.setFailed('Dependency review detected vulnerable packages.');
if (vulFound) {
const msg = 'Dependency review detected vulnerable packages.';
if (failOnVulnerability) {
const msg = 'Dependency review detected vulnerable packages.';
core.setFailed(msg);
}
else {
core.warning(msg);
}
}
else {
core.info(`Dependency review did not detect any vulnerable packages with severity level "${minSeverity}" or higher.`);
@@ -531,12 +544,18 @@ function printChangeVulnerabilities(change) {
core.info(`${vuln.advisory_url}`);
}
}
function printLicensesBlock(invalidLicenseChanges) {
function printLicensesBlock(invalidLicenseChanges, failOnVulnerability) {
core.group('Licenses', () => __awaiter(this, void 0, void 0, function* () {
if (invalidLicenseChanges.forbidden.length > 0) {
core.info('\nThe following dependencies have incompatible licenses:');
printLicensesError(invalidLicenseChanges.forbidden);
core.setFailed('Dependency review detected incompatible licenses.');
const msg = 'Dependency review detected incompatible licenses.';
if (failOnVulnerability) {
core.setFailed(msg);
}
else {
core.warning(msg);
}
}
if (invalidLicenseChanges.unresolved.length > 0) {
core.warning('\nThe validity of the licenses of the dependencies below could not be determined. Ensure that they are valid SPDX licenses:');
@@ -630,10 +649,12 @@ var __importStar = (this && this.__importStar) || function (mod) {
return result;
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.ChangesSchema = exports.ConfigurationOptionsSchema = exports.PullRequestSchema = exports.ChangeSchema = exports.SeveritySchema = exports.SCOPES = exports.SEVERITIES = void 0;
exports.ChangesSchema = exports.ConfigurationOptionsSchema = exports.PullRequestSchema = exports.ChangeSchema = exports.SeveritySchema = exports.FailOnSeveritySchema = exports.SCOPES = exports.SEVERITIES = exports.FAIL_ON_SEVERITIES = void 0;
const z = __importStar(__nccwpck_require__(3301));
exports.FAIL_ON_SEVERITIES = ['critical', 'high', 'moderate', 'low', 'none'];
exports.SEVERITIES = ['critical', 'high', 'moderate', 'low'];
exports.SCOPES = ['unknown', 'runtime', 'development'];
exports.FailOnSeveritySchema = z.enum(exports.FAIL_ON_SEVERITIES).default('low');
exports.SeveritySchema = z.enum(exports.SEVERITIES).default('low');
exports.ChangeSchema = z.object({
change_type: z.enum(['added', 'removed']),
@@ -662,7 +683,7 @@ exports.PullRequestSchema = z.object({
});
exports.ConfigurationOptionsSchema = z
.object({
fail_on_severity: exports.SeveritySchema,
fail_on_severity: exports.FailOnSeveritySchema,
fail_on_scopes: z.array(z.enum(exports.SCOPES)).default(['runtime']),
allow_licenses: z.array(z.string()).optional(),
deny_licenses: z.array(z.string()).optional(),
@@ -45083,10 +45104,12 @@ var __importStar = (this && this.__importStar) || function (mod) {
return result;
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.ChangesSchema = exports.ConfigurationOptionsSchema = exports.PullRequestSchema = exports.ChangeSchema = exports.SeveritySchema = exports.SCOPES = exports.SEVERITIES = void 0;
exports.ChangesSchema = exports.ConfigurationOptionsSchema = exports.PullRequestSchema = exports.ChangeSchema = exports.SeveritySchema = exports.FailOnSeveritySchema = exports.SCOPES = exports.SEVERITIES = exports.FAIL_ON_SEVERITIES = void 0;
const z = __importStar(__nccwpck_require__(3301));
exports.FAIL_ON_SEVERITIES = ['critical', 'high', 'moderate', 'low', 'none'];
exports.SEVERITIES = ['critical', 'high', 'moderate', 'low'];
exports.SCOPES = ['unknown', 'runtime', 'development'];
exports.FailOnSeveritySchema = z.enum(exports.FAIL_ON_SEVERITIES).default('low');
exports.SeveritySchema = z.enum(exports.SEVERITIES).default('low');
exports.ChangeSchema = z.object({
change_type: z.enum(['added', 'removed']),
@@ -45115,7 +45138,7 @@ exports.PullRequestSchema = z.object({
});
exports.ConfigurationOptionsSchema = z
.object({
fail_on_severity: exports.SeveritySchema,
fail_on_severity: exports.FailOnSeveritySchema,
fail_on_scopes: z.array(z.enum(exports.SCOPES)).default(['runtime']),
allow_licenses: z.array(z.string()).optional(),
deny_licenses: z.array(z.string()).optional(),

2
dist/index.js.map generated vendored

File diff suppressed because one or more lines are too long

View File

@@ -3,7 +3,7 @@ import * as dependencyGraph from './dependency-graph'
import * as github from '@actions/github'
import styles from 'ansi-styles'
import {RequestError} from '@octokit/request-error'
import {Change, Severity, Changes} from './schemas'
import {Change, Severity, Changes, FailOnSeverity} from './schemas'
import {readConfig} from '../src/config'
import {
filterChangesBySeverity,
@@ -33,8 +33,14 @@ async function run(): Promise<void> {
core.info('No Dependency Changes found. Skipping Dependency Review.')
return
}
// config.fail_on_severity
const failOnSeverityParams = config.fail_on_severity
const failOnVulnerability = (config.fail_on_severity != 'none')
let minSeverity: Severity = 'low'
if (failOnSeverityParams != 'none') {
minSeverity = failOnSeverityParams
}
const minSeverity = config.fail_on_severity
const scopedChanges = filterChangesByScopes(config.fail_on_scopes, changes)
const filteredChanges = filterAllowedAdvisories(
config.allow_ghsas,
@@ -67,11 +73,11 @@ async function run(): Promise<void> {
if (config.vulnerability_check) {
summary.addChangeVulnerabilitiesToSummary(vulnerableChanges, minSeverity)
printVulnerabilitiesBlock(vulnerableChanges, minSeverity)
printVulnerabilitiesBlock(vulnerableChanges, minSeverity, failOnVulnerability)
}
if (config.license_check) {
summary.addLicensesToSummary(invalidLicenseChanges, config)
printLicensesBlock(invalidLicenseChanges)
printLicensesBlock(invalidLicenseChanges, failOnVulnerability)
}
summary.addScannedDependencies(changes)
@@ -102,19 +108,26 @@ async function run(): Promise<void> {
function printVulnerabilitiesBlock(
addedChanges: Changes,
minSeverity: Severity
minSeverity: Severity,
failOnVulnerability: boolean
): void {
let failed = false
let vulFound = false
core.group('Vulnerabilities', async () => {
if (addedChanges.length > 0) {
for (const change of addedChanges) {
printChangeVulnerabilities(change)
}
failed = true
vulFound = true
}
if (failed) {
core.setFailed('Dependency review detected vulnerable packages.')
if (vulFound) {
const msg = 'Dependency review detected vulnerable packages.'
if (failOnVulnerability) {
const msg = 'Dependency review detected vulnerable packages.'
core.setFailed(msg)
} else {
core.warning(msg)
}
} else {
core.info(
`Dependency review did not detect any vulnerable packages with severity level "${minSeverity}" or higher.`
@@ -137,13 +150,19 @@ function printChangeVulnerabilities(change: Change): void {
}
function printLicensesBlock(
invalidLicenseChanges: Record<string, Changes>
invalidLicenseChanges: Record<string, Changes>,
failOnVulnerability: boolean
): void {
core.group('Licenses', async () => {
if (invalidLicenseChanges.forbidden.length > 0) {
core.info('\nThe following dependencies have incompatible licenses:')
printLicensesError(invalidLicenseChanges.forbidden)
core.setFailed('Dependency review detected incompatible licenses.')
const msg = 'Dependency review detected incompatible licenses.';
if (failOnVulnerability) {
core.setFailed(msg)
} else {
core.warning(msg)
}
}
if (invalidLicenseChanges.unresolved.length > 0) {
core.warning(

View File

@@ -1,8 +1,10 @@
import * as z from 'zod'
export const FAIL_ON_SEVERITIES = ['critical', 'high', 'moderate', 'low', 'none'] as const
export const SEVERITIES = ['critical', 'high', 'moderate', 'low'] as const
export const SCOPES = ['unknown', 'runtime', 'development'] as const
export const FailOnSeveritySchema = z.enum(FAIL_ON_SEVERITIES).default('low')
export const SeveritySchema = z.enum(SEVERITIES).default('low')
export const ChangeSchema = z.object({
@@ -36,7 +38,7 @@ export const PullRequestSchema = z.object({
export const ConfigurationOptionsSchema = z
.object({
fail_on_severity: SeveritySchema,
fail_on_severity: FailOnSeveritySchema,
fail_on_scopes: z.array(z.enum(SCOPES)).default(['runtime']),
allow_licenses: z.array(z.string()).optional(),
deny_licenses: z.array(z.string()).optional(),
@@ -77,5 +79,6 @@ export const ChangesSchema = z.array(ChangeSchema)
export type Change = z.infer<typeof ChangeSchema>
export type Changes = z.infer<typeof ChangesSchema>
export type ConfigurationOptions = z.infer<typeof ConfigurationOptionsSchema>
export type FailOnSeverity = z.infer<typeof FailOnSeveritySchema>
export type Severity = z.infer<typeof SeveritySchema>
export type Scope = (typeof SCOPES)[number]