omni-cortex 1.6.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- omni_cortex-1.6.0.data/data/share/omni-cortex/dashboard/backend/.env.example +22 -0
- omni_cortex-1.6.0.data/data/share/omni-cortex/dashboard/backend/backfill_summaries.py +280 -0
- omni_cortex-1.6.0.data/data/share/omni-cortex/dashboard/backend/chat_service.py +315 -0
- omni_cortex-1.6.0.data/data/share/omni-cortex/dashboard/backend/database.py +1093 -0
- omni_cortex-1.6.0.data/data/share/omni-cortex/dashboard/backend/image_service.py +549 -0
- omni_cortex-1.6.0.data/data/share/omni-cortex/dashboard/backend/logging_config.py +122 -0
- omni_cortex-1.6.0.data/data/share/omni-cortex/dashboard/backend/main.py +1124 -0
- omni_cortex-1.6.0.data/data/share/omni-cortex/dashboard/backend/models.py +241 -0
- omni_cortex-1.6.0.data/data/share/omni-cortex/dashboard/backend/project_config.py +170 -0
- omni_cortex-1.6.0.data/data/share/omni-cortex/dashboard/backend/project_scanner.py +164 -0
- omni_cortex-1.6.0.data/data/share/omni-cortex/dashboard/backend/prompt_security.py +111 -0
- omni_cortex-1.6.0.data/data/share/omni-cortex/dashboard/backend/pyproject.toml +23 -0
- omni_cortex-1.6.0.data/data/share/omni-cortex/dashboard/backend/security.py +104 -0
- omni_cortex-1.6.0.data/data/share/omni-cortex/dashboard/backend/uv.lock +1110 -0
- omni_cortex-1.6.0.data/data/share/omni-cortex/dashboard/backend/websocket_manager.py +104 -0
- omni_cortex-1.6.0.data/data/share/omni-cortex/hooks/post_tool_use.py +335 -0
- omni_cortex-1.6.0.data/data/share/omni-cortex/hooks/pre_tool_use.py +333 -0
- omni_cortex-1.6.0.data/data/share/omni-cortex/hooks/stop.py +184 -0
- omni_cortex-1.6.0.data/data/share/omni-cortex/hooks/subagent_stop.py +120 -0
- omni_cortex-1.6.0.dist-info/METADATA +319 -0
- omni_cortex-1.6.0.dist-info/RECORD +24 -0
- omni_cortex-1.6.0.dist-info/WHEEL +4 -0
- omni_cortex-1.6.0.dist-info/entry_points.txt +4 -0
- omni_cortex-1.6.0.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
"""Security utilities for Omni-Cortex Dashboard."""
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import re
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import Optional
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class PathValidator:
|
|
10
|
+
"""Validate and sanitize file paths to prevent traversal attacks."""
|
|
11
|
+
|
|
12
|
+
# Pattern for valid omni-cortex database paths
|
|
13
|
+
VALID_DB_PATTERN = re.compile(r'^.*[/\\]\.omni-cortex[/\\]cortex\.db$')
|
|
14
|
+
GLOBAL_DB_PATTERN = re.compile(r'^.*[/\\]\.omni-cortex[/\\]global\.db$')
|
|
15
|
+
|
|
16
|
+
@staticmethod
|
|
17
|
+
def is_valid_project_db(path: str) -> bool:
|
|
18
|
+
"""Check if path is a valid omni-cortex project database."""
|
|
19
|
+
try:
|
|
20
|
+
resolved = Path(path).resolve()
|
|
21
|
+
path_str = str(resolved)
|
|
22
|
+
|
|
23
|
+
# Must match expected patterns
|
|
24
|
+
if PathValidator.VALID_DB_PATTERN.match(path_str):
|
|
25
|
+
return resolved.exists() and resolved.is_file()
|
|
26
|
+
if PathValidator.GLOBAL_DB_PATTERN.match(path_str):
|
|
27
|
+
return resolved.exists() and resolved.is_file()
|
|
28
|
+
|
|
29
|
+
return False
|
|
30
|
+
except (ValueError, OSError):
|
|
31
|
+
return False
|
|
32
|
+
|
|
33
|
+
@staticmethod
|
|
34
|
+
def validate_project_path(path: str) -> Path:
|
|
35
|
+
"""Validate and return resolved path, or raise ValueError."""
|
|
36
|
+
if not PathValidator.is_valid_project_db(path):
|
|
37
|
+
raise ValueError(f"Invalid project database path: {path}")
|
|
38
|
+
return Path(path).resolve()
|
|
39
|
+
|
|
40
|
+
@staticmethod
|
|
41
|
+
def is_safe_static_path(base_dir: Path, requested_path: str) -> Optional[Path]:
|
|
42
|
+
"""Validate static file path is within base directory.
|
|
43
|
+
|
|
44
|
+
Returns resolved path if safe, None if traversal detected.
|
|
45
|
+
"""
|
|
46
|
+
try:
|
|
47
|
+
# Resolve both paths to absolute
|
|
48
|
+
base_resolved = base_dir.resolve()
|
|
49
|
+
requested = (base_dir / requested_path).resolve()
|
|
50
|
+
|
|
51
|
+
# Check if requested path is under base directory
|
|
52
|
+
if base_resolved in requested.parents or requested == base_resolved:
|
|
53
|
+
if requested.exists() and requested.is_file():
|
|
54
|
+
return requested
|
|
55
|
+
|
|
56
|
+
return None
|
|
57
|
+
except (ValueError, OSError):
|
|
58
|
+
return None
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def sanitize_log_input(value: str, max_length: int = 200) -> str:
|
|
62
|
+
"""Sanitize user input for safe logging.
|
|
63
|
+
|
|
64
|
+
Prevents log injection by:
|
|
65
|
+
- Escaping newlines
|
|
66
|
+
- Limiting length
|
|
67
|
+
- Removing control characters
|
|
68
|
+
"""
|
|
69
|
+
if not isinstance(value, str):
|
|
70
|
+
value = str(value)
|
|
71
|
+
|
|
72
|
+
# Remove control characters except spaces
|
|
73
|
+
sanitized = ''.join(c if c.isprintable() or c == ' ' else '?' for c in value)
|
|
74
|
+
|
|
75
|
+
# Escape potential log injection patterns
|
|
76
|
+
sanitized = sanitized.replace('\n', '\\n').replace('\r', '\\r')
|
|
77
|
+
|
|
78
|
+
# Truncate
|
|
79
|
+
if len(sanitized) > max_length:
|
|
80
|
+
sanitized = sanitized[:max_length] + '...'
|
|
81
|
+
|
|
82
|
+
return sanitized
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
# Environment-based configuration
|
|
86
|
+
IS_PRODUCTION = os.getenv("ENVIRONMENT", "development") == "production"
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def get_cors_config():
|
|
90
|
+
"""Get CORS configuration based on environment."""
|
|
91
|
+
if IS_PRODUCTION:
|
|
92
|
+
origins = os.getenv("CORS_ORIGINS", "").split(",")
|
|
93
|
+
origins = [o.strip() for o in origins if o.strip()]
|
|
94
|
+
return {
|
|
95
|
+
"allow_origins": origins,
|
|
96
|
+
"allow_methods": ["GET", "POST", "PUT", "DELETE"],
|
|
97
|
+
"allow_headers": ["Content-Type", "Authorization", "X-API-Key"],
|
|
98
|
+
}
|
|
99
|
+
else:
|
|
100
|
+
return {
|
|
101
|
+
"allow_origins": ["http://localhost:5173", "http://127.0.0.1:5173"],
|
|
102
|
+
"allow_methods": ["*"],
|
|
103
|
+
"allow_headers": ["*"],
|
|
104
|
+
}
|