main
vue 287 lines 11.2 KB
Raw
1 <template>
2 <div class="flex flex-col gap-8">
3 <!-- Hero -->
4 <div class="flex flex-col items-center gap-3 py-6 text-center">
5 <div class="bg-primary/10 flex h-16 w-16 items-center justify-center rounded-2xl">
6 <Icon name="carbon:machine-learning-model" :size="32" class="text-primary" />
7 </div>
8 <h1 class="text-default text-2xl font-bold">Talon AI Analyst</h1>
9 <p class="text-secondary max-w-xl text-sm leading-relaxed">
10 Automated Tier 1 SOC analyst that investigates every alert end-to-end &mdash; from raw SIEM events to
11 structured investigation reports with severity assessments and recommended actions.
12 </p>
13 <div class="mt-1 flex items-center gap-2">
14 <n-tag size="small" round type="success">
15 <template #icon>
16 <Icon name="carbon:checkmark-filled" />
17 </template>
18 Integrated
19 </n-tag>
20 <n-tag
21 v-if="status"
22 size="small"
23 round
24 :type="status === 'healthy' ? 'success' : 'warning'"
25 class="animate-fade"
26 >
27 {{ status === "healthy" ? "Online" : status }}
28 </n-tag>
29 <n-tag v-else-if="statusChecked" size="small" round type="error" class="animate-fade">
30 Unreachable
31 </n-tag>
32 </div>
33 <a
34 href="https://github.com/taylorwalton/talon"
35 target="_blank"
36 rel="noopener noreferrer"
37 class="text-primary mt-1 inline-flex items-center gap-1.5 text-xs no-underline hover:underline"
38 >
39 <Icon name="carbon:logo-github" :size="14" />
40 <span>github.com/taylorwalton/talon</span>
41 <Icon name="carbon:launch" :size="11" />
42 </a>
43 </div>
44
45 <n-tabs type="card" placement="left" animated>
46 <n-tab-pane name="How It Works" tab="How It Works">
47 <div class="grid grid-cols-1 gap-3">
48 <StepCard
49 v-for="item in investigationSteps"
50 :key="item.step"
51 :step="item.step"
52 :title="item.title"
53 :description="item.description"
54 :icon="item.icon"
55 />
56 </div>
57 </n-tab-pane>
58 <n-tab-pane name="Capabilities" tab="Capabilities">
59 <div class="grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-3">
60 <FeatureCard
61 v-for="feature in capabilities"
62 :key="feature.title"
63 :title="feature.title"
64 :description="feature.description"
65 :icon="feature.icon"
66 />
67 </div>
68 </n-tab-pane>
69 <n-tab-pane name="Architecture" tab="Architecture">
70 <pre class="text-default text-xs leading-relaxed"><code>{{ architectureDiagram }}</code></pre>
71 </n-tab-pane>
72 <n-tab-pane name="CoPilot Integration" tab="CoPilot Integration">
73 <div class="grid grid-cols-1 gap-3 sm:grid-cols-2">
74 <FeatureCard
75 v-for="point in integrationPoints"
76 :key="point.title"
77 :title="point.title"
78 :description="point.description"
79 :icon="point.icon"
80 />
81 </div>
82 </n-tab-pane>
83 </n-tabs>
84 </div>
85 </template>
86
87 <script setup lang="ts">
88 import { NTabPane, NTabs, NTag } from "naive-ui"
89 import { defineComponent, h, onMounted, ref } from "vue"
90 import Api from "@/api"
91 import Icon from "@/components/common/Icon.vue"
92
93 const StepCard = defineComponent({
94 props: { step: Number, title: String, description: String, icon: String },
95 setup(props) {
96 return () =>
97 h("div", { class: "bg-secondary flex gap-3 rounded-lg p-4" }, [
98 h(
99 "div",
100 { class: "bg-primary/10 flex h-9 w-9 shrink-0 items-center justify-center rounded-lg" },
101 h("span", { class: "text-primary text-sm font-bold" }, props.step)
102 ),
103 h("div", { class: "flex flex-col gap-1" }, [
104 h("div", { class: "text-default text-sm font-semibold" }, props.title),
105 h("div", { class: "text-secondary text-xs leading-relaxed" }, props.description)
106 ])
107 ])
108 }
109 })
110
111 const FeatureCard = defineComponent({
112 props: { title: String, description: String, icon: String },
113 setup(props) {
114 return () =>
115 h("div", { class: "bg-secondary flex gap-3 rounded-lg p-4" }, [
116 h(
117 "div",
118 { class: "bg-primary/10 flex h-9 w-9 shrink-0 items-center justify-center rounded-lg" },
119 h(Icon, { name: props.icon, size: 16, class: "text-primary" })
120 ),
121 h("div", { class: "flex flex-col gap-1" }, [
122 h("div", { class: "text-default text-sm font-semibold" }, props.title),
123 h("div", { class: "text-secondary text-xs leading-relaxed" }, props.description)
124 ])
125 ])
126 }
127 })
128
129 // --- Status check ---
130
131 const status = ref<string | null>(null)
132 const statusChecked = ref(false)
133
134 onMounted(() => {
135 Api.talon
136 .getStatus()
137 .then(res => {
138 status.value = res.data.success ? "healthy" : "degraded"
139 })
140 .catch(() => {
141 status.value = null
142 })
143 .finally(() => {
144 statusChecked.value = true
145 })
146 })
147
148 // --- Static content ---
149
150 const investigationSteps = [
151 {
152 step: 1,
153 title: "Alert Ingestion",
154 description:
155 "Talon picks up OPEN alerts via real-time webhook (POST /investigate) or a 15-minute scheduled sweep as a safety net.",
156 icon: "carbon:notification"
157 },
158 {
159 step: 2,
160 title: "SIEM Correlation",
161 description:
162 "Queries OpenSearch/Wazuh for the raw event and correlated events across the same asset, time window, and rule groups.",
163 icon: "carbon:search"
164 },
165 {
166 step: 3,
167 title: "IOC Enrichment",
168 description:
169 "Extracts IOCs (IPs, hashes, domains, user accounts) and enriches them via VirusTotal, Shodan, and AbuseIPDB.",
170 icon: "carbon:security"
171 },
172 {
173 step: 4,
174 title: "Report & Write-back",
175 description:
176 "Generates a structured investigation report with MITRE ATT&CK mapping, severity assessment, and recommended actions — written back to CoPilot.",
177 icon: "carbon:document"
178 }
179 ]
180
181 const capabilities = [
182 {
183 title: "Privacy-Aware Anonymization",
184 description:
185 "An anonymizing MCP proxy replaces PII (usernames, hostnames, internal IPs) with session tokens before they reach the cloud model. A deanonymize tool restores real values in the final report.",
186 icon: "carbon:locked"
187 },
188 {
189 title: "Local LLM Support",
190 description:
191 "If Ollama is running, raw event interpretation routes through a local model — keeping the most sensitive analysis step entirely on-premises. No config needed if on the same host.",
192 icon: "carbon:model-alt"
193 },
194 {
195 title: "MemPalace Persistent Memory",
196 description:
197 "Long-term memory via ChromaDB + SQLite — past investigation outcomes, asset metadata, confirmed false positives, and IOC history are retrieved automatically at the start of each investigation.",
198 icon: "carbon:data-base"
199 },
200 {
201 title: "Alert-Type Templates",
202 description:
203 "Per-alert-type investigation guides (Sysmon Event 1, 3, 7, 11, 22, etc.) load automatically based on the alert's rule.groups field. Add new templates without touching code.",
204 icon: "carbon:template"
205 },
206 {
207 title: "MITRE ATT&CK Mapping",
208 description:
209 "Every investigation maps findings to MITRE ATT&CK tactics and techniques, providing standardized classification for SOC analysts and compliance reporting.",
210 icon: "carbon:chart-relationship"
211 },
212 {
213 title: "Containerized Isolation",
214 description:
215 "Each investigation runs in an isolated Linux container with a mount allowlist controlling file system access. Agents cannot modify their own configuration or escape the sandbox.",
216 icon: "carbon:container-software"
217 }
218 ]
219
220 const integrationPoints = [
221 {
222 title: "Real-Time Investigation Trigger",
223 description:
224 "When an alert is created in CoPilot's Incident Management, Talon can be triggered immediately via POST /investigate. The \"Investigate with AI Analyst\" button on any alert's Overview tab does exactly this.",
225 icon: "carbon:flash"
226 },
227 {
228 title: "Scheduled Alert Sweep",
229 description:
230 "Every 15 minutes, Talon queries the CoPilot database for OPEN alerts with no existing job and automatically investigates them — a safety net ensuring nothing is missed.",
231 icon: "carbon:time"
232 },
233 {
234 title: "Report Write-back via MCP",
235 description:
236 "Job status, full investigation reports, and enriched IOCs are persisted back into CoPilot's database via the CoPilot MCP server — no direct database writes from Talon.",
237 icon: "carbon:document-add"
238 },
239 {
240 title: "In-Alert Report Viewing",
241 description:
242 "When you open any alert in Incident Management, the AI Analyst tab automatically loads if an investigation report exists — showing severity, summary, full report, and recommended actions.",
243 icon: "carbon:view"
244 }
245 ]
246
247 const architectureDiagram = `┌───────────────────────────────────────────────────────┐
248 │ CoPilot (FastAPI) │
249 │ │
250 │ Alert created → POST /investigate ───────────────┐ │
251 │ GET /status, GET /jobs/:alertId ← Talon HTTP API │ │
252 │ │ │
253 │ Write-back API (MCP tools): │ │
254 │ POST /api/ai_analyst/jobs ←────────────┘ │
255 │ POST /api/ai_analyst/reports │
256 │ POST /api/ai_analyst/iocs │
257 │ MySQL: ai_analyst_job / report / ioc │
258 └───────────┬───────────────────────────────────────────┘
259 │ ▲ REST write-back
260 ▼ read-only MCP │
261 ┌────────────────────────────────┴──────────────────────┐
262 │ Talon (Node.js) │
263 │ │
264 │ HTTP channel (port 3100) │
265 │ POST /investigate ← CoPilot triggers this │
266 │ POST /message ← ad-hoc analyst prompts │
267 │ GET /status ← queue + job overview │
268 │ │
269 │ Scheduled task (every 15 min) │
270 │ Queries MySQL for OPEN alerts with no job row │
271 │ Runs full investigation per alert │
272 │ │
273 │ SOC agent (containerized) │
274 │ groups/copilot/CLAUDE.md ← investigation flow │
275 │ groups/copilot/prompts/ ← per-alert templates │
276 └───────────────┬───────────────────────────────────────┘
277
278 ▼ MCP tools (read-only)
279 ┌───────────────────────────────────────────────────────┐
280 │ opensearch-mcp — raw SIEM queries │
281 │ opensearch_anon — anonymizing proxy (PII→tokens) │
282 │ mysql-mcp — CoPilot DB (alerts, assets) │
283 │ copilot-mcp — CoPilot REST API write-back │
284 │ ollama (optional) — local LLM for sensitive data │
285 │ mempalace — persistent investigation memory │
286 └───────────────────────────────────────────────────────┘`
287 </script>