precommit-fixes (#855)
taylor_socfortress committed
May 8, 2026 at 10:26 UTC
b7d7d121592ac4fc6105503090e9362e94496020
78 files changed
+868
-668
backend/app/active_response/schema/active_response.py
+18
-11
@@ -1,12 +1,16 @@
1
from enum import Enum
2
-from typing import Literal, Any
2
+from typing import Any
3
from typing import Dict
4
from typing import List
5
+from typing import Literal
6
from typing import Optional
7
8
from fastapi import HTTPException
8
-from pydantic import field_validator, model_validator, ConfigDict, BaseModel
9
+from pydantic import BaseModel
10
+from pydantic import ConfigDict
11
from pydantic import Field
12
+from pydantic import field_validator
13
+from pydantic import model_validator
14
15
16
class ActiveResponsesSupported(Enum):
@@ -121,16 +125,19 @@ class InvokeActiveResponseRequest(BaseModel):
125
raise HTTPException(status_code=400, detail="Invalid command for alert")
126
127
return values
124
- model_config = ConfigDict(json_schema_extra={
125
- "example": {
126
- "endpoint": "/active-response",
127
- "arguments": [],
128
- "command": "windows_firewall",
129
- "custom": True,
130
- "alert": {"action": "block", "ip": "1.1.1.1"},
131
- "params": {"wait_for_complete": True, "agents_list": ["032"]},
128
+
129
+ model_config = ConfigDict(
130
+ json_schema_extra={
131
+ "example": {
132
+ "endpoint": "/active-response",
133
+ "arguments": [],
134
+ "command": "windows_firewall",
135
+ "custom": True,
136
+ "alert": {"action": "block", "ip": "1.1.1.1"},
137
+ "params": {"wait_for_complete": True, "agents_list": ["032"]},
138
+ },
139
},
133
- })
140
+ )
141
142
143
class InvokeActiveResponseResponse(BaseModel):
backend/app/active_response/schema/graylog.py
+80
-75
@@ -4,7 +4,8 @@ from typing import Dict
4
from typing import List
5
from typing import Optional
6
7
-from pydantic import ConfigDict, BaseModel
7
+from pydantic import BaseModel
8
+from pydantic import ConfigDict
9
from pydantic import Field
10
11
@@ -69,46 +70,48 @@ class GraylogEventNotification(BaseModel):
70
job_trigger_id: str
71
event: GraylogEvent
72
backlog: List[Any] = Field(default_factory=list)
72
- model_config = ConfigDict(json_schema_extra={
73
- "example": {
74
- "event_definition_id": "67c78b93cf26aa2045bdc2ea",
75
- "event_definition_type": "aggregation-v1",
76
- "event_definition_title": "ACTIVE RESPONSE WEBSERVER THREAT INTEL",
77
- "event_definition_description": "",
78
- "job_definition_id": "67c78befcf26aa2045bdc4e9",
79
- "job_trigger_id": "67c78c0bcf26aa2045bdc5b5",
80
- "event": {
81
- "id": "01JNHQP35THD48VH8601F6EMHE",
82
- "event_definition_type": "aggregation-v1",
73
+ model_config = ConfigDict(
74
+ json_schema_extra={
75
+ "example": {
76
"event_definition_id": "67c78b93cf26aa2045bdc2ea",
84
- "origin_context": "urn:graylog:message:es:graylog-01_3:766b70b4-f94f-11ef-be9a-005056b6f13d",
85
- "timestamp": "2025-03-04T23:21:55.840Z",
86
- "timestamp_processing": "2025-03-04T23:26:03.450Z",
87
- "timerange_start": None,
88
- "timerange_end": None,
89
- "streams": [],
90
- "source_streams": ["679945aa7c4dd06afcef5feb", "679945a47c4dd06afcef5ef3"],
91
- "message": "ACTIVE RESPONSE WEBSERVER THREAT INTEL",
92
- "source": "soc-grlog01",
93
- "key_tuple": [],
94
- "key": "",
95
- "priority": 2,
96
- "scores": {},
97
- "associated_assets": [],
98
- "alert": True,
99
- "fields": {"COMMAND": "domain_sinkhole", "AGENT_ID": "032", "ACTION": "sinkhole", "VALUE": "example.com"},
100
- "group_by_fields": {},
101
- "replay_info": {
102
- "timerange_start": "2025-03-04T23:21:03.360Z",
103
- "timerange_end": "2025-03-04T23:26:03.360Z",
104
- "query": "_exists_:threat_intel_score",
105
- "streams": ["679945aa7c4dd06afcef5feb", "679945a47c4dd06afcef5ef3"],
106
- "filters": [],
77
+ "event_definition_type": "aggregation-v1",
78
+ "event_definition_title": "ACTIVE RESPONSE WEBSERVER THREAT INTEL",
79
+ "event_definition_description": "",
80
+ "job_definition_id": "67c78befcf26aa2045bdc4e9",
81
+ "job_trigger_id": "67c78c0bcf26aa2045bdc5b5",
82
+ "event": {
83
+ "id": "01JNHQP35THD48VH8601F6EMHE",
84
+ "event_definition_type": "aggregation-v1",
85
+ "event_definition_id": "67c78b93cf26aa2045bdc2ea",
86
+ "origin_context": "urn:graylog:message:es:graylog-01_3:766b70b4-f94f-11ef-be9a-005056b6f13d",
87
+ "timestamp": "2025-03-04T23:21:55.840Z",
88
+ "timestamp_processing": "2025-03-04T23:26:03.450Z",
89
+ "timerange_start": None,
90
+ "timerange_end": None,
91
+ "streams": [],
92
+ "source_streams": ["679945aa7c4dd06afcef5feb", "679945a47c4dd06afcef5ef3"],
93
+ "message": "ACTIVE RESPONSE WEBSERVER THREAT INTEL",
94
+ "source": "soc-grlog01",
95
+ "key_tuple": [],
96
+ "key": "",
97
+ "priority": 2,
98
+ "scores": {},
99
+ "associated_assets": [],
100
+ "alert": True,
101
+ "fields": {"COMMAND": "domain_sinkhole", "AGENT_ID": "032", "ACTION": "sinkhole", "VALUE": "example.com"},
102
+ "group_by_fields": {},
103
+ "replay_info": {
104
+ "timerange_start": "2025-03-04T23:21:03.360Z",
105
+ "timerange_end": "2025-03-04T23:26:03.360Z",
106
+ "query": "_exists_:threat_intel_score",
107
+ "streams": ["679945aa7c4dd06afcef5feb", "679945a47c4dd06afcef5ef3"],
108
+ "filters": [],
109
+ },
110
},
111
+ "backlog": [],
112
},
109
- "backlog": [],
113
},
111
- })
114
+ )
115
116
117
class GraylogThresholdEvent(BaseModel):
@@ -144,47 +147,49 @@ class GraylogThresholdEventNotification(BaseModel):
147
job_trigger_id: str
148
event: GraylogThresholdEvent
149
backlog: List[Any] = Field(default_factory=list)
147
- model_config = ConfigDict(json_schema_extra={
148
- "example": {
149
- "event_definition_id": "67b6687184088513bdc6cd1b",
150
- "event_definition_type": "aggregation-v1",
151
- "event_definition_title": "DELL SWITCHES - MULTIPLE AUTH FAILURES",
152
- "event_definition_description": "DELL SWITCHES - MULTIPLE AUTH FAILURES",
153
- "job_definition_id": "67dde9bc84088513bde5ce29",
154
- "job_trigger_id": "67ddeabf84088513bde5d283",
155
- "event": {
156
- "id": "01JPXDSZ8AECWZ88HR9JQPYHJP",
157
- "event_definition_type": "aggregation-v1",
150
+ model_config = ConfigDict(
151
+ json_schema_extra={
152
+ "example": {
153
"event_definition_id": "67b6687184088513bdc6cd1b",
159
- "origin_context": None,
160
- "timestamp": "2025-03-21T22:39:54.219Z",
161
- "timestamp_processing": "2025-03-21T22:39:59.754Z",
162
- "timerange_start": "2024-08-25T14:39:54.219Z",
163
- "timerange_end": "2025-03-21T22:39:54.219Z",
164
- "streams": [],
165
- "source_streams": ["67abcb0a84088513bdc09e32"],
166
- "message": "DELL SWITCHES - MULTIPLE AUTH FAILURES: 10.0.64.233 - count()=14.0",
167
- "source": "soc-grlog02",
168
- "key_tuple": [],
169
- "key": "",
170
- "priority": 2,
171
- "scores": {},
172
- "associated_assets": [],
173
- "alert": True,
174
- "fields": {
175
- "CUSTOMER_CODE": "6bdd96a0-06a5-11f0-a499-005056b6c109",
176
- "SOURCE": "DELLSWITCH",
177
- "ALERT_DESCRIPTION": "THIS IS A TEST",
178
- },
179
- "group_by_fields": {"source": "10.0.64.233"},
180
- "replay_info": {
154
+ "event_definition_type": "aggregation-v1",
155
+ "event_definition_title": "DELL SWITCHES - MULTIPLE AUTH FAILURES",
156
+ "event_definition_description": "DELL SWITCHES - MULTIPLE AUTH FAILURES",
157
+ "job_definition_id": "67dde9bc84088513bde5ce29",
158
+ "job_trigger_id": "67ddeabf84088513bde5d283",
159
+ "event": {
160
+ "id": "01JPXDSZ8AECWZ88HR9JQPYHJP",
161
+ "event_definition_type": "aggregation-v1",
162
+ "event_definition_id": "67b6687184088513bdc6cd1b",
163
+ "origin_context": None,
164
+ "timestamp": "2025-03-21T22:39:54.219Z",
165
+ "timestamp_processing": "2025-03-21T22:39:59.754Z",
166
"timerange_start": "2024-08-25T14:39:54.219Z",
167
"timerange_end": "2025-03-21T22:39:54.219Z",
183
- "query": '"An invalid user tried to login"',
184
- "streams": ["67abcb0a84088513bdc09e32"],
185
- "filters": [],
168
+ "streams": [],
169
+ "source_streams": ["67abcb0a84088513bdc09e32"],
170
+ "message": "DELL SWITCHES - MULTIPLE AUTH FAILURES: 10.0.64.233 - count()=14.0",
171
+ "source": "soc-grlog02",
172
+ "key_tuple": [],
173
+ "key": "",
174
+ "priority": 2,
175
+ "scores": {},
176
+ "associated_assets": [],
177
+ "alert": True,
178
+ "fields": {
179
+ "CUSTOMER_CODE": "6bdd96a0-06a5-11f0-a499-005056b6c109",
180
+ "SOURCE": "DELLSWITCH",
181
+ "ALERT_DESCRIPTION": "THIS IS A TEST",
182
+ },
183
+ "group_by_fields": {"source": "10.0.64.233"},
184
+ "replay_info": {
185
+ "timerange_start": "2024-08-25T14:39:54.219Z",
186
+ "timerange_end": "2025-03-21T22:39:54.219Z",
187
+ "query": '"An invalid user tried to login"',
188
+ "streams": ["67abcb0a84088513bdc09e32"],
189
+ "filters": [],
190
+ },
191
},
192
+ "backlog": [],
193
},
188
- "backlog": [],
194
},
190
- })
195
+ )
backend/app/agents/sca/schema/sca.py
+2
-1
@@ -4,7 +4,8 @@ from typing import Dict
4
from typing import List
5
from typing import Optional
6
7
-from pydantic import ConfigDict, BaseModel
7
+from pydantic import BaseModel
8
+from pydantic import ConfigDict
9
from pydantic import Field
10
11
backend/app/agents/velociraptor/schema/agents.py
+3
-1
@@ -2,7 +2,8 @@ from datetime import datetime
2
from typing import List
3
from typing import Optional
4
5
-from pydantic import ConfigDict, BaseModel
5
+from pydantic import BaseModel
6
+from pydantic import ConfigDict
7
from pydantic import Field
8
9
@@ -16,6 +17,7 @@ class VelociraptorAgent(BaseModel):
17
def client_last_seen_as_datetime(self):
18
dt = datetime.strptime(self.client_last_seen, "%Y-%m-%dT%H:%M:%S%z")
19
return dt.replace(tzinfo=None)
20
+
21
model_config = ConfigDict(populate_by_name=True)
22
23
backend/app/agents/vulnerabilities/schema/vulnerabilities.py
+2
-1
@@ -4,7 +4,8 @@ from typing import Dict
4
from typing import List
5
from typing import Optional
6
7
-from pydantic import ConfigDict, BaseModel
7
+from pydantic import BaseModel
8
+from pydantic import ConfigDict
9
from pydantic import Field
10
11
backend/app/agents/wazuh/schema/agents.py
+3
-1
@@ -3,7 +3,8 @@ from enum import Enum
3
from typing import List
4
from typing import Optional
5
6
-from pydantic import ConfigDict, BaseModel
6
+from pydantic import BaseModel
7
+from pydantic import ConfigDict
8
from pydantic import Field
9
10
@@ -29,6 +30,7 @@ class WazuhAgent(BaseModel):
30
def agent_last_seen_as_datetime(self):
31
dt = datetime.strptime(self.agent_last_seen, "%Y-%m-%dT%H:%M:%S%z")
32
return dt.replace(tzinfo=None)
33
+
34
model_config = ConfigDict(populate_by_name=True)
35
36
backend/app/agents/wazuh/syscollector/schema/packages.py
+2
-1
@@ -3,7 +3,8 @@ from typing import Dict
3
from typing import List
4
from typing import Optional
5
6
-from pydantic import ConfigDict, BaseModel
6
+from pydantic import BaseModel
7
+from pydantic import ConfigDict
8
from pydantic import Field
9
10
backend/app/ai_analyst/schema/ai_analyst.py
+2
-1
@@ -4,8 +4,9 @@ from enum import Enum
4
from typing import List
5
from typing import Optional
6
7
-from pydantic import field_validator, BaseModel
7
+from pydantic import BaseModel
8
from pydantic import Field
9
+from pydantic import field_validator
10
11
# --- Enums ---
12
backend/app/auth/models/users.py
+2
-1
@@ -7,8 +7,9 @@ from typing import List
7
from typing import Optional
8
9
import bcrypt
10
-from pydantic import field_validator, BaseModel
10
+from pydantic import BaseModel
11
from pydantic import EmailStr
12
+from pydantic import field_validator
13
from sqlmodel import Field
14
from sqlmodel import Relationship
15
from sqlmodel import SQLModel
backend/app/auth/services/totp.py
+1
-1
@@ -45,7 +45,7 @@ except (ValueError, TypeError) as e:
45
raise RuntimeError(
46
"TOTP_ENCRYPTION_KEY is malformed. Expected a 32-byte url-safe base64 key "
47
"(typically 44 characters ending with '='). Generate a valid one with:\n"
48
- " python -c \"from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())\"\n"
48
+ ' python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"\n'
49
f"Then paste the value into your .env without surrounding quotes or trailing whitespace. "
50
f"(underlying error: {e})",
51
) from e
backend/app/connectors/grafana/schema/reporting.py
+48
-45
@@ -2,8 +2,9 @@ from typing import List
2
from typing import Optional
3
4
from fastapi import HTTPException
5
-from pydantic import field_validator, BaseModel
5
+from pydantic import BaseModel
6
from pydantic import Field
7
+from pydantic import field_validator
8
9
10
class GrafanaOrganizations(BaseModel):
@@ -223,50 +224,52 @@ class GenerateReportRequest(BaseModel):
224
rows: List[RequestRow] = Field(
225
...,
226
description="Rows in the report",
226
- examples=[[
227
- {
228
- "id": 1710437961108,
229
- "panels": [
230
- {
231
- "panel_id": 5,
232
- "org_id": 1,
233
- "dashboard_title": "HUNTRESS - _SUMMARY",
234
- "dashboard_uid": "ab9bab2c-5d86-43e7-bac2-c1d68fc91342",
235
- "panel_width": 500,
236
- "panel_height": 300,
237
- },
238
- {
239
- "panel_id": 3,
240
- "org_id": 1,
241
- "dashboard_title": "HUNTRESS - _SUMMARY",
242
- "dashboard_uid": "ab9bab2c-5d86-43e7-bac2-c1d68fc91342",
243
- "panel_width": 500,
244
- "panel_height": 300,
245
- },
246
- ],
247
- },
248
- {
249
- "id": 1710437961109,
250
- "panels": [
251
- {
252
- "panel_id": 5,
253
- "org_id": 1,
254
- "dashboard_title": "HUNTRESS - _SUMMARY",
255
- "dashboard_uid": "ab9bab2c-5d86-43e7-bac2-c1d68fc91342",
256
- "panel_width": 500,
257
- "panel_height": 300,
258
- },
259
- {
260
- "panel_id": 3,
261
- "org_id": 1,
262
- "dashboard_title": "HUNTRESS - _SUMMARY",
263
- "dashboard_uid": "ab9bab2c-5d86-43e7-bac2-c1d68fc91342",
264
- "panel_width": 500,
265
- "panel_height": 300,
266
- },
267
- ],
268
- },
269
- ]],
227
+ examples=[
228
+ [
229
+ {
230
+ "id": 1710437961108,
231
+ "panels": [
232
+ {
233
+ "panel_id": 5,
234
+ "org_id": 1,
235
+ "dashboard_title": "HUNTRESS - _SUMMARY",
236
+ "dashboard_uid": "ab9bab2c-5d86-43e7-bac2-c1d68fc91342",
237
+ "panel_width": 500,
238
+ "panel_height": 300,
239
+ },
240
+ {
241
+ "panel_id": 3,
242
+ "org_id": 1,
243
+ "dashboard_title": "HUNTRESS - _SUMMARY",
244
+ "dashboard_uid": "ab9bab2c-5d86-43e7-bac2-c1d68fc91342",
245
+ "panel_width": 500,
246
+ "panel_height": 300,
247
+ },
248
+ ],
249
+ },
250
+ {
251
+ "id": 1710437961109,
252
+ "panels": [
253
+ {
254
+ "panel_id": 5,
255
+ "org_id": 1,
256
+ "dashboard_title": "HUNTRESS - _SUMMARY",
257
+ "dashboard_uid": "ab9bab2c-5d86-43e7-bac2-c1d68fc91342",
258
+ "panel_width": 500,
259
+ "panel_height": 300,
260
+ },
261
+ {
262
+ "panel_id": 3,
263
+ "org_id": 1,
264
+ "dashboard_title": "HUNTRESS - _SUMMARY",
265
+ "dashboard_uid": "ab9bab2c-5d86-43e7-bac2-c1d68fc91342",
266
+ "panel_width": 500,
267
+ "panel_height": 300,
268
+ },
269
+ ],
270
+ },
271
+ ],
272
+ ],
273
)
274
275
backend/app/connectors/graylog/schema/content_packs.py
+2
-1
@@ -3,7 +3,8 @@ from typing import Dict
3
from typing import List
4
from typing import Optional
5
6
-from pydantic import ConfigDict, BaseModel
6
+from pydantic import BaseModel
7
+from pydantic import ConfigDict
8
from pydantic import Field
9
10
backend/app/connectors/graylog/schema/monitoring.py
+14
-7
@@ -32,25 +32,32 @@ class GraylogThroughputMetrics(BaseModel):
32
33
class GraylogThroughputMetricsCollection(BaseModel):
34
graylog2_buffers_input_usage: Optional[str] = Field(
35
- None, alias="org.graylog2.buffers.input.usage",
35
+ None,
36
+ alias="org.graylog2.buffers.input.usage",
37
)
38
graylog2_buffers_output_usage: Optional[str] = Field(
38
- None, alias="org.graylog2.buffers.output.usage",
39
+ None,
40
+ alias="org.graylog2.buffers.output.usage",
41
)
42
graylog2_buffers_process_usage: Optional[str] = Field(
41
- None, alias="org.graylog2.buffers.process.usage",
43
+ None,
44
+ alias="org.graylog2.buffers.process.usage",
45
)
46
graylog2_throughput_input_1_sec_rate: Optional[str] = Field(
44
- None, alias="org.graylog2.throughput.input.1-sec-rate",
47
+ None,
48
+ alias="org.graylog2.throughput.input.1-sec-rate",
49
)
50
graylog2_throughput_output_1_sec_rate: Optional[str] = Field(
47
- None, alias="org.graylog2.throughput.output.1-sec-rate",
51
+ None,
52
+ alias="org.graylog2.throughput.output.1-sec-rate",
53
)
54
graylog2_throughput_output: Optional[str] = Field(
50
- None, alias="org.graylog2.throughput.output",
55
+ None,
56
+ alias="org.graylog2.throughput.output",
57
)
58
graylog2_throughput_input: Optional[str] = Field(
53
- None, alias="org.graylog2.throughput.input",
59
+ None,
60
+ alias="org.graylog2.throughput.input",
61
)
62
63
backend/app/connectors/influxdb/schema/alerts.py
+34
-27
@@ -2,7 +2,8 @@ from datetime import datetime
2
from enum import Enum
3
from typing import Optional
4
5
-from pydantic import ConfigDict, BaseModel
5
+from pydantic import BaseModel
6
+from pydantic import ConfigDict
7
from pydantic import Field
8
9
@@ -65,26 +66,29 @@ class InfluxDBAlertResponse(BaseModel):
66
filtered_count: int
67
active_alerts_count: int = 0
68
cleared_alerts_count: int = 0
68
- model_config = ConfigDict(from_attributes=True, json_schema_extra={
69
- "example": {
70
- "success": True,
71
- "message": "Successfully retrieved alerts",
72
- "alerts": [
73
- {
74
- "time": "2025-12-01T10:30:00Z",
75
- "check_name": "CPU CHECK",
76
- "sensor_type": "CPU",
77
- "severity": "warning",
78
- "message": "CPU usage high",
79
- "status": "active",
80
- },
81
- ],
82
- "total_count": 150,
83
- "filtered_count": 25,
84
- "active_alerts_count": 5,
85
- "cleared_alerts_count": 20,
69
+ model_config = ConfigDict(
70
+ from_attributes=True,
71
+ json_schema_extra={
72
+ "example": {
73
+ "success": True,
74
+ "message": "Successfully retrieved alerts",
75
+ "alerts": [
76
+ {
77
+ "time": "2025-12-01T10:30:00Z",
78
+ "check_name": "CPU CHECK",
79
+ "sensor_type": "CPU",
80
+ "severity": "warning",
81
+ "message": "CPU usage high",
82
+ "status": "active",
83
+ },
84
+ ],
85
+ "total_count": 150,
86
+ "filtered_count": 25,
87
+ "active_alerts_count": 5,
88
+ "cleared_alerts_count": 20,
89
+ },
90
},
87
- })
91
+ )
92
93
94
class InfluxDBAlertsResponse(BaseModel):
@@ -102,11 +106,14 @@ class InfluxDBCheckNamesResponse(BaseModel):
106
message: str
107
check_names: list[str]
108
total_count: int
105
- model_config = ConfigDict(from_attributes=True, json_schema_extra={
106
- "example": {
107
- "success": True,
108
- "message": "Successfully retrieved check names",
109
- "check_names": ["CPU CHECK", "Host Offline", "Memory Usage", "Disk Space"],
110
- "total_count": 4,
109
+ model_config = ConfigDict(
110
+ from_attributes=True,
111
+ json_schema_extra={
112
+ "example": {
113
+ "success": True,
114
+ "message": "Successfully retrieved check names",
115
+ "check_names": ["CPU CHECK", "Host Offline", "Memory Usage", "Disk Space"],
116
+ "total_count": 4,
117
+ },
118
},
112
- })
119
+ )
backend/app/connectors/schema.py
+2
-1
@@ -2,7 +2,8 @@ from datetime import datetime
2
from typing import List
3
from typing import Optional
4
5
-from pydantic import ConfigDict, BaseModel
5
+from pydantic import BaseModel
6
+from pydantic import ConfigDict
7
8
9
class ConnectorHistoryResponse(BaseModel):
backend/app/connectors/shuffle/schema/integrations.py
+7
-5
@@ -16,11 +16,13 @@ class IntegrationRequest(BaseModel):
16
fields: Optional[List[Dict[str, Any]]] = Field(
17
[],
18
description="The fields of the application",
19
- examples=[[
20
- {"key": "title", "value": "This is the title"},
21
- {"key": "description", "value": "This is the description"},
22
- {"key": "source", "value": "Shuffle"},
23
- ]],
19
+ examples=[
20
+ [
21
+ {"key": "title", "value": "This is the title"},
22
+ {"key": "description", "value": "This is the description"},
23
+ {"key": "source", "value": "Shuffle"},
24
+ ],
25
+ ],
26
)
27
skip_workflow: Optional[bool] = Field(
28
False,
backend/app/connectors/sublime/schema/alerts.py
+2
-1
@@ -2,7 +2,8 @@ import datetime
2
from typing import List
3
from typing import Optional
4
5
-from pydantic import ConfigDict, BaseModel
5
+from pydantic import BaseModel
6
+from pydantic import ConfigDict
7
from pydantic import Field
8
9
backend/app/connectors/velociraptor/schema/artifacts.py
+28
-22
@@ -6,8 +6,10 @@ from typing import Optional
6
from typing import Union
7
8
from fastapi import HTTPException
9
-from pydantic import field_validator, ConfigDict, BaseModel
9
+from pydantic import BaseModel
10
+from pydantic import ConfigDict
11
from pydantic import Field
12
+from pydantic import field_validator
13
14
15
class ArtifactParameter(BaseModel):
@@ -46,19 +48,21 @@ class ArtifactParametersResponse(BaseModel):
48
parameter_prefix: str = Field(..., description="The prefix used for filtering")
49
matching_parameters: List[ArtifactParameter] = Field(default_factory=list, description="List of parameters that match the prefix")
50
total_matches: int = Field(..., description="Total number of matching parameters")
49
- model_config = ConfigDict(json_schema_extra={
50
- "example": {
51
- "success": True,
52
- "message": "Found 2 parameters matching prefix 'T1552.001'",
53
- "artifact_name": "Windows.AttackSimulation.AtomicRedTeam",
54
- "parameter_prefix": "T1552.001",
55
- "matching_parameters": [
56
- {"name": "T1552.001 - 3", "description": "Credentials In Files - Extracting passwords with findstr", "type": "bool"},
57
- {"name": "T1552.001 - 4", "description": "Credentials In Files - Access unattend.xml", "type": "bool"},
58
- ],
59
- "total_matches": 2,
51
+ model_config = ConfigDict(
52
+ json_schema_extra={
53
+ "example": {
54
+ "success": True,
55
+ "message": "Found 2 parameters matching prefix 'T1552.001'",
56
+ "artifact_name": "Windows.AttackSimulation.AtomicRedTeam",
57
+ "parameter_prefix": "T1552.001",
58
+ "matching_parameters": [
59
+ {"name": "T1552.001 - 3", "description": "Credentials In Files - Extracting passwords with findstr", "type": "bool"},
60
+ {"name": "T1552.001 - 4", "description": "Credentials In Files - Access unattend.xml", "type": "bool"},
61
+ ],
62
+ "total_matches": 2,
63
+ },
64
},
61
- })
65
+ )
66
67
68
class OSPrefixEnum(Enum):
@@ -139,16 +143,18 @@ class CollectArtifactBody(BaseBody):
143
False,
144
description="If true, only store the collected data in the datastore without sending it back immediately",
145
)
142
- model_config = ConfigDict(json_schema_extra={
143
- "example": {
144
- "hostname": "WIN-HFOU106TD7K",
145
- "velociraptor_id": "C.475df76785008b04",
146
- "velociraptor_org": "root",
147
- "artifact_name": "Windows.AttackSimulation.AtomicRedTeam",
148
- "parameters": {"env": [{"key": "InstallART", "value": "N"}, {"key": "T1552.001 - 3", "value": "Y"}]},
149
- "data_store_only": False,
146
+ model_config = ConfigDict(
147
+ json_schema_extra={
148
+ "example": {
149
+ "hostname": "WIN-HFOU106TD7K",
150
+ "velociraptor_id": "C.475df76785008b04",
151
+ "velociraptor_org": "root",
152
+ "artifact_name": "Windows.AttackSimulation.AtomicRedTeam",
153
+ "parameters": {"env": [{"key": "InstallART", "value": "N"}, {"key": "T1552.001 - 3", "value": "Y"}]},
154
+ "data_store_only": False,
155
+ },
156
},
151
- })
157
+ )
158
159
160
class InvokeCopilotActionBody(BaseModel):
backend/app/connectors/velociraptor/schema/flows.py
+2
-1
@@ -3,8 +3,9 @@ from typing import Optional
3
4
from fastapi import HTTPException
5
from loguru import logger
6
-from pydantic import model_validator, BaseModel
6
+from pydantic import BaseModel
7
from pydantic import Field
8
+from pydantic import model_validator
9
10
11
class FlowSpecParameter(BaseModel):
backend/app/connectors/wazuh_indexer/schema/alerts.py
+2
-1
@@ -4,8 +4,9 @@ from typing import Dict
4
from typing import List
5
from typing import Optional
6
7
-from pydantic import field_validator, BaseModel
7
+from pydantic import BaseModel
8
from pydantic import Field
9
+from pydantic import field_validator
10
11
12
class Alert(BaseModel):
backend/app/connectors/wazuh_manager/schema/groups.py
+8
-5
@@ -2,7 +2,8 @@ from typing import List
2
from typing import Optional
3
from typing import Union
4
5
-from pydantic import ConfigDict, BaseModel
5
+from pydantic import BaseModel
6
+from pydantic import ConfigDict
7
from pydantic import Field
8
9
@@ -59,9 +60,10 @@ class WazuhGroupConfigurationUpdateRequest(BaseModel):
60
"""Request model for updating group configuration."""
61
62
configuration: str = Field(..., description="Full valid XML configuration content")
62
- model_config = ConfigDict(json_schema_extra={
63
- "example": {
64
- "configuration": """<agent_config>
63
+ model_config = ConfigDict(
64
+ json_schema_extra={
65
+ "example": {
66
+ "configuration": """<agent_config>
67
<labels>
68
<label key="customer">example</label>
69
</labels>
@@ -71,8 +73,9 @@ class WazuhGroupConfigurationUpdateRequest(BaseModel):
73
<events_per_second>1000</events_per_second>
74
</client_buffer>
75
</agent_config>""",
76
+ },
77
},
75
- })
78
+ )
79
80
81
class WazuhGroupConfigurationUpdateResponse(BaseModel):
backend/app/connectors/wazuh_manager/schema/mitre.py
+2
-1
@@ -3,7 +3,8 @@ from typing import Dict
3
from typing import List
4
from typing import Optional
5
6
-from pydantic import ConfigDict, BaseModel
6
+from pydantic import BaseModel
7
+from pydantic import ConfigDict
8
from pydantic import Field
9
10
backend/app/connectors/wazuh_manager/schema/rules.py
+3
-1
@@ -3,8 +3,10 @@ from typing import Optional
3
from typing import Union
4
5
from fastapi import HTTPException
6
-from pydantic import field_validator, ConfigDict, BaseModel
6
+from pydantic import BaseModel
7
+from pydantic import ConfigDict
8
from pydantic import Field
9
+from pydantic import field_validator
10
11
12
class RuleDisable(BaseModel):
backend/app/customer_portal/schema/settings.py
+7
-2
@@ -3,8 +3,10 @@ import re
3
from typing import Optional
4
5
from fastapi import HTTPException
6
-from pydantic import field_validator, ConfigDict, BaseModel
6
+from pydantic import BaseModel
7
+from pydantic import ConfigDict
8
from pydantic import Field
9
+from pydantic import field_validator
10
11
12
class UpdatePortalSettingsRequest(BaseModel):
@@ -52,7 +54,10 @@ class UpdatePortalSettingsRequest(BaseModel):
54
if v not in allowed_types:
55
raise HTTPException(status_code=400, detail=f"Invalid MIME type. Allowed types are: {', '.join(allowed_types)}")
56
return v
55
- model_config = ConfigDict(json_schema_extra={"example": {"title": "My Custom Portal", "logo_base64": "iVBORw0KGgoAAAANS...", "logo_mime_type": "image/png"}})
57
+
58
+ model_config = ConfigDict(
59
+ json_schema_extra={"example": {"title": "My Custom Portal", "logo_base64": "iVBORw0KGgoAAAANS...", "logo_mime_type": "image/png"}},
60
+ )
61
62
63
class PortalSettingsData(BaseModel):
backend/app/customer_provisioning/schema/graylog.py
+71
-64
@@ -1,7 +1,8 @@
1
from typing import List
2
from typing import Optional
3
4
-from pydantic import ConfigDict, BaseModel
4
+from pydantic import BaseModel
5
+from pydantic import ConfigDict
6
from pydantic import Field
7
8
@@ -32,31 +33,33 @@ class TimeBasedIndexSet(BaseModel):
33
index_optimization_disabled: bool
34
writable: bool
35
field_type_refresh_interval: int
35
- model_config = ConfigDict(json_schema_extra={
36
- "example": {
37
- "title": "Wazuh - Example Company",
38
- "description": "Wazuh - Example Company",
39
- "index_prefix": "wazuh-examplecode",
40
- "rotation_strategy_class": "org.graylog2.indexer.rotation.strategies.SizeBasedRotationStrategy",
41
- "rotation_strategy": {
42
- "type": "org.graylog2.indexer.rotation.strategies.SizeBasedRotationStrategyConfig",
43
- "max_size": 2684354560,
44
- },
45
- "retention_strategy_class": "org.graylog2.indexer.retention.strategies.DeletionRetentionStrategy",
46
- "retention_strategy": {
47
- "type": "org.graylog2.indexer.retention.strategies.DeletionRetentionStrategyConfig",
48
- "max_number_of_indices": 20,
36
+ model_config = ConfigDict(
37
+ json_schema_extra={
38
+ "example": {
39
+ "title": "Wazuh - Example Company",
40
+ "description": "Wazuh - Example Company",
41
+ "index_prefix": "wazuh-examplecode",
42
+ "rotation_strategy_class": "org.graylog2.indexer.rotation.strategies.SizeBasedRotationStrategy",
43
+ "rotation_strategy": {
44
+ "type": "org.graylog2.indexer.rotation.strategies.SizeBasedRotationStrategyConfig",
45
+ "max_size": 2684354560,
46
+ },
47
+ "retention_strategy_class": "org.graylog2.indexer.retention.strategies.DeletionRetentionStrategy",
48
+ "retention_strategy": {
49
+ "type": "org.graylog2.indexer.retention.strategies.DeletionRetentionStrategyConfig",
50
+ "max_number_of_indices": 20,
51
+ },
52
+ "creation_date": "2021-01-01T00:00:00.000Z",
53
+ "index_analyzer": "standard",
54
+ "shards": 1,
55
+ "replicas": 0,
56
+ "index_optimization_max_num_segments": 1,
57
+ "index_optimization_disabled": False,
58
+ "writable": True,
59
+ "field_type_refresh_interval": 5000,
60
},
50
- "creation_date": "2021-01-01T00:00:00.000Z",
51
- "index_analyzer": "standard",
52
- "shards": 1,
53
- "replicas": 0,
54
- "index_optimization_max_num_segments": 1,
55
- "index_optimization_disabled": False,
56
- "writable": True,
57
- "field_type_refresh_interval": 5000,
61
},
59
- })
62
+ )
63
64
65
class RotationStrategyConfig(BaseModel):
@@ -124,24 +127,26 @@ class WazuhEventStream(BaseModel):
127
None,
128
description="Associated content pack, if any",
129
)
127
- model_config = ConfigDict(json_schema_extra={
128
- "example": {
129
- "title": "WAZUH EVENTS CUSTOMERS - Example Company",
130
- "description": "WAZUH EVENTS CUSTOMERS - Example Company",
131
- "index_set_id": "12345",
132
- "rules": [
133
- {
134
- "field": "agent_labels_customer",
135
- "type": 1,
136
- "inverted": False,
137
- "value": "ExampleCode",
138
- },
139
- ],
140
- "matching_type": "AND",
141
- "remove_matches_from_default_stream": True,
142
- "content_pack": None,
130
+ model_config = ConfigDict(
131
+ json_schema_extra={
132
+ "example": {
133
+ "title": "WAZUH EVENTS CUSTOMERS - Example Company",
134
+ "description": "WAZUH EVENTS CUSTOMERS - Example Company",
135
+ "index_set_id": "12345",
136
+ "rules": [
137
+ {
138
+ "field": "agent_labels_customer",
139
+ "type": 1,
140
+ "inverted": False,
141
+ "value": "ExampleCode",
142
+ },
143
+ ],
144
+ "matching_type": "AND",
145
+ "remove_matches_from_default_stream": True,
146
+ "content_pack": None,
147
+ },
148
},
144
- })
149
+ )
150
151
152
class Office365EventStream(BaseModel):
@@ -158,30 +163,32 @@ class Office365EventStream(BaseModel):
163
None,
164
description="Associated content pack, if any",
165
)
161
- model_config = ConfigDict(json_schema_extra={
162
- "example": {
163
- "title": "Office365 EVENTS - Example Company",
164
- "description": "Office365 EVENTS - Example Company",
165
- "index_set_id": "12345",
166
- "rules": [
167
- {
168
- "field": "agent_labels_customer",
169
- "type": 1,
170
- "inverted": False,
171
- "value": "ExampleCode",
172
- },
173
- {
174
- "field": "agent_labels_integration",
175
- "type": 1,
176
- "inverted": False,
177
- "value": "Office365",
178
- },
179
- ],
180
- "matching_type": "AND",
181
- "remove_matches_from_default_stream": True,
182
- "content_pack": None,
166
+ model_config = ConfigDict(
167
+ json_schema_extra={
168
+ "example": {
169
+ "title": "Office365 EVENTS - Example Company",
170
+ "description": "Office365 EVENTS - Example Company",
171
+ "index_set_id": "12345",
172
+ "rules": [
173
+ {
174
+ "field": "agent_labels_customer",
175
+ "type": 1,
176
+ "inverted": False,
177
+ "value": "ExampleCode",
178
+ },
179
+ {
180
+ "field": "agent_labels_integration",
181
+ "type": 1,
182
+ "inverted": False,
183
+ "value": "Office365",
184
+ },
185
+ ],
186
+ "matching_type": "AND",
187
+ "remove_matches_from_default_stream": True,
188
+ "content_pack": None,
189
+ },
190
},
184
- })
191
+ )
192
193
194
class StreamData(BaseModel):
backend/app/customer_provisioning/schema/provision.py
+38
-33
@@ -3,8 +3,9 @@ from enum import Enum
3
from typing import List
4
from typing import Optional
5
6
-from pydantic import field_validator, BaseModel
6
+from pydantic import BaseModel
7
from pydantic import Field
8
+from pydantic import field_validator
9
10
from app.connectors.grafana.schema.dashboards import DashboardProvisionRequest
11
from app.db.universal_models import CustomersMeta
@@ -59,11 +60,13 @@ class ProvisionNewCustomer(BaseModel):
60
dashboards_to_include: DashboardProvisionRequest = Field(
61
...,
62
description="Dashboards to include in the customer's Grafana instance",
62
- examples=[{
63
- "dashboards": [
64
- "WAZUH_SUMMARY",
65
- ],
66
- }],
63
+ examples=[
64
+ {
65
+ "dashboards": [
66
+ "WAZUH_SUMMARY",
67
+ ],
68
+ },
69
+ ],
70
)
71
wazuh_auth_password: Optional[str] = Field("n/a", description="Password for the Wazuh API user")
72
wazuh_registration_port: Optional[str] = Field(
@@ -224,33 +227,35 @@ class ProvisionDashboardRequest(BaseModel):
227
dashboards_to_include: DashboardProvisionRequest = Field(
228
...,
229
description="Dashboards to include in the customer's Grafana instance",
227
- examples=[{
228
- "dashboards": [
229
- "WAZUH_SUMMARY",
230
- "EDR_WINDOWS_EVENT_LOGS",
231
- "EDR_WAZUH_INVENOTRY",
232
- "EDR_USERS_AND_GROUPS",
233
- "EDR_SYSTEM_VULNERABILITIES",
234
- "EDR_SYSTEM_SECURITY_AUDIT",
235
- "EDR_SYSTEM_PROCESSES",
236
- "EDR_PROCESS_INJECTION",
237
- "EDR_OPEN_AUDIT",
238
- "EDR_NETWORK_SCAN",
239
- "EDR_NETWORK_CONNECTIONS",
240
- "EDR_MITRE",
241
- "EDR_FIM",
242
- "EDR_DOCKER_MONITORING",
243
- "EDR_DNS_REQUESTS",
244
- "EDR_DLL_SIDE_LOADING",
245
- "EDR_COMPLIANCE",
246
- "EDR_AV_MALWARE_IOC",
247
- "EDR_AGENT_INVENTORY",
248
- "EDR_AD_INVENOTRY",
249
- ],
250
- "organizationId": 1,
251
- "folderId": 1,
252
- "datasourceUid": "wazuh",
253
- }],
230
+ examples=[
231
+ {
232
+ "dashboards": [
233
+ "WAZUH_SUMMARY",
234
+ "EDR_WINDOWS_EVENT_LOGS",
235
+ "EDR_WAZUH_INVENOTRY",
236
+ "EDR_USERS_AND_GROUPS",
237
+ "EDR_SYSTEM_VULNERABILITIES",
238
+ "EDR_SYSTEM_SECURITY_AUDIT",
239
+ "EDR_SYSTEM_PROCESSES",
240
+ "EDR_PROCESS_INJECTION",
241
+ "EDR_OPEN_AUDIT",
242
+ "EDR_NETWORK_SCAN",
243
+ "EDR_NETWORK_CONNECTIONS",
244
+ "EDR_MITRE",
245
+ "EDR_FIM",
246
+ "EDR_DOCKER_MONITORING",
247
+ "EDR_DNS_REQUESTS",
248
+ "EDR_DLL_SIDE_LOADING",
249
+ "EDR_COMPLIANCE",
250
+ "EDR_AV_MALWARE_IOC",
251
+ "EDR_AGENT_INVENTORY",
252
+ "EDR_AD_INVENOTRY",
253
+ ],
254
+ "organizationId": 1,
255
+ "folderId": 1,
256
+ "datasourceUid": "wazuh",
257
+ },
258
+ ],
259
)
260
grafana_org_id: int = Field(
261
...,
backend/app/customers/schema/customers.py
+44
-34
@@ -2,7 +2,8 @@ from datetime import datetime
2
from typing import List
3
from typing import Optional
4
5
-from pydantic import ConfigDict, BaseModel
5
+from pydantic import BaseModel
6
+from pydantic import ConfigDict
7
from pydantic import Field
8
9
@@ -26,24 +27,27 @@ class CustomerRequestBody(BaseModel):
27
customer_type: Optional[str] = Field(None, description="Type of the customer")
28
logo_file: Optional[str] = Field(None, description="Logo file for the customer")
29
is_provisioned: Optional[bool] = Field(None, description="Whether the customer has been provisioned")
29
- model_config = ConfigDict(from_attributes=True, json_schema_extra={
30
- "example": {
31
- "customer_code": "CUST123",
32
- "customer_name": "Sample Customer",
33
- "contact_last_name": "Doe",
34
- "contact_first_name": "John",
35
- "phone": "123-456-7890",
36
- "address_line1": "123 Main St",
37
- "address_line2": "Apt 4",
38
- "city": "Anytown",
39
- "state": "CA",
40
- "postal_code": "12345",
41
- "country": "USA",
42
- "customer_type": "Enterprise",
43
- "logo_file": "logo.png",
44
- "is_provisioned": True,
30
+ model_config = ConfigDict(
31
+ from_attributes=True,
32
+ json_schema_extra={
33
+ "example": {
34
+ "customer_code": "CUST123",
35
+ "customer_name": "Sample Customer",
36
+ "contact_last_name": "Doe",
37
+ "contact_first_name": "John",
38
+ "phone": "123-456-7890",
39
+ "address_line1": "123 Main St",
40
+ "address_line2": "Apt 4",
41
+ "city": "Anytown",
42
+ "state": "CA",
43
+ "postal_code": "12345",
44
+ "country": "USA",
45
+ "customer_type": "Enterprise",
46
+ "logo_file": "logo.png",
47
+ "is_provisioned": True,
48
+ },
49
},
46
- })
50
+ )
51
52
53
class CustomerResponse(BaseModel):
@@ -100,18 +104,21 @@ class CustomerMetaRequestBody(BaseModel):
104
None,
105
description="Portainer stack ID for the customer",
106
)
103
- model_config = ConfigDict(from_attributes=True, json_schema_extra={
104
- "example": {
105
- "customer_meta_graylog_index": "graylog_index",
106
- "customer_meta_graylog_stream": "graylog_stream",
107
- "customer_meta_grafana_org_id": "grafana_org",
108
- "customer_meta_wazuh_group": "wazuh_group",
109
- "customer_meta_index_retention": "30D",
110
- "customer_meta_wazuh_registration_port": "1514",
111
- "customer_meta_wazuh_log_ingestion_port": "1515",
112
- "customer_meta_wazuh_auth_password": "wazuh_password",
107
+ model_config = ConfigDict(
108
+ from_attributes=True,
109
+ json_schema_extra={
110
+ "example": {
111
+ "customer_meta_graylog_index": "graylog_index",
112
+ "customer_meta_graylog_stream": "graylog_stream",
113
+ "customer_meta_grafana_org_id": "grafana_org",
114
+ "customer_meta_wazuh_group": "wazuh_group",
115
+ "customer_meta_index_retention": "30D",
116
+ "customer_meta_wazuh_registration_port": "1514",
117
+ "customer_meta_wazuh_log_ingestion_port": "1515",
118
+ "customer_meta_wazuh_auth_password": "wazuh_password",
119
+ },
120
},
114
- })
121
+ )
122
123
124
class CustomerMetaResponse(BaseModel):
@@ -159,9 +166,12 @@ class DeleteCustomerResponse(BaseModel):
166
167
success: bool
168
message: str
162
- model_config = ConfigDict(from_attributes=True, json_schema_extra={
163
- "example": {
164
- "success": True,
165
- "message": "Customer 'customer_code' deleted successfully",
169
+ model_config = ConfigDict(
170
+ from_attributes=True,
171
+ json_schema_extra={
172
+ "example": {
173
+ "success": True,
174
+ "message": "Customer 'customer_code' deleted successfully",
175
+ },
176
},
167
- })
177
+ )
backend/app/data_store/data_store_schema.py
+2
-1
@@ -1,7 +1,8 @@
1
from datetime import datetime
2
from typing import Optional
3
4
-from pydantic import ConfigDict, BaseModel
4
+from pydantic import BaseModel
5
+from pydantic import ConfigDict
6
from pydantic import Field
7
8
backend/app/healthchecks/agents/schema/agents.py
+3
-1
@@ -4,8 +4,10 @@ from typing import Dict
4
from typing import List
5
from typing import Optional
6
7
-from pydantic import field_validator, ConfigDict, BaseModel
7
+from pydantic import BaseModel
8
+from pydantic import ConfigDict
9
from pydantic import Field
10
+from pydantic import field_validator
11
12
13
class AgentModel(BaseModel):
backend/app/incidents/models.py
+20
-5
@@ -245,7 +245,10 @@ class VeloSigmaExclusion(SQLModel, table=True):
245
title: Optional[str] = Field(max_length=255, nullable=True, description="Sigma rule title to match (exact match)")
246
247
# Field matching data - stored as JSON to allow flexible field matching
248
- field_matches: Optional[Dict] = Field(sa_column=Column(JSON, nullable=True), description="JSON of field names and values to match in the event data")
248
+ field_matches: Optional[Dict] = Field(
249
+ sa_column=Column(JSON, nullable=True),
250
+ description="JSON of field names and values to match in the event data",
251
+ )
252
253
# Metadata
254
customer_code: Optional[str] = Field(
@@ -271,7 +274,10 @@ class ThresholdAlertMetadata(SQLModel, table=True):
274
replay_query: str = Field(sa_column=Column(Text, nullable=False), description="Lucene query from Graylog replay_info")
275
timerange_start: datetime = Field(nullable=False, description="Start of the threshold evaluation window")
276
timerange_end: datetime = Field(nullable=False, description="End of the threshold evaluation window")
274
- group_by_fields: Optional[Dict] = Field(sa_column=Column(JSON, nullable=True), description="Group-by field key/value pairs from the threshold event")
277
+ group_by_fields: Optional[Dict] = Field(
278
+ sa_column=Column(JSON, nullable=True),
279
+ description="Group-by field key/value pairs from the threshold event",
280
+ )
281
source_streams: Optional[List] = Field(sa_column=Column(JSON, nullable=True), description="Graylog source stream IDs")
282
source: str = Field(max_length=50, nullable=False, description="SOURCE field value (e.g. wazuh)")
283
resolved_index_name: str = Field(max_length=255, nullable=False, description="OpenSearch index of the resolved event")
@@ -327,7 +333,10 @@ class CaseTemplateTask(SQLModel, table=True):
333
template_id: int = Field(foreign_key="incident_management_case_template.id", nullable=False)
334
title: str = Field(max_length=500, nullable=False)
335
description: Optional[str] = Field(sa_column=Column(Text, nullable=True))
330
- guidelines: Optional[str] = Field(sa_column=Column(Text, nullable=True), description="Best practices / steps the analyst should follow when executing this task")
336
+ guidelines: Optional[str] = Field(
337
+ sa_column=Column(Text, nullable=True),
338
+ description="Best practices / steps the analyst should follow when executing this task",
339
+ )
340
mandatory: bool = Field(
341
default=False,
342
nullable=False,
@@ -374,7 +383,10 @@ class CaseTask(SQLModel, table=True):
383
nullable=False,
384
description="One of TODO, DONE, NOT_NECESSARY (NOT_NECESSARY only valid when mandatory=False).",
385
)
377
- evidence_comment: Optional[str] = Field(sa_column=Column(Text, nullable=True), description="Free-form notes / evidence (logs, command output) attached when status changes.")
386
+ evidence_comment: Optional[str] = Field(
387
+ sa_column=Column(Text, nullable=True),
388
+ description="Free-form notes / evidence (logs, command output) attached when status changes.",
389
+ )
390
completed_by: Optional[str] = Field(max_length=100, nullable=True)
391
completed_at: Optional[datetime] = Field(default=None, nullable=True)
392
@@ -408,7 +420,10 @@ class CaseEvent(SQLModel, table=True):
420
)
421
actor: str = Field(max_length=100, nullable=False, description="user_name that performed the action")
422
timestamp: datetime = Field(default_factory=datetime.utcnow, index=True)
411
- payload: Optional[Dict] = Field(sa_column=Column(JSON, nullable=True), description="Event-type-specific JSON payload (e.g., from_status/to_status, alert_id, task_id).")
423
+ payload: Optional[Dict] = Field(
424
+ sa_column=Column(JSON, nullable=True),
425
+ description="Event-type-specific JSON payload (e.g., from_status/to_status, alert_id, task_id).",
426
+ )
427
428
429
class TagAccessSettings(SQLModel, table=True):
backend/app/incidents/schema/case_templates.py
+3
-1
@@ -14,8 +14,10 @@ from typing import Dict
14
from typing import List
15
from typing import Optional
16
17
-from pydantic import field_validator, ConfigDict, BaseModel
17
+from pydantic import BaseModel
18
+from pydantic import ConfigDict
19
from pydantic import Field
20
+from pydantic import field_validator
21
22
# ---------------------------------------------------------------------------
23
# Enums
backend/app/incidents/schema/db_operations.py
+2
-1
@@ -5,7 +5,8 @@ from typing import List
5
from typing import Optional
6
7
from fastapi import HTTPException
8
-from pydantic import field_validator, BaseModel
8
+from pydantic import BaseModel
9
+from pydantic import field_validator
10
from pydantic import model_validator
11
12
from app.incidents.models import Alert
backend/app/incidents/schema/incident_alert.py
+13
-10
@@ -5,7 +5,8 @@ from typing import Dict
5
from typing import List
6
from typing import Optional
7
8
-from pydantic import ConfigDict, BaseModel
8
+from pydantic import BaseModel
9
+from pydantic import ConfigDict
10
from pydantic import Field
11
12
@@ -55,16 +56,18 @@ class AutoCreateAlertResponse(BaseModel):
56
alerts_failed: int = 0
57
batches_processed: int = 0
58
alerts_remaining: int = 0
58
- model_config = ConfigDict(json_schema_extra={
59
- "example": {
60
- "success": True,
61
- "message": "Processed 5 batches: 487 alerts created, 13 failed. 2000 alerts remaining for next run",
62
- "alerts_created": 487,
63
- "alerts_failed": 13,
64
- "batches_processed": 5,
65
- "alerts_remaining": 2000,
59
+ model_config = ConfigDict(
60
+ json_schema_extra={
61
+ "example": {
62
+ "success": True,
63
+ "message": "Processed 5 batches: 487 alerts created, 13 failed. 2000 alerts remaining for next run",
64
+ "alerts_created": 487,
65
+ "alerts_failed": 13,
66
+ "batches_processed": 5,
67
+ "alerts_remaining": 2000,
68
+ },
69
},
67
- })
70
+ )
71
72
73
class IndexNamesResponse(BaseModel):
backend/app/incidents/schema/velo_sigma.py
+74
-66
@@ -7,8 +7,10 @@ from typing import Optional
7
from typing import Union
8
9
from loguru import logger
10
-from pydantic import field_validator, ConfigDict, BaseModel
10
+from pydantic import BaseModel
11
+from pydantic import ConfigDict
12
from pydantic import Field
13
+from pydantic import field_validator
14
15
16
class SystemProvider(BaseModel):
@@ -146,6 +148,7 @@ class PowerShellEventData(BaseModel):
148
# Generic event data model that accepts any fields
149
class GenericEventData(BaseModel):
150
"""Generic event data structure that accepts any fields"""
151
+
152
model_config = ConfigDict(extra="allow")
153
154
@@ -307,62 +310,65 @@ class VelociraptorSigmaAlert(BaseModel):
310
311
# Use generic model for other event types
312
return GenericEvent(**event_data)
310
- model_config = ConfigDict(json_schema_extra={
311
- "example": {
312
- "computer": "WIN-HFOU106TD7K",
313
- "clientID": "C.475df76785008b04",
314
- "channel": "Microsoft-Windows-Sysmon/Operational",
315
- "title": "Proc Access (Sysmon Alert)",
316
- "level": "high",
317
- "event": (
318
- '{"System":{"Provider":{"Name":"Microsoft-Windows-Sysmon","Guid":"5770385F-C22A-43E0-BF4C-06F5698FFBD9"},'
319
- '"EventID":{"Value":10},"Version":3,"Level":4,"Task":10,"Opcode":0,"Keywords":9223372036854775808,'
320
- '"TimeCreated":{"SystemTime":1744233485.0778975},"EventRecordID":564617,"Correlation":{},'
321
- '"Execution":{"ProcessID":2320,"ThreadID":3540},"Channel":"Microsoft-Windows-Sysmon/Operational",'
322
- '"Computer":"WIN-HFOU106TD7K","Security":{"UserID":"S-1-5-18"}},"EventData":{"RuleName":"technique_id=T1003,'
323
- 'technique_name=Credential Dumping","UtcTime":"2025-04-09 21:18:05.064",'
324
- '"SourceProcessGUID":"691FF406-E40B-67F6-2901-000000003A00","SourceProcessId":4964,"SourceThreadId":4448,'
325
- '"SourceImage":"C:\\\\Users\\\\ADMINI~1\\\\AppData\\\\Local\\\\Temp\\\\2\\\\AttackSim\\\\procdump.exe",'
326
- '"TargetProcessGUID":"691FF406-DDC8-67F6-0C00-000000003A00","TargetProcessId":668,'
327
- '"TargetImage":"C:\\\\Windows\\\\system32\\\\lsass.exe","GrantedAccess":2097151,'
328
- '"CallTrace":"C:\\\\Windows\\\\SYSTEM32\\\\ntdll.dll+9fc24|C:\\\\Windows\\\\System32\\\\wow64.dll+3cf4|'
329
- "C:\\\\Windows\\\\System32\\\\wow64.dll+7783|C:\\\\Windows\\\\System32\\\\wow64cpu.dll+1783|"
330
- "C:\\\\Windows\\\\System32\\\\wow64cpu.dll+1199|C:\\\\Windows\\\\System32\\\\wow64.dll+cfda|"
331
- "C:\\\\Windows\\\\System32\\\\wow64.dll+cea0|C:\\\\Windows\\\\SYSTEM32\\\\ntdll.dll+757db|"
332
- "C:\\\\Windows\\\\SYSTEM32\\\\ntdll.dll+756c3|C:\\\\Windows\\\\SYSTEM32\\\\ntdll.dll+7566e|"
333
- "C:\\\\Windows\\\\SYSTEM32\\\\ntdll.dll+7070c(wow64)|C:\\\\Windows\\\\System32\\\\KERNELBASE.dll+10eca8(wow64)|"
334
- "C:\\\\Users\\\\ADMINI~1\\\\AppData\\\\Local\\\\Temp\\\\2\\\\AttackSim\\\\procdump.exe+876e|"
335
- "C:\\\\Windows\\\\System32\\\\KERNEL32.DLL+20419(wow64)|C:\\\\Windows\\\\SYSTEM32\\\\ntdll.dll+6662d(wow64)|"
336
- 'C:\\\\Windows\\\\SYSTEM32\\\\ntdll.dll+665fd(wow64)","SourceUser":"WIN-HFOU106TD7K\\\\Administrator",'
337
- '"TargetUser":"NT AUTHORITY\\\\SYSTEM"},'
338
- '"Message":"Process accessed:\\nRuleName: technique_id=T1003,technique_name=Credential Dumping!s!\\n'
339
- "UtcTime: 2025-04-09 21:18:05.064!s!\\n"
340
- "SourceProcessGUID: 691FF406-E40B-67F6-2901-000000003A00!s!\\n"
341
- "SourceProcessId: 4964!s!\\n"
342
- "SourceThreadId: 4448!s!\\n"
343
- "SourceImage: C:\\\\Users\\\\ADMINI~1\\\\AppData\\\\Local\\\\Temp\\\\2\\\\AttackSim\\\\procdump.exe!s!\\n"
344
- "TargetProcessGUID: 691FF406-DDC8-67F6-0C00-000000003A00!s!\\n"
345
- "TargetProcessId: 668!s!\\n"
346
- "TargetImage: C:\\\\Windows\\\\system32\\\\lsass.exe!s!\\n"
347
- "GrantedAccess: 2097151!s!\\n"
348
- "CallTrace: C:\\\\Windows\\\\SYSTEM32\\\\ntdll.dll+9fc24|C:\\\\Windows\\\\System32\\\\wow64.dll+3cf4|"
349
- "C:\\\\Windows\\\\System32\\\\wow64.dll+7783|C:\\\\Windows\\\\System32\\\\wow64cpu.dll+1783|"
350
- "C:\\\\Windows\\\\System32\\\\wow64cpu.dll+1199|C:\\\\Windows\\\\System32\\\\wow64.dll+cfda|"
351
- "C:\\\\Windows\\\\System32\\\\wow64.dll+cea0|C:\\\\Windows\\\\SYSTEM32\\\\ntdll.dll+757db|"
352
- "C:\\\\Windows\\\\SYSTEM32\\\\ntdll.dll+756c3|C:\\\\Windows\\\\SYSTEM32\\\\ntdll.dll+7566e|"
353
- "C:\\\\Windows\\\\SYSTEM32\\\\ntdll.dll+7070c(wow64)|C:\\\\Windows\\\\System32\\\\KERNELBASE.dll+10eca8(wow64)|"
354
- "C:\\\\Users\\\\ADMINI~1\\\\AppData\\\\Local\\\\Temp\\\\2\\\\AttackSim\\\\procdump.exe+876e|"
355
- "C:\\\\Windows\\\\System32\\\\KERNEL32.DLL+20419(wow64)|C:\\\\Windows\\\\SYSTEM32\\\\ntdll.dll+6662d(wow64)|"
356
- "C:\\\\Windows\\\\SYSTEM32\\\\ntdll.dll+665fd(wow64)!s!\\n"
357
- "SourceUser: WIN-HFOU106TD7K\\\\Administrator!s!\\n"
358
- 'TargetUser: NT AUTHORITY\\\\SYSTEM!s!\\r\\n"}'
359
- ),
360
- "type": "sigma-alert",
361
- "source": "velociraptor",
362
- "index_pattern": "wazuh-*",
363
- "sourceRef": "754600692",
313
+
314
+ model_config = ConfigDict(
315
+ json_schema_extra={
316
+ "example": {
317
+ "computer": "WIN-HFOU106TD7K",
318
+ "clientID": "C.475df76785008b04",
319
+ "channel": "Microsoft-Windows-Sysmon/Operational",
320
+ "title": "Proc Access (Sysmon Alert)",
321
+ "level": "high",
322
+ "event": (
323
+ '{"System":{"Provider":{"Name":"Microsoft-Windows-Sysmon","Guid":"5770385F-C22A-43E0-BF4C-06F5698FFBD9"},'
324
+ '"EventID":{"Value":10},"Version":3,"Level":4,"Task":10,"Opcode":0,"Keywords":9223372036854775808,'
325
+ '"TimeCreated":{"SystemTime":1744233485.0778975},"EventRecordID":564617,"Correlation":{},'
326
+ '"Execution":{"ProcessID":2320,"ThreadID":3540},"Channel":"Microsoft-Windows-Sysmon/Operational",'
327
+ '"Computer":"WIN-HFOU106TD7K","Security":{"UserID":"S-1-5-18"}},"EventData":{"RuleName":"technique_id=T1003,'
328
+ 'technique_name=Credential Dumping","UtcTime":"2025-04-09 21:18:05.064",'
329
+ '"SourceProcessGUID":"691FF406-E40B-67F6-2901-000000003A00","SourceProcessId":4964,"SourceThreadId":4448,'
330
+ '"SourceImage":"C:\\\\Users\\\\ADMINI~1\\\\AppData\\\\Local\\\\Temp\\\\2\\\\AttackSim\\\\procdump.exe",'
331
+ '"TargetProcessGUID":"691FF406-DDC8-67F6-0C00-000000003A00","TargetProcessId":668,'
332
+ '"TargetImage":"C:\\\\Windows\\\\system32\\\\lsass.exe","GrantedAccess":2097151,'
333
+ '"CallTrace":"C:\\\\Windows\\\\SYSTEM32\\\\ntdll.dll+9fc24|C:\\\\Windows\\\\System32\\\\wow64.dll+3cf4|'
334
+ "C:\\\\Windows\\\\System32\\\\wow64.dll+7783|C:\\\\Windows\\\\System32\\\\wow64cpu.dll+1783|"
335
+ "C:\\\\Windows\\\\System32\\\\wow64cpu.dll+1199|C:\\\\Windows\\\\System32\\\\wow64.dll+cfda|"
336
+ "C:\\\\Windows\\\\System32\\\\wow64.dll+cea0|C:\\\\Windows\\\\SYSTEM32\\\\ntdll.dll+757db|"
337
+ "C:\\\\Windows\\\\SYSTEM32\\\\ntdll.dll+756c3|C:\\\\Windows\\\\SYSTEM32\\\\ntdll.dll+7566e|"
338
+ "C:\\\\Windows\\\\SYSTEM32\\\\ntdll.dll+7070c(wow64)|C:\\\\Windows\\\\System32\\\\KERNELBASE.dll+10eca8(wow64)|"
339
+ "C:\\\\Users\\\\ADMINI~1\\\\AppData\\\\Local\\\\Temp\\\\2\\\\AttackSim\\\\procdump.exe+876e|"
340
+ "C:\\\\Windows\\\\System32\\\\KERNEL32.DLL+20419(wow64)|C:\\\\Windows\\\\SYSTEM32\\\\ntdll.dll+6662d(wow64)|"
341
+ 'C:\\\\Windows\\\\SYSTEM32\\\\ntdll.dll+665fd(wow64)","SourceUser":"WIN-HFOU106TD7K\\\\Administrator",'
342
+ '"TargetUser":"NT AUTHORITY\\\\SYSTEM"},'
343
+ '"Message":"Process accessed:\\nRuleName: technique_id=T1003,technique_name=Credential Dumping!s!\\n'
344
+ "UtcTime: 2025-04-09 21:18:05.064!s!\\n"
345
+ "SourceProcessGUID: 691FF406-E40B-67F6-2901-000000003A00!s!\\n"
346
+ "SourceProcessId: 4964!s!\\n"
347
+ "SourceThreadId: 4448!s!\\n"
348
+ "SourceImage: C:\\\\Users\\\\ADMINI~1\\\\AppData\\\\Local\\\\Temp\\\\2\\\\AttackSim\\\\procdump.exe!s!\\n"
349
+ "TargetProcessGUID: 691FF406-DDC8-67F6-0C00-000000003A00!s!\\n"
350
+ "TargetProcessId: 668!s!\\n"
351
+ "TargetImage: C:\\\\Windows\\\\system32\\\\lsass.exe!s!\\n"
352
+ "GrantedAccess: 2097151!s!\\n"
353
+ "CallTrace: C:\\\\Windows\\\\SYSTEM32\\\\ntdll.dll+9fc24|C:\\\\Windows\\\\System32\\\\wow64.dll+3cf4|"
354
+ "C:\\\\Windows\\\\System32\\\\wow64.dll+7783|C:\\\\Windows\\\\System32\\\\wow64cpu.dll+1783|"
355
+ "C:\\\\Windows\\\\System32\\\\wow64cpu.dll+1199|C:\\\\Windows\\\\System32\\\\wow64.dll+cfda|"
356
+ "C:\\\\Windows\\\\System32\\\\wow64.dll+cea0|C:\\\\Windows\\\\SYSTEM32\\\\ntdll.dll+757db|"
357
+ "C:\\\\Windows\\\\SYSTEM32\\\\ntdll.dll+756c3|C:\\\\Windows\\\\SYSTEM32\\\\ntdll.dll+7566e|"
358
+ "C:\\\\Windows\\\\SYSTEM32\\\\ntdll.dll+7070c(wow64)|C:\\\\Windows\\\\System32\\\\KERNELBASE.dll+10eca8(wow64)|"
359
+ "C:\\\\Users\\\\ADMINI~1\\\\AppData\\\\Local\\\\Temp\\\\2\\\\AttackSim\\\\procdump.exe+876e|"
360
+ "C:\\\\Windows\\\\System32\\\\KERNEL32.DLL+20419(wow64)|C:\\\\Windows\\\\SYSTEM32\\\\ntdll.dll+6662d(wow64)|"
361
+ "C:\\\\Windows\\\\SYSTEM32\\\\ntdll.dll+665fd(wow64)!s!\\n"
362
+ "SourceUser: WIN-HFOU106TD7K\\\\Administrator!s!\\n"
363
+ 'TargetUser: NT AUTHORITY\\\\SYSTEM!s!\\r\\n"}'
364
+ ),
365
+ "type": "sigma-alert",
366
+ "source": "velociraptor",
367
+ "index_pattern": "wazuh-*",
368
+ "sourceRef": "754600692",
369
+ },
370
},
365
- })
371
+ )
372
373
374
class VelociraptorSigmaAlertResponse(BaseModel):
@@ -392,17 +398,19 @@ class VeloSigmaExclusionCreate(VeloSigmaExclusionBase):
398
399
# Make created_by optional so it can be set by the server
400
created_by: Optional[str] = Field(None, description="User who created this exclusion rule")
395
- model_config = ConfigDict(json_schema_extra={
396
- "example": {
397
- "name": "Chainsaw Batch Script Exclusion",
398
- "description": "Exclude alerts from chainsaw batch scripts in Windows Temp folder",
399
- "channel": "Microsoft-Windows-Sysmon/Operational",
400
- "title": "HackTool - Powerup Write Hijack DLL",
401
- "field_matches": {"TargetFilename": "C:\\Windows\\Temp\\chainsaw_batch.bat"},
402
- "customer_code": None, # Optional, NULL means apply to all customers
403
- "enabled": True,
401
+ model_config = ConfigDict(
402
+ json_schema_extra={
403
+ "example": {
404
+ "name": "Chainsaw Batch Script Exclusion",
405
+ "description": "Exclude alerts from chainsaw batch scripts in Windows Temp folder",
406
+ "channel": "Microsoft-Windows-Sysmon/Operational",
407
+ "title": "HackTool - Powerup Write Hijack DLL",
408
+ "field_matches": {"TargetFilename": "C:\\Windows\\Temp\\chainsaw_batch.bat"},
409
+ "customer_code": None, # Optional, NULL means apply to all customers
410
+ "enabled": True,
411
+ },
412
},
405
- })
413
+ )
414
415
416
class VeloSigmaExclusionUpdate(BaseModel):
backend/app/integrations/alert_escalation/schema/escalate_alert.py
+4
-2
@@ -4,7 +4,8 @@ from typing import Dict
4
from typing import List
5
from typing import Optional
6
7
-from pydantic import ConfigDict, BaseModel
7
+from pydantic import BaseModel
8
+from pydantic import ConfigDict
9
from pydantic import Field
10
11
@@ -175,7 +176,8 @@ class IrisAlertContext(BaseModel):
176
)
177
alert_level: int = Field(..., description="Severity level of the alert", examples=[3])
178
process_name: Optional[List[str]] = Field(
178
- None, examples=[["No process name found"]],
179
+ None,
180
+ examples=[["No process name found"]],
181
description="Name of the process",
182
)
183
model_config = ConfigDict(extra="allow")
backend/app/integrations/bitdefender/schema/provision.py
+2
-1
@@ -2,8 +2,9 @@ from typing import Any
2
from typing import Dict
3
from typing import Optional
4
5
-from pydantic import model_validator, BaseModel
5
+from pydantic import BaseModel
6
from pydantic import Field
7
+from pydantic import model_validator
8
9
10
class ProvisionBitdefenderRequest(BaseModel):
backend/app/integrations/carbonblack/schema/provision.py
+28
-24
@@ -3,8 +3,10 @@ from typing import Dict
3
from typing import List
4
from typing import Optional
5
6
-from pydantic import model_validator, ConfigDict, BaseModel
6
+from pydantic import BaseModel
7
+from pydantic import ConfigDict
8
from pydantic import Field
9
+from pydantic import model_validator
10
11
12
class ProvisionCarbonBlackRequest(BaseModel):
@@ -59,27 +61,29 @@ class CarbonBlackEventStream(BaseModel):
61
None,
62
description="Associated content pack, if any",
63
)
62
- model_config = ConfigDict(json_schema_extra={
63
- "example": {
64
- "title": "CarbonBlack SIEM EVENTS - Example Company",
65
- "description": "CarbonBlack SIEM EVENTS - Example Company",
66
- "index_set_id": "12345",
67
- "rules": [
68
- {
69
- "field": "customer_code",
70
- "type": 1,
71
- "inverted": False,
72
- "value": "ExampleCode",
73
- },
74
- {
75
- "field": "integration",
76
- "type": 1,
77
- "inverted": False,
78
- "value": "huntress",
79
- },
80
- ],
81
- "matching_type": "AND",
82
- "remove_matches_from_default_stream": True,
83
- "content_pack": None,
64
+ model_config = ConfigDict(
65
+ json_schema_extra={
66
+ "example": {
67
+ "title": "CarbonBlack SIEM EVENTS - Example Company",
68
+ "description": "CarbonBlack SIEM EVENTS - Example Company",
69
+ "index_set_id": "12345",
70
+ "rules": [
71
+ {
72
+ "field": "customer_code",
73
+ "type": 1,
74
+ "inverted": False,
75
+ "value": "ExampleCode",
76
+ },
77
+ {
78
+ "field": "integration",
79
+ "type": 1,
80
+ "inverted": False,
81
+ "value": "huntress",
82
+ },
83
+ ],
84
+ "matching_type": "AND",
85
+ "remove_matches_from_default_stream": True,
86
+ "content_pack": None,
87
+ },
88
},
85
- })
89
+ )
backend/app/integrations/cato/schema/provision.py
+28
-24
@@ -3,8 +3,10 @@ from typing import Dict
3
from typing import List
4
from typing import Optional
5
6
-from pydantic import model_validator, ConfigDict, BaseModel
6
+from pydantic import BaseModel
7
+from pydantic import ConfigDict
8
from pydantic import Field
9
+from pydantic import model_validator
10
11
12
class ProvisionCatoRequest(BaseModel):
@@ -59,27 +61,29 @@ class CatoEventStream(BaseModel):
61
None,
62
description="Associated content pack, if any",
63
)
62
- model_config = ConfigDict(json_schema_extra={
63
- "example": {
64
- "title": "Cato SIEM EVENTS - Example Company",
65
- "description": "Cato SIEM EVENTS - Example Company",
66
- "index_set_id": "12345",
67
- "rules": [
68
- {
69
- "field": "customer_code",
70
- "type": 1,
71
- "inverted": False,
72
- "value": "ExampleCode",
73
- },
74
- {
75
- "field": "integration",
76
- "type": 1,
77
- "inverted": False,
78
- "value": "cato",
79
- },
80
- ],
81
- "matching_type": "AND",
82
- "remove_matches_from_default_stream": True,
83
- "content_pack": None,
64
+ model_config = ConfigDict(
65
+ json_schema_extra={
66
+ "example": {
67
+ "title": "Cato SIEM EVENTS - Example Company",
68
+ "description": "Cato SIEM EVENTS - Example Company",
69
+ "index_set_id": "12345",
70
+ "rules": [
71
+ {
72
+ "field": "customer_code",
73
+ "type": 1,
74
+ "inverted": False,
75
+ "value": "ExampleCode",
76
+ },
77
+ {
78
+ "field": "integration",
79
+ "type": 1,
80
+ "inverted": False,
81
+ "value": "cato",
82
+ },
83
+ ],
84
+ "matching_type": "AND",
85
+ "remove_matches_from_default_stream": True,
86
+ "content_pack": None,
87
+ },
88
},
85
- })
89
+ )
backend/app/integrations/copilot_action/schema/copilot_action.py
+2
-1
@@ -6,8 +6,9 @@ from typing import List
6
from typing import Optional
7
from typing import Union
8
9
-from pydantic import field_validator, BaseModel
9
+from pydantic import BaseModel
10
from pydantic import Field
11
+from pydantic import field_validator
12
from pydantic import model_validator
13
14
backend/app/integrations/copilot_mcp/schema/copilot_mcp.py
+2
-1
@@ -5,8 +5,9 @@ from typing import List
5
from typing import Optional
6
7
from fastapi import HTTPException
8
-from pydantic import field_validator, BaseModel
8
+from pydantic import BaseModel
9
from pydantic import Field
10
+from pydantic import field_validator
11
12
13
class MCPServerType(str, Enum):
backend/app/integrations/copilot_searches/schema/copilot_searches.py
+14
-10
@@ -157,12 +157,14 @@ class ExecuteSearchRequest(BaseModel):
157
parameters: dict[str, Any] = Field(
158
default_factory=dict,
159
description="Parameter values to substitute in the query",
160
- examples=[{
161
- "AGENT_NAME": "my-server",
162
- "CUSTOMER_CODE": "lab",
163
- "START_TIME": "now-24h",
164
- "END_TIME": "now",
165
- }],
160
+ examples=[
161
+ {
162
+ "AGENT_NAME": "my-server",
163
+ "CUSTOMER_CODE": "lab",
164
+ "START_TIME": "now-24h",
165
+ "END_TIME": "now",
166
+ },
167
+ ],
168
)
169
size: Optional[int] = Field(
170
default=None,
@@ -226,10 +228,12 @@ class ExecuteGraylogQueryRequest(BaseModel):
228
parameters: dict[str, Any] = Field(
229
default_factory=dict,
230
description="Parameter values to substitute in the query",
229
- examples=[{
230
- "AGENT_NAME": "my-server",
231
- "CUSTOMER_CODE": "lab",
232
- }],
231
+ examples=[
232
+ {
233
+ "AGENT_NAME": "my-server",
234
+ "CUSTOMER_CODE": "lab",
235
+ },
236
+ ],
237
)
238
239
backend/app/integrations/crowdstrike/schema/provision.py
+2
-1
@@ -2,8 +2,9 @@ from typing import Any
2
from typing import Dict
3
from typing import Optional
4
5
-from pydantic import model_validator, BaseModel
5
+from pydantic import BaseModel
6
from pydantic import Field
7
+from pydantic import model_validator
8
9
10
class ProvisionCrowdstrikeRequest(BaseModel):
backend/app/integrations/darktrace/schema/provision.py
+28
-24
@@ -3,8 +3,10 @@ from typing import Dict
3
from typing import List
4
from typing import Optional
5
6
-from pydantic import model_validator, ConfigDict, BaseModel
6
+from pydantic import BaseModel
7
+from pydantic import ConfigDict
8
from pydantic import Field
9
+from pydantic import model_validator
10
11
12
class ProvisionDarktraceRequest(BaseModel):
@@ -59,27 +61,29 @@ class DarktraceEventStream(BaseModel):
61
None,
62
description="Associated content pack, if any",
63
)
62
- model_config = ConfigDict(json_schema_extra={
63
- "example": {
64
- "title": "Darktrace SIEM EVENTS - Example Company",
65
- "description": "Darktrace SIEM EVENTS - Example Company",
66
- "index_set_id": "12345",
67
- "rules": [
68
- {
69
- "field": "customer_code",
70
- "type": 1,
71
- "inverted": False,
72
- "value": "ExampleCode",
73
- },
74
- {
75
- "field": "integration",
76
- "type": 1,
77
- "inverted": False,
78
- "value": "darktrace",
79
- },
80
- ],
81
- "matching_type": "AND",
82
- "remove_matches_from_default_stream": True,
83
- "content_pack": None,
64
+ model_config = ConfigDict(
65
+ json_schema_extra={
66
+ "example": {
67
+ "title": "Darktrace SIEM EVENTS - Example Company",
68
+ "description": "Darktrace SIEM EVENTS - Example Company",
69
+ "index_set_id": "12345",
70
+ "rules": [
71
+ {
72
+ "field": "customer_code",
73
+ "type": 1,
74
+ "inverted": False,
75
+ "value": "ExampleCode",
76
+ },
77
+ {
78
+ "field": "integration",
79
+ "type": 1,
80
+ "inverted": False,
81
+ "value": "darktrace",
82
+ },
83
+ ],
84
+ "matching_type": "AND",
85
+ "remove_matches_from_default_stream": True,
86
+ "content_pack": None,
87
+ },
88
},
85
- })
89
+ )
backend/app/integrations/defender_for_endpoint/schema/provision.py
+2
-1
@@ -2,8 +2,9 @@ from typing import Any
2
from typing import Dict
3
from typing import Optional
4
5
-from pydantic import model_validator, BaseModel
5
+from pydantic import BaseModel
6
from pydantic import Field
7
+from pydantic import model_validator
8
9
10
class ProvisionDefenderForEndpointRequest(BaseModel):
backend/app/integrations/duo/schema/provision.py
+28
-24
@@ -3,8 +3,10 @@ from typing import Dict
3
from typing import List
4
from typing import Optional
5
6
-from pydantic import model_validator, ConfigDict, BaseModel
6
+from pydantic import BaseModel
7
+from pydantic import ConfigDict
8
from pydantic import Field
9
+from pydantic import model_validator
10
11
12
class ProvisionDuoRequest(BaseModel):
@@ -59,27 +61,29 @@ class DuoEventStream(BaseModel):
61
None,
62
description="Associated content pack, if any",
63
)
62
- model_config = ConfigDict(json_schema_extra={
63
- "example": {
64
- "title": "Duo SIEM EVENTS - Example Company",
65
- "description": "Duo SIEM EVENTS - Example Company",
66
- "index_set_id": "12345",
67
- "rules": [
68
- {
69
- "field": "customer_code",
70
- "type": 1,
71
- "inverted": False,
72
- "value": "ExampleCode",
73
- },
74
- {
75
- "field": "integration",
76
- "type": 1,
77
- "inverted": False,
78
- "value": "huntress",
79
- },
80
- ],
81
- "matching_type": "AND",
82
- "remove_matches_from_default_stream": True,
83
- "content_pack": None,
64
+ model_config = ConfigDict(
65
+ json_schema_extra={
66
+ "example": {
67
+ "title": "Duo SIEM EVENTS - Example Company",
68
+ "description": "Duo SIEM EVENTS - Example Company",
69
+ "index_set_id": "12345",
70
+ "rules": [
71
+ {
72
+ "field": "customer_code",
73
+ "type": 1,
74
+ "inverted": False,
75
+ "value": "ExampleCode",
76
+ },
77
+ {
78
+ "field": "integration",
79
+ "type": 1,
80
+ "inverted": False,
81
+ "value": "huntress",
82
+ },
83
+ ],
84
+ "matching_type": "AND",
85
+ "remove_matches_from_default_stream": True,
86
+ "content_pack": None,
87
+ },
88
},
85
- })
89
+ )
backend/app/integrations/github_audit/model.py
+8
-2
@@ -58,7 +58,10 @@ class GitHubAuditConfig(SQLModel, table=True):
58
default="all",
59
description="'all', 'include', or 'exclude'",
60
)
61
- repo_filter_list: Optional[List[str]] = Field(sa_column=Column(JSON, nullable=True), description="List of repos to include/exclude based on filter_mode")
61
+ repo_filter_list: Optional[List[str]] = Field(
62
+ sa_column=Column(JSON, nullable=True),
63
+ description="List of repos to include/exclude based on filter_mode",
64
+ )
65
66
# Notification settings
67
notify_on_critical: bool = Field(default=True, description="Send notification on critical findings")
@@ -209,7 +212,10 @@ class GitHubAuditBaseline(SQLModel, table=True):
212
description: Optional[str] = Field(sa_column=Column(Text, nullable=True))
213
214
# Expected values
212
- expected_checks: Optional[Dict] = Field(sa_column=Column(JSON, nullable=True), description="Expected check results by check_id: {check_id: expected_status}")
215
+ expected_checks: Optional[Dict] = Field(
216
+ sa_column=Column(JSON, nullable=True),
217
+ description="Expected check results by check_id: {check_id: expected_status}",
218
+ )
219
220
# Baseline from a previous report
221
baseline_report_id: Optional[int] = Field(
backend/app/integrations/huntress/schema/provision.py
+28
-24
@@ -3,8 +3,10 @@ from typing import Dict
3
from typing import List
4
from typing import Optional
5
6
-from pydantic import model_validator, ConfigDict, BaseModel
6
+from pydantic import BaseModel
7
+from pydantic import ConfigDict
8
from pydantic import Field
9
+from pydantic import model_validator
10
11
12
class ProvisionHuntressRequest(BaseModel):
@@ -59,27 +61,29 @@ class HuntressEventStream(BaseModel):
61
None,
62
description="Associated content pack, if any",
63
)
62
- model_config = ConfigDict(json_schema_extra={
63
- "example": {
64
- "title": "Huntress SIEM EVENTS - Example Company",
65
- "description": "Huntress SIEM EVENTS - Example Company",
66
- "index_set_id": "12345",
67
- "rules": [
68
- {
69
- "field": "customer_code",
70
- "type": 1,
71
- "inverted": False,
72
- "value": "ExampleCode",
73
- },
74
- {
75
- "field": "integration",
76
- "type": 1,
77
- "inverted": False,
78
- "value": "huntress",
79
- },
80
- ],
81
- "matching_type": "AND",
82
- "remove_matches_from_default_stream": True,
83
- "content_pack": None,
64
+ model_config = ConfigDict(
65
+ json_schema_extra={
66
+ "example": {
67
+ "title": "Huntress SIEM EVENTS - Example Company",
68
+ "description": "Huntress SIEM EVENTS - Example Company",
69
+ "index_set_id": "12345",
70
+ "rules": [
71
+ {
72
+ "field": "customer_code",
73
+ "type": 1,
74
+ "inverted": False,
75
+ "value": "ExampleCode",
76
+ },
77
+ {
78
+ "field": "integration",
79
+ "type": 1,
80
+ "inverted": False,
81
+ "value": "huntress",
82
+ },
83
+ ],
84
+ "matching_type": "AND",
85
+ "remove_matches_from_default_stream": True,
86
+ "content_pack": None,
87
+ },
88
},
85
- })
89
+ )
backend/app/integrations/mimecast/schema/mimecast.py
+3
-1
@@ -9,9 +9,11 @@ from typing import Dict
9
from typing import List
10
from typing import Optional
11
12
-from pydantic import model_validator, ConfigDict, BaseModel
12
+from pydantic import BaseModel
13
+from pydantic import ConfigDict
14
from pydantic import Field
15
from pydantic import HttpUrl
16
+from pydantic import model_validator
17
18
19
class PipelineRuleTitles(Enum):
backend/app/integrations/mimecast/schema/provision.py
+28
-24
@@ -3,8 +3,10 @@ from typing import Dict
3
from typing import List
4
from typing import Optional
5
6
-from pydantic import model_validator, ConfigDict, BaseModel
6
+from pydantic import BaseModel
7
+from pydantic import ConfigDict
8
from pydantic import Field
9
+from pydantic import model_validator
10
11
12
class ProvisionMimecastRequest(BaseModel):
@@ -54,27 +56,29 @@ class MimecastEventStream(BaseModel):
56
None,
57
description="Associated content pack, if any",
58
)
57
- model_config = ConfigDict(json_schema_extra={
58
- "example": {
59
- "title": "Mimecast EVENTS - Example Company",
60
- "description": "Mimecast EVENTS - Example Company",
61
- "index_set_id": "12345",
62
- "rules": [
63
- {
64
- "field": "agent_labels_customer",
65
- "type": 1,
66
- "inverted": False,
67
- "value": "ExampleCode",
68
- },
69
- {
70
- "field": "agent_labels_integration",
71
- "type": 1,
72
- "inverted": False,
73
- "value": "Office365",
74
- },
75
- ],
76
- "matching_type": "AND",
77
- "remove_matches_from_default_stream": True,
78
- "content_pack": None,
59
+ model_config = ConfigDict(
60
+ json_schema_extra={
61
+ "example": {
62
+ "title": "Mimecast EVENTS - Example Company",
63
+ "description": "Mimecast EVENTS - Example Company",
64
+ "index_set_id": "12345",
65
+ "rules": [
66
+ {
67
+ "field": "agent_labels_customer",
68
+ "type": 1,
69
+ "inverted": False,
70
+ "value": "ExampleCode",
71
+ },
72
+ {
73
+ "field": "agent_labels_integration",
74
+ "type": 1,
75
+ "inverted": False,
76
+ "value": "Office365",
77
+ },
78
+ ],
79
+ "matching_type": "AND",
80
+ "remove_matches_from_default_stream": True,
81
+ "content_pack": None,
82
+ },
83
},
80
- })
84
+ )
backend/app/integrations/modules/schema/carbonblack.py
+2
-1
@@ -1,8 +1,9 @@
1
from typing import Optional
2
3
from fastapi import HTTPException
4
-from pydantic import field_validator, BaseModel
4
+from pydantic import BaseModel
5
from pydantic import Field
6
+from pydantic import field_validator
7
8
9
class InvokeCarbonBlackRequest(BaseModel):
backend/app/integrations/modules/schema/cato.py
+2
-1
@@ -1,6 +1,7 @@
1
from fastapi import HTTPException
2
-from pydantic import field_validator, BaseModel
2
+from pydantic import BaseModel
3
from pydantic import Field
4
+from pydantic import field_validator
5
6
7
class InvokeCatoRequest(BaseModel):
backend/app/integrations/modules/schema/darktrace.py
+2
-1
@@ -1,6 +1,7 @@
1
from fastapi import HTTPException
2
-from pydantic import field_validator, BaseModel
2
+from pydantic import BaseModel
3
from pydantic import Field
4
+from pydantic import field_validator
5
6
7
class InvokeDarktraceRequest(BaseModel):
backend/app/integrations/modules/schema/duo.py
+2
-1
@@ -1,6 +1,7 @@
1
from fastapi import HTTPException
2
-from pydantic import field_validator, BaseModel
2
+from pydantic import BaseModel
3
from pydantic import Field
4
+from pydantic import field_validator
5
6
7
class InvokeDuoRequest(BaseModel):
backend/app/integrations/modules/schema/huntress.py
+2
-1
@@ -1,6 +1,7 @@
1
from fastapi import HTTPException
2
-from pydantic import field_validator, BaseModel
2
+from pydantic import BaseModel
3
from pydantic import Field
4
+from pydantic import field_validator
5
6
7
class InvokeHuntressRequest(BaseModel):
backend/app/integrations/modules/schema/mimecast.py
+2
-1
@@ -1,8 +1,9 @@
1
from typing import Optional
2
3
from fastapi import HTTPException
4
-from pydantic import field_validator, BaseModel
4
+from pydantic import BaseModel
5
from pydantic import Field
6
+from pydantic import field_validator
7
8
9
class InvokeMimecastRequest(BaseModel):
backend/app/integrations/modules/schema/sap_siem.py
+2
-1
@@ -2,8 +2,9 @@ from datetime import datetime
2
from datetime import timedelta
3
from typing import Optional
4
5
-from pydantic import model_validator, BaseModel
5
+from pydantic import BaseModel
6
from pydantic import Field
7
+from pydantic import model_validator
8
9
10
class InvokeSapSiemRequest(BaseModel):
backend/app/integrations/modules/services/sap_siem/collect.py
+3
-1
@@ -148,7 +148,9 @@ async def post_to_copilot_sap_module_brute_force_failed_logins_same_ip(data: Inv
148
Args:
149
data (InvokeSapSiemAnalysis): The data to send to the copilot-sap-module Docker container.
150
"""
151
- logger.info(f"Sending POST request to http://copilot-sap-module/sap-siem/brute_force_failed_logins_same_ip with data: {data.model_dump()}")
151
+ logger.info(
152
+ f"Sending POST request to http://copilot-sap-module/sap-siem/brute_force_failed_logins_same_ip with data: {data.model_dump()}",
153
+ )
154
async with httpx.AsyncClient() as client:
155
try:
156
response = await client.post(
backend/app/integrations/monitoring_alert/schema/provision.py
+10
-7
@@ -4,8 +4,9 @@ from typing import List
4
from typing import Optional
5
6
from fastapi import HTTPException
7
-from pydantic import field_validator, BaseModel
7
+from pydantic import BaseModel
8
from pydantic import Field
9
+from pydantic import field_validator
10
11
12
class AvailableMonitoringAlerts(str, Enum):
@@ -451,12 +452,14 @@ class CustomMonitoringAlertProvisionModel(BaseModel):
452
"have a pipeline rule that sets the SYSLOG_LEVEL field to ALERT when "
453
"the Wazuh rule level is greater than 11."
454
),
454
- examples=[(
455
- "This alert monitors the SYSLOG_LEVEL field in the Wazuh logs. When "
456
- "the level is ALERT, it triggers an alert that is created within "
457
- "DFIR-IRIS. Ensure that you have a pipeline rule that sets the "
458
- "SYSLOG_LEVEL field to ALERT when the Wazuh rule level is greater than 11."
459
- )],
455
+ examples=[
456
+ (
457
+ "This alert monitors the SYSLOG_LEVEL field in the Wazuh logs. When "
458
+ "the level is ALERT, it triggers an alert that is created within "
459
+ "DFIR-IRIS. Ensure that you have a pipeline rule that sets the "
460
+ "SYSLOG_LEVEL field to ALERT when the Wazuh rule level is greater than 11."
461
+ ),
462
+ ],
463
)
464
alert_priority: AlertPriority = Field(
465
...,
backend/app/integrations/monitoring_alert/services/provision.py
+8
-4
@@ -1127,7 +1127,8 @@ async def provision_fortinet_wids_wireless_eapol_packet_flooding_detected_monito
1127
Provisions Fortinet WIDS Wireless EAPOL Packet Flooding Detected monitoring alert.
1128
"""
1129
logger.info(
1130
- "Invoking provision_fortinet_wids_wireless_eapol_packet_flooding_detected_monitoring_alert " f"with request: {request.model_dump()}",
1130
+ "Invoking provision_fortinet_wids_wireless_eapol_packet_flooding_detected_monitoring_alert "
1131
+ f"with request: {request.model_dump()}",
1132
)
1133
await provision_alert_definition(
1134
GraylogAlertProvisionModel(
@@ -2432,7 +2433,8 @@ async def provision_sentinelone_new_mitigation_kill_performed_successfully_monit
2433
Provisions SentinelOne: New Mitigation, Kill performed successfully.
2434
"""
2435
logger.info(
2435
- "Invoking provision_sentinelone_new_mitigation_kill_performed_successfully_monitoring_alert " f"with request: {request.model_dump()}",
2436
+ "Invoking provision_sentinelone_new_mitigation_kill_performed_successfully_monitoring_alert "
2437
+ f"with request: {request.model_dump()}",
2438
)
2439
await provision_alert_definition(
2440
GraylogAlertProvisionModel(
@@ -2547,7 +2549,8 @@ async def provision_sentinelone_new_exclusion_was_added_or_modified_by_user_moni
2549
Provisions SentinelOne: New Exclusion was added/modified by user.
2550
"""
2551
logger.info(
2550
- "Invoking provision_sentinelone_new_exclusion_was_added_or_modified_by_user_monitoring_alert " f"with request: {request.model_dump()}",
2552
+ "Invoking provision_sentinelone_new_exclusion_was_added_or_modified_by_user_monitoring_alert "
2553
+ f"with request: {request.model_dump()}",
2554
)
2555
await provision_alert_definition(
2556
GraylogAlertProvisionModel(
@@ -2718,7 +2721,8 @@ async def provision_sentinelone_analyst_verdict_changed_to_false_positive_monito
2721
Provisions SentinelOne: Analyst verdict changed to False Positive.
2722
"""
2723
logger.info(
2721
- "Invoking provision_sentinelone_analyst_verdict_changed_to_false_positive_monitoring_alert " f"with request: {request.model_dump()}",
2724
+ "Invoking provision_sentinelone_analyst_verdict_changed_to_false_positive_monitoring_alert "
2725
+ f"with request: {request.model_dump()}",
2726
)
2727
await provision_alert_definition(
2728
GraylogAlertProvisionModel(
backend/app/integrations/office365/schema/provision.py
+2
-1
@@ -2,8 +2,9 @@ from enum import Enum
2
from typing import Any
3
from typing import Dict
4
5
-from pydantic import model_validator, BaseModel
5
+from pydantic import BaseModel
6
from pydantic import Field
7
+from pydantic import model_validator
8
9
10
class PipelineRuleTitles(Enum):
backend/app/integrations/sap_siem/schema/provision.py
+28
-24
@@ -3,8 +3,10 @@ from typing import Dict
3
from typing import List
4
from typing import Optional
5
6
-from pydantic import model_validator, ConfigDict, BaseModel
6
+from pydantic import BaseModel
7
+from pydantic import ConfigDict
8
from pydantic import Field
9
+from pydantic import model_validator
10
11
12
class ProvisionSapSiemRequest(BaseModel):
@@ -59,27 +61,29 @@ class SapSiemEventStream(BaseModel):
61
None,
62
description="Associated content pack, if any",
63
)
62
- model_config = ConfigDict(json_schema_extra={
63
- "example": {
64
- "title": "SAP SIEM EVENTS - Example Company",
65
- "description": "SAP SIEM EVENTS - Example Company",
66
- "index_set_id": "12345",
67
- "rules": [
68
- {
69
- "field": "customer_code",
70
- "type": 1,
71
- "inverted": False,
72
- "value": "ExampleCode",
73
- },
74
- {
75
- "field": "integration",
76
- "type": 1,
77
- "inverted": False,
78
- "value": "sap_siem",
79
- },
80
- ],
81
- "matching_type": "AND",
82
- "remove_matches_from_default_stream": True,
83
- "content_pack": None,
64
+ model_config = ConfigDict(
65
+ json_schema_extra={
66
+ "example": {
67
+ "title": "SAP SIEM EVENTS - Example Company",
68
+ "description": "SAP SIEM EVENTS - Example Company",
69
+ "index_set_id": "12345",
70
+ "rules": [
71
+ {
72
+ "field": "customer_code",
73
+ "type": 1,
74
+ "inverted": False,
75
+ "value": "ExampleCode",
76
+ },
77
+ {
78
+ "field": "integration",
79
+ "type": 1,
80
+ "inverted": False,
81
+ "value": "sap_siem",
82
+ },
83
+ ],
84
+ "matching_type": "AND",
85
+ "remove_matches_from_default_stream": True,
86
+ "content_pack": None,
87
+ },
88
},
85
- })
89
+ )
backend/app/integrations/sap_siem/schema/sap_siem.py
+2
-1
@@ -5,8 +5,9 @@ from typing import Dict
5
from typing import List
6
from typing import Optional
7
8
-from pydantic import model_validator, BaseModel
8
+from pydantic import BaseModel
9
from pydantic import Field
10
+from pydantic import model_validator
11
12
13
class InvokeSapSiemRequest(BaseModel):
backend/app/integrations/schema.py
+2
-1
@@ -1,7 +1,8 @@
1
from typing import List
2
from typing import Optional
3
4
-from pydantic import ConfigDict, BaseModel
4
+from pydantic import BaseModel
5
+from pydantic import ConfigDict
6
from pydantic import Field
7
8
backend/app/integrations/utils/schema.py
+2
-1
@@ -1,7 +1,8 @@
1
from typing import List
2
from typing import Optional
3
4
-from pydantic import ConfigDict, BaseModel
4
+from pydantic import BaseModel
5
+from pydantic import ConfigDict
6
from pydantic import Field
7
8
backend/app/network_connectors/schema.py
+2
-1
@@ -1,7 +1,8 @@
1
from typing import List
2
from typing import Optional
3
4
-from pydantic import ConfigDict, BaseModel
4
+from pydantic import BaseModel
5
+from pydantic import ConfigDict
6
from pydantic import Field
7
8
backend/app/notifications/schema/notifications.py
+3
-1
@@ -15,8 +15,10 @@ from enum import Enum
15
from typing import List
16
from typing import Optional
17
18
-from pydantic import field_validator, ConfigDict, BaseModel
18
+from pydantic import BaseModel
19
+from pydantic import ConfigDict
20
from pydantic import Field
21
+from pydantic import field_validator
22
from pydantic import model_validator
23
24
# ---------------------------------------------------------------------------
backend/app/siem/schema/dashboards.py
+2
-1
@@ -4,7 +4,8 @@ from typing import Dict
4
from typing import List
5
from typing import Optional
6
7
-from pydantic import ConfigDict, BaseModel
7
+from pydantic import BaseModel
8
+from pydantic import ConfigDict
9
from pydantic import Field
10
11
# ── Template browsing (read from disk) ───────────────────────────
backend/app/siem/schema/event_sources.py
+2
-1
@@ -3,7 +3,8 @@ from enum import Enum
3
from typing import List
4
from typing import Optional
5
6
-from pydantic import ConfigDict, BaseModel
6
+from pydantic import BaseModel
7
+from pydantic import ConfigDict
8
from pydantic import Field
9
10
backend/app/stack_provisioning/graylog/schema/fortinet.py
+2
-1
@@ -2,8 +2,9 @@ from typing import Any
2
from typing import Dict
3
from typing import Optional
4
5
-from pydantic import model_validator, BaseModel
5
+from pydantic import BaseModel
6
from pydantic import Field
7
+from pydantic import model_validator
8
9
10
class ProvisionFortinetRequest(BaseModel):
backend/app/stack_provisioning/graylog/schema/provision.py
+6
-4
@@ -69,10 +69,12 @@ class ContentPack(BaseModel):
69
class AvailableContentPacksResponse(BaseModel):
70
available_content_packs: List[ContentPack] = Field(
71
...,
72
- examples=[{
73
- "name": AvailableContentPacks.SOCFORTRESS_WAZUH_CONTENT_PACK.name,
74
- "description": AvailableContentPacks.SOCFORTRESS_WAZUH_CONTENT_PACK.value,
75
- }],
72
+ examples=[
73
+ {
74
+ "name": AvailableContentPacks.SOCFORTRESS_WAZUH_CONTENT_PACK.name,
75
+ "description": AvailableContentPacks.SOCFORTRESS_WAZUH_CONTENT_PACK.value,
76
+ },
77
+ ],
78
description="The available content packs for provisioning in Graylog",
79
)
80
success: bool = Field(
backend/app/stack_provisioning/graylog/schema/sentinelone.py
+2
-1
@@ -2,8 +2,9 @@ from typing import Any
2
from typing import Dict
3
from typing import Optional
4
5
-from pydantic import model_validator, BaseModel
5
+from pydantic import BaseModel
6
from pydantic import Field
7
+from pydantic import model_validator
8
9
10
class ProvisionSentinelOneRequest(BaseModel):
backend/app/stack_provisioning/graylog/schema/sonicwall.py
+2
-1
@@ -2,8 +2,9 @@ from typing import Any
2
from typing import Dict
3
from typing import Optional
4
5
-from pydantic import model_validator, BaseModel
5
+from pydantic import BaseModel
6
from pydantic import Field
7
+from pydantic import model_validator
8
9
10
class ProvisionSonicwallRequest(BaseModel):
backend/app/threat_intel/schema/socfortress.py
+2
-1
@@ -4,8 +4,9 @@ from typing import List
4
from typing import Optional
5
6
from fastapi import HTTPException
7
-from pydantic import field_validator, BaseModel
7
+from pydantic import BaseModel
8
from pydantic import Field
9
+from pydantic import field_validator
10
11
12
class SocfortressThreatIntelRequest(BaseModel):
backend/app/threat_intel/schema/virustotal.py
+2
-1
@@ -2,7 +2,8 @@ from typing import Dict
2
from typing import List
3
from typing import Optional
4
5
-from pydantic import ConfigDict, BaseModel
5
+from pydantic import BaseModel
6
+from pydantic import ConfigDict
7
from pydantic import Field
8
9
backend/app/utils.py
+2
-1
@@ -15,8 +15,9 @@ from fastapi import Request
15
from fastapi import Security
16
from fastapi.exceptions import RequestValidationError
17
from loguru import logger
18
-from pydantic import field_validator, BaseModel
18
+from pydantic import BaseModel
19
from pydantic import Field
20
+from pydantic import field_validator
21
from pydantic import model_validator
22
from sqlalchemy.ext.asyncio import AsyncSession
23
from sqlalchemy.future import select
backend/app/version/schema/version.py
+15
-12
@@ -1,6 +1,7 @@
1
from typing import Optional
2
3
-from pydantic import ConfigDict, BaseModel
3
+from pydantic import BaseModel
4
+from pydantic import ConfigDict
5
6
7
class VersionCheckResponse(BaseModel):
@@ -12,15 +13,17 @@ class VersionCheckResponse(BaseModel):
13
release_url: Optional[str] = None
14
release_notes: Optional[str] = None
15
published_at: Optional[str] = None
15
- model_config = ConfigDict(json_schema_extra={
16
- "example": {
17
- "success": True,
18
- "message": "New version v0.1.5 available!",
19
- "current_version": "0.1.4",
20
- "latest_version": "0.1.5",
21
- "is_outdated": True,
22
- "release_url": "https://github.com/socfortress/CoPilot/releases/tag/v0.1.5",
23
- "release_notes": "## What's Changed\n* Feature 1\n* Feature 2",
24
- "published_at": "2025-12-03T18:48:20Z",
16
+ model_config = ConfigDict(
17
+ json_schema_extra={
18
+ "example": {
19
+ "success": True,
20
+ "message": "New version v0.1.5 available!",
21
+ "current_version": "0.1.4",
22
+ "latest_version": "0.1.5",
23
+ "is_outdated": True,
24
+ "release_url": "https://github.com/socfortress/CoPilot/releases/tag/v0.1.5",
25
+ "release_notes": "## What's Changed\n* Feature 1\n* Feature 2",
26
+ "published_at": "2025-12-03T18:48:20Z",
27
+ },
28
},
26
- })
29
+ )
backend/copilot.py
+1
@@ -100,6 +100,7 @@ environment = os.getenv("ENVIRONMENT", "PRODUCTION")
100
# ssl_keyfile = os.path.join(os.path.dirname(__file__), "../nginx/server.key")
101
# ssl_certfile = os.path.join(os.path.dirname(__file__), "../nginx/server.crt")
102
103
+
104
@asynccontextmanager
105
async def lifespan(_app: FastAPI):
106
# ── startup ──
backend/requirements.txt
+1
-1
@@ -145,8 +145,8 @@ pyasn1==0.6.3
145
pyasn1-modules==0.4.2
146
pycparser==3.0
147
pycryptodome==3.23.0
148
-pydantic[email]==2.13.4
148
pydantic-core==2.46.4
149
+pydantic[email]==2.13.4
150
pydo==0.34.0
151
pyee==13.0.1
152
pygments==2.20.0