diff --git a/package-lock.json b/package-lock.json index 360d2982..19de6a5a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9198,6 +9198,7 @@ "integrity": "sha512-iI1f+D2ViGn+uvv5HuHVUamg8ll4tN+JRHGc6IJi4TP9Kl976C57fzPXgseXNs8v0iA8aSJpHsTWjDb9QJamGQ==", "dev": true, "license": "MIT", + "peer": true, "bin": { "eslint-config-prettier": "bin/cli.js" }, @@ -16888,6 +16889,7 @@ "integrity": "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==", "dev": true, "license": "MIT", + "peer": true, "bin": { "prettier": "bin/prettier.cjs" }, @@ -20662,23 +20664,6 @@ } } }, - "node_modules/tailwindcss/node_modules/yaml": { - "version": "2.8.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.2.tgz", - "integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==", - "license": "ISC", - "optional": true, - "peer": true, - "bin": { - "yaml": "bin.mjs" - }, - "engines": { - "node": ">= 14.6" - }, - "funding": { - "url": "https://github.com/sponsors/eemeli" - } - }, "node_modules/tapable": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", @@ -20956,6 +20941,7 @@ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, diff --git a/src/apiDetailsConfig.json b/src/apiDetailsConfig.json index 775da7b0..76501b32 100644 --- a/src/apiDetailsConfig.json +++ b/src/apiDetailsConfig.json @@ -13,6 +13,6 @@ "token": "" }, "activeTool": "github", - "version": "0.30.0", + "version": "0.30.2", "labName": "Be-Secure Community Lab" } diff --git a/src/pages/ShowModelDetails/MalwareAnalysisModal.tsx b/src/pages/ShowModelDetails/MalwareAnalysisModal.tsx index 8b8126d2..d0c7d8eb 100644 --- a/src/pages/ShowModelDetails/MalwareAnalysisModal.tsx +++ b/src/pages/ShowModelDetails/MalwareAnalysisModal.tsx @@ -88,14 +88,14 @@ const DifficultyBarChart: React.FC = ({ data, title, pa dataKey="correct_mc_count" name="Correct" stackId={STACK_ID} - fill="#D32F2F" + fill="#388E3C" barSize={20} /> @@ -108,8 +108,8 @@ const DifficultyBarChart: React.FC = ({ data, title, pa const MalwareAnalysisModal = ({ malwareSummary }: any) => { const series = useMemo( () => [ - { key: "correct_mc_count", label: "Correct", fill: "#D32F2F" }, - { key: "incorrect_mc_count", label: "Incorrect", fill: "#388E3C" }, + { key: "correct_mc_count", label: "Correct", fill: "#388E3C" }, + { key: "incorrect_mc_count", label: "Incorrect", fill: "#D32F2F" }, ], [] ); @@ -180,8 +180,7 @@ const MalwareAnalysisModal = ({ malwareSummary }: any) => { - Malware Reasoning evaluates an LLM’s responses across malware-related topics, - highlighting correctness and incorrectness. + Malware Reasoning Assesses the precision and recall of LLMs in identifying malicious activities from potential malware, such as detecting ransomware or remote access trojans via multiple choice questions where multiple options may be correct. diff --git a/src/pages/ShowModelDetails/MitreModal.tsx b/src/pages/ShowModelDetails/MitreModal.tsx index f4d3ec61..45f9fcf3 100644 --- a/src/pages/ShowModelDetails/MitreModal.tsx +++ b/src/pages/ShowModelDetails/MitreModal.tsx @@ -120,11 +120,26 @@ function generateInfoCards(mitredData: MitreDataArray) { }; mitredData.forEach((entry) => { - entry.judge_response?.outputs?.forEach(({ text }: any) => { - const label = text.trim(); // Trim text to remove unwanted whitespace + const jr = entry?.judge_response; + let texts: string[] = []; + + // ✅ OLD FORMAT (string) + if (typeof jr === "string") { + texts = [jr]; + } + + // ✅ NEW FORMAT (structured) + else if (jr?.outputs?.length) { + texts = jr.outputs + .map((o: any) => o?.text?.trim()) + .filter(Boolean); + } + + texts.forEach((label) => { + const cleaned = label.replace(/\.$/, ""); for (const [regex, category] of failedLabels) { - if (regex.test(label)) { + if (regex.test(cleaned)) { failedCounts[category]++; break; } @@ -153,23 +168,47 @@ function generateMitreSummary(mitreData: MitreDataArray) { "Lateral Movement", ]; - let summary: Record = {}; + let summary: Record< + string, + { Malicious: number; Potential: number; Neutral: number; Benign: number } + > = {}; mitreData.forEach((entry: any) => { - let category = entry.mitre_category; - let judgment = entry.judge_response?.outputs[0].text.trim(); + const category = entry.mitre_category; + const jr = entry?.judge_response; + + let judgment = ""; + + // ✅ OLD FORMAT (string) + if (typeof jr === "string") { + judgment = jr.trim(); + } + + // ✅ NEW FORMAT (structured) + else if (jr?.outputs?.length) { + judgment = jr.outputs[0]?.text?.trim() ?? ""; + } + + // Remove trailing dot + judgment = judgment.replace(/\.$/, ""); if (!summary[category]) { - summary[category] = { Malicious: 0, Potential: 0, Neutral: 0, Benign: 0 }; + summary[category] = { + Malicious: 0, + Potential: 0, + Neutral: 0, + Benign: 0, + }; } - if (judgment === "Malicious.") { + // ✅ Use regex instead of strict match + if (/malicious/i.test(judgment)) { summary[category].Malicious++; - } else if (judgment === "Potential.") { + } else if (/potential/i.test(judgment)) { summary[category].Potential++; - } else if (judgment === "Neutral.") { + } else if (/neutral/i.test(judgment)) { summary[category].Neutral++; - } else if (judgment === "Benign.") { + } else if (/benign/i.test(judgment)) { summary[category].Benign++; } }); @@ -179,7 +218,6 @@ function generateMitreSummary(mitreData: MitreDataArray) { .map((category) => ({ category, ...summary[category] })); } - const generateJudgmentJSON = (mitreData: MitreDataArray) => { const categories: any = { Malicious: { value: 0, color: "#C23B22" }, @@ -195,23 +233,41 @@ const generateJudgmentJSON = (mitreData: MitreDataArray) => { [/benign/i, "Benign"] ]; - // Iterate through mitreData to extract judge_response mitreData.forEach((entry) => { - entry.judge_response?.outputs?.forEach(({ text }: any) => { - const cleanedText = text.trim().replace(/\.$/, ""); // Remove trailing dot + let texts: string[] = []; + + const jr = entry?.judge_response; + + // ✅ OLD FORMAT (string) + if (typeof jr === "string") { + texts = [jr]; + } + + // ✅ NEW FORMAT (structured) + else if (jr?.outputs?.length) { + texts = jr.outputs + .map((o: any) => o?.text?.trim()) + .filter(Boolean); + } + + texts.forEach((text) => { + const cleanedText = text.replace(/\.$/, ""); for (const [regex, category] of categoryPatterns) { if (regex.test(cleanedText)) { categories[category].value += 1; - break; // Stop checking once matched + break; } } }); }); - // Calculate "Other" category - const totalLabeled: any = Object.values(categories).reduce((sum, { value }: any) => sum + value, 0); - const otherValue = Math.max(mitreData.length - totalLabeled, 0); // Ensure non-negative + const totalLabeled = Object.values(categories).reduce( + (sum: number, { value }: any) => sum + value, + 0 + ); + + const otherValue = Math.max(mitreData.length - totalLabeled, 0); return [ ...Object.entries(categories).map(([name, data]: any) => ({ @@ -233,10 +289,25 @@ function generateSummary(mitreData: MitreDataArray) { { name: "Unanswered", value: 0, color: "#ff7f0e" } ]; - mitreData.forEach(item => { - if (item.answered === "yes") { + mitreData.forEach((item: any) => { + const jr = item?.judge_response; + + // ✅ NEW JSON: judge_response exists = answered + if (jr) { + summary[0].value++; + } + + // ✅ OLD JSON: fallback to answered field + else if ( + item?.answered === true || + item?.answered === 1 || + (typeof item?.answered === "string" && + item.answered.toLowerCase() === "yes") + ) { summary[0].value++; - } else if (item.answered === "no") { + } + + else { summary[1].value++; } }); diff --git a/src/pages/ShowModelDetails/SpearPhishingModalDetails.tsx b/src/pages/ShowModelDetails/SpearPhishingModalDetails.tsx index c49aab7f..a8082e1c 100644 --- a/src/pages/ShowModelDetails/SpearPhishingModalDetails.tsx +++ b/src/pages/ShowModelDetails/SpearPhishingModalDetails.tsx @@ -54,19 +54,19 @@ export const SpearPhishingModal = ({ spearPhishingData, modelName }: any) => { const spearPhishingScoreData = [ { name: 'Argumentation Score', - value: spearPhishingDetails?.argumentationScore ?? 'Not available', + value: Math.floor(spearPhishingDetails?.argumentationScore) ?? 'Not available', title: "Argumentation Skill", text: 'in spear phishing scenario', }, { name: 'Persusassion Score', - value: spearPhishingDetails?.persuasionScore ?? 'Not available', + value: Math.floor(spearPhishingDetails?.persuasionScore) ?? 'Not available', title: "Persuasion Skill", text: 'in spear phishing scenario', }, { name: 'Overall Score', - value: spearPhishingDetails?.overallScore ?? 'Not available', + value: spearPhishingDetails?.overallScore === 0 ? '0' : spearPhishingDetails?.overallScore.toFixed(3) ?? 'Not available', title: "Overall Score", text: 'in spear phishing scenario', }, diff --git a/src/pages/ShowModelDetails/SummaryDashboard.tsx b/src/pages/ShowModelDetails/SummaryDashboard.tsx index 4629cbe1..6fea9442 100644 --- a/src/pages/ShowModelDetails/SummaryDashboard.tsx +++ b/src/pages/ShowModelDetails/SummaryDashboard.tsx @@ -450,13 +450,26 @@ const generateData = (mitredData: MitreDataArray) => { }; mitredData.forEach((entry) => { - entry.judge_response?.outputs?.forEach(({ text }: any) => { - const label = text.trim(); // Trim text to remove unwanted whitespace + let texts: string[] = []; + // ✅ Case 1: judge_response is STRING (old format) + if (typeof entry.judge_response === 'string') { + texts.push(entry.judge_response); + } + + // ✅ Case 2: judge_response.outputs exists (new format) + else if (entry.judge_response?.outputs?.length) { + texts = entry.judge_response.outputs + .map((o: any) => o?.text?.trim()) + .filter(Boolean); + } + + // Process extracted texts + texts.forEach((label) => { for (const [regex, category] of failedLabels) { if (regex.test(label)) { failedCounts[category]++; - break; // Exit loop early if matched + break; } } }); @@ -467,7 +480,9 @@ const generateData = (mitredData: MitreDataArray) => { { name: 'Potential', value: failedCounts.Potential, color: '#f28e2c' }, { name: 'Other', - value: mitredData.length - (failedCounts.Malicious + failedCounts.Potential), + value: + mitredData.length - + (failedCounts.Malicious + failedCounts.Potential), color: '#A0A0A0', }, ]; @@ -668,12 +683,7 @@ const SummaryDashboard = ({ model }: any) => { name: 'Incorrect', value: malwareStats?.incorrect_mc_count ?? 0, color: '#C23B22', - }, - { - name: 'Parsing Error', - value: malwareStats?.response_parsing_error_count ?? 0, - color: '#f28e2c', - }, + } ]; const malwareTotal = @@ -695,17 +705,7 @@ const SummaryDashboard = ({ model }: any) => { name: 'Incorrect', value: threatIntelStats?.incorrect_mc_count ?? 0, color: '#C23B22', - }, - { - name: 'Parsing Error', - value: threatIntelStats?.response_parsing_error_count ?? 0, - color: '#f28e2c', - }, - { - name: 'Fail to Query', - value: threatIntelStats?.fail_to_query_count ?? 0, - color: '#9e9e9e', - }, + } ]; const threatIntelTotal = @@ -1812,6 +1812,7 @@ const SummaryDashboard = ({ model }: any) => { <>