add groups
This commit is contained in:
@@ -0,0 +1,118 @@
|
|||||||
|
import {expect, jest, test} from '@jest/globals'
|
||||||
|
import {Change, Changes} from '../src/schemas'
|
||||||
|
|
||||||
|
let getDeniedChanges: Function
|
||||||
|
|
||||||
|
const npmChange: Change = {
|
||||||
|
manifest: 'package.json',
|
||||||
|
change_type: 'added',
|
||||||
|
ecosystem: 'npm',
|
||||||
|
name: 'Reeuhq',
|
||||||
|
version: '1.0.2',
|
||||||
|
package_url: 'pkg:npm/[email protected]',
|
||||||
|
license: 'MIT',
|
||||||
|
source_repository_url: 'github.com/some-repo',
|
||||||
|
scope: 'runtime',
|
||||||
|
vulnerabilities: [
|
||||||
|
{
|
||||||
|
severity: 'critical',
|
||||||
|
advisory_ghsa_id: 'first-random_string',
|
||||||
|
advisory_summary: 'very dangerous',
|
||||||
|
advisory_url: 'github.com/future-funk'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
const rubyChange: Change = {
|
||||||
|
change_type: 'added',
|
||||||
|
manifest: 'Gemfile.lock',
|
||||||
|
ecosystem: 'rubygems',
|
||||||
|
name: 'actionsomething',
|
||||||
|
version: '3.2.0',
|
||||||
|
package_url: 'pkg:gem/[email protected]',
|
||||||
|
license: 'BSD',
|
||||||
|
source_repository_url: 'github.com/some-repo',
|
||||||
|
scope: 'runtime',
|
||||||
|
vulnerabilities: [
|
||||||
|
{
|
||||||
|
severity: 'moderate',
|
||||||
|
advisory_ghsa_id: 'second-random_string',
|
||||||
|
advisory_summary: 'not so dangerous',
|
||||||
|
advisory_url: 'github.com/future-funk'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
severity: 'low',
|
||||||
|
advisory_ghsa_id: 'third-random_string',
|
||||||
|
advisory_summary: 'dont page me',
|
||||||
|
advisory_url: 'github.com/future-funk'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
const pipChange: Change = {
|
||||||
|
change_type: 'added',
|
||||||
|
manifest: 'requirements.txt',
|
||||||
|
ecosystem: 'pip',
|
||||||
|
name: 'package-1',
|
||||||
|
version: '1.1.1',
|
||||||
|
package_url: 'pkg:pip/[email protected]',
|
||||||
|
license: 'MIT',
|
||||||
|
source_repository_url: 'github.com/some-repo',
|
||||||
|
scope: 'runtime',
|
||||||
|
vulnerabilities: [
|
||||||
|
{
|
||||||
|
severity: 'moderate',
|
||||||
|
advisory_ghsa_id: 'second-random_string',
|
||||||
|
advisory_summary: 'not so dangerous',
|
||||||
|
advisory_url: 'github.com/future-funk'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
severity: 'low',
|
||||||
|
advisory_ghsa_id: 'third-random_string',
|
||||||
|
advisory_summary: 'dont page me',
|
||||||
|
advisory_url: 'github.com/future-funk'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
jest.mock('@actions/core')
|
||||||
|
|
||||||
|
const mockOctokit = {
|
||||||
|
rest: {
|
||||||
|
licenses: {
|
||||||
|
getForRepo: jest
|
||||||
|
.fn()
|
||||||
|
.mockReturnValue({data: {license: {spdx_id: 'AGPL'}}})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
jest.mock('octokit', () => {
|
||||||
|
return {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-extraneous-class
|
||||||
|
Octokit: class {
|
||||||
|
constructor() {
|
||||||
|
return mockOctokit
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
jest.resetModules()
|
||||||
|
jest.doMock('spdx-satisfies', () => {
|
||||||
|
// mock spdx-satisfies return value
|
||||||
|
// true for BSD, false for all others
|
||||||
|
return jest.fn((license: string, _: string): boolean => license === 'BSD')
|
||||||
|
})
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
||||||
|
;({getDeniedChanges} = require('../src/denylist'))
|
||||||
|
})
|
||||||
|
|
||||||
|
test('it adds license outside the allow list to forbidden changes', async () => {
|
||||||
|
const changes: Changes = [npmChange, rubyChange]
|
||||||
|
const deniedChanges = await getDeniedChanges(changes, ['actionsomething'])
|
||||||
|
|
||||||
|
expect(deniedChanges[0]).toBe(rubyChange)
|
||||||
|
expect(deniedChanges.length).toEqual(1)
|
||||||
|
})
|
||||||
@@ -24,6 +24,7 @@ const defaultConfig: ConfigurationOptions = {
|
|||||||
allow_ghsas: [],
|
allow_ghsas: [],
|
||||||
allow_licenses: [],
|
allow_licenses: [],
|
||||||
deny_licenses: [],
|
deny_licenses: [],
|
||||||
|
deny_list: [],
|
||||||
comment_summary_in_pr: true
|
comment_summary_in_pr: true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,6 +71,7 @@ test('prints headline as h1', () => {
|
|||||||
summary.addSummaryToSummary(
|
summary.addSummaryToSummary(
|
||||||
emptyChanges,
|
emptyChanges,
|
||||||
emptyInvalidLicenseChanges,
|
emptyInvalidLicenseChanges,
|
||||||
|
emptyChanges,
|
||||||
defaultConfig
|
defaultConfig
|
||||||
)
|
)
|
||||||
const text = core.summary.stringify()
|
const text = core.summary.stringify()
|
||||||
@@ -81,6 +83,7 @@ test('only includes "No vulnerabilities or license issues found"-message if both
|
|||||||
summary.addSummaryToSummary(
|
summary.addSummaryToSummary(
|
||||||
emptyChanges,
|
emptyChanges,
|
||||||
emptyInvalidLicenseChanges,
|
emptyInvalidLicenseChanges,
|
||||||
|
emptyChanges,
|
||||||
defaultConfig
|
defaultConfig
|
||||||
)
|
)
|
||||||
const text = core.summary.stringify()
|
const text = core.summary.stringify()
|
||||||
@@ -90,7 +93,12 @@ test('only includes "No vulnerabilities or license issues found"-message if both
|
|||||||
|
|
||||||
test('only includes "No vulnerabilities found"-message if "license_check" is set to false and nothing was found', () => {
|
test('only includes "No vulnerabilities found"-message if "license_check" is set to false and nothing was found', () => {
|
||||||
const config = {...defaultConfig, license_check: false}
|
const config = {...defaultConfig, license_check: false}
|
||||||
summary.addSummaryToSummary(emptyChanges, emptyInvalidLicenseChanges, config)
|
summary.addSummaryToSummary(
|
||||||
|
emptyChanges,
|
||||||
|
emptyInvalidLicenseChanges,
|
||||||
|
emptyChanges,
|
||||||
|
config
|
||||||
|
)
|
||||||
const text = core.summary.stringify()
|
const text = core.summary.stringify()
|
||||||
|
|
||||||
expect(text).toContain('✅ No vulnerabilities found.')
|
expect(text).toContain('✅ No vulnerabilities found.')
|
||||||
@@ -98,7 +106,12 @@ test('only includes "No vulnerabilities found"-message if "license_check" is set
|
|||||||
|
|
||||||
test('only includes "No license issues found"-message if "vulnerability_check" is set to false and nothing was found', () => {
|
test('only includes "No license issues found"-message if "vulnerability_check" is set to false and nothing was found', () => {
|
||||||
const config = {...defaultConfig, vulnerability_check: false}
|
const config = {...defaultConfig, vulnerability_check: false}
|
||||||
summary.addSummaryToSummary(emptyChanges, emptyInvalidLicenseChanges, config)
|
summary.addSummaryToSummary(
|
||||||
|
emptyChanges,
|
||||||
|
emptyInvalidLicenseChanges,
|
||||||
|
emptyChanges,
|
||||||
|
config
|
||||||
|
)
|
||||||
const text = core.summary.stringify()
|
const text = core.summary.stringify()
|
||||||
|
|
||||||
expect(text).toContain('✅ No license issues found.')
|
expect(text).toContain('✅ No license issues found.')
|
||||||
@@ -108,6 +121,7 @@ test('groups dependencies with empty manifest paths together', () => {
|
|||||||
summary.addSummaryToSummary(
|
summary.addSummaryToSummary(
|
||||||
changesWithEmptyManifests,
|
changesWithEmptyManifests,
|
||||||
emptyInvalidLicenseChanges,
|
emptyInvalidLicenseChanges,
|
||||||
|
emptyChanges,
|
||||||
defaultConfig
|
defaultConfig
|
||||||
)
|
)
|
||||||
summary.addScannedDependencies(changesWithEmptyManifests)
|
summary.addScannedDependencies(changesWithEmptyManifests)
|
||||||
@@ -124,6 +138,7 @@ test('does not include status section if nothing was found', () => {
|
|||||||
summary.addSummaryToSummary(
|
summary.addSummaryToSummary(
|
||||||
emptyChanges,
|
emptyChanges,
|
||||||
emptyInvalidLicenseChanges,
|
emptyInvalidLicenseChanges,
|
||||||
|
emptyChanges,
|
||||||
defaultConfig
|
defaultConfig
|
||||||
)
|
)
|
||||||
const text = core.summary.stringify()
|
const text = core.summary.stringify()
|
||||||
@@ -142,7 +157,12 @@ test('includes count and status icons for all findings', () => {
|
|||||||
unlicensed: [createTestChange(), createTestChange(), createTestChange()]
|
unlicensed: [createTestChange(), createTestChange(), createTestChange()]
|
||||||
}
|
}
|
||||||
|
|
||||||
summary.addSummaryToSummary(vulnerabilities, licenseIssues, defaultConfig)
|
summary.addSummaryToSummary(
|
||||||
|
vulnerabilities,
|
||||||
|
licenseIssues,
|
||||||
|
emptyChanges,
|
||||||
|
defaultConfig
|
||||||
|
)
|
||||||
|
|
||||||
const text = core.summary.stringify()
|
const text = core.summary.stringify()
|
||||||
expect(text).toContain('❌ 2 vulnerable package(s)')
|
expect(text).toContain('❌ 2 vulnerable package(s)')
|
||||||
@@ -159,6 +179,7 @@ test('uses checkmarks for license issues if only vulnerabilities were found', ()
|
|||||||
summary.addSummaryToSummary(
|
summary.addSummaryToSummary(
|
||||||
vulnerabilities,
|
vulnerabilities,
|
||||||
emptyInvalidLicenseChanges,
|
emptyInvalidLicenseChanges,
|
||||||
|
emptyChanges,
|
||||||
defaultConfig
|
defaultConfig
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -178,7 +199,12 @@ test('uses checkmarks for vulnerabilities if only license issues were found', ()
|
|||||||
unlicensed: []
|
unlicensed: []
|
||||||
}
|
}
|
||||||
|
|
||||||
summary.addSummaryToSummary(emptyChanges, licenseIssues, defaultConfig)
|
summary.addSummaryToSummary(
|
||||||
|
emptyChanges,
|
||||||
|
licenseIssues,
|
||||||
|
emptyChanges,
|
||||||
|
defaultConfig
|
||||||
|
)
|
||||||
|
|
||||||
const text = core.summary.stringify()
|
const text = core.summary.stringify()
|
||||||
expect(text).toContain('✅ 0 vulnerable package(s)')
|
expect(text).toContain('✅ 0 vulnerable package(s)')
|
||||||
|
|||||||
+1
-1
@@ -47,7 +47,7 @@ inputs:
|
|||||||
comment-summary-in-pr:
|
comment-summary-in-pr:
|
||||||
description: A boolean to determine if the report should be posted as a comment in the PR itself. Setting this to true requires you to give the workflow the write permissions for pull-requests
|
description: A boolean to determine if the report should be posted as a comment in the PR itself. Setting this to true requires you to give the workflow the write permissions for pull-requests
|
||||||
required: false
|
required: false
|
||||||
deny_list:
|
deny-list:
|
||||||
description: A comma-separated list of dependencies to deny (e.g. "pkg:npm/express, pkg:pip/pycrypto")
|
description: A comma-separated list of dependencies to deny (e.g. "pkg:npm/express, pkg:pip/pycrypto")
|
||||||
required: false
|
required: false
|
||||||
runs:
|
runs:
|
||||||
|
|||||||
+88
-4
@@ -135,6 +135,42 @@ function findCommentByMarker(commentBodyIncludes) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/***/ }),
|
||||||
|
|
||||||
|
/***/ 3491:
|
||||||
|
/***/ (function(__unused_webpack_module, exports) {
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||||
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||||
|
return new (P || (P = Promise))(function (resolve, reject) {
|
||||||
|
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||||
|
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||||
|
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
||||||
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||||
|
});
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||||
|
exports.getDeniedChanges = void 0;
|
||||||
|
function getDeniedChanges(changes, deniedList) {
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
const changesDenied = [];
|
||||||
|
for (const change of changes) {
|
||||||
|
change.name = change.name.toLowerCase();
|
||||||
|
change.package_url = change.package_url.toLowerCase();
|
||||||
|
for (const denied of deniedList) {
|
||||||
|
if (change.name.includes(denied)) {
|
||||||
|
changesDenied.push(change);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return changesDenied;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
exports.getDeniedChanges = getDeniedChanges;
|
||||||
|
|
||||||
|
|
||||||
/***/ }),
|
/***/ }),
|
||||||
|
|
||||||
/***/ 4966:
|
/***/ 4966:
|
||||||
@@ -485,6 +521,7 @@ const summary = __importStar(__nccwpck_require__(8608));
|
|||||||
const git_refs_1 = __nccwpck_require__(1086);
|
const git_refs_1 = __nccwpck_require__(1086);
|
||||||
const utils_1 = __nccwpck_require__(918);
|
const utils_1 = __nccwpck_require__(918);
|
||||||
const comment_pr_1 = __nccwpck_require__(5842);
|
const comment_pr_1 = __nccwpck_require__(5842);
|
||||||
|
const denylist_1 = __nccwpck_require__(3491);
|
||||||
function run() {
|
function run() {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
try {
|
try {
|
||||||
@@ -513,7 +550,11 @@ function run() {
|
|||||||
deny: config.deny_licenses,
|
deny: config.deny_licenses,
|
||||||
licenseExclusions: config.allow_dependencies_licenses
|
licenseExclusions: config.allow_dependencies_licenses
|
||||||
});
|
});
|
||||||
summary.addSummaryToSummary(vulnerableChanges, invalidLicenseChanges, config);
|
const deniedChanges = yield (0, denylist_1.getDeniedChanges)(filteredChanges, config.deny_list);
|
||||||
|
core.debug(`config: ${JSON.stringify(config)}`);
|
||||||
|
core.debug(`filteredChanges: ${JSON.stringify(filteredChanges)}`);
|
||||||
|
core.debug(`deniedChanges: ${JSON.stringify(deniedChanges)}`);
|
||||||
|
summary.addSummaryToSummary(vulnerableChanges, invalidLicenseChanges, deniedChanges, config);
|
||||||
if (snapshot_warnings) {
|
if (snapshot_warnings) {
|
||||||
summary.addSnapshotWarnings(snapshot_warnings);
|
summary.addSnapshotWarnings(snapshot_warnings);
|
||||||
}
|
}
|
||||||
@@ -525,6 +566,10 @@ function run() {
|
|||||||
summary.addLicensesToSummary(invalidLicenseChanges, config);
|
summary.addLicensesToSummary(invalidLicenseChanges, config);
|
||||||
printLicensesBlock(invalidLicenseChanges);
|
printLicensesBlock(invalidLicenseChanges);
|
||||||
}
|
}
|
||||||
|
if (config.deny_list) {
|
||||||
|
summary.addDeniedToSummary(deniedChanges);
|
||||||
|
printDeniedDependencies(deniedChanges, config);
|
||||||
|
}
|
||||||
summary.addScannedDependencies(changes);
|
summary.addScannedDependencies(changes);
|
||||||
printScannedDependencies(changes);
|
printScannedDependencies(changes);
|
||||||
if (config.comment_summary_in_pr) {
|
if (config.comment_summary_in_pr) {
|
||||||
@@ -640,6 +685,17 @@ function printScannedDependencies(changes) {
|
|||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
function printDeniedDependencies(changes, config) {
|
||||||
|
core.group('Denied', () => __awaiter(this, void 0, void 0, function* () {
|
||||||
|
for (const denied of config.deny_list) {
|
||||||
|
core.info(`Config: ${denied}`);
|
||||||
|
}
|
||||||
|
for (const change of changes) {
|
||||||
|
core.info(`Change: ${change.name}@${change.version} is denied`);
|
||||||
|
core.info(`Change: ${change.package_url} is denied`);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
run();
|
run();
|
||||||
|
|
||||||
|
|
||||||
@@ -712,6 +768,7 @@ exports.ConfigurationOptionsSchema = z
|
|||||||
deny_licenses: z.array(z.string()).optional(),
|
deny_licenses: z.array(z.string()).optional(),
|
||||||
allow_dependencies_licenses: z.array(z.string()).optional(),
|
allow_dependencies_licenses: z.array(z.string()).optional(),
|
||||||
allow_ghsas: z.array(z.string()).default([]),
|
allow_ghsas: z.array(z.string()).default([]),
|
||||||
|
deny_list: z.array(z.string()).default([]),
|
||||||
license_check: z.boolean().default(true),
|
license_check: z.boolean().default(true),
|
||||||
vulnerability_check: z.boolean().default(true),
|
vulnerability_check: z.boolean().default(true),
|
||||||
config_file: z.string().optional(),
|
config_file: z.string().optional(),
|
||||||
@@ -778,7 +835,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||||
exports.addSnapshotWarnings = exports.addScannedDependencies = exports.addLicensesToSummary = exports.addChangeVulnerabilitiesToSummary = exports.addSummaryToSummary = void 0;
|
exports.addDeniedToSummary = exports.addSnapshotWarnings = exports.addScannedDependencies = exports.addLicensesToSummary = exports.addChangeVulnerabilitiesToSummary = exports.addSummaryToSummary = void 0;
|
||||||
const core = __importStar(__nccwpck_require__(2186));
|
const core = __importStar(__nccwpck_require__(2186));
|
||||||
const utils_1 = __nccwpck_require__(918);
|
const utils_1 = __nccwpck_require__(918);
|
||||||
const icons = {
|
const icons = {
|
||||||
@@ -786,10 +843,11 @@ const icons = {
|
|||||||
cross: '❌',
|
cross: '❌',
|
||||||
warning: '⚠️'
|
warning: '⚠️'
|
||||||
};
|
};
|
||||||
function addSummaryToSummary(vulnerableChanges, invalidLicenseChanges, config) {
|
function addSummaryToSummary(vulnerableChanges, invalidLicenseChanges, deniedChanges, config) {
|
||||||
core.summary.addHeading('Dependency Review', 1);
|
core.summary.addHeading('Dependency Review', 1);
|
||||||
if (vulnerableChanges.length === 0 &&
|
if (vulnerableChanges.length === 0 &&
|
||||||
countLicenseIssues(invalidLicenseChanges) === 0) {
|
countLicenseIssues(invalidLicenseChanges) === 0 &&
|
||||||
|
deniedChanges.length === 0) {
|
||||||
if (!config.license_check) {
|
if (!config.license_check) {
|
||||||
core.summary.addRaw(`${icons.check} No vulnerabilities found.`);
|
core.summary.addRaw(`${icons.check} No vulnerabilities found.`);
|
||||||
}
|
}
|
||||||
@@ -815,6 +873,11 @@ function addSummaryToSummary(vulnerableChanges, invalidLicenseChanges, config) {
|
|||||||
`${checkOrFailIcon(invalidLicenseChanges.unresolved.length)} ${invalidLicenseChanges.unresolved.length} package(s) with invalid SPDX license definitions`,
|
`${checkOrFailIcon(invalidLicenseChanges.unresolved.length)} ${invalidLicenseChanges.unresolved.length} package(s) with invalid SPDX license definitions`,
|
||||||
`${checkOrWarnIcon(invalidLicenseChanges.unlicensed.length)} ${invalidLicenseChanges.unlicensed.length} package(s) with unknown licenses.`
|
`${checkOrWarnIcon(invalidLicenseChanges.unlicensed.length)} ${invalidLicenseChanges.unlicensed.length} package(s) with unknown licenses.`
|
||||||
]
|
]
|
||||||
|
: []),
|
||||||
|
...(deniedChanges.length > 0
|
||||||
|
? [
|
||||||
|
`${checkOrWarnIcon(deniedChanges.length)} ${deniedChanges.length} package(s) denied.`
|
||||||
|
]
|
||||||
: [])
|
: [])
|
||||||
])
|
])
|
||||||
.addRaw('See the Details below.');
|
.addRaw('See the Details below.');
|
||||||
@@ -956,6 +1019,24 @@ exports.addSnapshotWarnings = addSnapshotWarnings;
|
|||||||
function countLicenseIssues(invalidLicenseChanges) {
|
function countLicenseIssues(invalidLicenseChanges) {
|
||||||
return Object.values(invalidLicenseChanges).reduce((acc, val) => acc + val.length, 0);
|
return Object.values(invalidLicenseChanges).reduce((acc, val) => acc + val.length, 0);
|
||||||
}
|
}
|
||||||
|
function addDeniedToSummary(deniedChanges) {
|
||||||
|
if (deniedChanges.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
core.summary.addHeading('Denied dependencies', 2);
|
||||||
|
for (const change of deniedChanges) {
|
||||||
|
core.summary.addHeading(`<em>Denied dependencies</em>`, 4);
|
||||||
|
core.summary.addTable([
|
||||||
|
['Package', 'Version', 'License'],
|
||||||
|
[
|
||||||
|
(0, utils_1.renderUrl)(change.source_repository_url, change.name),
|
||||||
|
change.version,
|
||||||
|
change.license || ''
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exports.addDeniedToSummary = addDeniedToSummary;
|
||||||
function checkOrFailIcon(count) {
|
function checkOrFailIcon(count) {
|
||||||
return count === 0 ? icons.check : icons.cross;
|
return count === 0 ? icons.check : icons.cross;
|
||||||
}
|
}
|
||||||
@@ -47821,6 +47902,7 @@ function readInlineConfig() {
|
|||||||
const allow_licenses = parseList(getOptionalInput('allow-licenses'));
|
const allow_licenses = parseList(getOptionalInput('allow-licenses'));
|
||||||
const deny_licenses = parseList(getOptionalInput('deny-licenses'));
|
const deny_licenses = parseList(getOptionalInput('deny-licenses'));
|
||||||
const allow_dependencies_licenses = parseList(getOptionalInput('allow-dependencies-licenses'));
|
const allow_dependencies_licenses = parseList(getOptionalInput('allow-dependencies-licenses'));
|
||||||
|
const deny_list = parseList(getOptionalInput('deny-list'));
|
||||||
const allow_ghsas = parseList(getOptionalInput('allow-ghsas'));
|
const allow_ghsas = parseList(getOptionalInput('allow-ghsas'));
|
||||||
const license_check = getOptionalBoolean('license-check');
|
const license_check = getOptionalBoolean('license-check');
|
||||||
const vulnerability_check = getOptionalBoolean('vulnerability-check');
|
const vulnerability_check = getOptionalBoolean('vulnerability-check');
|
||||||
@@ -47835,6 +47917,7 @@ function readInlineConfig() {
|
|||||||
fail_on_scopes,
|
fail_on_scopes,
|
||||||
allow_licenses,
|
allow_licenses,
|
||||||
deny_licenses,
|
deny_licenses,
|
||||||
|
deny_list,
|
||||||
allow_dependencies_licenses,
|
allow_dependencies_licenses,
|
||||||
allow_ghsas,
|
allow_ghsas,
|
||||||
license_check,
|
license_check,
|
||||||
@@ -48119,6 +48202,7 @@ exports.ConfigurationOptionsSchema = z
|
|||||||
deny_licenses: z.array(z.string()).optional(),
|
deny_licenses: z.array(z.string()).optional(),
|
||||||
allow_dependencies_licenses: z.array(z.string()).optional(),
|
allow_dependencies_licenses: z.array(z.string()).optional(),
|
||||||
allow_ghsas: z.array(z.string()).default([]),
|
allow_ghsas: z.array(z.string()).default([]),
|
||||||
|
deny_list: z.array(z.string()).default([]),
|
||||||
license_check: z.boolean().default(true),
|
license_check: z.boolean().default(true),
|
||||||
vulnerability_check: z.boolean().default(true),
|
vulnerability_check: z.boolean().default(true),
|
||||||
config_file: z.string().optional(),
|
config_file: z.string().optional(),
|
||||||
|
|||||||
+1
-1
File diff suppressed because one or more lines are too long
@@ -6,7 +6,7 @@
|
|||||||
* npx ts-node scripts/create_summary.ts
|
* npx ts-node scripts/create_summary.ts
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {Changes, ConfigurationOptions} from '../src/schemas'
|
import {Change, Changes, ConfigurationOptions} from '../src/schemas'
|
||||||
import {createTestChange} from '../__tests__/fixtures/create-test-change'
|
import {createTestChange} from '../__tests__/fixtures/create-test-change'
|
||||||
import {InvalidLicenseChanges} from '../src/licenses'
|
import {InvalidLicenseChanges} from '../src/licenses'
|
||||||
import * as fs from 'fs'
|
import * as fs from 'fs'
|
||||||
@@ -22,6 +22,7 @@ const defaultConfig: ConfigurationOptions = {
|
|||||||
allow_ghsas: [],
|
allow_ghsas: [],
|
||||||
allow_licenses: ['MIT'],
|
allow_licenses: ['MIT'],
|
||||||
deny_licenses: [],
|
deny_licenses: [],
|
||||||
|
deny_list: [],
|
||||||
allow_dependencies_licenses: [
|
allow_dependencies_licenses: [
|
||||||
'pkg:npm/[email protected]',
|
'pkg:npm/[email protected]',
|
||||||
'pkg:pip/requests',
|
'pkg:pip/requests',
|
||||||
@@ -44,6 +45,7 @@ const createNonIssueSummary = async (): Promise<void> => {
|
|||||||
await createSummary(
|
await createSummary(
|
||||||
[],
|
[],
|
||||||
{forbidden: [], unresolved: [], unlicensed: []},
|
{forbidden: [], unresolved: [], unlicensed: []},
|
||||||
|
[],
|
||||||
defaultConfig,
|
defaultConfig,
|
||||||
'non-issue-summary.md'
|
'non-issue-summary.md'
|
||||||
)
|
)
|
||||||
@@ -85,16 +87,17 @@ const createFullSummary = async (): Promise<void> => {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
await createSummary(changes, licenses, defaultConfig, 'full-summary.md')
|
await createSummary(changes, licenses, [], defaultConfig, 'full-summary.md')
|
||||||
}
|
}
|
||||||
|
|
||||||
async function createSummary(
|
async function createSummary(
|
||||||
vulnerabilities: Changes,
|
vulnerabilities: Changes,
|
||||||
licenseIssues: InvalidLicenseChanges,
|
licenseIssues: InvalidLicenseChanges,
|
||||||
|
denied: Change[],
|
||||||
config: ConfigurationOptions,
|
config: ConfigurationOptions,
|
||||||
fileName: string
|
fileName: string
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
summary.addSummaryToSummary(vulnerabilities, licenseIssues, config)
|
summary.addSummaryToSummary(vulnerabilities, licenseIssues, denied, config)
|
||||||
summary.addChangeVulnerabilitiesToSummary(
|
summary.addChangeVulnerabilitiesToSummary(
|
||||||
vulnerabilities,
|
vulnerabilities,
|
||||||
config.fail_on_severity
|
config.fail_on_severity
|
||||||
|
|||||||
+1
-1
@@ -33,7 +33,7 @@ function readInlineConfig(): ConfigurationOptionsPartial {
|
|||||||
const allow_dependencies_licenses = parseList(
|
const allow_dependencies_licenses = parseList(
|
||||||
getOptionalInput('allow-dependencies-licenses')
|
getOptionalInput('allow-dependencies-licenses')
|
||||||
)
|
)
|
||||||
const deny_list = parseList(getOptionalInput('deny-dependencies'))
|
const deny_list = parseList(getOptionalInput('deny-list'))
|
||||||
const allow_ghsas = parseList(getOptionalInput('allow-ghsas'))
|
const allow_ghsas = parseList(getOptionalInput('allow-ghsas'))
|
||||||
const license_check = getOptionalBoolean('license-check')
|
const license_check = getOptionalBoolean('license-check')
|
||||||
const vulnerability_check = getOptionalBoolean('vulnerability-check')
|
const vulnerability_check = getOptionalBoolean('vulnerability-check')
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
import {Change} from './schemas'
|
||||||
|
import * as core from '@actions/core'
|
||||||
|
|
||||||
|
export async function getDeniedChanges(
|
||||||
|
changes: Change[],
|
||||||
|
deniedList: string[]
|
||||||
|
): Promise<Change[]> {
|
||||||
|
const changesDenied: Change[] = []
|
||||||
|
|
||||||
|
let failed = false
|
||||||
|
for (const change of changes) {
|
||||||
|
change.name = change.name.toLowerCase()
|
||||||
|
change.package_url = change.package_url.toLowerCase()
|
||||||
|
|
||||||
|
for (const denied of deniedList) {
|
||||||
|
if (change.name.includes(denied)) {
|
||||||
|
changesDenied.push(change)
|
||||||
|
failed = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (failed) {
|
||||||
|
core.setFailed('Dependency review detected denied packages.')
|
||||||
|
} else {
|
||||||
|
core.info('Dependency review did not detect any denied packages')
|
||||||
|
}
|
||||||
|
|
||||||
|
return changesDenied
|
||||||
|
}
|
||||||
+25
-1
@@ -3,7 +3,7 @@ import * as dependencyGraph from './dependency-graph'
|
|||||||
import * as github from '@actions/github'
|
import * as github from '@actions/github'
|
||||||
import styles from 'ansi-styles'
|
import styles from 'ansi-styles'
|
||||||
import {RequestError} from '@octokit/request-error'
|
import {RequestError} from '@octokit/request-error'
|
||||||
import {Change, Severity, Changes} from './schemas'
|
import {Change, Severity, Changes, ConfigurationOptions} from './schemas'
|
||||||
import {readConfig} from '../src/config'
|
import {readConfig} from '../src/config'
|
||||||
import {
|
import {
|
||||||
filterChangesBySeverity,
|
filterChangesBySeverity,
|
||||||
@@ -69,6 +69,10 @@ async function run(): Promise<void> {
|
|||||||
config.deny_list
|
config.deny_list
|
||||||
)
|
)
|
||||||
|
|
||||||
|
core.debug(`config: ${JSON.stringify(config)}`)
|
||||||
|
core.debug(`filteredChanges: ${JSON.stringify(filteredChanges)}`)
|
||||||
|
core.debug(`deniedChanges: ${JSON.stringify(deniedChanges)}`)
|
||||||
|
|
||||||
summary.addSummaryToSummary(
|
summary.addSummaryToSummary(
|
||||||
vulnerableChanges,
|
vulnerableChanges,
|
||||||
invalidLicenseChanges,
|
invalidLicenseChanges,
|
||||||
@@ -88,6 +92,10 @@ async function run(): Promise<void> {
|
|||||||
summary.addLicensesToSummary(invalidLicenseChanges, config)
|
summary.addLicensesToSummary(invalidLicenseChanges, config)
|
||||||
printLicensesBlock(invalidLicenseChanges)
|
printLicensesBlock(invalidLicenseChanges)
|
||||||
}
|
}
|
||||||
|
if (config.deny_list) {
|
||||||
|
summary.addDeniedToSummary(deniedChanges)
|
||||||
|
printDeniedDependencies(deniedChanges, config)
|
||||||
|
}
|
||||||
|
|
||||||
summary.addScannedDependencies(changes)
|
summary.addScannedDependencies(changes)
|
||||||
printScannedDependencies(changes)
|
printScannedDependencies(changes)
|
||||||
@@ -246,4 +254,20 @@ function printScannedDependencies(changes: Changes): void {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function printDeniedDependencies(
|
||||||
|
changes: Change[],
|
||||||
|
config: ConfigurationOptions
|
||||||
|
): void {
|
||||||
|
core.group('Denied', async () => {
|
||||||
|
for (const denied of config.deny_list) {
|
||||||
|
core.info(`Config: ${denied}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const change of changes) {
|
||||||
|
core.info(`Change: ${change.name}@${change.version} is denied`)
|
||||||
|
core.info(`Change: ${change.package_url} is denied`)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
run()
|
run()
|
||||||
|
|||||||
+29
-4
@@ -1,5 +1,5 @@
|
|||||||
import * as core from '@actions/core'
|
import * as core from '@actions/core'
|
||||||
import {ConfigurationOptions, Changes} from './schemas'
|
import {ConfigurationOptions, Changes, Change} from './schemas'
|
||||||
import {SummaryTableRow} from '@actions/core/lib/summary'
|
import {SummaryTableRow} from '@actions/core/lib/summary'
|
||||||
import {InvalidLicenseChanges, InvalidLicenseChangeTypes} from './licenses'
|
import {InvalidLicenseChanges, InvalidLicenseChangeTypes} from './licenses'
|
||||||
import {groupDependenciesByManifest, getManifestsSet, renderUrl} from './utils'
|
import {groupDependenciesByManifest, getManifestsSet, renderUrl} from './utils'
|
||||||
@@ -20,7 +20,8 @@ export function addSummaryToSummary(
|
|||||||
|
|
||||||
if (
|
if (
|
||||||
vulnerableChanges.length === 0 &&
|
vulnerableChanges.length === 0 &&
|
||||||
countLicenseIssues(invalidLicenseChanges) === 0
|
countLicenseIssues(invalidLicenseChanges) === 0 &&
|
||||||
|
deniedChanges.length === 0
|
||||||
) {
|
) {
|
||||||
if (!config.license_check) {
|
if (!config.license_check) {
|
||||||
core.summary.addRaw(`${icons.check} No vulnerabilities found.`)
|
core.summary.addRaw(`${icons.check} No vulnerabilities found.`)
|
||||||
@@ -35,8 +36,6 @@ export function addSummaryToSummary(
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
core.summary.addList(deniedChanges.map(change => `${change.name} is denied`))
|
|
||||||
|
|
||||||
core.summary
|
core.summary
|
||||||
.addRaw('The following issues were found:')
|
.addRaw('The following issues were found:')
|
||||||
.addList([
|
.addList([
|
||||||
@@ -59,6 +58,13 @@ export function addSummaryToSummary(
|
|||||||
invalidLicenseChanges.unlicensed.length
|
invalidLicenseChanges.unlicensed.length
|
||||||
} package(s) with unknown licenses.`
|
} package(s) with unknown licenses.`
|
||||||
]
|
]
|
||||||
|
: []),
|
||||||
|
...(deniedChanges.length > 0
|
||||||
|
? [
|
||||||
|
`${checkOrWarnIcon(deniedChanges.length)} ${
|
||||||
|
deniedChanges.length
|
||||||
|
} package(s) denied.`
|
||||||
|
]
|
||||||
: [])
|
: [])
|
||||||
])
|
])
|
||||||
.addRaw('See the Details below.')
|
.addRaw('See the Details below.')
|
||||||
@@ -251,6 +257,25 @@ function countLicenseIssues(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function addDeniedToSummary(deniedChanges: Change[]): void {
|
||||||
|
if (deniedChanges.length === 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
core.summary.addHeading('Denied dependencies', 2)
|
||||||
|
for (const change of deniedChanges) {
|
||||||
|
core.summary.addHeading(`<em>Denied dependencies</em>`, 4)
|
||||||
|
core.summary.addTable([
|
||||||
|
['Package', 'Version', 'License'],
|
||||||
|
[
|
||||||
|
renderUrl(change.source_repository_url, change.name),
|
||||||
|
change.version,
|
||||||
|
change.license || ''
|
||||||
|
]
|
||||||
|
])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function checkOrFailIcon(count: number): string {
|
function checkOrFailIcon(count: number): string {
|
||||||
return count === 0 ? icons.check : icons.cross
|
return count === 0 ? icons.check : icons.cross
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user