Compare commits

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