Compare commits
65 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b83777ffd0 | |||
| 1dc503a722 | |||
| 8975a27eeb | |||
| c003e7f8fc | |||
| ae4118f8fa | |||
| c5d7bdcf7f | |||
| bced8aa1b2 | |||
| ba8e0b013b | |||
| cfcdef93a4 | |||
| 43b6f9fe4a | |||
| 467931ed7e | |||
| 29c7e47bc6 | |||
| aa4260f0b0 | |||
| f187f64fc9 | |||
| f3bcf122c7 | |||
| c43f51429e | |||
| c9027d07d6 | |||
| c316251843 | |||
| d8e436b2d5 | |||
| 82d4814150 | |||
| 89de8ab245 | |||
| 3e74bf2266 | |||
| 1ea517b3fa | |||
| 2aef88c152 | |||
| 51d1824002 | |||
| 94edc9c394 | |||
| 7219e93649 | |||
| 08074685be | |||
| 3efca1e3dd | |||
| 9fdc2574b8 | |||
| 6e9189a5c1 | |||
| c6f347d470 | |||
| 40346e9340 | |||
| 7f576504ed | |||
| 09100640b0 | |||
| 26b7908701 | |||
| b564b42423 | |||
| 2ceda66c21 | |||
| 49a36aa04e | |||
| 17b8abf3bb | |||
| c699fc9e3e | |||
| 24ab96e8b8 | |||
| 04f86c1583 | |||
| 81b5cbd111 | |||
| 4b88091897 | |||
| febb822f26 | |||
| ea91d29cdf | |||
| a9539be12a | |||
| 9c688a568f | |||
| ff449a1296 | |||
| 2a961b0169 | |||
| 879687b22c | |||
| cb52804670 | |||
| 17187536c0 | |||
| c0faf55fe4 | |||
| b6f6142660 | |||
| 333e7ce17e | |||
| 4e9a45ca5b | |||
| 32a1ef9487 | |||
| 83be5f6c90 | |||
| 70f41926ca | |||
| 1c59cdf2a9 | |||
| ba0681f88b | |||
| 29fc7a23bd | |||
| 903977c63a |
@@ -9,3 +9,6 @@ updates:
|
||||
directory: /
|
||||
schedule:
|
||||
interval: daily
|
||||
ignore:
|
||||
- dependency-name: '@types/node'
|
||||
update-types: ['version-update:semver-major']
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
paths-ignore:
|
||||
- '**.md'
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- '**.md'
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
cache: npm
|
||||
- name: Install dependencies
|
||||
run: npm ci --ignore-scripts
|
||||
- name: Test
|
||||
run: |
|
||||
npm test
|
||||
lint:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
cache: npm
|
||||
- name: Install dependencies
|
||||
run: npm ci --ignore-scripts
|
||||
- name: Check format
|
||||
run: |
|
||||
npm run format-check
|
||||
- name: Lint
|
||||
run: |
|
||||
npm run lint
|
||||
Vendored
+3
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"recommendations": ["dbaeumer.vscode-eslint", "esbenp.prettier-vscode"]
|
||||
}
|
||||
Vendored
+4
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"editor.formatOnSave": true,
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
This action scans your pull requests for dependency changes and will raise an error if any new dependencies have existing vulnerabilities. The action is supported by an [API endpoint](https://docs.github.com/en/rest/reference/dependency-graph#dependency-review) that diffs the dependencies between any two revisions.
|
||||
|
||||
The action is available for all public repositories, as well as private repositories that have Github Advanced Security licensed.
|
||||
The action is available for all public repositories, as well as private repositories that have GitHub Advanced Security licensed.
|
||||
|
||||
<img width="854" alt="Screen Shot 2022-03-31 at 1 10 51 PM" src="https://user-images.githubusercontent.com/2161/161042286-b22d7dd3-13cb-458d-8744-ce70ed9bf562.png">
|
||||
|
||||
@@ -52,7 +52,7 @@ jobs:
|
||||
# Possible values: "critical", "high", "moderate", "low"
|
||||
# fail-on-severity: critical
|
||||
#
|
||||
# You can only can only include one of these two options: `allow-licenses` and `deny-licences`
|
||||
# You can only include one of these two options: `allow-licenses` and `deny-licenses`
|
||||
#
|
||||
# Possible values: Any `spdx_id` value(s) from https://docs.github.com/en/rest/licenses
|
||||
# allow-licenses: GPL-3.0, BSD-3-Clause, MIT
|
||||
|
||||
@@ -15,7 +15,7 @@ let npmChange: Change = {
|
||||
{
|
||||
severity: 'critical',
|
||||
advisory_ghsa_id: 'first-random_string',
|
||||
advisory_summary: 'very dangerouns',
|
||||
advisory_summary: 'very dangerous',
|
||||
advisory_url: 'github.com/future-funk'
|
||||
}
|
||||
]
|
||||
@@ -34,7 +34,7 @@ let rubyChange: Change = {
|
||||
{
|
||||
severity: 'moderate',
|
||||
advisory_ghsa_id: 'second-random_string',
|
||||
advisory_summary: 'not so dangerouns',
|
||||
advisory_summary: 'not so dangerous',
|
||||
advisory_url: 'github.com/future-funk'
|
||||
},
|
||||
{
|
||||
|
||||
@@ -15,7 +15,7 @@ let npmChange: Change = {
|
||||
{
|
||||
severity: 'critical',
|
||||
advisory_ghsa_id: 'first-random_string',
|
||||
advisory_summary: 'very dangerouns',
|
||||
advisory_summary: 'very dangerous',
|
||||
advisory_url: 'github.com/future-funk'
|
||||
}
|
||||
]
|
||||
@@ -34,7 +34,7 @@ let rubyChange: Change = {
|
||||
{
|
||||
severity: 'moderate',
|
||||
advisory_ghsa_id: 'second-random_string',
|
||||
advisory_summary: 'not so dangerouns',
|
||||
advisory_summary: 'not so dangerous',
|
||||
advisory_url: 'github.com/future-funk'
|
||||
},
|
||||
{
|
||||
@@ -68,3 +68,31 @@ test('it fails all license checks when allow is provided an empty array', async
|
||||
})
|
||||
expect(invalidChanges.length).toBe(2)
|
||||
})
|
||||
|
||||
test('it does not fail if a license outside the allow list is found in removed changes', async () => {
|
||||
const changes: Changes = [
|
||||
{...npmChange, change_type: 'removed'},
|
||||
{...rubyChange, change_type: 'removed'}
|
||||
]
|
||||
const [invalidChanges, _] = getDeniedLicenseChanges(changes, {allow: ['BSD']})
|
||||
expect(invalidChanges).toStrictEqual([])
|
||||
})
|
||||
|
||||
test('it does not fail if a license inside the deny list is found in removed changes', async () => {
|
||||
const changes: Changes = [
|
||||
{...npmChange, change_type: 'removed'},
|
||||
{...rubyChange, change_type: 'removed'}
|
||||
]
|
||||
const [invalidChanges, _] = getDeniedLicenseChanges(changes, {deny: ['BSD']})
|
||||
expect(invalidChanges).toStrictEqual([])
|
||||
})
|
||||
|
||||
test('it fails if a license outside the allow list is found in both of added and removed changes', async () => {
|
||||
const changes: Changes = [
|
||||
{...npmChange, change_type: 'removed'},
|
||||
npmChange,
|
||||
{...rubyChange, change_type: 'removed'}
|
||||
]
|
||||
const [invalidChanges, _] = getDeniedLicenseChanges(changes, {allow: ['BSD']})
|
||||
expect(invalidChanges).toStrictEqual([npmChange])
|
||||
})
|
||||
|
||||
+177
-18
@@ -81,11 +81,14 @@ exports.getDeniedLicenseChanges = void 0;
|
||||
* @returns {[Array<Change>, Array<Change]} A tuple where the first element is the list of denied changes and the second one is the list of changes with unknown licenses
|
||||
*/
|
||||
function getDeniedLicenseChanges(changes, licenses) {
|
||||
let { allow, deny } = licenses;
|
||||
let disallowed = [];
|
||||
let unknown = [];
|
||||
const { allow, deny } = licenses;
|
||||
const disallowed = [];
|
||||
const unknown = [];
|
||||
for (const change of changes) {
|
||||
let license = change.license;
|
||||
if (change.change_type === 'removed') {
|
||||
continue;
|
||||
}
|
||||
const license = change.license;
|
||||
if (license === null) {
|
||||
unknown.push(change);
|
||||
continue;
|
||||
@@ -171,14 +174,14 @@ function run() {
|
||||
baseRef: pull_request.base.sha,
|
||||
headRef: pull_request.head.sha
|
||||
});
|
||||
let config = (0, config_1.readConfig)();
|
||||
let minSeverity = config.fail_on_severity;
|
||||
const config = (0, config_1.readConfig)();
|
||||
const minSeverity = config.fail_on_severity;
|
||||
let failed = false;
|
||||
let licenses = {
|
||||
const licenses = {
|
||||
allow: config.allow_licenses,
|
||||
deny: config.deny_licenses
|
||||
};
|
||||
let filteredChanges = (0, filter_1.filterChangesBySeverity)(minSeverity, changes);
|
||||
const filteredChanges = (0, filter_1.filterChangesBySeverity)(minSeverity, changes);
|
||||
for (const change of filteredChanges) {
|
||||
if (change.change_type === 'added' &&
|
||||
change.vulnerabilities !== undefined &&
|
||||
@@ -187,9 +190,9 @@ function run() {
|
||||
failed = true;
|
||||
}
|
||||
}
|
||||
let [licenseErrors, unknownLicenses] = (0, licenses_1.getDeniedLicenseChanges)(changes, licenses);
|
||||
const [licenseErrors, unknownLicenses] = (0, licenses_1.getDeniedLicenseChanges)(changes, licenses);
|
||||
if (licenseErrors.length > 0) {
|
||||
printLicensesError(licenseErrors, licenses);
|
||||
printLicensesError(licenseErrors);
|
||||
core.setFailed('Dependency review detected incompatible licenses.');
|
||||
}
|
||||
printNullLicenses(unknownLicenses);
|
||||
@@ -233,17 +236,19 @@ function renderSeverity(severity) {
|
||||
}[severity];
|
||||
return `${ansi_styles_1.default.color[color].open}(${severity} severity)${ansi_styles_1.default.color[color].close}`;
|
||||
}
|
||||
function printLicensesError(changes, licenses) {
|
||||
if (changes.length == 0) {
|
||||
function printLicensesError(changes) {
|
||||
if (changes.length === 0) {
|
||||
return;
|
||||
}
|
||||
let { allow = [], deny = [] } = licenses;
|
||||
core.info('\nThe following dependencies have incompatible licenses:\n');
|
||||
for (const change of changes) {
|
||||
core.info(`${ansi_styles_1.default.bold.open}${change.manifest} » ${change.name}@${change.version}${ansi_styles_1.default.bold.close} – License: ${ansi_styles_1.default.color.red.open}${change.license}${ansi_styles_1.default.color.red.close}`);
|
||||
}
|
||||
}
|
||||
function printNullLicenses(changes) {
|
||||
if (changes.length === 0) {
|
||||
return;
|
||||
}
|
||||
core.info('\nWe could not detect a license for the following dependencies:\n');
|
||||
for (const change of changes) {
|
||||
core.info(`${ansi_styles_1.default.bold.open}${change.manifest} » ${change.name}@${change.version}${ansi_styles_1.default.bold.close}`);
|
||||
@@ -317,7 +322,7 @@ exports.ConfigurationOptionsSchema = z
|
||||
deny_licenses: z.array(z.string()).default([])
|
||||
})
|
||||
.partial()
|
||||
.refine(obj => !(obj.allow_licenses && obj.deny_licenses), "Your workflow file has both an allow_licenses list and deny_licenses list, but you can only set one or the other.");
|
||||
.refine(obj => !(obj.allow_licenses && obj.deny_licenses), 'Your workflow file has both an allow_licenses list and deny_licenses list, but you can only set one or the other.');
|
||||
exports.ChangesSchema = z.array(exports.ChangeSchema);
|
||||
|
||||
|
||||
@@ -747,6 +752,13 @@ Object.defineProperty(exports, "summary", ({ enumerable: true, get: function ()
|
||||
*/
|
||||
var summary_2 = __nccwpck_require__(1327);
|
||||
Object.defineProperty(exports, "markdownSummary", ({ enumerable: true, get: function () { return summary_2.markdownSummary; } }));
|
||||
/**
|
||||
* Path exports
|
||||
*/
|
||||
var path_utils_1 = __nccwpck_require__(2981);
|
||||
Object.defineProperty(exports, "toPosixPath", ({ enumerable: true, get: function () { return path_utils_1.toPosixPath; } }));
|
||||
Object.defineProperty(exports, "toWin32Path", ({ enumerable: true, get: function () { return path_utils_1.toWin32Path; } }));
|
||||
Object.defineProperty(exports, "toPlatformPath", ({ enumerable: true, get: function () { return path_utils_1.toPlatformPath; } }));
|
||||
//# sourceMappingURL=core.js.map
|
||||
|
||||
/***/ }),
|
||||
@@ -884,6 +896,71 @@ exports.OidcClient = OidcClient;
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 2981:
|
||||
/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
|
||||
|
||||
"use strict";
|
||||
|
||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
||||
}) : (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
o[k2] = m[k];
|
||||
}));
|
||||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
||||
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
||||
}) : function(o, v) {
|
||||
o["default"] = v;
|
||||
});
|
||||
var __importStar = (this && this.__importStar) || function (mod) {
|
||||
if (mod && mod.__esModule) return mod;
|
||||
var result = {};
|
||||
if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
||||
__setModuleDefault(result, mod);
|
||||
return result;
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||
exports.toPlatformPath = exports.toWin32Path = exports.toPosixPath = void 0;
|
||||
const path = __importStar(__nccwpck_require__(1017));
|
||||
/**
|
||||
* toPosixPath converts the given path to the posix form. On Windows, \\ will be
|
||||
* replaced with /.
|
||||
*
|
||||
* @param pth. Path to transform.
|
||||
* @return string Posix path.
|
||||
*/
|
||||
function toPosixPath(pth) {
|
||||
return pth.replace(/[\\]/g, '/');
|
||||
}
|
||||
exports.toPosixPath = toPosixPath;
|
||||
/**
|
||||
* toWin32Path converts the given path to the win32 form. On Linux, / will be
|
||||
* replaced with \\.
|
||||
*
|
||||
* @param pth. Path to transform.
|
||||
* @return string Win32 path.
|
||||
*/
|
||||
function toWin32Path(pth) {
|
||||
return pth.replace(/[/]/g, '\\');
|
||||
}
|
||||
exports.toWin32Path = toWin32Path;
|
||||
/**
|
||||
* toPlatformPath converts the given path to a platform-specific path. It does
|
||||
* this by replacing instances of / and \ with the platform-specific path
|
||||
* separator.
|
||||
*
|
||||
* @param pth The path to platformize.
|
||||
* @return string The platform-specific path.
|
||||
*/
|
||||
function toPlatformPath(pth) {
|
||||
return pth.replace(/[/\\]/g, path.sep);
|
||||
}
|
||||
exports.toPlatformPath = toPlatformPath;
|
||||
//# sourceMappingURL=path-utils.js.map
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 1327:
|
||||
/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
|
||||
|
||||
@@ -4413,7 +4490,7 @@ var endpoint = __nccwpck_require__(9440);
|
||||
var universalUserAgent = __nccwpck_require__(5030);
|
||||
var isPlainObject = __nccwpck_require__(3287);
|
||||
var nodeFetch = _interopDefault(__nccwpck_require__(467));
|
||||
var requestError = __nccwpck_require__(537);
|
||||
var requestError = __nccwpck_require__(13);
|
||||
|
||||
const VERSION = "5.6.3";
|
||||
|
||||
@@ -4582,6 +4659,88 @@ exports.request = request;
|
||||
//# sourceMappingURL=index.js.map
|
||||
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 13:
|
||||
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
|
||||
|
||||
"use strict";
|
||||
|
||||
|
||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||
|
||||
function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
|
||||
|
||||
var deprecation = __nccwpck_require__(8932);
|
||||
var once = _interopDefault(__nccwpck_require__(1223));
|
||||
|
||||
const logOnceCode = once(deprecation => console.warn(deprecation));
|
||||
const logOnceHeaders = once(deprecation => console.warn(deprecation));
|
||||
/**
|
||||
* Error with extra properties to help with debugging
|
||||
*/
|
||||
|
||||
class RequestError extends Error {
|
||||
constructor(message, statusCode, options) {
|
||||
super(message); // Maintains proper stack trace (only available on V8)
|
||||
|
||||
/* istanbul ignore next */
|
||||
|
||||
if (Error.captureStackTrace) {
|
||||
Error.captureStackTrace(this, this.constructor);
|
||||
}
|
||||
|
||||
this.name = "HttpError";
|
||||
this.status = statusCode;
|
||||
let headers;
|
||||
|
||||
if ("headers" in options && typeof options.headers !== "undefined") {
|
||||
headers = options.headers;
|
||||
}
|
||||
|
||||
if ("response" in options) {
|
||||
this.response = options.response;
|
||||
headers = options.response.headers;
|
||||
} // redact request credentials without mutating original request options
|
||||
|
||||
|
||||
const requestCopy = Object.assign({}, options.request);
|
||||
|
||||
if (options.request.headers.authorization) {
|
||||
requestCopy.headers = Object.assign({}, options.request.headers, {
|
||||
authorization: options.request.headers.authorization.replace(/ .*$/, " [REDACTED]")
|
||||
});
|
||||
}
|
||||
|
||||
requestCopy.url = requestCopy.url // client_id & client_secret can be passed as URL query parameters to increase rate limit
|
||||
// see https://developer.github.com/v3/#increasing-the-unauthenticated-rate-limit-for-oauth-applications
|
||||
.replace(/\bclient_secret=\w+/g, "client_secret=[REDACTED]") // OAuth tokens can be passed as URL query parameters, although it is not recommended
|
||||
// see https://developer.github.com/v3/#oauth2-token-sent-in-a-header
|
||||
.replace(/\baccess_token=\w+/g, "access_token=[REDACTED]");
|
||||
this.request = requestCopy; // deprecations
|
||||
|
||||
Object.defineProperty(this, "code", {
|
||||
get() {
|
||||
logOnceCode(new deprecation.Deprecation("[@octokit/request-error] `error.code` is deprecated, use `error.status`."));
|
||||
return statusCode;
|
||||
}
|
||||
|
||||
});
|
||||
Object.defineProperty(this, "headers", {
|
||||
get() {
|
||||
logOnceHeaders(new deprecation.Deprecation("[@octokit/request-error] `error.headers` is deprecated, use `error.response.headers`."));
|
||||
return headers || {};
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
exports.RequestError = RequestError;
|
||||
//# sourceMappingURL=index.js.map
|
||||
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 3682:
|
||||
@@ -13739,13 +13898,13 @@ const schemas_1 = __nccwpck_require__(1129);
|
||||
function filterChangesBySeverity(severity, changes) {
|
||||
const severityIdx = schemas_1.SEVERITIES.indexOf(severity);
|
||||
let filteredChanges = [];
|
||||
for (let change of changes) {
|
||||
for (const change of changes) {
|
||||
if (change === undefined ||
|
||||
change.vulnerabilities === undefined ||
|
||||
change.vulnerabilities.length === 0) {
|
||||
continue;
|
||||
}
|
||||
let fChange = Object.assign(Object.assign({}, change), { vulnerabilities: change.vulnerabilities.filter(vuln => {
|
||||
const fChange = Object.assign(Object.assign({}, change), { vulnerabilities: change.vulnerabilities.filter(vuln => {
|
||||
const vulnIdx = schemas_1.SEVERITIES.indexOf(vuln.severity);
|
||||
if (vulnIdx <= severityIdx) {
|
||||
return true;
|
||||
@@ -13825,7 +13984,7 @@ exports.ConfigurationOptionsSchema = z
|
||||
deny_licenses: z.array(z.string()).default([])
|
||||
})
|
||||
.partial()
|
||||
.refine(obj => !(obj.allow_licenses && obj.deny_licenses), "Your workflow file has both an allow_licenses list and deny_licenses list, but you can only set one or the other.");
|
||||
.refine(obj => !(obj.allow_licenses && obj.deny_licenses), 'Your workflow file has both an allow_licenses list and deny_licenses list, but you can only set one or the other.');
|
||||
exports.ChangesSchema = z.array(exports.ChangeSchema);
|
||||
|
||||
|
||||
|
||||
+1
-1
File diff suppressed because one or more lines are too long
Generated
+218
-1198
File diff suppressed because it is too large
Load Diff
+11
-11
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "dependency-review-action",
|
||||
"version": "2.0.1",
|
||||
"version": "2.0.2",
|
||||
"private": true,
|
||||
"description": "A GitHub Action for Dependency Review",
|
||||
"main": "lib/main.js",
|
||||
@@ -25,30 +25,30 @@
|
||||
"author": "GitHub",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@actions/core": "^1.8.2",
|
||||
"@actions/core": "^1.9.0",
|
||||
"@actions/github": "^5.0.3",
|
||||
"@octokit/plugin-retry": "^3.0.9",
|
||||
"@octokit/request-error": "^2.1.0",
|
||||
"@octokit/request-error": "^3.0.0",
|
||||
"ansi-styles": "^6.1.0",
|
||||
"got": "^12.1.0",
|
||||
"nodemon": "^2.0.16",
|
||||
"nodemon": "^2.0.19",
|
||||
"yaml": "^2.1.1",
|
||||
"zod": "^3.17.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^17.0.43",
|
||||
"@typescript-eslint/eslint-plugin": "^5.28.0",
|
||||
"@typescript-eslint/parser": "^5.28.0",
|
||||
"@types/node": "^16.11.44",
|
||||
"@typescript-eslint/eslint-plugin": "^5.30.6",
|
||||
"@typescript-eslint/parser": "^5.30.6",
|
||||
"@vercel/ncc": "^0.34.0",
|
||||
"esbuild-register": "^3.3.3",
|
||||
"eslint": "^8.17.0",
|
||||
"eslint": "^8.19.0",
|
||||
"eslint-plugin-github": "^4.3.6",
|
||||
"eslint-plugin-jest": "^26.5.3",
|
||||
"jest": "^27.5.1",
|
||||
"js-yaml": "^4.1.0",
|
||||
"nodemon": "^2.0.16",
|
||||
"prettier": "2.7.0",
|
||||
"nodemon": "^2.0.19",
|
||||
"prettier": "2.7.1",
|
||||
"ts-jest": "^27.1.4",
|
||||
"typescript": "^4.7.3"
|
||||
"typescript": "^4.7.4"
|
||||
}
|
||||
}
|
||||
|
||||
+3
-4
@@ -1,5 +1,4 @@
|
||||
import {Changes} from './schemas'
|
||||
import {Severity, SEVERITIES} from './schemas'
|
||||
import {Changes, Severity, SEVERITIES} from './schemas'
|
||||
|
||||
export function filterChangesBySeverity(
|
||||
severity: Severity,
|
||||
@@ -7,7 +6,7 @@ export function filterChangesBySeverity(
|
||||
): Changes {
|
||||
const severityIdx = SEVERITIES.indexOf(severity)
|
||||
let filteredChanges = []
|
||||
for (let change of changes) {
|
||||
for (const change of changes) {
|
||||
if (
|
||||
change === undefined ||
|
||||
change.vulnerabilities === undefined ||
|
||||
@@ -16,7 +15,7 @@ export function filterChangesBySeverity(
|
||||
continue
|
||||
}
|
||||
|
||||
let fChange = {
|
||||
const fChange = {
|
||||
...change,
|
||||
vulnerabilities: change.vulnerabilities.filter(vuln => {
|
||||
const vulnIdx = SEVERITIES.indexOf(vuln.severity)
|
||||
|
||||
+13
-9
@@ -1,4 +1,4 @@
|
||||
import {Change, ChangeSchema} from './schemas'
|
||||
import {Change} from './schemas'
|
||||
|
||||
/**
|
||||
* Loops through a list of changes, filtering and returning the
|
||||
@@ -13,19 +13,23 @@ import {Change, ChangeSchema} from './schemas'
|
||||
* @returns {[Array<Change>, Array<Change]} A tuple where the first element is the list of denied changes and the second one is the list of changes with unknown licenses
|
||||
*/
|
||||
export function getDeniedLicenseChanges(
|
||||
changes: Array<Change>,
|
||||
changes: Change[],
|
||||
licenses: {
|
||||
allow?: Array<string>
|
||||
deny?: Array<string>
|
||||
allow?: string[]
|
||||
deny?: string[]
|
||||
}
|
||||
): [Array<Change>, Array<Change>] {
|
||||
let {allow, deny} = licenses
|
||||
): [Change[], Change[]] {
|
||||
const {allow, deny} = licenses
|
||||
|
||||
let disallowed: Change[] = []
|
||||
let unknown: Change[] = []
|
||||
const disallowed: Change[] = []
|
||||
const unknown: Change[] = []
|
||||
|
||||
for (const change of changes) {
|
||||
let license = change.license
|
||||
if (change.change_type === 'removed') {
|
||||
continue
|
||||
}
|
||||
|
||||
const license = change.license
|
||||
if (license === null) {
|
||||
unknown.push(change)
|
||||
continue
|
||||
|
||||
+14
-18
@@ -27,16 +27,16 @@ async function run(): Promise<void> {
|
||||
headRef: pull_request.head.sha
|
||||
})
|
||||
|
||||
let config = readConfig()
|
||||
let minSeverity = config.fail_on_severity
|
||||
const config = readConfig()
|
||||
const minSeverity = config.fail_on_severity
|
||||
let failed = false
|
||||
|
||||
let licenses = {
|
||||
const licenses = {
|
||||
allow: config.allow_licenses,
|
||||
deny: config.deny_licenses
|
||||
}
|
||||
|
||||
let filteredChanges = filterChangesBySeverity(
|
||||
const filteredChanges = filterChangesBySeverity(
|
||||
minSeverity as Severity,
|
||||
changes
|
||||
)
|
||||
@@ -52,13 +52,13 @@ async function run(): Promise<void> {
|
||||
}
|
||||
}
|
||||
|
||||
let [licenseErrors, unknownLicenses] = getDeniedLicenseChanges(
|
||||
const [licenseErrors, unknownLicenses] = getDeniedLicenseChanges(
|
||||
changes,
|
||||
licenses
|
||||
)
|
||||
|
||||
if (licenseErrors.length > 0) {
|
||||
printLicensesError(licenseErrors, licenses)
|
||||
printLicensesError(licenseErrors)
|
||||
core.setFailed('Dependency review detected incompatible licenses.')
|
||||
}
|
||||
|
||||
@@ -90,7 +90,7 @@ async function run(): Promise<void> {
|
||||
}
|
||||
}
|
||||
|
||||
function printChangeVulnerabilities(change: Change) {
|
||||
function printChangeVulnerabilities(change: Change): void {
|
||||
for (const vuln of change.vulnerabilities) {
|
||||
core.info(
|
||||
`${styles.bold.open}${change.manifest} » ${change.name}@${
|
||||
@@ -117,19 +117,11 @@ function renderSeverity(
|
||||
return `${styles.color[color].open}(${severity} severity)${styles.color[color].close}`
|
||||
}
|
||||
|
||||
function printLicensesError(
|
||||
changes: Array<Change>,
|
||||
licenses: {
|
||||
allow?: Array<string>
|
||||
deny?: Array<string>
|
||||
}
|
||||
): void {
|
||||
if (changes.length == 0) {
|
||||
function printLicensesError(changes: Change[]): void {
|
||||
if (changes.length === 0) {
|
||||
return
|
||||
}
|
||||
|
||||
let {allow = [], deny = []} = licenses
|
||||
|
||||
core.info('\nThe following dependencies have incompatible licenses:\n')
|
||||
for (const change of changes) {
|
||||
core.info(
|
||||
@@ -138,7 +130,11 @@ function printLicensesError(
|
||||
}
|
||||
}
|
||||
|
||||
function printNullLicenses(changes: Array<Change>): void {
|
||||
function printNullLicenses(changes: Change[]): void {
|
||||
if (changes.length === 0) {
|
||||
return
|
||||
}
|
||||
|
||||
core.info('\nWe could not detect a license for the following dependencies:\n')
|
||||
for (const change of changes) {
|
||||
core.info(
|
||||
|
||||
+1
-1
@@ -39,7 +39,7 @@ export const ConfigurationOptionsSchema = z
|
||||
.partial()
|
||||
.refine(
|
||||
obj => !(obj.allow_licenses && obj.deny_licenses),
|
||||
"Your workflow file has both an allow_licenses list and deny_licenses list, but you can only set one or the other."
|
||||
'Your workflow file has both an allow_licenses list and deny_licenses list, but you can only set one or the other.'
|
||||
)
|
||||
|
||||
export const ChangesSchema = z.array(ChangeSchema)
|
||||
|
||||
Reference in New Issue
Block a user