Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
77a34f96cc |
@@ -71,20 +71,13 @@ or by inlining these options in your workflow file.
|
||||
|
||||
### config-file
|
||||
|
||||
A string representing the path to a configuraton file. It can be a
|
||||
local file, or a file located in an external repository. You can use
|
||||
this syntax for external repositories: `OWNER/REPOSITORY/FILENAME@BRANCH`.
|
||||
A string representing the path to an external configuration file. By
|
||||
default external configuration files are not used.
|
||||
|
||||
If the configuration file is located in an external private repository,
|
||||
use the [external-repo-token](#external-repo-token) parameter of the
|
||||
action to specify a token that has read access to the repository.
|
||||
**Possible values**: A string representing the absolute path to the
|
||||
configuration file.
|
||||
|
||||
**Possible values**: A string representing a path to a file located
|
||||
in the current repository, or in an external one.
|
||||
|
||||
**Example**: `config-file: ./.github/dependency-review-config.yml # local file`.
|
||||
|
||||
**Example**: `config-file: github/octorepo/dependency-review-config.yml@main # external repo`
|
||||
**Example**: `config-file: ./.github/dependency-review-config.yml`.
|
||||
|
||||
### fail-on-severity
|
||||
|
||||
@@ -148,9 +141,9 @@ deny-licenses:
|
||||
|
||||
### allow-ghsas
|
||||
|
||||
A list of GitHub Security Advisory IDs that can be skipped during detection.
|
||||
Add a custom list of GitHub Advisory IDs that can be skipped during detection.
|
||||
|
||||
**Possible values**: Any valid GHSAs from the [GitHub Advisory Database](https://github.com/advisories).
|
||||
**Possible values**: Any valid advisory GHSA ids.
|
||||
|
||||
**Inline example**: `allow-ghsas: GHSA-abcd-1234-5679, GHSA-efgh-1234-5679`
|
||||
|
||||
@@ -192,19 +185,6 @@ base-ref: 8bb8a58d6a4028b6c2e314d5caaf273f57644896
|
||||
head-ref: 69af5638bf660cf218aad5709a4c100e42a2f37b
|
||||
```
|
||||
|
||||
### external-repo-token
|
||||
|
||||
A token for fetching external configuration files if they live in
|
||||
an external private repository.
|
||||
|
||||
Visit the [developer settings](https://github.com/settings/tokens) to
|
||||
create a new personal access token with `read` permissions for the
|
||||
repository that hosts the config file.
|
||||
|
||||
**Possible values**: Any GitHub token with read access to the external repository.
|
||||
|
||||
**Example**: `external-repo-token: ghp_123456789abcdef...`
|
||||
|
||||
### Configuration File
|
||||
|
||||
You can use an external configuration file to specify the settings for
|
||||
|
||||
+70
-79
@@ -1,5 +1,5 @@
|
||||
import {expect, test, beforeEach} from '@jest/globals'
|
||||
import {readConfig} from '../src/config'
|
||||
import {readConfig, readConfigFile} from '../src/config'
|
||||
import {getRefs} from '../src/git-refs'
|
||||
import * as Utils from '../src/utils'
|
||||
|
||||
@@ -39,53 +39,43 @@ beforeEach(() => {
|
||||
})
|
||||
|
||||
test('it defaults to low severity', async () => {
|
||||
const config = await readConfig()
|
||||
expect(config.fail_on_severity).toEqual('low')
|
||||
const options = readConfig()
|
||||
expect(options.fail_on_severity).toEqual('low')
|
||||
})
|
||||
|
||||
test('it reads custom configs', async () => {
|
||||
setInput('fail-on-severity', 'critical')
|
||||
setInput('allow-licenses', ' BSD, GPL 2')
|
||||
|
||||
const config = await readConfig()
|
||||
expect(config.fail_on_severity).toEqual('critical')
|
||||
expect(config.allow_licenses).toEqual(['BSD', 'GPL 2'])
|
||||
const options = readConfig()
|
||||
expect(options.fail_on_severity).toEqual('critical')
|
||||
expect(options.allow_licenses).toEqual(['BSD', 'GPL 2'])
|
||||
})
|
||||
|
||||
test('it defaults to empty allow/deny lists ', async () => {
|
||||
const config = await readConfig()
|
||||
const options = readConfig()
|
||||
|
||||
expect(config.allow_licenses).toEqual(undefined)
|
||||
expect(config.deny_licenses).toEqual(undefined)
|
||||
expect(options.allow_licenses).toEqual(undefined)
|
||||
expect(options.deny_licenses).toEqual(undefined)
|
||||
})
|
||||
|
||||
test('it raises an error if both an allow and denylist are specified', async () => {
|
||||
setInput('allow-licenses', 'MIT')
|
||||
setInput('deny-licenses', 'BSD')
|
||||
|
||||
await expect(readConfig()).rejects.toThrow(
|
||||
'You cannot specify both allow-licenses and deny-licenses'
|
||||
)
|
||||
})
|
||||
test('it raises an error if an empty allow list is specified', async () => {
|
||||
setInput('config-file', './__tests__/fixtures/config-empty-allow-sample.yml')
|
||||
|
||||
await expect(readConfig()).rejects.toThrow(
|
||||
'You should provide at least one license in allow-licenses'
|
||||
)
|
||||
expect(() => readConfig()).toThrow()
|
||||
})
|
||||
|
||||
test('it raises an error when given an unknown severity', async () => {
|
||||
setInput('fail-on-severity', 'zombies')
|
||||
|
||||
await expect(readConfig()).rejects.toThrow(/received 'zombies'/)
|
||||
expect(() => readConfig()).toThrow()
|
||||
})
|
||||
|
||||
test('it uses the given refs when the event is not a pull request', async () => {
|
||||
setInput('base-ref', 'a-custom-base-ref')
|
||||
setInput('head-ref', 'a-custom-head-ref')
|
||||
|
||||
const refs = getRefs(await readConfig(), {
|
||||
const refs = getRefs(readConfig(), {
|
||||
payload: {},
|
||||
eventName: 'workflow_dispatch'
|
||||
})
|
||||
@@ -94,9 +84,9 @@ test('it uses the given refs when the event is not a pull request', async () =>
|
||||
})
|
||||
|
||||
test('it raises an error when no refs are provided and the event is not a pull request', async () => {
|
||||
const config = await readConfig()
|
||||
const options = readConfig()
|
||||
expect(() =>
|
||||
getRefs(config, {
|
||||
getRefs(options, {
|
||||
payload: {},
|
||||
eventName: 'workflow_dispatch'
|
||||
})
|
||||
@@ -104,132 +94,133 @@ test('it raises an error when no refs are provided and the event is not a pull r
|
||||
})
|
||||
|
||||
test('it reads an external config file', async () => {
|
||||
setInput('config-file', './__tests__/fixtures/config-allow-sample.yml')
|
||||
|
||||
const config = await readConfig()
|
||||
expect(config.fail_on_severity).toEqual('critical')
|
||||
expect(config.allow_licenses).toEqual(['BSD', 'GPL 2'])
|
||||
let options = readConfigFile('./__tests__/fixtures/config-allow-sample.yml')
|
||||
expect(options.fail_on_severity).toEqual('critical')
|
||||
expect(options.allow_licenses).toEqual(['BSD', 'GPL 2'])
|
||||
})
|
||||
|
||||
test('raises an error when the the config file was not found', async () => {
|
||||
setInput('config-file', 'fixtures/i-dont-exist')
|
||||
await expect(readConfig()).rejects.toThrow(/Unable to fetch config file/)
|
||||
expect(() => readConfigFile('fixtures/i-dont-exist')).toThrow()
|
||||
})
|
||||
|
||||
test('it parses options from both sources', async () => {
|
||||
setInput('config-file', './__tests__/fixtures/config-allow-sample.yml')
|
||||
|
||||
let config = await readConfig()
|
||||
expect(config.fail_on_severity).toEqual('critical')
|
||||
let options = readConfig()
|
||||
expect(options.fail_on_severity).toEqual('critical')
|
||||
|
||||
setInput('base-ref', 'a-custom-base-ref')
|
||||
config = await readConfig()
|
||||
expect(config.base_ref).toEqual('a-custom-base-ref')
|
||||
options = readConfig()
|
||||
expect(options.base_ref).toEqual('a-custom-base-ref')
|
||||
})
|
||||
|
||||
test('in case of conflicts, the inline config is the source of truth', async () => {
|
||||
setInput('fail-on-severity', 'low')
|
||||
test('in case of conflicts, the external config is the source of truth', async () => {
|
||||
setInput('config-file', './__tests__/fixtures/config-allow-sample.yml') // this will set fail-on-severity to 'critical'
|
||||
|
||||
const config = await readConfig()
|
||||
expect(config.fail_on_severity).toEqual('low')
|
||||
let options = readConfig()
|
||||
expect(options.fail_on_severity).toEqual('critical')
|
||||
|
||||
// this should not overwite the previous value
|
||||
setInput('fail-on-severity', 'low')
|
||||
options = readConfig()
|
||||
expect(options.fail_on_severity).toEqual('critical')
|
||||
})
|
||||
|
||||
test('it uses the default values when loading external files', async () => {
|
||||
setInput('config-file', './__tests__/fixtures/no-licenses-config.yml')
|
||||
let config = await readConfig()
|
||||
expect(config.allow_licenses).toEqual(undefined)
|
||||
expect(config.deny_licenses).toEqual(undefined)
|
||||
let options = readConfig()
|
||||
expect(options.allow_licenses).toEqual(undefined)
|
||||
expect(options.deny_licenses).toEqual(undefined)
|
||||
|
||||
setInput('config-file', './__tests__/fixtures/license-config-sample.yml')
|
||||
config = await readConfig()
|
||||
expect(config.fail_on_severity).toEqual('low')
|
||||
options = readConfig()
|
||||
expect(options.fail_on_severity).toEqual('low')
|
||||
})
|
||||
|
||||
test('it accepts an external configuration filename', async () => {
|
||||
setInput('config-file', './__tests__/fixtures/no-licenses-config.yml')
|
||||
const config = await readConfig()
|
||||
expect(config.fail_on_severity).toEqual('critical')
|
||||
const options = readConfig()
|
||||
expect(options.fail_on_severity).toEqual('critical')
|
||||
})
|
||||
|
||||
test('it raises an error when given an unknown severity in an external config file', async () => {
|
||||
setInput('config-file', './__tests__/fixtures/invalid-severity-config.yml')
|
||||
await expect(readConfig()).rejects.toThrow()
|
||||
expect(() => readConfig()).toThrow()
|
||||
})
|
||||
|
||||
test('it defaults to runtime scope', async () => {
|
||||
const config = await readConfig()
|
||||
expect(config.fail_on_scopes).toEqual(['runtime'])
|
||||
const options = readConfig()
|
||||
expect(options.fail_on_scopes).toEqual(['runtime'])
|
||||
})
|
||||
|
||||
test('it parses custom scopes preference', async () => {
|
||||
setInput('fail-on-scopes', 'runtime, development')
|
||||
let config = await readConfig()
|
||||
expect(config.fail_on_scopes).toEqual(['runtime', 'development'])
|
||||
let options = readConfig()
|
||||
expect(options.fail_on_scopes).toEqual(['runtime', 'development'])
|
||||
|
||||
clearInputs()
|
||||
setInput('fail-on-scopes', 'development')
|
||||
config = await readConfig()
|
||||
expect(config.fail_on_scopes).toEqual(['development'])
|
||||
options = readConfig()
|
||||
expect(options.fail_on_scopes).toEqual(['development'])
|
||||
})
|
||||
|
||||
test('it raises an error when given invalid scope', async () => {
|
||||
setInput('fail-on-scopes', 'runtime, zombies')
|
||||
await expect(readConfig()).rejects.toThrow(/received 'zombies'/)
|
||||
expect(() => readConfig()).toThrow()
|
||||
})
|
||||
|
||||
test('it defaults to an empty GHSA allowlist', async () => {
|
||||
const config = await readConfig()
|
||||
expect(config.allow_ghsas).toEqual([])
|
||||
const options = readConfig()
|
||||
expect(options.allow_ghsas).toEqual(undefined)
|
||||
})
|
||||
|
||||
test('it successfully parses GHSA allowlist', async () => {
|
||||
setInput('allow-ghsas', 'GHSA-abcd-1234-5679, GHSA-efgh-1234-5679')
|
||||
const config = await readConfig()
|
||||
expect(config.allow_ghsas).toEqual([
|
||||
const options = readConfig()
|
||||
expect(options.allow_ghsas).toEqual([
|
||||
'GHSA-abcd-1234-5679',
|
||||
'GHSA-efgh-1234-5679'
|
||||
])
|
||||
})
|
||||
|
||||
test('it defaults to checking licenses', async () => {
|
||||
const config = await readConfig()
|
||||
expect(config.license_check).toBe(true)
|
||||
const options = readConfig()
|
||||
expect(options.license_check).toBe(true)
|
||||
})
|
||||
|
||||
test('it parses the license-check input', async () => {
|
||||
setInput('license-check', 'false')
|
||||
let config = await readConfig()
|
||||
expect(config.license_check).toEqual(false)
|
||||
let options = readConfig()
|
||||
expect(options.license_check).toEqual(false)
|
||||
|
||||
clearInputs()
|
||||
setInput('license-check', 'true')
|
||||
config = await readConfig()
|
||||
expect(config.license_check).toEqual(true)
|
||||
options = readConfig()
|
||||
expect(options.license_check).toEqual(true)
|
||||
})
|
||||
|
||||
test('it defaults to checking vulnerabilities', async () => {
|
||||
const config = await readConfig()
|
||||
expect(config.vulnerability_check).toBe(true)
|
||||
const options = readConfig()
|
||||
expect(options.vulnerability_check).toBe(true)
|
||||
})
|
||||
|
||||
test('it parses the vulnerability-check input', async () => {
|
||||
setInput('vulnerability-check', 'false')
|
||||
let config = await readConfig()
|
||||
expect(config.vulnerability_check).toEqual(false)
|
||||
let options = readConfig()
|
||||
expect(options.vulnerability_check).toEqual(false)
|
||||
|
||||
clearInputs()
|
||||
setInput('vulnerability-check', 'true')
|
||||
config = await readConfig()
|
||||
expect(config.vulnerability_check).toEqual(true)
|
||||
options = readConfig()
|
||||
expect(options.vulnerability_check).toEqual(true)
|
||||
})
|
||||
|
||||
test('it is not possible to disable both checks', async () => {
|
||||
setInput('license-check', 'false')
|
||||
setInput('vulnerability-check', 'false')
|
||||
await expect(readConfig()).rejects.toThrow(
|
||||
/Can't disable both license-check and vulnerability-check/
|
||||
)
|
||||
expect(() => {
|
||||
readConfig()
|
||||
}).toThrow("Can't disable both license-check and vulnerability-check")
|
||||
})
|
||||
|
||||
describe('licenses that are not valid SPDX licenses', () => {
|
||||
@@ -239,15 +230,15 @@ describe('licenses that are not valid SPDX licenses', () => {
|
||||
|
||||
test('it raises an error for invalid licenses in allow-licenses', async () => {
|
||||
setInput('allow-licenses', ' BSD, GPL 2')
|
||||
await expect(readConfig()).rejects.toThrow(
|
||||
'Invalid license(s) in allow-licenses: BSD, GPL 2'
|
||||
)
|
||||
expect(() => {
|
||||
readConfig()
|
||||
}).toThrow('Invalid license(s) in allow-licenses: BSD, GPL 2')
|
||||
})
|
||||
|
||||
test('it raises an error for invalid licenses in deny-licenses', async () => {
|
||||
setInput('deny-licenses', ' BSD, GPL 2')
|
||||
await expect(readConfig()).rejects.toThrow(
|
||||
'Invalid license(s) in deny-licenses: BSD, GPL 2'
|
||||
)
|
||||
expect(() => {
|
||||
readConfig()
|
||||
}).toThrow('Invalid license(s) in deny-licenses: BSD, GPL 2')
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
fail_on_severity: critical
|
||||
allow_licenses: []
|
||||
@@ -99,6 +99,17 @@ test('it adds license inside the deny list to forbidden changes', async () => {
|
||||
expect(forbidden.length).toEqual(1)
|
||||
})
|
||||
|
||||
// This is more of a "here's a behavior that might be surprising" than an actual
|
||||
// thing we want in the system. Please remove this test after refactoring.
|
||||
test('it adds all licenses to forbidden changes when allow is provided an empty array', async () => {
|
||||
const changes: Changes = [npmChange, rubyChange]
|
||||
let {forbidden} = await getInvalidLicenseChanges(changes, {
|
||||
allow: [],
|
||||
deny: ['BSD']
|
||||
})
|
||||
expect(forbidden.length).toBe(2)
|
||||
})
|
||||
|
||||
test('it does not add license outside the allow list to forbidden changes if it is in removed changes', async () => {
|
||||
const changes: Changes = [
|
||||
{...npmChange, change_type: 'removed'},
|
||||
|
||||
+1
-5
@@ -21,7 +21,7 @@ inputs:
|
||||
description: The head git ref to be used for this check. Has a default value when the workflow event is `pull_request` or `pull_request_target`. Must be provided otherwise.
|
||||
required: false
|
||||
config-file:
|
||||
description: A path to the configuration file for the action.
|
||||
description: A filepath to the configuration file for the action.
|
||||
required: false
|
||||
allow-licenses:
|
||||
description: Comma-separated list of allowed licenses (e.g. "MIT, GPL 3.0, BSD 2 Clause")
|
||||
@@ -32,10 +32,6 @@ inputs:
|
||||
allow-ghsas:
|
||||
description: Comma-separated list of allowed Github Advisory IDs (e.g. "GHSA-abcd-1234-5679, GHSA-efgh-1234-5679")
|
||||
required: false
|
||||
external-repo-token:
|
||||
description: A token for fetching external configuration file if it lives in another repository. It is required if the repository is private
|
||||
required: false
|
||||
|
||||
runs:
|
||||
using: 'node16'
|
||||
main: 'dist/index.js'
|
||||
|
||||
+117
-237
@@ -107,6 +107,29 @@ exports.getRefs = getRefs;
|
||||
|
||||
"use strict";
|
||||
|
||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
var desc = Object.getOwnPropertyDescriptor(m, k);
|
||||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
||||
desc = { enumerable: true, get: function() { return m[k]; } };
|
||||
}
|
||||
Object.defineProperty(o, k2, desc);
|
||||
}) : (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.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
||||
__setModuleDefault(result, mod);
|
||||
return result;
|
||||
};
|
||||
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) {
|
||||
@@ -121,7 +144,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||
exports.getInvalidLicenseChanges = void 0;
|
||||
const core = __importStar(__nccwpck_require__(2186));
|
||||
const spdx_satisfies_1 = __importDefault(__nccwpck_require__(4424));
|
||||
const octokit_1 = __nccwpck_require__(7467);
|
||||
const utils_1 = __nccwpck_require__(918);
|
||||
/**
|
||||
* Loops through a list of changes, filtering and returning the
|
||||
@@ -180,11 +205,11 @@ function getInvalidLicenseChanges(changes, licenses) {
|
||||
exports.getInvalidLicenseChanges = getInvalidLicenseChanges;
|
||||
const fetchGHLicense = (owner, repo) => __awaiter(void 0, void 0, void 0, function* () {
|
||||
var _a, _b;
|
||||
const octokit = new octokit_1.Octokit({
|
||||
auth: core.getInput('repo-token', { required: true })
|
||||
});
|
||||
try {
|
||||
const response = yield (0, utils_1.octokitClient)().rest.licenses.getForRepo({
|
||||
owner,
|
||||
repo
|
||||
});
|
||||
const response = yield octokit.rest.licenses.getForRepo({ owner, repo });
|
||||
return (_b = (_a = response.data.license) === null || _a === void 0 ? void 0 : _a.spdx_id) !== null && _b !== void 0 ? _b : null;
|
||||
}
|
||||
catch (_) {
|
||||
@@ -325,7 +350,7 @@ const utils_1 = __nccwpck_require__(918);
|
||||
function run() {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
try {
|
||||
const config = yield (0, config_1.readConfig)();
|
||||
const config = (0, config_1.readConfig)();
|
||||
const refs = (0, git_refs_1.getRefs)(config, github.context);
|
||||
const changes = yield dependencyGraph.compare({
|
||||
owner: github.context.repo.owner,
|
||||
@@ -532,36 +557,17 @@ exports.ConfigurationOptionsSchema = z
|
||||
.object({
|
||||
fail_on_severity: exports.SeveritySchema,
|
||||
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(),
|
||||
allow_licenses: z.array(z.string()).default([]),
|
||||
deny_licenses: z.array(z.string()).default([]),
|
||||
allow_ghsas: z.array(z.string()).default([]),
|
||||
license_check: z.boolean().default(true),
|
||||
vulnerability_check: z.boolean().default(true),
|
||||
config_file: z.string().optional(),
|
||||
base_ref: z.string().optional(),
|
||||
head_ref: z.string().optional()
|
||||
config_file: z.string().optional().default('false'),
|
||||
base_ref: z.string(),
|
||||
head_ref: z.string()
|
||||
})
|
||||
.superRefine((config, context) => {
|
||||
if (config.allow_licenses && config.deny_licenses) {
|
||||
context.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
message: 'You cannot specify both allow-licenses and deny-licenses'
|
||||
});
|
||||
}
|
||||
if (config.allow_licenses && config.allow_licenses.length < 1) {
|
||||
context.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
message: 'You should provide at least one license in allow-licenses'
|
||||
});
|
||||
}
|
||||
if (config.license_check === false &&
|
||||
config.vulnerability_check === false) {
|
||||
context.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
message: "Can't disable both license-check and vulnerability-check"
|
||||
});
|
||||
}
|
||||
});
|
||||
.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.');
|
||||
exports.ChangesSchema = z.array(exports.ChangeSchema);
|
||||
|
||||
|
||||
@@ -735,36 +741,11 @@ exports.addScannedDependencies = addScannedDependencies;
|
||||
|
||||
"use strict";
|
||||
|
||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
var desc = Object.getOwnPropertyDescriptor(m, k);
|
||||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
||||
desc = { enumerable: true, get: function() { return m[k]; } };
|
||||
}
|
||||
Object.defineProperty(o, k2, desc);
|
||||
}) : (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.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
||||
__setModuleDefault(result, mod);
|
||||
return result;
|
||||
};
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||
exports.octokitClient = exports.isSPDXValid = exports.renderUrl = exports.getManifestsSet = exports.groupDependenciesByManifest = void 0;
|
||||
const core = __importStar(__nccwpck_require__(2186));
|
||||
const octokit_1 = __nccwpck_require__(7467);
|
||||
exports.isSPDXValid = exports.renderUrl = exports.getManifestsSet = exports.groupDependenciesByManifest = void 0;
|
||||
const spdx_expression_parse_1 = __importDefault(__nccwpck_require__(1620));
|
||||
function groupDependenciesByManifest(changes) {
|
||||
var _a;
|
||||
@@ -802,17 +783,6 @@ function isSPDXValid(license) {
|
||||
}
|
||||
}
|
||||
exports.isSPDXValid = isSPDXValid;
|
||||
function octokitClient(token = 'repo-token', required = true) {
|
||||
const opts = {};
|
||||
// auth is only added if token is present. For remote config files in public
|
||||
// repos the token is optional, so it could be undefined.
|
||||
const auth = core.getInput(token, { required });
|
||||
if (auth !== undefined) {
|
||||
opts['auth'] = auth;
|
||||
}
|
||||
return new octokit_1.Octokit(opts);
|
||||
}
|
||||
exports.octokitClient = octokitClient;
|
||||
|
||||
|
||||
/***/ }),
|
||||
@@ -27427,20 +27397,11 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
||||
__setModuleDefault(result, mod);
|
||||
return result;
|
||||
};
|
||||
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());
|
||||
});
|
||||
};
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||
exports.readConfig = void 0;
|
||||
exports.readConfigFile = exports.readInlineConfig = exports.readConfig = void 0;
|
||||
const fs = __importStar(__nccwpck_require__(7147));
|
||||
const path_1 = __importDefault(__nccwpck_require__(1017));
|
||||
const yaml_1 = __importDefault(__nccwpck_require__(4083));
|
||||
@@ -27448,43 +27409,6 @@ const core = __importStar(__nccwpck_require__(2186));
|
||||
const z = __importStar(__nccwpck_require__(3301));
|
||||
const schemas_1 = __nccwpck_require__(1129);
|
||||
const utils_1 = __nccwpck_require__(1314);
|
||||
function readConfig() {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
const inlineConfig = readInlineConfig();
|
||||
const configFile = getOptionalInput('config-file');
|
||||
if (configFile !== undefined) {
|
||||
const externalConfig = yield readConfigFile(configFile);
|
||||
return schemas_1.ConfigurationOptionsSchema.parse(Object.assign(Object.assign({}, externalConfig), inlineConfig));
|
||||
}
|
||||
return schemas_1.ConfigurationOptionsSchema.parse(inlineConfig);
|
||||
});
|
||||
}
|
||||
exports.readConfig = readConfig;
|
||||
function readInlineConfig() {
|
||||
const fail_on_severity = getOptionalInput('fail-on-severity');
|
||||
const fail_on_scopes = parseList(getOptionalInput('fail-on-scopes'));
|
||||
const allow_licenses = parseList(getOptionalInput('allow-licenses'));
|
||||
const deny_licenses = parseList(getOptionalInput('deny-licenses'));
|
||||
const allow_ghsas = parseList(getOptionalInput('allow-ghsas'));
|
||||
const license_check = getOptionalBoolean('license-check');
|
||||
const vulnerability_check = getOptionalBoolean('vulnerability-check');
|
||||
const base_ref = getOptionalInput('base-ref');
|
||||
const head_ref = getOptionalInput('head-ref');
|
||||
validateLicenses('allow-licenses', allow_licenses);
|
||||
validateLicenses('deny-licenses', deny_licenses);
|
||||
const keys = {
|
||||
fail_on_severity,
|
||||
fail_on_scopes,
|
||||
allow_licenses,
|
||||
deny_licenses,
|
||||
allow_ghsas,
|
||||
license_check,
|
||||
vulnerability_check,
|
||||
base_ref,
|
||||
head_ref
|
||||
};
|
||||
return Object.fromEntries(Object.entries(keys).filter(([_, value]) => value !== undefined));
|
||||
}
|
||||
function getOptionalBoolean(name) {
|
||||
const value = core.getInput(name);
|
||||
return value.length > 0 ? core.getBooleanInput(name) : undefined;
|
||||
@@ -27510,74 +27434,85 @@ function validateLicenses(key, licenses) {
|
||||
throw new Error(`Invalid license(s) in ${key}: ${invalid_licenses.join(', ')}`);
|
||||
}
|
||||
}
|
||||
function readConfigFile(filePath) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
// match a remote config (e.g. 'owner/repo/filepath@someref')
|
||||
const format = new RegExp('(?<owner>[^/]+)/(?<repo>[^/]+)/(?<path>[^@]+)@(?<ref>.*)');
|
||||
let data;
|
||||
const pieces = format.exec(filePath);
|
||||
try {
|
||||
if ((pieces === null || pieces === void 0 ? void 0 : pieces.groups) && pieces.length === 5) {
|
||||
data = yield getRemoteConfig({
|
||||
owner: pieces.groups.owner,
|
||||
repo: pieces.groups.repo,
|
||||
path: pieces.groups.path,
|
||||
ref: pieces.groups.ref
|
||||
});
|
||||
}
|
||||
else {
|
||||
data = fs.readFileSync(path_1.default.resolve(filePath), 'utf-8');
|
||||
}
|
||||
return parseConfigFile(data);
|
||||
}
|
||||
catch (error) {
|
||||
core.debug(error);
|
||||
throw new Error('Unable to fetch config file');
|
||||
}
|
||||
});
|
||||
function readConfig() {
|
||||
const externalConfig = getOptionalInput('config-file');
|
||||
if (externalConfig !== undefined) {
|
||||
const config = readConfigFile(externalConfig);
|
||||
// the reasoning behind reading the inline config when an external
|
||||
// config file is provided is that we still want to allow users to
|
||||
// pass inline options in the presence of an external config file.
|
||||
const inlineConfig = readInlineConfig();
|
||||
// the external config takes precedence
|
||||
return Object.assign({}, inlineConfig, config);
|
||||
}
|
||||
else {
|
||||
return readInlineConfig();
|
||||
}
|
||||
}
|
||||
function parseConfigFile(configData) {
|
||||
exports.readConfig = readConfig;
|
||||
function readInlineConfig() {
|
||||
const fail_on_severity = schemas_1.SeveritySchema.parse(getOptionalInput('fail-on-severity'));
|
||||
const fail_on_scopes = z
|
||||
.array(z.enum(schemas_1.SCOPES))
|
||||
.default(['runtime'])
|
||||
.parse(parseList(getOptionalInput('fail-on-scopes')));
|
||||
const allow_licenses = parseList(getOptionalInput('allow-licenses'));
|
||||
const deny_licenses = parseList(getOptionalInput('deny-licenses'));
|
||||
if (allow_licenses !== undefined && deny_licenses !== undefined) {
|
||||
throw new Error("Can't specify both allow_licenses and deny_licenses");
|
||||
}
|
||||
validateLicenses('allow-licenses', allow_licenses);
|
||||
validateLicenses('deny-licenses', deny_licenses);
|
||||
const allow_ghsas = parseList(getOptionalInput('allow-ghsas'));
|
||||
const license_check = z
|
||||
.boolean()
|
||||
.default(true)
|
||||
.parse(getOptionalBoolean('license-check'));
|
||||
const vulnerability_check = z
|
||||
.boolean()
|
||||
.default(true)
|
||||
.parse(getOptionalBoolean('vulnerability-check'));
|
||||
if (license_check === false && vulnerability_check === false) {
|
||||
throw new Error("Can't disable both license-check and vulnerability-check");
|
||||
}
|
||||
const base_ref = getOptionalInput('base-ref');
|
||||
const head_ref = getOptionalInput('head-ref');
|
||||
return {
|
||||
fail_on_severity,
|
||||
fail_on_scopes,
|
||||
allow_licenses,
|
||||
deny_licenses,
|
||||
allow_ghsas,
|
||||
license_check,
|
||||
vulnerability_check,
|
||||
base_ref,
|
||||
head_ref
|
||||
};
|
||||
}
|
||||
exports.readInlineConfig = readInlineConfig;
|
||||
function readConfigFile(filePath) {
|
||||
let data;
|
||||
try {
|
||||
const data = yaml_1.default.parse(configData);
|
||||
for (const key of Object.keys(data)) {
|
||||
if (key === 'allow-licenses' || key === 'deny-licenses') {
|
||||
validateLicenses(key, data[key]);
|
||||
}
|
||||
// get rid of the ugly dashes from the actions conventions
|
||||
if (key.includes('-')) {
|
||||
data[key.replace(/-/g, '_')] = data[key];
|
||||
delete data[key];
|
||||
}
|
||||
}
|
||||
return data;
|
||||
data = fs.readFileSync(path_1.default.resolve(filePath), 'utf-8');
|
||||
}
|
||||
catch (error) {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
function getRemoteConfig(configOpts) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
try {
|
||||
const { data } = yield (0, utils_1.octokitClient)('external-repo-token', false).rest.repos.getContent({
|
||||
mediaType: {
|
||||
format: 'raw'
|
||||
},
|
||||
owner: configOpts.owner,
|
||||
repo: configOpts.repo,
|
||||
path: configOpts.path,
|
||||
ref: configOpts.ref
|
||||
});
|
||||
// When using mediaType.format = 'raw', the response.data is a string
|
||||
// but this is not reflected in the return type of getContent, so we're
|
||||
// casting the return value to a string.
|
||||
return z.string().parse(data);
|
||||
data = yaml_1.default.parse(data);
|
||||
for (const key of Object.keys(data)) {
|
||||
if (key === 'allow-licenses' || key === 'deny-licenses') {
|
||||
validateLicenses(key, data[key]);
|
||||
}
|
||||
catch (error) {
|
||||
core.debug(error);
|
||||
throw new Error('Error fetching remote config file');
|
||||
// get rid of the ugly dashes from the actions conventions
|
||||
if (key.includes('-')) {
|
||||
data[key.replace(/-/g, '_')] = data[key];
|
||||
delete data[key];
|
||||
}
|
||||
});
|
||||
}
|
||||
const values = schemas_1.ConfigurationOptionsSchema.parse(data);
|
||||
return values;
|
||||
}
|
||||
exports.readConfigFile = readConfigFile;
|
||||
|
||||
|
||||
/***/ }),
|
||||
@@ -27723,36 +27658,17 @@ exports.ConfigurationOptionsSchema = z
|
||||
.object({
|
||||
fail_on_severity: exports.SeveritySchema,
|
||||
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(),
|
||||
allow_licenses: z.array(z.string()).default([]),
|
||||
deny_licenses: z.array(z.string()).default([]),
|
||||
allow_ghsas: z.array(z.string()).default([]),
|
||||
license_check: z.boolean().default(true),
|
||||
vulnerability_check: z.boolean().default(true),
|
||||
config_file: z.string().optional(),
|
||||
base_ref: z.string().optional(),
|
||||
head_ref: z.string().optional()
|
||||
config_file: z.string().optional().default('false'),
|
||||
base_ref: z.string(),
|
||||
head_ref: z.string()
|
||||
})
|
||||
.superRefine((config, context) => {
|
||||
if (config.allow_licenses && config.deny_licenses) {
|
||||
context.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
message: 'You cannot specify both allow-licenses and deny-licenses'
|
||||
});
|
||||
}
|
||||
if (config.allow_licenses && config.allow_licenses.length < 1) {
|
||||
context.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
message: 'You should provide at least one license in allow-licenses'
|
||||
});
|
||||
}
|
||||
if (config.license_check === false &&
|
||||
config.vulnerability_check === false) {
|
||||
context.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
message: "Can't disable both license-check and vulnerability-check"
|
||||
});
|
||||
}
|
||||
});
|
||||
.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.');
|
||||
exports.ChangesSchema = z.array(exports.ChangeSchema);
|
||||
|
||||
|
||||
@@ -27763,36 +27679,11 @@ exports.ChangesSchema = z.array(exports.ChangeSchema);
|
||||
|
||||
"use strict";
|
||||
|
||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
var desc = Object.getOwnPropertyDescriptor(m, k);
|
||||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
||||
desc = { enumerable: true, get: function() { return m[k]; } };
|
||||
}
|
||||
Object.defineProperty(o, k2, desc);
|
||||
}) : (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.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
||||
__setModuleDefault(result, mod);
|
||||
return result;
|
||||
};
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||
exports.octokitClient = exports.isSPDXValid = exports.renderUrl = exports.getManifestsSet = exports.groupDependenciesByManifest = void 0;
|
||||
const core = __importStar(__nccwpck_require__(2186));
|
||||
const octokit_1 = __nccwpck_require__(7467);
|
||||
exports.isSPDXValid = exports.renderUrl = exports.getManifestsSet = exports.groupDependenciesByManifest = void 0;
|
||||
const spdx_expression_parse_1 = __importDefault(__nccwpck_require__(1620));
|
||||
function groupDependenciesByManifest(changes) {
|
||||
var _a;
|
||||
@@ -27830,17 +27721,6 @@ function isSPDXValid(license) {
|
||||
}
|
||||
}
|
||||
exports.isSPDXValid = isSPDXValid;
|
||||
function octokitClient(token = 'repo-token', required = true) {
|
||||
const opts = {};
|
||||
// auth is only added if token is present. For remote config files in public
|
||||
// repos the token is optional, so it could be undefined.
|
||||
const auth = core.getInput(token, { required });
|
||||
if (auth !== undefined) {
|
||||
opts['auth'] = auth;
|
||||
}
|
||||
return new octokit_1.Octokit(opts);
|
||||
}
|
||||
exports.octokitClient = octokitClient;
|
||||
|
||||
|
||||
/***/ }),
|
||||
|
||||
+1
-1
File diff suppressed because one or more lines are too long
Generated
+89
-103
@@ -24,11 +24,11 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/jest": "^27.5.2",
|
||||
"@types/node": "^16.18.3",
|
||||
"@types/spdx-expression-parse": "^3.0.2",
|
||||
"@types/spdx-satisfies": "^0.1.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.42.0",
|
||||
"@typescript-eslint/parser": "^5.42.0",
|
||||
"@types/node": "^16.18.2",
|
||||
"@typescript-eslint/eslint-plugin": "^5.41.0",
|
||||
"@typescript-eslint/parser": "^5.41.0",
|
||||
"@vercel/ncc": "^0.34.0",
|
||||
"esbuild-register": "^3.3.3",
|
||||
"eslint": "^8.26.0",
|
||||
@@ -1802,9 +1802,9 @@
|
||||
"integrity": "sha512-ssE3Vlrys7sdIzs5LOxCzTVMsU7i9oa/IaW92wF32JFb3CVczqOkru2xspuKczHEbG3nvmPY7IFqVmGGHdNbYw=="
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "16.18.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.3.tgz",
|
||||
"integrity": "sha512-jh6m0QUhIRcZpNv7Z/rpN+ZWXOicUUQbSoWks7Htkbb9IjFQj4kzcX/xFCkjstCj5flMsN8FiSvt+q+Tcs4Llg=="
|
||||
"version": "16.18.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.2.tgz",
|
||||
"integrity": "sha512-KIGQJyya+opDCFvDSZMNNS899ov5jlNdtN7PypgHWeb8e+5vWISdwTRo/ClsNVlmDihzOGqFyNBDamUs7TQQCA=="
|
||||
},
|
||||
"node_modules/@types/prettier": {
|
||||
"version": "2.7.1",
|
||||
@@ -1852,17 +1852,16 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin": {
|
||||
"version": "5.42.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.42.0.tgz",
|
||||
"integrity": "sha512-5TJh2AgL6+wpL8H/GTSjNb4WrjKoR2rqvFxR/DDTqYNk6uXn8BJMEcncLSpMbf/XV1aS0jAjYwn98uvVCiAywQ==",
|
||||
"version": "5.41.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.41.0.tgz",
|
||||
"integrity": "sha512-DXUS22Y57/LAFSg3x7Vi6RNAuLpTXwxB9S2nIA7msBb/Zt8p7XqMwdpdc1IU7CkOQUPgAqR5fWvxuKCbneKGmA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/scope-manager": "5.42.0",
|
||||
"@typescript-eslint/type-utils": "5.42.0",
|
||||
"@typescript-eslint/utils": "5.42.0",
|
||||
"@typescript-eslint/scope-manager": "5.41.0",
|
||||
"@typescript-eslint/type-utils": "5.41.0",
|
||||
"@typescript-eslint/utils": "5.41.0",
|
||||
"debug": "^4.3.4",
|
||||
"ignore": "^5.2.0",
|
||||
"natural-compare-lite": "^1.4.0",
|
||||
"regexpp": "^3.2.0",
|
||||
"semver": "^7.3.7",
|
||||
"tsutils": "^3.21.0"
|
||||
@@ -1885,14 +1884,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/parser": {
|
||||
"version": "5.42.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.42.0.tgz",
|
||||
"integrity": "sha512-Ixh9qrOTDRctFg3yIwrLkgf33AHyEIn6lhyf5cCfwwiGtkWhNpVKlEZApi3inGQR/barWnY7qY8FbGKBO7p3JA==",
|
||||
"version": "5.41.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.41.0.tgz",
|
||||
"integrity": "sha512-HQVfix4+RL5YRWZboMD1pUfFN8MpRH4laziWkkAzyO1fvNOY/uinZcvo3QiFJVS/siNHupV8E5+xSwQZrl6PZA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/scope-manager": "5.42.0",
|
||||
"@typescript-eslint/types": "5.42.0",
|
||||
"@typescript-eslint/typescript-estree": "5.42.0",
|
||||
"@typescript-eslint/scope-manager": "5.41.0",
|
||||
"@typescript-eslint/types": "5.41.0",
|
||||
"@typescript-eslint/typescript-estree": "5.41.0",
|
||||
"debug": "^4.3.4"
|
||||
},
|
||||
"engines": {
|
||||
@@ -1912,13 +1911,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/scope-manager": {
|
||||
"version": "5.42.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.42.0.tgz",
|
||||
"integrity": "sha512-l5/3IBHLH0Bv04y+H+zlcLiEMEMjWGaCX6WyHE5Uk2YkSGAMlgdUPsT/ywTSKgu9D1dmmKMYgYZijObfA39Wow==",
|
||||
"version": "5.41.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.41.0.tgz",
|
||||
"integrity": "sha512-xOxPJCnuktUkY2xoEZBKXO5DBCugFzjrVndKdUnyQr3+9aDWZReKq9MhaoVnbL+maVwWJu/N0SEtrtEUNb62QQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "5.42.0",
|
||||
"@typescript-eslint/visitor-keys": "5.42.0"
|
||||
"@typescript-eslint/types": "5.41.0",
|
||||
"@typescript-eslint/visitor-keys": "5.41.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||
@@ -1929,13 +1928,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/type-utils": {
|
||||
"version": "5.42.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.42.0.tgz",
|
||||
"integrity": "sha512-HW14TXC45dFVZxnVW8rnUGnvYyRC0E/vxXShFCthcC9VhVTmjqOmtqj6H5rm9Zxv+ORxKA/1aLGD7vmlLsdlOg==",
|
||||
"version": "5.41.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.41.0.tgz",
|
||||
"integrity": "sha512-L30HNvIG6A1Q0R58e4hu4h+fZqaO909UcnnPbwKiN6Rc3BUEx6ez2wgN7aC0cBfcAjZfwkzE+E2PQQ9nEuoqfA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/typescript-estree": "5.42.0",
|
||||
"@typescript-eslint/utils": "5.42.0",
|
||||
"@typescript-eslint/typescript-estree": "5.41.0",
|
||||
"@typescript-eslint/utils": "5.41.0",
|
||||
"debug": "^4.3.4",
|
||||
"tsutils": "^3.21.0"
|
||||
},
|
||||
@@ -1956,9 +1955,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/types": {
|
||||
"version": "5.42.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.42.0.tgz",
|
||||
"integrity": "sha512-t4lzO9ZOAUcHY6bXQYRuu+3SSYdD9TS8ooApZft4WARt4/f2Cj/YpvbTe8A4GuhT4bNW72goDMOy7SW71mZwGw==",
|
||||
"version": "5.41.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.41.0.tgz",
|
||||
"integrity": "sha512-5BejraMXMC+2UjefDvrH0Fo/eLwZRV6859SXRg+FgbhA0R0l6lDqDGAQYhKbXhPN2ofk2kY5sgGyLNL907UXpA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||
@@ -1969,13 +1968,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/typescript-estree": {
|
||||
"version": "5.42.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.42.0.tgz",
|
||||
"integrity": "sha512-2O3vSq794x3kZGtV7i4SCWZWCwjEtkWfVqX4m5fbUBomOsEOyd6OAD1qU2lbvV5S8tgy/luJnOYluNyYVeOTTg==",
|
||||
"version": "5.41.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.41.0.tgz",
|
||||
"integrity": "sha512-SlzFYRwFSvswzDSQ/zPkIWcHv8O5y42YUskko9c4ki+fV6HATsTODUPbRbcGDFYP86gaJL5xohUEytvyNNcXWg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "5.42.0",
|
||||
"@typescript-eslint/visitor-keys": "5.42.0",
|
||||
"@typescript-eslint/types": "5.41.0",
|
||||
"@typescript-eslint/visitor-keys": "5.41.0",
|
||||
"debug": "^4.3.4",
|
||||
"globby": "^11.1.0",
|
||||
"is-glob": "^4.0.3",
|
||||
@@ -1996,16 +1995,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/utils": {
|
||||
"version": "5.42.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.42.0.tgz",
|
||||
"integrity": "sha512-JZ++3+h1vbeG1NUECXQZE3hg0kias9kOtcQr3+JVQ3whnjvKuMyktJAAIj6743OeNPnGBmjj7KEmiDL7qsdnCQ==",
|
||||
"version": "5.41.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.41.0.tgz",
|
||||
"integrity": "sha512-QlvfwaN9jaMga9EBazQ+5DDx/4sAdqDkcs05AsQHMaopluVCUyu1bTRUVKzXbgjDlrRAQrYVoi/sXJ9fmG+KLQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/json-schema": "^7.0.9",
|
||||
"@types/semver": "^7.3.12",
|
||||
"@typescript-eslint/scope-manager": "5.42.0",
|
||||
"@typescript-eslint/types": "5.42.0",
|
||||
"@typescript-eslint/typescript-estree": "5.42.0",
|
||||
"@typescript-eslint/scope-manager": "5.41.0",
|
||||
"@typescript-eslint/types": "5.41.0",
|
||||
"@typescript-eslint/typescript-estree": "5.41.0",
|
||||
"eslint-scope": "^5.1.1",
|
||||
"eslint-utils": "^3.0.0",
|
||||
"semver": "^7.3.7"
|
||||
@@ -2022,12 +2021,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/visitor-keys": {
|
||||
"version": "5.42.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.42.0.tgz",
|
||||
"integrity": "sha512-QHbu5Hf/2lOEOwy+IUw0GoSCuAzByTAWWrOTKzTzsotiUnWFpuKnXcAhC9YztAf2EElQ0VvIK+pHJUPkM0q7jg==",
|
||||
"version": "5.41.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.41.0.tgz",
|
||||
"integrity": "sha512-vilqeHj267v8uzzakbm13HkPMl7cbYpKVjgFWZPIOHIJHZtinvypUhJ5xBXfWYg4eFKqztbMMpOgFpT9Gfx4fw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "5.42.0",
|
||||
"@typescript-eslint/types": "5.41.0",
|
||||
"eslint-visitor-keys": "^3.3.0"
|
||||
},
|
||||
"engines": {
|
||||
@@ -6278,12 +6277,6 @@
|
||||
"integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/natural-compare-lite": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz",
|
||||
"integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/node-fetch": {
|
||||
"version": "2.6.7",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
|
||||
@@ -9599,9 +9592,9 @@
|
||||
"integrity": "sha512-ssE3Vlrys7sdIzs5LOxCzTVMsU7i9oa/IaW92wF32JFb3CVczqOkru2xspuKczHEbG3nvmPY7IFqVmGGHdNbYw=="
|
||||
},
|
||||
"@types/node": {
|
||||
"version": "16.18.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.3.tgz",
|
||||
"integrity": "sha512-jh6m0QUhIRcZpNv7Z/rpN+ZWXOicUUQbSoWks7Htkbb9IjFQj4kzcX/xFCkjstCj5flMsN8FiSvt+q+Tcs4Llg=="
|
||||
"version": "16.18.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.2.tgz",
|
||||
"integrity": "sha512-KIGQJyya+opDCFvDSZMNNS899ov5jlNdtN7PypgHWeb8e+5vWISdwTRo/ClsNVlmDihzOGqFyNBDamUs7TQQCA=="
|
||||
},
|
||||
"@types/prettier": {
|
||||
"version": "2.7.1",
|
||||
@@ -9649,70 +9642,69 @@
|
||||
"dev": true
|
||||
},
|
||||
"@typescript-eslint/eslint-plugin": {
|
||||
"version": "5.42.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.42.0.tgz",
|
||||
"integrity": "sha512-5TJh2AgL6+wpL8H/GTSjNb4WrjKoR2rqvFxR/DDTqYNk6uXn8BJMEcncLSpMbf/XV1aS0jAjYwn98uvVCiAywQ==",
|
||||
"version": "5.41.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.41.0.tgz",
|
||||
"integrity": "sha512-DXUS22Y57/LAFSg3x7Vi6RNAuLpTXwxB9S2nIA7msBb/Zt8p7XqMwdpdc1IU7CkOQUPgAqR5fWvxuKCbneKGmA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/scope-manager": "5.42.0",
|
||||
"@typescript-eslint/type-utils": "5.42.0",
|
||||
"@typescript-eslint/utils": "5.42.0",
|
||||
"@typescript-eslint/scope-manager": "5.41.0",
|
||||
"@typescript-eslint/type-utils": "5.41.0",
|
||||
"@typescript-eslint/utils": "5.41.0",
|
||||
"debug": "^4.3.4",
|
||||
"ignore": "^5.2.0",
|
||||
"natural-compare-lite": "^1.4.0",
|
||||
"regexpp": "^3.2.0",
|
||||
"semver": "^7.3.7",
|
||||
"tsutils": "^3.21.0"
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/parser": {
|
||||
"version": "5.42.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.42.0.tgz",
|
||||
"integrity": "sha512-Ixh9qrOTDRctFg3yIwrLkgf33AHyEIn6lhyf5cCfwwiGtkWhNpVKlEZApi3inGQR/barWnY7qY8FbGKBO7p3JA==",
|
||||
"version": "5.41.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.41.0.tgz",
|
||||
"integrity": "sha512-HQVfix4+RL5YRWZboMD1pUfFN8MpRH4laziWkkAzyO1fvNOY/uinZcvo3QiFJVS/siNHupV8E5+xSwQZrl6PZA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/scope-manager": "5.42.0",
|
||||
"@typescript-eslint/types": "5.42.0",
|
||||
"@typescript-eslint/typescript-estree": "5.42.0",
|
||||
"@typescript-eslint/scope-manager": "5.41.0",
|
||||
"@typescript-eslint/types": "5.41.0",
|
||||
"@typescript-eslint/typescript-estree": "5.41.0",
|
||||
"debug": "^4.3.4"
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/scope-manager": {
|
||||
"version": "5.42.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.42.0.tgz",
|
||||
"integrity": "sha512-l5/3IBHLH0Bv04y+H+zlcLiEMEMjWGaCX6WyHE5Uk2YkSGAMlgdUPsT/ywTSKgu9D1dmmKMYgYZijObfA39Wow==",
|
||||
"version": "5.41.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.41.0.tgz",
|
||||
"integrity": "sha512-xOxPJCnuktUkY2xoEZBKXO5DBCugFzjrVndKdUnyQr3+9aDWZReKq9MhaoVnbL+maVwWJu/N0SEtrtEUNb62QQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/types": "5.42.0",
|
||||
"@typescript-eslint/visitor-keys": "5.42.0"
|
||||
"@typescript-eslint/types": "5.41.0",
|
||||
"@typescript-eslint/visitor-keys": "5.41.0"
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/type-utils": {
|
||||
"version": "5.42.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.42.0.tgz",
|
||||
"integrity": "sha512-HW14TXC45dFVZxnVW8rnUGnvYyRC0E/vxXShFCthcC9VhVTmjqOmtqj6H5rm9Zxv+ORxKA/1aLGD7vmlLsdlOg==",
|
||||
"version": "5.41.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.41.0.tgz",
|
||||
"integrity": "sha512-L30HNvIG6A1Q0R58e4hu4h+fZqaO909UcnnPbwKiN6Rc3BUEx6ez2wgN7aC0cBfcAjZfwkzE+E2PQQ9nEuoqfA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/typescript-estree": "5.42.0",
|
||||
"@typescript-eslint/utils": "5.42.0",
|
||||
"@typescript-eslint/typescript-estree": "5.41.0",
|
||||
"@typescript-eslint/utils": "5.41.0",
|
||||
"debug": "^4.3.4",
|
||||
"tsutils": "^3.21.0"
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/types": {
|
||||
"version": "5.42.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.42.0.tgz",
|
||||
"integrity": "sha512-t4lzO9ZOAUcHY6bXQYRuu+3SSYdD9TS8ooApZft4WARt4/f2Cj/YpvbTe8A4GuhT4bNW72goDMOy7SW71mZwGw==",
|
||||
"version": "5.41.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.41.0.tgz",
|
||||
"integrity": "sha512-5BejraMXMC+2UjefDvrH0Fo/eLwZRV6859SXRg+FgbhA0R0l6lDqDGAQYhKbXhPN2ofk2kY5sgGyLNL907UXpA==",
|
||||
"dev": true
|
||||
},
|
||||
"@typescript-eslint/typescript-estree": {
|
||||
"version": "5.42.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.42.0.tgz",
|
||||
"integrity": "sha512-2O3vSq794x3kZGtV7i4SCWZWCwjEtkWfVqX4m5fbUBomOsEOyd6OAD1qU2lbvV5S8tgy/luJnOYluNyYVeOTTg==",
|
||||
"version": "5.41.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.41.0.tgz",
|
||||
"integrity": "sha512-SlzFYRwFSvswzDSQ/zPkIWcHv8O5y42YUskko9c4ki+fV6HATsTODUPbRbcGDFYP86gaJL5xohUEytvyNNcXWg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/types": "5.42.0",
|
||||
"@typescript-eslint/visitor-keys": "5.42.0",
|
||||
"@typescript-eslint/types": "5.41.0",
|
||||
"@typescript-eslint/visitor-keys": "5.41.0",
|
||||
"debug": "^4.3.4",
|
||||
"globby": "^11.1.0",
|
||||
"is-glob": "^4.0.3",
|
||||
@@ -9721,28 +9713,28 @@
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/utils": {
|
||||
"version": "5.42.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.42.0.tgz",
|
||||
"integrity": "sha512-JZ++3+h1vbeG1NUECXQZE3hg0kias9kOtcQr3+JVQ3whnjvKuMyktJAAIj6743OeNPnGBmjj7KEmiDL7qsdnCQ==",
|
||||
"version": "5.41.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.41.0.tgz",
|
||||
"integrity": "sha512-QlvfwaN9jaMga9EBazQ+5DDx/4sAdqDkcs05AsQHMaopluVCUyu1bTRUVKzXbgjDlrRAQrYVoi/sXJ9fmG+KLQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/json-schema": "^7.0.9",
|
||||
"@types/semver": "^7.3.12",
|
||||
"@typescript-eslint/scope-manager": "5.42.0",
|
||||
"@typescript-eslint/types": "5.42.0",
|
||||
"@typescript-eslint/typescript-estree": "5.42.0",
|
||||
"@typescript-eslint/scope-manager": "5.41.0",
|
||||
"@typescript-eslint/types": "5.41.0",
|
||||
"@typescript-eslint/typescript-estree": "5.41.0",
|
||||
"eslint-scope": "^5.1.1",
|
||||
"eslint-utils": "^3.0.0",
|
||||
"semver": "^7.3.7"
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/visitor-keys": {
|
||||
"version": "5.42.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.42.0.tgz",
|
||||
"integrity": "sha512-QHbu5Hf/2lOEOwy+IUw0GoSCuAzByTAWWrOTKzTzsotiUnWFpuKnXcAhC9YztAf2EElQ0VvIK+pHJUPkM0q7jg==",
|
||||
"version": "5.41.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.41.0.tgz",
|
||||
"integrity": "sha512-vilqeHj267v8uzzakbm13HkPMl7cbYpKVjgFWZPIOHIJHZtinvypUhJ5xBXfWYg4eFKqztbMMpOgFpT9Gfx4fw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/types": "5.42.0",
|
||||
"@typescript-eslint/types": "5.41.0",
|
||||
"eslint-visitor-keys": "^3.3.0"
|
||||
}
|
||||
},
|
||||
@@ -12849,12 +12841,6 @@
|
||||
"integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
|
||||
"dev": true
|
||||
},
|
||||
"natural-compare-lite": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz",
|
||||
"integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==",
|
||||
"dev": true
|
||||
},
|
||||
"node-fetch": {
|
||||
"version": "2.6.7",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
|
||||
|
||||
+3
-3
@@ -40,9 +40,9 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/jest": "^27.5.2",
|
||||
"@types/node": "^16.18.3",
|
||||
"@typescript-eslint/eslint-plugin": "^5.42.0",
|
||||
"@typescript-eslint/parser": "^5.42.0",
|
||||
"@types/node": "^16.18.2",
|
||||
"@typescript-eslint/eslint-plugin": "^5.41.0",
|
||||
"@typescript-eslint/parser": "^5.41.0",
|
||||
"@types/spdx-expression-parse": "^3.0.2",
|
||||
"@types/spdx-satisfies": "^0.1.0",
|
||||
"@vercel/ncc": "^0.34.0",
|
||||
|
||||
+86
-116
@@ -3,57 +3,15 @@ import path from 'path'
|
||||
import YAML from 'yaml'
|
||||
import * as core from '@actions/core'
|
||||
import * as z from 'zod'
|
||||
import {ConfigurationOptions, ConfigurationOptionsSchema} from './schemas'
|
||||
import {isSPDXValid, octokitClient} from './utils'
|
||||
import {
|
||||
ConfigurationOptions,
|
||||
ConfigurationOptionsSchema,
|
||||
SeveritySchema,
|
||||
SCOPES
|
||||
} from './schemas'
|
||||
import {isSPDXValid} from './utils'
|
||||
|
||||
type ConfigurationOptionsPartial = Partial<ConfigurationOptions>
|
||||
|
||||
export async function readConfig(): Promise<ConfigurationOptions> {
|
||||
const inlineConfig = readInlineConfig()
|
||||
|
||||
const configFile = getOptionalInput('config-file')
|
||||
if (configFile !== undefined) {
|
||||
const externalConfig = await readConfigFile(configFile)
|
||||
|
||||
return ConfigurationOptionsSchema.parse({
|
||||
...externalConfig,
|
||||
...inlineConfig
|
||||
})
|
||||
}
|
||||
|
||||
return ConfigurationOptionsSchema.parse(inlineConfig)
|
||||
}
|
||||
|
||||
function readInlineConfig(): ConfigurationOptionsPartial {
|
||||
const fail_on_severity = getOptionalInput('fail-on-severity')
|
||||
const fail_on_scopes = parseList(getOptionalInput('fail-on-scopes'))
|
||||
const allow_licenses = parseList(getOptionalInput('allow-licenses'))
|
||||
const deny_licenses = parseList(getOptionalInput('deny-licenses'))
|
||||
const allow_ghsas = parseList(getOptionalInput('allow-ghsas'))
|
||||
const license_check = getOptionalBoolean('license-check')
|
||||
const vulnerability_check = getOptionalBoolean('vulnerability-check')
|
||||
const base_ref = getOptionalInput('base-ref')
|
||||
const head_ref = getOptionalInput('head-ref')
|
||||
|
||||
validateLicenses('allow-licenses', allow_licenses)
|
||||
validateLicenses('deny-licenses', deny_licenses)
|
||||
|
||||
const keys = {
|
||||
fail_on_severity,
|
||||
fail_on_scopes,
|
||||
allow_licenses,
|
||||
deny_licenses,
|
||||
allow_ghsas,
|
||||
license_check,
|
||||
vulnerability_check,
|
||||
base_ref,
|
||||
head_ref
|
||||
}
|
||||
|
||||
return Object.fromEntries(
|
||||
Object.entries(keys).filter(([_, value]) => value !== undefined)
|
||||
)
|
||||
}
|
||||
type licenseKey = 'allow-licenses' | 'deny-licenses'
|
||||
|
||||
function getOptionalBoolean(name: string): boolean | undefined {
|
||||
const value = core.getInput(name)
|
||||
@@ -74,7 +32,7 @@ function parseList(list: string | undefined): string[] | undefined {
|
||||
}
|
||||
|
||||
function validateLicenses(
|
||||
key: 'allow-licenses' | 'deny-licenses',
|
||||
key: licenseKey,
|
||||
licenses: string[] | undefined
|
||||
): void {
|
||||
if (licenses === undefined) {
|
||||
@@ -89,77 +47,89 @@ function validateLicenses(
|
||||
}
|
||||
}
|
||||
|
||||
async function readConfigFile(
|
||||
filePath: string
|
||||
): Promise<ConfigurationOptionsPartial> {
|
||||
// match a remote config (e.g. 'owner/repo/filepath@someref')
|
||||
const format = new RegExp(
|
||||
'(?<owner>[^/]+)/(?<repo>[^/]+)/(?<path>[^@]+)@(?<ref>.*)'
|
||||
)
|
||||
|
||||
let data: string
|
||||
const pieces = format.exec(filePath)
|
||||
|
||||
try {
|
||||
if (pieces?.groups && pieces.length === 5) {
|
||||
data = await getRemoteConfig({
|
||||
owner: pieces.groups.owner,
|
||||
repo: pieces.groups.repo,
|
||||
path: pieces.groups.path,
|
||||
ref: pieces.groups.ref
|
||||
})
|
||||
} else {
|
||||
data = fs.readFileSync(path.resolve(filePath), 'utf-8')
|
||||
}
|
||||
return parseConfigFile(data)
|
||||
} catch (error) {
|
||||
core.debug(error as string)
|
||||
throw new Error('Unable to fetch config file')
|
||||
export function readConfig(): ConfigurationOptions {
|
||||
const externalConfig = getOptionalInput('config-file')
|
||||
if (externalConfig !== undefined) {
|
||||
const config = readConfigFile(externalConfig)
|
||||
// the reasoning behind reading the inline config when an external
|
||||
// config file is provided is that we still want to allow users to
|
||||
// pass inline options in the presence of an external config file.
|
||||
const inlineConfig = readInlineConfig()
|
||||
// the external config takes precedence
|
||||
return Object.assign({}, inlineConfig, config)
|
||||
} else {
|
||||
return readInlineConfig()
|
||||
}
|
||||
}
|
||||
|
||||
function parseConfigFile(configData: string): ConfigurationOptionsPartial {
|
||||
export function readInlineConfig(): ConfigurationOptions {
|
||||
const fail_on_severity = SeveritySchema.parse(
|
||||
getOptionalInput('fail-on-severity')
|
||||
)
|
||||
const fail_on_scopes = z
|
||||
.array(z.enum(SCOPES))
|
||||
.default(['runtime'])
|
||||
.parse(parseList(getOptionalInput('fail-on-scopes')))
|
||||
|
||||
const allow_licenses = parseList(getOptionalInput('allow-licenses'))
|
||||
const deny_licenses = parseList(getOptionalInput('deny-licenses'))
|
||||
|
||||
if (allow_licenses !== undefined && deny_licenses !== undefined) {
|
||||
throw new Error("Can't specify both allow_licenses and deny_licenses")
|
||||
}
|
||||
validateLicenses('allow-licenses', allow_licenses)
|
||||
validateLicenses('deny-licenses', deny_licenses)
|
||||
|
||||
const allow_ghsas = parseList(getOptionalInput('allow-ghsas'))
|
||||
|
||||
const license_check = z
|
||||
.boolean()
|
||||
.default(true)
|
||||
.parse(getOptionalBoolean('license-check'))
|
||||
const vulnerability_check = z
|
||||
.boolean()
|
||||
.default(true)
|
||||
.parse(getOptionalBoolean('vulnerability-check'))
|
||||
if (license_check === false && vulnerability_check === false) {
|
||||
throw new Error("Can't disable both license-check and vulnerability-check")
|
||||
}
|
||||
|
||||
const base_ref = getOptionalInput('base-ref')
|
||||
const head_ref = getOptionalInput('head-ref')
|
||||
|
||||
return {
|
||||
fail_on_severity,
|
||||
fail_on_scopes,
|
||||
allow_licenses,
|
||||
deny_licenses,
|
||||
allow_ghsas,
|
||||
license_check,
|
||||
vulnerability_check,
|
||||
base_ref,
|
||||
head_ref
|
||||
}
|
||||
}
|
||||
|
||||
export function readConfigFile(filePath: string): ConfigurationOptions {
|
||||
let data
|
||||
|
||||
try {
|
||||
const data = YAML.parse(configData)
|
||||
for (const key of Object.keys(data)) {
|
||||
if (key === 'allow-licenses' || key === 'deny-licenses') {
|
||||
validateLicenses(key, data[key])
|
||||
}
|
||||
// get rid of the ugly dashes from the actions conventions
|
||||
if (key.includes('-')) {
|
||||
data[key.replace(/-/g, '_')] = data[key]
|
||||
delete data[key]
|
||||
}
|
||||
}
|
||||
return data
|
||||
} catch (error) {
|
||||
data = fs.readFileSync(path.resolve(filePath), 'utf-8')
|
||||
} catch (error: unknown) {
|
||||
throw error
|
||||
}
|
||||
}
|
||||
data = YAML.parse(data)
|
||||
|
||||
async function getRemoteConfig(configOpts: {
|
||||
[key: string]: string
|
||||
}): Promise<string> {
|
||||
try {
|
||||
const {data} = await octokitClient(
|
||||
'external-repo-token',
|
||||
false
|
||||
).rest.repos.getContent({
|
||||
mediaType: {
|
||||
format: 'raw'
|
||||
},
|
||||
owner: configOpts.owner,
|
||||
repo: configOpts.repo,
|
||||
path: configOpts.path,
|
||||
ref: configOpts.ref
|
||||
})
|
||||
|
||||
// When using mediaType.format = 'raw', the response.data is a string
|
||||
// but this is not reflected in the return type of getContent, so we're
|
||||
// casting the return value to a string.
|
||||
return z.string().parse(data as unknown)
|
||||
} catch (error) {
|
||||
core.debug(error as string)
|
||||
throw new Error('Error fetching remote config file')
|
||||
for (const key of Object.keys(data)) {
|
||||
if (key === 'allow-licenses' || key === 'deny-licenses') {
|
||||
validateLicenses(key, data[key])
|
||||
}
|
||||
// get rid of the ugly dashes from the actions conventions
|
||||
if (key.includes('-')) {
|
||||
data[key.replace(/-/g, '_')] = data[key]
|
||||
delete data[key]
|
||||
}
|
||||
}
|
||||
const values = ConfigurationOptionsSchema.parse(data)
|
||||
return values
|
||||
}
|
||||
|
||||
+8
-5
@@ -1,6 +1,8 @@
|
||||
import * as core from '@actions/core'
|
||||
import spdxSatisfies from 'spdx-satisfies'
|
||||
import {Octokit} from 'octokit'
|
||||
import {Change, Changes} from './schemas'
|
||||
import {isSPDXValid, octokitClient} from './utils'
|
||||
import {isSPDXValid} from './utils'
|
||||
|
||||
/**
|
||||
* Loops through a list of changes, filtering and returning the
|
||||
@@ -74,11 +76,12 @@ const fetchGHLicense = async (
|
||||
owner: string,
|
||||
repo: string
|
||||
): Promise<string | null> => {
|
||||
const octokit = new Octokit({
|
||||
auth: core.getInput('repo-token', {required: true})
|
||||
})
|
||||
|
||||
try {
|
||||
const response = await octokitClient().rest.licenses.getForRepo({
|
||||
owner,
|
||||
repo
|
||||
})
|
||||
const response = await octokit.rest.licenses.getForRepo({owner, repo})
|
||||
return response.data.license?.spdx_id ?? null
|
||||
} catch (_) {
|
||||
return null
|
||||
|
||||
+2
-2
@@ -18,7 +18,7 @@ import {groupDependenciesByManifest} from './utils'
|
||||
|
||||
async function run(): Promise<void> {
|
||||
try {
|
||||
const config = await readConfig()
|
||||
const config = readConfig()
|
||||
const refs = getRefs(config, github.context)
|
||||
|
||||
const changes = await dependencyGraph.compare({
|
||||
@@ -28,7 +28,7 @@ async function run(): Promise<void> {
|
||||
headRef: refs.head
|
||||
})
|
||||
|
||||
const minSeverity = config.fail_on_severity
|
||||
const minSeverity = config.fail_on_severity as Severity
|
||||
const scopedChanges = filterChangesByScopes(config.fail_on_scopes, changes)
|
||||
const filteredChanges = filterAllowedAdvisories(
|
||||
config.allow_ghsas,
|
||||
|
||||
+10
-28
@@ -38,38 +38,20 @@ export const ConfigurationOptionsSchema = z
|
||||
.object({
|
||||
fail_on_severity: SeveritySchema,
|
||||
fail_on_scopes: z.array(z.enum(SCOPES)).default(['runtime']),
|
||||
allow_licenses: z.array(z.string()).optional(),
|
||||
deny_licenses: z.array(z.string()).optional(),
|
||||
allow_licenses: z.array(z.string()).default([]),
|
||||
deny_licenses: z.array(z.string()).default([]),
|
||||
allow_ghsas: z.array(z.string()).default([]),
|
||||
license_check: z.boolean().default(true),
|
||||
vulnerability_check: z.boolean().default(true),
|
||||
config_file: z.string().optional(),
|
||||
base_ref: z.string().optional(),
|
||||
head_ref: z.string().optional()
|
||||
})
|
||||
.superRefine((config, context) => {
|
||||
if (config.allow_licenses && config.deny_licenses) {
|
||||
context.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
message: 'You cannot specify both allow-licenses and deny-licenses'
|
||||
})
|
||||
}
|
||||
if (config.allow_licenses && config.allow_licenses.length < 1) {
|
||||
context.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
message: 'You should provide at least one license in allow-licenses'
|
||||
})
|
||||
}
|
||||
if (
|
||||
config.license_check === false &&
|
||||
config.vulnerability_check === false
|
||||
) {
|
||||
context.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
message: "Can't disable both license-check and vulnerability-check"
|
||||
})
|
||||
}
|
||||
config_file: z.string().optional().default('false'),
|
||||
base_ref: z.string(),
|
||||
head_ref: z.string()
|
||||
})
|
||||
.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.'
|
||||
)
|
||||
|
||||
export const ChangesSchema = z.array(ChangeSchema)
|
||||
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import * as core from '@actions/core'
|
||||
import {Octokit} from 'octokit'
|
||||
import spdxParse from 'spdx-expression-parse'
|
||||
import {Changes} from './schemas'
|
||||
|
||||
@@ -40,16 +38,3 @@ export function isSPDXValid(license: string): boolean {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
export function octokitClient(token = 'repo-token', required = true): Octokit {
|
||||
const opts: Record<string, unknown> = {}
|
||||
|
||||
// auth is only added if token is present. For remote config files in public
|
||||
// repos the token is optional, so it could be undefined.
|
||||
const auth = core.getInput(token, {required})
|
||||
if (auth !== undefined) {
|
||||
opts['auth'] = auth
|
||||
}
|
||||
|
||||
return new Octokit(opts)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user