Skip to content

Commit

Permalink
feat: add audit info to removed dependencies (#754)
Browse files Browse the repository at this point in the history
  • Loading branch information
ybiquitous authored Jul 7, 2023
1 parent e0c76ea commit f4d683d
Show file tree
Hide file tree
Showing 8 changed files with 144 additions and 108 deletions.
107 changes: 56 additions & 51 deletions dist/index.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -10367,7 +10367,7 @@ function splitPackageName(packageName) {
}

// lib/aggregateReport.js
var byNameAndVersion = (a, b) => {
function byNameAndVersion(a, b) {
const res = a.name.localeCompare(b.name);
if (res > 0) {
return 1;
Expand All @@ -10376,41 +10376,42 @@ var byNameAndVersion = (a, b) => {
return -1;
}
return semverToNumber(a.version) - semverToNumber(b.version);
};
}
function getAuditInfo(audit2, name) {
const info4 = audit2.get(name);
const severity = info4 == null ? null : capitalize(info4.severity);
const title = info4 == null ? null : info4.title;
const url = info4 == null ? null : info4.url;
return { severity, title, url };
}
async function aggregateReport(audit2, beforePackages, afterPackages) {
const added = [];
afterPackages.forEach((version2, name) => {
if (!beforePackages.has(name)) {
const pkg = splitPackageName(name);
added.push({ name: pkg.name, location: pkg.location, version: version2 });
afterPackages.forEach((version2, pkgName) => {
if (!beforePackages.has(pkgName)) {
const { name, location } = splitPackageName(pkgName);
added.push({ name, location, version: version2 });
}
});
added.sort(byNameAndVersion);
const removed = [];
beforePackages.forEach((version2, name) => {
if (!afterPackages.has(name)) {
const pkg = splitPackageName(name);
removed.push({ name: pkg.name, location: pkg.location, version: version2 });
beforePackages.forEach((version2, pkgName) => {
if (!afterPackages.has(pkgName)) {
const { name, location } = splitPackageName(pkgName);
removed.push({ name, location, version: version2, ...getAuditInfo(audit2, name) });
}
});
removed.sort(byNameAndVersion);
const updated = [];
afterPackages.forEach((version2, name) => {
const previousVersion = beforePackages.get(name);
afterPackages.forEach((version2, pkgName) => {
const previousVersion = beforePackages.get(pkgName);
if (version2 !== previousVersion && previousVersion != null) {
const pkg = splitPackageName(name);
const info4 = audit2.get(pkg.name);
const severity = info4 == null ? null : capitalize(info4.severity);
const title = info4 == null ? null : info4.title;
const url = info4 == null ? null : info4.url;
const { name, location } = splitPackageName(pkgName);
updated.push({
name: pkg.name,
location: pkg.location,
name,
location,
version: version2,
previousVersion,
severity,
title,
url
...getAuditInfo(audit2, name)
});
}
});
Expand Down Expand Up @@ -10442,23 +10443,21 @@ async function audit(execFn = import_exec2.getExecOutput) {
});
const { vulnerabilities } = JSON.parse(stdout);
if (vulnerabilities != null && typeof vulnerabilities === "object") {
const map = (
/** @type {AuditReport} */
/* @__PURE__ */ new Map()
);
Object.values(vulnerabilities).forEach(({ name, severity, via }) => {
const map = /* @__PURE__ */ new Map();
for (const { name, severity, via } of Object.values(vulnerabilities)) {
if (Array.isArray(via)) {
const [viaFirst] = via;
if (typeof viaFirst.title === "string" && typeof viaFirst.url === "string") {
map.set(name, { name, severity, title: viaFirst.title, url: viaFirst.url });
const { title, url } = viaFirst;
if (typeof title === "string" && typeof url === "string") {
map.set(name, { name, severity, title, url });
} else if (typeof viaFirst === "string") {
} else {
throw new Error(`"via" of "${name}" is invalid: ${JSON.stringify(via)}`);
}
} else {
throw new Error('"via" is not an array');
}
});
}
return map;
}
throw new Error('"vulnerabilities" is missing');
Expand All @@ -10480,21 +10479,24 @@ async function auditFix() {
}

// lib/buildCommitBody.js
function buildCommitBody(report) {
function buildCommitBody({ updated, added, removed }) {
const lines = [];
lines.push("Summary:");
lines.push(`- Updated packages: ${report.updated.length}`);
lines.push(`- Added packages: ${report.added.length}`);
lines.push(`- Removed packages: ${report.removed.length}`);
lines.push(`- Updated packages: ${updated.length}`);
lines.push(`- Added packages: ${added.length}`);
lines.push(`- Removed packages: ${removed.length}`);
lines.push("");
if (report.updated.length > 0) {
lines.push("Fixed vulnerabilities:");
const vulnerabilities = /* @__PURE__ */ new Set();
report.updated.forEach(({ name, severity, title, url }) => {
const vulnerabilities = /* @__PURE__ */ new Set();
for (const entry of [...updated, ...added, ...removed]) {
if ("severity" in entry && "title" in entry && "url" in entry) {
const { name, severity, title, url } = entry;
if (severity != null && title != null && url != null) {
vulnerabilities.add(`- ${name}: "${title}" (${url})`);
}
});
}
}
if (vulnerabilities.size > 0) {
lines.push("Fixed vulnerabilities:");
lines.push(...Array.from(vulnerabilities));
} else {
lines.push("No fixed vulnerabilities.");
Expand Down Expand Up @@ -10523,6 +10525,12 @@ var repoLink = (report, name) => {
return url ? `[${url.type}](${url.url})` : EMPTY;
};
var versionLabel = (version2) => `\`${version2}\``;
var detail = ({ severity, title, url }) => {
if (severity != null && title != null && url != null) {
return `**[${severity}]** ${title} ([ref](${url}))`;
}
return EMPTY;
};
function buildPullRequestBody(report, npmVersion) {
const header = [];
header.push("| Package | Version | Source | Detail |");
Expand All @@ -10538,16 +10546,12 @@ function buildPullRequestBody(report, npmVersion) {
lines.push("");
lines.push(...header);
report.updated.forEach(({ name, version: version2, location, previousVersion, severity, title, url }) => {
let extra = EMPTY;
if (severity != null && title != null && url != null) {
extra = `**[${severity}]** ${title} ([ref](${url}))`;
}
lines.push(
buildTableRow(
npmPackage(name, version2, location),
`${versionLabel(previousVersion)} \u2192 ${versionLabel(version2)}`,
repoLink(report, name),
extra
detail({ severity, title, url })
)
);
});
Expand All @@ -10566,7 +10570,7 @@ function buildPullRequestBody(report, npmVersion) {
npmPackage(name, version2, location),
versionLabel(version2),
repoLink(report, name),
EMPTY
detail({})
)
);
});
Expand All @@ -10579,13 +10583,13 @@ function buildPullRequestBody(report, npmVersion) {
lines.push(`<summary><strong>Removed (${report.removed.length})</strong></summary>`);
lines.push("");
lines.push(...header);
report.removed.forEach(({ name, version: version2, location }) => {
report.removed.forEach(({ name, version: version2, location, severity, title, url }) => {
lines.push(
buildTableRow(
npmPackage(name, version2, location),
versionLabel(version2),
repoLink(report, name),
EMPTY
detail({ severity, title, url })
)
);
});
Expand Down Expand Up @@ -10766,10 +10770,11 @@ async function run() {
await (0, import_exec7.exec)("npm", npmArgs("ci"));
});
const afterPackages = await core2.group("List packages after", () => listPackages());
const report = await core2.group(
"Aggregate report",
() => aggregateReport(auditReport, beforePackages, afterPackages)
);
const report = await core2.group("Aggregate report", async () => {
const res = await aggregateReport(auditReport, beforePackages, afterPackages);
core2.info(JSON.stringify(res, null, 2));
return res;
});
if (report.packageCount === 0) {
core2.info("No update.");
return;
Expand Down
6 changes: 6 additions & 0 deletions lib/__tests__/__snapshots__/aggregateReport.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,17 @@ exports[`aggregateReport() 1`] = `
{
"location": "svgo/node_modules/css-select",
"name": "css-select",
"severity": null,
"title": null,
"url": null,
"version": "3.1.2",
},
{
"location": null,
"name": "xmldom",
"severity": "Low",
"title": "Misinterpretation of malicious XML input",
"url": "https://npmjs.com/advisories/1650",
"version": "0.5.0",
},
],
Expand Down
51 changes: 29 additions & 22 deletions lib/aggregateReport.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import splitPackageName from "./utils/splitPackageName.js";
* @param {{ name: string, version: string }} b
* @returns {number}
*/
const byNameAndVersion = (a, b) => {
function byNameAndVersion(a, b) {
const res = a.name.localeCompare(b.name);
if (res > 0) {
return 1;
Expand All @@ -17,7 +17,20 @@ const byNameAndVersion = (a, b) => {
return -1;
}
return semverToNumber(a.version) - semverToNumber(b.version);
};
}

/**
* @param {AuditReport} audit
* @param {string} name
* @returns {{ severity: string | null, title: string | null, url: string | null }}
*/
function getAuditInfo(audit, name) {
const info = audit.get(name);
const severity = info == null ? null : capitalize(info.severity);
const title = info == null ? null : info.title;
const url = info == null ? null : info.url;
return { severity, title, url };
}

/**
* @param {AuditReport} audit
Expand All @@ -28,42 +41,36 @@ const byNameAndVersion = (a, b) => {
export default async function aggregateReport(audit, beforePackages, afterPackages) {
/** @type {Report["added"]} */
const added = [];
afterPackages.forEach((version, name) => {
if (!beforePackages.has(name)) {
const pkg = splitPackageName(name);
added.push({ name: pkg.name, location: pkg.location, version });
afterPackages.forEach((version, pkgName) => {
if (!beforePackages.has(pkgName)) {
const { name, location } = splitPackageName(pkgName);
added.push({ name, location, version });
}
});
added.sort(byNameAndVersion);

/** @type {Report["removed"]} */
const removed = [];
beforePackages.forEach((version, name) => {
if (!afterPackages.has(name)) {
const pkg = splitPackageName(name);
removed.push({ name: pkg.name, location: pkg.location, version });
beforePackages.forEach((version, pkgName) => {
if (!afterPackages.has(pkgName)) {
const { name, location } = splitPackageName(pkgName);
removed.push({ name, location, version, ...getAuditInfo(audit, name) });
}
});
removed.sort(byNameAndVersion);

/** @type {Report["updated"]} */
const updated = [];
afterPackages.forEach((version, name) => {
const previousVersion = beforePackages.get(name);
afterPackages.forEach((version, pkgName) => {
const previousVersion = beforePackages.get(pkgName);
if (version !== previousVersion && previousVersion != null) {
const pkg = splitPackageName(name);
const info = audit.get(pkg.name);
const severity = info == null ? null : capitalize(info.severity);
const title = info == null ? null : info.title;
const url = info == null ? null : info.url;
const { name, location } = splitPackageName(pkgName);
updated.push({
name: pkg.name,
location: pkg.location,
name,
location,
version,
previousVersion,
severity,
title,
url,
...getAuditInfo(audit, name),
});
}
});
Expand Down
12 changes: 7 additions & 5 deletions lib/audit.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,15 @@ export default async function audit(execFn = getExecOutput) {
const { vulnerabilities } = JSON.parse(stdout);

if (vulnerabilities != null && typeof vulnerabilities === "object") {
const map = /** @type {AuditReport} */ new Map();
/** @type {AuditReport} */
const map = new Map();

Object.values(vulnerabilities).forEach(({ name, severity, via }) => {
for (const { name, severity, via } of Object.values(vulnerabilities)) {
if (Array.isArray(via)) {
const [viaFirst] = via;
if (typeof viaFirst.title === "string" && typeof viaFirst.url === "string") {
map.set(name, { name, severity, title: viaFirst.title, url: viaFirst.url });
const { title, url } = viaFirst;
if (typeof title === "string" && typeof url === "string") {
map.set(name, { name, severity, title, url });
} else if (typeof viaFirst === "string") {
// ignore
} else {
Expand All @@ -27,7 +29,7 @@ export default async function audit(execFn = getExecOutput) {
} else {
throw new Error('"via" is not an array');
}
});
}

return map;
}
Expand Down
25 changes: 15 additions & 10 deletions lib/buildCommitBody.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,31 @@
* @param {Report} report
* @returns {string}
*/
export default function buildCommitBody(report) {
export default function buildCommitBody({ updated, added, removed }) {
/** @type {string[]} */
const lines = [];

lines.push("Summary:");
lines.push(`- Updated packages: ${report.updated.length}`);
lines.push(`- Added packages: ${report.added.length}`);
lines.push(`- Removed packages: ${report.removed.length}`);
lines.push(`- Updated packages: ${updated.length}`);
lines.push(`- Added packages: ${added.length}`);
lines.push(`- Removed packages: ${removed.length}`);

lines.push("");
if (report.updated.length > 0) {
lines.push("Fixed vulnerabilities:");

/** @type {Set<string>} */
const vulnerabilities = new Set();
report.updated.forEach(({ name, severity, title, url }) => {
/** @type {Set<string>} */
const vulnerabilities = new Set();

for (const entry of [...updated, ...added, ...removed]) {
if ("severity" in entry && "title" in entry && "url" in entry) {
const { name, severity, title, url } = entry;
if (severity != null && title != null && url != null) {
vulnerabilities.add(`- ${name}: "${title}" (${url})`);
}
});
}
}

if (vulnerabilities.size > 0) {
lines.push("Fixed vulnerabilities:");
lines.push(...Array.from(vulnerabilities));
} else {
lines.push("No fixed vulnerabilities.");
Expand Down
Loading

0 comments on commit f4d683d

Please sign in to comment.