Compare commits

...

2 Commits

Author SHA1 Message Date
Justin Holguín 51d5d2913d fix header 2023-03-22 16:26:03 +00:00
Justin Holguín 10529907c7 Add support for snapshot dependency changes 2023-03-22 15:59:17 +00:00
11 changed files with 111 additions and 19 deletions
+2 -1
View File
@@ -21,7 +21,8 @@ test('it properly catches RequestError type', async () => {
owner: 'actions', owner: 'actions',
repo: 'dependency-review-action', repo: 'dependency-review-action',
baseRef: 'refs/heads/master', baseRef: 'refs/heads/master',
headRef: 'refs/heads/master' headRef: 'refs/heads/master',
includeDependencySnapshots: false
}) })
} catch (error) { } catch (error) {
expect(error).toBeInstanceOf(RequestError) expect(error).toBeInstanceOf(RequestError)
+1
View File
@@ -21,6 +21,7 @@ const defaultConfig: ConfigurationOptions = {
license_check: true, license_check: true,
fail_on_severity: 'high', fail_on_severity: 'high',
fail_on_scopes: ['runtime'], fail_on_scopes: ['runtime'],
include_dependency_snapshots: false,
allow_ghsas: [], allow_ghsas: [],
allow_licenses: [], allow_licenses: [],
deny_licenses: [], deny_licenses: [],
+3
View File
@@ -20,6 +20,9 @@ inputs:
head-ref: head-ref:
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
include-dependency-snapshots:
description: Whether to include dependencies submitted through the Dependency Submission API in the comparison. Defaults to `false`.
required: false
config-file: config-file:
description: A path to the configuration file for the action. description: A path to the configuration file for the action.
required: false required: false
Generated Vendored
+47 -9
View File
@@ -181,15 +181,29 @@ const githubUtils = __importStar(__nccwpck_require__(3030));
const retry = __importStar(__nccwpck_require__(6298)); const retry = __importStar(__nccwpck_require__(6298));
const schemas_1 = __nccwpck_require__(8774); const schemas_1 = __nccwpck_require__(8774);
const retryingOctokit = githubUtils.GitHub.plugin(retry.retry); const retryingOctokit = githubUtils.GitHub.plugin(retry.retry);
const SnapshotWarningsHeader = 'x-github-dependency-graph-snapshot-warnings';
const octo = new retryingOctokit(githubUtils.getOctokitOptions(core.getInput('repo-token', { required: true }))); const octo = new retryingOctokit(githubUtils.getOctokitOptions(core.getInput('repo-token', { required: true })));
function compare({ owner, repo, baseRef, headRef }) { function compare({ owner, repo, baseRef, headRef, includeDependencySnapshots }) {
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
const changes = yield octo.paginate('GET /repos/{owner}/{repo}/dependency-graph/compare/{basehead}', { let snapshot_warnings = '';
const changes = yield octo.paginate({
method: 'GET',
url: '/repos/{owner}/{repo}/dependency-graph/compare/{basehead}',
owner, owner,
repo, repo,
basehead: `${baseRef}...${headRef}` basehead: `${baseRef}...${headRef}`,
includes_dependency_snapshots: includeDependencySnapshots
}, response => {
if (response.headers[SnapshotWarningsHeader] &&
typeof response.headers[SnapshotWarningsHeader] === 'string') {
snapshot_warnings = Buffer.from(response.headers[SnapshotWarningsHeader], 'base64').toString('utf-8');
}
return schemas_1.ChangesSchema.parse(response.data);
});
return schemas_1.ComparisonResponseSchema.parse({
changes,
snapshot_warnings
}); });
return schemas_1.ChangesSchema.parse(changes);
}); });
} }
exports.compare = compare; exports.compare = compare;
@@ -452,12 +466,15 @@ function run() {
try { try {
const config = yield (0, config_1.readConfig)(); const config = yield (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 comparison = yield dependencyGraph.compare({
owner: github.context.repo.owner, owner: github.context.repo.owner,
repo: github.context.repo.repo, repo: github.context.repo.repo,
baseRef: refs.base, baseRef: refs.base,
headRef: refs.head headRef: refs.head,
includeDependencySnapshots: config.include_dependency_snapshots
}); });
const changes = comparison.changes;
const snapshot_warnings = comparison.snapshot_warnings;
if (!changes) { if (!changes) {
core.info('No Dependency Changes found. Skipping Dependency Review.'); core.info('No Dependency Changes found. Skipping Dependency Review.');
return; return;
@@ -473,6 +490,9 @@ function run() {
deny: config.deny_licenses deny: config.deny_licenses
}); });
summary.addSummaryToSummary(vulnerableChanges, invalidLicenseChanges, config); summary.addSummaryToSummary(vulnerableChanges, invalidLicenseChanges, config);
if (snapshot_warnings) {
summary.addSnapshotWarnings(snapshot_warnings);
}
if (config.vulnerability_check) { if (config.vulnerability_check) {
summary.addChangeVulnerabilitiesToSummary(vulnerableChanges, minSeverity); summary.addChangeVulnerabilitiesToSummary(vulnerableChanges, minSeverity);
printVulnerabilitiesBlock(vulnerableChanges, minSeverity); printVulnerabilitiesBlock(vulnerableChanges, minSeverity);
@@ -630,7 +650,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
return result; return result;
}; };
Object.defineProperty(exports, "__esModule", ({ value: true })); Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.ChangesSchema = exports.ConfigurationOptionsSchema = exports.PullRequestSchema = exports.ChangeSchema = exports.SeveritySchema = exports.SCOPES = exports.SEVERITIES = void 0; exports.ComparisonResponseSchema = exports.ChangesSchema = exports.ConfigurationOptionsSchema = exports.PullRequestSchema = exports.ChangeSchema = exports.SeveritySchema = exports.SCOPES = exports.SEVERITIES = void 0;
const z = __importStar(__nccwpck_require__(3301)); const z = __importStar(__nccwpck_require__(3301));
exports.SEVERITIES = ['critical', 'high', 'moderate', 'low']; exports.SEVERITIES = ['critical', 'high', 'moderate', 'low'];
exports.SCOPES = ['unknown', 'runtime', 'development']; exports.SCOPES = ['unknown', 'runtime', 'development'];
@@ -672,6 +692,7 @@ exports.ConfigurationOptionsSchema = z
config_file: z.string().optional(), config_file: z.string().optional(),
base_ref: z.string().optional(), base_ref: z.string().optional(),
head_ref: z.string().optional(), head_ref: z.string().optional(),
include_dependency_snapshots: z.boolean().default(false),
comment_summary_in_pr: z.boolean().default(false) comment_summary_in_pr: z.boolean().default(false)
}) })
.superRefine((config, context) => { .superRefine((config, context) => {
@@ -696,6 +717,10 @@ exports.ConfigurationOptionsSchema = z
} }
}); });
exports.ChangesSchema = z.array(exports.ChangeSchema); exports.ChangesSchema = z.array(exports.ChangeSchema);
exports.ComparisonResponseSchema = z.object({
changes: z.array(exports.ChangeSchema),
snapshot_warnings: z.string()
});
/***/ }), /***/ }),
@@ -729,7 +754,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
return result; return result;
}; };
Object.defineProperty(exports, "__esModule", ({ value: true })); Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.addScannedDependencies = exports.addLicensesToSummary = exports.addChangeVulnerabilitiesToSummary = exports.addSummaryToSummary = void 0; exports.addSnapshotWarnings = exports.addScannedDependencies = exports.addLicensesToSummary = exports.addChangeVulnerabilitiesToSummary = exports.addSummaryToSummary = void 0;
const core = __importStar(__nccwpck_require__(2186)); const core = __importStar(__nccwpck_require__(2186));
const utils_1 = __nccwpck_require__(918); const utils_1 = __nccwpck_require__(918);
const icons = { const icons = {
@@ -887,6 +912,12 @@ function addScannedDependencies(changes) {
} }
} }
exports.addScannedDependencies = addScannedDependencies; exports.addScannedDependencies = addScannedDependencies;
function addSnapshotWarnings(warnings) {
core.summary.addHeading('Snapshot Warnings', 2);
core.summary.addQuote(`${icons.warning}: ${warnings}`);
core.summary.addRaw('See the documentation for troubleshooting help.');
}
exports.addSnapshotWarnings = addSnapshotWarnings;
function countLicenseIssues(invalidLicenseChanges) { function countLicenseIssues(invalidLicenseChanges) {
return Object.values(invalidLicenseChanges).reduce((acc, val) => acc + val.length, 0); return Object.values(invalidLicenseChanges).reduce((acc, val) => acc + val.length, 0);
} }
@@ -44846,6 +44877,7 @@ function readInlineConfig() {
const vulnerability_check = getOptionalBoolean('vulnerability-check'); const vulnerability_check = getOptionalBoolean('vulnerability-check');
const base_ref = getOptionalInput('base-ref'); const base_ref = getOptionalInput('base-ref');
const head_ref = getOptionalInput('head-ref'); const head_ref = getOptionalInput('head-ref');
const include_dependency_snapshots = getOptionalBoolean('include-dependency-snapshots');
const comment_summary_in_pr = getOptionalBoolean('comment-summary-in-pr'); const comment_summary_in_pr = getOptionalBoolean('comment-summary-in-pr');
validateLicenses('allow-licenses', allow_licenses); validateLicenses('allow-licenses', allow_licenses);
validateLicenses('deny-licenses', deny_licenses); validateLicenses('deny-licenses', deny_licenses);
@@ -44859,6 +44891,7 @@ function readInlineConfig() {
vulnerability_check, vulnerability_check,
base_ref, base_ref,
head_ref, head_ref,
include_dependency_snapshots,
comment_summary_in_pr comment_summary_in_pr
}; };
return Object.fromEntries(Object.entries(keys).filter(([_, value]) => value !== undefined)); return Object.fromEntries(Object.entries(keys).filter(([_, value]) => value !== undefined));
@@ -45083,7 +45116,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
return result; return result;
}; };
Object.defineProperty(exports, "__esModule", ({ value: true })); Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.ChangesSchema = exports.ConfigurationOptionsSchema = exports.PullRequestSchema = exports.ChangeSchema = exports.SeveritySchema = exports.SCOPES = exports.SEVERITIES = void 0; exports.ComparisonResponseSchema = exports.ChangesSchema = exports.ConfigurationOptionsSchema = exports.PullRequestSchema = exports.ChangeSchema = exports.SeveritySchema = exports.SCOPES = exports.SEVERITIES = void 0;
const z = __importStar(__nccwpck_require__(3301)); const z = __importStar(__nccwpck_require__(3301));
exports.SEVERITIES = ['critical', 'high', 'moderate', 'low']; exports.SEVERITIES = ['critical', 'high', 'moderate', 'low'];
exports.SCOPES = ['unknown', 'runtime', 'development']; exports.SCOPES = ['unknown', 'runtime', 'development'];
@@ -45125,6 +45158,7 @@ exports.ConfigurationOptionsSchema = z
config_file: z.string().optional(), config_file: z.string().optional(),
base_ref: z.string().optional(), base_ref: z.string().optional(),
head_ref: z.string().optional(), head_ref: z.string().optional(),
include_dependency_snapshots: z.boolean().default(false),
comment_summary_in_pr: z.boolean().default(false) comment_summary_in_pr: z.boolean().default(false)
}) })
.superRefine((config, context) => { .superRefine((config, context) => {
@@ -45149,6 +45183,10 @@ exports.ConfigurationOptionsSchema = z
} }
}); });
exports.ChangesSchema = z.array(exports.ChangeSchema); exports.ChangesSchema = z.array(exports.ChangeSchema);
exports.ComparisonResponseSchema = z.object({
changes: z.array(exports.ChangeSchema),
snapshot_warnings: z.string()
});
/***/ }), /***/ }),
Generated Vendored
+1 -1
View File
File diff suppressed because one or more lines are too long
+1
View File
@@ -19,6 +19,7 @@ const defaultConfig: ConfigurationOptions = {
license_check: true, license_check: true,
fail_on_severity: 'high', fail_on_severity: 'high',
fail_on_scopes: ['runtime'], fail_on_scopes: ['runtime'],
include_dependency_snapshots: false,
allow_ghsas: [], allow_ghsas: [],
allow_licenses: ['MIT'], allow_licenses: ['MIT'],
deny_licenses: [], deny_licenses: [],
+4
View File
@@ -34,6 +34,9 @@ function readInlineConfig(): ConfigurationOptionsPartial {
const vulnerability_check = getOptionalBoolean('vulnerability-check') const vulnerability_check = getOptionalBoolean('vulnerability-check')
const base_ref = getOptionalInput('base-ref') const base_ref = getOptionalInput('base-ref')
const head_ref = getOptionalInput('head-ref') const head_ref = getOptionalInput('head-ref')
const include_dependency_snapshots = getOptionalBoolean(
'include-dependency-snapshots'
)
const comment_summary_in_pr = getOptionalBoolean('comment-summary-in-pr') const comment_summary_in_pr = getOptionalBoolean('comment-summary-in-pr')
validateLicenses('allow-licenses', allow_licenses) validateLicenses('allow-licenses', allow_licenses)
@@ -49,6 +52,7 @@ function readInlineConfig(): ConfigurationOptionsPartial {
vulnerability_check, vulnerability_check,
base_ref, base_ref,
head_ref, head_ref,
include_dependency_snapshots,
comment_summary_in_pr comment_summary_in_pr
} }
+31 -6
View File
@@ -1,9 +1,14 @@
import * as core from '@actions/core' import * as core from '@actions/core'
import * as githubUtils from '@actions/github/lib/utils' import * as githubUtils from '@actions/github/lib/utils'
import * as retry from '@octokit/plugin-retry' import * as retry from '@octokit/plugin-retry'
import {Changes, ChangesSchema} from './schemas' import {
ChangesSchema,
ComparisonResponse,
ComparisonResponseSchema
} from './schemas'
const retryingOctokit = githubUtils.GitHub.plugin(retry.retry) const retryingOctokit = githubUtils.GitHub.plugin(retry.retry)
const SnapshotWarningsHeader = 'x-github-dependency-graph-snapshot-warnings'
const octo = new retryingOctokit( const octo = new retryingOctokit(
githubUtils.getOctokitOptions(core.getInput('repo-token', {required: true})) githubUtils.getOctokitOptions(core.getInput('repo-token', {required: true}))
) )
@@ -12,20 +17,40 @@ export async function compare({
owner, owner,
repo, repo,
baseRef, baseRef,
headRef headRef,
includeDependencySnapshots
}: { }: {
owner: string owner: string
repo: string repo: string
baseRef: string baseRef: string
headRef: string headRef: string
}): Promise<Changes> { includeDependencySnapshots: boolean
}): Promise<ComparisonResponse> {
let snapshot_warnings = ''
const changes = await octo.paginate( const changes = await octo.paginate(
'GET /repos/{owner}/{repo}/dependency-graph/compare/{basehead}',
{ {
method: 'GET',
url: '/repos/{owner}/{repo}/dependency-graph/compare/{basehead}',
owner, owner,
repo, repo,
basehead: `${baseRef}...${headRef}` basehead: `${baseRef}...${headRef}`,
includes_dependency_snapshots: includeDependencySnapshots
},
response => {
if (
response.headers[SnapshotWarningsHeader] &&
typeof response.headers[SnapshotWarningsHeader] === 'string'
) {
snapshot_warnings = Buffer.from(
response.headers[SnapshotWarningsHeader],
'base64'
).toString('utf-8')
}
return ChangesSchema.parse(response.data)
} }
) )
return ChangesSchema.parse(changes) return ComparisonResponseSchema.parse({
changes,
snapshot_warnings
})
} }
+9 -2
View File
@@ -22,12 +22,15 @@ async function run(): Promise<void> {
const config = await readConfig() const config = await readConfig()
const refs = getRefs(config, github.context) const refs = getRefs(config, github.context)
const changes = await dependencyGraph.compare({ const comparison = await dependencyGraph.compare({
owner: github.context.repo.owner, owner: github.context.repo.owner,
repo: github.context.repo.repo, repo: github.context.repo.repo,
baseRef: refs.base, baseRef: refs.base,
headRef: refs.head headRef: refs.head,
includeDependencySnapshots: config.include_dependency_snapshots
}) })
const changes = comparison.changes
const snapshot_warnings = comparison.snapshot_warnings
if (!changes) { if (!changes) {
core.info('No Dependency Changes found. Skipping Dependency Review.') core.info('No Dependency Changes found. Skipping Dependency Review.')
@@ -65,6 +68,10 @@ async function run(): Promise<void> {
config config
) )
if (snapshot_warnings) {
summary.addSnapshotWarnings(snapshot_warnings)
}
if (config.vulnerability_check) { if (config.vulnerability_check) {
summary.addChangeVulnerabilitiesToSummary(vulnerableChanges, minSeverity) summary.addChangeVulnerabilitiesToSummary(vulnerableChanges, minSeverity)
printVulnerabilitiesBlock(vulnerableChanges, minSeverity) printVulnerabilitiesBlock(vulnerableChanges, minSeverity)
+6
View File
@@ -46,6 +46,7 @@ export const ConfigurationOptionsSchema = z
config_file: z.string().optional(), config_file: z.string().optional(),
base_ref: z.string().optional(), base_ref: z.string().optional(),
head_ref: z.string().optional(), head_ref: z.string().optional(),
include_dependency_snapshots: z.boolean().default(false),
comment_summary_in_pr: z.boolean().default(false) comment_summary_in_pr: z.boolean().default(false)
}) })
.superRefine((config, context) => { .superRefine((config, context) => {
@@ -73,9 +74,14 @@ export const ConfigurationOptionsSchema = z
}) })
export const ChangesSchema = z.array(ChangeSchema) export const ChangesSchema = z.array(ChangeSchema)
export const ComparisonResponseSchema = z.object({
changes: z.array(ChangeSchema),
snapshot_warnings: z.string()
})
export type Change = z.infer<typeof ChangeSchema> export type Change = z.infer<typeof ChangeSchema>
export type Changes = z.infer<typeof ChangesSchema> export type Changes = z.infer<typeof ChangesSchema>
export type ComparisonResponse = z.infer<typeof ComparisonResponseSchema>
export type ConfigurationOptions = z.infer<typeof ConfigurationOptionsSchema> export type ConfigurationOptions = z.infer<typeof ConfigurationOptionsSchema>
export type Severity = z.infer<typeof SeveritySchema> export type Severity = z.infer<typeof SeveritySchema>
export type Scope = (typeof SCOPES)[number] export type Scope = (typeof SCOPES)[number]
+6
View File
@@ -215,6 +215,12 @@ export function addScannedDependencies(changes: Changes): void {
} }
} }
export function addSnapshotWarnings(warnings: string): void {
core.summary.addHeading('Snapshot Warnings', 2)
core.summary.addQuote(`${icons.warning}: ${warnings}`)
core.summary.addRaw('See the documentation for troubleshooting help.')
}
function countLicenseIssues( function countLicenseIssues(
invalidLicenseChanges: InvalidLicenseChanges invalidLicenseChanges: InvalidLicenseChanges
): number { ): number {