Files
2026-05-11 09:53:55 +02:00

101 lines
2.7 KiB
TypeScript

import { describe, expect, it } from "vitest";
import { Framework, REQUIREMENT_STATUS } from "@/types/compliance";
import { getTopFailedSections } from "./threat-helpers";
import { THREATSCORE_PILLARS } from "./threatscore-pillars";
const buildFramework = (
categoriesSpec: Array<{
name: string;
statuses: Array<"PASS" | "FAIL" | "MANUAL">;
}>,
): Framework => ({
name: "ProwlerThreatScore",
pass: 0,
fail: 0,
manual: 0,
categories: categoriesSpec.map((spec) => ({
name: spec.name,
pass: 0,
fail: 0,
manual: 0,
controls: [
{
label: "control-0",
pass: 0,
fail: 0,
manual: 0,
requirements: spec.statuses.map((status, i) => ({
name: `${spec.name}-req-${i}`,
description: "",
status: REQUIREMENT_STATUS[status],
check_ids: [],
pass: 0,
fail: 0,
manual: 0,
})),
},
],
})),
});
describe("threat.getTopFailedSections", () => {
it("returns every canonical pillar with zero-fill when no failures", () => {
const data = [buildFramework([{ name: "1. IAM", statuses: ["PASS"] }])];
const result = getTopFailedSections(data);
expect(result.items.map((i) => i.name)).toEqual([...THREATSCORE_PILLARS]);
expect(result.items.every((i) => i.total === 0)).toBe(true);
});
it("counts FAIL requirements per category and keeps canonical order", () => {
const data = [
buildFramework([
{ name: "1. IAM", statuses: ["FAIL", "FAIL"] },
{ name: "4. Encryption", statuses: ["FAIL"] },
]),
];
const result = getTopFailedSections(data);
expect(result.items).toEqual([
{ name: "1. IAM", total: 2 },
{ name: "2. Attack Surface", total: 0 },
{ name: "3. Logging and Monitoring", total: 0 },
{ name: "4. Encryption", total: 1 },
]);
});
it("appends non-canonical sections after the canonical ones", () => {
const data = [
buildFramework([
{ name: "1. IAM", statuses: ["FAIL"] },
{ name: "5. Data Protection", statuses: ["FAIL", "FAIL"] },
]),
];
const result = getTopFailedSections(data);
expect(result.items.map((i) => i.name)).toEqual([
"1. IAM",
"2. Attack Surface",
"3. Logging and Monitoring",
"4. Encryption",
"5. Data Protection",
]);
expect(
result.items.find((i) => i.name === "5. Data Protection")?.total,
).toBe(2);
});
it("ignores PASS and MANUAL when counting failures", () => {
const data = [
buildFramework([
{ name: "1. IAM", statuses: ["PASS", "MANUAL", "FAIL", "PASS"] },
]),
];
const result = getTopFailedSections(data);
expect(result.items.find((i) => i.name === "1. IAM")?.total).toBe(1);
});
});