dtSpark 1.0.4__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.
- dtSpark/__init__.py +0 -0
- dtSpark/_description.txt +1 -0
- dtSpark/_full_name.txt +1 -0
- dtSpark/_licence.txt +21 -0
- dtSpark/_metadata.yaml +6 -0
- dtSpark/_name.txt +1 -0
- dtSpark/_version.txt +1 -0
- dtSpark/aws/__init__.py +7 -0
- dtSpark/aws/authentication.py +296 -0
- dtSpark/aws/bedrock.py +578 -0
- dtSpark/aws/costs.py +318 -0
- dtSpark/aws/pricing.py +580 -0
- dtSpark/cli_interface.py +2645 -0
- dtSpark/conversation_manager.py +3050 -0
- dtSpark/core/__init__.py +12 -0
- dtSpark/core/application.py +3355 -0
- dtSpark/core/context_compaction.py +735 -0
- dtSpark/daemon/__init__.py +104 -0
- dtSpark/daemon/__main__.py +10 -0
- dtSpark/daemon/action_monitor.py +213 -0
- dtSpark/daemon/daemon_app.py +730 -0
- dtSpark/daemon/daemon_manager.py +289 -0
- dtSpark/daemon/execution_coordinator.py +194 -0
- dtSpark/daemon/pid_file.py +169 -0
- dtSpark/database/__init__.py +482 -0
- dtSpark/database/autonomous_actions.py +1191 -0
- dtSpark/database/backends.py +329 -0
- dtSpark/database/connection.py +122 -0
- dtSpark/database/conversations.py +520 -0
- dtSpark/database/credential_prompt.py +218 -0
- dtSpark/database/files.py +205 -0
- dtSpark/database/mcp_ops.py +355 -0
- dtSpark/database/messages.py +161 -0
- dtSpark/database/schema.py +673 -0
- dtSpark/database/tool_permissions.py +186 -0
- dtSpark/database/usage.py +167 -0
- dtSpark/files/__init__.py +4 -0
- dtSpark/files/manager.py +322 -0
- dtSpark/launch.py +39 -0
- dtSpark/limits/__init__.py +10 -0
- dtSpark/limits/costs.py +296 -0
- dtSpark/limits/tokens.py +342 -0
- dtSpark/llm/__init__.py +17 -0
- dtSpark/llm/anthropic_direct.py +446 -0
- dtSpark/llm/base.py +146 -0
- dtSpark/llm/context_limits.py +438 -0
- dtSpark/llm/manager.py +177 -0
- dtSpark/llm/ollama.py +578 -0
- dtSpark/mcp_integration/__init__.py +5 -0
- dtSpark/mcp_integration/manager.py +653 -0
- dtSpark/mcp_integration/tool_selector.py +225 -0
- dtSpark/resources/config.yaml.template +631 -0
- dtSpark/safety/__init__.py +22 -0
- dtSpark/safety/llm_service.py +111 -0
- dtSpark/safety/patterns.py +229 -0
- dtSpark/safety/prompt_inspector.py +442 -0
- dtSpark/safety/violation_logger.py +346 -0
- dtSpark/scheduler/__init__.py +20 -0
- dtSpark/scheduler/creation_tools.py +599 -0
- dtSpark/scheduler/execution_queue.py +159 -0
- dtSpark/scheduler/executor.py +1152 -0
- dtSpark/scheduler/manager.py +395 -0
- dtSpark/tools/__init__.py +4 -0
- dtSpark/tools/builtin.py +833 -0
- dtSpark/web/__init__.py +20 -0
- dtSpark/web/auth.py +152 -0
- dtSpark/web/dependencies.py +37 -0
- dtSpark/web/endpoints/__init__.py +17 -0
- dtSpark/web/endpoints/autonomous_actions.py +1125 -0
- dtSpark/web/endpoints/chat.py +621 -0
- dtSpark/web/endpoints/conversations.py +353 -0
- dtSpark/web/endpoints/main_menu.py +547 -0
- dtSpark/web/endpoints/streaming.py +421 -0
- dtSpark/web/server.py +578 -0
- dtSpark/web/session.py +167 -0
- dtSpark/web/ssl_utils.py +195 -0
- dtSpark/web/static/css/dark-theme.css +427 -0
- dtSpark/web/static/js/actions.js +1101 -0
- dtSpark/web/static/js/chat.js +614 -0
- dtSpark/web/static/js/main.js +496 -0
- dtSpark/web/static/js/sse-client.js +242 -0
- dtSpark/web/templates/actions.html +408 -0
- dtSpark/web/templates/base.html +93 -0
- dtSpark/web/templates/chat.html +814 -0
- dtSpark/web/templates/conversations.html +350 -0
- dtSpark/web/templates/goodbye.html +81 -0
- dtSpark/web/templates/login.html +90 -0
- dtSpark/web/templates/main_menu.html +983 -0
- dtSpark/web/templates/new_conversation.html +191 -0
- dtSpark/web/web_interface.py +137 -0
- dtspark-1.0.4.dist-info/METADATA +187 -0
- dtspark-1.0.4.dist-info/RECORD +96 -0
- dtspark-1.0.4.dist-info/WHEEL +5 -0
- dtspark-1.0.4.dist-info/entry_points.txt +3 -0
- dtspark-1.0.4.dist-info/licenses/LICENSE +21 -0
- dtspark-1.0.4.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Violation logger for Cyber Security audit trail.
|
|
3
|
+
|
|
4
|
+
This module handles database operations for logging prompt inspection violations,
|
|
5
|
+
enabling security monitoring, compliance, and incident response.
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import sqlite3
|
|
11
|
+
import logging
|
|
12
|
+
from datetime import datetime
|
|
13
|
+
from typing import List, Dict, Optional
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class ViolationLogger:
|
|
17
|
+
"""
|
|
18
|
+
Logs prompt inspection violations to database for audit trail.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
def __init__(self, database_connection: sqlite3.Connection, config: Dict):
|
|
22
|
+
"""
|
|
23
|
+
Initialise violation logger.
|
|
24
|
+
|
|
25
|
+
Args:
|
|
26
|
+
database_connection: SQLite database connection
|
|
27
|
+
config: Configuration dictionary
|
|
28
|
+
"""
|
|
29
|
+
self.conn = database_connection
|
|
30
|
+
self.config = config
|
|
31
|
+
self.enabled = config.get('log_violations', True)
|
|
32
|
+
self.alert_threshold = config.get('violation_threshold', 5)
|
|
33
|
+
self.alert_enabled = config.get('alert_on_repeated_violations', True)
|
|
34
|
+
|
|
35
|
+
def log_violation(self, user_guid: str, violation_types: List[str],
|
|
36
|
+
severity: str, prompt_snippet: str, detection_method: str,
|
|
37
|
+
action_taken: str, confidence_score: Optional[float] = None,
|
|
38
|
+
conversation_id: Optional[int] = None):
|
|
39
|
+
"""
|
|
40
|
+
Log a prompt inspection violation to database.
|
|
41
|
+
|
|
42
|
+
Args:
|
|
43
|
+
user_guid: User's unique identifier
|
|
44
|
+
violation_types: List of violation types detected
|
|
45
|
+
severity: Severity level (none, low, medium, high, critical)
|
|
46
|
+
prompt_snippet: First 500 characters of the violating prompt
|
|
47
|
+
detection_method: How violation was detected (pattern, llm, hybrid)
|
|
48
|
+
action_taken: Action taken (blocked, warned, sanitised, logged)
|
|
49
|
+
confidence_score: Optional confidence score (0.0-1.0)
|
|
50
|
+
conversation_id: Optional conversation ID
|
|
51
|
+
"""
|
|
52
|
+
if not self.enabled:
|
|
53
|
+
return
|
|
54
|
+
|
|
55
|
+
try:
|
|
56
|
+
cursor = self.conn.cursor()
|
|
57
|
+
|
|
58
|
+
# Log each violation type separately for better analysis
|
|
59
|
+
for violation_type in violation_types:
|
|
60
|
+
cursor.execute('''
|
|
61
|
+
INSERT INTO prompt_inspection_violations
|
|
62
|
+
(user_guid, conversation_id, violation_type, severity,
|
|
63
|
+
prompt_snippet, detection_method, action_taken,
|
|
64
|
+
confidence_score, timestamp)
|
|
65
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
66
|
+
''', (
|
|
67
|
+
user_guid,
|
|
68
|
+
conversation_id,
|
|
69
|
+
violation_type,
|
|
70
|
+
severity,
|
|
71
|
+
prompt_snippet[:500], # Ensure max 500 chars
|
|
72
|
+
detection_method,
|
|
73
|
+
action_taken,
|
|
74
|
+
confidence_score,
|
|
75
|
+
datetime.now()
|
|
76
|
+
))
|
|
77
|
+
|
|
78
|
+
self.conn.commit()
|
|
79
|
+
|
|
80
|
+
logging.info(f"Logged {len(violation_types)} violation(s) for user {user_guid}: {', '.join(violation_types)}")
|
|
81
|
+
|
|
82
|
+
# Check if alert threshold reached
|
|
83
|
+
if self.alert_enabled:
|
|
84
|
+
self._check_alert_threshold(user_guid)
|
|
85
|
+
|
|
86
|
+
except Exception as e:
|
|
87
|
+
logging.error(f"Failed to log violation: {e}")
|
|
88
|
+
self.conn.rollback()
|
|
89
|
+
|
|
90
|
+
def get_user_violation_count(self, user_guid: str, hours: int = 24) -> int:
|
|
91
|
+
"""
|
|
92
|
+
Get count of violations for a user in the last N hours.
|
|
93
|
+
|
|
94
|
+
Args:
|
|
95
|
+
user_guid: User's unique identifier
|
|
96
|
+
hours: Number of hours to look back (default 24)
|
|
97
|
+
|
|
98
|
+
Returns:
|
|
99
|
+
Count of violations
|
|
100
|
+
"""
|
|
101
|
+
try:
|
|
102
|
+
cursor = self.conn.cursor()
|
|
103
|
+
cursor.execute('''
|
|
104
|
+
SELECT COUNT(*)
|
|
105
|
+
FROM prompt_inspection_violations
|
|
106
|
+
WHERE user_guid = ?
|
|
107
|
+
AND timestamp >= datetime('now', '-' || ? || ' hours')
|
|
108
|
+
''', (user_guid, hours))
|
|
109
|
+
|
|
110
|
+
return cursor.fetchone()[0]
|
|
111
|
+
|
|
112
|
+
except Exception as e:
|
|
113
|
+
logging.error(f"Failed to get user violation count: {e}")
|
|
114
|
+
return 0
|
|
115
|
+
|
|
116
|
+
def get_user_violations(self, user_guid: str, limit: int = 50) -> List[Dict]:
|
|
117
|
+
"""
|
|
118
|
+
Get recent violations for a user.
|
|
119
|
+
|
|
120
|
+
Args:
|
|
121
|
+
user_guid: User's unique identifier
|
|
122
|
+
limit: Maximum number of records to return
|
|
123
|
+
|
|
124
|
+
Returns:
|
|
125
|
+
List of violation records
|
|
126
|
+
"""
|
|
127
|
+
try:
|
|
128
|
+
cursor = self.conn.cursor()
|
|
129
|
+
cursor.execute('''
|
|
130
|
+
SELECT id, conversation_id, violation_type, severity,
|
|
131
|
+
prompt_snippet, detection_method, action_taken,
|
|
132
|
+
confidence_score, timestamp
|
|
133
|
+
FROM prompt_inspection_violations
|
|
134
|
+
WHERE user_guid = ?
|
|
135
|
+
ORDER BY timestamp DESC
|
|
136
|
+
LIMIT ?
|
|
137
|
+
''', (user_guid, limit))
|
|
138
|
+
|
|
139
|
+
rows = cursor.fetchall()
|
|
140
|
+
return [
|
|
141
|
+
{
|
|
142
|
+
'id': row[0],
|
|
143
|
+
'conversation_id': row[1],
|
|
144
|
+
'violation_type': row[2],
|
|
145
|
+
'severity': row[3],
|
|
146
|
+
'prompt_snippet': row[4],
|
|
147
|
+
'detection_method': row[5],
|
|
148
|
+
'action_taken': row[6],
|
|
149
|
+
'confidence_score': row[7],
|
|
150
|
+
'timestamp': row[8]
|
|
151
|
+
}
|
|
152
|
+
for row in rows
|
|
153
|
+
]
|
|
154
|
+
|
|
155
|
+
except Exception as e:
|
|
156
|
+
logging.error(f"Failed to get user violations: {e}")
|
|
157
|
+
return []
|
|
158
|
+
|
|
159
|
+
def get_violation_statistics(self, user_guid: Optional[str] = None,
|
|
160
|
+
days: int = 30) -> Dict:
|
|
161
|
+
"""
|
|
162
|
+
Get violation statistics for reporting and analysis.
|
|
163
|
+
|
|
164
|
+
Args:
|
|
165
|
+
user_guid: Optional user to filter by
|
|
166
|
+
days: Number of days to analyse (default 30)
|
|
167
|
+
|
|
168
|
+
Returns:
|
|
169
|
+
Dictionary with statistics
|
|
170
|
+
"""
|
|
171
|
+
try:
|
|
172
|
+
cursor = self.conn.cursor()
|
|
173
|
+
|
|
174
|
+
# Base query
|
|
175
|
+
base_where = "WHERE timestamp >= datetime('now', '-' || ? || ' days')"
|
|
176
|
+
params = [days]
|
|
177
|
+
|
|
178
|
+
if user_guid:
|
|
179
|
+
base_where += " AND user_guid = ?"
|
|
180
|
+
params.append(user_guid)
|
|
181
|
+
|
|
182
|
+
# Total violations
|
|
183
|
+
cursor.execute(f'''
|
|
184
|
+
SELECT COUNT(*)
|
|
185
|
+
FROM prompt_inspection_violations
|
|
186
|
+
{base_where}
|
|
187
|
+
''', params)
|
|
188
|
+
total = cursor.fetchone()[0]
|
|
189
|
+
|
|
190
|
+
# By severity
|
|
191
|
+
cursor.execute(f'''
|
|
192
|
+
SELECT severity, COUNT(*)
|
|
193
|
+
FROM prompt_inspection_violations
|
|
194
|
+
{base_where}
|
|
195
|
+
GROUP BY severity
|
|
196
|
+
''', params)
|
|
197
|
+
by_severity = {row[0]: row[1] for row in cursor.fetchall()}
|
|
198
|
+
|
|
199
|
+
# By violation type
|
|
200
|
+
cursor.execute(f'''
|
|
201
|
+
SELECT violation_type, COUNT(*)
|
|
202
|
+
FROM prompt_inspection_violations
|
|
203
|
+
{base_where}
|
|
204
|
+
GROUP BY violation_type
|
|
205
|
+
ORDER BY COUNT(*) DESC
|
|
206
|
+
LIMIT 10
|
|
207
|
+
''', params)
|
|
208
|
+
by_type = {row[0]: row[1] for row in cursor.fetchall()}
|
|
209
|
+
|
|
210
|
+
# By action taken
|
|
211
|
+
cursor.execute(f'''
|
|
212
|
+
SELECT action_taken, COUNT(*)
|
|
213
|
+
FROM prompt_inspection_violations
|
|
214
|
+
{base_where}
|
|
215
|
+
GROUP BY action_taken
|
|
216
|
+
''', params)
|
|
217
|
+
by_action = {row[0]: row[1] for row in cursor.fetchall()}
|
|
218
|
+
|
|
219
|
+
# Top users (if not filtered by user)
|
|
220
|
+
top_users = []
|
|
221
|
+
if not user_guid:
|
|
222
|
+
cursor.execute(f'''
|
|
223
|
+
SELECT user_guid, COUNT(*) as count
|
|
224
|
+
FROM prompt_inspection_violations
|
|
225
|
+
{base_where}
|
|
226
|
+
GROUP BY user_guid
|
|
227
|
+
ORDER BY count DESC
|
|
228
|
+
LIMIT 10
|
|
229
|
+
''', params)
|
|
230
|
+
top_users = [{'user_guid': row[0], 'count': row[1]} for row in cursor.fetchall()]
|
|
231
|
+
|
|
232
|
+
return {
|
|
233
|
+
'total': total,
|
|
234
|
+
'by_severity': by_severity,
|
|
235
|
+
'by_type': by_type,
|
|
236
|
+
'by_action': by_action,
|
|
237
|
+
'top_users': top_users,
|
|
238
|
+
'days': days
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
except Exception as e:
|
|
242
|
+
logging.error(f"Failed to get violation statistics: {e}")
|
|
243
|
+
return {
|
|
244
|
+
'total': 0,
|
|
245
|
+
'by_severity': {},
|
|
246
|
+
'by_type': {},
|
|
247
|
+
'by_action': {},
|
|
248
|
+
'top_users': [],
|
|
249
|
+
'days': days
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
def _check_alert_threshold(self, user_guid: str):
|
|
253
|
+
"""
|
|
254
|
+
Check if user has exceeded violation threshold and log alert.
|
|
255
|
+
|
|
256
|
+
Args:
|
|
257
|
+
user_guid: User's unique identifier
|
|
258
|
+
"""
|
|
259
|
+
count = self.get_user_violation_count(user_guid, hours=24)
|
|
260
|
+
|
|
261
|
+
if count >= self.alert_threshold:
|
|
262
|
+
logging.warning(
|
|
263
|
+
f"SECURITY ALERT: User {user_guid} has {count} violations in the last 24 hours "
|
|
264
|
+
f"(threshold: {self.alert_threshold})"
|
|
265
|
+
)
|
|
266
|
+
|
|
267
|
+
def export_violations_to_csv(self, file_path: str, user_guid: Optional[str] = None,
|
|
268
|
+
days: int = 30) -> bool:
|
|
269
|
+
"""
|
|
270
|
+
Export violations to CSV for audit and analysis.
|
|
271
|
+
|
|
272
|
+
Args:
|
|
273
|
+
file_path: Path to output CSV file
|
|
274
|
+
user_guid: Optional user to filter by
|
|
275
|
+
days: Number of days to export (default 30)
|
|
276
|
+
|
|
277
|
+
Returns:
|
|
278
|
+
True if successful
|
|
279
|
+
"""
|
|
280
|
+
try:
|
|
281
|
+
import csv
|
|
282
|
+
|
|
283
|
+
cursor = self.conn.cursor()
|
|
284
|
+
|
|
285
|
+
# Build query
|
|
286
|
+
base_where = "WHERE timestamp >= datetime('now', '-' || ? || ' days')"
|
|
287
|
+
params = [days]
|
|
288
|
+
|
|
289
|
+
if user_guid:
|
|
290
|
+
base_where += " AND user_guid = ?"
|
|
291
|
+
params.append(user_guid)
|
|
292
|
+
|
|
293
|
+
cursor.execute(f'''
|
|
294
|
+
SELECT user_guid, conversation_id, violation_type, severity,
|
|
295
|
+
prompt_snippet, detection_method, action_taken,
|
|
296
|
+
confidence_score, timestamp
|
|
297
|
+
FROM prompt_inspection_violations
|
|
298
|
+
{base_where}
|
|
299
|
+
ORDER BY timestamp DESC
|
|
300
|
+
''', params)
|
|
301
|
+
|
|
302
|
+
rows = cursor.fetchall()
|
|
303
|
+
|
|
304
|
+
# Write to CSV
|
|
305
|
+
with open(file_path, 'w', newline='', encoding='utf-8') as csvfile:
|
|
306
|
+
writer = csv.writer(csvfile)
|
|
307
|
+
|
|
308
|
+
# Header
|
|
309
|
+
writer.writerow([
|
|
310
|
+
'User GUID', 'Conversation ID', 'Violation Type', 'Severity',
|
|
311
|
+
'Prompt Snippet', 'Detection Method', 'Action Taken',
|
|
312
|
+
'Confidence Score', 'Timestamp'
|
|
313
|
+
])
|
|
314
|
+
|
|
315
|
+
# Data rows
|
|
316
|
+
writer.writerows(rows)
|
|
317
|
+
|
|
318
|
+
logging.info(f"Exported {len(rows)} violation records to {file_path}")
|
|
319
|
+
return True
|
|
320
|
+
|
|
321
|
+
except Exception as e:
|
|
322
|
+
logging.error(f"Failed to export violations to CSV: {e}")
|
|
323
|
+
return False
|
|
324
|
+
|
|
325
|
+
def cleanup_old_violations(self, days: int = 90):
|
|
326
|
+
"""
|
|
327
|
+
Clean up old violation records.
|
|
328
|
+
|
|
329
|
+
Args:
|
|
330
|
+
days: Delete records older than this many days (default 90)
|
|
331
|
+
"""
|
|
332
|
+
try:
|
|
333
|
+
cursor = self.conn.cursor()
|
|
334
|
+
cursor.execute('''
|
|
335
|
+
DELETE FROM prompt_inspection_violations
|
|
336
|
+
WHERE timestamp < datetime('now', '-' || ? || ' days')
|
|
337
|
+
''', (days,))
|
|
338
|
+
|
|
339
|
+
deleted = cursor.rowcount
|
|
340
|
+
self.conn.commit()
|
|
341
|
+
|
|
342
|
+
logging.info(f"Cleaned up {deleted} old violation records (older than {days} days)")
|
|
343
|
+
|
|
344
|
+
except Exception as e:
|
|
345
|
+
logging.error(f"Failed to cleanup old violations: {e}")
|
|
346
|
+
self.conn.rollback()
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Scheduler module for autonomous action execution.
|
|
3
|
+
|
|
4
|
+
This module provides:
|
|
5
|
+
- ActionSchedulerManager: APScheduler wrapper for scheduling actions
|
|
6
|
+
- ActionExecutionQueue: Thread-safe sequential execution queue
|
|
7
|
+
- ActionExecutor: LLM invocation and result handling
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from .manager import ActionSchedulerManager
|
|
13
|
+
from .execution_queue import ActionExecutionQueue
|
|
14
|
+
from .executor import ActionExecutor
|
|
15
|
+
|
|
16
|
+
__all__ = [
|
|
17
|
+
'ActionSchedulerManager',
|
|
18
|
+
'ActionExecutionQueue',
|
|
19
|
+
'ActionExecutor'
|
|
20
|
+
]
|