@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.
Files changed (129) hide show
  1. package/README.md +80 -190
  2. package/bin/orion.js +30 -29
  3. package/dist/orion.exe +0 -0
  4. package/package.json +46 -48
  5. package/docs/API_REFERENCE.md +0 -211
  6. package/docs/ARCHITECTURE.md +0 -183
  7. package/docs/CHANGELOG.md +0 -112
  8. package/docs/CONTRIBUTING.md +0 -157
  9. package/docs/ENGINE_CATALOG.md +0 -87
  10. package/docs/GETTING_STARTED.md +0 -226
  11. package/pyproject.toml +0 -16
  12. package/src/orion/__init__.py +0 -0
  13. package/src/orion/__pycache__/__init__.cpython-313.pyc +0 -0
  14. package/src/orion/engine/__init__.py +0 -17
  15. package/src/orion/engine/__pycache__/__init__.cpython-313.pyc +0 -0
  16. package/src/orion/engine/__pycache__/config.cpython-313.pyc +0 -0
  17. package/src/orion/engine/__pycache__/core.cpython-313.pyc +0 -0
  18. package/src/orion/engine/__pycache__/ir.cpython-313.pyc +0 -0
  19. package/src/orion/engine/__pycache__/languages.cpython-313.pyc +0 -0
  20. package/src/orion/engine/__pycache__/registry.cpython-313.pyc +0 -0
  21. package/src/orion/engine/__pycache__/results.cpython-313.pyc +0 -0
  22. package/src/orion/engine/__pycache__/runner.cpython-313.pyc +0 -0
  23. package/src/orion/engine/api_security/__pycache__/engine.cpython-313.pyc +0 -0
  24. package/src/orion/engine/api_security/engine.py +0 -125
  25. package/src/orion/engine/architecture/__pycache__/engine.cpython-313.pyc +0 -0
  26. package/src/orion/engine/architecture/engine.py +0 -463
  27. package/src/orion/engine/authorization/__pycache__/engine.cpython-313.pyc +0 -0
  28. package/src/orion/engine/authorization/engine.py +0 -337
  29. package/src/orion/engine/callgraph/__pycache__/engine.cpython-313.pyc +0 -0
  30. package/src/orion/engine/callgraph/engine.py +0 -236
  31. package/src/orion/engine/cfg/__pycache__/engine.cpython-313.pyc +0 -0
  32. package/src/orion/engine/cfg/engine.py +0 -509
  33. package/src/orion/engine/chaos/__pycache__/engine.cpython-313.pyc +0 -0
  34. package/src/orion/engine/chaos/engine.py +0 -268
  35. package/src/orion/engine/chaos_config/__pycache__/engine.cpython-313.pyc +0 -0
  36. package/src/orion/engine/chaos_config/engine.py +0 -322
  37. package/src/orion/engine/complexity/__pycache__/engine.cpython-313.pyc +0 -0
  38. package/src/orion/engine/complexity/engine.py +0 -144
  39. package/src/orion/engine/compliance/__pycache__/engine.cpython-313.pyc +0 -0
  40. package/src/orion/engine/compliance/engine.py +0 -325
  41. package/src/orion/engine/config.py +0 -41
  42. package/src/orion/engine/config_engine/__pycache__/engine.cpython-313.pyc +0 -0
  43. package/src/orion/engine/config_engine/engine.py +0 -364
  44. package/src/orion/engine/config_validation/__pycache__/engine.cpython-313.pyc +0 -0
  45. package/src/orion/engine/config_validation/engine.py +0 -313
  46. package/src/orion/engine/container/__pycache__/engine.cpython-313.pyc +0 -0
  47. package/src/orion/engine/container/engine.py +0 -546
  48. package/src/orion/engine/contract_probe/__pycache__/engine.cpython-313.pyc +0 -0
  49. package/src/orion/engine/contract_probe/engine.py +0 -316
  50. package/src/orion/engine/core.py +0 -75
  51. package/src/orion/engine/crypto_guard/__pycache__/engine.cpython-313.pyc +0 -0
  52. package/src/orion/engine/crypto_guard/engine.py +0 -134
  53. package/src/orion/engine/data_residency/__pycache__/engine.cpython-313.pyc +0 -0
  54. package/src/orion/engine/data_residency/engine.py +0 -238
  55. package/src/orion/engine/dataflow/__pycache__/engine.cpython-313.pyc +0 -0
  56. package/src/orion/engine/dataflow/engine.py +0 -398
  57. package/src/orion/engine/dead_import/__pycache__/engine.cpython-313.pyc +0 -0
  58. package/src/orion/engine/dead_import/engine.py +0 -293
  59. package/src/orion/engine/deps/__pycache__/engine.cpython-313.pyc +0 -0
  60. package/src/orion/engine/deps/engine.py +0 -244
  61. package/src/orion/engine/dispatcher.py +0 -350
  62. package/src/orion/engine/docs/AUDIT_PROMPT.md +0 -1248
  63. package/src/orion/engine/duplication/__pycache__/engine.cpython-313.pyc +0 -0
  64. package/src/orion/engine/duplication/engine.py +0 -120
  65. package/src/orion/engine/error_handling/__pycache__/engine.cpython-313.pyc +0 -0
  66. package/src/orion/engine/error_handling/engine.py +0 -256
  67. package/src/orion/engine/fp_learn/__pycache__/engine.cpython-313.pyc +0 -0
  68. package/src/orion/engine/fp_learn/engine.py +0 -248
  69. package/src/orion/engine/hunter/__pycache__/engine.cpython-313.pyc +0 -0
  70. package/src/orion/engine/hunter/engine.py +0 -324
  71. package/src/orion/engine/iac_security/__pycache__/engine.cpython-313.pyc +0 -0
  72. package/src/orion/engine/iac_security/engine.py +0 -218
  73. package/src/orion/engine/ir.py +0 -22
  74. package/src/orion/engine/languages.py +0 -454
  75. package/src/orion/engine/license/__pycache__/engine.cpython-313.pyc +0 -0
  76. package/src/orion/engine/license/engine.py +0 -172
  77. package/src/orion/engine/lint/__pycache__/engine.cpython-313.pyc +0 -0
  78. package/src/orion/engine/lint/engine.py +0 -558
  79. package/src/orion/engine/llm_security/__pycache__/engine.cpython-313.pyc +0 -0
  80. package/src/orion/engine/llm_security/engine.py +0 -125
  81. package/src/orion/engine/logging_c/__pycache__/engine.cpython-313.pyc +0 -0
  82. package/src/orion/engine/logging_c/engine.py +0 -164
  83. package/src/orion/engine/noise/__pycache__/engine.cpython-313.pyc +0 -0
  84. package/src/orion/engine/noise/engine.py +0 -140
  85. package/src/orion/engine/orphan/__pycache__/engine.cpython-313.pyc +0 -0
  86. package/src/orion/engine/orphan/engine.py +0 -244
  87. package/src/orion/engine/perf_guard/__pycache__/engine.cpython-313.pyc +0 -0
  88. package/src/orion/engine/perf_guard/engine.py +0 -345
  89. package/src/orion/engine/prompt_security/__pycache__/engine.cpython-313.pyc +0 -0
  90. package/src/orion/engine/prompt_security/detectors/__init__.py +0 -4
  91. package/src/orion/engine/prompt_security/engine.py +0 -170
  92. package/src/orion/engine/provenance/__pycache__/engine.cpython-313.pyc +0 -0
  93. package/src/orion/engine/provenance/engine.py +0 -242
  94. package/src/orion/engine/registry.py +0 -55
  95. package/src/orion/engine/regression/__pycache__/engine.cpython-313.pyc +0 -0
  96. package/src/orion/engine/regression/engine.py +0 -213
  97. package/src/orion/engine/results.py +0 -21
  98. package/src/orion/engine/runner.py +0 -1310
  99. package/src/orion/engine/sandbox_escape/__pycache__/engine.cpython-313.pyc +0 -0
  100. package/src/orion/engine/sandbox_escape/engine.py +0 -284
  101. package/src/orion/engine/sast/__pycache__/engine.cpython-313.pyc +0 -0
  102. package/src/orion/engine/sast/engine.py +0 -217
  103. package/src/orion/engine/sast/patterns/__init__.py +0 -513
  104. package/src/orion/engine/sast/patterns/__pycache__/__init__.cpython-313.pyc +0 -0
  105. package/src/orion/engine/secrets/__pycache__/engine.cpython-313.pyc +0 -0
  106. package/src/orion/engine/secrets/engine.py +0 -77
  107. package/src/orion/engine/secrets/patterns/__init__.py +0 -74
  108. package/src/orion/engine/secrets/patterns/__pycache__/__init__.cpython-313.pyc +0 -0
  109. package/src/orion/engine/sensitive_data/__pycache__/engine.cpython-313.pyc +0 -0
  110. package/src/orion/engine/sensitive_data/engine.py +0 -143
  111. package/src/orion/engine/state/__pycache__/engine.cpython-313.pyc +0 -0
  112. package/src/orion/engine/state/engine.py +0 -218
  113. package/src/orion/engine/supply_chain_sbom/__pycache__/engine.cpython-313.pyc +0 -0
  114. package/src/orion/engine/supply_chain_sbom/engine.py +0 -290
  115. package/src/orion/engine/symbol/__pycache__/engine.cpython-313.pyc +0 -0
  116. package/src/orion/engine/symbol/engine.py +0 -463
  117. package/src/orion/engine/taint/__pycache__/engine.cpython-313.pyc +0 -0
  118. package/src/orion/engine/taint/engine.py +0 -464
  119. package/src/orion/engine/test_coverage/__pycache__/engine.cpython-313.pyc +0 -0
  120. package/src/orion/engine/test_coverage/engine.py +0 -445
  121. package/src/orion/engine/threat_model/__pycache__/engine.cpython-313.pyc +0 -0
  122. package/src/orion/engine/threat_model/engine.py +0 -126
  123. package/src/orion/engine/wiring_trace/__pycache__/engine.cpython-313.pyc +0 -0
  124. package/src/orion/engine/wiring_trace/engine.py +0 -200
  125. package/src/orion_engine.egg-info/PKG-INFO +0 -7
  126. package/src/orion_engine.egg-info/SOURCES.txt +0 -65
  127. package/src/orion_engine.egg-info/dependency_links.txt +0 -1
  128. package/src/orion_engine.egg-info/entry_points.txt +0 -2
  129. package/src/orion_engine.egg-info/top_level.txt +0 -1
@@ -1,454 +0,0 @@
1
- """Universal language support for Orion Engine."""
2
-
3
- from enum import Enum
4
- from dataclasses import dataclass
5
- from typing import Dict, List, Set, Optional
6
- import os
7
-
8
-
9
- class Language(Enum):
10
- """Supported programming languages."""
11
- PYTHON = "python"
12
- JAVASCRIPT = "javascript"
13
- TYPESCRIPT = "typescript"
14
- JAVA = "java"
15
- GO = "go"
16
- RUST = "rust"
17
- CPP = "cpp"
18
- C = "c"
19
- CSHARP = "csharp"
20
- PHP = "php"
21
- RUBY = "ruby"
22
- SWIFT = "swift"
23
- KOTLIN = "kotlin"
24
- SCALA = "scala"
25
- HTML = "html"
26
- CSS = "css"
27
- SQL = "sql"
28
- YAML = "yaml"
29
- JSON = "json"
30
- TOML = "toml"
31
- XML = "xml"
32
- DOCKERFILE = "dockerfile"
33
- MARKDOWN = "markdown"
34
- SHELL = "shell"
35
- POWERSHELL = "powershell"
36
- UNKNOWN = "unknown"
37
-
38
-
39
- # File extension to language mapping
40
- EXTENSION_MAP: Dict[str, Language] = {
41
- # Python
42
- ".py": Language.PYTHON,
43
- ".pyw": Language.PYTHON,
44
- ".pyi": Language.PYTHON,
45
-
46
- # JavaScript/TypeScript
47
- ".js": Language.JAVASCRIPT,
48
- ".jsx": Language.JAVASCRIPT,
49
- ".mjs": Language.JAVASCRIPT,
50
- ".cjs": Language.JAVASCRIPT,
51
- ".ts": Language.TYPESCRIPT,
52
- ".tsx": Language.TYPESCRIPT,
53
- ".mts": Language.TYPESCRIPT,
54
- ".cts": Language.TYPESCRIPT,
55
-
56
- # Java
57
- ".java": Language.JAVA,
58
-
59
- # Go
60
- ".go": Language.GO,
61
-
62
- # Rust
63
- ".rs": Language.RUST,
64
-
65
- # C/C++
66
- ".c": Language.C,
67
- ".h": Language.C,
68
- ".cpp": Language.CPP,
69
- ".cc": Language.CPP,
70
- ".cxx": Language.CPP,
71
- ".hpp": Language.CPP,
72
- ".hxx": Language.CPP,
73
-
74
- # C#
75
- ".cs": Language.CSHARP,
76
-
77
- # PHP
78
- ".php": Language.PHP,
79
- ".phtml": Language.PHP,
80
-
81
- # Ruby
82
- ".rb": Language.RUBY,
83
- ".erb": Language.RUBY,
84
-
85
- # Swift
86
- ".swift": Language.SWIFT,
87
-
88
- # Kotlin
89
- ".kt": Language.KOTLIN,
90
- ".kts": Language.KOTLIN,
91
-
92
- # Scala
93
- ".scala": Language.SCALA,
94
-
95
- # Web
96
- ".html": Language.HTML,
97
- ".htm": Language.HTML,
98
- ".xhtml": Language.HTML,
99
- ".css": Language.CSS,
100
- ".scss": Language.CSS,
101
- ".sass": Language.CSS,
102
- ".less": Language.CSS,
103
-
104
- # SQL
105
- ".sql": Language.SQL,
106
-
107
- # Config
108
- ".yaml": Language.YAML,
109
- ".yml": Language.YAML,
110
- ".json": Language.JSON,
111
- ".toml": Language.TOML,
112
- ".xml": Language.XML,
113
- ".ini": Language.YAML,
114
- ".cfg": Language.YAML,
115
- ".conf": Language.YAML,
116
- ".properties": Language.YAML,
117
-
118
- # Docker/Container
119
- "Dockerfile": Language.DOCKERFILE,
120
- "dockerfile": Language.DOCKERFILE,
121
- ".dockerfile": Language.DOCKERFILE,
122
- "docker-compose.yml": Language.DOCKERFILE,
123
- "docker-compose.yaml": Language.DOCKERFILE,
124
-
125
- # Shell
126
- ".sh": Language.SHELL,
127
- ".bash": Language.SHELL,
128
- ".zsh": Language.SHELL,
129
- ".fish": Language.SHELL,
130
-
131
- # PowerShell
132
- ".ps1": Language.POWERSHELL,
133
- ".psm1": Language.POWERSHELL,
134
- ".psd1": Language.POWERSHELL,
135
-
136
- # Documentation
137
- ".md": Language.MARKDOWN,
138
- ".markdown": Language.MARKDOWN,
139
- ".rst": Language.MARKDOWN,
140
-
141
- # Config files without extensions
142
- "Makefile": Language.SHELL,
143
- "makefile": Language.SHELL,
144
- "CMakeLists.txt": Language.SHELL,
145
- ".gitignore": Language.YAML,
146
- ".gitattributes": Language.YAML,
147
- ".editorconfig": Language.YAML,
148
- ".env": Language.YAML,
149
- ".env.example": Language.YAML,
150
- ".env.local": Language.YAML,
151
- "package.json": Language.JSON,
152
- "package-lock.json": Language.JSON,
153
- "yarn.lock": Language.YAML,
154
- "pnpm-lock.yaml": Language.YAML,
155
- "requirements.txt": Language.YAML,
156
- "requirements-dev.txt": Language.YAML,
157
- "Pipfile": Language.TOML,
158
- "Pipfile.lock": Language.JSON,
159
- "pyproject.toml": Language.TOML,
160
- "poetry.lock": Language.JSON,
161
- "Cargo.toml": Language.TOML,
162
- "Cargo.lock": Language.JSON,
163
- "go.mod": Language.YAML,
164
- "go.sum": Language.YAML,
165
- "pom.xml": Language.XML,
166
- "build.gradle": Language.SHELL,
167
- "build.gradle.kts": Language.SHELL,
168
- "settings.gradle": Language.SHELL,
169
- "composer.json": Language.JSON,
170
- "composer.lock": Language.JSON,
171
- "Gemfile": Language.YAML,
172
- "Gemfile.lock": Language.YAML,
173
- "mix.exs": Language.SHELL,
174
- "mix.lock": Language.YAML,
175
- "pubspec.yaml": Language.YAML,
176
- "pubspec.lock": Language.YAML,
177
- }
178
-
179
-
180
- # Filename patterns for special files
181
- FILENAME_PATTERNS: Dict[str, Language] = {
182
- "Dockerfile": Language.DOCKERFILE,
183
- "dockerfile": Language.DOCKERFILE,
184
- "docker-compose.yml": Language.DOCKERFILE,
185
- "docker-compose.yaml": Language.DOCKERFILE,
186
- "docker-compose.override.yml": Language.DOCKERFILE,
187
- "docker-compose.override.yaml": Language.DOCKERFILE,
188
- "Makefile": Language.SHELL,
189
- "makefile": Language.SHELL,
190
- "CMakeLists.txt": Language.SHELL,
191
- "CMakeLists.txt": Language.SHELL,
192
- }
193
-
194
-
195
- def detect_language(filepath: str) -> Language:
196
- """Detect language from file path."""
197
- filename = os.path.basename(filepath)
198
-
199
- # Check exact filename matches first
200
- if filename in FILENAME_PATTERNS:
201
- return FILENAME_PATTERNS[filename]
202
-
203
- # Check extension
204
- _, ext = os.path.splitext(filename)
205
- ext = ext.lower()
206
- if ext in EXTENSION_MAP:
207
- return EXTENSION_MAP[ext]
208
-
209
- # Check for double extensions (e.g., .dockerfile, .min.js)
210
- if '.' in filename:
211
- parts = filename.split('.')
212
- if len(parts) > 2:
213
- double_ext = '.' + '.'.join(parts[-2:]).lower()
214
- if double_ext in EXTENSION_MAP:
215
- return EXTENSION_MAP[double_ext]
216
-
217
- return Language.UNKNOWN
218
-
219
-
220
- def is_binary_file(filepath: str) -> bool:
221
- """Quick check if file is likely binary."""
222
- try:
223
- with open(filepath, 'rb') as f:
224
- chunk = f.read(8192)
225
- return b'\x00' in chunk
226
- except Exception:
227
- return True
228
-
229
-
230
- # Language groups for engine targeting
231
- LANGUAGE_GROUPS: Dict[str, Set[Language]] = {
232
- "pythonic": {Language.PYTHON},
233
- "javascript": {Language.JAVASCRIPT, Language.TYPESCRIPT},
234
- "jvm": {Language.JAVA, Language.KOTLIN, Language.SCALA},
235
- "native": {Language.C, Language.CPP, Language.RUST, Language.GO, Language.CSHARP},
236
- "web": {Language.HTML, Language.CSS, Language.JAVASCRIPT, Language.TYPESCRIPT},
237
- "scripting": {Language.PYTHON, Language.JAVASCRIPT, Language.TYPESCRIPT, Language.PHP, Language.RUBY, Language.SHELL, Language.POWERSHELL},
238
- "compiled": {Language.C, Language.CPP, Language.RUST, Language.GO, Language.JAVA, Language.CSHARP, Language.SWIFT, Language.KOTLIN, Language.SCALA},
239
- "interpreted": {Language.PYTHON, Language.JAVASCRIPT, Language.TYPESCRIPT, Language.PHP, Language.RUBY, Language.SHELL},
240
- "config": {Language.YAML, Language.JSON, Language.TOML, Language.XML},
241
- "container": {Language.DOCKERFILE},
242
- "data": {Language.SQL, Language.JSON, Language.YAML, Language.XML},
243
- "web_static": {Language.HTML, Language.CSS},
244
- "documentation": {Language.MARKDOWN},
245
- }
246
-
247
-
248
- def get_language_group(language: Language) -> List[str]:
249
- """Get groups a language belongs to."""
250
- groups = []
251
- for group_name, langs in LANGUAGE_GROUPS.items():
252
- if language in langs:
253
- groups.append(group_name)
254
- return groups
255
-
256
-
257
- @dataclass
258
- class LanguageCapabilities:
259
- """What analysis capabilities are available for a language."""
260
- language: Language
261
- has_ast_parser: bool = False
262
- has_tree_sitter: bool = False
263
- sast_patterns: int = 0
264
- secret_patterns: int = 0
265
- dep_parsers: List[str] = None
266
- taint_sources: List[str] = None
267
- taint_sinks: List[str] = None
268
-
269
- def __post_init__(self):
270
- if self.dep_parsers is None:
271
- self.dep_parsers = []
272
- if self.taint_sources is None:
273
- self.taint_sources = []
274
- if self.taint_sinks is None:
275
- self.taint_sinks = []
276
-
277
-
278
- # Language capability registry
279
- LANGUAGE_CAPABILITIES: Dict[Language, LanguageCapabilities] = {
280
- Language.PYTHON: LanguageCapabilities(
281
- language=Language.PYTHON,
282
- has_ast_parser=True,
283
- has_tree_sitter=True,
284
- sast_patterns=28,
285
- secret_patterns=12,
286
- dep_parsers=["requirements.txt", "pyproject.toml", "Pipfile", "poetry.lock", "setup.py"],
287
- taint_sources=["request.", "input(", "sys.argv", "os.environ", "request.GET", "request.POST"],
288
- taint_sinks=["execute", "eval", "exec", "system", "popen", "subprocess", "render_template_string"],
289
- ),
290
- Language.JAVASCRIPT: LanguageCapabilities(
291
- language=Language.JAVASCRIPT,
292
- has_ast_parser=True,
293
- has_tree_sitter=True,
294
- sast_patterns=6,
295
- secret_patterns=8,
296
- dep_parsers=["package.json", "package-lock.json", "yarn.lock", "pnpm-lock.yaml"],
297
- taint_sources=["req.body", "req.query", "req.params", "req.headers", "process.env"],
298
- taint_sinks=["eval", "exec", "Function", "innerHTML", "outerHTML", "document.write"],
299
- ),
300
- Language.TYPESCRIPT: LanguageCapabilities(
301
- language=Language.TYPESCRIPT,
302
- has_ast_parser=True,
303
- has_tree_sitter=True,
304
- sast_patterns=6,
305
- secret_patterns=8,
306
- dep_parsers=["package.json", "package-lock.json", "yarn.lock", "pnpm-lock.yaml"],
307
- taint_sources=["req.body", "req.query", "req.params", "req.headers", "process.env"],
308
- taint_sinks=["eval", "exec", "Function", "innerHTML", "outerHTML", "document.write"],
309
- ),
310
- Language.JAVA: LanguageCapabilities(
311
- language=Language.JAVA,
312
- has_ast_parser=True,
313
- has_tree_sitter=True,
314
- sast_patterns=0,
315
- secret_patterns=8,
316
- dep_parsers=["pom.xml", "build.gradle", "build.gradle.kts"],
317
- taint_sources=["request.getParameter", "request.getHeader", "System.getenv"],
318
- taint_sinks=["executeQuery", "executeUpdate", "Runtime.exec", "ProcessBuilder"],
319
- ),
320
- Language.GO: LanguageCapabilities(
321
- language=Language.GO,
322
- has_ast_parser=True,
323
- has_tree_sitter=True,
324
- sast_patterns=0,
325
- secret_patterns=8,
326
- dep_parsers=["go.mod", "go.sum"],
327
- taint_sources=["r.FormValue", "r.URL.Query", "os.Getenv"],
328
- taint_sinks=["Exec", "Query", "ExecContext", "os/exec.Command"],
329
- ),
330
- Language.RUST: LanguageCapabilities(
331
- language=Language.RUST,
332
- has_ast_parser=True,
333
- has_tree_sitter=True,
334
- sast_patterns=0,
335
- secret_patterns=8,
336
- dep_parsers=["Cargo.toml", "Cargo.lock"],
337
- taint_sources=["std::env::var", "req.body", "req.query"],
338
- taint_sinks=["std::process::Command", "sqlx::query", "diesel::RunQueryDsl"],
339
- ),
340
- Language.CSHARP: LanguageCapabilities(
341
- language=Language.CSHARP,
342
- has_ast_parser=True,
343
- has_tree_sitter=True,
344
- sast_patterns=0,
345
- secret_patterns=8,
346
- dep_parsers=["*.csproj", "packages.config", "paket.dependencies"],
347
- taint_sources=["Request.QueryString", "Request.Form", "Environment.GetEnvironmentVariable"],
348
- taint_sinks=["SqlCommand.ExecuteReader", "Process.Start", "SqlCommand.ExecuteNonQuery"],
349
- ),
350
- Language.PHP: LanguageCapabilities(
351
- language=Language.PHP,
352
- has_ast_parser=True,
353
- has_tree_sitter=True,
354
- sast_patterns=0,
355
- secret_patterns=8,
356
- dep_parsers=["composer.json", "composer.lock"],
357
- taint_sources=["$_GET", "$_POST", "$_REQUEST", "$_COOKIE", "$_SERVER", "$_ENV"],
358
- taint_sinks=["exec", "system", "shell_exec", "passthru", "proc_open", "eval", "mysqli_query"],
359
- ),
360
- Language.RUBY: LanguageCapabilities(
361
- language=Language.RUBY,
362
- has_ast_parser=True,
363
- has_tree_sitter=True,
364
- sast_patterns=0,
365
- secret_patterns=8,
366
- dep_parsers=["Gemfile", "Gemfile.lock"],
367
- taint_sources=["params", "request.env", "ENV"],
368
- taint_sinks=["system", "exec", "`", "eval", "ActiveRecord::Base.connection.execute"],
369
- ),
370
- Language.HTML: LanguageCapabilities(
371
- language=Language.HTML,
372
- has_ast_parser=False,
373
- has_tree_sitter=True,
374
- sast_patterns=0,
375
- secret_patterns=4,
376
- dep_parsers=[],
377
- taint_sources=[],
378
- taint_sinks=["innerHTML", "outerHTML", "document.write", "eval"],
379
- ),
380
- Language.CSS: LanguageCapabilities(
381
- language=Language.CSS,
382
- has_ast_parser=False,
383
- has_tree_sitter=True,
384
- sast_patterns=0,
385
- secret_patterns=0,
386
- dep_parsers=[],
387
- taint_sources=[],
388
- taint_sinks=[],
389
- ),
390
- Language.YAML: LanguageCapabilities(
391
- language=Language.YAML,
392
- has_ast_parser=False,
393
- has_tree_sitter=False,
394
- sast_patterns=0,
395
- secret_patterns=8,
396
- dep_parsers=[],
397
- taint_sources=[],
398
- taint_sinks=[],
399
- ),
400
- Language.JSON: LanguageCapabilities(
401
- language=Language.JSON,
402
- has_ast_parser=False,
403
- has_tree_sitter=False,
404
- sast_patterns=0,
405
- secret_patterns=4,
406
- dep_parsers=["package.json", "composer.json", "composer.lock", "poetry.lock"],
407
- taint_sources=[],
408
- taint_sinks=[],
409
- ),
410
- Language.TOML: LanguageCapabilities(
411
- language=Language.TOML,
412
- has_ast_parser=False,
413
- has_tree_sitter=False,
414
- sast_patterns=0,
415
- secret_patterns=4,
416
- dep_parsers=["pyproject.toml", "Cargo.toml"],
417
- taint_sources=[],
418
- taint_sinks=[],
419
- ),
420
- Language.DOCKERFILE: LanguageCapabilities(
421
- language=Language.DOCKERFILE,
422
- has_ast_parser=False,
423
- has_tree_sitter=False,
424
- sast_patterns=0,
425
- secret_patterns=8,
426
- dep_parsers=["Dockerfile", "docker-compose.yml"],
427
- taint_sources=[],
428
- taint_sinks=["ADD http", "ADD https", "RUN curl", "RUN wget"],
429
- ),
430
- }
431
-
432
-
433
- def get_capabilities(language: Language) -> LanguageCapabilities:
434
- """Get capabilities for a language."""
435
- return LANGUAGE_CAPABILITIES.get(language, LanguageCapabilities(language=language))
436
-
437
-
438
- def get_supported_languages() -> List[Language]:
439
- """Get all supported languages."""
440
- return list(Language)[:-1] # Exclude UNKNOWN
441
-
442
-
443
- __all__ = [
444
- "Language",
445
- "detect_language",
446
- "is_binary_file",
447
- "LanguageCapabilities",
448
- "get_capabilities",
449
- "get_supported_languages",
450
- "LANGUAGE_GROUPS",
451
- "get_language_group",
452
- "EXTENSION_MAP",
453
- "FILENAME_PATTERNS",
454
- ]
@@ -1,172 +0,0 @@
1
- """License header + GPL contamination detection engine."""
2
- import re
3
- import os
4
- from pathlib import Path
5
- from orion.engine.config import EngineConfig
6
- from orion.engine.ir import OrionIR
7
- from orion.engine.results import EngineResult, Finding
8
-
9
-
10
- class Engine:
11
- name = "license"
12
- version = "1.0.0"
13
-
14
- SPDX_PATTERN = re.compile(r"SPDX-License-Identifier:\s*([A-Za-z0-9\.\-\+]+)")
15
- LICENSE_HEADER_PATTERNS = [
16
- re.compile(r"Copyright\s+\(c\)\s+\d{4}"),
17
- re.compile(r"Licensed under the\s+([A-Za-z0-9\.\-\+]+)"),
18
- re.compile(r"License:\s*([A-Za-z0-9\.\-\+]+)"),
19
- ]
20
-
21
- GPL_LICENSES = {
22
- "GPL-2.0", "GPL-3.0", "AGPL-3.0", "LGPL-2.1", "LGPL-3.0",
23
- "GPL-2.0-only", "GPL-2.0-or-later", "GPL-3.0-only", "GPL-3.0-or-later",
24
- "AGPL-3.0-only", "AGPL-3.0-or-later", "LGPL-2.1-only", "LGPL-2.1-or-later",
25
- "LGPL-3.0-only", "LGPL-3.0-or-later",
26
- }
27
-
28
- PERMISSIVE_LICENSES = {
29
- "MIT", "Apache-2.0", "BSD-2-Clause", "BSD-3-Clause", "ISC", "MPL-2.0",
30
- "Unlicense", "0BSD", "Zlib", "Python-2.0",
31
- }
32
-
33
- TEST_PATHS = {"test", "tests", "testing", "spec", "specs", "__pycache__", "vendor", "third_party", "generated"}
34
- GENERATED_MARKERS = ["generated", "auto-generated", "do not edit", "codegen"]
35
-
36
- async def check_availability(self) -> bool:
37
- return True
38
-
39
- def resource_limits(self):
40
- from orion.engine.config import ResourceLimits
41
- return ResourceLimits(max_cpu_seconds=30, max_memory_mb=128)
42
-
43
- async def run(self, ir: OrionIR, config: EngineConfig) -> EngineResult:
44
- try:
45
- text = ir.content.decode("utf-8", errors="replace")
46
- except Exception:
47
- text = str(ir.content)
48
-
49
- path = ir.metadata.get("path", "unknown")
50
- findings = []
51
-
52
- if self._is_test_or_generated(path, text):
53
- return EngineResult(engine=self.name, findings=findings, ok=True)
54
-
55
- has_spdx, spdx_license = self._check_spdx_header(text)
56
- has_license_hdr, hdr_license = self._check_license_header(text)
57
- detected_license = spdx_license or hdr_license
58
-
59
- # Focus on GPL/Copyleft contamination in proprietary projects
60
- if detected_license and self._is_gpl_contaminated(detected_license):
61
- findings.append(Finding(
62
- engine=self.name,
63
- severity="high",
64
- title=f"GPL/Copyleft Contamination Risk: {detected_license}",
65
- description=f"Strong copyleft license '{detected_license}' detected, which may impose open-source distribution requirements",
66
- location=path,
67
- metadata={
68
- "license": detected_license,
69
- "risk": "gpl_copyleft",
70
- "cwe": "CWE-1104",
71
- "confidence": 0.95,
72
- },
73
- ))
74
-
75
- return EngineResult(engine=self.name, findings=findings, ok=True)
76
-
77
- def _is_test_or_generated(self, path: str, text: str) -> bool:
78
- path_lower = path.lower()
79
- for test_dir in self.TEST_PATHS:
80
- if f"/{test_dir}/" in path_lower or path_lower.startswith(f"{test_dir}/"):
81
- return True
82
- for marker in self.GENERATED_MARKERS:
83
- if marker.lower() in text[:500].lower():
84
- return True
85
- return False
86
-
87
- def _check_spdx_header(self, text: str):
88
- lines = text.splitlines()[:30]
89
- header_text = "\n".join(lines)
90
- match = self.SPDX_PATTERN.search(header_text)
91
- if match:
92
- return True, match.group(1).strip()
93
- for pattern in self.LICENSE_HEADER_PATTERNS:
94
- match = pattern.search(header_text)
95
- if match:
96
- return True, match.group(1).strip() if match.groups() else "Unknown"
97
- return False, None
98
-
99
- def _check_root_license_files(self, path: str):
100
- findings = []
101
- p = Path(path)
102
- project_root = None
103
- for parent in p.parents:
104
- if (parent / ".git").exists() or (parent / "pyproject.toml").exists() or (parent / "package.json").exists():
105
- project_root = parent
106
- break
107
-
108
- if project_root:
109
- license_files = list(project_root.glob("LICENSE*")) + list(project_root.glob("COPYING*"))
110
- if not license_files:
111
- findings.append(Finding(
112
- engine=self.name,
113
- severity="low",
114
- title="Missing license file at project root",
115
- description="No LICENSE or COPYING file found in project root",
116
- location=str(project_root),
117
- metadata={
118
- "confidence": 0.8,
119
- "missing_license_file": True,
120
- "project_root": str(project_root),
121
- },
122
- ))
123
- else:
124
- for lf in license_files:
125
- try:
126
- content = lf.read_text(encoding="utf-8", errors="replace")
127
- for gpl in self.GPL_LICENSES:
128
- if gpl in content:
129
- findings.append(Finding(
130
- engine=self.name,
131
- severity="high",
132
- title=f"GPL/AGPL license file detected: {gpl}",
133
- description=f"Project root license file contains {gpl}",
134
- location=str(lf),
135
- metadata={
136
- "confidence": 0.95,
137
- "license": gpl,
138
- "file": str(lf),
139
- "cwe": "CWE-1104",
140
- },
141
- ))
142
- except Exception:
143
- pass
144
- return findings
145
-
146
- def _check_dep_gpl_conflicts(self, ir: OrionIR, file_license: str):
147
- findings = []
148
- if file_license not in self.PERMISSIVE_LICENSES:
149
- return findings
150
-
151
- metrics = ir.metadata.get("metrics", {})
152
- deps = metrics.get("deps", {})
153
- if isinstance(deps, dict):
154
- for dep_name, dep_info in deps.items():
155
- dep_license = dep_info.get("license") if isinstance(dep_info, dict) else None
156
- if dep_license and dep_license in self.GPL_LICENSES:
157
- findings.append(Finding(
158
- engine=self.name,
159
- severity="high",
160
- title=f"GPL/AGPL dependency in permissive project: {dep_name}",
161
- description=f"Dependency '{dep_name}' uses {dep_license} but project uses {file_license or 'permissive'} license",
162
- location=ir.metadata.get("path", "unknown"),
163
- metadata={
164
- "confidence": 0.85,
165
- "gpl_dep": dep_name,
166
- "license": dep_license,
167
- "project_license": file_license,
168
- "cwe": "CWE-1104",
169
- "cvss": 7.0,
170
- },
171
- ))
172
- return findings