Add 'show-patched-versions' option to configuration and update summary handling

- Introduced 'show-patched-versions' input in action.yml to control visibility of patched versions in vulnerability summaries.
- Updated default configuration and related functions to handle the new option.
- Enhanced tests to verify behavior with and without the patched version column.
This commit is contained in:
Chad Bentz
2026-02-27 14:58:54 -05:00
parent e404798400
commit aa60746a92
11 changed files with 166 additions and 57 deletions

67
dist/index.js generated vendored
View File

@@ -786,7 +786,7 @@ function run() {
let issueFound = false;
if (config.vulnerability_check) {
core.setOutput('vulnerable-changes', JSON.stringify(vulnerableChanges));
yield summary.addChangeVulnerabilitiesToSummary(vulnerableChanges, minSeverity);
yield summary.addChangeVulnerabilitiesToSummary(vulnerableChanges, minSeverity, config.show_patched_versions);
issueFound || (issueFound = yield printVulnerabilitiesBlock(vulnerableChanges, minSeverity, warnOnly));
}
if (config.license_check) {
@@ -1311,6 +1311,7 @@ exports.ConfigurationOptionsSchema = z
retry_on_snapshot_warnings_timeout: z.number().default(120),
show_openssf_scorecard: z.boolean().optional().default(true),
warn_on_openssf_scorecard_level: z.number().default(3),
show_patched_versions: z.boolean().default(false),
comment_summary_in_pr: z
.union([
z.preprocess(val => (val === 'true' ? true : val === 'false' ? false : val), z.boolean()),
@@ -1878,17 +1879,25 @@ function promisePool(tasks, limit) {
yield Promise.all(executing);
});
}
function addChangeVulnerabilitiesToSummary(vulnerableChanges, severity) {
return __awaiter(this, void 0, void 0, function* () {
function addChangeVulnerabilitiesToSummary(vulnerableChanges_1, severity_1) {
return __awaiter(this, arguments, void 0, function* (vulnerableChanges, severity, showPatchedVersions = false) {
if (vulnerableChanges.length === 0) {
return;
}
const manifests = (0, utils_1.getManifestsSet)(vulnerableChanges);
// Build set of unique advisories to query
const advisorySet = new Set();
for (const pkg of vulnerableChanges) {
for (const vuln of pkg.vulnerabilities) {
advisorySet.add(vuln.advisory_ghsa_id);
if (showPatchedVersions) {
if ((0, utils_1.isEnterprise)()) {
core.warning('show-patched-versions is not supported on GitHub Enterprise Server. The Patched Version column will be omitted.');
showPatchedVersions = false;
}
else {
for (const pkg of vulnerableChanges) {
for (const vuln of pkg.vulnerabilities) {
advisorySet.add(vuln.advisory_ghsa_id);
}
}
}
}
// Query GitHub API for patch info with concurrency limiting
@@ -1992,34 +2001,43 @@ function addChangeVulnerabilitiesToSummary(vulnerableChanges, severity) {
core.debug(`No advisory data available for ${vuln.advisory_ghsa_id}`);
}
if (!sameAsPrevious) {
rows.push([
const row = [
(0, utils_1.renderUrl)(change.source_repository_url, change.name),
change.version,
(0, utils_1.renderUrl)(vuln.advisory_url, vuln.advisory_summary),
vuln.severity,
patchVer
]);
vuln.severity
];
if (showPatchedVersions) {
row.push(patchVer);
}
rows.push(row);
}
else {
rows.push([
const row = [
{ data: '', colspan: '2' },
(0, utils_1.renderUrl)(vuln.advisory_url, vuln.advisory_summary),
vuln.severity,
patchVer
]);
vuln.severity
];
if (showPatchedVersions) {
row.push(patchVer);
}
rows.push(row);
}
previous_package = change.name;
previous_version = change.version;
}
}
const headerRow = [
{ data: 'Name', header: true },
{ data: 'Version', header: true },
{ data: 'Vulnerability', header: true },
{ data: 'Severity', header: true }
];
if (showPatchedVersions) {
headerRow.push({ data: 'Patched Version', header: true });
}
core.summary.addHeading(`<em>${manifest}</em>`, 4).addTable([
[
{ data: 'Name', header: true },
{ data: 'Version', header: true },
{ data: 'Vulnerability', header: true },
{ data: 'Severity', header: true },
{ data: 'Patched Version', header: true }
],
headerRow,
...rows
]);
}
@@ -2251,6 +2269,7 @@ Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.groupDependenciesByManifest = groupDependenciesByManifest;
exports.getManifestsSet = getManifestsSet;
exports.renderUrl = renderUrl;
exports.isEnterprise = isEnterprise;
exports.octokitClient = octokitClient;
const core = __importStar(__nccwpck_require__(37484));
const octokit_1 = __nccwpck_require__(42373);
@@ -98859,6 +98878,7 @@ function readInlineConfig() {
const warn_only = getOptionalBoolean('warn-only');
const show_openssf_scorecard = getOptionalBoolean('show-openssf-scorecard');
const warn_on_openssf_scorecard_level = getOptionalNumber('warn-on-openssf-scorecard-level');
const show_patched_versions = getOptionalBoolean('show-patched-versions');
validateLicenses('allow-licenses', allow_licenses);
validateLicenses('deny-licenses', deny_licenses);
const keys = {
@@ -98879,7 +98899,8 @@ function readInlineConfig() {
retry_on_snapshot_warnings_timeout,
warn_only,
show_openssf_scorecard,
warn_on_openssf_scorecard_level
warn_on_openssf_scorecard_level,
show_patched_versions
};
return Object.fromEntries(Object.entries(keys).filter(([_, value]) => value !== undefined));
}
@@ -99369,6 +99390,7 @@ exports.ConfigurationOptionsSchema = z
retry_on_snapshot_warnings_timeout: z.number().default(120),
show_openssf_scorecard: z.boolean().optional().default(true),
warn_on_openssf_scorecard_level: z.number().default(3),
show_patched_versions: z.boolean().default(false),
comment_summary_in_pr: z
.union([
z.preprocess(val => (val === 'true' ? true : val === 'false' ? false : val), z.boolean()),
@@ -99600,6 +99622,7 @@ Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.groupDependenciesByManifest = groupDependenciesByManifest;
exports.getManifestsSet = getManifestsSet;
exports.renderUrl = renderUrl;
exports.isEnterprise = isEnterprise;
exports.octokitClient = octokitClient;
const core = __importStar(__nccwpck_require__(37484));
const octokit_1 = __nccwpck_require__(42373);

2
dist/index.js.map generated vendored

File diff suppressed because one or more lines are too long