memorisdk 1.0.2__py3-none-any.whl → 2.0.1__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.
Potentially problematic release.
This version of memorisdk might be problematic. Click here for more details.
- memori/__init__.py +24 -8
- memori/agents/conscious_agent.py +252 -414
- memori/agents/memory_agent.py +487 -224
- memori/agents/retrieval_agent.py +491 -68
- memori/config/memory_manager.py +323 -0
- memori/core/conversation.py +393 -0
- memori/core/database.py +386 -371
- memori/core/memory.py +1683 -532
- memori/core/providers.py +217 -0
- memori/database/adapters/__init__.py +10 -0
- memori/database/adapters/mysql_adapter.py +331 -0
- memori/database/adapters/postgresql_adapter.py +291 -0
- memori/database/adapters/sqlite_adapter.py +229 -0
- memori/database/auto_creator.py +320 -0
- memori/database/connection_utils.py +207 -0
- memori/database/connectors/base_connector.py +283 -0
- memori/database/connectors/mysql_connector.py +240 -18
- memori/database/connectors/postgres_connector.py +277 -4
- memori/database/connectors/sqlite_connector.py +178 -3
- memori/database/models.py +400 -0
- memori/database/queries/base_queries.py +1 -1
- memori/database/queries/memory_queries.py +91 -2
- memori/database/query_translator.py +222 -0
- memori/database/schema_generators/__init__.py +7 -0
- memori/database/schema_generators/mysql_schema_generator.py +215 -0
- memori/database/search/__init__.py +8 -0
- memori/database/search/mysql_search_adapter.py +255 -0
- memori/database/search/sqlite_search_adapter.py +180 -0
- memori/database/search_service.py +700 -0
- memori/database/sqlalchemy_manager.py +888 -0
- memori/integrations/__init__.py +36 -11
- memori/integrations/litellm_integration.py +340 -6
- memori/integrations/openai_integration.py +506 -240
- memori/tools/memory_tool.py +94 -4
- memori/utils/input_validator.py +395 -0
- memori/utils/pydantic_models.py +138 -36
- memori/utils/query_builder.py +530 -0
- memori/utils/security_audit.py +594 -0
- memori/utils/security_integration.py +339 -0
- memori/utils/transaction_manager.py +547 -0
- {memorisdk-1.0.2.dist-info → memorisdk-2.0.1.dist-info}/METADATA +56 -23
- memorisdk-2.0.1.dist-info/RECORD +66 -0
- memori/scripts/llm_text.py +0 -50
- memorisdk-1.0.2.dist-info/RECORD +0 -44
- memorisdk-1.0.2.dist-info/entry_points.txt +0 -2
- {memorisdk-1.0.2.dist-info → memorisdk-2.0.1.dist-info}/WHEEL +0 -0
- {memorisdk-1.0.2.dist-info → memorisdk-2.0.1.dist-info}/licenses/LICENSE +0 -0
- {memorisdk-1.0.2.dist-info → memorisdk-2.0.1.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,339 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Security Integration Module for Memori
|
|
3
|
+
Integrates all security components into a unified system
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from typing import Any, Dict, List, Optional
|
|
7
|
+
|
|
8
|
+
from loguru import logger
|
|
9
|
+
|
|
10
|
+
from .exceptions import DatabaseError, SecurityError, ValidationError
|
|
11
|
+
from .input_validator import DatabaseInputValidator, InputValidator
|
|
12
|
+
from .query_builder import DatabaseDialect, DatabaseQueryExecutor, QueryBuilder
|
|
13
|
+
from .security_audit import get_security_auditor
|
|
14
|
+
from .transaction_manager import TransactionManager
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class SecureMemoriDatabase:
|
|
18
|
+
"""Secure wrapper for Memori database operations"""
|
|
19
|
+
|
|
20
|
+
def __init__(self, connector, dialect: DatabaseDialect):
|
|
21
|
+
self.connector = connector
|
|
22
|
+
self.dialect = dialect
|
|
23
|
+
self.query_builder = QueryBuilder(dialect)
|
|
24
|
+
self.query_executor = DatabaseQueryExecutor(connector, dialect)
|
|
25
|
+
self.transaction_manager = TransactionManager(connector)
|
|
26
|
+
self.security_auditor = get_security_auditor()
|
|
27
|
+
|
|
28
|
+
def secure_search(
|
|
29
|
+
self,
|
|
30
|
+
query_text: str,
|
|
31
|
+
namespace: str = "default",
|
|
32
|
+
category_filter: Optional[List[str]] = None,
|
|
33
|
+
limit: int = 10,
|
|
34
|
+
use_fts: bool = True,
|
|
35
|
+
) -> List[Dict[str, Any]]:
|
|
36
|
+
"""Execute secure search with comprehensive validation"""
|
|
37
|
+
try:
|
|
38
|
+
# Phase 1: Input validation
|
|
39
|
+
validated_params = DatabaseInputValidator.validate_search_params(
|
|
40
|
+
query_text, namespace, category_filter, limit
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
# Phase 2: Build secure query
|
|
44
|
+
if use_fts:
|
|
45
|
+
try:
|
|
46
|
+
sql_query, params = self.query_builder.build_fts_query(
|
|
47
|
+
validated_params["query"],
|
|
48
|
+
validated_params["namespace"],
|
|
49
|
+
validated_params["category_filter"],
|
|
50
|
+
validated_params["limit"],
|
|
51
|
+
)
|
|
52
|
+
except Exception as e:
|
|
53
|
+
logger.debug(
|
|
54
|
+
f"FTS query building failed, falling back to LIKE: {e}"
|
|
55
|
+
)
|
|
56
|
+
use_fts = False
|
|
57
|
+
|
|
58
|
+
if not use_fts:
|
|
59
|
+
sql_query, params = self.query_builder.build_search_query(
|
|
60
|
+
["short_term_memory", "long_term_memory"],
|
|
61
|
+
["searchable_content", "summary"],
|
|
62
|
+
validated_params["query"],
|
|
63
|
+
validated_params["namespace"],
|
|
64
|
+
validated_params["category_filter"],
|
|
65
|
+
validated_params["limit"],
|
|
66
|
+
use_fts=False,
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
# Phase 3: Security audit
|
|
70
|
+
is_safe, security_findings = self.security_auditor.validate_query_safety(
|
|
71
|
+
sql_query, params, "secure_search"
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
if not is_safe:
|
|
75
|
+
critical_findings = [
|
|
76
|
+
f
|
|
77
|
+
for f in security_findings
|
|
78
|
+
if f.severity.value in ["critical", "high"]
|
|
79
|
+
]
|
|
80
|
+
logger.error(f"Search query failed security audit: {critical_findings}")
|
|
81
|
+
raise SecurityError("Search query blocked due to security concerns")
|
|
82
|
+
|
|
83
|
+
# Phase 4: Execute with proper error handling
|
|
84
|
+
results = self.connector.execute_query(sql_query, params)
|
|
85
|
+
|
|
86
|
+
# Phase 5: Log successful operation
|
|
87
|
+
logger.debug(f"Secure search completed: {len(results)} results")
|
|
88
|
+
|
|
89
|
+
return results
|
|
90
|
+
|
|
91
|
+
except (ValidationError, SecurityError) as e:
|
|
92
|
+
logger.error(f"Secure search blocked: {e}")
|
|
93
|
+
return []
|
|
94
|
+
except Exception as e:
|
|
95
|
+
logger.error(f"Secure search failed: {e}")
|
|
96
|
+
return []
|
|
97
|
+
|
|
98
|
+
def secure_insert(
|
|
99
|
+
self, table: str, data: Dict[str, Any], on_conflict: str = "REPLACE"
|
|
100
|
+
) -> Optional[str]:
|
|
101
|
+
"""Execute secure insert with comprehensive validation"""
|
|
102
|
+
try:
|
|
103
|
+
# Phase 1: Input validation
|
|
104
|
+
validated_data = DatabaseInputValidator.validate_insert_params(table, data)
|
|
105
|
+
|
|
106
|
+
# Phase 2: Build secure query
|
|
107
|
+
sql_query, params = self.query_builder.build_insert_query(
|
|
108
|
+
table, validated_data, on_conflict
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
# Phase 3: Security audit
|
|
112
|
+
is_safe, security_findings = self.security_auditor.validate_query_safety(
|
|
113
|
+
sql_query, params, f"secure_insert_{table}"
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
if not is_safe:
|
|
117
|
+
critical_findings = [
|
|
118
|
+
f
|
|
119
|
+
for f in security_findings
|
|
120
|
+
if f.severity.value in ["critical", "high"]
|
|
121
|
+
]
|
|
122
|
+
logger.error(f"Insert query failed security audit: {critical_findings}")
|
|
123
|
+
raise SecurityError("Insert query blocked due to security concerns")
|
|
124
|
+
|
|
125
|
+
# Phase 4: Execute with transaction
|
|
126
|
+
with self.transaction_manager.transaction() as tx:
|
|
127
|
+
result = tx.execute(sql_query, params)
|
|
128
|
+
return str(result[0].get("affected_rows", 0)) if result else None
|
|
129
|
+
|
|
130
|
+
except (ValidationError, SecurityError) as e:
|
|
131
|
+
logger.error(f"Secure insert blocked: {e}")
|
|
132
|
+
raise DatabaseError(f"Secure insert failed: {e}")
|
|
133
|
+
except Exception as e:
|
|
134
|
+
logger.error(f"Secure insert failed: {e}")
|
|
135
|
+
raise DatabaseError(f"Secure insert failed: {e}")
|
|
136
|
+
|
|
137
|
+
def secure_update(
|
|
138
|
+
self, table: str, data: Dict[str, Any], where_conditions: Dict[str, Any]
|
|
139
|
+
) -> int:
|
|
140
|
+
"""Execute secure update with comprehensive validation"""
|
|
141
|
+
try:
|
|
142
|
+
# Phase 1: Input validation
|
|
143
|
+
validated_data = {
|
|
144
|
+
k: (
|
|
145
|
+
InputValidator.validate_text_content(str(v))
|
|
146
|
+
if isinstance(v, str)
|
|
147
|
+
else v
|
|
148
|
+
)
|
|
149
|
+
for k, v in data.items()
|
|
150
|
+
}
|
|
151
|
+
validated_where = {
|
|
152
|
+
k: (
|
|
153
|
+
InputValidator.validate_text_content(str(v))
|
|
154
|
+
if isinstance(v, str)
|
|
155
|
+
else v
|
|
156
|
+
)
|
|
157
|
+
for k, v in where_conditions.items()
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
# Phase 2: Build secure query
|
|
161
|
+
sql_query, params = self.query_builder.build_update_query(
|
|
162
|
+
table, validated_data, validated_where
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
# Phase 3: Security audit
|
|
166
|
+
is_safe, security_findings = self.security_auditor.validate_query_safety(
|
|
167
|
+
sql_query, params, f"secure_update_{table}"
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
if not is_safe:
|
|
171
|
+
critical_findings = [
|
|
172
|
+
f
|
|
173
|
+
for f in security_findings
|
|
174
|
+
if f.severity.value in ["critical", "high"]
|
|
175
|
+
]
|
|
176
|
+
logger.error(f"Update query failed security audit: {critical_findings}")
|
|
177
|
+
raise SecurityError("Update query blocked due to security concerns")
|
|
178
|
+
|
|
179
|
+
# Phase 4: Execute with transaction
|
|
180
|
+
with self.transaction_manager.transaction() as tx:
|
|
181
|
+
result = tx.execute(sql_query, params)
|
|
182
|
+
return result[0].get("affected_rows", 0) if result else 0
|
|
183
|
+
|
|
184
|
+
except (ValidationError, SecurityError) as e:
|
|
185
|
+
logger.error(f"Secure update blocked: {e}")
|
|
186
|
+
raise DatabaseError(f"Secure update failed: {e}")
|
|
187
|
+
except Exception as e:
|
|
188
|
+
logger.error(f"Secure update failed: {e}")
|
|
189
|
+
raise DatabaseError(f"Secure update failed: {e}")
|
|
190
|
+
|
|
191
|
+
def secure_delete(self, table: str, where_conditions: Dict[str, Any]) -> int:
|
|
192
|
+
"""Execute secure delete with comprehensive validation"""
|
|
193
|
+
try:
|
|
194
|
+
# Phase 1: Input validation
|
|
195
|
+
if not where_conditions:
|
|
196
|
+
raise ValidationError("DELETE operations must include WHERE conditions")
|
|
197
|
+
|
|
198
|
+
validated_where = {
|
|
199
|
+
k: (
|
|
200
|
+
InputValidator.validate_text_content(str(v))
|
|
201
|
+
if isinstance(v, str)
|
|
202
|
+
else v
|
|
203
|
+
)
|
|
204
|
+
for k, v in where_conditions.items()
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
# Phase 2: Build secure query
|
|
208
|
+
sql_query, params = self.query_builder.build_delete_query(
|
|
209
|
+
table, validated_where
|
|
210
|
+
)
|
|
211
|
+
|
|
212
|
+
# Phase 3: Security audit
|
|
213
|
+
is_safe, security_findings = self.security_auditor.validate_query_safety(
|
|
214
|
+
sql_query, params, f"secure_delete_{table}"
|
|
215
|
+
)
|
|
216
|
+
|
|
217
|
+
if not is_safe:
|
|
218
|
+
critical_findings = [
|
|
219
|
+
f
|
|
220
|
+
for f in security_findings
|
|
221
|
+
if f.severity.value in ["critical", "high"]
|
|
222
|
+
]
|
|
223
|
+
logger.error(f"Delete query failed security audit: {critical_findings}")
|
|
224
|
+
raise SecurityError("Delete query blocked due to security concerns")
|
|
225
|
+
|
|
226
|
+
# Phase 4: Execute with transaction
|
|
227
|
+
with self.transaction_manager.transaction() as tx:
|
|
228
|
+
result = tx.execute(sql_query, params)
|
|
229
|
+
return result[0].get("affected_rows", 0) if result else 0
|
|
230
|
+
|
|
231
|
+
except (ValidationError, SecurityError) as e:
|
|
232
|
+
logger.error(f"Secure delete blocked: {e}")
|
|
233
|
+
raise DatabaseError(f"Secure delete failed: {e}")
|
|
234
|
+
except Exception as e:
|
|
235
|
+
logger.error(f"Secure delete failed: {e}")
|
|
236
|
+
raise DatabaseError(f"Secure delete failed: {e}")
|
|
237
|
+
|
|
238
|
+
def get_security_report(self) -> Dict[str, Any]:
|
|
239
|
+
"""Get comprehensive security report"""
|
|
240
|
+
audit_report = self.security_auditor.generate_audit_report()
|
|
241
|
+
|
|
242
|
+
return {
|
|
243
|
+
"total_queries_audited": audit_report.total_queries_audited,
|
|
244
|
+
"security_findings": {
|
|
245
|
+
"critical": audit_report.critical_count,
|
|
246
|
+
"high": audit_report.high_count,
|
|
247
|
+
"medium": audit_report.medium_count,
|
|
248
|
+
"low": audit_report.low_count,
|
|
249
|
+
},
|
|
250
|
+
"overall_risk_score": audit_report.overall_risk_score,
|
|
251
|
+
"risk_level": self._get_risk_level(audit_report.overall_risk_score),
|
|
252
|
+
"audit_timestamp": audit_report.audit_timestamp,
|
|
253
|
+
"database_type": self.dialect.value,
|
|
254
|
+
"security_features_enabled": [
|
|
255
|
+
"input_validation",
|
|
256
|
+
"parameterized_queries",
|
|
257
|
+
"transaction_management",
|
|
258
|
+
"security_audit",
|
|
259
|
+
"multi_database_compatibility",
|
|
260
|
+
],
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
def _get_risk_level(self, risk_score: float) -> str:
|
|
264
|
+
"""Convert risk score to risk level"""
|
|
265
|
+
if risk_score >= 75:
|
|
266
|
+
return "CRITICAL"
|
|
267
|
+
elif risk_score >= 50:
|
|
268
|
+
return "HIGH"
|
|
269
|
+
elif risk_score >= 25:
|
|
270
|
+
return "MEDIUM"
|
|
271
|
+
elif risk_score > 0:
|
|
272
|
+
return "LOW"
|
|
273
|
+
else:
|
|
274
|
+
return "MINIMAL"
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
def create_secure_database(connector, dialect: DatabaseDialect) -> SecureMemoriDatabase:
|
|
278
|
+
"""Factory function to create a secure database instance"""
|
|
279
|
+
return SecureMemoriDatabase(connector, dialect)
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
def validate_memori_security_config() -> Dict[str, Any]:
|
|
283
|
+
"""Validate that all security components are properly configured"""
|
|
284
|
+
validation_results = {
|
|
285
|
+
"input_validator": False,
|
|
286
|
+
"query_builder": False,
|
|
287
|
+
"transaction_manager": False,
|
|
288
|
+
"security_auditor": False,
|
|
289
|
+
"database_adapters": False,
|
|
290
|
+
"overall_status": False,
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
try:
|
|
294
|
+
# Test input validator
|
|
295
|
+
InputValidator.validate_and_sanitize_query("test query")
|
|
296
|
+
validation_results["input_validator"] = True
|
|
297
|
+
|
|
298
|
+
# Test query builder
|
|
299
|
+
QueryBuilder(DatabaseDialect.SQLITE)
|
|
300
|
+
validation_results["query_builder"] = True
|
|
301
|
+
|
|
302
|
+
# Test security auditor
|
|
303
|
+
auditor = get_security_auditor()
|
|
304
|
+
auditor.audit_query("SELECT * FROM test", None, "validation")
|
|
305
|
+
validation_results["security_auditor"] = True
|
|
306
|
+
|
|
307
|
+
# Check database adapters
|
|
308
|
+
try:
|
|
309
|
+
from ..database.adapters import (
|
|
310
|
+
MySQLSearchAdapter, # noqa: F401
|
|
311
|
+
PostgreSQLSearchAdapter, # noqa: F401
|
|
312
|
+
SQLiteSearchAdapter, # noqa: F401
|
|
313
|
+
)
|
|
314
|
+
|
|
315
|
+
validation_results["database_adapters"] = True
|
|
316
|
+
except ImportError as e:
|
|
317
|
+
logger.warning(f"Database adapter validation failed: {e}")
|
|
318
|
+
|
|
319
|
+
# Test transaction manager (requires actual connector)
|
|
320
|
+
validation_results["transaction_manager"] = True # Assume OK if no errors above
|
|
321
|
+
|
|
322
|
+
# Overall status
|
|
323
|
+
validation_results["overall_status"] = all(
|
|
324
|
+
[
|
|
325
|
+
validation_results["input_validator"],
|
|
326
|
+
validation_results["query_builder"],
|
|
327
|
+
validation_results["security_auditor"],
|
|
328
|
+
validation_results["database_adapters"],
|
|
329
|
+
validation_results["transaction_manager"],
|
|
330
|
+
]
|
|
331
|
+
)
|
|
332
|
+
|
|
333
|
+
logger.info(f"Security configuration validation: {validation_results}")
|
|
334
|
+
|
|
335
|
+
except Exception as e:
|
|
336
|
+
logger.error(f"Security configuration validation failed: {e}")
|
|
337
|
+
validation_results["error"] = str(e)
|
|
338
|
+
|
|
339
|
+
return validation_results
|