diff --git a/ui/components/RecentAlerts.tsx b/ui/components/RecentAlerts.tsx index 0c476b8..e966d44 100644 --- a/ui/components/RecentAlerts.tsx +++ b/ui/components/RecentAlerts.tsx @@ -68,11 +68,11 @@ const RecentAlerts: React.FC = ({ alerts }) => {
- + {alert.sourceIp} - + {alert.destinationIp}
diff --git a/ui/components/TopThreats.tsx b/ui/components/TopThreats.tsx index cb9fd1b..af6851b 100644 --- a/ui/components/TopThreats.tsx +++ b/ui/components/TopThreats.tsx @@ -45,7 +45,7 @@ const TopThreats: React.FC = ({ threats }) => {

{threat.evidence}

- MITRE: {threat.category} + MITRE: {threat.category}
diff --git a/ui/components/dashboard/ProtocolDistribution.tsx b/ui/components/dashboard/ProtocolDistribution.tsx index 80e10af..18081b7 100644 --- a/ui/components/dashboard/ProtocolDistribution.tsx +++ b/ui/components/dashboard/ProtocolDistribution.tsx @@ -51,7 +51,7 @@ const ProtocolDistribution: React.FC = ({ protocols, onBarClick }) => { )}
- {p.percentage}% + {p.percentage}%

{p.volume}

diff --git a/ui/components/dashboard/RecentAlertsTable.tsx b/ui/components/dashboard/RecentAlertsTable.tsx index aa54a02..f407ab8 100644 --- a/ui/components/dashboard/RecentAlertsTable.tsx +++ b/ui/components/dashboard/RecentAlertsTable.tsx @@ -60,7 +60,7 @@ const RecentAlertsTable: React.FC = ({ alerts, onAlertClick }) => {

{alert.name}

{alert.mitreTactic}

- + {alert.sourceIp} {alert.destinationIp} diff --git a/ui/components/detections/AlertCard.tsx b/ui/components/detections/AlertCard.tsx index a7d7635..aef7ddc 100644 --- a/ui/components/detections/AlertCard.tsx +++ b/ui/components/detections/AlertCard.tsx @@ -53,7 +53,7 @@ const AlertCard: React.FC = ({ alert, onViewDetails }) => {

{alert.name}

-
+
{alert.sourceIp} {alert.assetContext?.hostname && ( diff --git a/ui/components/investigations/InvestigationAnalytics.tsx b/ui/components/investigations/InvestigationAnalytics.tsx index 645115d..7869507 100644 --- a/ui/components/investigations/InvestigationAnalytics.tsx +++ b/ui/components/investigations/InvestigationAnalytics.tsx @@ -1,10 +1,8 @@ - import React, { useState } from 'react'; import { TrendingUp, TrendingDown, Clock, ShieldCheck, AlertCircle, Users, Activity, BarChart2, PieChart as PieChartIcon, Download, Settings2, Target, Zap, Brain, CheckCircle2, - // Comment: Fixed missing 'ArrowRight' icon import ChevronRight, ArrowUpRight, ArrowRight } from 'lucide-react'; import { @@ -21,17 +19,17 @@ const TIMELINE_DATA = Array.from({ length: 30 }, (_, i) => ({ const STATUS_DIST = [ { name: 'New', value: 5, color: '#3b82f6' }, - { name: 'Active', value: 12, color: '#06b6d4' }, + { name: 'Active', value: 12, color: '#3b82f6' }, { name: 'Escalated', value: 2, color: '#ef4444' }, - { name: 'On Hold', value: 3, color: '#6b7280' }, - { name: 'Closed', value: 45, color: '#10b981' }, + { name: 'On Hold', value: 3, color: '#71717a' }, + { name: 'Closed', value: 45, color: '#22c55e' }, ]; const SEVERITY_MTTR = [ { name: 'Critical', target: 2, actual: 2.1, color: '#ef4444' }, { name: 'High', target: 4, actual: 4.5, color: '#f97316' }, { name: 'Medium', target: 8, actual: 8.2, color: '#eab308' }, - { name: 'Low', target: 24, actual: 12.3, color: '#10b981' }, + { name: 'Low', target: 24, actual: 12.3, color: '#3b82f6' }, ]; const ANALYST_WORKLOAD = [ @@ -45,25 +43,31 @@ const InvestigationAnalytics: React.FC = () => { const [timeRange, setTimeRange] = useState('LAST 30D'); return ( -
+
{/* Filters Header */} -
-
+
+
{['LAST 24H', 'LAST 7D', 'LAST 30D', 'LAST 90D', 'CUSTOM'].map(r => ( ))}
- - +
@@ -72,240 +76,256 @@ const InvestigationAnalytics: React.FC = () => { {[ { label: 'ACTIVE CASES', val: '12', trend: '+3', good: false, sub: 'vs last week', icon: Activity, color: 'text-white' }, { label: 'AVG RESOLUTION', val: '4.2h', trend: '-1.3h', good: true, sub: 'Target: 6.0h', icon: Clock, color: 'text-[#00D4AA]' }, - { label: 'CLOSED (30D)', val: '45', trend: '+12', good: true, sub: 'vs last 30d', icon: ShieldCheck, color: 'text-blue-400' }, - { label: 'SLA BREACH', val: '3.2%', trend: '-1.5%', good: true, sub: 'Global Compliance', icon: AlertCircle, color: 'text-red-500' }, + { label: 'CLOSED (30D)', val: '45', trend: '+12', good: true, sub: 'vs last 30d', icon: ShieldCheck, color: 'text-white' }, + { label: 'SLA BREACH', val: '3.2%', trend: '-1.5%', good: true, sub: 'Global Compliance', icon: AlertCircle, color: 'text-white' }, ].map((m, i) => ( -
+

{m.label}

- +
-
-

{m.val}

-
+
+

{m.val}

+
{m.trend.startsWith('+') ? : } {m.trend}
-

{m.sub}

+

{m.sub}

))}
{/* Analytics Grid */} -
+
{/* LEFT COLUMN: Distribution */} -
-
-

Case Status Distribution

-
- - - - {STATUS_DIST.map((entry, index) => )} - - - -
-

Total

-

27

+
+
+

+ Case Status Distribution + +

+
+ + + + {STATUS_DIST.map((entry, index) => )} + + + +
+

Total

+

27

+
+
+
+ {STATUS_DIST.map(s => ( +
+
+
+ {s.name} +
+ {s.value}
-
-
- {STATUS_DIST.map(s => ( -
-
-
- {s.name} -
- {s.value} -
- ))} -
-

Average case age: 8.5 hours

+ ))} +
+

+ Average case age: 8.5 hours +

-
-

Severity vs Resolution

-
- {SEVERITY_MTTR.map(s => ( -
-
- {s.name} - MTTR: {s.actual}h -
-
-
-
-
- ))} -
+
+

Severity vs Resolution

+
+ {SEVERITY_MTTR.map(s => ( +
+
+ {s.name} + MTTR: {s.actual}h +
+
+
+
+
+ ))} +
-
-

Top Investigated Tactics

-
- {[ - { name: 'Command & Control', count: 12, pct: 45, color: '#ef4444' }, - { name: 'Lateral Movement', count: 8, pct: 30, color: '#f97316' }, - { name: 'Exfiltration', count: 5, pct: 15, color: '#eab308' }, - { name: 'Discovery', count: 2, pct: 10, color: '#3b82f6' }, - ].map(t => ( -
-
-
- {t.name} - {t.count} -
-
-
-
-
- -
- ))} -
+
+

Top Investigated Tactics

+
+ {[ + { name: 'Command & Control', count: 12, pct: 45, color: '#ef4444' }, + { name: 'Lateral Movement', count: 8, pct: 30, color: '#f97316' }, + { name: 'Exfiltration', count: 5, pct: 15, color: '#eab308' }, + { name: 'Discovery', count: 2, pct: 10, color: '#3b82f6' }, + ].map(t => ( +
+
+
+ {t.name} + {t.count} +
+
+
+
+
+ +
+ ))} +
{/* MIDDLE COLUMN: Trends & MTTR */} -
-
-
-

Case Volume Trend

-
-
Opened
-
Closed
+
+
+
+

Case Volume Trend

+
+
+
+ Opened
-
-
- - - - - - - - - - - -
-

- Backlog growing by avg +2 cases/week -

+
+
+ Closed +
+
+
+
+ + + + + + + + + + + +
+

+ Backlog growing by avg +2 cases/week +

-
-

Mean Time to Resolve (Actual vs Target)

-
- - - - - - - - - - -
-
-

SLA Compliance: 96.8% ✅

- -
+
+

Mean Time to Resolve (Actual vs Target)

+
+ + + + + + + + + + +
+
+

SLA Compliance: 96.8% ✅

+ +
-
-

SLA Performance Summary

-
-
-

44

-

Met SLA

-
-
-

1

-

Breached

-
-
-

+2.5h

-

Avg Margin

-
-
- +
+

SLA Performance Summary

+
+
+

44

+

Met SLA

+
+
+

1

+

Breached

+
+
+

+2.5h

+

Avg Margin

+
+
+
{/* RIGHT COLUMN: Team & Insights */} -
-
-
-

Analyst Workload

- -
-
- {ANALYST_WORKLOAD.map(a => ( -
-
-
-

{a.name}

-

{a.total} Cases • Avg age {a.age}h

-
-
- {Array.from({length: a.critical}).map((_, i) =>
)} - {Array.from({length: a.high}).map((_, i) =>
)} - {Array.from({length: a.medium}).map((_, i) =>
)} -
-
-
-
4 ? 'bg-red-500' : 'bg-blue-500'}`} style={{ width: `${(a.total / 6) * 100}%` }} /> -
-
- ))} -
+
+
+
+

+ Analyst Workload +

+ +
+
+ {ANALYST_WORKLOAD.map(a => ( +
+
+
+

{a.name}

+

{a.total} Cases • Avg age {a.age}h

+
+
+ {Array.from({length: a.critical}).map((_, i) =>
)} + {Array.from({length: a.high}).map((_, i) =>
)} + {Array.from({length: a.medium}).map((_, i) =>
)} +
+
+
+
4 ? 'bg-red-500' : 'bg-blue-500'}`} style={{ width: `${(a.total / 6) * 100}%` }} /> +
+
+ ))} +
-
- {/*
- -
*/} -

Intelligence Insights

-
-
-

⚠️ Backlog Growing

-

Active cases increased 25% over last 2 weeks. Capacity re-evaluation recommended.

-
-
-

✅ Resolution Velocity

-

MTTR decreased by 18% month-over-month. Credited to improved playbooks.

-
-
-

💡 False Positive Risk

-

33% of cases closed as FP. Review "DNS-TUNNEL-01" rule logic.

-
-
- +
+

+ Intelligence Insights +

+
+
+

⚠️ Backlog Growing

+

Active cases increased 25% over last 2 weeks. Capacity re-evaluation recommended.

+
+
+

✅ Resolution Velocity

+

MTTR decreased by 18% month-over-month. Credited to improved playbooks.

+
+
+

💡 False Positive Risk

+

33% of cases closed as FP. Review "DNS-TUNNEL-01" rule logic.

+
+
+
-
-

Mean Response Metrics

-
-
-

12m

-

MTTA

-
-
-

3.2h

-

MTTI

-
-
-

1.8h

-

MTTR

-
-
-
- Efficiency increased by 18% -
+
+

Mean Response Metrics

+
+
+

12m

+

MTTA

+
+
+

3.2h

+

MTTI

+
+
+

1.8h

+

MTTR

+
+
+
+ Efficiency increased by 18% +
@@ -313,4 +333,4 @@ const InvestigationAnalytics: React.FC = () => { ); }; -export default InvestigationAnalytics; +export default InvestigationAnalytics; \ No newline at end of file diff --git a/ui/components/investigations/InvestigationList.tsx b/ui/components/investigations/InvestigationList.tsx index 89bab39..68eb2cc 100644 --- a/ui/components/investigations/InvestigationList.tsx +++ b/ui/components/investigations/InvestigationList.tsx @@ -48,45 +48,45 @@ const InvestigationList: React.FC = ({ onSelectCase }) => { const getStatusColor = (status: string) => { switch (status.toLowerCase()) { case 'active': - return 'bg-blue-500/20 text-blue-400 border-blue-500/30'; + return 'bg-blue-500/10 border-blue-500/20 text-blue-500'; case 'new': - return 'bg-emerald-500/20 text-emerald-400 border-emerald-500/30'; + return 'bg-green-500/10 border-green-500/20 text-green-500'; case 'pending': - return 'bg-yellow-500/20 text-yellow-400 border-yellow-500/30'; + return 'bg-yellow-500/10 border-yellow-500/20 text-yellow-500'; case 'resolved': - return 'bg-zinc-500/20 text-zinc-400 border-zinc-500/30'; + return 'bg-zinc-500/10 border-zinc-500/20 text-zinc-500'; default: - return 'bg-zinc-500/20 text-zinc-400 border-zinc-500/30'; + return 'bg-zinc-500/10 border-zinc-500/20 text-zinc-500'; } }; const getPriorityColor = (priority: string) => { switch (priority.toLowerCase()) { case 'critical': - return 'bg-red-500/20 text-red-400 border-red-500/30'; + return 'bg-red-500/10 border-red-500/20 text-red-500'; case 'high': - return 'bg-orange-500/20 text-orange-400 border-orange-500/30'; + return 'bg-orange-500/10 border-orange-500/20 text-orange-500'; case 'medium': - return 'bg-yellow-500/20 text-yellow-400 border-yellow-500/30'; + return 'bg-yellow-500/10 border-yellow-500/20 text-yellow-500'; case 'low': - return 'bg-zinc-500/20 text-zinc-400 border-zinc-500/30'; + return 'bg-blue-500/10 border-blue-500/20 text-blue-500'; default: - return 'bg-zinc-500/20 text-zinc-400 border-zinc-500/30'; + return 'bg-zinc-500/10 border-zinc-500/20 text-zinc-500'; } }; return ( -
+
{/* Filter Bar */}
{/* Search Field */} -
- +
+ setSearchTerm(e.target.value)} /> @@ -95,7 +95,7 @@ const InvestigationList: React.FC = ({ onSelectCase }) => { {/* Log Source Dropdown */}
- +
{openDropdown === 'log' && ( -
+
{['Conn', 'DNS', 'SSL', 'HTTP', 'Files', 'DHCP'].map(source => (
{openDropdown === 'mitre' && ( -
+
{[ 'Lateral Movement', 'Command & Control', @@ -162,7 +162,7 @@ const InvestigationList: React.FC = ({ onSelectCase }) => { {/* Asset Group Dropdown */}
- +
{openDropdown === 'asset' && ( -
+
{['All Segments', 'Engineering', 'Production', 'Management', 'Guest WiFi', 'DMZ'].map(group => (
{openDropdown === 'horizon' && ( -
+
{['Last 1 Hour', 'Last 24 Hours', 'Last 7 Days', 'Last 30 Days', 'Custom Range'].map(range => ( | -
diff --git a/ui/dist.zip b/ui/dist.zip deleted file mode 100644 index ddb0795..0000000 Binary files a/ui/dist.zip and /dev/null differ diff --git a/ui/pages/AlertDetailPage.tsx b/ui/pages/AlertDetailPage.tsx index 941a945..67e9b97 100644 --- a/ui/pages/AlertDetailPage.tsx +++ b/ui/pages/AlertDetailPage.tsx @@ -41,7 +41,7 @@ const NETWORK_ACTIVITY_DATA = [ { time: '23', value: 43, alert: false }, ]; -const AlertDetailPage: React.FC = ({ id, onBack }) => { +const DetectionDetailPage: React.FC = ({ id, onBack }) => { const [activeTab, setActiveTab] = useState('explanation'); const [behaviorTab, setBehaviorTab] = useState('network'); const [isEscalateOpen, setIsEscalateOpen] = useState(false); @@ -68,86 +68,79 @@ const AlertDetailPage: React.FC = ({ id, onBack }) => { }; return ( -
+
{/* Top Header Row */}
-
- Network Live +
+ Network Live
- {/*
- -
*/}
{/* Title Block */} -
+
-

High Entropy DNS Queries

- Zeek Analyzed +

High Entropy DNS Queries

+ + Zeek Analyzed +
-

Alert ID: {id || 'ALT-001'}

+

Alert ID: {id || 'ALT-001'}

-
- - {actionsDropdownOpen && ( -
- - - -
- )} -
-
- - -
+
+ + {actionsDropdownOpen && ( +
+ + + +
+ )} +
+
+ +
@@ -158,117 +151,64 @@ const AlertDetailPage: React.FC = ({ id, onBack }) => {
{/* Why This Alert Was Triggered */} -
- {/* Header */} -
-
- -

- Why This Alert Was Triggered -

-
-
- - {/* Body */} -
-
- {/* Summary */} -

- This alert was triggered because the system detected - - {" "}sustained abnormal outbound data transfer behavior - - , which deviated significantly from the host’s historical baseline. -

- - {/* Detection stages */} -
-

- Detection Stages -

-
    -
  • - Anomaly detected:{" "} - Initial abnormal outbound activity was identified compared to normal behavior. -
  • -
  • - Behavior sustained:{" "} - The abnormal behavior persisted across multiple observation intervals. -
  • -
  • - Alert threshold exceeded:{" "} - Combined signal confidence crossed the alert threshold, resulting in alert generation. -
  • -
-
- - {/* Key factors */} -
-

- Key Contributing Factors -

-
    -
  • Sustained outbound volume spike
  • -
  • Abnormal upload-to-download ratio
  • -
-
- - {/* Footer note */} -

- The activity was observed consistently over a defined time window and was not a single transient spike. -

-
-
-
- - - {/* Attack Progression */} - {/*
+
+ {/* Header */}
- -

Attack Progression

+ +

+ Why This Alert Was Triggered +

- -
-
- {[ - { stage: 'Initial Activity', time: '13:40', status: 'complete', color: 'cyan' }, - { stage: 'Suspicious Behavior', time: '13:45', status: 'complete', color: 'cyan' }, - { stage: 'Escalation', time: '13:48', status: 'active', color: 'red' }, - { stage: 'Impact', time: '13:51', status: 'pending', color: 'red' }, - ].map((item, idx) => ( - - - {idx < 3 && ( -
- )} -
- ))} + + {/* Body */} +
+ {/* Summary */} +

+ This alert was triggered because the system detected + + {" "}sustained abnormal outbound data transfer behavior + + , which deviated significantly from the host's historical baseline. +

+ + {/* Detection stages */} +
+

+ Detection Stages +

+
    +
  • + Anomaly detected:{" "} + Initial abnormal outbound activity was identified compared to normal behavior. +
  • +
  • + Behavior sustained:{" "} + The abnormal behavior persisted across multiple observation intervals. +
  • +
  • + Alert threshold exceeded:{" "} + Combined signal confidence crossed the alert threshold, resulting in alert generation. +
  • +
+
+ + {/* Key factors */} +
+

+ Key Contributing Factors +

+
    +
  • Sustained outbound volume spike
  • +
  • Abnormal upload-to-download ratio
  • +
-
*/} +
{/* Attack Timeline - Detailed Signal Observations */} -
+
@@ -277,117 +217,119 @@ const AlertDetailPage: React.FC = ({ id, onBack }) => {
-
- {/* Timeline Item 1 */} -
openSidebar('signal-outbound')} className="flex gap-3 cursor-pointer"> -
-
- 1 -
-
-
- -
-
- Initial Activity - 13:40 -
- -
-
-
-
-
Outbound Volume Spike
-
The host sent significantly more data than it normally does.
-
-
-
-
-
- - {/* Timeline Item 2 */} -
openSidebar('signal-ratio')} className="flex gap-3 cursor-pointer"> -
-
- 2 -
-
-
- -
-
- Initial Activity - 13:40 -
- -
-
-
-
-
Outbound Volume Spike
-
The host sent significantly more data than it normally does.
-
-
-
-
-
- - {/* Timeline Item 3 */} -
-
-
- 3 -
-
-
- -
-
- Initial Activity - 13:40 -
- -
-
-
-
-
Outbound Volume Spike
-
-
-
-
-
- - {/* Timeline Item 4 - Final */} -
-
-
- 4 -
-
- -
-
- Initial Activity - 13:40 -
- -
-
-
-
-
Triggered Rule
-
-
-
-
-
-
+
+ {/* Timeline Item 1 */} +
openSidebar('signal-outbound')} className="flex gap-3 cursor-pointer hover:bg-zinc-900/30 transition-colors rounded-lg p-2 -ml-2"> +
+
+ 1 +
+
+
+ +
+
+ Initial Activity + 13:40 +
+ +
+
+
+
+
Outbound Volume Spike
+
The host sent significantly more data than it normally does.
+
+
+
+
+
+ + {/* Timeline Item 2 */} +
openSidebar('signal-ratio')} className="flex gap-3 cursor-pointer hover:bg-zinc-900/30 transition-colors rounded-lg p-2 -ml-2"> +
+
+ 2 +
+
+
+ +
+
+ Suspicious Behavior + 13:45 +
+ +
+
+
+
+
Upload/Download Ratio Shift
+
Unusual upload pattern detected compared to downloads.
+
+
+
+
+
+ + {/* Timeline Item 3 */} +
+
+
+ 3 +
+
+
+ +
+
+ Escalation + 13:48 +
+ +
+
+
+
+
Sustained Activity Pattern
+
Behavior persisted beyond normal threshold.
+
+
+
+
+
+ + {/* Timeline Item 4 - Final */} +
+
+
+ 4 +
+
+ +
+
+ Alert Generated + 13:51 +
+ +
+
+
+
+
Alert Threshold Triggered
+
Combined signals exceeded detection threshold.
+
+
+
+
+
+
{/* Observed Network Behavior - With Two Tabs */} -
+
@@ -400,17 +342,17 @@ const AlertDetailPage: React.FC = ({ id, onBack }) => { onClick={() => setBehaviorTab('network')} className={`flex-1 px-6 py-3 text-[10px] font-black uppercase tracking-widest transition-all ${behaviorTab === 'network' - ? 'bg-[#00D4AA10] text-[#00D4AA] border-b-2 border-[#00D4AA10]' - : 'text-zinc-500 hover:text-zinc-300 hover:bg-[#00D4AA10]'}`} + ? 'bg-[#00D4AA]/10 text-[#00D4AA] border-b-2 border-[#00D4AA]' + : 'text-zinc-500 hover:text-zinc-300 hover:bg-zinc-900/30'}`} > - Observed Network Behavior + Network Activity @@ -420,42 +362,42 @@ const AlertDetailPage: React.FC = ({ id, onBack }) => { {behaviorTab === 'network' && (
- Total Data + Total Data
-
- 2.6 GB +
+ 2.6 GB
- 12.1 + 12.1
- 45 Mbps + 45 Mbps
-
+
- + = ({ id, onBack }) => { @@ -471,7 +413,7 @@ const AlertDetailPage: React.FC = ({ id, onBack }) => {
-

+

Network traffic shifted from normal download behavior to sustained outbound data transfer.

@@ -479,28 +421,36 @@ const AlertDetailPage: React.FC = ({ id, onBack }) => { {behaviorTab === 'data' && (
-
- - - - - - - +
+
TimestampProtocolBytes SentDestination
+ + + + + + - + {[ { ts: '13:40:15', proto: 'HTTPS', bytes: '524 KB', dest: '185.12.45.23' }, { ts: '13:42:33', proto: 'HTTPS', bytes: '892 KB', dest: '185.12.45.23' }, { ts: '13:45:12', proto: 'HTTPS', bytes: '1.2 MB', dest: '185.12.45.23' }, { ts: '13:48:45', proto: 'HTTPS', bytes: '1.5 MB', dest: '185.12.45.23' }, ].map((row, i) => ( - - - - - + + + + + ))} @@ -516,7 +466,7 @@ const AlertDetailPage: React.FC = ({ id, onBack }) => {
{/* Affected Systems and Destinations */} -
+

Affected Systems and Destinations

@@ -525,39 +475,39 @@ const AlertDetailPage: React.FC = ({ id, onBack }) => { {/* Source System */} {/* Internal Systems */}
{/* What Should I Check Next */} -
+

What Should I Check Next?

@@ -598,25 +548,25 @@ const AlertDetailPage: React.FC = ({ id, onBack }) => { 'Monitor external connections for continued activity.', ].map((item, idx) => (
-
+
{idx + 1}
-

{item}

+

{item}

))}
{/* Threat Classification */} -
+

Threat Classification

-
-
Mitre Attack
-
TA0010 - Exfiltration
-

+

+
Mitre Attack
+
TA0010 - Exfiltration
+

Adversary is attempting to steal data from your network.

@@ -631,13 +581,13 @@ const AlertDetailPage: React.FC = ({ id, onBack }) => { onClick={closeSidebar} >
e.stopPropagation()} >
{/* Sidebar Header */} -
-

+
+

{(sidebarOpen === 'signal-outbound' || sidebarOpen === 'signal-ratio') && 'Signal Detail: ' + (sidebarOpen === 'signal-outbound' ? 'Outbound Volume Spike' : 'Upload/Download Ratio Shift')} {sidebarOpen === 'source' && 'Source System Details'} {sidebarOpen === 'internal' && 'Internal Systems'} @@ -651,14 +601,14 @@ const AlertDetailPage: React.FC = ({ id, onBack }) => {

{/* Sidebar Content */} -
+
{/* Signal Detail Tabs */} {(sidebarOpen === 'signal-outbound' || sidebarOpen === 'signal-ratio') && ( <> @@ -673,8 +623,8 @@ const AlertDetailPage: React.FC = ({ id, onBack }) => { onClick={() => setActiveTab(tab.id)} className={`flex-1 px-6 py-3 text-[10px] font-black uppercase tracking-widest transition-all ${activeTab === tab.id - ? 'bg-[#00D4AA10] text-[#00D4AA] border-b-2 border-[#00D4AA10]' - : 'text-zinc-500 hover:text-zinc-300 hover:bg-[#00D4AA10]'}`} + ? 'bg-[#00D4AA]/10 text-[#00D4AA] border-b-2 border-[#00D4AA]' + : 'text-zinc-500 hover:text-zinc-300 hover:bg-zinc-900/30'}`} > {tab.label} @@ -684,15 +634,15 @@ const AlertDetailPage: React.FC = ({ id, onBack }) => {
{activeTab === 'explanation' && (
-
-

+

+

{sidebarOpen === 'signal-outbound' ? '"This signal indicates that the observed network behavior deviated significantly from what is normally expected for this system over a sustained period."' : '"The host uploaded much more data than it downloaded, which is unusual for typical network behavior."' }

-

+

{sidebarOpen === 'signal-outbound' ? 'This signal indicates that the observed network behavior deviated significantly from what is normally expected for this system over a sustained period.' : 'This pattern often indicates data exfiltration where an attacker is uploading stolen data to an external server while minimizing downloads to avoid detection.' @@ -705,7 +655,7 @@ const AlertDetailPage: React.FC = ({ id, onBack }) => {

What was monitored:

-
    +
      {sidebarOpen === 'signal-outbound' ? ( <>
    • @@ -742,7 +692,7 @@ const AlertDetailPage: React.FC = ({ id, onBack }) => {

      When it is considered suspicious:

      -
        +
          {sidebarOpen === 'signal-outbound' ? ( <>
        • @@ -771,7 +721,7 @@ const AlertDetailPage: React.FC = ({ id, onBack }) => {

          Why this matters:

          -

          +

          {sidebarOpen === 'signal-outbound' ? 'This pattern is commonly associated with unauthorized data transfer or exfiltration.' : 'Unusual upload patterns often indicate data theft where attackers extract sensitive information to external servers.' @@ -784,10 +734,10 @@ const AlertDetailPage: React.FC = ({ id, onBack }) => { {activeTab === 'evidence' && (

          -
          +
          Time Window
          -
          13:40 - 13:58
          +
          13:40 - 13:58
          @@ -795,12 +745,12 @@ const AlertDetailPage: React.FC = ({ id, onBack }) => { @@ -889,13 +840,13 @@ const AlertDetailPage: React.FC = ({ id, onBack }) => {
          Evidence Summary
          -
          -
          Time Window
          -
          13:58 UTC
          +
          +
          Time Window
          +
          13:58 UTC
          -
          -
          Affected Systems
          -
          Affected system(s) and associated network logs
          +
          +
          Affected Systems
          +
          Multiple systems
          @@ -903,7 +854,7 @@ const AlertDetailPage: React.FC = ({ id, onBack }) => { {/* Why This Stage Matters */}
          Why This Stage Matters
          -

          +

          "Activity in this stage is often observed before escalation or data loss."

          @@ -925,7 +876,7 @@ const AlertDetailPage: React.FC = ({ id, onBack }) => { setIsEscalateOpen(false); }} /> -
          +
          ); }; diff --git a/ui/pages/AlertPage.tsx b/ui/pages/AlertPage.tsx index b4fa816..1dfde01 100644 --- a/ui/pages/AlertPage.tsx +++ b/ui/pages/AlertPage.tsx @@ -11,7 +11,7 @@ import { AreaChart, Area, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, Line } from 'recharts'; import { MOCK_ALERTS } from '../constants/mockData/detections'; -import AlertDetailPage from './AlertDetailPage'; +import DetectionDetailPage from './DetectionDetailPage'; import AlertCard from '../components/detections/AlertCard'; import { Severity } from '../types'; @@ -40,8 +40,6 @@ const DetectionsPage: React.FC<{ defaultView?: 'feed' | 'stats' }> = ({ defaultV useEffect(() => { setView(defaultView); }, [defaultView]); - - // Close dropdowns when clicking outside useEffect(() => { const handleClickOutside = (e: MouseEvent) => { @@ -141,7 +139,7 @@ const DetectionsPage: React.FC<{ defaultView?: 'feed' | 'stats' }> = ({ defaultV case 'medium': return 'text-yellow-500'; default: - return 'text-zinc-500'; + return 'text-blue-500'; } }; @@ -154,57 +152,57 @@ const DetectionsPage: React.FC<{ defaultView?: 'feed' | 'stats' }> = ({ defaultV case 'medium': return 'bg-yellow-500/10 border-yellow-500/20'; default: - return 'bg-zinc-500/10 border-zinc-500/20'; + return 'bg-blue-500/10 border-blue-500/20'; } }; const renderFilterHeader = () => (
          - {/* Search Bar */} + {/* Search Bar - STANDARDIZED */}
          - - - setSearchTerm(e.target.value)} - /> -
          - - {/* Filter Dropdowns Bar */} + + setSearchTerm(e.target.value)} + /> +
          + + {/* Filter Dropdowns Bar - STANDARDIZED */}
          + {/* Advanced Filter Button - STANDARDIZED */} - {/* Severity Dropdown */} + {/* Severity Dropdown - STANDARDIZED */}
          {openDropdown === 'severity' && ( -
          +
          {(['critical', 'high', 'medium'] as Severity[]).map(sev => ( @@ -213,18 +211,18 @@ const DetectionsPage: React.FC<{ defaultView?: 'feed' | 'stats' }> = ({ defaultV )}
          - {/* Asset Group Dropdown */} + {/* Asset Group Dropdown - STANDARDIZED */}
          {openDropdown === 'asset' && ( -
          +
          {['all', 'User VLAN', 'Server VLAN', 'DMZ', 'Management'].map(group => (
          - {/* MITRE Tactic Dropdown */} + {/* MITRE Tactic Dropdown - STANDARDIZED (removed purple icon) */}
          {openDropdown === 'mitre' && ( -
          +
          {['all', 'Command & Control', 'Lateral Movement', 'Exfiltration', 'Defense Evasion', 'Credential Access'].map(tactic => (
          - {/* Log Source Dropdown */} + {/* Log Source Dropdown - STANDARDIZED (kept green for status) */}
          {openDropdown === 'log' && ( -
          +
          {['all', 'Zeek', 'Suricata', 'Sysmon', 'Windows Events', 'Linux Auditd'].map(source => (
          - {/* Directionality Dropdown */} + {/* Directionality Dropdown - STANDARDIZED (changed cyan to zinc) */}
          {openDropdown === 'direction' && ( -
          +
          {['all', 'North-South', 'East-West', 'Internal', 'External'].map(dir => (
          - {/* Time Range Dropdown */} + {/* Time Range Dropdown - STANDARDIZED */}
          {openDropdown === 'time' && ( -
          +
          {[ { value: '1h', label: 'Last 1 Hour' }, { value: '24h', label: 'Last 24 Hours' }, @@ -359,7 +357,7 @@ const DetectionsPage: React.FC<{ defaultView?: 'feed' | 'stats' }> = ({ defaultV
          - {/* Active Filters */} + {/* Active Filters - STANDARDIZED */} {activeFilters.length > 0 && (
          FILTERS APPLIED: @@ -391,187 +389,192 @@ const DetectionsPage: React.FC<{ defaultView?: 'feed' | 'stats' }> = ({ defaultV const renderDetectionTable = () => (

TimestampProtocolBytes SentDestination
{row.ts}{row.proto}{row.bytes}{row.dest}
+ {row.ts} + + {row.proto} + + {row.bytes} + + {row.dest} +
- - - - - - - - - - - - - - {filteredAlerts.length > 0 ? ( - filteredAlerts.slice(0, 10).map((alert) => ( - setSelectedAlertId(alert.id)} - > - - - - - - - - + + + + + + + + + + + + + {filteredAlerts.length > 0 ? ( + filteredAlerts.slice(0, 10).map((alert) => ( + setSelectedAlertId(alert.id)} > - - - {openActionMenu === alert.id && ( -
- - - - -
- +
+ + + + + + + + + )) + ) : ( + + - - )) - ) : ( - - - - )} - -
- 0} - onChange={toggleAllRows} - /> - LEVELUSECASE NAME / MITRE IDSOURCE → DESTINATIONTELEMETRY & TRAFFICSEVERITY ANALYSISTRIGGEREDACTIONS
- toggleRowSelection(alert.id)} - onClick={(e) => e.stopPropagation()} -/> - -
-
-
-
{alert.name}
-
{alert.mitreId || 'T1071.001'} · {alert.mitreStage || 'C&C'} · 2024-{alert.timestamp?.split('-')[1] || '06'}-{alert.timestamp?.split('-')[2]?.split(' ')[0] || '15'}
-
-
-
-
- {alert.sourceIp} - - {alert.destIp || '45.12.88.2'} -
-
{alert.assetContext?.segment || 'MGMT-CHQ-K02'} ({alert.protocol || 'ZEEK DHCP'})
-
-
-
- - ZEEK-CONN - - - ZEEK-SSL - - - NORTH-SOUTH - -
-
-
- - {alert.severity} ({alert.score || 88}) - -
-
-
-
- - 2 mins ago -
-
- JAN 22, 16:22 -
-
-
-
-
+ 0} + onChange={toggleAllRows} + /> + LEVELUSECASE NAME / MITRE IDSOURCE → DESTINATIONTELEMETRY & TRAFFICSEVERITY ANALYSISTRIGGEREDACTIONS
+ toggleRowSelection(alert.id)} + onClick={(e) => e.stopPropagation()} + /> + +
+
+
+
{alert.name}
+
+ {alert.mitreId || 'T1071.001'} · {alert.mitreStage || 'C&C'} · 2024-{alert.timestamp?.split('-')[1] || '06'}-{alert.timestamp?.split('-')[2]?.split(' ')[0] || '15'} +
+
+
+
+
+ {alert.sourceIp} + + {alert.destIp || '45.12.88.2'} +
+
+ {alert.assetContext?.segment || 'MGMT-CHQ-K02'} ({alert.protocol || 'ZEEK DHCP'}) +
+
+
+
+ + ZEEK-CONN + + + ZEEK-SSL + + + NORTH-SOUTH + +
+
+
+ + {alert.severity} ({alert.score || 88}) + +
+
+
+
+ + 2 mins ago +
+
+ JAN 22, 16:22 +
+
+
+
+ + {openActionMenu === alert.id && ( +
+ + + + +
+ +
+ )} +
+
+
+ +

+ No matching detections +

- )} - -
-
- -

- No matching detections -

-
-
+ + + )} + + - {/* Pagination */} + {/* Pagination - STANDARDIZED */}
Detections: 1,284 @@ -579,10 +582,10 @@ const DetectionsPage: React.FC<{ defaultView?: 'feed' | 'stats' }> = ({ defaultV Filtered: {filteredAlerts.length}
- - -
@@ -601,12 +604,12 @@ const DetectionsPage: React.FC<{ defaultView?: 'feed' | 'stats' }> = ({ defaultV const renderStats = () => (
- {/* Top row metric cards */} + {/* Top row metric cards - STANDARDIZED */}
{[ - { label: 'TOTAL DETECTIONS (24H)', value: '247', sub: '↑ 12% from previous', color: 'text-white', trend: 'text-[#10b981]' }, - { label: 'MTTR (MEAN RESPONSE)', value: '2.4h', sub: 'Target: < 3.0h', color: 'text-[#00D4AA]', trend: 'text-[#3b82f6]' }, - { label: 'DETECTION PRECISION', value: '94.2%', sub: 'False Positives: 5.8%', color: 'text-[#10b981]', trend: 'text-zinc-500' }, + { label: 'TOTAL DETECTIONS (24H)', value: '247', sub: '↑ 12% from previous', color: 'text-white', trend: 'text-green-500' }, + { label: 'MTTR (MEAN RESPONSE)', value: '2.4h', sub: 'Target: < 3.0h', color: 'text-[#00D4AA]', trend: 'text-blue-500' }, + { label: 'DETECTION PRECISION', value: '94.2%', sub: 'False Positives: 5.8%', color: 'text-green-500', trend: 'text-zinc-500' }, { label: 'SENSOR EFFICIENCY', value: '99.8%', sub: 'Packet Loss: 0.002%', color: 'text-white', trend: 'text-zinc-500' }, ].map((m, i) => (
@@ -618,10 +621,12 @@ const DetectionsPage: React.FC<{ defaultView?: 'feed' | 'stats' }> = ({ defaultV
- {/* Main Chart Area */} + {/* Main Chart Area - STANDARDIZED */}
-

DETECTION TIMELINE (LAST 24H / 15M WINDOWS)

+

+ DETECTION TIMELINE (LAST 24H / 15M WINDOWS) +

@@ -633,29 +638,31 @@ const DetectionsPage: React.FC<{ defaultView?: 'feed' | 'stats' }> = ({ defaultV - - - + + +
- {/* Right Sidebar: Protocol Threats */} + {/* Right Sidebar: Protocol Threats - STANDARDIZED */}
-

PROTOCOL-BASED THREATS (ZEEK LOGS)

+

+ PROTOCOL-BASED THREATS (ZEEK LOGS) +

{[ - { label: 'HTTP C2 (conn.log)', pct: 45, color: 'bg-blue-500' }, - { label: 'DNS Tunneling (dns.log)', pct: 25, color: 'bg-blue-500' }, - { label: 'SMB Lateral (smb.log)', pct: 15, color: 'bg-blue-500' }, - { label: 'RDP Brute (notice.log)', pct: 10, color: 'bg-blue-500' }, + { label: 'HTTP C2 (conn.log)', pct: 45, color: 'bg-[#00D4AA]' }, + { label: 'DNS Tunneling (dns.log)', pct: 25, color: 'bg-[#00D4AA]' }, + { label: 'SMB Lateral (smb.log)', pct: 15, color: 'bg-[#00D4AA]' }, + { label: 'RDP Brute (notice.log)', pct: 10, color: 'bg-[#00D4AA]' }, ].map(p => (
{p.label} - {p.pct}% + {p.pct}%
@@ -667,14 +674,21 @@ const DetectionsPage: React.FC<{ defaultView?: 'feed' | 'stats' }> = ({ defaultV
- {/* Heatmap Section */} + {/* Heatmap Section - STANDARDIZED */}
-

ATTACK TIMELINE HEATMAP (7 DAYS)

+

+ ATTACK TIMELINE HEATMAP (7 DAYS) +

{Array.from({ length: 7 * 24 }).map((_, i) => { const isActive = Math.random() > 0.8; return ( -
0.5 ? 'bg-blue-500' : 'bg-[#00D4AA]/40') : 'bg-zinc-800/40'}`} /> +
0.5 ? 'bg-[#00D4AA]' : 'bg-[#00D4AA]/40') : 'bg-zinc-800/40' + }`} + /> ); })}
@@ -683,13 +697,15 @@ const DetectionsPage: React.FC<{ defaultView?: 'feed' | 'stats' }> = ({ defaultV
- {/* Targeted Assets Section */} + {/* Targeted Assets Section - STANDARDIZED */}
-

MOST TARGETED INTERNAL ASSETS

+

+ MOST TARGETED INTERNAL ASSETS +

- + @@ -702,14 +718,14 @@ const DetectionsPage: React.FC<{ defaultView?: 'feed' | 'stats' }> = ({ defaultV { host: '10.0.5.42', tag: '(CEO-MBP)', alert: 'C2 Beaconing', volume: '15 Hits', score: '92/100', color: 'text-red-500' }, { host: '10.0.1.10', tag: '(DC-PROD-01)', alert: 'Suspicious SMB', volume: '12 Hits', score: '78/100', color: 'text-orange-500' }, ].map((row, i) => ( - + - - - + + + ))} @@ -720,20 +736,34 @@ const DetectionsPage: React.FC<{ defaultView?: 'feed' | 'stats' }> = ({ defaultV ); if (selectedAlertId) { - return setSelectedAlertId(null)} />; + return setSelectedAlertId(null)} />; } return (
- {/* Header section - UNCHANGED */} + {/* Header section - STANDARDIZED */}
-

- {view === 'feed' ? 'Detection Feed' : 'Detection Feed'} -

+

+ Detection Feed +

- - + +
diff --git a/ui/pages/AssetDetailPage.tsx b/ui/pages/AssetDetailPage.tsx index 4b13807..b27a8f3 100644 --- a/ui/pages/AssetDetailPage.tsx +++ b/ui/pages/AssetDetailPage.tsx @@ -1,441 +1,331 @@ import React, { useState } from 'react'; import { - ArrowLeft, Monitor, ShieldAlert, Wifi, Activity, Clock, Lock, - Info, Globe, Shield, Terminal, Server, ArrowRight, Database, - TrendingUp, Calendar, Zap, AlertTriangle, ExternalLink, ShieldCheck, - Layers, CheckCircle, XCircle, AlertCircle, Eye, ChevronDown, MoreVertical + ArrowLeft, Activity, Clock, Lock, + Globe, Server, ArrowRight, + Calendar, AlertCircle, ShieldCheck, + CheckCircle, Eye, ChevronDown, MoreVertical, Shield } from 'lucide-react'; -import { AreaChart, Area, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, PieChart, Pie, Cell } from 'recharts'; interface Props { ip: string; onBack: () => void; } +// ─── MOCK DATA ───────────────────────────────────────────────────────────── +const PROTOCOL_DATA = [ + { name: 'SMB', count: 4821, pct: 46 }, + { name: 'DNS', count: 2403, pct: 23 }, + { name: 'LDAP', count: 1572, pct: 15 }, + { name: 'HTTP', count: 838, pct: 8 }, + { name: 'TLS', count: 418, pct: 4 }, +]; + +const LISTENING_SERVICES = [ + { name: 'SMB', port: 445, status: 'Listening', change: '+8.2%', up: true }, + { name: 'LDAP', port: 389, status: 'Listening', change: '-2.1%', up: false }, + { name: 'DNS', port: 53, status: 'Listening', change: '+3.0%', up: true }, +]; + +const DETECTIONS = [ + { id: 'det-1', name: 'High-Entropy DNS Queries', severity: 'medium', timeAgo: '2 days ago' }, + { id: 'det-2', name: 'SMB Lateral Movement Attempt', severity: 'high', timeAgo: '14 days ago' }, +]; + +// ─── COMPONENT ───────────────────────────────────────────────────────────── const AssetDetailPage: React.FC = ({ ip, onBack }) => { - const [activeTab, setActiveTab] = useState('alerts'); const [showActionMenu, setShowActionMenu] = useState(false); + const [activeWindow, setActiveWindow] = useState<'1h' | '24h' | '7d'>('24h'); - const riskData = Array.from({ length: 12 }, (_, i) => ({ - time: `${i * 2}h`, - score: 60 + Math.random() * 30 - })); - - const trafficData = [ - { name: 'SMB', value: 46, color: '#10b981' }, - { name: 'DNS', value: 23, color: '#3b82f6' }, - { name: 'LDAP', value: 15, color: '#f59e0b' }, - ]; + // max bar width reference (longest bar = 100%) + const maxCount = Math.max(...PROTOCOL_DATA.map(p => p.count)); return ( -
- - {/* Header Section */} -
- {/* Top Bar with Back Button and Title */} -
-
- -
-
-

{ip}

- - STABLE ASSET - +
+ + {/* ════════════════════════════════════════════════════════════════════ + 1. ASSET HEADER + ════════════════════════════════════════════════════════════════════ */} +
+ + {/* Back + identity */} +
+ +
+
+

{ip}

+
+ Normal
-

- MS-ENG-042 • Windows Server 2022 • Server Role (High Confidence) -

+ {/* Alerts-in-30-days badge */} + + + 2 Alerts · 30 d +
+

+ MS-ENG-042 · Windows Server 2022 · Server Role (High Confidence) +

+
- {/* Action Button Dropdown */} -
- + {/* Actions dropdown */} +
+ - {/* Dropdown Menu */} - {showActionMenu && ( -
- + {showActionMenu && ( +
+ + +
+ )} +
+
+ + {/* ════════════════════════════════════════════════════════════════════ + 2. CURRENT NETWORK STATUS (full-width banner) + ════════════════════════════════════════════════════════════════════ */} +
+
+
+ +
+
+

Current Network Status

+

Normal Network Activity Observed

+
+
+ {/* status tag */} +
+ +
+ Normal + +
+
+ + {/* ════════════════════════════════════════════════════════════════════ + 3. OBSERVED NETWORK ACTIVITY + ════════════════════════════════════════════════════════════════════ */} +
+ + {/* card header */} +
+
+
+ +

Observed Network Activity

+
+ {/* window toggle */} +
+ {(['1h', '24h', '7d'] as const).map(w => ( -
- )} + ))} +
- {/* Summary Banner */} - {/*
- -

- Summary: This server is behaving like a predictable internal service host. Current activity is 92% consistent with its 30-day baseline. -

-
*/} + {/* body: 2-col — left graph, right text */} +
- {/* Risk Score Card */} - -
- - {/* Main Content Grid */} -
- - {/* Left Column - 2/3 width */} -
- - {/* How This Host Uses the Network */} -
-
-
-
- -

How This Host Uses the Network

-
-
- - - -
-
-
- -
-

- This shows what kind of network activity this host primarily generates. -

+ {/* subtitle */} +
+

+ Observed Protocol Distribution +

+

+ Based on network traffic observed from Zeek logs +

+
-
- {/* Traffic Volume */} -
-

Traffic Volume

-
-
-
- Inbound (92%) - 1.2 GB -
-
-
-
-
-
-
- Outbound (8%) - 104 MB -
-
-
-
-
-
-

- Volume is consistent with typical internal server behavior (Inbound Outbound). -

-
+
- {/* Main Types of Traffic */} -
-

Main Types of Traffic

-
-
- - - - {trafficData.map((entry, index) => ( - - ))} - - - -
- ZEEK -
-
-
-
-
-
- SMB - 46% -
-
-
-
-
- DNS - 23% -
-
-
-
-
- LDAP - 15% -
-
+ {/* ── LEFT: horizontal bar chart ── */} +
+ {PROTOCOL_DATA.map((proto) => { + const widthPct = (proto.count / maxCount) * 100; + return ( +
+ {/* label */} + {proto.name} + {/* bar track */} +
+
+ {/* count label inside bar (only if bar wide enough) */} + {widthPct > 18 && ( + + {proto.count.toLocaleString()} + + )}
+ {/* count label outside bar (fallback when bar is narrow) */} + {widthPct <= 18 && ( + {proto.count.toLocaleString()} + )}
-

- Traffic distribution matches standard Active Directory server role profile. -

-
-
-
-
+ ); + })} - {/* How Predictable This Host Is */} -
-
-
- -

How Predictable This Host Is

+ {/* Traffic direction line */} +
+ Traffic Pattern + Inbound-dominant + · + Inbound: High + | + Outbound: Low
- -
-

- Current activity closely matches learned behavior. -

-
-
-
- {Array.from({ length: 20 }).map((_, i) => { - const height = 30 + Math.random() * 70; - return ( -
- ); - })} -
-
-
-
92%
-
Match
-
-
-
-
- - {/* Active Services */} -
-
-
- -

Observed Listening Services

-
- -
- -
-
+ {/* ── RIGHT: text observations ── */} +
+

Observations

+
{[ - { name: 'SMB', status: 'Listening', change: '+8.2%' }, - { name: 'LDAP', status: 'Listening', change: '-2%' }, - { name: 'DNS', status: 'Listening', change: '+3%' }, - ].map((service, i) => ( -
-
- {service.name} - -
-
{service.status}
-
- {service.change} -
+ 'Traffic is primarily inbound and service-oriented.', + 'SMB and directory-related protocols dominate activity.', + 'Limited outbound application traffic observed.', + ].map((obs, i) => ( +
+
+

{obs}

))}
+
- {/* Right Column - 1/3 width */} -
-
-
-
-

Current Network Status

-
- 12 - Nominal -
-
-
-
-
-
-
+ {/* ════════════════════════════════════════════════════════════════════ + 4. OBSERVED LISTENING SERVICES + ════════════════════════════════════════════════════════════════════ */} +
+ +
+
+ +

Observed Listening Services

+
- - {/* Why This Host Is Considered Stable */} -
-
-
- -

Why This Host Is Considered Stable

-
-
- -
-
- -
-
LDAP / SMB usage within learned baseline
-
-15
-
-
-
- -
-
No lateral movement detected
-
-15
-
-
-
-
- {/* Operational Risk Summary */} -
-
-
Operational Risk Summary
-
Low Risk
-
- -
-
-
Things to Watch For
-
-
- - Outbound SMB to new subnets -
-
- - LDAP spikes outside business hours -
-
- - Anomalous DNS query patterns +
+
+ {LISTENING_SERVICES.map((svc, i) => ( +
+
+
+ {svc.name} + :{svc.port}
+
-
-
-
- - {/* Who It Talks To */} -
-
-
- -

Who It Talks To

-
-
- -
-
- Production Segment -
- - Production Segment +
{svc.status}
+
+ {svc.change}
-
+ ))}
+
+
- {/* Where It Reaches Out */} -
-
-
- -

Where It Reaches Out

-
-
- -
-
- - Known Update Servers -
-
+ {/* ════════════════════════════════════════════════════════════════════ + 5. DETECTION HISTORY (new — essential) + ════════════════════════════════════════════════════════════════════ */} +
+ +
+
+ +

Detections Involving This Host

+ Last 30 days +
- {/* Recent Milestones */} -
-
-
- -

Recent Milestones

-
-
- -
-
- -
-
80 days ago
-
Baseline learning cycle complete
-
-
-
- -
-
Yesterday
-
Scheduled Patch Window observed
-
-
+
+ {DETECTIONS.length === 0 ? ( +

No detections in the last 30 days.

+ ) : ( +
+ {DETECTIONS.map((det) => { + const severityStyles = { + critical: { bg: 'bg-red-500/10', border: 'border-red-500/20', text: 'text-red-500', dot: 'bg-red-500' }, + high: { bg: 'bg-orange-500/10', border: 'border-orange-500/20', text: 'text-orange-500', dot: 'bg-orange-500' }, + medium: { bg: 'bg-yellow-500/10', border: 'border-yellow-500/20', text: 'text-yellow-500', dot: 'bg-yellow-500' }, + low: { bg: 'bg-blue-500/10', border: 'border-blue-500/20', text: 'text-blue-500', dot: 'bg-blue-500' }, + }; + const s = severityStyles[det.severity as keyof typeof severityStyles] || severityStyles.low; + + return ( +
+ {/* left: severity dot + name */} +
+
+ + {det.name} + +
+ + {/* right: time + arrow */} +
+
+ + {det.timeAgo} +
+ +
+
+ ); + })}
-
+ )}
+
); }; diff --git a/ui/pages/AssetsPage.tsx b/ui/pages/AssetsPage.tsx index dee5658..749519b 100644 --- a/ui/pages/AssetsPage.tsx +++ b/ui/pages/AssetsPage.tsx @@ -30,18 +30,18 @@ interface Props { } const RISK_DISTRIBUTION = [ - { name: 'Critical', value: 12, color: '#e11d48' }, - { name: 'High', value: 25, color: '#f59e0b' }, - { name: 'Medium', value: 45, color: '#3b82f6' }, - { name: 'Low', value: 18, color: '#10b981' }, + { name: 'Critical', value: 12, color: '#ef4444' }, + { name: 'High', value: 25, color: '#f97316' }, + { name: 'Medium', value: 45, color: '#eab308' }, + { name: 'Low', value: 18, color: '#3b82f6' }, ]; const TYPE_DISTRIBUTION = [ { name: 'Workstations', value: 840, color: '#00D4AA' }, { name: 'Servers', value: 210, color: '#3b82f6' }, - { name: 'Databases', value: 45, color: '#8b5cf6' }, - { name: 'Network', value: 32, color: '#f59e0b' }, - { name: 'IoT/Other', value: 120, color: '#6b7280' }, + { name: 'Databases', value: 45, color: '#6b7280' }, + { name: 'Network', value: 32, color: '#f97316' }, + { name: 'IoT/Other', value: 120, color: '#71717a' }, ]; const DISCOVERY_TIMELINE = Array.from({ length: 30 }, (_, i) => ({ @@ -95,7 +95,7 @@ const AssetsPage: React.FC = ({ onSelectAsset, defaultView = 'inventory' segment: segments[i % segments.length], os: osList[i % osList.length], services: i === 0 ? ['HTTP', 'SMB', 'LDAP', 'DNS'] : i === 1 ? ['SSH'] : ['RTSP', 'HTTP'], - logSources: i === 0 ? ['known_hosts.log', 'known_services.log'] : i === 1 ? ['dhcp.log', 'notice.log'] : ['known_hosts.log', 'conn.log'], + logSources: i === 0 ? ['known_hosts.log', 'known_services.log'] : i === 1 ? ['dhcp.log', 'notice.log'] : ['known_hosts.log', 'conn.log'], lastActivity: i === 0 ? '2 mins ago' : i === 1 ? 'Just now' : '15 mins ago', vulnerabilities: { critical: Math.floor(Math.random() * 5), @@ -127,12 +127,12 @@ const AssetsPage: React.FC = ({ onSelectAsset, defaultView = 'inventory' {/* Filter Bar */}
{/* Search Field */} -
- +
+ setSearchTerm(e.target.value)} /> @@ -141,17 +141,17 @@ const AssetsPage: React.FC = ({ onSelectAsset, defaultView = 'inventory' {/* Asset Type Dropdown */}
- +
{openDropdown === 'type' && ( -
+
{['All Types', 'Server', 'Workstation', 'Network Device', 'Database'].map(type => (
{openDropdown === 'segment' && ( -
+
{['All Segments', 'Production', 'Engineering', 'DMZ', 'Finance', 'Corporate', 'Guest Network'].map(seg => (
{openDropdown === 'risk' && ( -
+
{['All Risks', 'Critical', 'High', 'Medium', 'Low'].map(risk => (
{/* Tabs */} -
+
- - Live Asset Polling Active + + Live Asset Polling Active
{/* Asset Table */}
INTERNAL HOST LATEST ALERT
- {row.host} - {row.tag} + {row.host} + {row.tag} {row.alert}{row.volume}{row.score}{row.alert}{row.volume}{row.score}
- - - - - - - - + + + + + + + + {loading ? ( - ) : filteredAssets.length > 0 ? ( filteredAssets.slice(0, 10).map((asset, idx) => { const riskScore = asset.riskLevel === 'critical' ? 82 : asset.riskLevel === 'high' ? 51 : asset.riskLevel === 'medium' ? 45 : 12; - const riskColor = asset.riskLevel === 'critical' ? 'bg-red-500/20 text-red-400 border-red-500/30' : - asset.riskLevel === 'high' ? 'bg-orange-500/20 text-orange-400 border-orange-500/30' : - 'bg-emerald-500/20 text-emerald-400 border-emerald-500/30'; + const riskColor = asset.riskLevel === 'critical' ? 'bg-red-500/10 text-red-500 border-red-500/20' : + asset.riskLevel === 'high' ? 'bg-orange-500/10 text-orange-500 border-orange-500/20' : + asset.riskLevel === 'medium' ? 'bg-yellow-500/10 text-yellow-500 border-yellow-500/20' : + 'bg-green-500/10 text-green-500 border-green-500/20'; return ( = ({ onSelectAsset, defaultView = 'inventory' className="hover:bg-zinc-900/30 transition-colors group cursor-pointer" onClick={() => onSelectAsset?.(asset.ip)} > - - - - - - -
IdentityOS / EnvironmentRisk StatusServices (Known Services.log)Log ProvenanceLast Activity
IdentityOS / EnvironmentRisk StatusServicesLog ProvenanceLast Activity
- Synchronizing Inventory... + +
+
+ Synchronizing Inventory... +
+
-
- {asset.type === 'server' ? : } +
+ {asset.type === 'server' ? : }
-
+
{asset.hostname}
-
+
{asset.ip}
+
-
{asset.os}
+
{asset.os}
- + {asset.segment} {idx === 0 && ( - + Active Directory )}
- + +
{riskScore} - +
+
{asset.services.map(service => ( {service} ))}
+
{asset.logSources.map(log => ( -
- +
+
{log}
))}
+
-
+
{asset.lastActivity}
-
+
{idx === 0 ? 'INTERNAL-SERVERS-VLAN' : idx === 1 ? 'WIFI USERS' : 'IOT-SENSORS'}
@@ -363,7 +367,7 @@ const AssetsPage: React.FC = ({ onSelectAsset, defaultView = 'inventory' }) ) : (
+

@@ -377,12 +381,12 @@ const AssetsPage: React.FC = ({ onSelectAsset, defaultView = 'inventory'

{/* Footer */} -
+
- Asset classification derived from SSL, HTTP, and DHCP flows. + Asset classification derived from SSL, HTTP, and DHCP flows.
- {filteredAssets.length} Assets in View + Total: {filteredAssets.length}
@@ -390,136 +394,236 @@ const AssetsPage: React.FC = ({ onSelectAsset, defaultView = 'inventory' ); const renderStats = () => ( -
-
-
+
+ {/* Header with View Toggle */} +
+
Home - Assets + Assets - Risk Analytics + Risk Analytics
-
- - +
+ +
-
+ {/* Metric Cards */} +
{[ - { label: 'TOTAL ASSETS', value: '1,247', trend: '+12', icon: Monitor, color: 'text-[#00D4AA]' }, - { label: 'HIGH RISK ENTITIES', value: '32', trend: '+3', icon: ShieldAlert, color: 'text-red-500' }, - { label: 'ACTIVE THREATS', value: '145', trend: '-8', icon: Activity, color: 'text-orange-500' }, - { label: 'CRITICAL VULNS', value: '28', trend: '+2', icon: AlertTriangle, color: 'text-red-600' }, + { label: 'TOTAL ASSETS', value: '1,247', trend: '+12', icon: Monitor, trendUp: true }, + { label: 'HIGH RISK ENTITIES', value: '32', trend: '+3', icon: ShieldAlert, trendUp: true }, + { label: 'ACTIVE THREATS', value: '145', trend: '-8', icon: Activity, trendUp: false }, + { label: 'CRITICAL VULNS', value: '28', trend: '+2', icon: AlertTriangle, trendUp: true }, ].map((stat, i) => ( -
-
-

{stat.label}

- -
-
-

{stat.value}

- {stat.trend} -
+
+
+

{stat.label}

+ +
+

{stat.value}

+

+ {stat.trend} vs last month +

))}
-
-
-

Risk Level Distribution

-
- - - - {RISK_DISTRIBUTION.map((entry, index) => )} - - - - -
-

Avg Risk

-

42%

+ {/* Charts Row 1 */} +
+ {/* Risk Distribution Pie Chart */} +
+

Risk Level Distribution

+
+ + + + {RISK_DISTRIBUTION.map((entry, index) => )} + + + + +
+

Avg Risk

+

42%

+
+
+
+ {RISK_DISTRIBUTION.map(r => ( +
+
+ {r.name} + {r.value}%
-
-
- {RISK_DISTRIBUTION.map(r => ( -
-
- {r.name} - {r.value}% -
- ))} -
+ ))} +
-
-

Asset Category Breakdown

-
- - - - - - - {TYPE_DISTRIBUTION.map((entry, index) => )} - - - -
-

Infrastructure classified via OUI, MAC analysis, and port fingerprinting.

+ {/* Asset Category Breakdown */} +
+

Asset Category Breakdown

+
+ + + + + + + {TYPE_DISTRIBUTION.map((entry, index) => )} + + + +
+

+ Infrastructure classified via OUI, MAC analysis, and port fingerprinting. +

-
-
-

Discovery Timeline (Discovered vs Inventory Growth)

-
- - - - - - - - - - - - - -
+ {/* Charts Row 2 */} +
+ {/* Discovery Timeline */} +
+

Discovery Timeline

+
+ + + + + + + + + + + + + + + + +
-
-

Risk Exposure by Network Segment

-
- {SEGMENT_RISK.map(s => ( -
-
- {s.name} ({s.assets} Assets) - 80 ? 'text-red-500' : 'text-white'}>{s.risk}% Risk -
-
-
80 ? 'bg-red-500 shadow-[0_0_8px_#ef4444]' : s.risk > 50 ? 'bg-orange-500' : 'bg-[#00D4AA]'}`} style={{ width: `${s.risk}%` }} /> -
-
- ))} -
-
-

Risk calculation integrates vulnerabilities, lateral movement proximity, and asset sensitivity.

-
+ {/* Risk Exposure by Segment */} +
+

Risk Exposure by Network Segment

+
+ {SEGMENT_RISK.map(s => ( +
+
+ + {s.name} ({s.assets} Assets) + + 80 ? 'text-red-500' : s.risk > 50 ? 'text-orange-500' : 'text-white'}> + {s.risk}% + +
+
+
80 + ? 'bg-red-500' + : s.risk > 50 + ? 'bg-orange-500' + : 'bg-[#00D4AA]' + }`} + style={{ width: `${s.risk}%` }} + /> +
+
+ ))} +
+
+

+ Risk calculation integrates vulnerabilities, lateral movement proximity, and asset sensitivity. +

+
-
- Inventory Analytics Sync: {new Date().toLocaleTimeString()} + {/* Footer Timestamp */} +
+ + Inventory Analytics Sync: {new Date().toLocaleTimeString()} +
); return ( -
+
{view === 'inventory' ? renderInventory() : renderStats()}
); diff --git a/ui/pages/DetectionDetailPage.tsx b/ui/pages/DetectionDetailPage.tsx index 3aa05cc..dc32c37 100644 --- a/ui/pages/DetectionDetailPage.tsx +++ b/ui/pages/DetectionDetailPage.tsx @@ -68,86 +68,79 @@ const DetectionDetailPage: React.FC = ({ id, onBack }) => { }; return ( -
+
{/* Top Header Row */}
-
- Network Live +
+ Network Live
- {/*
- -
*/}
{/* Title Block */} -
+
-

High Entropy DNS Queries

- Zeek Analyzed +

High Entropy DNS Queries

+ + Zeek Analyzed +
-

Alert ID: {id || 'ALT-001'}

+

Alert ID: {id || 'ALT-001'}

-
- - {actionsDropdownOpen && ( -
- - - -
- )} -
-
- - -
+
+ + {actionsDropdownOpen && ( +
+ + + +
+ )} +
+
+ +
@@ -158,117 +151,64 @@ const DetectionDetailPage: React.FC = ({ id, onBack }) => {
{/* Why This Alert Was Triggered */} -
- {/* Header */} -
-
- -

- Why This Alert Was Triggered -

-
-
- - {/* Body */} -
-
- {/* Summary */} -

- This alert was triggered because the system detected - - {" "}sustained abnormal outbound data transfer behavior - - , which deviated significantly from the host’s historical baseline. -

- - {/* Detection stages */} -
-

- Detection Stages -

-
    -
  • - Anomaly detected:{" "} - Initial abnormal outbound activity was identified compared to normal behavior. -
  • -
  • - Behavior sustained:{" "} - The abnormal behavior persisted across multiple observation intervals. -
  • -
  • - Alert threshold exceeded:{" "} - Combined signal confidence crossed the alert threshold, resulting in alert generation. -
  • -
-
- - {/* Key factors */} -
-

- Key Contributing Factors -

-
    -
  • Sustained outbound volume spike
  • -
  • Abnormal upload-to-download ratio
  • -
-
- - {/* Footer note */} -

- The activity was observed consistently over a defined time window and was not a single transient spike. -

-
-
-
- - - {/* Attack Progression */} - {/*
+
+ {/* Header */}
- -

Attack Progression

+ +

+ Why This Alert Was Triggered +

- -
-
- {[ - { stage: 'Initial Activity', time: '13:40', status: 'complete', color: 'cyan' }, - { stage: 'Suspicious Behavior', time: '13:45', status: 'complete', color: 'cyan' }, - { stage: 'Escalation', time: '13:48', status: 'active', color: 'red' }, - { stage: 'Impact', time: '13:51', status: 'pending', color: 'red' }, - ].map((item, idx) => ( - - - {idx < 3 && ( -
- )} -
- ))} + + {/* Body */} +
+ {/* Summary */} +

+ This alert was triggered because the system detected + + {" "}sustained abnormal outbound data transfer behavior + + , which deviated significantly from the host's historical baseline. +

+ + {/* Detection stages */} +
+

+ Detection Stages +

+
    +
  • + Anomaly detected:{" "} + Initial abnormal outbound activity was identified compared to normal behavior. +
  • +
  • + Behavior sustained:{" "} + The abnormal behavior persisted across multiple observation intervals. +
  • +
  • + Alert threshold exceeded:{" "} + Combined signal confidence crossed the alert threshold, resulting in alert generation. +
  • +
+
+ + {/* Key factors */} +
+

+ Key Contributing Factors +

+
    +
  • Sustained outbound volume spike
  • +
  • Abnormal upload-to-download ratio
  • +
-
*/} +
{/* Attack Timeline - Detailed Signal Observations */} -
+
@@ -277,117 +217,119 @@ const DetectionDetailPage: React.FC = ({ id, onBack }) => {
-
- {/* Timeline Item 1 */} -
openSidebar('signal-outbound')} className="flex gap-3 cursor-pointer"> -
-
- 1 -
-
-
- -
-
- Initial Activity - 13:40 -
- -
-
-
-
-
Outbound Volume Spike
-
The host sent significantly more data than it normally does.
-
-
-
-
-
+
+ {/* Timeline Item 1 */} +
openSidebar('signal-outbound')} className="flex gap-3 cursor-pointer hover:bg-zinc-900/30 transition-colors rounded-lg p-2 -ml-2"> +
+
+ 1 +
+
+
+ +
+
+ Initial Activity + 13:40 +
+ +
+
+
+
+
Outbound Volume Spike
+
The host sent significantly more data than it normally does.
+
+
+
+
+
- {/* Timeline Item 2 */} -
openSidebar('signal-ratio')} className="flex gap-3 cursor-pointer"> -
-
- 2 -
-
-
- -
-
- Initial Activity - 13:40 -
- -
-
-
-
-
Outbound Volume Spike
-
The host sent significantly more data than it normally does.
-
-
-
-
-
+ {/* Timeline Item 2 */} +
openSidebar('signal-ratio')} className="flex gap-3 cursor-pointer hover:bg-zinc-900/30 transition-colors rounded-lg p-2 -ml-2"> +
+
+ 2 +
+
+
+ +
+
+ Suspicious Behavior + 13:45 +
+ +
+
+
+
+
Upload/Download Ratio Shift
+
Unusual upload pattern detected compared to downloads.
+
+
+
+
+
- {/* Timeline Item 3 */} -
-
-
- 3 -
-
-
- -
-
- Initial Activity - 13:40 -
- -
-
-
-
-
Outbound Volume Spike
-
-
-
-
-
+ {/* Timeline Item 3 */} +
+
+
+ 3 +
+
+
+ +
+
+ Escalation + 13:48 +
+ +
+
+
+
+
Sustained Activity Pattern
+
Behavior persisted beyond normal threshold.
+
+
+
+
+
- {/* Timeline Item 4 - Final */} -
-
-
- 4 -
-
- -
-
- Initial Activity - 13:40 -
- -
-
-
-
-
Triggered Rule
-
-
-
-
-
-
+ {/* Timeline Item 4 - Final */} +
+
+
+ 4 +
+
+ +
+
+ Alert Generated + 13:51 +
+ +
+
+
+
+
Alert Threshold Triggered
+
Combined signals exceeded detection threshold.
+
+
+
+
+
+
{/* Observed Network Behavior - With Two Tabs */} -
+
@@ -400,17 +342,17 @@ const DetectionDetailPage: React.FC = ({ id, onBack }) => { onClick={() => setBehaviorTab('network')} className={`flex-1 px-6 py-3 text-[10px] font-black uppercase tracking-widest transition-all ${behaviorTab === 'network' - ? 'bg-[#00D4AA10] text-[#00D4AA] border-b-2 border-[#00D4AA10]' - : 'text-zinc-500 hover:text-zinc-300 hover:bg-[#00D4AA10]'}`} + ? 'bg-[#00D4AA]/10 text-[#00D4AA] border-b-2 border-[#00D4AA]' + : 'text-zinc-500 hover:text-zinc-300 hover:bg-zinc-900/30'}`} > - Observed Network Behavior + Network Activity @@ -420,42 +362,42 @@ const DetectionDetailPage: React.FC = ({ id, onBack }) => { {behaviorTab === 'network' && (
- Total Data + Total Data
-
- 2.6 GB +
+ 2.6 GB
- 12.1 + 12.1
- 45 Mbps + 45 Mbps
-
+
- + = ({ id, onBack }) => { @@ -471,7 +413,7 @@ const DetectionDetailPage: React.FC = ({ id, onBack }) => {
-

+

Network traffic shifted from normal download behavior to sustained outbound data transfer.

@@ -479,28 +421,36 @@ const DetectionDetailPage: React.FC = ({ id, onBack }) => { {behaviorTab === 'data' && (
-
- - - - - - - +
+
TimestampProtocolBytes SentDestination
+ + + + + + - + {[ { ts: '13:40:15', proto: 'HTTPS', bytes: '524 KB', dest: '185.12.45.23' }, { ts: '13:42:33', proto: 'HTTPS', bytes: '892 KB', dest: '185.12.45.23' }, { ts: '13:45:12', proto: 'HTTPS', bytes: '1.2 MB', dest: '185.12.45.23' }, { ts: '13:48:45', proto: 'HTTPS', bytes: '1.5 MB', dest: '185.12.45.23' }, ].map((row, i) => ( - - - - - + + + + + ))} @@ -516,7 +466,7 @@ const DetectionDetailPage: React.FC = ({ id, onBack }) => {
{/* Affected Systems and Destinations */} -
+

Affected Systems and Destinations

@@ -525,39 +475,39 @@ const DetectionDetailPage: React.FC = ({ id, onBack }) => { {/* Source System */} {/* Internal Systems */}
{/* What Should I Check Next */} -
+

What Should I Check Next?

@@ -598,25 +548,25 @@ const DetectionDetailPage: React.FC = ({ id, onBack }) => { 'Monitor external connections for continued activity.', ].map((item, idx) => (
-
+
{idx + 1}
-

{item}

+

{item}

))}
{/* Threat Classification */} -
+

Threat Classification

-
-
Mitre Attack
-
TA0010 - Exfiltration
-

+

+
Mitre Attack
+
TA0010 - Exfiltration
+

Adversary is attempting to steal data from your network.

@@ -631,13 +581,13 @@ const DetectionDetailPage: React.FC = ({ id, onBack }) => { onClick={closeSidebar} >
e.stopPropagation()} >
{/* Sidebar Header */} -
-

+
+

{(sidebarOpen === 'signal-outbound' || sidebarOpen === 'signal-ratio') && 'Signal Detail: ' + (sidebarOpen === 'signal-outbound' ? 'Outbound Volume Spike' : 'Upload/Download Ratio Shift')} {sidebarOpen === 'source' && 'Source System Details'} {sidebarOpen === 'internal' && 'Internal Systems'} @@ -651,14 +601,14 @@ const DetectionDetailPage: React.FC = ({ id, onBack }) => {

{/* Sidebar Content */} -
+
{/* Signal Detail Tabs */} {(sidebarOpen === 'signal-outbound' || sidebarOpen === 'signal-ratio') && ( <> @@ -673,8 +623,8 @@ const DetectionDetailPage: React.FC = ({ id, onBack }) => { onClick={() => setActiveTab(tab.id)} className={`flex-1 px-6 py-3 text-[10px] font-black uppercase tracking-widest transition-all ${activeTab === tab.id - ? 'bg-[#00D4AA10] text-[#00D4AA] border-b-2 border-[#00D4AA10]' - : 'text-zinc-500 hover:text-zinc-300 hover:bg-[#00D4AA10]'}`} + ? 'bg-[#00D4AA]/10 text-[#00D4AA] border-b-2 border-[#00D4AA]' + : 'text-zinc-500 hover:text-zinc-300 hover:bg-zinc-900/30'}`} > {tab.label} @@ -684,15 +634,15 @@ const DetectionDetailPage: React.FC = ({ id, onBack }) => {
{activeTab === 'explanation' && (
-
-

+

+

{sidebarOpen === 'signal-outbound' ? '"This signal indicates that the observed network behavior deviated significantly from what is normally expected for this system over a sustained period."' : '"The host uploaded much more data than it downloaded, which is unusual for typical network behavior."' }

-

+

{sidebarOpen === 'signal-outbound' ? 'This signal indicates that the observed network behavior deviated significantly from what is normally expected for this system over a sustained period.' : 'This pattern often indicates data exfiltration where an attacker is uploading stolen data to an external server while minimizing downloads to avoid detection.' @@ -705,7 +655,7 @@ const DetectionDetailPage: React.FC = ({ id, onBack }) => {

What was monitored:

-
    +
      {sidebarOpen === 'signal-outbound' ? ( <>
    • @@ -742,7 +692,7 @@ const DetectionDetailPage: React.FC = ({ id, onBack }) => {

      When it is considered suspicious:

      -
        +
          {sidebarOpen === 'signal-outbound' ? ( <>
        • @@ -771,7 +721,7 @@ const DetectionDetailPage: React.FC = ({ id, onBack }) => {

          Why this matters:

          -

          +

          {sidebarOpen === 'signal-outbound' ? 'This pattern is commonly associated with unauthorized data transfer or exfiltration.' : 'Unusual upload patterns often indicate data theft where attackers extract sensitive information to external servers.' @@ -784,10 +734,10 @@ const DetectionDetailPage: React.FC = ({ id, onBack }) => { {activeTab === 'evidence' && (

          -
          +
          Time Window
          -
          13:40 - 13:58
          +
          13:40 - 13:58
          @@ -795,12 +745,12 @@ const DetectionDetailPage: React.FC = ({ id, onBack }) => { @@ -889,13 +840,13 @@ const DetectionDetailPage: React.FC = ({ id, onBack }) => {
          Evidence Summary
          -
          -
          Time Window
          -
          13:58 UTC
          +
          +
          Time Window
          +
          13:58 UTC
          -
          -
          Affected Systems
          -
          Affected system(s) and associated network logs
          +
          +
          Affected Systems
          +
          Multiple systems
          @@ -903,7 +854,7 @@ const DetectionDetailPage: React.FC = ({ id, onBack }) => { {/* Why This Stage Matters */}
          Why This Stage Matters
          -

          +

          "Activity in this stage is often observed before escalation or data loss."

          diff --git a/ui/pages/DetectionRulesPage.tsx b/ui/pages/DetectionRulesPage.tsx index 5a0beee..7a54620 100644 --- a/ui/pages/DetectionRulesPage.tsx +++ b/ui/pages/DetectionRulesPage.tsx @@ -73,6 +73,7 @@ const DetectionRulesPage: React.FC<{ defaultView?: TabId }> = ({ defaultView = ' const [activeFieldInput, setActiveFieldInput] = useState<{groupId: string, condId: string, fieldType: 'field' | 'value'} | null>(null); const [modalTab, setModalTab] = useState<'default' | 'enriched' | 'datasets' | 'static'>('default'); const [selectedDefaultField, setSelectedDefaultField] = useState(null); + // Field Catalog Data const fieldCatalog = { default: [ @@ -132,495 +133,409 @@ const DetectionRulesPage: React.FC<{ defaultView?: TabId }> = ({ defaultView = ' const openFieldModal = (groupId: string, condId: string, fieldType: 'field' | 'value') => { setActiveFieldInput({ groupId, condId, fieldType }); setModalTab(fieldType === 'field' ? 'default' : 'datasets'); - setSelectedDefaultField(null); // Reset selected field + setSelectedDefaultField(null); setShowFieldModal(true); }; const closeFieldModal = () => { setShowFieldModal(false); setActiveFieldInput(null); - setSelectedDefaultField(null); // Reset when closing + setSelectedDefaultField(null); }; const selectFieldValue = (value: string) => { if (activeFieldInput) { const { groupId, condId, fieldType } = activeFieldInput; - - // Handle correlation join keys if (groupId === 'correlation-g1' && condId === 'join-key') { setThresholdField(value); } else if (groupId === 'correlation-g2' && condId === 'join-key') { - // Handle second correlation key (you might want to add state for this) console.log('Group B join key:', value); } else if (groupId === 'dedup' && condId === 'key') { - // Handle deduplication key addition console.log('Add dedup key:', value); - // You can add logic here to add the key to a deduplication keys array } else { - // Handle normal condition fields/values updateCondition(groupId, condId, fieldType === 'field' ? { field: value } : { value }); } } closeFieldModal(); }; - // Field Picker Modal Component -// Update the FieldPickerModal component - replace the entire value picker section: - -const FieldPickerModal = () => { - if (!showFieldModal) return null; - - const isFieldPicker = activeFieldInput?.fieldType === 'field'; - - if (isFieldPicker) { - // Field picker - show enriched fields only when a default field is selected - return ( -
          -
          -
          -

          - Select Field -

          - -
          - -
          - {/* Left Side - Default Fields */} -
          -
          -

          Default Fields

          -
          -
          - {fieldCatalog.default.map((item) => ( -
          { - if (selectedDefaultField === item.id) { - // If clicking the same field, select it - selectFieldValue(item.id); - setSelectedDefaultField(null); - } else { - // Show enriched fields for this default field - setSelectedDefaultField(item.id); - } - }} - className={`p-3 mb-1 rounded-xl cursor-pointer border transition-all group ${ - selectedDefaultField === item.id - ? 'bg-zinc-800 border-blue-500/50' - : 'hover:bg-zinc-800 border-transparent hover:border-zinc-700' - }`} - > -
          - {item.id} - {selectedDefaultField === item.id && ( - - )} -
          -
          {item.desc}
          -
          - ))} -
          + // ─── FIELD PICKER MODAL ──────────────────────────────────────────── + const FieldPickerModal = () => { + if (!showFieldModal) return null; + const isFieldPicker = activeFieldInput?.fieldType === 'field'; + + if (isFieldPicker) { + return ( +
          +
          +
          +

          Select Field

          +
          - - {/* Right Side - Enriched Fields (only shown when default field selected) */} - {selectedDefaultField && ( -
          -
          -

          - Enriched Fields for {selectedDefaultField} -

          - + +
          + {/* Left — Default Fields */} +
          +
          +

          Default Fields

          - {fieldCatalog.enriched.map((item) => ( + {fieldCatalog.default.map((item) => (
          { - selectFieldValue(item.id); - setSelectedDefaultField(null); + if (selectedDefaultField === item.id) { + selectFieldValue(item.id); + setSelectedDefaultField(null); + } else { + setSelectedDefaultField(item.id); + } }} - className="p-3 mb-1 rounded-xl hover:bg-zinc-800 cursor-pointer border border-transparent hover:border-blue-700/30 transition-all group" + className={`p-3 mb-1 rounded-xl cursor-pointer border transition-all group ${ + selectedDefaultField === item.id + ? 'bg-zinc-800 border-blue-500/50' + : 'hover:bg-zinc-800 border-transparent hover:border-zinc-700' + }`} > -
          {item.id}
          +
          + {item.id} + {selectedDefaultField === item.id && } +
          {item.desc}
          ))} - - {/* Option to select the base field */} -
          -
          { - selectFieldValue(selectedDefaultField); - setSelectedDefaultField(null); - }} - className="p-3 rounded-xl hover:bg-blue-600/10 cursor-pointer border border-blue-500/30 hover:border-blue-500/50 transition-all" - > -
          - Use base field: {selectedDefaultField} +
          +
          + + {/* Right — Enriched Fields */} + {selectedDefaultField && ( +
          +
          +

          + Enriched Fields for {selectedDefaultField} +

          + +
          +
          + {fieldCatalog.enriched.map((item) => ( +
          { selectFieldValue(item.id); setSelectedDefaultField(null); }} + className="p-3 mb-1 rounded-xl hover:bg-zinc-800 cursor-pointer border border-transparent hover:border-blue-700/30 transition-all group" + > +
          {item.id}
          +
          {item.desc}
          +
          + ))} +
          +
          { selectFieldValue(selectedDefaultField); setSelectedDefaultField(null); }} + className="p-3 rounded-xl hover:bg-blue-600/10 cursor-pointer border border-blue-500/30 hover:border-blue-500/50 transition-all" + > +
          Use base field: {selectedDefaultField}
          +
          Select the original field without enrichment
          -
          Select the original field without enrichment
          -
          - )} -
          - -
          - Phase-1 Engine • Automatic Fact Discovery Enabled + )} +
          +
          + Phase-1 Engine • Automatic Fact Discovery Enabled +
          -
          - ); - } else { - // Value picker - show datasets only when a static value is selected - return ( -
          -
          -
          -

          - Select Value -

          - -
          - -
          - {/* Left Side - Static Values */} -
          -
          -

          Common Values

          -
          -
          - {valueCatalog.static.map((item) => ( -
          { - if (selectedDefaultField === item.id) { - // If clicking the same value, select it - selectFieldValue(item.id); - setSelectedDefaultField(null); - } else { - // Show datasets for this static value - setSelectedDefaultField(item.id); - } - }} - className={`p-3 mb-1 rounded-xl cursor-pointer border transition-all group ${ - selectedDefaultField === item.id - ? 'bg-zinc-800 border-emerald-500/50' - : 'hover:bg-zinc-800 border-transparent hover:border-zinc-700' - }`} - > -
          - {item.id} - {selectedDefaultField === item.id && ( - - )} -
          -
          {item.desc}
          -
          - ))} -
          + ); + } else { + // Value picker + return ( +
          +
          +
          +

          Select Value

          +
          - - {/* Right Side - Datasets (only shown when static value selected) */} - {selectedDefaultField && ( -
          -
          -

          - Datasets -

          - + +
          +
          +
          +

          Common Values

          - {valueCatalog.datasets.map((item) => ( + {valueCatalog.static.map((item) => (
          { - selectFieldValue(item.id); - setSelectedDefaultField(null); + if (selectedDefaultField === item.id) { + selectFieldValue(item.id); + setSelectedDefaultField(null); + } else { + setSelectedDefaultField(item.id); + } }} - className="p-3 mb-1 rounded-xl hover:bg-zinc-800 cursor-pointer border border-transparent hover:border-emerald-700/30 transition-all group" + className={`p-3 mb-1 rounded-xl cursor-pointer border transition-all group ${ + selectedDefaultField === item.id + ? 'bg-zinc-800 border-emerald-500/50' + : 'hover:bg-zinc-800 border-transparent hover:border-zinc-700' + }`} > -
          {item.id}
          +
          + {item.id} + {selectedDefaultField === item.id && } +
          {item.desc}
          - {item.table && ( -
          Table: {item.table}
          - )}
          ))} - - {/* Option to select the base value */} -
          -
          { - selectFieldValue(selectedDefaultField); - setSelectedDefaultField(null); - }} - className="p-3 rounded-xl hover:bg-emerald-600/10 cursor-pointer border border-emerald-500/30 hover:border-emerald-500/50 transition-all" - > -
          - Use value: {selectedDefaultField} +
          +
          + + {selectedDefaultField && ( +
          +
          +

          Datasets

          + +
          +
          + {valueCatalog.datasets.map((item) => ( +
          { selectFieldValue(item.id); setSelectedDefaultField(null); }} + className="p-3 mb-1 rounded-xl hover:bg-zinc-800 cursor-pointer border border-transparent hover:border-emerald-700/30 transition-all group" + > +
          {item.id}
          +
          {item.desc}
          + {item.table &&
          Table: {item.table}
          } +
          + ))} +
          +
          { selectFieldValue(selectedDefaultField); setSelectedDefaultField(null); }} + className="p-3 rounded-xl hover:bg-emerald-600/10 cursor-pointer border border-emerald-500/30 hover:border-emerald-500/50 transition-all" + > +
          Use value: {selectedDefaultField}
          +
          Select this common value directly
          -
          Select this common value directly
          -
          - )} -
          - -
          - Phase-1 Engine • Automatic Fact Discovery Enabled + )} +
          +
          + Phase-1 Engine • Automatic Fact Discovery Enabled +
          -
          - ); - } -}; + ); + } + }; - // --- Step 1: Definition & Scheduling --- + // ─── STEP 1: DEFINE ──────────────────────────────────────────────── const renderStep1About = () => (
          {/* LEFT SIDE */}
          - - {/* GENERAL INFORMATION */} -
          -
          - -
          -

          - Detection Definition -

          -

          Describe what this detection identifies and how it should be classified.

          + {/* DETECTION DEFINITION */} +
          +
          + +
          +

          Detection Definition

          +

          Describe what this detection identifies and how it should be classified.

          +
          +
          -
          - -
          - -
          - {/* Rule Name */} -
          - - setRuleName(e.target.value)} - className="w-full bg-zinc-950 border border-zinc-800 rounded-md px-3 py-2 text-sm text-white outline-none focus:border-[#00D4AA]" - /> -
          +
          + {/* Rule Name */} +
          + + setRuleName(e.target.value)} + className="w-full bg-zinc-950 border border-zinc-800 rounded-md px-3 py-2 text-sm text-white outline-none focus:border-[#00D4AA]" + /> +
          - {/* Severity */} -
          - - -
          + {/* Severity */} +
          + + +

          Alert severity when this detection triggers

          +
          +
          - {/* Description */} - -
          -
          - - -
          +
          + + +
          - + +
          diff --git a/ui/pages/LogsPage.tsx b/ui/pages/LogsPage.tsx index c15eac0..2627542 100644 --- a/ui/pages/LogsPage.tsx +++ b/ui/pages/LogsPage.tsx @@ -157,9 +157,9 @@ const LogsPage: React.FC<{ defaultView?: 'search' | 'stats' | 'live' }> = ({ def

          {label}

          -

          {value}

          +

          {value}

          {trend && ( -
          +
          {trend.startsWith('↑') ? : } {trend}
          )} @@ -344,7 +344,7 @@ const LogsPage: React.FC<{ defaultView?: 'search' | 'stats' | 'live' }> = ({ def onClick={() => setSelectedLog(log)} className="hover:bg-zinc-800/50 transition-colors cursor-pointer group" > -

+ @@ -443,7 +443,7 @@ const LogsPage: React.FC<{ defaultView?: 'search' | 'stats' | 'live' }> = ({ def
Storage Growth Rate85GB/Day
-
Days Until Full45 Days ⚠️
+
Days Until Full45 Days ⚠️
@@ -502,7 +502,7 @@ const LogsPage: React.FC<{ defaultView?: 'search' | 'stats' | 'live' }> = ({ def {s.value}%
- {s.count} + {s.count}
@@ -522,7 +522,7 @@ const LogsPage: React.FC<{ defaultView?: 'search' | 'stats' | 'live' }> = ({ def
-

{gen.ip}

+

{gen.ip}

{gen.hostname} • {gen.type}

@@ -539,7 +539,7 @@ const LogsPage: React.FC<{ defaultView?: 'search' | 'stats' | 'live' }> = ({ def
- {gen.anomaly &&

{gen.reason} - Spike +340%

} + {gen.anomaly &&

{gen.reason} - Spike +340%

}
))}
@@ -553,7 +553,7 @@ const LogsPage: React.FC<{ defaultView?: 'search' | 'stats' | 'live' }> = ({ def

Data Quality

- 97.8% + 97.8%
{[ @@ -623,34 +623,34 @@ const LogsPage: React.FC<{ defaultView?: 'search' | 'stats' | 'live' }> = ({ def
-

Critical Anomalies

+

Critical Anomalies

C2 Traffic detected: Asset 10.0.5.42 log volume increased 340% following unusual DNS entropy peaks.

- +
-

Pipeline Alerts

+

Pipeline Alerts

Exhaustion Risk: Total telemetry storage will be at capacity in ~45 days based on current growth rate.

- +
-

Performance Hits

+

Performance Hits

Latency Optimized: End-to-end pipeline latency improved by 10% following recent cluster reconfiguration.

- +

Optimization

Rule Tuning: "DNS-TUNNEL-001" is causing 40% of detection latency. Consider regex optimization.

- +
@@ -677,7 +677,7 @@ const LogsPage: React.FC<{ defaultView?: 'search' | 'stats' | 'live' }> = ({ def
-
+
{MOCK_LOGS.map((log, i) => (
{log.timestamp.split(' ')[1]} @@ -715,7 +715,7 @@ const LogsPage: React.FC<{ defaultView?: 'search' | 'stats' | 'live' }> = ({ def

Log Details

-

{selectedLog.id}

+

{selectedLog.id}

))} diff --git a/ui/pages/NetworkViewPage.tsx b/ui/pages/NetworkViewPage.tsx index 56dad0f..dd646c0 100644 --- a/ui/pages/NetworkViewPage.tsx +++ b/ui/pages/NetworkViewPage.tsx @@ -1,4 +1,3 @@ - import React, { useState, useEffect, useMemo } from 'react'; import { Network, @@ -28,7 +27,6 @@ import { ExternalLink, ShieldCheck, ChevronDown, - // Added missing icon imports X, Monitor } from 'lucide-react'; @@ -138,45 +136,55 @@ const NetworkViewPage: React.FC = () => { ]; const StatCard = ({ label, value, sub, icon: Icon, color }: any) => ( -
-
- -
-
-

{label}

-

{value}

-

{sub}

+
+
+
+ +
+
+

{label}

+

{value}

+

{sub}

+
); return ( -
+
{/* Page Header */}
-

Network View

-

Real-time Visualization of Topology, Service Usage, and Cross-Segment Flows

+

Network View

+

Real-time Visualization of Topology, Service Usage, and Cross-Segment Flows

-
+
{(['1h', '6h', '24h', '7d', 'all'] as TimeRange[]).map(r => ( ))}
-
+
{(['all', 'critical', 'high'] as RiskFilter[]).map(rf => ( @@ -185,7 +193,10 @@ const NetworkViewPage: React.FC = () => {
{/* Main Tabs Navigation */} -
+
{tabs.map(tab => ( - - + + +
@@ -238,10 +258,10 @@ const NetworkViewPage: React.FC = () => { onClick={() => setSelectedNodeId('1')} className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 cursor-pointer group" > -
+
- FW-EDGE-01 + FW-EDGE-01
{NODES.filter(n => n.id !== '1').map((node, i) => { @@ -253,12 +273,14 @@ const NetworkViewPage: React.FC = () => { return ( -
setSelectedNodeId(node.id)} className="absolute cursor-pointer group" style={{ left: `calc(50% + ${x}px)`, top: `calc(50% + ${y}px)`, transform: 'translate(-50%, -50%)' }} > -
{node.type === 'server' && } @@ -266,7 +288,7 @@ const NetworkViewPage: React.FC = () => { {node.type === 'workstation' && } {node.type === 'external' && }
- {node.name} + {node.name}
); @@ -274,60 +296,87 @@ const NetworkViewPage: React.FC = () => {
-
-

Topology Legend

+
+

Topology Legend

-
Critical Risk
-
Low Risk
-
Server
-
Endpoint
+
+
+ Critical Risk +
+
+
+ Low Risk +
+
+ + Server +
+
+ + Endpoint +
{selectedNode ? ( -
+
-

{selectedNode.name}

- +

{selectedNode.name}

+
-
-

IP Address

{selectedNode.ip}

+
+
+

IP Address

+

{selectedNode.ip}

+
-

Network Risk Score

-
-
-
80 ? '#e11d48' : selectedNode.risk > 40 ? '#f59e0b' : '#00D4AA' }} /> +

Network Risk Score

+
+
+
80 ? '#e11d48' : selectedNode.risk > 40 ? '#f59e0b' : '#00D4AA' + }} + />
- {selectedNode.risk}/100 + {selectedNode.risk}/100
-

Contextual Flows

+

Contextual Flows

-
- Outbound to External - 2m ago +
+ Outbound to External + 2m ago
-
- RPC Auth Attempt - 15m ago +
+ RPC Auth Attempt + 15m ago
- - + +
) : ( -
-
+
+
-

Select node to analyze

+

Select node to analyze

)}
@@ -336,71 +385,85 @@ const NetworkViewPage: React.FC = () => { {/* --- SERVICES TAB --- */} {activeTab === 'services' && ( -
+
- - - + + +
-
-
+
+
-

Active Network Services

-
- +

Active Network Services

+
+ setSearchQuery(e.target.value)} />
-
-
TimestampProtocolBytes SentDestination
{row.ts}{row.proto}{row.bytes}{row.dest}
+ {row.ts} + + {row.proto} + + {row.bytes} + + {row.dest} +
{log.timestamp.split(' ')[1]}{log.timestamp.split(' ')[1]}
= ({ def
-

{log.sourceIP}

+

{log.sourceIP}

{log.sourceAsset &&

{log.sourceAsset.hostname}

}
-

{log.destIP}

+

{log.destIP}

{log.destInfo &&

{log.destInfo.flag} {log.destInfo.hostname} {log.destInfo.malicious && }

}
- - - - - - - - +
+
ServicePort / ProtocolAssetsBandwidthRisk ProfileOps
+ + + + + + + + - + {filteredServices.map((service) => ( setSelectedServiceId(service.id === selectedServiceId ? null : service.id)} - className={`hover:bg-[#1e1e20] transition-colors group cursor-pointer ${selectedServiceId === service.id ? 'bg-[#1e1e20]' : ''}`} + className={`hover:bg-zinc-900/30 transition-colors group cursor-pointer ${ + selectedServiceId === service.id ? 'bg-zinc-900/30' : '' + }`} > - - - - - + + + + - ))} @@ -410,46 +473,54 @@ const NetworkViewPage: React.FC = () => { {selectedService && ( -
+
-

{selectedService.service} Details

-

Protocol Intelligence Analysis

+

{selectedService.service} Details

+

Protocol Intelligence Analysis

- +
-
-

Service Description

-

Encrypted web traffic using {selectedService.protocol} protocol on port {selectedService.port}. Primary entry/exit vector for web assets.

+
+

Service Description

+

+ Encrypted web traffic using {selectedService.protocol} protocol on port {selectedService.port}. Primary entry/exit vector for web assets. +

-
-

Top Assets Using Service

+
+

Top Assets Using Service

{[1, 2, 3].map(i => ( -
- 10.0.5.{i + 40} - 2.4 GB +
+ 10.0.5.{i + 40} + 2.4 GB
))}
-
-

Associated Detections

-
- +
+

Associated Detections

+
+
-

C2 Beaconing Found

-

Jan 15, 08:02 PM • HIGH CONF.

+

C2 Beaconing Found

+

Jan 15, 08:02 PM • HIGH CONF.

-
- - +
+ +
)} @@ -459,22 +530,31 @@ const NetworkViewPage: React.FC = () => { {/* --- TRAFFIC MATRIX TAB --- */} {activeTab === 'matrix' && ( -
+
- - - + + +
-
+
-

Cross-Segment Traffic Matrix

+

Cross-Segment Traffic Matrix

-
Low
-
High
-
Anomaly
+
+
+ Low +
+
+
+ High +
+
+
+ Anomaly +
@@ -484,14 +564,14 @@ const NetworkViewPage: React.FC = () => {
{SEGMENTS.map(h => ( - + ))} {SEGMENTS.map((row, i) => ( - + {SEGMENTS.map((col, j) => { const val = (Math.random() * 10).toFixed(1); const isAnomaly = (i === 2 && j === 4) || (i === 1 && j === 0); @@ -501,8 +581,8 @@ const NetworkViewPage: React.FC = () => {
ServicePort / ProtocolAssetsBandwidthRisk ProfileOps
+
-
+
- {service.service} + {service.service}
{service.port} / {service.protocol}{service.assets}{service.bandwidth} - - {service.risk} - + {service.port} / {service.protocol}{service.assets}{service.bandwidth} + {service.risk === 'high' && ( + + High + + )} + {service.risk === 'medium' && ( + + Medium + + )} + {service.risk === 'low' && ( + + Low + + )} + +
{h}{h}
{row}{row} setSelectedCell({ row: i, col: j })} - className={`p-6 rounded-xl text-xs font-black transition-all hover:scale-105 cursor-pointer relative group - ${isAnomaly ? 'bg-[#e11d48] text-white shadow-[0_0_15px_rgba(225,29,72,0.4)]' : 'text-gray-300'} + className={`p-6 rounded-xl text-sm font-semibold transition-all hover:scale-105 cursor-pointer relative group + ${isAnomaly ? 'bg-red-500 text-white shadow-lg' : 'text-white'} ${isActive ? 'ring-2 ring-white scale-105 z-10' : ''}`} style={!isAnomaly ? { backgroundColor: `rgba(0, 212, 170, ${intensity * 0.4 + 0.1})` } : {}} > @@ -520,46 +600,59 @@ const NetworkViewPage: React.FC = () => { {selectedCell && ( -
+
-

Flow Detail

-

{SEGMENTS[selectedCell.row]} → {SEGMENTS[selectedCell.col]}

+

Flow Detail

+

{SEGMENTS[selectedCell.row]} → {SEGMENTS[selectedCell.col]}

- +
-
-
ACTIVE SESSIONS1,423
-
AVG BANDWIDTH4.2 Gbps
-
UNIQUE ASSETS84
+
+
+ Active Sessions + 1,423 +
+
+ Avg Bandwidth + 4.2 Gbps +
+
+ Unique Assets + 84 +
-

Protocol Breakdown

+

Protocol Breakdown

{['HTTPS (82%)', 'SMB (12%)', 'RDP (4%)', 'Other (2%)'].map(p => (
-
-
+
+
- {p} + {p}
))}
-
-

Recent Connections

+
+

Recent Connections

{[1, 2, 3].map(i => ( -
- 10.0.{i}.42 → 10.0.{i + 2}.1 - 2m ago +
+ 10.0.{i}.42 → 10.0.{i + 2}.1 + 2m ago
))}
- +
)}
@@ -568,37 +661,39 @@ const NetworkViewPage: React.FC = () => { {/* --- PROTOCOLS TAB --- */} {activeTab === 'protocols' && ( -
+
- - - + + +
-
-

Protocol Volume (Last 24h)

- - - - - - - - {PROTOCOL_STATS.map((entry, index) => ( - - ))} - - - +
+

Protocol Volume (Last 24h)

+
+ + + + + + + + {PROTOCOL_STATS.map((entry, index) => ( + + ))} + + + +
-
-

Global Distribution

+
+

Global Distribution

@@ -615,18 +710,18 @@ const NetworkViewPage: React.FC = () => { ))} - +
-
+
{PROTOCOL_STATS.map((p, i) => ( -
+
- {p.name} + {p.name}
- {(p.value / 100).toFixed(1)}% + {(p.value / 100).toFixed(1)}%
))}
@@ -634,12 +729,15 @@ const NetworkViewPage: React.FC = () => {
-
+
-

Protocol Trends (Last 7 Days)

+

Protocol Trends (Last 7 Days)

{['HTTPS', 'DNS', 'SMB'].map(p => ( -
s.name===p)?.color }} />{p}
+
+
s.name===p)?.color }} /> + {p} +
))}
@@ -647,9 +745,9 @@ const NetworkViewPage: React.FC = () => { - - - + + + @@ -658,26 +756,34 @@ const NetworkViewPage: React.FC = () => {
-
-

Unusual Protocols Detected

-
+
+

Unusual Protocols Detected

+
{UNUSUAL_PROTOCOLS.map((u, i) => ( -
+
-
+
-

{u.proto}

-

{u.conns} Connections • {u.firstSeen}

+

{u.proto}

+

{u.conns} Connections • {u.firstSeen}

- +
))}
- +
@@ -688,4 +794,4 @@ const NetworkViewPage: React.FC = () => { ); }; -export default NetworkViewPage; +export default NetworkViewPage; \ No newline at end of file diff --git a/ui/pages/PlatformHealthPage.tsx b/ui/pages/PlatformHealthPage.tsx index 9680d78..9221bcd 100644 --- a/ui/pages/PlatformHealthPage.tsx +++ b/ui/pages/PlatformHealthPage.tsx @@ -149,7 +149,7 @@ const PlatformHealthPage: React.FC = () => {

Network Sensors Cluster (Zeek)

6 NODES ACTIVE
- +
@@ -256,7 +256,7 @@ const PlatformHealthPage: React.FC = () => { ].map(topic => (
-

{topic.name}

+

{topic.name}

{topic.rate} INBOUND

@@ -298,7 +298,7 @@ const PlatformHealthPage: React.FC = () => {

Processing Engine (Flink Clusters)

-
Component
+
@@ -344,7 +344,7 @@ const PlatformHealthPage: React.FC = () => {

Detection Performance Breakdown

-
Job Name
+
diff --git a/ui/pages/SettingsPage.tsx b/ui/pages/SettingsPage.tsx index 5a144b1..eec70bb 100644 --- a/ui/pages/SettingsPage.tsx +++ b/ui/pages/SettingsPage.tsx @@ -105,7 +105,7 @@ const SettingsPage: React.FC = ({ currentView }) => {
- +
@@ -210,7 +210,7 @@ const SettingsPage: React.FC = ({ currentView }) => {
-
Detection Type
+
@@ -492,7 +492,7 @@ const SettingsPage: React.FC = ({ currentView }) => {
-

Path

/data/hot

+

Path

/data/hot

Growth Rate

85 GB/day

Days Until Full

~90 Days

Retention

45 Days

@@ -514,7 +514,7 @@ const SettingsPage: React.FC = ({ currentView }) => {
-

ndr-archive

+

ndr-archive

Compression

Parquet (8:1)

Retention

365 Days

Retrieval Time

2.3s p50

@@ -529,7 +529,7 @@ const SettingsPage: React.FC = ({ currentView }) => { + Add Custom Policy}>
-
Device
+
@@ -623,7 +623,7 @@ const SettingsPage: React.FC = ({ currentView }) => {
-
Log Type
+
@@ -734,8 +734,8 @@ const SettingsPage: React.FC = ({ currentView }) => {

ClearFlow X Core

-

Version

v2.4.1

-

Build

847

+

Version

v2.4.1

+

Build

847

Released

2024-01-10

@@ -756,7 +756,7 @@ const SettingsPage: React.FC = ({ currentView }) => { ].map(comp => (
• {comp.name} - {comp.ver} + {comp.ver}
))} diff --git a/ui/pages/ThreatHuntingPage.tsx b/ui/pages/ThreatHuntingPage.tsx index 4d943d9..3b6c335 100644 --- a/ui/pages/ThreatHuntingPage.tsx +++ b/ui/pages/ThreatHuntingPage.tsx @@ -223,6 +223,7 @@ const MOCK_MATCHES: HuntResult[] = [ const ThreatHuntingPage: React.FC<{ defaultView?: 'builder' | 'history' | 'detail' | 'results' | 'findings' }> = ({ defaultView = 'history' }) => { const [view, setView] = useState<'builder' | 'history' | 'detail' | 'results' | 'findings'>(defaultView); const [selectedHunt, setSelectedHunt] = useState(null); + const [open, setOpen] = useState(false); // Builder State const [huntName, setHuntName] = useState(''); @@ -424,7 +425,7 @@ const ThreatHuntingPage: React.FC<{ defaultView?: 'builder' | 'history' | 'detai : 'hover:bg-zinc-800 border-transparent hover:border-zinc-700' }`} > -
+
{item.id} {selectedDefaultField === item.id && ( @@ -459,7 +460,7 @@ const ThreatHuntingPage: React.FC<{ defaultView?: 'builder' | 'history' | 'detai }} className="p-3 mb-1 rounded-xl hover:bg-zinc-800 cursor-pointer border border-transparent hover:border-blue-700/30 transition-all group" > -
{item.id}
+
{item.id}
{item.desc}
))} @@ -472,7 +473,7 @@ const ThreatHuntingPage: React.FC<{ defaultView?: 'builder' | 'history' | 'detai }} className="p-3 rounded-xl hover:bg-blue-600/10 cursor-pointer border border-blue-500/30 hover:border-blue-500/50 transition-all" > -
+
Use base field: {selectedDefaultField}
Select the original field without enrichment
@@ -535,7 +536,7 @@ const ThreatHuntingPage: React.FC<{ defaultView?: 'builder' | 'history' | 'detai : 'hover:bg-zinc-800 border-transparent hover:border-zinc-700' }`} > -
+
{item.id} {selectedDefaultField === item.id && ( @@ -570,10 +571,10 @@ const ThreatHuntingPage: React.FC<{ defaultView?: 'builder' | 'history' | 'detai }} className="p-3 mb-1 rounded-xl hover:bg-zinc-800 cursor-pointer border border-transparent hover:border-emerald-700/30 transition-all group" > -
{item.id}
+
{item.id}
{item.desc}
{item.table && ( -
Table: {item.table}
+
Table: {item.table}
)}
))} @@ -586,7 +587,7 @@ const ThreatHuntingPage: React.FC<{ defaultView?: 'builder' | 'history' | 'detai }} className="p-3 rounded-xl hover:bg-emerald-600/10 cursor-pointer border border-emerald-500/30 hover:border-emerald-500/50 transition-all" > -
+
Use value: {selectedDefaultField}
Select this common value directly
@@ -654,7 +655,7 @@ const ThreatHuntingPage: React.FC<{ defaultView?: 'builder' | 'history' | 'detai -

+ {/*

Coverage: 28.4 million events

Why this works:
@@ -663,7 +664,7 @@ const ThreatHuntingPage: React.FC<{ defaultView?: 'builder' | 'history' | 'detai
  • Honest about data source
  • Reads like a mission briefing
  • - + */} {/*
    Coverage: 28.4M events @@ -673,7 +674,7 @@ const ThreatHuntingPage: React.FC<{ defaultView?: 'builder' | 'history' | 'detai
    {/* IDENTITY & DETECTION LOGIC SECTION */} -
    +
    {/* STAGE 1: Initial Trigger */}
    @@ -717,7 +718,7 @@ const ThreatHuntingPage: React.FC<{ defaultView?: 'builder' | 'history' | 'detai value={cond.field} onChange={e => updateCondition(logicGroups[0].id, cond.id, { field: e.target.value })} placeholder="id.orig_h" - className="w-full bg-zinc-900 border border-zinc-800 rounded-lg pl-3 pr-10 py-3 text-xs font-mono text-zinc-300 outline-none focus:border-blue-500" + className="w-full bg-zinc-900 border border-zinc-800 rounded-lg pl-3 pr-10 py-3 text-xs text-zinc-300 outline-none focus:border-blue-500" /> @@ -1505,133 +1506,467 @@ const ThreatHuntingPage: React.FC<{ defaultView?: 'builder' | 'history' | 'detai
    {/* Correlation Key Set Cards */} -
    - {/* First Entity - 10.0.8.115 */} -
    -
    -
    -
    -
    -

    Affected Entity

    -
    - {/* - Entity Cluster - */} - Host: 10.0.8.115 -
    -

    UID: 9F3C2A77...

    -
    +
    + {/* First Entity - 10.0.8.115 */} + {/*
    +
    +
    +
    +
    +

    Affected Entity

    +
    + Host: 10.0.8.115 +
    +

    UID: 9F3C2A77...

    +
    -
    +
    -
    -

    Signals Observed

    -
    - - 01 - - - 02 - -
    -
    +
    +

    Signals Observed

    +
    + + 01 + + + 02 + +
    +
    -
    +
    -
    -

    Observed Activity Window

    -
    -

    - 08:0208:34 -

    -

    (32 minutes)

    -
    -
    +
    +

    Observed Activity Window

    +
    +

    + 08:0208:34 +

    +

    (32 minutes)

    +
    +
    -
    +
    -
    -

    Finding Confidence

    -
    - HIGH -
    -
    +
    +

    Finding Confidence

    +
    + HIGH
    +
    +
    - + +
    +
    */} + + {/* Second Entity - 10.0.12.88 */} +
    +
    +
    +
    +
    +

    Affected Entity

    +
    + Host: 10.0.12.88 +
    +

    UID: 7A4B9E12...

    +
    + +
    + +
    +

    Signals Observed

    +
    + + 01 + + + 02 + +
    +
    + +
    + +
    +

    Observed Activity Window

    +
    +

    + 09:1509:42 +

    +

    (27 minutes)

    +
    +
    + +
    + +
    +

    Finding Confidence

    +
    + MEDIUM +
    +
    - {/* Second Entity - 10.0.12.88 */} -
    -
    -
    -
    -
    -

    Affected Entity

    -
    - {/* - Entity Cluster - */} - Host: 10.0.8.115 -
    -

    UID: 7A4B9E12...

    -
    + {/* */} + + +
    + {open && (
    + {/* Header */} + {/*
    + +
    +
    +

    {selectedHunt.name}

    + + ZEEK ANALYZED + +
    +
    + HUNT ID: {selectedHunt.id} + + Executed 2 hours ago + +
    +
    + Network.Live +
    +
    +
    +
    + + +
    +
    */} + +
    + {/* Left Column - Main Content */} +
    + {/* Hunt Definition */} +
    +
    + +

    Hunt Definition

    +
    +

    + {selectedHunt.hypothesis} +

    -
    +
    + {/* Signal 1: DNS Activity */} +
    +
    + Signal 1: DNS Activity + + Active + +
    +
    +
    + Field: + query +
    +
    + Match: + *.top +
    +
    + Threshold: + More than 50 events within 5 minutes +
    +
    +
    -
    -

    Signals Observed

    -
    - - 01 - - - 02 - -
    -
    + {/* Signal 2: HTTP Activity */} +
    +
    + Signal 2: HTTP Activity + + Active + +
    +
    +
    + Field: + method +
    +
    + Value: + POST +
    +
    + Threshold: + More than 10 events within 10 minutes +
    +
    +
    +
    -
    + {/* Correlation Info */} +
    + + Signals correlated by + Source Host +
    + Global Window: + 5 Minutes +
    +
    +
    -
    -

    Observed Activity Window

    -
    -

    - 09:1509:42 -

    -

    (27 minutes)

    - -
    -
    + {/* Signals Observed */} +
    +

    Signals Observed

    + +
    +
    +
    Signal Name
    +
    Matches
    +
    Execution Window
    +
    -
    +
    +
    DNS Activity
    +
    5 matches
    +
    13:48 - 13:55
    +
    -
    -

    Finding Confidence

    -
    - MEDIUM -
    -
    +
    +
    HTTP Activity
    +
    2 matches
    +
    13:48 - 14:00
    +
    +
    +
    + + {/* Observed Activity Timeline */} +
    +

    Observed Activity Timeline

    + +
    + {/* Timeline line */} +
    + + {/* Timeline Event 1 */} +
    +
    +
    +
    + 13:48 DNS Signal Matched + 13:48
    +

    + Initial high-entropy query threshold reached from 192.168.1.45. +

    +
    - + {/* Timeline Event 2 */} +
    +
    +
    +
    + 13:46 DNS Signal Repeated + 13:46 +
    +

    + Subsequent queries to domain update.srv-log identified. +

    +
    +
    + + {/* Timeline Event 3 */} +
    +
    +
    +
    + 13:48 HTTP Signal Matched + 13:48 +
    +

    + Outbound POST request detected, initiating correlation sequence. +

    +
    +
    + + {/* Timeline Event 4 */} +
    +
    +
    +
    + 14:00 Correlation Window Completed + 14:00 +
    +

    + Final execution facts summarized. Correlation confirmed across 7 specific matches. +

    +
    +
    +
    +
    +
    + + {/* Right Column - Sidebar */} +
    + {/* Entities Involved */} +
    +

    Entities Involved

    + +
    + {/* Primary Entity */} +
    +
    + + 192.168.1.45 +
    +
    + Source System: WS-FRAN +
    + + Critical Asset + +
    + + {/* Secondary Entity */} +
    +
    + + FVLAN +
    +
    + Network System Involved +
    +
    + + {/* Destinations */} +
    +
    + + 3 Destinations +
    +
    + Countries Entities Contacted +
    +
    +
    +
    + + {/* Hunt Results Summary - Compact */} +
    +

    Hunt Results Summary

    + +
    + {/* Compact Grid Layout */} +
    + {/* Correlated Matches */} +
    +
    {selectedHunt.matchesFound}
    +
    Matches
    +
    + + {/* Total Activity */} +
    +
    32m
    +
    Time Span
    +
    +
    + + {/* Signals Satisfied */} +
    +
    + Signals Satisfied + 2 of 2 +
    +
    +
    +
    +
    +
    +
    + + {/* Next Actions */} +
    +

    Next Actions

    + +
    + + + + + +
    +
    +
    +
    + + {/* Footer Stats */} +
    +
    +
    +
    + + Total Data: 2.6 GB +
    +
    + + 12:1 +
    +
    + + 45 MB/s
    +
    )} + +
    +
    + +
    ); }; @@ -1656,7 +1991,7 @@ const ThreatHuntingPage: React.FC<{ defaultView?: 'builder' | 'history' | 'detai
    - HUNT ID: {selectedHunt.id} + HUNT ID: {selectedHunt.id} Executed 2 hours ago @@ -1676,282 +2011,280 @@ const ThreatHuntingPage: React.FC<{ defaultView?: 'builder' | 'history' | 'detai
    -
    - {/* Left Column - Main Content */} -
    - {/* Hunt Definition */} -
    -
    - -

    Hunt Definition

    -
    -

    - {selectedHunt.hypothesis} -

    - -
    - {/* Signal 1: DNS Activity */} -
    -
    - Signal 1: DNS Activity - - Active - +
    + {/* Left Column - Main Content */} +
    + {/* Hunt Definition */} +
    +
    + +

    Hunt Definition

    +
    +

    + {selectedHunt.hypothesis} +

    + +
    + {/* Signal 1: DNS Activity */} +
    +
    + Signal 1: DNS Activity + + Active + +
    +
    +
    + Field: + query
    -
    -
    - Field: - query -
    -
    - Match: - *.top -
    -
    - Threshold: - More than 50 events within 5 minutes -
    +
    + Match: + *.top +
    +
    + Threshold: + More than 50 events within 5 minutes
    +
    - {/* Signal 2: HTTP Activity */} -
    -
    - Signal 2: HTTP Activity - - Active - + {/* Signal 2: HTTP Activity */} +
    +
    + Signal 2: HTTP Activity + + Active + +
    +
    +
    + Field: + method
    -
    -
    - Field: - method -
    -
    - Value: - POST -
    -
    - Threshold: - More than 10 events within 10 minutes -
    +
    + Value: + POST +
    +
    + Threshold: + More than 10 events within 10 minutes
    +
    - {/* Correlation Info */} -
    - - Signals correlated by - Source Host -
    - Global Window: - 5 Minutes -
    + {/* Correlation Info */} +
    + + Signals correlated by + Source Host +
    + Global Window: + 5 Minutes
    -
    +
    +
    - {/* Signals Observed */} -
    -

    Signals Observed

    - -
    -
    -
    Signal Name
    -
    Matches
    -
    Execution Window
    -
    + {/* Signals Observed */} +
    +

    Signals Observed

    + +
    +
    +
    Signal Name
    +
    Matches
    +
    Execution Window
    +
    -
    -
    DNS Activity
    -
    5 matches
    -
    13:48 - 13:55
    -
    +
    +
    DNS Activity
    +
    5 matches
    +
    13:48 - 13:55
    +
    -
    -
    HTTP Activity
    -
    2 matches
    -
    13:48 - 14:00
    -
    +
    +
    HTTP Activity
    +
    2 matches
    +
    13:48 - 14:00
    -
    +
    +
    - {/* Observed Activity Timeline */} -
    -

    Observed Activity Timeline

    - -
    - {/* Timeline line */} -
    - - {/* Timeline Event 1 */} -
    -
    -
    -
    - 13:48 DNS Signal Matched - 13:48 -
    -

    - Initial high-entropy query threshold reached from 192.168.1.45. -

    + {/* Observed Activity Timeline */} +
    +

    Observed Activity Timeline

    + +
    + {/* Timeline line */} +
    + + {/* Timeline Event 1 */} +
    +
    +
    +
    + 13:48 DNS Signal Matched + 13:48
    +

    + Initial high-entropy query threshold reached from 192.168.1.45. +

    +
    - {/* Timeline Event 2 */} -
    -
    -
    -
    - 13:46 DNS Signal Repeated - 13:46 -
    -

    - Subsequent queries to domain update.srv-log identified. -

    + {/* Timeline Event 2 */} +
    +
    +
    +
    + 13:46 DNS Signal Repeated + 13:46
    +

    + Subsequent queries to domain update.srv-log identified. +

    +
    - {/* Timeline Event 3 */} -
    -
    -
    -
    - 13:48 HTTP Signal Matched - 13:48 -
    -

    - Outbound POST request detected, initiating correlation sequence. -

    + {/* Timeline Event 3 */} +
    +
    +
    +
    + 13:48 HTTP Signal Matched + 13:48
    +

    + Outbound POST request detected, initiating correlation sequence. +

    +
    - {/* Timeline Event 4 */} -
    -
    -
    -
    - 14:98 Correlation Window Completed - 14:98 -
    -

    - Final execution facts summarized. Correlation confirmed across 7 specific matches. -

    + {/* Timeline Event 4 */} +
    +
    +
    +
    + 14:00 Correlation Window Completed + 14:00
    +

    + Final execution facts summarized. Correlation confirmed across 7 specific matches. +

    -
    -
    +
    +
    +
    - {/* Right Column - Sidebar */} -
    - {/* Entities Involved */} -
    -

    Entities Involved

    - -
    - {/* Primary Entity */} -
    -
    - - 192.168.1.45 -
    -
    - Source System: WS-FRAN -
    -
    - - Critical Asset - -
    + {/* Right Column - Sidebar */} +
    + {/* Entities Involved */} +
    +

    Entities Involved

    + +
    + {/* Primary Entity */} +
    +
    + + 192.168.1.45 +
    +
    + Source System: WS-FRAN
    + + Critical Asset + +
    - {/* Secondary Entity */} -
    -
    - - FVLAN -
    -
    - Network System Involved -
    + {/* Secondary Entity */} +
    +
    + + FVLAN +
    +
    + Network System Involved
    +
    - {/* Destinations */} -
    -
    - - 3 Destinations -
    -
    - Countries Entities Contacted -
    + {/* Destinations */} +
    +
    + + 3 Destinations +
    +
    + Countries Entities Contacted
    -
    +
    +
    - {/* Hunt Results Summary */} -
    -

    Hunt Results Summary

    - -
    + {/* Hunt Results Summary - Compact */} +
    +

    Hunt Results Summary

    + +
    + {/* Compact Grid Layout */} +
    {/* Correlated Matches */} -
    -
    {selectedHunt.matchesFound}
    -
    Correlated Matches
    +
    +
    {selectedHunt.matchesFound}
    +
    Matches
    {/* Total Activity */} -
    -
    32m
    -
    Total Activity Span
    +
    +
    32m
    +
    Time Span
    +
    - {/* Signals Satisfied */} -
    -
    - Signals Satisfied - 2 of 2 -
    -
    -
    -
    -

    - All configured scoring criteria were associated output. -

    + {/* Signals Satisfied */} +
    +
    + Signals Satisfied + 2 of 2 +
    +
    +
    -
    +
    +
    - {/* Next Actions */} -
    -

    Next Actions

    - -
    - + {/* Next Actions */} +
    +

    Next Actions

    + +
    + - + - -
    -
    -
    + +
    +
    +
    {/* Footer Stats */}
    diff --git a/ui/pages/UseCaseDetailPage.tsx b/ui/pages/UseCaseDetailPage.tsx index 7af4f62..5f75ea1 100644 --- a/ui/pages/UseCaseDetailPage.tsx +++ b/ui/pages/UseCaseDetailPage.tsx @@ -1,27 +1,9 @@ import React, { useState } from 'react'; -import { - ArrowLeft, Layers, AlertTriangle, Shield, CheckCircle2, - ChevronDown, ChevronRight, Clock, Database, FileText +import { + ArrowLeft, Layers, AlertTriangle, Shield, CheckCircle2, + ChevronDown, ChevronRight, Clock, Database, FileText, Activity } from 'lucide-react'; -interface Stage { - id: number; - name: string; - purpose: string; - inputDependency: string; - dataSource: string; - fieldsUsed: string[]; - conditions: string[]; - thresholdLogic: string; - output: string; - status: 'active' | 'triggered' | 'pending'; -} - -interface Props { - useCaseId: string | null; - onBack: () => void; -} - const MOCK_USE_CASE = { id: 'UC-001', name: 'Ransomware Detection', @@ -32,7 +14,7 @@ const MOCK_USE_CASE = { confidence: 'HIGH' }; -const MOCK_STAGES: Stage[] = [ +const MOCK_STAGES = [ { id: 1, name: 'Behavioral Anomaly', @@ -43,7 +25,7 @@ const MOCK_STAGES: Stage[] = [ conditions: [ 'outbound_connection_count > (host_baseline + 3σ)', 'upload_bytes > 5 * daily_average', - 'activity_time between 00:00-05:00 local' + 'activity_time between 00:00–05:00 local' ], thresholdLogic: 'baseline_window = 14 days\nwindow_size = 5 minutes', output: 'STAGE-1 SIGNAL EMITTED (LOW CONFIDENCE)', @@ -53,7 +35,7 @@ const MOCK_STAGES: Stage[] = [ id: 2, name: 'File System Pressure', purpose: 'Identify rapid file operations characteristic of encryption.', - inputDependency: 'stage_1 and stage_2 signals triggered within 15 minutes window', + inputDependency: 'stage_1 signal within 15 min window', dataSource: 'OSQUERY: FILE_EVENTS', fieldsUsed: ['hostname', 'action', 'target_path', 'timestamp'], conditions: [ @@ -69,7 +51,7 @@ const MOCK_STAGES: Stage[] = [ id: 3, name: 'Context Correlation', purpose: 'Combine behavioral and system indicators for high-confidence detection.', - inputDependency: 'stage_1 and stage_2 signals triggered within 15 minutes window', + inputDependency: 'stage_1 and stage_2 within 15 min window', dataSource: 'MULTI-SOURCE', fieldsUsed: ['all_previous_stages', 'threat_intel', 'user_context'], conditions: [ @@ -83,262 +65,265 @@ const MOCK_STAGES: Stage[] = [ } ]; -const UseCaseDetailPage: React.FC = ({ useCaseId, onBack }) => { - const [expandedStages, setExpandedStages] = useState([1]); +const statusColor = (status) => ({ + active: { bg: 'bg-green-500/10', border: 'border-green-500/20', text: 'text-green-500', dot: 'bg-green-500' }, + triggered: { bg: 'bg-blue-500/10', border: 'border-blue-500/20', text: 'text-blue-500', dot: 'bg-blue-500' }, + pending: { bg: 'bg-zinc-900' , border: 'border-[#1e1e20]', text: 'text-zinc-500', dot: 'bg-zinc-500' } +}[status]); + +export default function UseCaseDetailPage({ useCaseId, onBack }) { + const [expandedStages, setExpandedStages] = useState([1]); - const toggleStage = (stageId: number) => { - setExpandedStages(prev => - prev.includes(stageId) - ? prev.filter(id => id !== stageId) - : [...prev, stageId] + const toggleStage = (id) => + setExpandedStages(prev => + prev.includes(id) ? prev.filter(s => s !== id) : [...prev, id] ); - }; return ( -
    - - {/* Compact Header */} -
    -
    - -
    -

    {MOCK_USE_CASE.name}

    -

    - {useCaseId || 'UC-001'} • {MOCK_USE_CASE.description} -

    +
    +
    + + {/* COMPACT HEADER */} +
    +
    + +
    +

    {MOCK_USE_CASE.name}

    +

    + {useCaseId || 'UC-001'} • {MOCK_USE_CASE.description} +

    +
    +
    +
    + + {MOCK_USE_CASE.stages} + + + {MOCK_USE_CASE.signals} + +
    + ML +
    +
    + {MOCK_USE_CASE.confidence} +
    - - {/* Inline Meta Info */} -
    - - - {MOCK_USE_CASE.stages} - - - - {MOCK_USE_CASE.signals} - - - ML - - - {MOCK_USE_CASE.confidence} - -
    -
    - {/* Why This Alert Was Triggered */} -
    -

    - Why This Alert Was Triggered -

    - -

    - This alert was triggered because the system detected sustained abnormal outbound data transfer behavior that deviated significantly from the host's historical baseline. -

    + {/* WHY THIS ALERT */} +
    +
    + + Why This Alert Was Triggered +
    -
    - - {/* Detection Stages */} -
    -

    - Detection stages: -

    -
    -
    - 1. -

    - Anomaly detected – Initial abnormal outbound activity was identified compared to normal behavior. -

    -
    -
    - 2. -

    - Behavior sustained – The abnormal behavior persisted across multiple observation intervals. -

    -
    -
    - 3. -

    - Alert threshold exceeded – Combined signal confidence crossed the alert threshold, resulting in alert generation. -

    +
    +

    + This alert fired because the system detected{' '} + sustained abnormal outbound data transfer behavior + {' '}that deviated significantly from the host's historical baseline. +

    + +
    + {/* Detection Stages */} +
    +
    +
    + Detection Stages +
    + {[ + ['Anomaly detected', 'Initial abnormal outbound activity identified vs. normal behavior.'], + ['Behavior sustained', 'Abnormal behavior persisted across multiple observation intervals.'], + ['Threshold exceeded', 'Combined signal confidence crossed the alert threshold.'] + ].map(([title, desc], i) => ( +
    + {i + 1} +
    + {title}: + {desc} +
    +
    + ))}
    -
    -
    - {/* Key Contributing Factors */} -
    -

    - Key contributing factors: -

    -
    -
    - -

    - Sustained outbound volume spike -

    + {/* Key Factors */} +
    +
    +
    + Key Factors +
    + {[ + 'Sustained outbound volume spike over baseline window.', + 'Abnormal upload-to-download ratio detected.', + 'Activity concentrated in off-hours (00:00–05:00).', + 'No corresponding authorized process found.' + ].map((item, i) => ( +
    + + {item} +
    + ))}
    -
    - -

    - Abnormal upload-to-download ratio + + {/* Context */} +

    +
    +
    + Context +
    +

    + Activity was observed consistently over a defined time window and was not a single transient spike. Host had no scheduled maintenance or backup activity during the flagged period.

    +
    +
    +

    Window

    +

    15 min

    +
    +
    +
    +

    Baseline

    +

    14 days

    +
    +
    +
    +

    Conf.

    +

    HIGH

    +
    +
    - - {/* Additional Context */} -
    -

    - Context: -

    -

    - The activity was observed consistently over a defined time window and was not a single transient spike. -

    -
    -
    -
    - {/* All Stages in Single View - Maximum Columns */} -
    - {MOCK_STAGES.map(stage => ( -
    - {/* Ultra Compact Stage Header */} - - - {/* Ultra Compact Content - 4 Column Grid */} - {expandedStages.includes(stage.id) && ( -
    -
    - - {/* Column 1: Input & Data Source */} -
    -
    -

    Input Dependency

    - {stage.inputDependency} + {/* card */} +
    + - {/* Column 2: Fields Used */} -
    -

    Fields Used

    -
    - {stage.fieldsUsed.map((field, idx) => ( - - {field} - - ))} -
    -
    + {open && ( +
    +
    - {/* Column 3: Conditions - Box for Important Info */} -
    -

    Detection Conditions

    -
    - {stage.conditions.map((condition, idx) => ( -
    - - {condition} + {/* col 1 – source */} +
    +
    +

    Input Dependency

    +
    {stage.inputDependency}
    +
    +
    +

    Data Source

    +
    + +
    {stage.dataSource}
    +
    +
    +
    + + {/* col 2 – fields */} +
    +

    Fields Used

    +
    + {stage.fieldsUsed.map((f, i) => ( + {f} + ))} +
    +
    + + {/* col 3 – conditions */} +
    +

    Detection Conditions

    +
    + {stage.conditions.map((c, i) => ( +
    + +
    {c}
    +
    + ))} +
    +
    + + {/* col 4 – threshold + output */} +
    +
    +

    Threshold Logic

    +
    {stage.thresholdLogic}
    +
    +
    +

    Output Signal

    +
    + +
    {stage.output}
    +
    +
    - ))} -
    -
    - {/* Column 4: Threshold & Output - Box for Important Info */} -
    -
    -

    Threshold Logic

    -
    {stage.thresholdLogic}
    -
    -
    -

    Output Signal

    -
    - - - {stage.output} -
    -
    - + )}
    - )} -
    - ))} -
    + ); + })} +
    - {/* Compact Triggered When Section */} -
    - -
    -

    Triggered When:

    -

    stage_1 signal exists for same host and time difference < 15 minutes

    + {/* TRIGGERED WHEN */} +
    +
    + +
    +
    + Triggered When: + + stage_1 signal exists for same host && time_diff {'<'} 15 minutes + +
    +
    ); -}; - -export default UseCaseDetailPage; \ No newline at end of file +} \ No newline at end of file diff --git a/ui/pages/UseCasesCatalogPage.tsx b/ui/pages/UseCasesCatalogPage.tsx index 2b3d367..ccc16bb 100644 --- a/ui/pages/UseCasesCatalogPage.tsx +++ b/ui/pages/UseCasesCatalogPage.tsx @@ -56,8 +56,8 @@ const CATEGORIES = [ { id: 'ALL', label: 'All Categories', color: 'zinc' }, { id: 'MALWARE', label: 'Malware', color: 'red' }, { id: 'EXFILTRATION', label: 'Exfiltration', color: 'blue' }, - { id: 'LATERAL_MOVEMENT', label: 'Lateral Movement', color: 'purple' }, - { id: 'RECONNAISSANCE', label: 'Reconnaissance', color: 'amber' } + { id: 'LATERAL_MOVEMENT', label: 'Lateral Movement', color: 'orange' }, + { id: 'RECONNAISSANCE', label: 'Reconnaissance', color: 'yellow' } ]; interface Props { @@ -80,35 +80,35 @@ const UseCasesCatalogPage: React.FC = ({ onSelectUseCase }) => { }; return ( -
    +
    {/* Header */}
    -

    Detection Catalog

    -

    Review architectural logic and multi-stage behavioral detection modules.

    +

    Detection Catalog

    +

    Review architectural logic and multi-stage behavioral detection modules.

    {/* Search and Filters */}
    {/* Search Bar */} -
    - +
    + setSearchQuery(e.target.value)} - className="w-full bg-zinc-900/60 border border-zinc-800 rounded-lg pl-12 pr-4 py-3.5 text-xs text-white outline-none focus:border-cyan-600 transition-colors" + className="w-full bg-zinc-900/60 backdrop-blur-md border border-white/10 rounded-lg pl-12 pr-6 py-3 text-sm text-zinc-200 outline-none focus:border-[#00D4AA] transition-all placeholder:text-zinc-500" />
    {/* Category Filter */}
    - +
    Timestamp