Skip to content
Open
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
23 changes: 21 additions & 2 deletions src/output/sarif.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,25 @@ import { buildMaintenanceSarifComponent, buildMaintenanceSarifResults } from "./
import type { LicenseFinding } from "../licenses/types.js";
import { buildLicenseSarifComponent, buildLicenseSarifResults } from "./license-findings-sarif.js";

/**
* The same logo header the GitHub App puts on its PR comments, so an alert in
* Code Scanning is recognisably from this tool rather than from whichever
* scanner the reader assumed.
*
* ⚠ These two strings are duplicated from `scripts/pr-scan-delta.mjs` on
* purpose. That file imports nothing from the CLI, deliberately, because the
* Action's `delta` input and the GitHub App both deep-import it from the
* published package. Making it depend on `src/` would break both. If the logo
* ever moves, both copies have to change.
*/
const PROJECT_URL = "https://github.com/OWASP/cve-lite-cli";
const LOGO_URL =
"https://raw.githubusercontent.com/OWASP/cve-lite-cli/main/assets/logo-with-title-transparent.png";
const LOGO_HEADER = `<a href="${PROJECT_URL}"><img src="${LOGO_URL}" width="120" alt="CVE Lite CLI"></a>`;
const TEXT_ATTRIBUTION = `Reported by CVE Lite CLI - ${PROJECT_URL}`;



const SARIF_SCHEMA = "https://docs.oasis-open.org/sarif/sarif/v2.1.0/errata01/os/schemas/sarif-schema-2.1.0.json";

type SarifLog = {
Expand Down Expand Up @@ -149,7 +168,7 @@ function buildRuleHelp(
const cweIds = Array.isArray(rawCweIds) ? (rawCweIds as string[]) : null;
const range = extractAffectedRange(vuln);

const textParts: string[] = [`Vulnerability: ${title}`];
const textParts: string[] = [TEXT_ATTRIBUTION, "", `Vulnerability: ${title}`];
if (body) textParts.push("", body);
if (cvssScore) textParts.push("", `CVSS: ${cvssScore}`);
if (cweIds?.length) textParts.push(`CWE: ${cweIds.join(", ")}`);
Expand All @@ -160,7 +179,7 @@ function buildRuleHelp(
if (depPath) textParts.push("", `Dependency path: ${depPath}`);
textParts.push("", `Fix: ${action}`);

const mdParts: string[] = [`## ${title}`];
const mdParts: string[] = [LOGO_HEADER, "", `## ${title}`];
if (body) mdParts.push("", body);
if (cvssScore) mdParts.push("", `**CVSS:** \`${cvssScore}\``);
if (cweIds?.length) mdParts.push(`**CWE:** ${cweIds.join(", ")}`);
Expand Down
24 changes: 24 additions & 0 deletions tests/sarif.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,30 @@ describe("buildSarifOutput — rule enrichment", () => {
it("populates help.markdown with the recommended fix action", () => {
expect(rule.help?.markdown).toContain("## Fix");
});

// A Code Scanning alert gives no indication of which tool produced it beyond
// the tool name in the run metadata, which the alert detail view does not put
// in front of the reader. The header is the same attribution the GitHub App
// puts on its PR comments.
it("leads help.markdown with the project logo, linked to the project", () => {
const markdown: string = rule.help?.markdown ?? "";
const firstLine = markdown.split("\n")[0];

expect(firstLine).toContain('href="https://github.com/OWASP/cve-lite-cli"');
expect(firstLine).toContain("assets/logo-with-title-transparent.png");
expect(firstLine).toContain('alt="CVE Lite CLI"');
});

it("leads help.text with a plain-text attribution, since text has no markup", () => {
const text: string = rule.help?.text ?? "";

expect(text.split("\n")[0]).toBe("Reported by CVE Lite CLI - https://github.com/OWASP/cve-lite-cli");
});

it("adds the attribution without displacing the title", () => {
expect(rule.help?.markdown).toContain("## undici vulnerable to HTTP header injection");
expect(rule.help?.text).toContain("Vulnerability: undici vulnerable to HTTP header injection");
});
});

describe("buildSarifOutput — graceful degradation", () => {
Expand Down
Loading