mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-07-23 20:42:02 +00:00
197 lines
6.2 KiB
TypeScript
197 lines
6.2 KiB
TypeScript
import React from "react";
|
|
|
|
import { AWSWellArchitectedCustomDetails } from "@/components/compliance/compliance-custom-details/aws-well-architected-details";
|
|
import { CISCustomDetails } from "@/components/compliance/compliance-custom-details/cis-details";
|
|
import { ENSCustomDetails } from "@/components/compliance/compliance-custom-details/ens-details";
|
|
import { ISOCustomDetails } from "@/components/compliance/compliance-custom-details/iso-details";
|
|
import { AccordionItemProps } from "@/components/ui/accordion/Accordion";
|
|
import {
|
|
AttributesData,
|
|
CategoryData,
|
|
FailedSection,
|
|
Framework,
|
|
Requirement,
|
|
RequirementsData,
|
|
} from "@/types/compliance";
|
|
|
|
import {
|
|
mapComplianceData as mapAWSWellArchitectedComplianceData,
|
|
toAccordionItems as toAWSWellArchitectedAccordionItems,
|
|
} from "./aws-well-architected";
|
|
import {
|
|
mapComplianceData as mapCISComplianceData,
|
|
toAccordionItems as toCISAccordionItems,
|
|
} from "./cis";
|
|
import {
|
|
mapComplianceData as mapENSComplianceData,
|
|
toAccordionItems as toENSAccordionItems,
|
|
} from "./ens";
|
|
import {
|
|
mapComplianceData as mapISOComplianceData,
|
|
toAccordionItems as toISOAccordionItems,
|
|
} from "./iso";
|
|
|
|
export interface ComplianceMapper {
|
|
mapComplianceData: (
|
|
attributesData: AttributesData,
|
|
requirementsData: RequirementsData,
|
|
filter?: string,
|
|
) => Framework[];
|
|
toAccordionItems: (
|
|
data: Framework[],
|
|
scanId: string | undefined,
|
|
) => AccordionItemProps[];
|
|
getTopFailedSections: (mappedData: Framework[]) => FailedSection[];
|
|
getDetailsComponent: (requirement: Requirement) => React.ReactNode;
|
|
}
|
|
|
|
// Common function for getting top failed sections
|
|
export const getTopFailedSections = (
|
|
mappedData: Framework[],
|
|
): FailedSection[] => {
|
|
const failedSectionMap = new Map();
|
|
|
|
mappedData.forEach((framework) => {
|
|
framework.categories.forEach((category) => {
|
|
category.controls.forEach((control) => {
|
|
control.requirements.forEach((requirement) => {
|
|
if (requirement.status === "FAIL") {
|
|
const sectionName = category.name;
|
|
|
|
if (!failedSectionMap.has(sectionName)) {
|
|
failedSectionMap.set(sectionName, { total: 0, types: {} });
|
|
}
|
|
|
|
const sectionData = failedSectionMap.get(sectionName);
|
|
sectionData.total += 1;
|
|
|
|
const type = requirement.type || "Fails";
|
|
|
|
sectionData.types[type as string] =
|
|
(sectionData.types[type as string] || 0) + 1;
|
|
}
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
// Convert in descending order and slice top 5
|
|
return Array.from(failedSectionMap.entries())
|
|
.map(([name, data]) => ({ name, ...data }))
|
|
.sort((a, b) => b.total - a.total)
|
|
.slice(0, 5); // Top 5
|
|
};
|
|
|
|
// Registry of compliance mappers
|
|
const complianceMappers: Record<string, ComplianceMapper> = {
|
|
ENS: {
|
|
mapComplianceData: mapENSComplianceData,
|
|
toAccordionItems: toENSAccordionItems,
|
|
getTopFailedSections,
|
|
getDetailsComponent: (requirement: Requirement) =>
|
|
React.createElement(ENSCustomDetails, { requirement }),
|
|
},
|
|
ISO27001: {
|
|
mapComplianceData: mapISOComplianceData,
|
|
toAccordionItems: toISOAccordionItems,
|
|
getTopFailedSections,
|
|
getDetailsComponent: (requirement: Requirement) =>
|
|
React.createElement(ISOCustomDetails, { requirement }),
|
|
},
|
|
CIS: {
|
|
mapComplianceData: mapCISComplianceData,
|
|
toAccordionItems: toCISAccordionItems,
|
|
getTopFailedSections,
|
|
getDetailsComponent: (requirement: Requirement) =>
|
|
React.createElement(CISCustomDetails, { requirement }),
|
|
},
|
|
"AWS-Well-Architected-Framework-Security-Pillar": {
|
|
mapComplianceData: mapAWSWellArchitectedComplianceData,
|
|
toAccordionItems: toAWSWellArchitectedAccordionItems,
|
|
getTopFailedSections,
|
|
getDetailsComponent: (requirement: Requirement) =>
|
|
React.createElement(AWSWellArchitectedCustomDetails, { requirement }),
|
|
},
|
|
"AWS-Well-Architected-Framework-Reliability-Pillar": {
|
|
mapComplianceData: mapAWSWellArchitectedComplianceData,
|
|
toAccordionItems: toAWSWellArchitectedAccordionItems,
|
|
getTopFailedSections,
|
|
getDetailsComponent: (requirement: Requirement) =>
|
|
React.createElement(AWSWellArchitectedCustomDetails, { requirement }),
|
|
},
|
|
};
|
|
|
|
// Default mapper (fallback to ENS for backward compatibility)
|
|
const defaultMapper: ComplianceMapper = complianceMappers.ENS;
|
|
|
|
/**
|
|
* Get the appropriate compliance mapper based on the framework name
|
|
* @param framework - The framework name (e.g., "ENS", "ISO27001", "CIS")
|
|
* @returns ComplianceMapper object with specific functions for the framework
|
|
*/
|
|
export const getComplianceMapper = (framework?: string): ComplianceMapper => {
|
|
if (!framework) {
|
|
return defaultMapper;
|
|
}
|
|
|
|
return complianceMappers[framework] || defaultMapper;
|
|
};
|
|
|
|
export const calculateCategoryHeatmapData = (
|
|
complianceData: Framework[],
|
|
): CategoryData[] => {
|
|
if (!complianceData?.length) {
|
|
return [];
|
|
}
|
|
|
|
try {
|
|
const categoryMap = new Map<
|
|
string,
|
|
{ pass: number; fail: number; manual: number }
|
|
>();
|
|
|
|
// Aggregate data by category
|
|
complianceData.forEach((framework) => {
|
|
framework.categories.forEach((category) => {
|
|
const existing = categoryMap.get(category.name) || {
|
|
pass: 0,
|
|
fail: 0,
|
|
manual: 0,
|
|
};
|
|
categoryMap.set(category.name, {
|
|
pass: existing.pass + category.pass,
|
|
fail: existing.fail + category.fail,
|
|
manual: existing.manual + category.manual,
|
|
});
|
|
});
|
|
});
|
|
|
|
const categoryData: CategoryData[] = Array.from(categoryMap.entries()).map(
|
|
([name, stats]) => {
|
|
const totalRequirements = stats.pass + stats.fail + stats.manual;
|
|
const failurePercentage =
|
|
totalRequirements > 0
|
|
? Math.round((stats.fail / totalRequirements) * 100)
|
|
: 0;
|
|
|
|
return {
|
|
name,
|
|
failurePercentage,
|
|
totalRequirements,
|
|
failedRequirements: stats.fail,
|
|
};
|
|
},
|
|
);
|
|
|
|
const filteredData = categoryData
|
|
.filter((category) => category.totalRequirements > 0)
|
|
.sort((a, b) => b.failurePercentage - a.failurePercentage)
|
|
.slice(0, 9); // Show top 9 categories
|
|
|
|
return filteredData;
|
|
} catch (error) {
|
|
console.error("Error calculating category heatmap data:", error);
|
|
return [];
|
|
}
|
|
};
|