@orionscanner/cli 0.1.0 → 0.5.1
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.
- package/README.md +80 -190
- package/bin/orion.js +30 -29
- package/dist/orion.exe +0 -0
- package/package.json +46 -48
- package/docs/API_REFERENCE.md +0 -211
- package/docs/ARCHITECTURE.md +0 -183
- package/docs/CHANGELOG.md +0 -112
- package/docs/CONTRIBUTING.md +0 -157
- package/docs/ENGINE_CATALOG.md +0 -87
- package/docs/GETTING_STARTED.md +0 -226
- package/pyproject.toml +0 -16
- package/src/orion/__init__.py +0 -0
- package/src/orion/__pycache__/__init__.cpython-313.pyc +0 -0
- package/src/orion/engine/__init__.py +0 -17
- package/src/orion/engine/__pycache__/__init__.cpython-313.pyc +0 -0
- package/src/orion/engine/__pycache__/config.cpython-313.pyc +0 -0
- package/src/orion/engine/__pycache__/core.cpython-313.pyc +0 -0
- package/src/orion/engine/__pycache__/ir.cpython-313.pyc +0 -0
- package/src/orion/engine/__pycache__/languages.cpython-313.pyc +0 -0
- package/src/orion/engine/__pycache__/registry.cpython-313.pyc +0 -0
- package/src/orion/engine/__pycache__/results.cpython-313.pyc +0 -0
- package/src/orion/engine/__pycache__/runner.cpython-313.pyc +0 -0
- package/src/orion/engine/api_security/__pycache__/engine.cpython-313.pyc +0 -0
- package/src/orion/engine/api_security/engine.py +0 -125
- package/src/orion/engine/architecture/__pycache__/engine.cpython-313.pyc +0 -0
- package/src/orion/engine/architecture/engine.py +0 -463
- package/src/orion/engine/authorization/__pycache__/engine.cpython-313.pyc +0 -0
- package/src/orion/engine/authorization/engine.py +0 -337
- package/src/orion/engine/callgraph/__pycache__/engine.cpython-313.pyc +0 -0
- package/src/orion/engine/callgraph/engine.py +0 -236
- package/src/orion/engine/cfg/__pycache__/engine.cpython-313.pyc +0 -0
- package/src/orion/engine/cfg/engine.py +0 -509
- package/src/orion/engine/chaos/__pycache__/engine.cpython-313.pyc +0 -0
- package/src/orion/engine/chaos/engine.py +0 -268
- package/src/orion/engine/chaos_config/__pycache__/engine.cpython-313.pyc +0 -0
- package/src/orion/engine/chaos_config/engine.py +0 -322
- package/src/orion/engine/complexity/__pycache__/engine.cpython-313.pyc +0 -0
- package/src/orion/engine/complexity/engine.py +0 -144
- package/src/orion/engine/compliance/__pycache__/engine.cpython-313.pyc +0 -0
- package/src/orion/engine/compliance/engine.py +0 -325
- package/src/orion/engine/config.py +0 -41
- package/src/orion/engine/config_engine/__pycache__/engine.cpython-313.pyc +0 -0
- package/src/orion/engine/config_engine/engine.py +0 -364
- package/src/orion/engine/config_validation/__pycache__/engine.cpython-313.pyc +0 -0
- package/src/orion/engine/config_validation/engine.py +0 -313
- package/src/orion/engine/container/__pycache__/engine.cpython-313.pyc +0 -0
- package/src/orion/engine/container/engine.py +0 -546
- package/src/orion/engine/contract_probe/__pycache__/engine.cpython-313.pyc +0 -0
- package/src/orion/engine/contract_probe/engine.py +0 -316
- package/src/orion/engine/core.py +0 -75
- package/src/orion/engine/crypto_guard/__pycache__/engine.cpython-313.pyc +0 -0
- package/src/orion/engine/crypto_guard/engine.py +0 -134
- package/src/orion/engine/data_residency/__pycache__/engine.cpython-313.pyc +0 -0
- package/src/orion/engine/data_residency/engine.py +0 -238
- package/src/orion/engine/dataflow/__pycache__/engine.cpython-313.pyc +0 -0
- package/src/orion/engine/dataflow/engine.py +0 -398
- package/src/orion/engine/dead_import/__pycache__/engine.cpython-313.pyc +0 -0
- package/src/orion/engine/dead_import/engine.py +0 -293
- package/src/orion/engine/deps/__pycache__/engine.cpython-313.pyc +0 -0
- package/src/orion/engine/deps/engine.py +0 -244
- package/src/orion/engine/dispatcher.py +0 -350
- package/src/orion/engine/docs/AUDIT_PROMPT.md +0 -1248
- package/src/orion/engine/duplication/__pycache__/engine.cpython-313.pyc +0 -0
- package/src/orion/engine/duplication/engine.py +0 -120
- package/src/orion/engine/error_handling/__pycache__/engine.cpython-313.pyc +0 -0
- package/src/orion/engine/error_handling/engine.py +0 -256
- package/src/orion/engine/fp_learn/__pycache__/engine.cpython-313.pyc +0 -0
- package/src/orion/engine/fp_learn/engine.py +0 -248
- package/src/orion/engine/hunter/__pycache__/engine.cpython-313.pyc +0 -0
- package/src/orion/engine/hunter/engine.py +0 -324
- package/src/orion/engine/iac_security/__pycache__/engine.cpython-313.pyc +0 -0
- package/src/orion/engine/iac_security/engine.py +0 -218
- package/src/orion/engine/ir.py +0 -22
- package/src/orion/engine/languages.py +0 -454
- package/src/orion/engine/license/__pycache__/engine.cpython-313.pyc +0 -0
- package/src/orion/engine/license/engine.py +0 -172
- package/src/orion/engine/lint/__pycache__/engine.cpython-313.pyc +0 -0
- package/src/orion/engine/lint/engine.py +0 -558
- package/src/orion/engine/llm_security/__pycache__/engine.cpython-313.pyc +0 -0
- package/src/orion/engine/llm_security/engine.py +0 -125
- package/src/orion/engine/logging_c/__pycache__/engine.cpython-313.pyc +0 -0
- package/src/orion/engine/logging_c/engine.py +0 -164
- package/src/orion/engine/noise/__pycache__/engine.cpython-313.pyc +0 -0
- package/src/orion/engine/noise/engine.py +0 -140
- package/src/orion/engine/orphan/__pycache__/engine.cpython-313.pyc +0 -0
- package/src/orion/engine/orphan/engine.py +0 -244
- package/src/orion/engine/perf_guard/__pycache__/engine.cpython-313.pyc +0 -0
- package/src/orion/engine/perf_guard/engine.py +0 -345
- package/src/orion/engine/prompt_security/__pycache__/engine.cpython-313.pyc +0 -0
- package/src/orion/engine/prompt_security/detectors/__init__.py +0 -4
- package/src/orion/engine/prompt_security/engine.py +0 -170
- package/src/orion/engine/provenance/__pycache__/engine.cpython-313.pyc +0 -0
- package/src/orion/engine/provenance/engine.py +0 -242
- package/src/orion/engine/registry.py +0 -55
- package/src/orion/engine/regression/__pycache__/engine.cpython-313.pyc +0 -0
- package/src/orion/engine/regression/engine.py +0 -213
- package/src/orion/engine/results.py +0 -21
- package/src/orion/engine/runner.py +0 -1310
- package/src/orion/engine/sandbox_escape/__pycache__/engine.cpython-313.pyc +0 -0
- package/src/orion/engine/sandbox_escape/engine.py +0 -284
- package/src/orion/engine/sast/__pycache__/engine.cpython-313.pyc +0 -0
- package/src/orion/engine/sast/engine.py +0 -217
- package/src/orion/engine/sast/patterns/__init__.py +0 -513
- package/src/orion/engine/sast/patterns/__pycache__/__init__.cpython-313.pyc +0 -0
- package/src/orion/engine/secrets/__pycache__/engine.cpython-313.pyc +0 -0
- package/src/orion/engine/secrets/engine.py +0 -77
- package/src/orion/engine/secrets/patterns/__init__.py +0 -74
- package/src/orion/engine/secrets/patterns/__pycache__/__init__.cpython-313.pyc +0 -0
- package/src/orion/engine/sensitive_data/__pycache__/engine.cpython-313.pyc +0 -0
- package/src/orion/engine/sensitive_data/engine.py +0 -143
- package/src/orion/engine/state/__pycache__/engine.cpython-313.pyc +0 -0
- package/src/orion/engine/state/engine.py +0 -218
- package/src/orion/engine/supply_chain_sbom/__pycache__/engine.cpython-313.pyc +0 -0
- package/src/orion/engine/supply_chain_sbom/engine.py +0 -290
- package/src/orion/engine/symbol/__pycache__/engine.cpython-313.pyc +0 -0
- package/src/orion/engine/symbol/engine.py +0 -463
- package/src/orion/engine/taint/__pycache__/engine.cpython-313.pyc +0 -0
- package/src/orion/engine/taint/engine.py +0 -464
- package/src/orion/engine/test_coverage/__pycache__/engine.cpython-313.pyc +0 -0
- package/src/orion/engine/test_coverage/engine.py +0 -445
- package/src/orion/engine/threat_model/__pycache__/engine.cpython-313.pyc +0 -0
- package/src/orion/engine/threat_model/engine.py +0 -126
- package/src/orion/engine/wiring_trace/__pycache__/engine.cpython-313.pyc +0 -0
- package/src/orion/engine/wiring_trace/engine.py +0 -200
- package/src/orion_engine.egg-info/PKG-INFO +0 -7
- package/src/orion_engine.egg-info/SOURCES.txt +0 -65
- package/src/orion_engine.egg-info/dependency_links.txt +0 -1
- package/src/orion_engine.egg-info/entry_points.txt +0 -2
- package/src/orion_engine.egg-info/top_level.txt +0 -1
|
@@ -1,144 +0,0 @@
|
|
|
1
|
-
"""Cyclomatic complexity engine - analyze function/method complexity."""
|
|
2
|
-
import ast
|
|
3
|
-
from orion.engine.config import EngineConfig
|
|
4
|
-
from orion.engine.ir import OrionIR
|
|
5
|
-
from orion.engine.results import EngineResult, Finding
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
class Engine:
|
|
9
|
-
name = "complexity"
|
|
10
|
-
version = "1.0.0"
|
|
11
|
-
|
|
12
|
-
async def check_availability(self) -> bool:
|
|
13
|
-
return True
|
|
14
|
-
|
|
15
|
-
def resource_limits(self):
|
|
16
|
-
from orion.engine.config import ResourceLimits
|
|
17
|
-
return ResourceLimits(max_cpu_seconds=30, max_memory_mb=128)
|
|
18
|
-
|
|
19
|
-
async def run(self, ir: OrionIR, config: EngineConfig) -> EngineResult:
|
|
20
|
-
try:
|
|
21
|
-
text = ir.content.decode("utf-8", errors="replace")
|
|
22
|
-
except Exception:
|
|
23
|
-
text = str(ir.content)
|
|
24
|
-
|
|
25
|
-
path = ir.metadata.get("path", "unknown")
|
|
26
|
-
findings = []
|
|
27
|
-
metrics = {"functions": []}
|
|
28
|
-
|
|
29
|
-
if not path.endswith(".py"):
|
|
30
|
-
return EngineResult(engine=self.name, findings=findings, metrics=metrics, ok=True)
|
|
31
|
-
|
|
32
|
-
try:
|
|
33
|
-
tree = ast.parse(text)
|
|
34
|
-
except SyntaxError as e:
|
|
35
|
-
return EngineResult(engine=self.name, findings=findings, metrics=metrics, ok=True, errors=[str(e)])
|
|
36
|
-
|
|
37
|
-
lines = text.splitlines()
|
|
38
|
-
|
|
39
|
-
for node in ast.walk(tree):
|
|
40
|
-
if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)):
|
|
41
|
-
cc = self._calculate_cyclomatic_complexity(node)
|
|
42
|
-
cognitive = self._calculate_cognitive_complexity(node)
|
|
43
|
-
func_metrics = {
|
|
44
|
-
"name": node.name,
|
|
45
|
-
"line": node.lineno,
|
|
46
|
-
"cyclomatic_complexity": cc,
|
|
47
|
-
"cognitive_complexity": cognitive,
|
|
48
|
-
}
|
|
49
|
-
metrics["functions"].append(func_metrics)
|
|
50
|
-
|
|
51
|
-
if cc > 20:
|
|
52
|
-
severity = "critical" if cc > 50 else "high"
|
|
53
|
-
findings.append(Finding(
|
|
54
|
-
engine=self.name,
|
|
55
|
-
severity=severity,
|
|
56
|
-
title=f"High cyclomatic complexity: {node.name} (CC={cc})",
|
|
57
|
-
description=f"Function '{node.name}' has cyclomatic complexity of {cc} (cognitive: {cognitive}) - consider refactoring",
|
|
58
|
-
location=f"{path}:{node.lineno}",
|
|
59
|
-
metadata={
|
|
60
|
-
"confidence": 1.0,
|
|
61
|
-
"snippet": self._get_snippet(lines, node.lineno),
|
|
62
|
-
"function": node.name,
|
|
63
|
-
"cyclomatic_complexity": cc,
|
|
64
|
-
"cognitive_complexity": cognitive,
|
|
65
|
-
"threshold": "critical" if cc > 50 else "high",
|
|
66
|
-
"cwe": "CWE-1121",
|
|
67
|
-
"cvss": 4.0,
|
|
68
|
-
},
|
|
69
|
-
))
|
|
70
|
-
elif cc > 10:
|
|
71
|
-
findings.append(Finding(
|
|
72
|
-
engine=self.name,
|
|
73
|
-
severity="medium",
|
|
74
|
-
title=f"Elevated cyclomatic complexity: {node.name} (CC={cc})",
|
|
75
|
-
description=f"Function '{node.name}' has cyclomatic complexity of {cc} - monitor for maintainability",
|
|
76
|
-
location=f"{path}:{node.lineno}",
|
|
77
|
-
metadata={
|
|
78
|
-
"confidence": 1.0,
|
|
79
|
-
"snippet": self._get_snippet(lines, node.lineno),
|
|
80
|
-
"function": node.name,
|
|
81
|
-
"cyclomatic_complexity": cc,
|
|
82
|
-
"cognitive_complexity": cognitive,
|
|
83
|
-
"threshold": "medium",
|
|
84
|
-
"cwe": "CWE-1121",
|
|
85
|
-
},
|
|
86
|
-
))
|
|
87
|
-
|
|
88
|
-
return EngineResult(engine=self.name, findings=findings, metrics=metrics, ok=True)
|
|
89
|
-
|
|
90
|
-
def _calculate_cyclomatic_complexity(self, node: ast.FunctionDef) -> int:
|
|
91
|
-
complexity = 1
|
|
92
|
-
for child in ast.walk(node):
|
|
93
|
-
if isinstance(child, (ast.If, ast.While, ast.For, ast.AsyncFor)):
|
|
94
|
-
complexity += 1
|
|
95
|
-
elif isinstance(child, ast.ExceptHandler):
|
|
96
|
-
complexity += 1
|
|
97
|
-
elif isinstance(child, ast.BoolOp):
|
|
98
|
-
complexity += len(child.values) - 1
|
|
99
|
-
elif isinstance(child, ast.With):
|
|
100
|
-
complexity += 1
|
|
101
|
-
elif isinstance(child, (ast.ListComp, ast.SetComp, ast.DictComp, ast.GeneratorExp)):
|
|
102
|
-
complexity += 1
|
|
103
|
-
elif isinstance(child, ast.IfExp):
|
|
104
|
-
complexity += 1
|
|
105
|
-
elif isinstance(child, ast.Match):
|
|
106
|
-
complexity += len(child.cases)
|
|
107
|
-
return complexity
|
|
108
|
-
|
|
109
|
-
def _calculate_cognitive_complexity(self, node: ast.FunctionDef) -> int:
|
|
110
|
-
complexity = 0
|
|
111
|
-
nesting = 0
|
|
112
|
-
|
|
113
|
-
def walk(n, nest_level):
|
|
114
|
-
nonlocal complexity
|
|
115
|
-
current_nest = nest_level
|
|
116
|
-
if isinstance(n, (ast.If, ast.While, ast.For, ast.AsyncFor, ast.With, ast.Try)):
|
|
117
|
-
current_nest = nest_level + 1
|
|
118
|
-
complexity += current_nest
|
|
119
|
-
elif isinstance(n, ast.ExceptHandler):
|
|
120
|
-
complexity += nest_level + 1
|
|
121
|
-
elif isinstance(n, ast.BoolOp):
|
|
122
|
-
complexity += len(n.values) - 1
|
|
123
|
-
elif isinstance(n, ast.IfExp):
|
|
124
|
-
complexity += nest_level + 1
|
|
125
|
-
elif isinstance(n, (ast.ListComp, ast.SetComp, ast.DictComp, ast.GeneratorExp)):
|
|
126
|
-
complexity += nest_level + 1
|
|
127
|
-
elif isinstance(n, ast.Match):
|
|
128
|
-
complexity += len(n.cases) * (nest_level + 1)
|
|
129
|
-
current_nest = nest_level + 1
|
|
130
|
-
elif isinstance(n, (ast.FunctionDef, ast.AsyncFunctionDef, ast.ClassDef, ast.Lambda)):
|
|
131
|
-
return
|
|
132
|
-
|
|
133
|
-
for child in ast.iter_child_nodes(n):
|
|
134
|
-
walk(child, current_nest)
|
|
135
|
-
|
|
136
|
-
walk(node, 0)
|
|
137
|
-
return complexity
|
|
138
|
-
|
|
139
|
-
def _get_snippet(self, lines: list, line_no: int, context: int = 3) -> str:
|
|
140
|
-
if line_no <= 0:
|
|
141
|
-
return ""
|
|
142
|
-
start = max(0, line_no - context - 1)
|
|
143
|
-
end = min(len(lines), line_no + context)
|
|
144
|
-
return "\n".join(lines[start:end])
|
|
Binary file
|
|
@@ -1,325 +0,0 @@
|
|
|
1
|
-
"""Compliance mapping engine - maps findings to compliance frameworks."""
|
|
2
|
-
from typing import List, Dict, Any, Optional
|
|
3
|
-
from dataclasses import dataclass
|
|
4
|
-
from collections import defaultdict
|
|
5
|
-
|
|
6
|
-
from orion.engine.config import EngineConfig
|
|
7
|
-
from orion.engine.ir import OrionIR
|
|
8
|
-
from orion.engine.results import EngineResult, Finding
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
@dataclass
|
|
12
|
-
class ComplianceMapping:
|
|
13
|
-
framework: str
|
|
14
|
-
article: str
|
|
15
|
-
control: str
|
|
16
|
-
description: str
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
class ComplianceEngine:
|
|
20
|
-
name = "compliance"
|
|
21
|
-
version = "1.0.0"
|
|
22
|
-
|
|
23
|
-
# Mapping from finding patterns to compliance frameworks
|
|
24
|
-
COMPLIANCE_MAP = {
|
|
25
|
-
# GDPR mappings
|
|
26
|
-
"sql_injection": [
|
|
27
|
-
ComplianceMapping("GDPR", "Art. 32", "security_of_processing", "SQL injection allows unauthorized access to personal data"),
|
|
28
|
-
ComplianceMapping("GDPR", "Art. 25", "privacy_by_design", "Lack of parameterized queries violates privacy by design"),
|
|
29
|
-
],
|
|
30
|
-
"xss": [
|
|
31
|
-
ComplianceMapping("GDPR", "Art. 32", "security_of_processing", "XSS can lead to personal data theft"),
|
|
32
|
-
ComplianceMapping("GDPR", "Art. 25", "privacy_by_design", "Missing output encoding violates privacy by design"),
|
|
33
|
-
],
|
|
34
|
-
"path_traversal": [
|
|
35
|
-
ComplianceMapping("GDPR", "Art. 32", "security_of_processing", "Path traversal can expose personal data files"),
|
|
36
|
-
],
|
|
37
|
-
"hardcoded_secret": [
|
|
38
|
-
ComplianceMapping("GDPR", "Art. 32", "encryption_at_rest", "Hardcoded secrets violate encryption requirements"),
|
|
39
|
-
ComplianceMapping("GDPR", "Art. 33", "breach_notification", "Exposed secrets require breach notification"),
|
|
40
|
-
],
|
|
41
|
-
"hardcoded_credential": [
|
|
42
|
-
ComplianceMapping("GDPR", "Art. 32", "encryption_at_rest", "Hardcoded credentials violate encryption requirements"),
|
|
43
|
-
],
|
|
44
|
-
"weak_crypto": [
|
|
45
|
-
ComplianceMapping("GDPR", "Art. 32", "encryption_at_rest", "Weak cryptography fails to protect personal data"),
|
|
46
|
-
ComplianceMapping("GDPR", "Art. 25", "privacy_by_design", "Weak crypto violates privacy by design"),
|
|
47
|
-
],
|
|
48
|
-
"md5": [
|
|
49
|
-
ComplianceMapping("GDPR", "Art. 32", "encryption_at_rest", "MD5 is cryptographically broken"),
|
|
50
|
-
],
|
|
51
|
-
"sha1": [
|
|
52
|
-
ComplianceMapping("GDPR", "Art. 32", "encryption_at_rest", "SHA1 is cryptographically weak"),
|
|
53
|
-
],
|
|
54
|
-
"insecure_deserialization": [
|
|
55
|
-
ComplianceMapping("GDPR", "Art. 32", "security_of_processing", "Deserialization vulnerabilities can lead to data breach"),
|
|
56
|
-
],
|
|
57
|
-
"missing_auth": [
|
|
58
|
-
ComplianceMapping("GDPR", "Art. 32", "access_control", "Missing authentication violates access control requirements"),
|
|
59
|
-
],
|
|
60
|
-
"authorization_bypass": [
|
|
61
|
-
ComplianceMapping("GDPR", "Art. 32", "access_control", "Authorization bypass allows unauthorized data access"),
|
|
62
|
-
],
|
|
63
|
-
"pii_logging": [
|
|
64
|
-
ComplianceMapping("GDPR", "Art. 32", "security_of_processing", "Logging PII exposes personal data"),
|
|
65
|
-
ComplianceMapping("GDPR", "Art. 25", "data_minimization", "Logging PII violates data minimization"),
|
|
66
|
-
],
|
|
67
|
-
"sensitive_data_logging": [
|
|
68
|
-
ComplianceMapping("GDPR", "Art. 32", "security_of_processing", "Logging sensitive data exposes it"),
|
|
69
|
-
],
|
|
70
|
-
"missing_csp": [
|
|
71
|
-
ComplianceMapping("GDPR", "Art. 32", "security_of_processing", "Missing CSP increases XSS risk"),
|
|
72
|
-
],
|
|
73
|
-
|
|
74
|
-
# PCI-DSS mappings
|
|
75
|
-
"sql_injection": [
|
|
76
|
-
ComplianceMapping("PCI-DSS", "Req 6.5.1", "injection_flaws", "SQL injection is a primary injection flaw"),
|
|
77
|
-
],
|
|
78
|
-
"xss": [
|
|
79
|
-
ComplianceMapping("PCI-DSS", "Req 6.5.7", "cross_site_scripting", "XSS is explicitly mentioned in PCI-DSS"),
|
|
80
|
-
],
|
|
81
|
-
"hardcoded_secret": [
|
|
82
|
-
ComplianceMapping("PCI-DSS", "Req 3", "protect_stored_data", "Hardcoded secrets violate stored data protection"),
|
|
83
|
-
ComplianceMapping("PCI-DSS", "Req 8", "identify_authenticate", "Hardcoded credentials violate authentication requirements"),
|
|
84
|
-
],
|
|
85
|
-
"weak_crypto": [
|
|
86
|
-
ComplianceMapping("PCI-DSS", "Req 3.4", "encrypt_transmission", "Weak crypto fails to protect cardholder data"),
|
|
87
|
-
ComplianceMapping("PCI-DSS", "Req 4", "encrypt_transmission", "Weak crypto in transit violates encryption requirements"),
|
|
88
|
-
],
|
|
89
|
-
"md5": [
|
|
90
|
-
ComplianceMapping("PCI-DSS", "Req 3.4", "encrypt_transmission", "MD5 not allowed for protecting cardholder data"),
|
|
91
|
-
],
|
|
92
|
-
"sha1": [
|
|
93
|
-
ComplianceMapping("PCI-DSS", "Req 3.4", "encrypt_transmission", "SHA1 not allowed for protecting cardholder data"),
|
|
94
|
-
],
|
|
95
|
-
"missing_auth": [
|
|
96
|
-
ComplianceMapping("PCI-DSS", "Req 8", "identify_authenticate", "Missing authentication violates Req 8"),
|
|
97
|
-
],
|
|
98
|
-
"insecure_deserialization": [
|
|
99
|
-
ComplianceMapping("PCI-DSS", "Req 6.5.8", "insecure_deserialization", "Insecure deserialization is a software vulnerability"),
|
|
100
|
-
],
|
|
101
|
-
"path_traversal": [
|
|
102
|
-
ComplianceMapping("PCI-DSS", "Req 6.5.5", "improper_access_control", "Path traversal is improper access control"),
|
|
103
|
-
],
|
|
104
|
-
|
|
105
|
-
# SOC2 mappings
|
|
106
|
-
"sql_injection": [
|
|
107
|
-
ComplianceMapping("SOC2", "CC6.1", "logical_access", "SQL injection bypasses logical access controls"),
|
|
108
|
-
],
|
|
109
|
-
"xss": [
|
|
110
|
-
ComplianceMapping("SOC2", "CC6.1", "logical_access", "XSS bypasses logical access controls"),
|
|
111
|
-
],
|
|
112
|
-
"hardcoded_secret": [
|
|
113
|
-
ComplianceMapping("SOC2", "CC6.1", "logical_access", "Hardcoded secrets bypass logical access controls"),
|
|
114
|
-
ComplianceMapping("SOC2", "CC6.7", "data_transmission", "Secrets in code can be transmitted"),
|
|
115
|
-
],
|
|
116
|
-
"weak_crypto": [
|
|
117
|
-
ComplianceMapping("SOC2", "CC6.7", "data_transmission", "Weak crypto fails to protect data in transmission"),
|
|
118
|
-
],
|
|
119
|
-
"missing_auth": [
|
|
120
|
-
ComplianceMapping("SOC2", "CC6.1", "logical_access", "Missing authentication violates logical access"),
|
|
121
|
-
],
|
|
122
|
-
"authorization_bypass": [
|
|
123
|
-
ComplianceMapping("SOC2", "CC6.1", "logical_access", "Authorization bypass violates logical access"),
|
|
124
|
-
],
|
|
125
|
-
"pii_logging": [
|
|
126
|
-
ComplianceMapping("SOC2", "CC6.7", "data_transmission", "Logging PII exposes data in transmission"),
|
|
127
|
-
],
|
|
128
|
-
"missing_csp": [
|
|
129
|
-
ComplianceMapping("SOC2", "CC7.2", "system_monitoring", "Missing CSP reduces monitoring effectiveness"),
|
|
130
|
-
],
|
|
131
|
-
"insecure_deserialization": [
|
|
132
|
-
ComplianceMapping("SOC2", "CC6.1", "logical_access", "Deserialization bypasses logical access"),
|
|
133
|
-
],
|
|
134
|
-
|
|
135
|
-
# HIPAA mappings
|
|
136
|
-
"sql_injection": [
|
|
137
|
-
ComplianceMapping("HIPAA", "164.312(a)(1)", "access_control", "SQL injection bypasses access control"),
|
|
138
|
-
],
|
|
139
|
-
"xss": [
|
|
140
|
-
ComplianceMapping("HIPAA", "164.312(a)(1)", "access_control", "XSS bypasses access control"),
|
|
141
|
-
],
|
|
142
|
-
"hardcoded_secret": [
|
|
143
|
-
ComplianceMapping("HIPAA", "164.312(a)(1)", "access_control", "Hardcoded secrets bypass access control"),
|
|
144
|
-
ComplianceMapping("HIPAA", "164.312(e)(1)", "transmission_security", "Secrets in code violate transmission security"),
|
|
145
|
-
],
|
|
146
|
-
"weak_crypto": [
|
|
147
|
-
ComplianceMapping("HIPAA", "164.312(e)(1)", "transmission_security", "Weak crypto violates transmission security"),
|
|
148
|
-
ComplianceMapping("HIPAA", "164.312(a)(2)(iv)", "encryption", "Weak crypto fails encryption standard"),
|
|
149
|
-
],
|
|
150
|
-
"md5": [
|
|
151
|
-
ComplianceMapping("HIPAA", "164.312(e)(1)", "transmission_security", "MD5 not approved for ePHI"),
|
|
152
|
-
],
|
|
153
|
-
"sha1": [
|
|
154
|
-
ComplianceMapping("HIPAA", "164.312(e)(1)", "transmission_security", "SHA1 not approved for ePHI"),
|
|
155
|
-
],
|
|
156
|
-
"insecure_deserialization": [
|
|
157
|
-
ComplianceMapping("HIPAA", "164.312(a)(1)", "access_control", "Deserialization bypasses access control"),
|
|
158
|
-
],
|
|
159
|
-
"pii_logging": [
|
|
160
|
-
ComplianceMapping("HIPAA", "164.312(a)(1)", "access_control", "Logging ePHI violates access control"),
|
|
161
|
-
ComplianceMapping("HIPAA", "164.312(b)", "audit_controls", "Improper logging violates audit controls"),
|
|
162
|
-
],
|
|
163
|
-
"missing_auth": [
|
|
164
|
-
ComplianceMapping("HIPAA", "164.312(a)(1)", "access_control", "Missing authentication violates access control"),
|
|
165
|
-
],
|
|
166
|
-
|
|
167
|
-
# Additional mappings
|
|
168
|
-
"cmd_injection": [
|
|
169
|
-
ComplianceMapping("GDPR", "Art. 32", "security_of_processing", "Command injection allows system compromise"),
|
|
170
|
-
ComplianceMapping("PCI-DSS", "Req 6.5.1", "injection_flaws", "Command injection is an injection flaw"),
|
|
171
|
-
ComplianceMapping("SOC2", "CC6.1", "logical_access", "Command injection bypasses logical access"),
|
|
172
|
-
ComplianceMapping("HIPAA", "164.312(a)(1)", "access_control", "Command injection bypasses access control"),
|
|
173
|
-
],
|
|
174
|
-
"ssrf": [
|
|
175
|
-
ComplianceMapping("GDPR", "Art. 32", "security_of_processing", "SSRF allows internal network access"),
|
|
176
|
-
ComplianceMapping("PCI-DSS", "Req 1.3", "network_segmentation", "SSRF bypasses network segmentation"),
|
|
177
|
-
ComplianceMapping("SOC2", "CC6.1", "logical_access", "SSRF bypasses logical access"),
|
|
178
|
-
],
|
|
179
|
-
"missing_healthcheck": [
|
|
180
|
-
ComplianceMapping("SOC2", "CC7.2", "system_monitoring", "Missing health checks reduce monitoring"),
|
|
181
|
-
],
|
|
182
|
-
"missing_resource_limits": [
|
|
183
|
-
ComplianceMapping("SOC2", "CC7.2", "system_monitoring", "Missing resource limits affect availability"),
|
|
184
|
-
],
|
|
185
|
-
"privileged_container": [
|
|
186
|
-
ComplianceMapping("GDPR", "Art. 32", "security_of_processing", "Privileged containers increase attack surface"),
|
|
187
|
-
ComplianceMapping("PCI-DSS", "Req 2.2", "secure_configuration", "Privileged containers violate secure config"),
|
|
188
|
-
ComplianceMapping("SOC2", "CC6.1", "logical_access", "Privileged containers bypass logical access"),
|
|
189
|
-
],
|
|
190
|
-
"run_as_root": [
|
|
191
|
-
ComplianceMapping("GDPR", "Art. 32", "security_of_processing", "Running as root increases risk"),
|
|
192
|
-
ComplianceMapping("PCI-DSS", "Req 2.2", "secure_configuration", "Running as root violates secure config"),
|
|
193
|
-
],
|
|
194
|
-
"allow_privilege_escalation": [
|
|
195
|
-
ComplianceMapping("GDPR", "Art. 32", "security_of_processing", "Privilege escalation increases risk"),
|
|
196
|
-
ComplianceMapping("PCI-DSS", "Req 2.2", "secure_configuration", "Privilege escalation violates secure config"),
|
|
197
|
-
],
|
|
198
|
-
"host_network": [
|
|
199
|
-
ComplianceMapping("PCI-DSS", "Req 1.3", "network_segmentation", "Host network bypasses segmentation"),
|
|
200
|
-
],
|
|
201
|
-
"missing_egress_control": [
|
|
202
|
-
ComplianceMapping("PCI-DSS", "Req 1.3", "network_segmentation", "Missing egress control violates segmentation"),
|
|
203
|
-
ComplianceMapping("SOC2", "CC6.7", "data_transmission", "Missing egress control allows data exfiltration"),
|
|
204
|
-
],
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
async def check_availability(self) -> bool:
|
|
208
|
-
return True
|
|
209
|
-
|
|
210
|
-
def resource_limits(self):
|
|
211
|
-
from orion.engine.config import ResourceLimits
|
|
212
|
-
return ResourceLimits(max_cpu_seconds=10, max_memory_mb=64)
|
|
213
|
-
|
|
214
|
-
def _extract_pattern_key(self, finding: Finding) -> str:
|
|
215
|
-
"""Extract normalized pattern key from finding."""
|
|
216
|
-
# Try metadata first
|
|
217
|
-
pattern = finding.metadata.get("pattern", "")
|
|
218
|
-
if pattern:
|
|
219
|
-
return pattern.lower()
|
|
220
|
-
|
|
221
|
-
# Try title
|
|
222
|
-
title = finding.title.lower()
|
|
223
|
-
# Map common patterns
|
|
224
|
-
patterns = [
|
|
225
|
-
"sql_injection", "sqli", "xss", "cmd_injection", "ssrf",
|
|
226
|
-
"path_traversal", "hardcoded_secret", "hardcoded_credential",
|
|
227
|
-
"weak_crypto", "md5", "sha1", "insecure_deserialization",
|
|
228
|
-
"pickle", "yaml", "eval", "exec", "subprocess", "shell",
|
|
229
|
-
"missing_auth", "authorization", "csp", "logging",
|
|
230
|
-
"pii", "sensitive", "privileged", "run_as_root",
|
|
231
|
-
"allow_privilege_escalation", "host_network", "host_pid", "host_ipc",
|
|
232
|
-
"missing_healthcheck", "missing_resource_limits", "read_only",
|
|
233
|
-
"cap_add", "network_mode", "pid_mode", "ipc_mode",
|
|
234
|
-
"missing_egress_control", "allow_all_outbound",
|
|
235
|
-
]
|
|
236
|
-
for p in patterns:
|
|
237
|
-
if p in title:
|
|
238
|
-
return p
|
|
239
|
-
return title[:50]
|
|
240
|
-
|
|
241
|
-
def _get_mappings(self, pattern_key: str) -> List[ComplianceMapping]:
|
|
242
|
-
"""Get compliance mappings for a pattern key."""
|
|
243
|
-
mappings = []
|
|
244
|
-
for key, comp_mappings in self.COMPLIANCE_MAP.items():
|
|
245
|
-
if key in pattern_key or pattern_key in key:
|
|
246
|
-
mappings.extend(comp_mappings)
|
|
247
|
-
return mappings
|
|
248
|
-
|
|
249
|
-
async def run(self, ir: OrionIR, config: EngineConfig) -> EngineResult:
|
|
250
|
-
# Get all findings from context
|
|
251
|
-
all_findings = ir.metadata.get("all_findings", [])
|
|
252
|
-
|
|
253
|
-
# Also check project context
|
|
254
|
-
project_ctx = ir.metadata.get("project_context")
|
|
255
|
-
if project_ctx and hasattr(project_ctx, 'findings'):
|
|
256
|
-
all_findings.extend(project_ctx.findings)
|
|
257
|
-
|
|
258
|
-
if not all_findings:
|
|
259
|
-
return EngineResult(engine=self.name, ok=True, metrics={"findings_processed": 0})
|
|
260
|
-
|
|
261
|
-
# Process each finding and add compliance metadata
|
|
262
|
-
enriched_findings = []
|
|
263
|
-
compliance_stats = defaultdict(int)
|
|
264
|
-
|
|
265
|
-
for finding in all_findings:
|
|
266
|
-
pattern_key = self._extract_pattern_key(finding)
|
|
267
|
-
mappings = self._get_mappings(pattern_key)
|
|
268
|
-
|
|
269
|
-
if mappings:
|
|
270
|
-
# Add compliance metadata to finding
|
|
271
|
-
compliance_metadata = []
|
|
272
|
-
for m in mappings:
|
|
273
|
-
compliance_metadata.append({
|
|
274
|
-
"framework": m.framework,
|
|
275
|
-
"article": m.article,
|
|
276
|
-
"control": m.control,
|
|
277
|
-
"description": m.description,
|
|
278
|
-
})
|
|
279
|
-
compliance_stats[m.framework] += 1
|
|
280
|
-
|
|
281
|
-
# Create enriched finding with compliance metadata
|
|
282
|
-
enriched = Finding(
|
|
283
|
-
engine=finding.engine,
|
|
284
|
-
severity=finding.severity,
|
|
285
|
-
title=finding.title,
|
|
286
|
-
description=finding.description,
|
|
287
|
-
location=finding.location,
|
|
288
|
-
metadata={
|
|
289
|
-
**finding.metadata,
|
|
290
|
-
"compliance": compliance_metadata,
|
|
291
|
-
},
|
|
292
|
-
)
|
|
293
|
-
enriched_findings.append(enriched)
|
|
294
|
-
else:
|
|
295
|
-
enriched_findings.append(finding)
|
|
296
|
-
|
|
297
|
-
# Create summary finding
|
|
298
|
-
if compliance_stats:
|
|
299
|
-
summary = Finding(
|
|
300
|
-
engine=self.name,
|
|
301
|
-
severity="info",
|
|
302
|
-
title="Compliance mapping summary",
|
|
303
|
-
description=f"Mapped findings to compliance frameworks: {dict(compliance_stats)}",
|
|
304
|
-
location="",
|
|
305
|
-
metadata={
|
|
306
|
-
"rule": "compliance_summary",
|
|
307
|
-
"frameworks": dict(compliance_stats),
|
|
308
|
-
"total_mappings": sum(compliance_stats.values()),
|
|
309
|
-
},
|
|
310
|
-
)
|
|
311
|
-
enriched_findings.append(summary)
|
|
312
|
-
|
|
313
|
-
return EngineResult(
|
|
314
|
-
engine=self.name,
|
|
315
|
-
findings=enriched_findings,
|
|
316
|
-
ok=True,
|
|
317
|
-
metrics={
|
|
318
|
-
"findings_processed": len(all_findings),
|
|
319
|
-
"findings_with_mappings": len([f for f in enriched_findings if "compliance" in f.metadata]),
|
|
320
|
-
"compliance_stats": dict(compliance_stats),
|
|
321
|
-
},
|
|
322
|
-
)
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
Engine = ComplianceEngine
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import hashlib
|
|
2
|
-
from dataclasses import dataclass, field
|
|
3
|
-
from typing import Optional
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
@dataclass
|
|
7
|
-
class ResourceLimits:
|
|
8
|
-
max_memory_mb: int = 512
|
|
9
|
-
max_cpu_seconds: int = 60
|
|
10
|
-
max_file_size_mb: int = 10
|
|
11
|
-
max_files: int = 50000
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
@dataclass
|
|
15
|
-
class NetworkPolicy:
|
|
16
|
-
allow_outbound: bool = False
|
|
17
|
-
allowed_hosts: list = field(default_factory=list)
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
@dataclass
|
|
21
|
-
class EngineConfig:
|
|
22
|
-
toggles: dict = field(default_factory=dict)
|
|
23
|
-
resource_limits: dict = field(default_factory=dict)
|
|
24
|
-
network_policy: dict = field(default_factory=dict)
|
|
25
|
-
|
|
26
|
-
def get_limits(self) -> ResourceLimits:
|
|
27
|
-
defaults = ResourceLimits()
|
|
28
|
-
rl = self.resource_limits or {}
|
|
29
|
-
return ResourceLimits(
|
|
30
|
-
max_memory_mb=rl.get("max_memory_mb", defaults.max_memory_mb),
|
|
31
|
-
max_cpu_seconds=rl.get("max_cpu_seconds", defaults.max_cpu_seconds),
|
|
32
|
-
max_file_size_mb=rl.get("max_file_size_mb", defaults.max_file_size_mb),
|
|
33
|
-
max_files=rl.get("max_files", defaults.max_files),
|
|
34
|
-
)
|
|
35
|
-
|
|
36
|
-
def get_network_policy(self) -> NetworkPolicy:
|
|
37
|
-
np = self.network_policy or {}
|
|
38
|
-
return NetworkPolicy(
|
|
39
|
-
allow_outbound=np.get("allow_outbound", False),
|
|
40
|
-
allowed_hosts=np.get("allowed_hosts", []),
|
|
41
|
-
)
|
|
Binary file
|