Skip to content

Commit

Permalink
chore: Fix CVE URL logic (#4936)
Browse files Browse the repository at this point in the history
* docs: fix CVE url logic

* chore: add missing line

* chore: fix list data
  • Loading branch information
karl-cardenas-coding authored Dec 9, 2024
1 parent 427e699 commit 8fb75f8
Show file tree
Hide file tree
Showing 4 changed files with 136 additions and 19 deletions.
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");
});
});

0 comments on commit 8fb75f8

Please sign in to comment.