fix: D3FEND expandable cards, System page cleanup, and multi-source improvements

- Make D3FEND defense cards clickable with expandable details and external link
- Fix D3FEND URLs to use PascalCase technique names matching the ontology
- Remove duplicate Import Atomic Red Team from System page (use Data Sources)
- Add bulk Activate All / Deactivate All buttons with confirmation modal
- Fix template admin list to show both active and inactive templates
- Add PATCH /test-templates/bulk-activate backend endpoint
- Auto-seed data sources on container startup via entrypoint.sh
- Fix SigmaHQ, CALDERA, GTFOBins import issues
- Register D3FEND sync handler in data sources router
- Add CIS Controls v8 compliance framework import
- Expand Test Catalog source filters (CALDERA, LOLBAS, GTFOBins)
- Campaign Generate from Threat Actor now opens actor selector modal
- Add coverage snapshot creation button to Comparison page
- Update README with accurate data source and feature documentation
This commit is contained in:
2026-02-10 13:22:23 +01:00
parent 8032b67fab
commit c2e9c687f4
19 changed files with 778 additions and 197 deletions

View File

@@ -1,17 +1,23 @@
import { useState } from "react";
import { useQuery } from "@tanstack/react-query";
import { Loader2, AlertCircle, Download, FileText } from "lucide-react";
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
import { Loader2, AlertCircle, Download, FileText, Plus } from "lucide-react";
import {
getComplianceFrameworks,
getFrameworkStatus,
downloadComplianceCSV,
importNistMappings,
importCisMappings,
type ComplianceFrameworkSummary,
} from "../api/compliance";
import { useAuth } from "../context/AuthContext";
import ComplianceGauge from "../components/compliance/ComplianceGauge";
import ControlsTable from "../components/compliance/ControlsTable";
export default function CompliancePage() {
const [selectedFrameworkId, setSelectedFrameworkId] = useState<string | null>(null);
const queryClient = useQueryClient();
const { user } = useAuth();
const isAdmin = user?.role === "admin";
// Fetch available frameworks
const {
@@ -59,6 +65,24 @@ export default function CompliancePage() {
URL.revokeObjectURL(url);
};
const importNist = useMutation({
mutationFn: importNistMappings,
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ["compliance-frameworks"] });
queryClient.invalidateQueries({ queryKey: ["compliance-status"] });
},
});
const importCis = useMutation({
mutationFn: importCisMappings,
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ["compliance-frameworks"] });
queryClient.invalidateQueries({ queryKey: ["compliance-status"] });
},
});
const isImporting = importNist.isPending || importCis.isPending;
if (isLoading && !frameworkStatus) {
return (
<div className="flex h-64 items-center justify-center">
@@ -171,6 +195,35 @@ export default function CompliancePage() {
</div>
)}
{/* Import buttons for admin */}
{isAdmin && (
<div className="flex flex-wrap items-center gap-2">
<span className="text-xs text-gray-500">Import frameworks:</span>
<button
onClick={() => importNist.mutate()}
disabled={isImporting}
className="flex items-center gap-1.5 rounded-lg border border-gray-700 bg-gray-800 px-3 py-1.5 text-xs font-medium text-gray-300 hover:border-cyan-500/50 hover:text-white transition-colors disabled:opacity-50"
>
{importNist.isPending ? <Loader2 className="h-3 w-3 animate-spin" /> : <Plus className="h-3 w-3" />}
NIST 800-53
</button>
<button
onClick={() => importCis.mutate()}
disabled={isImporting}
className="flex items-center gap-1.5 rounded-lg border border-gray-700 bg-gray-800 px-3 py-1.5 text-xs font-medium text-gray-300 hover:border-cyan-500/50 hover:text-white transition-colors disabled:opacity-50"
>
{importCis.isPending ? <Loader2 className="h-3 w-3 animate-spin" /> : <Plus className="h-3 w-3" />}
CIS Controls v8
</button>
{(importNist.isSuccess || importCis.isSuccess) && (
<span className="text-xs text-green-400">Import complete</span>
)}
{(importNist.isError || importCis.isError) && (
<span className="text-xs text-red-400">Import failed</span>
)}
</div>
)}
{/* Controls table */}
{controls.length > 0 ? (
<ControlsTable controls={controls} />
@@ -179,7 +232,7 @@ export default function CompliancePage() {
<div className="rounded-xl border border-gray-800 bg-gray-900 p-8 text-center">
<AlertCircle className="mx-auto h-10 w-10 text-gray-600" />
<p className="mt-3 text-gray-400">
No compliance data available. Import a compliance framework from the System page.
No compliance data available. Use the import buttons above to load a compliance framework.
</p>
</div>
)