@orionscanner/cli 0.1.0 → 0.1.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 +135 -248
- package/bin/orion.js +30 -29
- package/dist/orion.exe +0 -0
- package/package.json +8 -10
- 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
package/docs/API_REFERENCE.md
DELETED
|
@@ -1,211 +0,0 @@
|
|
|
1
|
-
# API Reference
|
|
2
|
-
|
|
3
|
-
## Core Classes
|
|
4
|
-
|
|
5
|
-
### OrionEngine
|
|
6
|
-
Main orchestrator — single entry point for all 38 engines.
|
|
7
|
-
|
|
8
|
-
```python
|
|
9
|
-
from orion.engine import OrionEngine, EngineConfig, ResourceLimits
|
|
10
|
-
from orion.engine.ir import OrionIR
|
|
11
|
-
from pathlib import Path
|
|
12
|
-
|
|
13
|
-
engine = OrionEngine()
|
|
14
|
-
ir = OrionIR(content=code.encode(), metadata={"path": "app.py", "language": "python"})
|
|
15
|
-
config = EngineConfig(resource_limits=ResourceLimits(max_cpu_seconds=60))
|
|
16
|
-
|
|
17
|
-
result = await engine.run([ir], config)
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
**Methods:**
|
|
21
|
-
- `register_engine(name: str, engine_cls: type)` — Register custom engine
|
|
22
|
-
- `run(irs: List[OrionIR], config: EngineConfig) -> EngineResult` — Run all engines
|
|
23
|
-
- `registered_count: int` — Number of registered engines
|
|
24
|
-
|
|
25
|
-
### EngineConfig
|
|
26
|
-
Configuration for scan execution.
|
|
27
|
-
|
|
28
|
-
```python
|
|
29
|
-
config = EngineConfig(
|
|
30
|
-
toggles={
|
|
31
|
-
"exclude": ["tests/", "vendor/", "*.min.js"],
|
|
32
|
-
"only_engines": ["sast", "secrets", "deps"],
|
|
33
|
-
"severity_threshold": "medium",
|
|
34
|
-
},
|
|
35
|
-
resource_limits=ResourceLimits(
|
|
36
|
-
max_cpu_seconds=120,
|
|
37
|
-
max_memory_mb=1024,
|
|
38
|
-
max_file_size_mb=10,
|
|
39
|
-
max_files=50000
|
|
40
|
-
),
|
|
41
|
-
network_policy=NetworkPolicy(
|
|
42
|
-
allow_outbound=False,
|
|
43
|
-
allowed_hosts=[]
|
|
44
|
-
)
|
|
45
|
-
)
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
### ResourceLimits
|
|
49
|
-
Per-engine resource constraints.
|
|
50
|
-
|
|
51
|
-
```python
|
|
52
|
-
ResourceLimits(
|
|
53
|
-
max_cpu_seconds=60, # Timeout per engine
|
|
54
|
-
max_memory_mb=512, # Memory limit
|
|
55
|
-
max_file_size_mb=10, # Max file size to scan
|
|
56
|
-
max_files=50000 # Max files per scan
|
|
57
|
-
)
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
### NetworkPolicy
|
|
61
|
-
Network access control.
|
|
62
|
-
|
|
63
|
-
```python
|
|
64
|
-
NetworkPolicy(
|
|
65
|
-
allow_outbound=False, # Block external calls
|
|
66
|
-
allowed_hosts=[] # Allowlist (if outbound enabled)
|
|
67
|
-
)
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
### OrionIR
|
|
71
|
-
Intermediate Representation — content-addressed, immutable.
|
|
72
|
-
|
|
73
|
-
```python
|
|
74
|
-
ir = OrionIR(
|
|
75
|
-
content=b"source code bytes",
|
|
76
|
-
metadata={
|
|
77
|
-
"path": "relative/path.py",
|
|
78
|
-
"language": "python",
|
|
79
|
-
"project_root": "/absolute/project/root"
|
|
80
|
-
}
|
|
81
|
-
)
|
|
82
|
-
|
|
83
|
-
# Properties
|
|
84
|
-
ir.address # SHA-256 hash (first 16 chars)
|
|
85
|
-
ir.content # Raw bytes
|
|
86
|
-
ir.metadata # Dict with path, language, project_root
|
|
87
|
-
```
|
|
88
|
-
|
|
89
|
-
### EngineResult
|
|
90
|
-
Aggregated scan results.
|
|
91
|
-
|
|
92
|
-
```python
|
|
93
|
-
result = EngineResult(
|
|
94
|
-
engine="orion", # Orchestrator name
|
|
95
|
-
findings=[Finding, ...], # List of findings
|
|
96
|
-
errors=["engine: error"], # Engine errors (silent to user)
|
|
97
|
-
metrics={ # Scan metadata
|
|
98
|
-
"elapsed_s": 1.23,
|
|
99
|
-
"engines_run": 38,
|
|
100
|
-
"files_scanned": 150
|
|
101
|
-
},
|
|
102
|
-
ok=True # False if any engine errored
|
|
103
|
-
)
|
|
104
|
-
```
|
|
105
|
-
|
|
106
|
-
### Finding
|
|
107
|
-
Individual security/quality issue.
|
|
108
|
-
|
|
109
|
-
```python
|
|
110
|
-
finding = Finding(
|
|
111
|
-
engine="sast", # Source engine
|
|
112
|
-
severity="critical", # critical|high|medium|low|info
|
|
113
|
-
title="SQL Injection", # Short title
|
|
114
|
-
description="User input in SQL", # Detailed description
|
|
115
|
-
location="app.py:42", # file:line
|
|
116
|
-
metadata={ # Evidence
|
|
117
|
-
"confidence": 0.95, # 0.0-1.0
|
|
118
|
-
"snippet": "query = f\"...\"", # Code context
|
|
119
|
-
"cwe": "CWE-89", # CWE ID
|
|
120
|
-
"cvss": 8.9, # CVSS score
|
|
121
|
-
"pattern": "sql_injection", # Pattern name
|
|
122
|
-
"file": "app.py", # File path
|
|
123
|
-
"line": 42 # Line number
|
|
124
|
-
}
|
|
125
|
-
)
|
|
126
|
-
```
|
|
127
|
-
|
|
128
|
-
## Engine Interface
|
|
129
|
-
|
|
130
|
-
All engines implement this interface:
|
|
131
|
-
|
|
132
|
-
```python
|
|
133
|
-
class Engine:
|
|
134
|
-
name = "engine_name"
|
|
135
|
-
version = "1.0.0"
|
|
136
|
-
|
|
137
|
-
async def check_availability(self) -> bool:
|
|
138
|
-
"""Return True if engine can run."""
|
|
139
|
-
return True
|
|
140
|
-
|
|
141
|
-
def resource_limits(self) -> ResourceLimits:
|
|
142
|
-
"""Return resource limits for this engine."""
|
|
143
|
-
return ResourceLimits(max_cpu_seconds=60, max_memory_mb=512)
|
|
144
|
-
|
|
145
|
-
async def run(self, ir: OrionIR, config: EngineConfig) -> EngineResult:
|
|
146
|
-
"""Analyze a single IR."""
|
|
147
|
-
# Language detection
|
|
148
|
-
language = ir.metadata.get("language")
|
|
149
|
-
if isinstance(language, str):
|
|
150
|
-
language = Language(language.lower())
|
|
151
|
-
|
|
152
|
-
# Route to language-specific analyzer
|
|
153
|
-
if language == Language.PYTHON:
|
|
154
|
-
return await self._run_python_ast(ir, config)
|
|
155
|
-
|
|
156
|
-
# Universal regex fallback
|
|
157
|
-
return self.universal.run(ir, config)
|
|
158
|
-
```
|
|
159
|
-
|
|
160
|
-
## CLI Usage
|
|
161
|
-
|
|
162
|
-
```bash
|
|
163
|
-
# Interactive menu
|
|
164
|
-
orion
|
|
165
|
-
|
|
166
|
-
# Direct scan
|
|
167
|
-
orion . --security # Security engines only
|
|
168
|
-
orion . --quality # Quality engines only
|
|
169
|
-
orion . --arch # Architecture engines only
|
|
170
|
-
orion . # Full audit (all 38 engines)
|
|
171
|
-
orion path/to/file.py # Single file
|
|
172
|
-
orion ./my_project # Directory scan
|
|
173
|
-
|
|
174
|
-
# Config
|
|
175
|
-
orion . --config-json '{"resource_limits":{"max_cpu_seconds":30}}'
|
|
176
|
-
```
|
|
177
|
-
|
|
178
|
-
## Reports
|
|
179
|
-
|
|
180
|
-
Generated in `ORION SCANNER REPORTS/`:
|
|
181
|
-
- `ScanType_target_timestamp.html` — Dark theme, sidebar, expandable findings, score/grade
|
|
182
|
-
- `ScanType_target_timestamp.json` — Machine-readable
|
|
183
|
-
- `ScanType_target_timestamp.txt` — Human-readable summary
|
|
184
|
-
|
|
185
|
-
## Language Detection
|
|
186
|
-
|
|
187
|
-
Automatic from file extension/filename:
|
|
188
|
-
|
|
189
|
-
| Extension | Language |
|
|
190
|
-
|-----------|----------|
|
|
191
|
-
| `.py` | python |
|
|
192
|
-
| `.js`, `.jsx`, `.mjs` | javascript |
|
|
193
|
-
| `.ts`, `.tsx` | typescript |
|
|
194
|
-
| `.java` | java |
|
|
195
|
-
| `.go` | go |
|
|
196
|
-
| `.rs` | rust |
|
|
197
|
-
| `.php` | php |
|
|
198
|
-
| `.rb` | ruby |
|
|
199
|
-
| `.cs` | csharp |
|
|
200
|
-
| `.html`, `.htm` | html |
|
|
201
|
-
| `.css`, `.scss` | css |
|
|
202
|
-
| `.yml`, `.yaml` | yaml |
|
|
203
|
-
| `.json` | json |
|
|
204
|
-
| `.toml` | toml |
|
|
205
|
-
| `.xml` | xml |
|
|
206
|
-
| `Dockerfile` | dockerfile |
|
|
207
|
-
| `.sh` | shell |
|
|
208
|
-
| `.ps1` | powershell |
|
|
209
|
-
| `.md` | markdown |
|
|
210
|
-
|
|
211
|
-
Special filenames: `Dockerfile`, `Makefile`, `package.json`, `requirements.txt`, `Cargo.toml`, `pom.xml`, `go.mod`, `composer.json`, `Gemfile`, `pyproject.toml`, `poetry.lock`, `yarn.lock`, `pnpm-lock.yaml`
|
package/docs/ARCHITECTURE.md
DELETED
|
@@ -1,183 +0,0 @@
|
|
|
1
|
-
# Orion Engine Architecture
|
|
2
|
-
|
|
3
|
-
## Overview
|
|
4
|
-
|
|
5
|
-
Orion Engine is a **polyglot code audit platform** with 38 native analysis engines, built as a single MIT-licensed Python package. No external tool dependencies (Semgrep, TruffleHog, Safety, Bandit, etc.).
|
|
6
|
-
|
|
7
|
-
## Core Design Principles
|
|
8
|
-
|
|
9
|
-
| Principle | Implementation |
|
|
10
|
-
|-----------|----------------|
|
|
11
|
-
| **Total Coverage** | 38 engines covering security, quality, architecture, supply chain, compliance |
|
|
12
|
-
| **Hardened** | No silent failures, secret zeroization, resource limits, per-engine timeouts |
|
|
13
|
-
| **Atomic** | Per-engine isolation - one failure doesn't cascade |
|
|
14
|
-
| **Native** | Pure Python, zero subprocess calls, zero external tool dependencies |
|
|
15
|
-
| **Orchestrated** | Single `OrionEngine().run()` entry point for all 38 engines |
|
|
16
|
-
| **Scalable** | Async/await, connection pooling, stateless engines, polyglot dispatch |
|
|
17
|
-
|
|
18
|
-
## Architecture Overview
|
|
19
|
-
|
|
20
|
-
```
|
|
21
|
-
��─────────────────────────────────────────────────────────────��
|
|
22
|
-
│ OrionEngine │
|
|
23
|
-
│ (Orchestrator - single run() entry point) │
|
|
24
|
-
��──────────────────────────��──────────────────────────────────��
|
|
25
|
-
│
|
|
26
|
-
��─────────────────��─────────────────��
|
|
27
|
-
�� �� ��
|
|
28
|
-
��────────────────�� ��────────────────�� ��────────────────��
|
|
29
|
-
│ Polyglot │ │ Engine │ │ Registry │
|
|
30
|
-
│ Dispatcher │ │ Registry │ │ (38 engines) │
|
|
31
|
-
��──────��─────────�� └────────────────�� └────────────────��
|
|
32
|
-
│
|
|
33
|
-
��
|
|
34
|
-
��─────────────────────────────────────────────────────────────��
|
|
35
|
-
│ Language Detection │
|
|
36
|
-
│ .py → Python .js/.ts → JS/TS .html → HTML │
|
|
37
|
-
│ .java → Java .go → Go .rs → Rust │
|
|
38
|
-
│ Dockerfile docker-compose .yaml/.json/.toml │
|
|
39
|
-
��──────────────────────────��────────────────────────────────────��
|
|
40
|
-
│
|
|
41
|
-
��─────────────────��─────────────────��
|
|
42
|
-
�� �� ��
|
|
43
|
-
��────────────────�� ��────────────────�� ��────────────────��
|
|
44
|
-
│ Python AST │ Universal Regex │ Language-Specific│
|
|
45
|
-
│ Analyzers │ (Fallback) │ Analyzers │
|
|
46
|
-
��────────────────�� └────────────────�� └────────────────��
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
## Core Components
|
|
50
|
-
|
|
51
|
-
### 1. OrionEngine (Orchestrator)
|
|
52
|
-
- Single entry point: `OrionEngine().run(irs, config)`
|
|
53
|
-
- Manages 38 engines concurrently with timeouts
|
|
54
|
-
- Aggregates findings, handles errors silently
|
|
55
|
-
|
|
56
|
-
### 2. Polyglot Dispatcher
|
|
57
|
-
- Detects language from file extension/filename
|
|
58
|
-
- Routes to language-specific analyzer or universal fallback
|
|
59
|
-
- Supports 20+ languages out of the box
|
|
60
|
-
|
|
61
|
-
### 3. Engine Registry
|
|
62
|
-
- Auto-discovers 38 engines on first use
|
|
63
|
-
- Maps engine name → engine class
|
|
64
|
-
- Provides health checks and resource limits
|
|
65
|
-
|
|
66
|
-
### 4. IR (Intermediate Representation)
|
|
67
|
-
- Content-addressed (SHA-256)
|
|
68
|
-
- Carries: content, path, language, project_root, metadata
|
|
69
|
-
- Immutable, serializable
|
|
70
|
-
|
|
71
|
-
## 38 Engines by Category
|
|
72
|
-
|
|
73
|
-
### Security (7)
|
|
74
|
-
| Engine | Purpose | Languages |
|
|
75
|
-
|--------|---------|-----------|
|
|
76
|
-
| `sast` | SQLi, XSS, CMDi, SSRF, path traversal, secrets, weak crypto | Python (AST), JS/TS (regex), Universal |
|
|
77
|
-
| `secrets` | API keys, tokens, passwords (regex + entropy) | All text files |
|
|
78
|
-
| `deps` | Vulnerable deps (requirements.txt, package.json, Cargo.toml, etc.) | Python, JS/TS, Go, Rust, Java, PHP, Ruby |
|
|
79
|
-
| `taint` | User input → dangerous sink tracking | Python (AST), JS/TS (planned) |
|
|
80
|
-
| `authorization` | Missing auth on routes | Python (Flask/FastAPI/Django), JS/TS (Express) |
|
|
81
|
-
| `sandbox_escape` | `__import__('os')`, `eval(compile())`, etc. | Python |
|
|
82
|
-
| `prompt_security` | Prompt injection detection | All text files |
|
|
83
|
-
|
|
84
|
-
### AST/IR Analysis (8)
|
|
85
|
-
`callgraph`, `cfg`, `symbol`, `dataflow`, `orphan`, `dead_import`, `wiring_trace`, `state`
|
|
86
|
-
|
|
87
|
-
### Quality (7)
|
|
88
|
-
`complexity`, `duplication`, `error_handling`, `logging_c`, `license`, `lint`, `test_coverage`
|
|
89
|
-
|
|
90
|
-
### Config/Infra (7)
|
|
91
|
-
`config_engine`, `config_validation`, `contract_probe`, `perf_guard`, `data_residency`, `regression`, `container`
|
|
92
|
-
|
|
93
|
-
### Meta/Supply Chain (9)
|
|
94
|
-
`chaos`, `chaos_config`, `noise`, `hunter`, `supply_chain_sbom`, `compliance`, `provenance`, `fp_learn`, `architecture`
|
|
95
|
-
|
|
96
|
-
## Data Flow
|
|
97
|
-
|
|
98
|
-
```
|
|
99
|
-
User Code → Files → IR List → OrionEngine.run()
|
|
100
|
-
│
|
|
101
|
-
��
|
|
102
|
-
��──────────────────────��
|
|
103
|
-
│ For each IR: │
|
|
104
|
-
│ 1. Detect language │
|
|
105
|
-
│ 2. Route to analyzer │
|
|
106
|
-
│ 3. Collect findings │
|
|
107
|
-
└──────────────────────��
|
|
108
|
-
│
|
|
109
|
-
��
|
|
110
|
-
��──────────────────────��
|
|
111
|
-
│ Aggregate & Dedupe │
|
|
112
|
-
│ Score & Grade │
|
|
113
|
-
│ Generate Reports │
|
|
114
|
-
└──────────────────────��
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
## Configuration
|
|
118
|
-
|
|
119
|
-
```python
|
|
120
|
-
config = EngineConfig(
|
|
121
|
-
toggles={
|
|
122
|
-
"exclude": ["tests/", "vendor/", "*.min.js"],
|
|
123
|
-
"only_engines": ["sast", "secrets", "deps"],
|
|
124
|
-
"severity_threshold": "medium",
|
|
125
|
-
},
|
|
126
|
-
resource_limits=ResourceLimits(
|
|
127
|
-
max_cpu_seconds=120,
|
|
128
|
-
max_memory_mb=1024,
|
|
129
|
-
max_files=50000
|
|
130
|
-
),
|
|
131
|
-
network_policy=NetworkPolicy(allow_outbound=False)
|
|
132
|
-
)
|
|
133
|
-
```
|
|
134
|
-
|
|
135
|
-
## Reports
|
|
136
|
-
|
|
137
|
-
Three formats generated in `ORION SCANNER REPORTS/`:
|
|
138
|
-
- **HTML** - Dark theme, sidebar nav, expandable findings, score/grade
|
|
139
|
-
- **JSON** - Machine-readable, CI/CD integration
|
|
140
|
-
- **TXT** - Human-readable summary
|
|
141
|
-
|
|
142
|
-
## Extending Engines
|
|
143
|
-
|
|
144
|
-
```python
|
|
145
|
-
class MyEngine:
|
|
146
|
-
name = "my_engine"
|
|
147
|
-
version = "1.0.0"
|
|
148
|
-
|
|
149
|
-
async def check_availability(self) -> bool: return True
|
|
150
|
-
|
|
151
|
-
def resource_limits(self):
|
|
152
|
-
return ResourceLimits(max_cpu_seconds=30, max_memory_mb=256)
|
|
153
|
-
|
|
154
|
-
async def run(self, ir: OrionIR, config: EngineConfig) -> EngineResult:
|
|
155
|
-
# Language-aware analysis
|
|
156
|
-
language = ir.metadata.get("language")
|
|
157
|
-
# ... analysis logic
|
|
158
|
-
return EngineResult(engine=self.name, findings=[...], ok=True)
|
|
159
|
-
|
|
160
|
-
# Register
|
|
161
|
-
EngineRegistry().register("my_engine", MyEngine)
|
|
162
|
-
```
|
|
163
|
-
|
|
164
|
-
## Polyglot Support Matrix
|
|
165
|
-
|
|
166
|
-
| Language | SAST | Secrets | Deps | Taint | Callgraph | Config |
|
|
167
|
-
|----------|------|---------|------|-------|-----------|--------|
|
|
168
|
-
| Python | �� AST | �� | �� | �� AST | �� | �� |
|
|
169
|
-
| JavaScript | �� Regex | �� | �� | ��� Planned | ��� | �� |
|
|
170
|
-
| TypeScript | �� Regex | �� | �� | ��� Planned | ��� | �� |
|
|
171
|
-
| Java | ��� Regex | �� | �� | ��� | ��� | �� |
|
|
172
|
-
| Go | ��� Regex | �� | �� | ��� | ��� | �� |
|
|
173
|
-
| Rust | ��� Regex | �� | �� | ��� | ��� | �� |
|
|
174
|
-
| PHP | ��� Regex | �� | �� | ��� | ��� | �� |
|
|
175
|
-
| Ruby | ��� Regex | �� | �� | ��� | ��� | �� |
|
|
176
|
-
| C/C++ | ��� Regex | �� | ��� | ��� | ��� | �� |
|
|
177
|
-
| C# | ��� Regex | �� | �� | ��� | ��� | �� |
|
|
178
|
-
| Go/Rust/JS/TS | Universal | �� | �� | Universal | ��� | �� |
|
|
179
|
-
| HTML/CSS | ��� Regex | �� | ��� | Universal | ��� | ��� |
|
|
180
|
-
| Dockerfile | ��� Regex | �� | �� | Universal | ��� | �� |
|
|
181
|
-
| YAML/JSON/TOML | ��� | �� | �� | ��� | ��� | �� |
|
|
182
|
-
|
|
183
|
-
��� = Full support | ��� = Regex/Universal fallback | ��� = Not applicable
|
package/docs/CHANGELOG.md
DELETED
|
@@ -1,112 +0,0 @@
|
|
|
1
|
-
# Changelog
|
|
2
|
-
|
|
3
|
-
All notable changes to Orion Engine.
|
|
4
|
-
|
|
5
|
-
## [0.1.0] - 2026-08-14
|
|
6
|
-
|
|
7
|
-
### Added
|
|
8
|
-
- **38 Native Engines** — SAST, Secrets, Deps, Taint, Callgraph, CFG, Symbol, Dataflow, Authorization, Orphan, Prompt Security, Contract Probe, Wiring Trace, State, License, Complexity, Duplication, Dead Import, Error Handling, Logging, Config Engine, Chaos, Chaos Config, Regression, Perf Guard, Data Residency, Noise, Supply Chain SBOM, Hunter, Lint, Architecture, Test Coverage, Container, Compliance, Provenance, FP Learn, Sandbox Escape, Config Validation
|
|
9
|
-
- **Polyglot Support** — 20+ languages via automatic detection and universal regex fallback
|
|
10
|
-
- **Polyglot Dispatcher** — Routes files to language-specific analyzers or universal regex
|
|
11
|
-
- **Language Infrastructure** — 20+ languages, capabilities registry, extension mapping
|
|
12
|
-
- **Professional HTML Reports** — Dark theme, sidebar nav, expandable findings, score/grade (A-F), responsive design
|
|
13
|
-
- **Interactive CLI** — Menu system (9 options), multi-colored spinner, auto clear-screen
|
|
14
|
-
- **Three Report Formats** — HTML (dark theme), JSON (CI/CD), TXT (human-readable)
|
|
15
|
-
- **False Positive Learning** — Reads `.orion-feedback.json`, reduces confidence on matches
|
|
16
|
-
- **Compliance Mapping** — GDPR, PCI-DSS, SOC2, HIPAA
|
|
17
|
-
- **SBOM Generation** — CycloneDX format with purl, hashes, licenses
|
|
18
|
-
- **Provenance Attestation** — SLSA-like: git commit, file hashes, builder identity
|
|
19
|
-
- **FP Learning** — Reads feedback, reduces confidence on similar patterns
|
|
20
|
-
- **Config Validation** — Self-validates OrionEngine config
|
|
21
|
-
|
|
22
|
-
### Core Platform
|
|
23
|
-
- `OrionEngine` — Single orchestrator, async, 38 engines concurrent
|
|
24
|
-
- `EngineConfig` — Toggles, resource limits, network policy
|
|
25
|
-
- `ResourceLimits` — CPU, memory, file size, file count limits
|
|
26
|
-
- `NetworkPolicy` — Outbound control with allowlist
|
|
27
|
-
- `OrionIR` — Content-addressed (SHA-256), immutable
|
|
28
|
-
- `EngineResult` / `Finding` — Structured results with evidence
|
|
29
|
-
- `EngineRegistry` — Auto-discovery of 38 engines
|
|
30
|
-
|
|
31
|
-
### Language Support (20+)
|
|
32
|
-
Python, JavaScript, TypeScript, Java, Go, Rust, PHP, Ruby, C/C++, C#, HTML, CSS, YAML, JSON, TOML, XML, Dockerfile, Shell, PowerShell, Markdown
|
|
33
|
-
|
|
34
|
-
### Security Engines
|
|
35
|
-
- **sast** — SQLi, XSS, CMDi, SSRF, path traversal, hardcoded creds, weak crypto, deserialization
|
|
36
|
-
- **secrets** — API keys, tokens, passwords (regex + entropy), test pattern filtering
|
|
37
|
-
- **deps** — Vulnerable deps (requirements.txt, package.json, Cargo.toml, go.mod, pom.xml, composer.json, Gemfile, Pipfile, poetry.lock, yarn.lock, pnpm-lock.yaml)
|
|
38
|
-
- **taint** — User input → dangerous sinks (SQL, shell, code exec, template, deserialization)
|
|
39
|
-
- **authorization** — Missing auth on Flask/FastAPI/Django/Express/Spring/Gin/Laravel/Rails/ASP.NET routes
|
|
40
|
-
- **sandbox_escape** — `__import__('os')`, `eval(compile())`, `ctypes`, `__subclasses__()`, `Function` constructor, `Runtime.exec`, `Process.Start`
|
|
41
|
-
- **prompt_security** — Prompt injection, jailbreak, base64 payloads, special tokens
|
|
42
|
-
|
|
43
|
-
### AST/IR Analysis Engines
|
|
44
|
-
- **callgraph** — Function calls, recursion, undefined functions, deep chains
|
|
45
|
-
- **cfg** — Control flow: unreachable code, infinite loops, missing returns, cyclomatic complexity
|
|
46
|
-
- **symbol** — Symbol table: shadowed builtins, undefined names, unused imports, late-binding closures
|
|
47
|
-
- **dataflow** — Variable def/use: use-before-def, dead stores, mutable defaults, global mutations
|
|
48
|
-
- **orphan** — Zero incoming imports (excludes entry points)
|
|
49
|
-
- **dead_import** — Unused imports across scopes
|
|
50
|
-
- **wiring_trace** — Config → usage tracing
|
|
51
|
-
- **state** — Mutable globals, class attrs, function defaults, `global`/`nonlocal`
|
|
52
|
-
|
|
53
|
-
### Quality Engines
|
|
54
|
-
- **complexity** — Cyclomatic & cognitive complexity (>10/20/50)
|
|
55
|
-
- **duplication** — Sliding window token normalization, SHA256 clustering
|
|
56
|
-
- **error_handling** — Bare except, swallowed errors, lost causes, assert in prod, sys.exit in libs
|
|
57
|
-
- **logging_c** — print() in prod, PII in logs, missing getLogger, DEBUG in prod, no structured logging
|
|
58
|
-
- **license** — SPDX headers, GPL/AGPL detection, root LICENSE, dep conflicts
|
|
59
|
-
- **lint** — Unused vars, undefined names, import order, line length, docstrings, wildcards, ==None, bare except
|
|
60
|
-
- **test_coverage** — Untested public functions, test-only-mocks, no assertions, long tests, missing conftest
|
|
61
|
-
|
|
62
|
-
### Config/Infra Engines
|
|
63
|
-
- **config_engine** — Required keys, types, placeholders, secrets, duplicates, URLs, emails
|
|
64
|
-
- **chaos** — No retry/circuit-breaker/timeout/idempotency, global locks, direct instantiation
|
|
65
|
-
- **chaos_config** — Empty/null/negative/huge values, invalid enums, circular refs, long strings
|
|
66
|
-
- **regression** — Monkey patching, dynamic imports, sys.modules mutation, builtins/env mutation
|
|
67
|
-
- **perf_guard** — N+1 queries, O(n²) loops, string concat, large in-memory, missing pagination, sync I/O in async
|
|
68
|
-
- **data_residency** — PII: emails, phones, SSN, credit cards (Luhn), IPs, UUIDs, API keys
|
|
69
|
-
- **container** — Dockerfile, docker-compose, K8s YAML, Helm: root, latest tag, secrets, privileged, host namespaces, healthcheck, limits
|
|
70
|
-
|
|
71
|
-
### Meta/Supply Chain Engines
|
|
72
|
-
- **noise** — Low confidence + recent changes + high churn, duplicates, generated files
|
|
73
|
-
- **hunter** — Cross-engine correlation: SQLi+auth=CRITICAL, XSS+CSP=HIGH, secret+public=CRITICAL
|
|
74
|
-
- **supply_chain_sbom** — CycloneDX: purl, hashes, licenses, external refs
|
|
75
|
-
- **compliance** — GDPR (Art 25/32/33), PCI-DSS (Req 3/4/6/8), SOC2 (CC6.1/6.7/7.2), HIPAA (164.312)
|
|
76
|
-
- **provenance** — Git commit/tag/branch, SHA256 file hashes, builder identity, dep hashes
|
|
77
|
-
- **fp_learn** — Reads `.orion-feedback.json`, reduces confidence by 0.3 on feature match
|
|
78
|
-
- **config_validation** — Validates paths, globs, limits, network policy, parallelism, timeout
|
|
79
|
-
- **architecture** — Cyclic imports, layer violations (domain→app→infra→pres), god classes/modules, feature envy
|
|
80
|
-
|
|
81
|
-
### Reports
|
|
82
|
-
- **HTML** — Dark theme, fixed sidebar, expandable findings, score/grade (A-F), responsive, print-ready
|
|
83
|
-
- **JSON** — Machine-readable, CI/CD ready
|
|
84
|
-
- **TXT** — Human-readable summary
|
|
85
|
-
|
|
86
|
-
### CLI
|
|
87
|
-
- `orion` — Interactive menu (9 options)
|
|
88
|
-
- `orion .` — Full audit
|
|
89
|
-
- `orion . --security` — Security engines only
|
|
90
|
-
- `orion . --quality` — Quality engines only
|
|
91
|
-
- `orion . --arch` — Architecture engines only
|
|
92
|
-
- `orion path` — Scan file or directory
|
|
93
|
-
- `orion . --config-json '{}'` — Custom config
|
|
94
|
-
|
|
95
|
-
### Removed
|
|
96
|
-
- All GPL/AGPL dependencies (Semgrep, TruffleHog, Safety, Bandit)
|
|
97
|
-
- External tool subprocess calls
|
|
98
|
-
- Old adapter/check/intelligence/reporting architecture
|
|
99
|
-
- Benchmarks, fixtures, test suites (legacy)
|
|
100
|
-
- Docker, npm, GUI, serve, sandbox modules
|
|
101
|
-
|
|
102
|
-
## Upgrade Guide
|
|
103
|
-
|
|
104
|
-
### From 0.x (Legacy)
|
|
105
|
-
- Complete rewrite — no migration path
|
|
106
|
-
- Install fresh: `pip install -e .`
|
|
107
|
-
- Config format changed — use new `EngineConfig`
|
|
108
|
-
- API changed — use `OrionEngine().run(irs, config)`
|
|
109
|
-
|
|
110
|
-
---
|
|
111
|
-
|
|
112
|
-
**Orion Engine v0.1.0** — 38 native MIT engines, polyglot, zero external deps, professional reports.
|
package/docs/CONTRIBUTING.md
DELETED
|
@@ -1,157 +0,0 @@
|
|
|
1
|
-
# Contributing
|
|
2
|
-
|
|
3
|
-
## Development Setup
|
|
4
|
-
|
|
5
|
-
```bash
|
|
6
|
-
git clone https://github.com/chandrahotha/OrionEngine
|
|
7
|
-
cd OrionEngine
|
|
8
|
-
pip install -e .[dev]
|
|
9
|
-
pre-commit install
|
|
10
|
-
```
|
|
11
|
-
|
|
12
|
-
## Code Style
|
|
13
|
-
|
|
14
|
-
- **Python 3.10+** — type hints required
|
|
15
|
-
- **Black** — formatting (`black src/`)
|
|
16
|
-
- **Ruff** — linting (`ruff check src/`)
|
|
17
|
-
- **MyPy** — type checking (`mypy src/`)
|
|
18
|
-
- **Async first** — all engines async
|
|
19
|
-
|
|
20
|
-
## Adding a New Engine
|
|
21
|
-
|
|
22
|
-
1. Create directory: `src/orion/engine/my_engine/`
|
|
23
|
-
2. Create `engine.py`:
|
|
24
|
-
|
|
25
|
-
```python
|
|
26
|
-
from orion.engine.languages import detect_language, Language, get_capabilities
|
|
27
|
-
from orion.engine.dispatcher import UniversalRegexAnalyzer, PolyglotEngine
|
|
28
|
-
from orion.engine.config import EngineConfig, ResourceLimits
|
|
29
|
-
from orion.engine.ir import OrionIR
|
|
30
|
-
from orion.engine.results import EngineResult, Finding
|
|
31
|
-
|
|
32
|
-
class Engine:
|
|
33
|
-
name = "my_engine"
|
|
34
|
-
version = "1.0.0"
|
|
35
|
-
|
|
36
|
-
def __init__(self):
|
|
37
|
-
self.universal = UniversalRegexAnalyzer(
|
|
38
|
-
categories=["secrets", "sql_injection", "xss", "command_injection"]
|
|
39
|
-
)
|
|
40
|
-
|
|
41
|
-
async def check_availability(self) -> bool:
|
|
42
|
-
return True
|
|
43
|
-
|
|
44
|
-
def resource_limits(self) -> ResourceLimits:
|
|
45
|
-
return ResourceLimits(max_cpu_seconds=60, max_memory_mb=512)
|
|
46
|
-
|
|
47
|
-
async def run(self, ir: OrionIR, config: EngineConfig) -> EngineResult:
|
|
48
|
-
language = ir.metadata.get("language")
|
|
49
|
-
if isinstance(language, str):
|
|
50
|
-
try:
|
|
51
|
-
language = Language(language.lower())
|
|
52
|
-
except ValueError:
|
|
53
|
-
from orion.engine.languages import detect_language
|
|
54
|
-
language = detect_language(ir.metadata.get("path", ""))
|
|
55
|
-
|
|
56
|
-
if language == Language.PYTHON:
|
|
57
|
-
return await self._run_python(ir, config)
|
|
58
|
-
|
|
59
|
-
return self.universal.run(ir, config)
|
|
60
|
-
|
|
61
|
-
async def _run_python(self, ir: OrionIR, config: EngineConfig) -> EngineResult:
|
|
62
|
-
# Python-specific AST analysis
|
|
63
|
-
findings = []
|
|
64
|
-
# ... your analysis
|
|
65
|
-
return EngineResult(engine=self.name, findings=findings, ok=True)
|
|
66
|
-
|
|
67
|
-
# Backward compatibility
|
|
68
|
-
Engine = Engine
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
3. Register in `src/orion/engine/registry.py` (auto-discovery works automatically)
|
|
72
|
-
|
|
73
|
-
## Testing
|
|
74
|
-
|
|
75
|
-
```bash
|
|
76
|
-
# Run all tests
|
|
77
|
-
pytest tests/
|
|
78
|
-
|
|
79
|
-
# Run specific engine tests
|
|
80
|
-
pytest tests/test_sast.py -v
|
|
81
|
-
|
|
82
|
-
# Type check
|
|
83
|
-
mypy src/
|
|
84
|
-
|
|
85
|
-
# Lint
|
|
86
|
-
ruff check src/
|
|
87
|
-
|
|
88
|
-
# Format
|
|
89
|
-
black src/
|
|
90
|
-
```
|
|
91
|
-
|
|
92
|
-
## Engine Guidelines
|
|
93
|
-
|
|
94
|
-
1. **No silent failures** — wrap in try/except, return errors in `EngineResult.errors`
|
|
95
|
-
2. **Confidence scoring** — every finding needs `metadata["confidence"]` (0.0-1.0)
|
|
96
|
-
3. **Evidence** — include `snippet`, `cwe`, `cvss`, `line`, `file` in metadata
|
|
97
|
-
4. **Language support** — use `detect_language()`, `get_capabilities()`, `UniversalRegexAnalyzer`
|
|
98
|
-
5. **Resource limits** — respect `config.get_limits().max_cpu_seconds`
|
|
99
|
-
5. **No silent failures** — engine errors go to `EngineResult.errors`, not stdout
|
|
100
|
-
6. **Async** — `run()` must be async, use `asyncio.wait_for` for timeouts
|
|
101
|
-
|
|
102
|
-
## Polyglot Support
|
|
103
|
-
|
|
104
|
-
Add language support to your engine:
|
|
105
|
-
|
|
106
|
-
```python
|
|
107
|
-
async def run(self, ir: OrionIR, config: EngineConfig) -> EngineResult:
|
|
108
|
-
language = ir.metadata.get("language")
|
|
109
|
-
if isinstance(language, str):
|
|
110
|
-
try:
|
|
111
|
-
language = Language(language.lower())
|
|
112
|
-
except ValueError:
|
|
113
|
-
from orion.engine.languages import detect_language
|
|
114
|
-
language = detect_language(ir.metadata.get("path", ""))
|
|
115
|
-
|
|
116
|
-
caps = get_capabilities(language)
|
|
117
|
-
|
|
118
|
-
if language == Language.PYTHON:
|
|
119
|
-
return await self._run_python_ast(ir, config)
|
|
120
|
-
elif language in (Language.JAVASCRIPT, Language.TYPESCRIPT):
|
|
121
|
-
return await self._run_js_regex(ir, config)
|
|
122
|
-
elif language in (Language.JAVA, Language.GO, Language.RUST, Language.PHP, Language.RUBY):
|
|
123
|
-
return await self._run_universal(ir, config)
|
|
124
|
-
|
|
125
|
-
return self.universal.run(ir, config)
|
|
126
|
-
```
|
|
127
|
-
|
|
128
|
-
## Adding Language Support
|
|
129
|
-
|
|
130
|
-
1. Add to `Language` enum in `languages.py`
|
|
131
|
-
2. Add extension mapping in `EXTENSION_MAP`
|
|
132
|
-
3. Add `LanguageCapabilities` in `LANGUAGE_CAPABILITIES`
|
|
133
|
-
4. Add patterns to `UNIVERSAL_PATTERNS` in `dispatcher.py`
|
|
134
|
-
5. Test with sample files
|
|
135
|
-
|
|
136
|
-
## Reporting Bugs
|
|
137
|
-
|
|
138
|
-
Use GitHub Issues with:
|
|
139
|
-
- Orion version (`orion --version` or check `pyproject.toml`)
|
|
140
|
-
- Python version
|
|
141
|
-
- OS
|
|
142
|
-
- Minimal reproduction code
|
|
143
|
-
- Expected vs actual behavior
|
|
144
|
-
- Engine(s) involved
|
|
145
|
-
|
|
146
|
-
## Pull Request Process
|
|
147
|
-
|
|
148
|
-
1. Fork & create feature branch
|
|
149
|
-
2. Write tests for new functionality
|
|
150
|
-
3. Ensure all tests pass
|
|
151
|
-
4. Run `black`, `ruff`, `mypy`
|
|
152
|
-
5. Update docs if needed
|
|
153
|
-
6. Submit PR with clear description
|
|
154
|
-
|
|
155
|
-
## License
|
|
156
|
-
|
|
157
|
-
MIT — all contributions must be MIT-compatible.
|