Compare commits
72 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 | |||
| aabd50a60d | |||
| 981c44c2a9 | |||
| c0d32934e8 | |||
| 963fe8045d | |||
| bf94d94f63 | |||
| 43ce5df965 | |||
| 24bc5e9934 |
@@ -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"
|
||||
}
|
||||
@@ -73,6 +73,39 @@ Here are a few things you can do that will increase the likelihood of your pull
|
||||
- Keep your change as focused as possible. If there are multiple changes you would like to make that are not dependent upon each other, consider submitting them as separate pull requests.
|
||||
- Write a [good commit message](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html).
|
||||
|
||||
## Cutting a new release
|
||||
|
||||
1. Go to [Draft a new
|
||||
release](https://github.com/actions/dependency-review-action/releases/new)
|
||||
in the Releases page.
|
||||
2. Make sure that the `Publish this Action to the GitHub Marketplace`
|
||||
checkbox is enabled
|
||||
|
||||
<img width="481" alt="Screenshot 2022-06-15 at 12 08 19" src="https://user-images.githubusercontent.com/2161/173822484-4b60d8b4-c674-4bff-b5ff-b0c4a3650ab7.png">
|
||||
|
||||
3. Click "Choose a tag" and then "Create new tag", where the tag name
|
||||
will be your version prefixed by a `v` (e.g. `v1.2.3`).
|
||||
4. Use a version number for the release title (e.g. "1.2.3").
|
||||
|
||||
<img width="700" alt="Screenshot 2022-06-15 at 12 08 36" src="https://user-images.githubusercontent.com/2161/173822548-33ab3432-d679-4dc1-adf8-b50fdaf47de3.png">
|
||||
|
||||
5. Add your release notes. If this is a major version make sure to
|
||||
include a small description of the biggest changes in the new version.
|
||||
6. Click "Publish Release".
|
||||
|
||||
You now have a tag and release using the semver version you used
|
||||
above. The last remaining thing to do is to move the dynamic version
|
||||
identifier to match the current SHA. This allows users to adopt a
|
||||
major version number (e.g. `v1`) in their workflows while
|
||||
automatically getting all the
|
||||
minor/patch updates.
|
||||
|
||||
To do this just force-create a new annotated tag and push it:
|
||||
```
|
||||
git tag -fa v1 -m "Updating v1 tag"
|
||||
git push origin v1 --force
|
||||
```
|
||||
|
||||
## Resources
|
||||
|
||||
- [How to Contribute to Open Source](https://opensource.guide/how-to-contribute/)
|
||||
|
||||
@@ -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])
|
||||
})
|
||||
|
||||
+178
-20
@@ -81,12 +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;
|
||||
// TODO: be loud about unknown licenses
|
||||
if (change.change_type === 'removed') {
|
||||
continue;
|
||||
}
|
||||
const license = change.license;
|
||||
if (license === null) {
|
||||
unknown.push(change);
|
||||
continue;
|
||||
@@ -172,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 &&
|
||||
@@ -188,12 +190,12 @@ 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);
|
||||
printNullLicenses(unknownLicenses);
|
||||
printLicensesError(licenseErrors);
|
||||
core.setFailed('Dependency review detected incompatible licenses.');
|
||||
}
|
||||
printNullLicenses(unknownLicenses);
|
||||
if (failed) {
|
||||
core.setFailed('Dependency review detected vulnerable packages.');
|
||||
}
|
||||
@@ -234,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}`);
|
||||
@@ -318,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);
|
||||
|
||||
|
||||
@@ -748,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
|
||||
|
||||
/***/ }),
|
||||
@@ -885,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__) {
|
||||
|
||||
@@ -4414,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";
|
||||
|
||||
@@ -4583,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:
|
||||
@@ -13740,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;
|
||||
@@ -13826,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.0",
|
||||
"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
-10
@@ -1,4 +1,4 @@
|
||||
import {Change, ChangeSchema} from './schemas'
|
||||
import {Change} from './schemas'
|
||||
|
||||
/**
|
||||
* Loops through a list of changes, filtering and returning the
|
||||
@@ -13,20 +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
|
||||
// TODO: be loud about unknown licenses
|
||||
if (change.change_type === 'removed') {
|
||||
continue
|
||||
}
|
||||
|
||||
const license = change.license
|
||||
if (license === null) {
|
||||
unknown.push(change)
|
||||
continue
|
||||
|
||||
+16
-19
@@ -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,17 +52,18 @@ async function run(): Promise<void> {
|
||||
}
|
||||
}
|
||||
|
||||
let [licenseErrors, unknownLicenses] = getDeniedLicenseChanges(
|
||||
const [licenseErrors, unknownLicenses] = getDeniedLicenseChanges(
|
||||
changes,
|
||||
licenses
|
||||
)
|
||||
|
||||
if (licenseErrors.length > 0) {
|
||||
printLicensesError(licenseErrors, licenses)
|
||||
printNullLicenses(unknownLicenses)
|
||||
printLicensesError(licenseErrors)
|
||||
core.setFailed('Dependency review detected incompatible licenses.')
|
||||
}
|
||||
|
||||
printNullLicenses(unknownLicenses)
|
||||
|
||||
if (failed) {
|
||||
core.setFailed('Dependency review detected vulnerable packages.')
|
||||
} else {
|
||||
@@ -89,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}@${
|
||||
@@ -116,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(
|
||||
@@ -137,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