Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[version-4-3] chore: Fix CVE URL logic (#4936) #4956

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 36 additions & 8 deletions src/components/CveReportsTable/CveReportsTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,31 @@ type CveDataUnion =
vertexAirgap: MinimizedCve[];
};

// generateCVEOfficialDetailsUrl returns a URL that is used to link to the official CVE report.
// The URL is generated based on the cveId.
// The function checks if the cveId starts with "ghsa" and returns a GitHub Security Advisory URL. Other formal sites can be added in the future.
// The default URL is the NVD official CVE report.
function generateCVEOfficialDetailsUrl(cveId: string) {
let url;

// If cveId is empty, return the default reports page URL
if (!cveId) {
return "/security-bulletins/reports/";
}

switch (true) {
// GitHub Security Advisory
case cveId.toLocaleLowerCase().startsWith("ghsa"):
url = `https://github.com/advisories/${cveId.toLocaleLowerCase()}`;
break;
// Default CVE URL
default:
url = `https://nvd.nist.gov/vuln/detail/${cveId.toLocaleLowerCase()}`;
}

return url;
}

export default function CveReportsTable() {
const [data, setData] = useState<CveDataUnion | null>(null);
const [loading, setLoading] = useState(true);
Expand Down Expand Up @@ -146,11 +171,13 @@ export default function CveReportsTable() {
dataIndex: ["metadata", "cve"],
key: "cve",
sorter: (a, b) => a.metadata.cve.localeCompare(b.metadata.cve),
render: (cve: string, record) => (
<Link to={`/security-bulletins/reports/${record.metadata.uid.toLowerCase()}`} style={{ color: "#1890ff" }}>
{cve}
</Link>
),
render: (cve: string, record) => {
return (
<Link to={`/security-bulletins/reports/${record.metadata.uid.toLowerCase()}`} style={{ color: "#1890ff" }}>
{cve}
</Link>
);
},
},
{
title: "Initial Pub Date",
Expand Down Expand Up @@ -199,9 +226,10 @@ export default function CveReportsTable() {
dataIndex: ["metadata", "cvssScore"],
key: "baseScore",
sorter: (a, b) => a.metadata.cvssScore - b.metadata.cvssScore,
render: (baseScore: number, record) => (
<Link to={`https://nvd.nist.gov/vuln/detail/${record.metadata.cve}`}>{baseScore}</Link>
),
render: (baseScore: number, record) => {
const url = generateCVEOfficialDetailsUrl(record.metadata.cve.toLocaleLowerCase());
return <Link to={url}>{baseScore}</Link>;
},
},
{
title: "Status",
Expand Down
44 changes: 33 additions & 11 deletions utils/cves/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ const { formatDateCveDetails } = require("../helpers/date");
const { escapeMDXSpecialChars } = require("../helpers/string");
const { generateMarkdownTable } = require("../helpers/affected-table");
const { generateRevisionHistory } = require("../helpers/revision-history");
const { generateCVEOfficialDetailsUrl } = require("../helpers/urls");

async function getSecurityBulletins(payload) {
const limit = 100;
Expand Down Expand Up @@ -40,6 +41,21 @@ async function getSecurityBulletins(payload) {
}
}

// This function filters the items by UID and returns only the items that start with the keyword, such as "PA-", "VA-", etc.
function filterByUID(items, keyword) {
if (!Array.isArray(items)) {
throw new Error("Input must be an array of objects");
}

return items.filter((item) => {
if (!item.metadata || typeof item.metadata.uid !== "string") {
console.warn("Skipping item due to missing or invalid metadata.uid:", item);
return false;
}
return item.metadata.uid.startsWith(keyword);
});
}

async function generateCVEs() {
let GlobalCVEData = {};

Expand Down Expand Up @@ -153,19 +169,25 @@ async function generateCVEs() {
],
});

// There is no way to filter by product in the API, so we need to filter the results manually to get a list of CVEs for each product
const filterdPalette = filterByUID(palette.data, "PC-");
const filterdPaletteAirgap = filterByUID(paletteAirgap.data, "PA-");
const filterdVertex = filterByUID(vertex.data, "VC-");
const filterdVertexAirgap = filterByUID(vertexAirgap.data, "VA-");

// Debug logs
// logger.info(`Palette CVEs:", ${palette.data.length}`);
// logger.info(`Palette Airgap CVEs:", ${paletteAirgap.data.length}`);
// logger.info(`Vertex CVEs:", ${vertex.data.length}`);
// logger.info(`Vertex Airgap CVEs:", ${vertexAirgap.data.length}`);
// logger.info(`Palette CVEs:", ${filterdPalette.length}`);
// logger.info(`Palette Airgap CVEs:", ${filterdPaletteAirgap.length}`);
// logger.info(`Vertex CVEs:", ${filterdVertex.length}`);
// logger.info(`Vertex Airgap CVEs:", ${filterdVertexAirgap.length}`);

securityBulletins.set("palette", palette);
securityBulletins.set("paletteAirgap", paletteAirgap);
securityBulletins.set("vertex", vertex);
securityBulletins.set("vertexAirgap", vertexAirgap);
securityBulletins.set("palette", filterdPalette);
securityBulletins.set("paletteAirgap", filterdPaletteAirgap);
securityBulletins.set("vertex", filterdVertex);
securityBulletins.set("vertexAirgap", filterdVertexAirgap);

const plainObject = Object.fromEntries(
Array.from(securityBulletins.entries()).map(([key, value]) => [key, value.data])
Array.from(securityBulletins.entries()).map(([key, value]) => [key, value])
);
GlobalCVEData = plainObject;

Expand Down Expand Up @@ -269,7 +291,7 @@ tags: ["security", "cve"]
## CVE Details
[${upperCaseCve}](https://nvd.nist.gov/vuln/detail/${upperCaseCve})
Visit the official vulnerability details page for [${upperCaseCve}](${generateCVEOfficialDetailsUrl(item.metadata.cve)}) to learn more.
## Initial Publication
Expand All @@ -288,7 +310,7 @@ ${escapeMDXSpecialChars(item.metadata.summary)}
## CVE Severity
${item.metadata.cvssScore}
[${item.metadata.cvssScore}](${generateCVEOfficialDetailsUrl(item.metadata.cve)})
## Our Official Summary
Expand Down
28 changes: 28 additions & 0 deletions utils/helpers/urls.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// generateCVEOfficialDetailsUrl returns a URL that is used to link to the official CVE report.
// The URL is generated based on the cveId.
// The function checks if the cveId starts with "ghsa" and returns a GitHub Security Advisory URL. Other formal sites can be added in the future.
// The default URL is the NVD official CVE report.
function generateCVEOfficialDetailsUrl(cveId) {
let url;

// If cveId is empty, return the default reports page URL
if (!cveId) {
return "/security-bulletins/reports/";
}

switch (true) {
// GitHub Security Advisory
case cveId.toLocaleLowerCase().startsWith("ghsa"):
url = `https://github.com/advisories/${cveId.toLocaleLowerCase()}`;
break;
// Default CVE URL
default:
url = `https://nvd.nist.gov/vuln/detail/${cveId.toLocaleLowerCase()}`;
}

return url;
}

module.exports = {
generateCVEOfficialDetailsUrl,
};
39 changes: 39 additions & 0 deletions utils/helpers/urls.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
const { generateCVEOfficialDetailsUrl } = require("./urls");

describe("generateCVEOfficialDetailsUrl", () => {
it("should generate the GitHub Security Advisory URL for CVEs starting with 'ghsa'", () => {
const cveId = "GHSA-27wf-5967-98gx";
const result = generateCVEOfficialDetailsUrl(cveId);
expect(result).toBe("https://github.com/advisories/ghsa-27wf-5967-98gx");
});

it("should handle 'ghsa' case-insensitively and generate the correct URL", () => {
const cveId = "ghsa-27wf-5967-98gx";
const result = generateCVEOfficialDetailsUrl(cveId);
expect(result).toBe("https://github.com/advisories/ghsa-27wf-5967-98gx");
});

it("should generate the NVD URL for a CVE ID not starting with 'ghsa'", () => {
const cveId = "CVE-2020-16156";
const result = generateCVEOfficialDetailsUrl(cveId);
expect(result).toBe("https://nvd.nist.gov/vuln/detail/cve-2020-16156");
});

it("should generate the NVD URL for another CVE ID not starting with 'ghsa'", () => {
const cveId = "CVE-2019-20838";
const result = generateCVEOfficialDetailsUrl(cveId);
expect(result).toBe("https://nvd.nist.gov/vuln/detail/cve-2019-20838");
});

it("should return the default reports page URL for an empty CVE ID", () => {
const cveId = "";
const result = generateCVEOfficialDetailsUrl(cveId);
expect(result).toBe("/security-bulletins/reports/");
});

it("should return the NVD URL for a CVE ID with mixed case and normalize it", () => {
const cveId = "CVE-2020-16156";
const result = generateCVEOfficialDetailsUrl(cveId);
expect(result).toBe("https://nvd.nist.gov/vuln/detail/cve-2020-16156");
});
});
Loading