import { useState } from "react"; import { useParams, useNavigate } from "react-router-dom"; import MarkdownText from "../components/MarkdownText"; import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"; import { Loader2, AlertCircle, ArrowLeft, CheckCircle, Clock, Shield, FileText, ExternalLink, Plus, AlertTriangle, BookOpen, FlaskConical, ChevronDown, ChevronUp, Radar, } from "lucide-react"; import { getTechniqueByMitreId, markTechniqueReviewed } from "../api/techniques"; import { getTemplatesByTechnique } from "../api/test-templates"; import { useAuth } from "../context/AuthContext"; import TestFromTemplateForm from "../components/TestFromTemplateForm"; import JiraLinkPanel from "../components/JiraLinkPanel"; import type { TechniqueStatus, TestState, TestResult } from "../types/models"; const statusBadgeColors: Record = { validated: "bg-green-900/50 text-green-400 border-green-500/30", partial: "bg-yellow-900/50 text-yellow-400 border-yellow-500/30", in_progress: "bg-blue-900/50 text-blue-400 border-blue-500/30", not_covered: "bg-red-900/50 text-red-400 border-red-500/30", not_evaluated: "bg-gray-800/50 text-gray-400 border-gray-600/30", review_required: "bg-orange-900/50 text-orange-400 border-orange-500/30", }; const testStateBadgeColors: Record = { draft: "bg-gray-800/50 text-gray-400 border-gray-600/30", red_executing: "bg-orange-900/50 text-orange-400 border-orange-500/30", blue_evaluating: "bg-indigo-900/50 text-indigo-400 border-indigo-500/30", in_review: "bg-blue-900/50 text-blue-400 border-blue-500/30", validated: "bg-green-900/50 text-green-400 border-green-500/30", rejected: "bg-red-900/50 text-red-400 border-red-500/30", }; const testResultBadgeColors: Record = { detected: "bg-green-900/50 text-green-400 border-green-500/30", not_detected: "bg-red-900/50 text-red-400 border-red-500/30", partially_detected: "bg-yellow-900/50 text-yellow-400 border-yellow-500/30", }; export default function TechniqueDetailPage() { const { mitreId } = useParams<{ mitreId: string }>(); const navigate = useNavigate(); const queryClient = useQueryClient(); const { user } = useAuth(); const [templateFormId, setTemplateFormId] = useState(null); const canReview = user?.role === "admin" || user?.role === "red_lead" || user?.role === "blue_lead"; const { data: technique, isLoading, error, } = useQuery({ queryKey: ["technique", mitreId], queryFn: () => getTechniqueByMitreId(mitreId!), enabled: !!mitreId, }); const { data: templates = [], isLoading: isTemplatesLoading } = useQuery({ queryKey: ["templates-for-technique", mitreId], queryFn: () => getTemplatesByTechnique(mitreId!), enabled: !!mitreId, }); const reviewMutation = useMutation({ mutationFn: () => markTechniqueReviewed(mitreId!), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["technique", mitreId] }); queryClient.invalidateQueries({ queryKey: ["techniques"] }); }, }); if (isLoading) { return (
); } if (error || !technique) { return (

Failed to load technique

); } const formatDate = (dateStr: string | null) => { if (!dateStr) return "—"; return new Date(dateStr).toLocaleDateString("en-US", { year: "numeric", month: "short", day: "numeric", hour: "2-digit", minute: "2-digit", }); }; return (
{/* Back button */} {/* Header */}

{technique.mitre_id}

{technique.status_global.replace(/_/g, " ")} {technique.review_required && ( Review Required )}

{technique.name}

{canReview && technique.review_required && ( )}
{/* Review required banner */} {technique.review_required && (

This technique has been updated in MITRE ATT&CK

The MITRE ATT&CK sync detected changes to this technique. {technique.mitre_last_modified && ( <> Last modified in ATT&CK: {technique.mitre_last_modified.slice(0, 10)}. )} {" "}A lead or admin should review the changes and click{" "} Mark as Reviewed to acknowledge them.

{!canReview && ( Leads only )}
)} {/* Info Section */}
{/* Description */}

Description

{/* Metadata */}

Details

Tactic
{technique.tactic?.replace(/-/g, " ") || "—"}
Platforms
{technique.platforms && technique.platforms.length > 0 ? ( technique.platforms.map((p) => ( {p} )) ) : ( )}
Subtechnique
{technique.is_subtechnique ? `Yes (${technique.parent_mitre_id})` : "No"}
Last Review
{formatDate(technique.last_review_date)}
MITRE Version
{technique.mitre_version || "—"}
{/* Tests Section */}

Associated Tests

{technique.tests && technique.tests.length > 0 ? (
{technique.tests.map((test) => ( ))}
Name State Result Platform Created Actions
{test.name} {test.state.replace(/_/g, " ")} {test.result ? ( {test.result.replace(/_/g, " ")} ) : ( )} {test.platform || "—"} {formatDate(test.created_at)}
) : (

No tests have been created for this technique yet.

)}
{/* Detection Rules Section */} {/* Available Test Templates Section */}

Available Test Templates

{isTemplatesLoading ? (
) : templates.length > 0 ? (
{templates.map((tpl) => { // ── Derive test status for this technique ────────────── const allTests = (technique as any).tests ?? []; // Any test currently in a non-terminal state const ACTIVE_STATES: TestState[] = [ "draft", "red_executing", "blue_evaluating", "in_review", ]; const activeTest = allTests.find( (t: { state: TestState }) => ACTIVE_STATES.includes(t.state) ) ?? null; // Most recent validated test const latestValidated: { id: string; detection_result: TestResult | null; updated_at: string | null; created_at: string; } | null = [...allTests] .filter((t: { state: TestState }) => t.state === "validated") .sort((a: { updated_at: string | null; created_at: string }, b: { updated_at: string | null; created_at: string }) => (b.updated_at || b.created_at).localeCompare(a.updated_at || a.created_at) )[0] ?? null; // Coverage is stale if the sync job raised the review flag // (only meaningful when we already have a validated test) const isStale = technique.review_required && !!latestValidated; // ── Helpers ──────────────────────────────────────────── const ACTIVE_LABEL: Partial> = { draft: "Draft", red_executing: "Executing", blue_evaluating: "Evaluating", in_review: "In Review", }; const detResult = latestValidated?.detection_result; const detBadgeStyle = detResult === "detected" ? "border-green-500/30 bg-green-500/10 text-green-400" : detResult === "partially_detected" ? "border-yellow-500/30 bg-yellow-500/10 text-yellow-400" : detResult === "not_detected" ? "border-red-500/30 bg-red-500/10 text-red-400" : "border-gray-600/30 bg-gray-800/50 text-gray-400"; const detLabel = detResult === "detected" ? "Detected" : detResult === "partially_detected" ? "Partial" : detResult === "not_detected" ? "Not detected" : "Validated"; const needsReRun = !activeTest && latestValidated && (detResult !== "detected" || isStale); return (
{/* Left: template info */}

{tpl.name}

{tpl.source === "atomic_red_team" ? "Atomic" : tpl.source} {tpl.platform && ( {tpl.platform} )} {tpl.severity && ( {tpl.severity} )}
{/* Right: status + action */}
{/* ── Status badge ── */} {activeTest && ( {ACTIVE_LABEL[activeTest.state as TestState] ?? activeTest.state.replace(/_/g, " ")} )} {!activeTest && latestValidated && (
{detResult === "detected" ? : } {detLabel} {isStale && ( ⚠ Coverage may be stale )}
)} {/* ── Action button ── */} {activeTest ? ( ) : ( )}
); })}
) : (

No test templates available for this technique.

)}
{/* Recommended Defenses (D3FEND) */} {technique.d3fend_defenses && technique.d3fend_defenses.length > 0 && ( )} {/* Intel Items Section */} {technique.intel_items && technique.intel_items.length > 0 && (

Threat Intelligence

{technique.intel_items.map((intel) => (

{intel.title || intel.url}

{intel.source && {intel.source} • } Detected {formatDate(intel.detected_at)}

View
))}
)} {/* Jira Integration */} {technique && ( )} {/* Template instantiation modal */} {templateFormId && technique && ( setTemplateFormId(null)} /> )}
); } // ── Detection Rules Section ─────────────────────────────────────────── interface DetectionRule { id: string; title: string; description: string | null; source: string; source_id: string | null; source_url: string | null; rule_format: string; severity: string | null; platforms: string[]; false_positive_rate: string | null; } const severityColors: Record = { critical: "bg-red-900/40 text-red-400 border-red-500/30", high: "bg-orange-900/40 text-orange-400 border-orange-500/30", medium: "bg-yellow-900/40 text-yellow-400 border-yellow-500/30", low: "bg-blue-900/40 text-blue-400 border-blue-500/30", informational: "bg-gray-800/60 text-gray-400 border-gray-600/30", }; const sourceColors: Record = { sigma: "bg-purple-900/40 text-purple-400 border-purple-500/30", elastic: "bg-blue-900/40 text-blue-400 border-blue-500/30", splunk: "bg-orange-900/40 text-orange-400 border-orange-500/30", custom: "bg-cyan-900/40 text-cyan-400 border-cyan-500/30", }; function DetectionRulesSection({ rules }: { rules: DetectionRule[] }) { const [expandedId, setExpandedId] = useState(null); return (

Detection Rules

0 ? "border-cyan-500/30 bg-cyan-900/40 text-cyan-400" : "border-gray-600/30 bg-gray-800/50 text-gray-500" }`} > {rules.length} rule{rules.length !== 1 ? "s" : ""}
{rules.length === 0 ? (

No detection rules linked to this technique.

) : (
{rules.map((rule) => { const isExpanded = expandedId === rule.id; const sevColor = severityColors[rule.severity ?? ""] ?? severityColors.informational; const srcColor = sourceColors[rule.source] ?? sourceColors.custom; return (
setExpandedId(isExpanded ? null : rule.id)} >
{/* Severity dot */}
{/* Title */} {rule.title} {/* Badges */}
{rule.severity && ( {rule.severity} )} {rule.source} {rule.rule_format.replace("_yaml", "").toUpperCase()} {isExpanded ? ( ) : ( )}
{isExpanded && (
e.stopPropagation()} > {rule.description && ( )}
{rule.rule_format && ( Format: {rule.rule_format} )} {rule.false_positive_rate && ( False positives: {rule.false_positive_rate} )} {rule.platforms && rule.platforms.length > 0 && ( Platforms: {rule.platforms.join(", ")} )} {rule.source_id && ( Source ID: {rule.source_id} )}
{rule.source_url && ( View source rule )}
)}
); })}
)}
); } // ── D3FEND Section ──────────────────────────────────────────────────── function D3FENDSection({ defenses }: { defenses: Array<{ id: string; d3fend_id: string; name: string; description?: string | null; tactic?: string | null; d3fend_url?: string | null; }> }) { const [expandedId, setExpandedId] = useState(null); const grouped: Record = {}; for (const def of defenses) { const tactic = def.tactic || "Other"; if (!grouped[tactic]) grouped[tactic] = []; grouped[tactic].push(def); } const tacticColors: Record = { Detect: "border-blue-500/30 bg-blue-900/20 text-blue-400", Harden: "border-emerald-500/30 bg-emerald-900/20 text-emerald-400", Isolate: "border-purple-500/30 bg-purple-900/20 text-purple-400", Deceive: "border-amber-500/30 bg-amber-900/20 text-amber-400", Evict: "border-red-500/30 bg-red-900/20 text-red-400", Model: "border-cyan-500/30 bg-cyan-900/20 text-cyan-400", }; const tacticDescriptions: Record = { Detect: "Techniques for identifying adversary activity through monitoring and analysis.", Harden: "Techniques for strengthening systems to reduce the attack surface.", Isolate: "Techniques for containing threats by limiting communication and access.", Deceive: "Techniques that use deception to mislead adversaries.", Evict: "Techniques for removing adversary presence from systems.", Model: "Techniques for understanding and mapping the environment.", }; return (

Recommended Defenses (D3FEND)

{defenses.length} countermeasure{defenses.length !== 1 ? "s" : ""}
{Object.entries(grouped).map(([tactic, defs]) => (

{tactic}

{tacticDescriptions[tactic] && (

{tacticDescriptions[tactic]}

)}
{defs.map((def) => { const isExpanded = expandedId === def.id; return (
setExpandedId(isExpanded ? null : def.id)} >

{def.d3fend_id} {def.name}

{isExpanded ? ( ) : ( )}
{isExpanded && (
{def.description ? ( ) : (

No description available.

)}
Tactic: {def.tactic || "Unknown"} ID: {def.d3fend_id}
{def.d3fend_url && ( e.stopPropagation()} className="inline-flex items-center gap-1.5 text-xs text-cyan-400 hover:text-cyan-300 hover:underline mt-1" > View on MITRE D3FEND )}
)}
); })}
))}
); }