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
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ import type {
VulnEventDTO,
} from "@/types/api/api";
import { RequirementsLevel } from "@/types/api/api";
import { getVexRulesSectionLabel } from "@/utils/vexRuleHelpers";
import { getIntegrationNameFromRepositoryIdOrExternalProviderId } from "@/utils/view";
import {
InformationCircleIcon,
Expand Down Expand Up @@ -919,7 +920,9 @@ const Index: FunctionComponent = () => {
</div>
)}
<span className="font-semibold block mb-2">
Applied Rules ({vexRulesData?.length || 0})
{vuln
? `${getVexRulesSectionLabel(vexRulesData ?? [], vuln)} (${vexRulesData?.length ?? 0})`
: `Matching Rules (${vexRulesData?.length ?? 0})`}
</span>
{vexRulesData && vexRulesData.length > 0 && (
<div className="flex flex-col gap-2">
Expand Down
81 changes: 81 additions & 0 deletions src/utils/vexRuleHelpers.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import type { DetailedDependencyVulnDTO, VexRule } from "@/types/api/api";
import {
getVexRulesSectionLabel,
isVexRuleAppliedToVuln,
} from "./vexRuleHelpers";

const baseVuln = {
state: "open",
} as DetailedDependencyVulnDTO;

const falsePositiveRule = {
id: "rule-1",
eventType: "falsePositive",
} as VexRule;

const acceptedRule = {
id: "rule-2",
eventType: "accepted",
} as VexRule;

describe("isVexRuleAppliedToVuln", () => {
it("returns true when false positive rule matches vuln state", () => {
expect(
isVexRuleAppliedToVuln(falsePositiveRule, {
...baseVuln,
state: "falsePositive",
}),
).toBe(true);
});

it("returns false when vuln was reopened (state is open)", () => {
expect(
isVexRuleAppliedToVuln(falsePositiveRule, {
...baseVuln,
state: "open",
}),
).toBe(false);
});

it("returns true when accepted rule matches vuln state", () => {
expect(
isVexRuleAppliedToVuln(acceptedRule, {
...baseVuln,
state: "accepted",
}),
).toBe(true);
});
});

describe("getVexRulesSectionLabel", () => {
it('shows "Matching Rules" when rule is not currently applied (reopened vuln)', () => {
expect(
getVexRulesSectionLabel([falsePositiveRule], {
...baseVuln,
state: "open",
}),
).toBe("Matching Rules");
});

it('shows "Applied Rules" when false positive rule is applied', () => {
expect(
getVexRulesSectionLabel([falsePositiveRule], {
...baseVuln,
state: "falsePositive",
}),
).toBe("Applied Rules");
});

it('shows "Matching Rules" when only some rules are applied', () => {
expect(
getVexRulesSectionLabel([falsePositiveRule, acceptedRule], {
...baseVuln,
state: "falsePositive",
}),
).toBe("Matching Rules");
});

it('shows "Matching Rules" when there are no rules', () => {
expect(getVexRulesSectionLabel([], baseVuln)).toBe("Matching Rules");
});
});
27 changes: 27 additions & 0 deletions src/utils/vexRuleHelpers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import type { DetailedDependencyVulnDTO, VexRule } from "@/types/api/api";

export function isVexRuleAppliedToVuln(
rule: VexRule,
vuln: DetailedDependencyVulnDTO,
): boolean {
if (rule.eventType === "falsePositive") {
return vuln.state === "falsePositive";
}
if (rule.eventType === "accepted") {
return vuln.state === "accepted";
}
return false;
}

export function getVexRulesSectionLabel(
rules: VexRule[],
vuln: DetailedDependencyVulnDTO,
): string {
if (rules.length === 0) {
return "Matching Rules";
}
const allApplied = rules.every((rule) =>
isVexRuleAppliedToVuln(rule, vuln),
);
return allApplied ? "Applied Rules" : "Matching Rules";
}