iflow-mcp-m507_ai-soc-agent 1.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- iflow_mcp_m507_ai_soc_agent-1.0.0.dist-info/METADATA +410 -0
- iflow_mcp_m507_ai_soc_agent-1.0.0.dist-info/RECORD +85 -0
- iflow_mcp_m507_ai_soc_agent-1.0.0.dist-info/WHEEL +5 -0
- iflow_mcp_m507_ai_soc_agent-1.0.0.dist-info/entry_points.txt +2 -0
- iflow_mcp_m507_ai_soc_agent-1.0.0.dist-info/licenses/LICENSE +21 -0
- iflow_mcp_m507_ai_soc_agent-1.0.0.dist-info/top_level.txt +1 -0
- src/__init__.py +8 -0
- src/ai_controller/README.md +139 -0
- src/ai_controller/__init__.py +12 -0
- src/ai_controller/agent_executor.py +596 -0
- src/ai_controller/cli/__init__.py +2 -0
- src/ai_controller/cli/main.py +243 -0
- src/ai_controller/session_manager.py +409 -0
- src/ai_controller/web/__init__.py +2 -0
- src/ai_controller/web/server.py +1181 -0
- src/ai_controller/web/static/css/README.md +102 -0
- src/api/__init__.py +13 -0
- src/api/case_management.py +271 -0
- src/api/edr.py +187 -0
- src/api/kb.py +136 -0
- src/api/siem.py +308 -0
- src/core/__init__.py +10 -0
- src/core/config.py +242 -0
- src/core/config_storage.py +684 -0
- src/core/dto.py +50 -0
- src/core/errors.py +36 -0
- src/core/logging.py +128 -0
- src/integrations/__init__.py +8 -0
- src/integrations/case_management/__init__.py +5 -0
- src/integrations/case_management/iris/__init__.py +11 -0
- src/integrations/case_management/iris/iris_client.py +885 -0
- src/integrations/case_management/iris/iris_http.py +274 -0
- src/integrations/case_management/iris/iris_mapper.py +263 -0
- src/integrations/case_management/iris/iris_models.py +128 -0
- src/integrations/case_management/thehive/__init__.py +8 -0
- src/integrations/case_management/thehive/thehive_client.py +193 -0
- src/integrations/case_management/thehive/thehive_http.py +147 -0
- src/integrations/case_management/thehive/thehive_mapper.py +190 -0
- src/integrations/case_management/thehive/thehive_models.py +125 -0
- src/integrations/cti/__init__.py +6 -0
- src/integrations/cti/local_tip/__init__.py +10 -0
- src/integrations/cti/local_tip/local_tip_client.py +90 -0
- src/integrations/cti/local_tip/local_tip_http.py +110 -0
- src/integrations/cti/opencti/__init__.py +10 -0
- src/integrations/cti/opencti/opencti_client.py +101 -0
- src/integrations/cti/opencti/opencti_http.py +418 -0
- src/integrations/edr/__init__.py +6 -0
- src/integrations/edr/elastic_defend/__init__.py +6 -0
- src/integrations/edr/elastic_defend/elastic_defend_client.py +351 -0
- src/integrations/edr/elastic_defend/elastic_defend_http.py +162 -0
- src/integrations/eng/__init__.py +10 -0
- src/integrations/eng/clickup/__init__.py +8 -0
- src/integrations/eng/clickup/clickup_client.py +513 -0
- src/integrations/eng/clickup/clickup_http.py +156 -0
- src/integrations/eng/github/__init__.py +8 -0
- src/integrations/eng/github/github_client.py +169 -0
- src/integrations/eng/github/github_http.py +158 -0
- src/integrations/eng/trello/__init__.py +8 -0
- src/integrations/eng/trello/trello_client.py +207 -0
- src/integrations/eng/trello/trello_http.py +162 -0
- src/integrations/kb/__init__.py +12 -0
- src/integrations/kb/fs_kb_client.py +313 -0
- src/integrations/siem/__init__.py +6 -0
- src/integrations/siem/elastic/__init__.py +6 -0
- src/integrations/siem/elastic/elastic_client.py +3319 -0
- src/integrations/siem/elastic/elastic_http.py +165 -0
- src/mcp/README.md +183 -0
- src/mcp/TOOLS.md +2827 -0
- src/mcp/__init__.py +13 -0
- src/mcp/__main__.py +18 -0
- src/mcp/agent_profiles.py +408 -0
- src/mcp/flow_agent_profiles.py +424 -0
- src/mcp/mcp_server.py +4086 -0
- src/mcp/rules_engine.py +487 -0
- src/mcp/runbook_manager.py +264 -0
- src/orchestrator/__init__.py +11 -0
- src/orchestrator/incident_workflow.py +244 -0
- src/orchestrator/tools_case.py +1085 -0
- src/orchestrator/tools_cti.py +359 -0
- src/orchestrator/tools_edr.py +315 -0
- src/orchestrator/tools_eng.py +378 -0
- src/orchestrator/tools_kb.py +156 -0
- src/orchestrator/tools_siem.py +1709 -0
- src/web/__init__.py +8 -0
- src/web/config_server.py +511 -0
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# CSS File Organization
|
|
2
|
+
|
|
3
|
+
This directory contains the CSS styles for the AI Controller web interface, organized into logical modules for easier maintenance and updates.
|
|
4
|
+
|
|
5
|
+
## File Structure
|
|
6
|
+
|
|
7
|
+
### `base.css`
|
|
8
|
+
**Purpose:** Base styles, CSS reset, body, and container styles
|
|
9
|
+
- Global reset rules (`*`, `margin`, `padding`, `box-sizing`)
|
|
10
|
+
- Body styling (font, background, colors, overflow)
|
|
11
|
+
- Container layout
|
|
12
|
+
|
|
13
|
+
### `layout.css`
|
|
14
|
+
**Purpose:** Main layout structure, sidebar, header, and content areas
|
|
15
|
+
- Main layout with sidebar (`main-layout`, `sidebar`, `main-panel`)
|
|
16
|
+
- Navigation items (`nav-item`, `nav-label`)
|
|
17
|
+
- Header styling (`header`, `header-actions`)
|
|
18
|
+
- Content area (`content-area`, `session-content`, `session-header`)
|
|
19
|
+
- Empty state messages (`no-session`)
|
|
20
|
+
|
|
21
|
+
### `buttons.css`
|
|
22
|
+
**Purpose:** All button variants and sizes
|
|
23
|
+
- Base button styles (`.btn`)
|
|
24
|
+
- Button variants: primary, secondary, danger
|
|
25
|
+
- Button sizes: small (`.btn-sm`)
|
|
26
|
+
- Hover states for all variants
|
|
27
|
+
|
|
28
|
+
### `tabs.css`
|
|
29
|
+
**Purpose:** Tab container, tabs, and tab-related elements
|
|
30
|
+
- Tab container and header (`tabs-container`, `tabs-header`)
|
|
31
|
+
- Tab groups and labels (`tab-group`, `tab-group-label`)
|
|
32
|
+
- Individual tabs (`tab`, `tab.active`)
|
|
33
|
+
- Tab badges and close buttons (`tab-badge`, `tab-close`)
|
|
34
|
+
|
|
35
|
+
### `status.css`
|
|
36
|
+
**Purpose:** Status badge indicators for sessions and autoruns
|
|
37
|
+
- Base status badge styles
|
|
38
|
+
- Status variants: pending, running, completed, failed, stopped
|
|
39
|
+
|
|
40
|
+
### `terminal.css`
|
|
41
|
+
**Purpose:** Terminal container, terminal output, and command input
|
|
42
|
+
- Terminal container and terminal display
|
|
43
|
+
- Terminal line styles (command, output, error, success, timestamp)
|
|
44
|
+
- Command input container and input field
|
|
45
|
+
|
|
46
|
+
### `autorun.css`
|
|
47
|
+
**Purpose:** Autorun-specific layout and terminal scrolling behavior
|
|
48
|
+
- Autorun content layout with fixed header and scrollable terminal
|
|
49
|
+
- Autorun terminal container overrides
|
|
50
|
+
- Autorun prompt display styling
|
|
51
|
+
- Scrolling behavior for autorun terminal (only terminal scrolls, header stays fixed)
|
|
52
|
+
|
|
53
|
+
### `modal.css`
|
|
54
|
+
**Purpose:** Dialog modals for creating sessions and autoruns
|
|
55
|
+
- Modal overlay and content container
|
|
56
|
+
- Modal header, body, and footer
|
|
57
|
+
- Form inputs within modals
|
|
58
|
+
- Close button styling
|
|
59
|
+
|
|
60
|
+
### `settings.css`
|
|
61
|
+
**Purpose:** Settings page layout and form elements
|
|
62
|
+
- Settings content and body layout
|
|
63
|
+
- Toggle switches and labels
|
|
64
|
+
- Help text and tooltips
|
|
65
|
+
- Help link styling
|
|
66
|
+
|
|
67
|
+
### `scrollbar.css`
|
|
68
|
+
**Purpose:** Custom scrollbar appearance
|
|
69
|
+
- Webkit scrollbar styling (width, track, thumb)
|
|
70
|
+
- Scrollbar hover states
|
|
71
|
+
|
|
72
|
+
## Loading Order
|
|
73
|
+
|
|
74
|
+
The CSS files are loaded in the following order in `index.html`:
|
|
75
|
+
1. `base.css` - Foundation styles
|
|
76
|
+
2. `layout.css` - Layout structure
|
|
77
|
+
3. `buttons.css` - Button components
|
|
78
|
+
4. `tabs.css` - Tab components
|
|
79
|
+
5. `status.css` - Status indicators
|
|
80
|
+
6. `terminal.css` - Terminal components
|
|
81
|
+
7. `autorun.css` - Autorun-specific overrides
|
|
82
|
+
8. `modal.css` - Modal components
|
|
83
|
+
9. `settings.css` - Settings page
|
|
84
|
+
10. `scrollbar.css` - Scrollbar styling
|
|
85
|
+
|
|
86
|
+
This order ensures that more specific styles (like `autorun.css`) can override base styles when needed.
|
|
87
|
+
|
|
88
|
+
## Making Changes
|
|
89
|
+
|
|
90
|
+
When updating styles:
|
|
91
|
+
- **Layout changes:** Edit `layout.css`
|
|
92
|
+
- **Button styling:** Edit `buttons.css`
|
|
93
|
+
- **Terminal appearance:** Edit `terminal.css`
|
|
94
|
+
- **Autorun scrolling/layout:** Edit `autorun.css`
|
|
95
|
+
- **Modal dialogs:** Edit `modal.css`
|
|
96
|
+
- **Settings page:** Edit `settings.css`
|
|
97
|
+
- **Global changes:** Edit `base.css` or `scrollbar.css`
|
|
98
|
+
|
|
99
|
+
## Versioning
|
|
100
|
+
|
|
101
|
+
Each CSS file includes a version query parameter in the HTML (`?v=1`) to enable cache busting when styles are updated. Increment the version number when making changes to force browsers to reload the updated styles.
|
|
102
|
+
|
src/api/__init__.py
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Generic, vendor-neutral APIs for SamiGPT.
|
|
3
|
+
|
|
4
|
+
This package defines interfaces and DTOs for:
|
|
5
|
+
- Case management (`case_management.py`)
|
|
6
|
+
- SIEM (`siem.py`)
|
|
7
|
+
- EDR (`edr.py`)
|
|
8
|
+
|
|
9
|
+
The orchestrator and LLM tools depend only on these modules, never on
|
|
10
|
+
vendor-specific integrations.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Generic case management API for SamiGPT.
|
|
3
|
+
|
|
4
|
+
This module defines vendor-neutral DTOs and the ``CaseManagementClient``
|
|
5
|
+
interface that orchestrator code and LLM tools will use. Concrete
|
|
6
|
+
implementations (e.g., TheHive) live under ``src/integrations``.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
from dataclasses import dataclass
|
|
12
|
+
from datetime import datetime
|
|
13
|
+
from enum import Enum
|
|
14
|
+
from typing import List, Optional, Protocol
|
|
15
|
+
|
|
16
|
+
from ..core.dto import BaseDTO
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class CaseStatus(str, Enum):
|
|
20
|
+
"""
|
|
21
|
+
High-level lifecycle status for a case.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
OPEN = "open"
|
|
25
|
+
IN_PROGRESS = "in_progress"
|
|
26
|
+
CLOSED = "closed"
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class CasePriority(str, Enum):
|
|
30
|
+
"""
|
|
31
|
+
Generic priority of a case.
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
LOW = "low"
|
|
35
|
+
MEDIUM = "medium"
|
|
36
|
+
HIGH = "high"
|
|
37
|
+
CRITICAL = "critical"
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
@dataclass
|
|
41
|
+
class CaseObservable(BaseDTO):
|
|
42
|
+
"""
|
|
43
|
+
Observable associated with a case (hash, IP, domain, URL, etc.).
|
|
44
|
+
"""
|
|
45
|
+
|
|
46
|
+
type: str
|
|
47
|
+
value: str
|
|
48
|
+
tags: Optional[List[str]] = None
|
|
49
|
+
description: Optional[str] = None
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
@dataclass
|
|
53
|
+
class CaseComment(BaseDTO):
|
|
54
|
+
"""
|
|
55
|
+
Comment on a case, either from a human analyst or the agent.
|
|
56
|
+
"""
|
|
57
|
+
|
|
58
|
+
id: Optional[str]
|
|
59
|
+
case_id: str
|
|
60
|
+
author: Optional[str]
|
|
61
|
+
content: str
|
|
62
|
+
created_at: Optional[datetime] = None
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
@dataclass
|
|
66
|
+
class CaseSummary(BaseDTO):
|
|
67
|
+
"""
|
|
68
|
+
Lightweight representation of a case for listing/search results.
|
|
69
|
+
"""
|
|
70
|
+
|
|
71
|
+
id: str
|
|
72
|
+
title: str
|
|
73
|
+
status: CaseStatus
|
|
74
|
+
priority: CasePriority
|
|
75
|
+
created_at: Optional[datetime] = None
|
|
76
|
+
updated_at: Optional[datetime] = None
|
|
77
|
+
assignee: Optional[str] = None
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
@dataclass
|
|
81
|
+
class Case(BaseDTO):
|
|
82
|
+
"""
|
|
83
|
+
Full case representation.
|
|
84
|
+
"""
|
|
85
|
+
|
|
86
|
+
id: Optional[str]
|
|
87
|
+
title: str
|
|
88
|
+
description: str
|
|
89
|
+
status: CaseStatus
|
|
90
|
+
priority: CasePriority
|
|
91
|
+
created_at: Optional[datetime] = None
|
|
92
|
+
updated_at: Optional[datetime] = None
|
|
93
|
+
assignee: Optional[str] = None
|
|
94
|
+
tags: Optional[List[str]] = None
|
|
95
|
+
observables: Optional[List[CaseObservable]] = None
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
@dataclass
|
|
99
|
+
class CaseAssignment(BaseDTO):
|
|
100
|
+
"""
|
|
101
|
+
Representation of a case assignment operation.
|
|
102
|
+
"""
|
|
103
|
+
|
|
104
|
+
case_id: str
|
|
105
|
+
assignee: str
|
|
106
|
+
assigned_at: Optional[datetime] = None
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
@dataclass
|
|
110
|
+
class CaseSearchQuery(BaseDTO):
|
|
111
|
+
"""
|
|
112
|
+
Generic search query for cases.
|
|
113
|
+
"""
|
|
114
|
+
|
|
115
|
+
text: Optional[str] = None
|
|
116
|
+
status: Optional[CaseStatus] = None
|
|
117
|
+
priority: Optional[CasePriority] = None
|
|
118
|
+
tags: Optional[List[str]] = None
|
|
119
|
+
assignee: Optional[str] = None
|
|
120
|
+
limit: int = 50
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
class CaseManagementClient(Protocol):
|
|
124
|
+
"""
|
|
125
|
+
Vendor-neutral interface for case management operations.
|
|
126
|
+
|
|
127
|
+
This interface is designed to support the skills described in the README:
|
|
128
|
+
- review_case
|
|
129
|
+
- list_cases
|
|
130
|
+
- search_cases
|
|
131
|
+
- add_case_comment
|
|
132
|
+
- attach_observable_to_case
|
|
133
|
+
- update_case_status
|
|
134
|
+
- assign_case
|
|
135
|
+
- get_case_timeline
|
|
136
|
+
"""
|
|
137
|
+
|
|
138
|
+
# Core CRUD operations
|
|
139
|
+
def create_case(self, case: Case) -> Case:
|
|
140
|
+
...
|
|
141
|
+
|
|
142
|
+
def get_case(self, case_id: str) -> Case:
|
|
143
|
+
...
|
|
144
|
+
|
|
145
|
+
def list_cases(
|
|
146
|
+
self,
|
|
147
|
+
status: Optional[CaseStatus] = None,
|
|
148
|
+
limit: int = 50,
|
|
149
|
+
) -> List[CaseSummary]:
|
|
150
|
+
...
|
|
151
|
+
|
|
152
|
+
def search_cases(self, query: CaseSearchQuery) -> List[CaseSummary]:
|
|
153
|
+
...
|
|
154
|
+
|
|
155
|
+
def update_case(self, case_id: str, updates: dict) -> Case:
|
|
156
|
+
...
|
|
157
|
+
|
|
158
|
+
def delete_case(self, case_id: str) -> None:
|
|
159
|
+
...
|
|
160
|
+
|
|
161
|
+
# Comments and observables
|
|
162
|
+
def add_case_comment(
|
|
163
|
+
self,
|
|
164
|
+
case_id: str,
|
|
165
|
+
content: str,
|
|
166
|
+
author: Optional[str] = None,
|
|
167
|
+
) -> CaseComment:
|
|
168
|
+
...
|
|
169
|
+
|
|
170
|
+
def add_case_observable(
|
|
171
|
+
self,
|
|
172
|
+
case_id: str,
|
|
173
|
+
observable: CaseObservable,
|
|
174
|
+
) -> CaseObservable:
|
|
175
|
+
...
|
|
176
|
+
|
|
177
|
+
# Status and assignment
|
|
178
|
+
def update_case_status(
|
|
179
|
+
self,
|
|
180
|
+
case_id: str,
|
|
181
|
+
status: CaseStatus,
|
|
182
|
+
) -> Case:
|
|
183
|
+
...
|
|
184
|
+
|
|
185
|
+
def assign_case(
|
|
186
|
+
self,
|
|
187
|
+
case_id: str,
|
|
188
|
+
assignee: str,
|
|
189
|
+
) -> CaseAssignment:
|
|
190
|
+
...
|
|
191
|
+
|
|
192
|
+
# Linking and timeline
|
|
193
|
+
def link_cases(
|
|
194
|
+
self,
|
|
195
|
+
source_case_id: str,
|
|
196
|
+
target_case_id: str,
|
|
197
|
+
link_type: str,
|
|
198
|
+
) -> None:
|
|
199
|
+
...
|
|
200
|
+
|
|
201
|
+
def get_case_timeline(self, case_id: str) -> List[CaseComment]:
|
|
202
|
+
...
|
|
203
|
+
|
|
204
|
+
# Tasks
|
|
205
|
+
def add_case_task(
|
|
206
|
+
self,
|
|
207
|
+
case_id: str,
|
|
208
|
+
title: str,
|
|
209
|
+
description: str,
|
|
210
|
+
assignee: Optional[str] = None,
|
|
211
|
+
priority: str = "medium",
|
|
212
|
+
status: str = "pending",
|
|
213
|
+
) -> Dict[str, Any]:
|
|
214
|
+
...
|
|
215
|
+
|
|
216
|
+
def list_case_tasks(self, case_id: str) -> List[Dict[str, Any]]:
|
|
217
|
+
...
|
|
218
|
+
|
|
219
|
+
def update_case_task_status(
|
|
220
|
+
self,
|
|
221
|
+
case_id: str,
|
|
222
|
+
task_id: str,
|
|
223
|
+
status: str,
|
|
224
|
+
) -> Dict[str, Any]:
|
|
225
|
+
"""
|
|
226
|
+
Update the status of a task in a case.
|
|
227
|
+
|
|
228
|
+
Args:
|
|
229
|
+
case_id: The ID of the case
|
|
230
|
+
task_id: The ID of the task to update
|
|
231
|
+
status: New task status (pending, in_progress, completed, blocked)
|
|
232
|
+
|
|
233
|
+
Returns:
|
|
234
|
+
Dictionary with updated task details
|
|
235
|
+
"""
|
|
236
|
+
...
|
|
237
|
+
|
|
238
|
+
# Assets
|
|
239
|
+
def add_case_asset(
|
|
240
|
+
self,
|
|
241
|
+
case_id: str,
|
|
242
|
+
asset_name: str,
|
|
243
|
+
asset_type: str,
|
|
244
|
+
description: Optional[str] = None,
|
|
245
|
+
ip_address: Optional[str] = None,
|
|
246
|
+
hostname: Optional[str] = None,
|
|
247
|
+
tags: Optional[List[str]] = None,
|
|
248
|
+
) -> Dict[str, Any]:
|
|
249
|
+
...
|
|
250
|
+
|
|
251
|
+
def list_case_assets(self, case_id: str) -> List[Dict[str, Any]]:
|
|
252
|
+
...
|
|
253
|
+
|
|
254
|
+
# Evidence
|
|
255
|
+
def add_case_evidence(
|
|
256
|
+
self,
|
|
257
|
+
case_id: str,
|
|
258
|
+
file_path: str,
|
|
259
|
+
description: Optional[str] = None,
|
|
260
|
+
evidence_type: Optional[str] = None,
|
|
261
|
+
) -> Dict[str, Any]:
|
|
262
|
+
...
|
|
263
|
+
|
|
264
|
+
def list_case_evidence(self, case_id: str) -> List[Dict[str, Any]]:
|
|
265
|
+
...
|
|
266
|
+
|
|
267
|
+
# Health check
|
|
268
|
+
def ping(self) -> bool:
|
|
269
|
+
...
|
|
270
|
+
|
|
271
|
+
|
src/api/edr.py
ADDED
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Generic EDR API for SamiGPT.
|
|
3
|
+
|
|
4
|
+
This module defines vendor-neutral DTOs and the ``EDRClient`` interface
|
|
5
|
+
that orchestrator code and LLM tools will use for endpoint investigation
|
|
6
|
+
and response actions.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
from dataclasses import dataclass
|
|
12
|
+
from datetime import datetime
|
|
13
|
+
from enum import Enum
|
|
14
|
+
from typing import List, Optional, Protocol
|
|
15
|
+
|
|
16
|
+
from ..core.dto import BaseDTO
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class Platform(str, Enum):
|
|
20
|
+
"""
|
|
21
|
+
Endpoint platform/OS.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
WINDOWS = "windows"
|
|
25
|
+
LINUX = "linux"
|
|
26
|
+
MACOS = "macos"
|
|
27
|
+
OTHER = "other"
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class DetectionType(str, Enum):
|
|
31
|
+
"""
|
|
32
|
+
High-level detection category.
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
MALWARE = "malware"
|
|
36
|
+
SUSPICIOUS_ACTIVITY = "suspicious_activity"
|
|
37
|
+
POLICY_VIOLATION = "policy_violation"
|
|
38
|
+
OTHER = "other"
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class ActionResult(str, Enum):
|
|
42
|
+
"""
|
|
43
|
+
Result of a response action.
|
|
44
|
+
"""
|
|
45
|
+
|
|
46
|
+
SUCCESS = "success"
|
|
47
|
+
FAILED = "failed"
|
|
48
|
+
PENDING = "pending"
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
@dataclass
|
|
52
|
+
class Endpoint(BaseDTO):
|
|
53
|
+
"""
|
|
54
|
+
Endpoint (host) representation.
|
|
55
|
+
"""
|
|
56
|
+
|
|
57
|
+
id: str
|
|
58
|
+
hostname: str
|
|
59
|
+
platform: Platform
|
|
60
|
+
last_seen: Optional[datetime] = None
|
|
61
|
+
primary_user: Optional[str] = None
|
|
62
|
+
is_isolated: bool = False
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
@dataclass
|
|
66
|
+
class Process(BaseDTO):
|
|
67
|
+
"""
|
|
68
|
+
Process running on an endpoint.
|
|
69
|
+
"""
|
|
70
|
+
|
|
71
|
+
pid: int
|
|
72
|
+
name: str
|
|
73
|
+
path: Optional[str] = None
|
|
74
|
+
user: Optional[str] = None
|
|
75
|
+
command_line: Optional[str] = None
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
@dataclass
|
|
79
|
+
class Detection(BaseDTO):
|
|
80
|
+
"""
|
|
81
|
+
Detection/alert from an EDR system.
|
|
82
|
+
"""
|
|
83
|
+
|
|
84
|
+
id: str
|
|
85
|
+
endpoint_id: str
|
|
86
|
+
created_at: datetime
|
|
87
|
+
detection_type: DetectionType
|
|
88
|
+
severity: Optional[str] = None
|
|
89
|
+
description: Optional[str] = None
|
|
90
|
+
file_hash: Optional[str] = None
|
|
91
|
+
process: Optional[Process] = None
|
|
92
|
+
raw: Optional[dict] = None
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
@dataclass
|
|
96
|
+
class QuarantineAction(BaseDTO):
|
|
97
|
+
"""
|
|
98
|
+
Represents an isolation/quarantine action on an endpoint.
|
|
99
|
+
"""
|
|
100
|
+
|
|
101
|
+
endpoint_id: str
|
|
102
|
+
requested_at: datetime
|
|
103
|
+
completed_at: Optional[datetime] = None
|
|
104
|
+
result: ActionResult = ActionResult.PENDING
|
|
105
|
+
message: Optional[str] = None
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
@dataclass
|
|
109
|
+
class KillProcessAction(BaseDTO):
|
|
110
|
+
"""
|
|
111
|
+
Represents a process termination action on an endpoint.
|
|
112
|
+
"""
|
|
113
|
+
|
|
114
|
+
endpoint_id: str
|
|
115
|
+
pid: int
|
|
116
|
+
requested_at: datetime
|
|
117
|
+
completed_at: Optional[datetime] = None
|
|
118
|
+
result: ActionResult = ActionResult.PENDING
|
|
119
|
+
message: Optional[str] = None
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
@dataclass
|
|
123
|
+
class ArtifactCollectionRequest(BaseDTO):
|
|
124
|
+
"""
|
|
125
|
+
Represents a forensic artifact collection request.
|
|
126
|
+
"""
|
|
127
|
+
|
|
128
|
+
endpoint_id: str
|
|
129
|
+
requested_at: datetime
|
|
130
|
+
artifact_types: List[str]
|
|
131
|
+
completed_at: Optional[datetime] = None
|
|
132
|
+
result: ActionResult = ActionResult.PENDING
|
|
133
|
+
message: Optional[str] = None
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
class EDRClient(Protocol):
|
|
137
|
+
"""
|
|
138
|
+
Vendor-neutral interface for EDR operations.
|
|
139
|
+
|
|
140
|
+
This interface is designed to support the skills described in the README:
|
|
141
|
+
- get_endpoint_summary
|
|
142
|
+
- get_detection_details
|
|
143
|
+
- isolate_endpoint
|
|
144
|
+
- release_endpoint_isolation
|
|
145
|
+
- kill_process_on_endpoint
|
|
146
|
+
- collect_forensic_artifacts
|
|
147
|
+
"""
|
|
148
|
+
|
|
149
|
+
# Endpoint and detection retrieval
|
|
150
|
+
def get_endpoint_summary(self, endpoint_id: str) -> Endpoint:
|
|
151
|
+
...
|
|
152
|
+
|
|
153
|
+
def list_endpoints(self, limit: int = 50) -> List[Endpoint]:
|
|
154
|
+
...
|
|
155
|
+
|
|
156
|
+
def get_detection_details(self, detection_id: str) -> Detection:
|
|
157
|
+
...
|
|
158
|
+
|
|
159
|
+
def list_detections(
|
|
160
|
+
self,
|
|
161
|
+
endpoint_id: Optional[str] = None,
|
|
162
|
+
limit: int = 50,
|
|
163
|
+
) -> List[Detection]:
|
|
164
|
+
...
|
|
165
|
+
|
|
166
|
+
# Response actions
|
|
167
|
+
def isolate_endpoint(self, endpoint_id: str) -> QuarantineAction:
|
|
168
|
+
...
|
|
169
|
+
|
|
170
|
+
def release_endpoint_isolation(self, endpoint_id: str) -> QuarantineAction:
|
|
171
|
+
...
|
|
172
|
+
|
|
173
|
+
def kill_process_on_endpoint(
|
|
174
|
+
self,
|
|
175
|
+
endpoint_id: str,
|
|
176
|
+
pid: int,
|
|
177
|
+
) -> KillProcessAction:
|
|
178
|
+
...
|
|
179
|
+
|
|
180
|
+
def collect_forensic_artifacts(
|
|
181
|
+
self,
|
|
182
|
+
endpoint_id: str,
|
|
183
|
+
artifact_types: List[str],
|
|
184
|
+
) -> ArtifactCollectionRequest:
|
|
185
|
+
...
|
|
186
|
+
|
|
187
|
+
|
src/api/kb.py
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Knowledge Base (KB) API for client infrastructure.
|
|
3
|
+
|
|
4
|
+
This module defines DTOs and the ``KBClient`` interface that orchestrator code
|
|
5
|
+
and MCP tools will use to read and present client infrastructure knowledge from
|
|
6
|
+
the local filesystem (``client_env/*``).
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
from dataclasses import dataclass, field
|
|
12
|
+
from typing import List, Optional, Protocol, Dict, Any
|
|
13
|
+
|
|
14
|
+
from ..core.dto import BaseDTO
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@dataclass
|
|
18
|
+
class KBSubnet(BaseDTO):
|
|
19
|
+
"""Represents a logical subnet or network segment."""
|
|
20
|
+
|
|
21
|
+
name: str
|
|
22
|
+
cidr: str
|
|
23
|
+
network_type: Optional[str] = None
|
|
24
|
+
access_method: Optional[List[str]] = None
|
|
25
|
+
description: Optional[str] = None
|
|
26
|
+
tags: Optional[List[str]] = None
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@dataclass
|
|
30
|
+
class KBServer(BaseDTO):
|
|
31
|
+
"""Represents an internal server or infrastructure node."""
|
|
32
|
+
|
|
33
|
+
hostname: str
|
|
34
|
+
ip_address: Optional[str] = None
|
|
35
|
+
role: Optional[str] = None
|
|
36
|
+
environment: Optional[str] = None
|
|
37
|
+
os: Optional[str] = None
|
|
38
|
+
description: Optional[str] = None
|
|
39
|
+
criticality: Optional[str] = None
|
|
40
|
+
tags: Optional[List[str]] = None
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
@dataclass
|
|
44
|
+
class KBUser(BaseDTO):
|
|
45
|
+
"""Represents an internal user/account in the environment."""
|
|
46
|
+
|
|
47
|
+
username: str
|
|
48
|
+
display_name: Optional[str] = None
|
|
49
|
+
account_type: Optional[str] = None
|
|
50
|
+
department: Optional[str] = None
|
|
51
|
+
privilege_level: Optional[str] = None
|
|
52
|
+
description: Optional[str] = None
|
|
53
|
+
tags: Optional[List[str]] = None
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
@dataclass
|
|
57
|
+
class KBDeviceSchema(BaseDTO):
|
|
58
|
+
"""Represents a naming schema pattern for devices/hosts."""
|
|
59
|
+
|
|
60
|
+
pattern: str
|
|
61
|
+
pattern_style: str
|
|
62
|
+
device_type: str
|
|
63
|
+
example: Optional[str] = None
|
|
64
|
+
description: Optional[str] = None
|
|
65
|
+
tags: Optional[List[str]] = None
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
@dataclass
|
|
69
|
+
class KBUserSchema(BaseDTO):
|
|
70
|
+
"""Represents a naming schema pattern for user accounts."""
|
|
71
|
+
|
|
72
|
+
pattern: str
|
|
73
|
+
pattern_style: str
|
|
74
|
+
user_type: str
|
|
75
|
+
example: Optional[str] = None
|
|
76
|
+
description: Optional[str] = None
|
|
77
|
+
tags: Optional[List[str]] = None
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
@dataclass
|
|
81
|
+
class KBEnvRules(BaseDTO):
|
|
82
|
+
"""Represents environment-wide classification and risk rules."""
|
|
83
|
+
|
|
84
|
+
version: Optional[str] = None
|
|
85
|
+
environment_types: Optional[List[str]] = None
|
|
86
|
+
network_classification: Optional[Dict[str, Any]] = None
|
|
87
|
+
user_categories: Optional[Dict[str, Any]] = None
|
|
88
|
+
general_rules: Optional[List[Dict[str, Any]]] = None
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
@dataclass
|
|
92
|
+
class KBClientInfra(BaseDTO):
|
|
93
|
+
"""
|
|
94
|
+
Aggregated view of a client's infrastructure as loaded from client_env/*.
|
|
95
|
+
"""
|
|
96
|
+
|
|
97
|
+
client_name: str
|
|
98
|
+
subnets: List[KBSubnet] = field(default_factory=list)
|
|
99
|
+
servers: List[KBServer] = field(default_factory=list)
|
|
100
|
+
users: List[KBUser] = field(default_factory=list)
|
|
101
|
+
device_schemas: List[KBDeviceSchema] = field(default_factory=list)
|
|
102
|
+
user_schemas: List[KBUserSchema] = field(default_factory=list)
|
|
103
|
+
env_rules: Optional[KBEnvRules] = None
|
|
104
|
+
summary: Optional[str] = None
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
class KBClient(Protocol):
|
|
108
|
+
"""
|
|
109
|
+
Interface for knowledge base clients that provide client infrastructure
|
|
110
|
+
knowledge to the MCP server and orchestrator tools.
|
|
111
|
+
"""
|
|
112
|
+
|
|
113
|
+
def list_clients(self) -> List[str]:
|
|
114
|
+
"""
|
|
115
|
+
List available client environments.
|
|
116
|
+
|
|
117
|
+
Returns:
|
|
118
|
+
List of client identifiers (e.g., ``acme_corp_client``).
|
|
119
|
+
"""
|
|
120
|
+
|
|
121
|
+
...
|
|
122
|
+
|
|
123
|
+
def get_client_infra(self, client_name: str) -> KBClientInfra:
|
|
124
|
+
"""
|
|
125
|
+
Load and aggregate infrastructure knowledge for a specific client.
|
|
126
|
+
|
|
127
|
+
Args:
|
|
128
|
+
client_name: Client identifier (e.g., ``acme_corp_client`` or ``acme_corp``).
|
|
129
|
+
|
|
130
|
+
Returns:
|
|
131
|
+
KBClientInfra object with normalized data and an optional summary string.
|
|
132
|
+
"""
|
|
133
|
+
|
|
134
|
+
...
|
|
135
|
+
|
|
136
|
+
|