dravix-agent 0.1.0
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/.claude/settings.example.json +30 -0
- package/ARCHITECTURE.md +410 -0
- package/LICENSE +21 -0
- package/README.md +153 -0
- package/ROADMAP.md +117 -0
- package/data/vulnkb.json +666 -0
- package/dist/bin/aegis.d.ts +3 -0
- package/dist/bin/aegis.d.ts.map +1 -0
- package/dist/bin/aegis.js +489 -0
- package/dist/bin/aegis.js.map +1 -0
- package/dist/cache.d.ts +9 -0
- package/dist/cache.d.ts.map +1 -0
- package/dist/cache.js +146 -0
- package/dist/cache.js.map +1 -0
- package/dist/engines/ai-sinks.d.ts +52 -0
- package/dist/engines/ai-sinks.d.ts.map +1 -0
- package/dist/engines/ai-sinks.js +204 -0
- package/dist/engines/ai-sinks.js.map +1 -0
- package/dist/engines/eslint.d.ts +9 -0
- package/dist/engines/eslint.d.ts.map +1 -0
- package/dist/engines/eslint.js +245 -0
- package/dist/engines/eslint.js.map +1 -0
- package/dist/engines/joern.d.ts +3 -0
- package/dist/engines/joern.d.ts.map +1 -0
- package/dist/engines/joern.js +98 -0
- package/dist/engines/joern.js.map +1 -0
- package/dist/engines/js-sinks.d.ts +70 -0
- package/dist/engines/js-sinks.d.ts.map +1 -0
- package/dist/engines/js-sinks.js +370 -0
- package/dist/engines/js-sinks.js.map +1 -0
- package/dist/engines/llm-critic.d.ts +130 -0
- package/dist/engines/llm-critic.d.ts.map +1 -0
- package/dist/engines/llm-critic.js +551 -0
- package/dist/engines/llm-critic.js.map +1 -0
- package/dist/engines/pragma.d.ts +20 -0
- package/dist/engines/pragma.d.ts.map +1 -0
- package/dist/engines/pragma.js +83 -0
- package/dist/engines/pragma.js.map +1 -0
- package/dist/engines/property-test.d.ts +3 -0
- package/dist/engines/property-test.d.ts.map +1 -0
- package/dist/engines/property-test.js +134 -0
- package/dist/engines/property-test.js.map +1 -0
- package/dist/engines/pyright.d.ts +10 -0
- package/dist/engines/pyright.d.ts.map +1 -0
- package/dist/engines/pyright.js +143 -0
- package/dist/engines/pyright.js.map +1 -0
- package/dist/engines/pysa.d.ts +3 -0
- package/dist/engines/pysa.d.ts.map +1 -0
- package/dist/engines/pysa.js +83 -0
- package/dist/engines/pysa.js.map +1 -0
- package/dist/engines/python-sinks.d.ts +82 -0
- package/dist/engines/python-sinks.d.ts.map +1 -0
- package/dist/engines/python-sinks.js +459 -0
- package/dist/engines/python-sinks.js.map +1 -0
- package/dist/engines/registry.d.ts +26 -0
- package/dist/engines/registry.d.ts.map +1 -0
- package/dist/engines/registry.js +70 -0
- package/dist/engines/registry.js.map +1 -0
- package/dist/engines/secret-scan.d.ts +22 -0
- package/dist/engines/secret-scan.d.ts.map +1 -0
- package/dist/engines/secret-scan.js +179 -0
- package/dist/engines/secret-scan.js.map +1 -0
- package/dist/engines/semgrep.d.ts +10 -0
- package/dist/engines/semgrep.d.ts.map +1 -0
- package/dist/engines/semgrep.js +200 -0
- package/dist/engines/semgrep.js.map +1 -0
- package/dist/engines/treesitter.d.ts +18 -0
- package/dist/engines/treesitter.d.ts.map +1 -0
- package/dist/engines/treesitter.js +135 -0
- package/dist/engines/treesitter.js.map +1 -0
- package/dist/engines/tsc.d.ts +10 -0
- package/dist/engines/tsc.d.ts.map +1 -0
- package/dist/engines/tsc.js +142 -0
- package/dist/engines/tsc.js.map +1 -0
- package/dist/engines/types.d.ts +47 -0
- package/dist/engines/types.d.ts.map +1 -0
- package/dist/engines/types.js +27 -0
- package/dist/engines/types.js.map +1 -0
- package/dist/findings.d.ts +121 -0
- package/dist/findings.d.ts.map +1 -0
- package/dist/findings.js +98 -0
- package/dist/findings.js.map +1 -0
- package/dist/hooks/claude-code.d.ts +3 -0
- package/dist/hooks/claude-code.d.ts.map +1 -0
- package/dist/hooks/claude-code.js +187 -0
- package/dist/hooks/claude-code.js.map +1 -0
- package/dist/index/context.d.ts +127 -0
- package/dist/index/context.d.ts.map +1 -0
- package/dist/index/context.js +267 -0
- package/dist/index/context.js.map +1 -0
- package/dist/index/embeddings.d.ts +68 -0
- package/dist/index/embeddings.d.ts.map +1 -0
- package/dist/index/embeddings.js +570 -0
- package/dist/index/embeddings.js.map +1 -0
- package/dist/index/graph_routing.d.ts +36 -0
- package/dist/index/graph_routing.d.ts.map +1 -0
- package/dist/index/graph_routing.js +170 -0
- package/dist/index/graph_routing.js.map +1 -0
- package/dist/index/joern.d.ts +76 -0
- package/dist/index/joern.d.ts.map +1 -0
- package/dist/index/joern.js +782 -0
- package/dist/index/joern.js.map +1 -0
- package/dist/index/property-test.d.ts +88 -0
- package/dist/index/property-test.d.ts.map +1 -0
- package/dist/index/property-test.js +466 -0
- package/dist/index/property-test.js.map +1 -0
- package/dist/index/proto/scip.proto +897 -0
- package/dist/index/pysa.d.ts +91 -0
- package/dist/index/pysa.d.ts.map +1 -0
- package/dist/index/pysa.js +617 -0
- package/dist/index/pysa.js.map +1 -0
- package/dist/index/scip.d.ts +76 -0
- package/dist/index/scip.d.ts.map +1 -0
- package/dist/index/scip.js +541 -0
- package/dist/index/scip.js.map +1 -0
- package/dist/index/vulrag.d.ts +86 -0
- package/dist/index/vulrag.d.ts.map +1 -0
- package/dist/index/vulrag.js +242 -0
- package/dist/index/vulrag.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/install/claude-code.d.ts +31 -0
- package/dist/install/claude-code.d.ts.map +1 -0
- package/dist/install/claude-code.js +447 -0
- package/dist/install/claude-code.js.map +1 -0
- package/dist/lang.d.ts +5 -0
- package/dist/lang.d.ts.map +1 -0
- package/dist/lang.js +52 -0
- package/dist/lang.js.map +1 -0
- package/dist/learning/suppressions.d.ts +70 -0
- package/dist/learning/suppressions.d.ts.map +1 -0
- package/dist/learning/suppressions.js +179 -0
- package/dist/learning/suppressions.js.map +1 -0
- package/dist/mcp/server.d.ts +2 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +187 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/tools/explain.d.ts +58 -0
- package/dist/mcp/tools/explain.d.ts.map +1 -0
- package/dist/mcp/tools/explain.js +60 -0
- package/dist/mcp/tools/explain.js.map +1 -0
- package/dist/mcp/tools/precheck.d.ts +29 -0
- package/dist/mcp/tools/precheck.d.ts.map +1 -0
- package/dist/mcp/tools/precheck.js +42 -0
- package/dist/mcp/tools/precheck.js.map +1 -0
- package/dist/mcp/tools/validate.d.ts +73 -0
- package/dist/mcp/tools/validate.d.ts.map +1 -0
- package/dist/mcp/tools/validate.js +66 -0
- package/dist/mcp/tools/validate.js.map +1 -0
- package/dist/mcp/warm.d.ts +88 -0
- package/dist/mcp/warm.d.ts.map +1 -0
- package/dist/mcp/warm.js +331 -0
- package/dist/mcp/warm.js.map +1 -0
- package/dist/orchestrator.d.ts +46 -0
- package/dist/orchestrator.d.ts.map +1 -0
- package/dist/orchestrator.js +596 -0
- package/dist/orchestrator.js.map +1 -0
- package/dist/policy.d.ts +51 -0
- package/dist/policy.d.ts.map +1 -0
- package/dist/policy.js +201 -0
- package/dist/policy.js.map +1 -0
- package/dist/risk.d.ts +31 -0
- package/dist/risk.d.ts.map +1 -0
- package/dist/risk.js +92 -0
- package/dist/risk.js.map +1 -0
- package/dist/stats.d.ts +72 -0
- package/dist/stats.d.ts.map +1 -0
- package/dist/stats.js +217 -0
- package/dist/stats.js.map +1 -0
- package/dist/telemetry/collector.d.ts +10 -0
- package/dist/telemetry/collector.d.ts.map +1 -0
- package/dist/telemetry/collector.js +75 -0
- package/dist/telemetry/collector.js.map +1 -0
- package/dist/telemetry/consent.d.ts +9 -0
- package/dist/telemetry/consent.d.ts.map +1 -0
- package/dist/telemetry/consent.js +42 -0
- package/dist/telemetry/consent.js.map +1 -0
- package/dist/telemetry/installation.d.ts +2 -0
- package/dist/telemetry/installation.d.ts.map +1 -0
- package/dist/telemetry/installation.js +32 -0
- package/dist/telemetry/installation.js.map +1 -0
- package/dist/telemetry/sanitizer.d.ts +5 -0
- package/dist/telemetry/sanitizer.d.ts.map +1 -0
- package/dist/telemetry/sanitizer.js +60 -0
- package/dist/telemetry/sanitizer.js.map +1 -0
- package/dist/telemetry/types.d.ts +39 -0
- package/dist/telemetry/types.d.ts.map +1 -0
- package/dist/telemetry/types.js +4 -0
- package/dist/telemetry/types.js.map +1 -0
- package/dist/telemetry/uploader.d.ts +12 -0
- package/dist/telemetry/uploader.d.ts.map +1 -0
- package/dist/telemetry/uploader.js +92 -0
- package/dist/telemetry/uploader.js.map +1 -0
- package/dist/util/logger.d.ts +19 -0
- package/dist/util/logger.d.ts.map +1 -0
- package/dist/util/logger.js +58 -0
- package/dist/util/logger.js.map +1 -0
- package/dist/util/safe-paths.d.ts +8 -0
- package/dist/util/safe-paths.d.ts.map +1 -0
- package/dist/util/safe-paths.js +102 -0
- package/dist/util/safe-paths.js.map +1 -0
- package/dist/util/subprocess.d.ts +32 -0
- package/dist/util/subprocess.d.ts.map +1 -0
- package/dist/util/subprocess.js +137 -0
- package/dist/util/subprocess.js.map +1 -0
- package/package.json +93 -0
|
@@ -0,0 +1,459 @@
|
|
|
1
|
+
import { makeFindingId } from "../findings.js";
|
|
2
|
+
import { isLineSuppressed, isTestOrFixturePath } from "./pragma.js";
|
|
3
|
+
// ── Helpers ──────────────────────────────────────────────────────────────
|
|
4
|
+
/** A snippet "looks tainted" if it is NOT a pure string literal. We treat
|
|
5
|
+
* f-strings as tainted because their substituted parts are interpolation —
|
|
6
|
+
* which is the entire point of an injection bug. */
|
|
7
|
+
function looksTainted(arg) {
|
|
8
|
+
const s = arg.trim();
|
|
9
|
+
if (s === "")
|
|
10
|
+
return false;
|
|
11
|
+
// f-string: ALWAYS tainted in a sink context (it interpolates).
|
|
12
|
+
if (/^[rRbBuU]?[fF]['"]/.test(s))
|
|
13
|
+
return true;
|
|
14
|
+
// Triple-quoted literal (basic check): treat as untainted IF no expansion.
|
|
15
|
+
if (/^[rRbBuU]?(?:"""|''')/.test(s))
|
|
16
|
+
return false;
|
|
17
|
+
// Plain string literal (no concat / format / mod): untainted.
|
|
18
|
+
if (/^[rRbBuU]?['"]/.test(s)) {
|
|
19
|
+
// Look for concat indicators: + var, % var, .format(, .join(
|
|
20
|
+
if (/[+%]\s*[a-zA-Z_]/.test(s))
|
|
21
|
+
return true;
|
|
22
|
+
if (/\.format\s*\(/.test(s))
|
|
23
|
+
return true;
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
// Anything else is a variable / function call / expression → tainted.
|
|
27
|
+
return true;
|
|
28
|
+
}
|
|
29
|
+
/** Detect ``shell=True`` anywhere in the call args. */
|
|
30
|
+
function hasShellTrue(args) {
|
|
31
|
+
return /shell\s*=\s*True\b/.test(args);
|
|
32
|
+
}
|
|
33
|
+
/** Detect ``Loader=`` keyword in yaml.load arg list. */
|
|
34
|
+
function hasYamlLoader(args) {
|
|
35
|
+
return /\bLoader\s*=/.test(args);
|
|
36
|
+
}
|
|
37
|
+
/** Approximate first positional argument from a parenthesized call body.
|
|
38
|
+
* Naive: split on the first top-level comma. Good enough for the patterns
|
|
39
|
+
* here; we explicitly do NOT attempt to handle nested calls precisely
|
|
40
|
+
* because the critic refines. */
|
|
41
|
+
function firstPositionalArg(body) {
|
|
42
|
+
let depth = 0;
|
|
43
|
+
let inStr = null;
|
|
44
|
+
for (let i = 0; i < body.length; i++) {
|
|
45
|
+
const c = body[i];
|
|
46
|
+
if (inStr) {
|
|
47
|
+
if (c === inStr && body[i - 1] !== "\\")
|
|
48
|
+
inStr = null;
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
if (c === '"' || c === "'") {
|
|
52
|
+
inStr = c;
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
if (c === "(" || c === "[" || c === "{")
|
|
56
|
+
depth++;
|
|
57
|
+
else if (c === ")" || c === "]" || c === "}")
|
|
58
|
+
depth--;
|
|
59
|
+
else if (c === "," && depth === 0)
|
|
60
|
+
return body.slice(0, i).trim();
|
|
61
|
+
}
|
|
62
|
+
return body.trim();
|
|
63
|
+
}
|
|
64
|
+
// ── Rules ────────────────────────────────────────────────────────────────
|
|
65
|
+
const RULES = [
|
|
66
|
+
{
|
|
67
|
+
id: "os-system-tainted",
|
|
68
|
+
cwe: "CWE-78",
|
|
69
|
+
severity: "high",
|
|
70
|
+
what: "os.system() called with non-literal argument",
|
|
71
|
+
pattern: /\bos\.system\s*\(([^()]*(?:\([^()]*\)[^()]*)*)\)/g,
|
|
72
|
+
isDangerous: (first) => looksTainted(first),
|
|
73
|
+
remediation: "Replace os.system() with subprocess.run([...], shell=False) passing a list of args. " +
|
|
74
|
+
"Validate the user-controlled value against a strict allow-list before invoking.",
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
id: "subprocess-shell-true",
|
|
78
|
+
cwe: "CWE-78",
|
|
79
|
+
severity: "high",
|
|
80
|
+
what: "subprocess.* called with shell=True and a tainted command",
|
|
81
|
+
pattern: /\bsubprocess\.(?:run|call|check_output|check_call|Popen)\s*\(([^()]*(?:\([^()]*\)[^()]*)*)\)/g,
|
|
82
|
+
isDangerous: (first, all) => hasShellTrue(all) && looksTainted(first),
|
|
83
|
+
remediation: "Drop shell=True; pass the command as a list (e.g. ['nslookup', user_input]). " +
|
|
84
|
+
"shell=True invokes /bin/sh -c which lets the attacker chain commands with ; | & $().",
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
id: "subprocess-fstring",
|
|
88
|
+
cwe: "CWE-78",
|
|
89
|
+
severity: "high",
|
|
90
|
+
what: "subprocess.* called with an f-string as the command",
|
|
91
|
+
pattern: /\bsubprocess\.(?:run|call|check_output|check_call|Popen)\s*\(([^()]*(?:\([^()]*\)[^()]*)*)\)/g,
|
|
92
|
+
isDangerous: (first) => /^[rRbBuU]?[fF]['"]/.test(first.trim()),
|
|
93
|
+
remediation: "Build the command as a list: subprocess.run(['nslookup', value], shell=False). " +
|
|
94
|
+
"An f-string in the command position interpolates user input directly into shell metacharacters.",
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
id: "eval-tainted",
|
|
98
|
+
cwe: "CWE-95",
|
|
99
|
+
severity: "critical",
|
|
100
|
+
what: "eval() called with non-literal argument",
|
|
101
|
+
pattern: /(?<![\w.])eval\s*\(([^()]*(?:\([^()]*\)[^()]*)*)\)/g,
|
|
102
|
+
isDangerous: (first) => looksTainted(first),
|
|
103
|
+
remediation: "Never eval untrusted input. If you need to evaluate constants safely, use ast.literal_eval(). " +
|
|
104
|
+
"For JSON, use json.loads(). For dynamic dispatch, use a name→function dict, not eval.",
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
id: "exec-tainted",
|
|
108
|
+
cwe: "CWE-95",
|
|
109
|
+
severity: "critical",
|
|
110
|
+
what: "exec() called with non-literal argument",
|
|
111
|
+
pattern: /(?<![\w.])exec\s*\(([^()]*(?:\([^()]*\)[^()]*)*)\)/g,
|
|
112
|
+
isDangerous: (first) => looksTainted(first),
|
|
113
|
+
remediation: "Never exec untrusted input. Replace dynamic exec patterns with explicit dispatch over an " +
|
|
114
|
+
"allow-listed map of behaviors. Code-as-data should be data — JSON / config files / plugins.",
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
id: "pickle-loads",
|
|
118
|
+
cwe: "CWE-502",
|
|
119
|
+
severity: "high",
|
|
120
|
+
what: "pickle.{loads,load}() — unsafe deserialization",
|
|
121
|
+
pattern: /\bpickle\.(?:loads|load)\s*\(([^()]*(?:\([^()]*\)[^()]*)*)\)/g,
|
|
122
|
+
isDangerous: () => true, // pickle.loads on ANY untrusted bytes is RCE
|
|
123
|
+
remediation: "pickle deserialization on untrusted bytes is remote code execution. Switch to JSON / msgpack / " +
|
|
124
|
+
"protobuf — or sign the pickle blob (HMAC) before reading and verify signature.",
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
id: "yaml-load-no-safe-loader",
|
|
128
|
+
cwe: "CWE-502",
|
|
129
|
+
severity: "high",
|
|
130
|
+
what: "yaml.load() without Loader=SafeLoader",
|
|
131
|
+
pattern: /\byaml\.load\s*\(([^()]*(?:\([^()]*\)[^()]*)*)\)/g,
|
|
132
|
+
isDangerous: (_first, all) => !hasYamlLoader(all),
|
|
133
|
+
remediation: "Use yaml.safe_load(stream) — or yaml.load(stream, Loader=yaml.SafeLoader). Plain yaml.load " +
|
|
134
|
+
"with the default Loader constructs arbitrary Python objects and can execute attacker code.",
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
id: "dynamic-import",
|
|
138
|
+
cwe: "CWE-94",
|
|
139
|
+
severity: "high",
|
|
140
|
+
what: "__import__() called with non-literal argument",
|
|
141
|
+
pattern: /\b__import__\s*\(([^()]*(?:\([^()]*\)[^()]*)*)\)/g,
|
|
142
|
+
isDangerous: (first) => looksTainted(first),
|
|
143
|
+
remediation: "Dynamic __import__ on user input lets attackers load any module path. Maintain an explicit " +
|
|
144
|
+
"allow-list of permitted module names and use importlib.import_module(name) after validating.",
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
id: "path-traversal-send-file",
|
|
148
|
+
cwe: "CWE-22",
|
|
149
|
+
severity: "high",
|
|
150
|
+
what: "Flask send_file() with a tainted path",
|
|
151
|
+
// send_file is essentially "ship this file to the client". Any tainted
|
|
152
|
+
// arg here is path-traversal-of-the-week — caller can read /etc/passwd.
|
|
153
|
+
pattern: /\bsend_file\s*\(([^()]*(?:\([^()]*\)[^()]*)*)\)/g,
|
|
154
|
+
isDangerous: (first) => looksTainted(first),
|
|
155
|
+
remediation: "Resolve the requested name to an allow-listed file under a fixed root; reject anything containing " +
|
|
156
|
+
"'..', '/', '\\\\', or a colon. Better: use Flask.send_from_directory(safe_root, requested_name) " +
|
|
157
|
+
"which Flask itself rejects traversal sequences from.",
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
id: "ssrf-urlopen",
|
|
161
|
+
cwe: "CWE-918",
|
|
162
|
+
severity: "high",
|
|
163
|
+
what: "urlopen() called with a tainted URL — server-side request forgery",
|
|
164
|
+
pattern: /\burlopen\s*\(([^()]*(?:\([^()]*\)[^()]*)*)\)/g,
|
|
165
|
+
isDangerous: (first) => looksTainted(first),
|
|
166
|
+
remediation: "Validate the URL: parse with urllib.parse.urlparse, require an https scheme, and check the host " +
|
|
167
|
+
"against an allow-list (or at minimum reject 169.254.169.254, localhost, RFC1918 ranges to stop " +
|
|
168
|
+
"metadata-service / internal-network probes). Consider requests with a timeout + verify=True.",
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
id: "weak-crypto-md5",
|
|
172
|
+
cwe: "CWE-327",
|
|
173
|
+
severity: "high",
|
|
174
|
+
what: "MD5 used for hashing — broken; do not use for credentials, tokens, or signatures",
|
|
175
|
+
// hashlib.md5(<anything>) — MD5 is collisionable, not preimage-resistant
|
|
176
|
+
// enough for any security use. Allowing checksums is the user's call (a
|
|
177
|
+
// suppress entry / non-security context) — critic refines.
|
|
178
|
+
pattern: /\bhashlib\.md5\s*\(/g,
|
|
179
|
+
isDangerous: () => true,
|
|
180
|
+
remediation: "Switch to a memory-hard password hash (argon2-cffi / bcrypt / scrypt) for credentials. For " +
|
|
181
|
+
"integrity / signatures use SHA-256 (hashlib.sha256). If MD5 is required for protocol compatibility " +
|
|
182
|
+
"(legacy etag, content checksum vs trusted source), suppress with a comment explaining why.",
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
id: "weak-crypto-sha1",
|
|
186
|
+
cwe: "CWE-327",
|
|
187
|
+
severity: "high",
|
|
188
|
+
what: "SHA-1 used for hashing — collisions are practical; do not use for security",
|
|
189
|
+
pattern: /\bhashlib\.sha1\s*\(/g,
|
|
190
|
+
isDangerous: () => true,
|
|
191
|
+
remediation: "Replace with hashlib.sha256 or hashlib.sha3_256. For password hashing use argon2 / bcrypt / scrypt. " +
|
|
192
|
+
"SHA-1 has practical collision attacks (SHAttered) and must not be used for signatures or password storage.",
|
|
193
|
+
},
|
|
194
|
+
{
|
|
195
|
+
id: "weak-crypto-hashlib-new",
|
|
196
|
+
cwe: "CWE-327",
|
|
197
|
+
severity: "high",
|
|
198
|
+
what: "hashlib.new() called with a weak algorithm name (md5/sha1/md4)",
|
|
199
|
+
pattern: /\bhashlib\.new\s*\(\s*['"]([^'"]+)['"]/g,
|
|
200
|
+
// Group 1 is the algorithm name string.
|
|
201
|
+
isDangerous: (first) => /^(md5|sha1|md4|md2|mdc2|ripemd160)$/i.test(first),
|
|
202
|
+
remediation: "Use hashlib.new('sha256') or a direct constructor (hashlib.sha256). Avoid MD5/SHA1/MD4 for any " +
|
|
203
|
+
"security-related hashing including passwords, session tokens, signatures, and integrity proofs.",
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
id: "open-redirect-flask",
|
|
207
|
+
cwe: "CWE-601",
|
|
208
|
+
severity: "high",
|
|
209
|
+
what: "Flask redirect() with a tainted URL — open redirect / phishing pivot",
|
|
210
|
+
pattern: /\bredirect\s*\(([^()]*(?:\([^()]*\)[^()]*)*)\)/g,
|
|
211
|
+
fileGate: (c) => /\b(?:from\s+flask\b|import\s+flask\b)/.test(c),
|
|
212
|
+
isDangerous: (first) => looksTainted(first),
|
|
213
|
+
remediation: "Validate the next URL: only allow same-host destinations via urlparse + url_for, or maintain " +
|
|
214
|
+
"an allow-list of safe targets. Never blindly redirect to a value taken from request.args/form.",
|
|
215
|
+
},
|
|
216
|
+
{
|
|
217
|
+
id: "ssrf-requests",
|
|
218
|
+
cwe: "CWE-918",
|
|
219
|
+
severity: "high",
|
|
220
|
+
what: "requests.{get,post,put,delete,patch,head} called with a tainted URL",
|
|
221
|
+
pattern: /\brequests\.(?:get|post|put|delete|patch|head|request)\s*\(([^()]*(?:\([^()]*\)[^()]*)*)\)/g,
|
|
222
|
+
isDangerous: (first) => looksTainted(first),
|
|
223
|
+
remediation: "Validate the URL: parse with urllib.parse.urlparse, check scheme in {http,https}, resolve hostname " +
|
|
224
|
+
"and reject loopback / link-local / RFC1918 ranges. Use an allow-list per integration boundary. " +
|
|
225
|
+
"Set timeout= and verify=True; do not follow redirects to internal hosts.",
|
|
226
|
+
},
|
|
227
|
+
{
|
|
228
|
+
id: "ssti-render-template-string",
|
|
229
|
+
cwe: "CWE-94",
|
|
230
|
+
severity: "critical",
|
|
231
|
+
what: "Jinja render_template_string() with tainted template — server-side template injection (RCE)",
|
|
232
|
+
pattern: /\brender_template_string\s*\(([^()]*(?:\([^()]*\)[^()]*)*)\)/g,
|
|
233
|
+
// render_template_string is a flask import — gate keeps the FP rate low.
|
|
234
|
+
fileGate: (c) => /\b(?:from\s+flask\b|import\s+flask\b|render_template_string)/.test(c),
|
|
235
|
+
isDangerous: (first) => looksTainted(first),
|
|
236
|
+
remediation: "Never pass user input as the template SOURCE — pass it as a CONTEXT variable to a static template " +
|
|
237
|
+
"(render_template('view.html', name=user_input)). SSTI in Jinja gives the attacker arbitrary Python " +
|
|
238
|
+
"execution via {{ ''.__class__.__mro__[1].__subclasses__()[...]() }} sandbox-escape chains.",
|
|
239
|
+
},
|
|
240
|
+
{
|
|
241
|
+
id: "jwt-signature-disabled",
|
|
242
|
+
cwe: "CWE-347",
|
|
243
|
+
severity: "critical",
|
|
244
|
+
what: "JWT decoded with signature verification DISABLED",
|
|
245
|
+
pattern: /\bjwt\.decode\s*\(([^()]*(?:\([^()]*\)[^()]*)*)\)/g,
|
|
246
|
+
isDangerous: (_first, all) => /verify_signature\s*[:=]\s*False/.test(all) || /verify\s*=\s*False/.test(all),
|
|
247
|
+
remediation: "Remove verify=False / verify_signature=False — that disables ALL authenticity guarantees. Always " +
|
|
248
|
+
"call jwt.decode(token, key, algorithms=['HS256']) with the actual signing key. If the token must " +
|
|
249
|
+
"be inspected pre-validation, parse the header only via jwt.get_unverified_header (NEVER trust the body).",
|
|
250
|
+
},
|
|
251
|
+
{
|
|
252
|
+
id: "weak-random-for-security",
|
|
253
|
+
cwe: "CWE-330",
|
|
254
|
+
severity: "high",
|
|
255
|
+
what: "random module used in a security-sensitive context",
|
|
256
|
+
// Only flag when the FILE contains a security keyword (token / secret /
|
|
257
|
+
// key / password / nonce / csrf / session / api_key / auth). Files that
|
|
258
|
+
// use random for dice / Monte Carlo / unit tests don't trigger.
|
|
259
|
+
pattern: /\brandom\.(?:random|randint|randrange|choice|choices|sample|getrandbits|shuffle|uniform)\s*\(/g,
|
|
260
|
+
// V2-20b/c — drop \b for snake_case/camelCase-appendable terms. The
|
|
261
|
+
// \b in /\bsession\b/ doesn't match inside `create_session_id` because
|
|
262
|
+
// `_` and letters are both word chars (no boundary between `n` and
|
|
263
|
+
// `_`). For tightly-bounded false-positive terms ("secret" matching
|
|
264
|
+
// "Secretary") we keep the boundary explicitly.
|
|
265
|
+
fileGate: (c) => /(?:token|password|nonce|csrf|sessionid|session|sid|api[_-]?key|auth[_-]?key|signing[_-]?key)/i.test(c) ||
|
|
266
|
+
/\bsecret\b/i.test(c) ||
|
|
267
|
+
/\bsalt\b/i.test(c),
|
|
268
|
+
isDangerous: () => true,
|
|
269
|
+
remediation: "Use the secrets module: secrets.token_urlsafe(), secrets.token_bytes(), secrets.choice(). The random " +
|
|
270
|
+
"module is a Mersenne Twister — predictable after observing ~624 outputs and unsuitable for tokens, " +
|
|
271
|
+
"session ids, passwords, nonces, CSRF tokens, or anything an attacker can guess and exploit.",
|
|
272
|
+
},
|
|
273
|
+
{
|
|
274
|
+
id: "xxe-lxml-parse",
|
|
275
|
+
cwe: "CWE-611",
|
|
276
|
+
severity: "high",
|
|
277
|
+
what: "lxml.etree.parse / fromstring without resolve_entities=False — XXE risk",
|
|
278
|
+
pattern: /\blxml\.etree\.(?:parse|fromstring|XML|HTML)\s*\(([^()]*(?:\([^()]*\)[^()]*)*)\)/g,
|
|
279
|
+
isDangerous: (_first, all) => !/resolve_entities\s*=\s*False/.test(all),
|
|
280
|
+
remediation: "Use a hardened parser: parser = lxml.etree.XMLParser(resolve_entities=False, no_network=True, " +
|
|
281
|
+
"huge_tree=False); etree.parse(source, parser). Plain lxml.etree.parse with the default parser " +
|
|
282
|
+
"expands external entities and is vulnerable to billion-laughs DoS + SSRF + local file disclosure.",
|
|
283
|
+
},
|
|
284
|
+
{
|
|
285
|
+
id: "flask-debug-true",
|
|
286
|
+
cwe: "CWE-489",
|
|
287
|
+
severity: "high",
|
|
288
|
+
what: "Flask app.run(debug=True) — Werkzeug debugger exposes a Python REPL via PIN bypass",
|
|
289
|
+
pattern: /\.run\s*\(([^()]*(?:\([^()]*\)[^()]*)*)\)/g,
|
|
290
|
+
fileGate: (c) => /\b(?:from\s+flask\b|import\s+flask\b|Flask\s*\()/.test(c),
|
|
291
|
+
isDangerous: (_first, all) => /debug\s*=\s*True\b/.test(all),
|
|
292
|
+
remediation: "Never ship debug=True. Read from env: app.run(debug=os.environ.get('FLASK_ENV')=='development'). " +
|
|
293
|
+
"The Werkzeug debugger PIN can be derived from publicly-readable values (machine-id + uuid) — Snyk and " +
|
|
294
|
+
"ProjectDiscovery have weaponised this into one-shot RCE on real-world exposed Flask apps.",
|
|
295
|
+
},
|
|
296
|
+
{
|
|
297
|
+
id: "sqli-cursor-fstring",
|
|
298
|
+
cwe: "CWE-89",
|
|
299
|
+
severity: "critical",
|
|
300
|
+
what: "cursor.execute() called with an f-string (SQL built by string interpolation)",
|
|
301
|
+
pattern: /\b(?:cursor|cur|conn)\.execute\s*\(\s*([rR]?[fF]['"][\s\S]*?['"])(?:\s*[,)])/g,
|
|
302
|
+
isDangerous: (first) => /^[rR]?[fF]['"]/.test(first.trim()),
|
|
303
|
+
remediation: "Use parameter binding: cursor.execute('SELECT ... WHERE col = ?', (value,)). " +
|
|
304
|
+
"F-string interpolation into SQL is SQL injection by construction; even \"safe-looking\" inputs " +
|
|
305
|
+
"(numbers, UUIDs) can be exploited via type coercion bugs in the driver.",
|
|
306
|
+
},
|
|
307
|
+
{
|
|
308
|
+
id: "sqli-cursor-percent-format",
|
|
309
|
+
cwe: "CWE-89",
|
|
310
|
+
severity: "critical",
|
|
311
|
+
what: "cursor.execute() with %-format string concatenating a variable into SQL",
|
|
312
|
+
// Match cursor.execute("SELECT ... %s ..." % var) — Python's `%` operator
|
|
313
|
+
// applied to a SQL string with non-literal RHS.
|
|
314
|
+
pattern: /\b(?:cursor|cur|conn)\.execute\s*\(\s*['"][^'"]*%[sd][^'"]*['"]\s*%\s*([^)]+)\)/g,
|
|
315
|
+
isDangerous: (first) => looksTainted(first),
|
|
316
|
+
remediation: "Replace the manual %-substitution with DB-API parameter binding: " +
|
|
317
|
+
"cursor.execute('SELECT ... WHERE col = %s', (value,)) (NOT the Python %-operator — " +
|
|
318
|
+
"let the driver do the substitution).",
|
|
319
|
+
},
|
|
320
|
+
{
|
|
321
|
+
id: "xxe-stdlib-etree",
|
|
322
|
+
cwe: "CWE-611",
|
|
323
|
+
severity: "high",
|
|
324
|
+
what: "Python stdlib xml.* parser used on untrusted input — XXE / billion laughs",
|
|
325
|
+
pattern: /\bxml\.(?:sax|dom\.minidom|etree\.ElementTree)\.(?:parse|parseString|fromstring|XML)\s*\(([^()]*(?:\([^()]*\)[^()]*)*)\)/g,
|
|
326
|
+
isDangerous: () => true,
|
|
327
|
+
remediation: "Switch to defusedxml: from defusedxml.ElementTree import parse, fromstring (drop-in replacement). " +
|
|
328
|
+
"Python's stdlib xml.* documentation explicitly says it is NOT safe for untrusted XML — defusedxml " +
|
|
329
|
+
"disables entity expansion, external-entity resolution, and DTD loading by default.",
|
|
330
|
+
},
|
|
331
|
+
{
|
|
332
|
+
id: "requests-verify-false",
|
|
333
|
+
cwe: "CWE-295",
|
|
334
|
+
severity: "critical",
|
|
335
|
+
what: "requests.* called with verify=False — TLS certificate verification disabled",
|
|
336
|
+
pattern: /\brequests\.(?:get|post|put|delete|patch|head|request)\s*\(([^()]*(?:\([^()]*\)[^()]*)*)\)/g,
|
|
337
|
+
isDangerous: (_first, all) => /\bverify\s*=\s*False\b/.test(all),
|
|
338
|
+
remediation: "Remove verify=False. If the target uses a private CA, point verify= to your CA bundle path " +
|
|
339
|
+
"(verify='/etc/ssl/private-ca.pem'). Disabling verification removes ALL guarantees about who you " +
|
|
340
|
+
"are talking to — a MITM can transparently read and modify the traffic.",
|
|
341
|
+
},
|
|
342
|
+
{
|
|
343
|
+
id: "fail-open-permission-except",
|
|
344
|
+
cwe: "CWE-755",
|
|
345
|
+
severity: "high",
|
|
346
|
+
// Auth-named function whose body contains `except ... return True`.
|
|
347
|
+
// Real-world ransom: a DB blip → all-access-granted for an hour.
|
|
348
|
+
what: "Authorization function returns True from an exception handler — fail-OPEN on errors (CWE-755 + CWE-863)",
|
|
349
|
+
// Match a def with auth-suggestive name; capture up to 4000 chars of
|
|
350
|
+
// body in group 1. isDangerous checks the body for an `except: return True`.
|
|
351
|
+
// Naming prefixes restricted to security-critical ones so non-auth
|
|
352
|
+
// utility funcs (is_debug, is_dry_run) don't false-positive.
|
|
353
|
+
pattern: /def\s+(?:can_|may_|has_(?:perm|access|role|right|priv)|is_(?:admin|allowed|authorized|authenticated|owner|trusted|permitted|approved|staff|superuser|root)|check_(?:perm|access|auth)|authorize|verify_(?:token|bearer|signature|jwt|owner|access|password)|allow_|grant_)\w*\s*\([^)]*\)[^:]*:([\s\S]{0,4000})/g,
|
|
354
|
+
isDangerous: (_first, body) => /\bexcept\b[^:]*:[\s\S]{0,500}?\breturn\s+True\b/.test(body),
|
|
355
|
+
remediation: "Fail CLOSED: replace `except: return True` with `except Exception as e: log.exception(...); " +
|
|
356
|
+
"return False`. Authorization functions MUST default to DENYING access when the dependency (DB, " +
|
|
357
|
+
"network, cache) is unavailable — a fail-open default lets a transient outage silently grant " +
|
|
358
|
+
"unrestricted access (real-world: TJ-Maxx 2007, AT&T 2010). If the caller needs to differentiate " +
|
|
359
|
+
"'denied' from 'unknown', raise a typed error and let an outer middleware decide.",
|
|
360
|
+
},
|
|
361
|
+
{
|
|
362
|
+
id: "non-constant-time-compare",
|
|
363
|
+
cwe: "CWE-208",
|
|
364
|
+
severity: "high",
|
|
365
|
+
what: "Non-constant-time comparison of secret material (token / password / HMAC / signature) using == or != — timing side-channel leak",
|
|
366
|
+
// Match ANY var-to-var (or var-to-literal) comparison. The
|
|
367
|
+
// isDangerous predicate decides if it's a secret comparison.
|
|
368
|
+
pattern: /\b([a-zA-Z_]\w*\s*(?:==|!=)\s*(?:[a-zA-Z_]\w*|['"][^'"]*['"]|None|True|False|\d+))/g,
|
|
369
|
+
isDangerous: (expr) => {
|
|
370
|
+
// Nullity / empty / boolean checks are NOT timing-sensitive.
|
|
371
|
+
if (/(?:==|!=)\s*(?:None|null|undefined|False|True|0|''|"")/.test(expr))
|
|
372
|
+
return false;
|
|
373
|
+
const m = expr.match(/^([a-zA-Z_]\w*)\s*(?:==|!=)\s*(.+)$/);
|
|
374
|
+
if (!m)
|
|
375
|
+
return false;
|
|
376
|
+
const lhs = m[1];
|
|
377
|
+
const rhs = m[2].trim();
|
|
378
|
+
if (lhs === rhs)
|
|
379
|
+
return false; // var == var → bogus
|
|
380
|
+
// Either side contains a secret-named word (case-insensitive, camelCase-friendly).
|
|
381
|
+
const SECRET = /(token|secret|password|hmac|signature|api[_-]?key|auth[_-]?key|csrf|nonce|session[_-]?id|bearer|mac|digest|salt)/i;
|
|
382
|
+
return SECRET.test(lhs) || SECRET.test(rhs);
|
|
383
|
+
},
|
|
384
|
+
remediation: "Use hmac.compare_digest(supplied, expected) for any secret comparison — it runs in constant time " +
|
|
385
|
+
"regardless of how many bytes match, so an attacker cannot recover the secret one byte at a time " +
|
|
386
|
+
"by measuring response latency. Applies to bearer tokens, CSRF tokens, HMAC verification, password " +
|
|
387
|
+
"equality checks, JWT signature compares, and webhook signing-secret validation.",
|
|
388
|
+
},
|
|
389
|
+
];
|
|
390
|
+
// ── Engine ───────────────────────────────────────────────────────────────
|
|
391
|
+
export class PythonSinksEngine {
|
|
392
|
+
name = "python-sinks";
|
|
393
|
+
languages = ["python"];
|
|
394
|
+
async available() {
|
|
395
|
+
return true; // pure JS regex; always available
|
|
396
|
+
}
|
|
397
|
+
async run(input) {
|
|
398
|
+
const t0 = Date.now();
|
|
399
|
+
const findings = [];
|
|
400
|
+
if (input.lang !== "python") {
|
|
401
|
+
return { engine: this.name, findings: [], unavailable: false, durationMs: 0 };
|
|
402
|
+
}
|
|
403
|
+
if (isTestOrFixturePath(input.filePath)) {
|
|
404
|
+
return { engine: this.name, findings: [], unavailable: false, durationMs: 0 };
|
|
405
|
+
}
|
|
406
|
+
const content = input.content;
|
|
407
|
+
const lines = content.split(/\r?\n/);
|
|
408
|
+
for (const rule of RULES) {
|
|
409
|
+
// File-level gate: skip the whole rule if the file doesn't fit
|
|
410
|
+
// the framework/context it targets (cheaper than per-match check).
|
|
411
|
+
if (rule.fileGate && !rule.fileGate(content))
|
|
412
|
+
continue;
|
|
413
|
+
rule.pattern.lastIndex = 0;
|
|
414
|
+
let m;
|
|
415
|
+
while ((m = rule.pattern.exec(content)) !== null) {
|
|
416
|
+
const allArgs = m[1] ?? "";
|
|
417
|
+
const firstArg = firstPositionalArg(allArgs);
|
|
418
|
+
if (!rule.isDangerous(firstArg, allArgs, content))
|
|
419
|
+
continue;
|
|
420
|
+
const upTo = content.slice(0, m.index);
|
|
421
|
+
const line = upTo.split(/\r?\n/).length;
|
|
422
|
+
const snippet = (lines[line - 1] ?? "").slice(0, 400);
|
|
423
|
+
if (isLineSuppressed(snippet, rule.id))
|
|
424
|
+
continue;
|
|
425
|
+
findings.push({
|
|
426
|
+
id: makeFindingId({
|
|
427
|
+
engine: this.name,
|
|
428
|
+
file: input.filePath,
|
|
429
|
+
line,
|
|
430
|
+
rule_id: rule.id,
|
|
431
|
+
}),
|
|
432
|
+
engine: "python-sinks",
|
|
433
|
+
file: input.filePath,
|
|
434
|
+
line,
|
|
435
|
+
rule_id: rule.id,
|
|
436
|
+
cwe: rule.cwe,
|
|
437
|
+
severity: rule.severity,
|
|
438
|
+
message: `${rule.what}. Likely ${rule.cwe} — review and remediate before merging.`,
|
|
439
|
+
evidence: { snippet },
|
|
440
|
+
// 0.75 = enough to drive a high-severity block via decide() rules
|
|
441
|
+
// AND to route the critic for refinement (stage1_findings signal),
|
|
442
|
+
// but the critic can refute with its own counter-finding.
|
|
443
|
+
confidence: 0.75,
|
|
444
|
+
source: "pattern",
|
|
445
|
+
remediation: rule.remediation,
|
|
446
|
+
});
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
return {
|
|
450
|
+
engine: this.name,
|
|
451
|
+
findings,
|
|
452
|
+
unavailable: false,
|
|
453
|
+
durationMs: Date.now() - t0,
|
|
454
|
+
};
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
// Internal exports for unit tests only.
|
|
458
|
+
export const _testing = { RULES, looksTainted, firstPositionalArg, hasShellTrue, hasYamlLoader };
|
|
459
|
+
//# sourceMappingURL=python-sinks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"python-sinks.js","sourceRoot":"","sources":["../../src/engines/python-sinks.ts"],"names":[],"mappings":"AAiCA,OAAO,EAAW,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAExD,OAAO,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAuBpE,4EAA4E;AAE5E;;oDAEoD;AACpD,SAAS,YAAY,CAAC,GAAW;IAC/B,MAAM,CAAC,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;IACrB,IAAI,CAAC,KAAK,EAAE;QAAE,OAAO,KAAK,CAAC;IAC3B,gEAAgE;IAChE,IAAI,oBAAoB,CAAC,IAAI,CAAC,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IAC9C,2EAA2E;IAC3E,IAAI,uBAAuB,CAAC,IAAI,CAAC,CAAC,CAAC;QAAE,OAAO,KAAK,CAAC;IAClD,8DAA8D;IAC9D,IAAI,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;QAC7B,6DAA6D;QAC7D,IAAI,kBAAkB,CAAC,IAAI,CAAC,CAAC,CAAC;YAAE,OAAO,IAAI,CAAC;QAC5C,IAAI,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC;YAAE,OAAO,IAAI,CAAC;QACzC,OAAO,KAAK,CAAC;IACf,CAAC;IACD,sEAAsE;IACtE,OAAO,IAAI,CAAC;AACd,CAAC;AAED,uDAAuD;AACvD,SAAS,YAAY,CAAC,IAAY;IAChC,OAAO,oBAAoB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACzC,CAAC;AAED,wDAAwD;AACxD,SAAS,aAAa,CAAC,IAAY;IACjC,OAAO,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACnC,CAAC;AAED;;;iCAGiC;AACjC,SAAS,kBAAkB,CAAC,IAAY;IACtC,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,IAAI,KAAK,GAAkB,IAAI,CAAC;IAChC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAE,CAAC;QACnB,IAAI,KAAK,EAAE,CAAC;YACV,IAAI,CAAC,KAAK,KAAK,IAAI,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,IAAI;gBAAE,KAAK,GAAG,IAAI,CAAC;YACtD,SAAS;QACX,CAAC;QACD,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC;YAC3B,KAAK,GAAG,CAAC,CAAC;YACV,SAAS;QACX,CAAC;QACD,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,GAAG;YAAE,KAAK,EAAE,CAAC;aAC5C,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,GAAG;YAAE,KAAK,EAAE,CAAC;aACjD,IAAI,CAAC,KAAK,GAAG,IAAI,KAAK,KAAK,CAAC;YAAE,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IACpE,CAAC;IACD,OAAO,IAAI,CAAC,IAAI,EAAE,CAAC;AACrB,CAAC;AAED,4EAA4E;AAE5E,MAAM,KAAK,GAA4B;IACrC;QACE,EAAE,EAAE,mBAAmB;QACvB,GAAG,EAAE,QAAQ;QACb,QAAQ,EAAE,MAAM;QAChB,IAAI,EAAE,8CAA8C;QACpD,OAAO,EAAE,mDAAmD;QAC5D,WAAW,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,YAAY,CAAC,KAAK,CAAC;QAC3C,WAAW,EACT,sFAAsF;YACtF,iFAAiF;KACpF;IACD;QACE,EAAE,EAAE,uBAAuB;QAC3B,GAAG,EAAE,QAAQ;QACb,QAAQ,EAAE,MAAM;QAChB,IAAI,EAAE,2DAA2D;QACjE,OAAO,EACL,+FAA+F;QACjG,WAAW,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,YAAY,CAAC,KAAK,CAAC;QACrE,WAAW,EACT,+EAA+E;YAC/E,sFAAsF;KACzF;IACD;QACE,EAAE,EAAE,oBAAoB;QACxB,GAAG,EAAE,QAAQ;QACb,QAAQ,EAAE,MAAM;QAChB,IAAI,EAAE,qDAAqD;QAC3D,OAAO,EACL,+FAA+F;QACjG,WAAW,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,oBAAoB,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QAC/D,WAAW,EACT,iFAAiF;YACjF,iGAAiG;KACpG;IACD;QACE,EAAE,EAAE,cAAc;QAClB,GAAG,EAAE,QAAQ;QACb,QAAQ,EAAE,UAAU;QACpB,IAAI,EAAE,yCAAyC;QAC/C,OAAO,EAAE,qDAAqD;QAC9D,WAAW,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,YAAY,CAAC,KAAK,CAAC;QAC3C,WAAW,EACT,gGAAgG;YAChG,uFAAuF;KAC1F;IACD;QACE,EAAE,EAAE,cAAc;QAClB,GAAG,EAAE,QAAQ;QACb,QAAQ,EAAE,UAAU;QACpB,IAAI,EAAE,yCAAyC;QAC/C,OAAO,EAAE,qDAAqD;QAC9D,WAAW,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,YAAY,CAAC,KAAK,CAAC;QAC3C,WAAW,EACT,2FAA2F;YAC3F,6FAA6F;KAChG;IACD;QACE,EAAE,EAAE,cAAc;QAClB,GAAG,EAAE,SAAS;QACd,QAAQ,EAAE,MAAM;QAChB,IAAI,EAAE,gDAAgD;QACtD,OAAO,EAAE,+DAA+D;QACxE,WAAW,EAAE,GAAG,EAAE,CAAC,IAAI,EAAE,6CAA6C;QACtE,WAAW,EACT,iGAAiG;YACjG,gFAAgF;KACnF;IACD;QACE,EAAE,EAAE,0BAA0B;QAC9B,GAAG,EAAE,SAAS;QACd,QAAQ,EAAE,MAAM;QAChB,IAAI,EAAE,uCAAuC;QAC7C,OAAO,EAAE,mDAAmD;QAC5D,WAAW,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,aAAa,CAAC,GAAG,CAAC;QACjD,WAAW,EACT,6FAA6F;YAC7F,4FAA4F;KAC/F;IACD;QACE,EAAE,EAAE,gBAAgB;QACpB,GAAG,EAAE,QAAQ;QACb,QAAQ,EAAE,MAAM;QAChB,IAAI,EAAE,+CAA+C;QACrD,OAAO,EAAE,mDAAmD;QAC5D,WAAW,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,YAAY,CAAC,KAAK,CAAC;QAC3C,WAAW,EACT,6FAA6F;YAC7F,8FAA8F;KACjG;IACD;QACE,EAAE,EAAE,0BAA0B;QAC9B,GAAG,EAAE,QAAQ;QACb,QAAQ,EAAE,MAAM;QAChB,IAAI,EAAE,uCAAuC;QAC7C,uEAAuE;QACvE,wEAAwE;QACxE,OAAO,EAAE,kDAAkD;QAC3D,WAAW,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,YAAY,CAAC,KAAK,CAAC;QAC3C,WAAW,EACT,oGAAoG;YACpG,kGAAkG;YAClG,sDAAsD;KACzD;IACD;QACE,EAAE,EAAE,cAAc;QAClB,GAAG,EAAE,SAAS;QACd,QAAQ,EAAE,MAAM;QAChB,IAAI,EAAE,mEAAmE;QACzE,OAAO,EAAE,gDAAgD;QACzD,WAAW,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,YAAY,CAAC,KAAK,CAAC;QAC3C,WAAW,EACT,kGAAkG;YAClG,iGAAiG;YACjG,8FAA8F;KACjG;IACD;QACE,EAAE,EAAE,iBAAiB;QACrB,GAAG,EAAE,SAAS;QACd,QAAQ,EAAE,MAAM;QAChB,IAAI,EAAE,kFAAkF;QACxF,yEAAyE;QACzE,wEAAwE;QACxE,2DAA2D;QAC3D,OAAO,EAAE,sBAAsB;QAC/B,WAAW,EAAE,GAAG,EAAE,CAAC,IAAI;QACvB,WAAW,EACT,6FAA6F;YAC7F,qGAAqG;YACrG,4FAA4F;KAC/F;IACD;QACE,EAAE,EAAE,kBAAkB;QACtB,GAAG,EAAE,SAAS;QACd,QAAQ,EAAE,MAAM;QAChB,IAAI,EAAE,4EAA4E;QAClF,OAAO,EAAE,uBAAuB;QAChC,WAAW,EAAE,GAAG,EAAE,CAAC,IAAI;QACvB,WAAW,EACT,sGAAsG;YACtG,4GAA4G;KAC/G;IACD;QACE,EAAE,EAAE,yBAAyB;QAC7B,GAAG,EAAE,SAAS;QACd,QAAQ,EAAE,MAAM;QAChB,IAAI,EAAE,gEAAgE;QACtE,OAAO,EAAE,yCAAyC;QAClD,wCAAwC;QACxC,WAAW,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,sCAAsC,CAAC,IAAI,CAAC,KAAK,CAAC;QAC1E,WAAW,EACT,iGAAiG;YACjG,iGAAiG;KACpG;IACD;QACE,EAAE,EAAE,qBAAqB;QACzB,GAAG,EAAE,SAAS;QACd,QAAQ,EAAE,MAAM;QAChB,IAAI,EAAE,sEAAsE;QAC5E,OAAO,EAAE,iDAAiD;QAC1D,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,uCAAuC,CAAC,IAAI,CAAC,CAAC,CAAC;QAChE,WAAW,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,YAAY,CAAC,KAAK,CAAC;QAC3C,WAAW,EACT,+FAA+F;YAC/F,gGAAgG;KACnG;IACD;QACE,EAAE,EAAE,eAAe;QACnB,GAAG,EAAE,SAAS;QACd,QAAQ,EAAE,MAAM;QAChB,IAAI,EAAE,qEAAqE;QAC3E,OAAO,EAAE,6FAA6F;QACtG,WAAW,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,YAAY,CAAC,KAAK,CAAC;QAC3C,WAAW,EACT,qGAAqG;YACrG,iGAAiG;YACjG,0EAA0E;KAC7E;IACD;QACE,EAAE,EAAE,6BAA6B;QACjC,GAAG,EAAE,QAAQ;QACb,QAAQ,EAAE,UAAU;QACpB,IAAI,EAAE,6FAA6F;QACnG,OAAO,EAAE,+DAA+D;QACxE,yEAAyE;QACzE,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CACd,8DAA8D,CAAC,IAAI,CAAC,CAAC,CAAC;QACxE,WAAW,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,YAAY,CAAC,KAAK,CAAC;QAC3C,WAAW,EACT,oGAAoG;YACpG,qGAAqG;YACrG,4FAA4F;KAC/F;IACD;QACE,EAAE,EAAE,wBAAwB;QAC5B,GAAG,EAAE,SAAS;QACd,QAAQ,EAAE,UAAU;QACpB,IAAI,EAAE,kDAAkD;QACxD,OAAO,EAAE,oDAAoD;QAC7D,WAAW,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE,EAAE,CAC3B,iCAAiC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,oBAAoB,CAAC,IAAI,CAAC,GAAG,CAAC;QAC/E,WAAW,EACT,mGAAmG;YACnG,mGAAmG;YACnG,0GAA0G;KAC7G;IACD;QACE,EAAE,EAAE,0BAA0B;QAC9B,GAAG,EAAE,SAAS;QACd,QAAQ,EAAE,MAAM;QAChB,IAAI,EAAE,oDAAoD;QAC1D,wEAAwE;QACxE,wEAAwE;QACxE,gEAAgE;QAChE,OAAO,EACL,gGAAgG;QAClG,oEAAoE;QACpE,uEAAuE;QACvE,mEAAmE;QACnE,oEAAoE;QACpE,gDAAgD;QAChD,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CACd,+FAA+F,CAAC,IAAI,CAClG,CAAC,CACF;YACD,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC;YACrB,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC;QACrB,WAAW,EAAE,GAAG,EAAE,CAAC,IAAI;QACvB,WAAW,EACT,uGAAuG;YACvG,qGAAqG;YACrG,6FAA6F;KAChG;IACD;QACE,EAAE,EAAE,gBAAgB;QACpB,GAAG,EAAE,SAAS;QACd,QAAQ,EAAE,MAAM;QAChB,IAAI,EAAE,yEAAyE;QAC/E,OAAO,EAAE,mFAAmF;QAC5F,WAAW,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,8BAA8B,CAAC,IAAI,CAAC,GAAG,CAAC;QACvE,WAAW,EACT,gGAAgG;YAChG,gGAAgG;YAChG,mGAAmG;KACtG;IACD;QACE,EAAE,EAAE,kBAAkB;QACtB,GAAG,EAAE,SAAS;QACd,QAAQ,EAAE,MAAM;QAChB,IAAI,EAAE,oFAAoF;QAC1F,OAAO,EAAE,4CAA4C;QACrD,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,kDAAkD,CAAC,IAAI,CAAC,CAAC,CAAC;QAC3E,WAAW,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE,EAAE,CAAC,oBAAoB,CAAC,IAAI,CAAC,GAAG,CAAC;QAC5D,WAAW,EACT,mGAAmG;YACnG,wGAAwG;YACxG,2FAA2F;KAC9F;IACD;QACE,EAAE,EAAE,qBAAqB;QACzB,GAAG,EAAE,QAAQ;QACb,QAAQ,EAAE,UAAU;QACpB,IAAI,EAAE,8EAA8E;QACpF,OAAO,EAAE,+EAA+E;QACxF,WAAW,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,gBAAgB,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QAC3D,WAAW,EACT,+EAA+E;YAC/E,iGAAiG;YACjG,yEAAyE;KAC5E;IACD;QACE,EAAE,EAAE,4BAA4B;QAChC,GAAG,EAAE,QAAQ;QACb,QAAQ,EAAE,UAAU;QACpB,IAAI,EAAE,yEAAyE;QAC/E,0EAA0E;QAC1E,gDAAgD;QAChD,OAAO,EACL,kFAAkF;QACpF,WAAW,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,YAAY,CAAC,KAAK,CAAC;QAC3C,WAAW,EACT,mEAAmE;YACnE,sFAAsF;YACtF,sCAAsC;KACzC;IACD;QACE,EAAE,EAAE,kBAAkB;QACtB,GAAG,EAAE,SAAS;QACd,QAAQ,EAAE,MAAM;QAChB,IAAI,EAAE,2EAA2E;QACjF,OAAO,EACL,2HAA2H;QAC7H,WAAW,EAAE,GAAG,EAAE,CAAC,IAAI;QACvB,WAAW,EACT,oGAAoG;YACpG,oGAAoG;YACpG,oFAAoF;KACvF;IACD;QACE,EAAE,EAAE,uBAAuB;QAC3B,GAAG,EAAE,SAAS;QACd,QAAQ,EAAE,UAAU;QACpB,IAAI,EAAE,6EAA6E;QACnF,OAAO,EACL,6FAA6F;QAC/F,WAAW,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE,EAAE,CAAC,wBAAwB,CAAC,IAAI,CAAC,GAAG,CAAC;QAChE,WAAW,EACT,6FAA6F;YAC7F,kGAAkG;YAClG,wEAAwE;KAC3E;IACD;QACE,EAAE,EAAE,6BAA6B;QACjC,GAAG,EAAE,SAAS;QACd,QAAQ,EAAE,MAAM;QAChB,oEAAoE;QACpE,iEAAiE;QACjE,IAAI,EACF,yGAAyG;QAC3G,qEAAqE;QACrE,6EAA6E;QAC7E,mEAAmE;QACnE,6DAA6D;QAC7D,OAAO,EACL,kTAAkT;QACpT,WAAW,EAAE,CAAC,MAAM,EAAE,IAAI,EAAE,EAAE,CAC5B,iDAAiD,CAAC,IAAI,CAAC,IAAI,CAAC;QAC9D,WAAW,EACT,8FAA8F;YAC9F,iGAAiG;YACjG,8FAA8F;YAC9F,kGAAkG;YAClG,kFAAkF;KACrF;IACD;QACE,EAAE,EAAE,2BAA2B;QAC/B,GAAG,EAAE,SAAS;QACd,QAAQ,EAAE,MAAM;QAChB,IAAI,EACF,iIAAiI;QACnI,2DAA2D;QAC3D,6DAA6D;QAC7D,OAAO,EACL,qFAAqF;QACvF,WAAW,EAAE,CAAC,IAAI,EAAE,EAAE;YACpB,6DAA6D;YAC7D,IAAI,wDAAwD,CAAC,IAAI,CAAC,IAAI,CAAC;gBAAE,OAAO,KAAK,CAAC;YACtF,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,qCAAqC,CAAC,CAAC;YAC5D,IAAI,CAAC,CAAC;gBAAE,OAAO,KAAK,CAAC;YACrB,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,CAAE,CAAC;YAClB,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,CAAE,CAAC,IAAI,EAAE,CAAC;YACzB,IAAI,GAAG,KAAK,GAAG;gBAAE,OAAO,KAAK,CAAC,CAAC,qBAAqB;YACpD,mFAAmF;YACnF,MAAM,MAAM,GACV,mHAAmH,CAAC;YACtH,OAAO,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC9C,CAAC;QACD,WAAW,EACT,mGAAmG;YACnG,kGAAkG;YAClG,oGAAoG;YACpG,iFAAiF;KACpF;CACF,CAAC;AAEF,4EAA4E;AAE5E,MAAM,OAAO,iBAAiB;IACnB,IAAI,GAAG,cAAuB,CAAC;IAC/B,SAAS,GAAwB,CAAC,QAAQ,CAAC,CAAC;IAErD,KAAK,CAAC,SAAS;QACb,OAAO,IAAI,CAAC,CAAC,kCAAkC;IACjD,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,KAAqB;QAC7B,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACtB,MAAM,QAAQ,GAAc,EAAE,CAAC;QAC/B,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YAC5B,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,WAAW,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC,EAAE,CAAC;QAChF,CAAC;QACD,IAAI,mBAAmB,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC;YACxC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,WAAW,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC,EAAE,CAAC;QAChF,CAAC;QACD,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC;QAC9B,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAErC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,+DAA+D;YAC/D,mEAAmE;YACnE,IAAI,IAAI,CAAC,QAAQ,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC;gBAAE,SAAS;YACvD,IAAI,CAAC,OAAO,CAAC,SAAS,GAAG,CAAC,CAAC;YAC3B,IAAI,CAAyB,CAAC;YAC9B,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;gBACjD,MAAM,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;gBAC3B,MAAM,QAAQ,GAAG,kBAAkB,CAAC,OAAO,CAAC,CAAC;gBAC7C,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,QAAQ,EAAE,OAAO,EAAE,OAAO,CAAC;oBAAE,SAAS;gBAE5D,MAAM,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC;gBACvC,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC;gBACxC,MAAM,OAAO,GAAG,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;gBACtD,IAAI,gBAAgB,CAAC,OAAO,EAAE,IAAI,CAAC,EAAE,CAAC;oBAAE,SAAS;gBACjD,QAAQ,CAAC,IAAI,CAAC;oBACZ,EAAE,EAAE,aAAa,CAAC;wBAChB,MAAM,EAAE,IAAI,CAAC,IAAI;wBACjB,IAAI,EAAE,KAAK,CAAC,QAAQ;wBACpB,IAAI;wBACJ,OAAO,EAAE,IAAI,CAAC,EAAE;qBACjB,CAAC;oBACF,MAAM,EAAE,cAAc;oBACtB,IAAI,EAAE,KAAK,CAAC,QAAQ;oBACpB,IAAI;oBACJ,OAAO,EAAE,IAAI,CAAC,EAAE;oBAChB,GAAG,EAAE,IAAI,CAAC,GAAG;oBACb,QAAQ,EAAE,IAAI,CAAC,QAAQ;oBACvB,OAAO,EAAE,GAAG,IAAI,CAAC,IAAI,YAAY,IAAI,CAAC,GAAG,yCAAyC;oBAClF,QAAQ,EAAE,EAAE,OAAO,EAAE;oBACrB,kEAAkE;oBAClE,mEAAmE;oBACnE,0DAA0D;oBAC1D,UAAU,EAAE,IAAI;oBAChB,MAAM,EAAE,SAAS;oBACjB,WAAW,EAAE,IAAI,CAAC,WAAW;iBAC9B,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,OAAO;YACL,MAAM,EAAE,IAAI,CAAC,IAAI;YACjB,QAAQ;YACR,WAAW,EAAE,KAAK;YAClB,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE;SAC5B,CAAC;IACJ,CAAC;CACF;AAED,wCAAwC;AACxC,MAAM,CAAC,MAAM,QAAQ,GAAG,EAAE,KAAK,EAAE,YAAY,EAAE,kBAAkB,EAAE,YAAY,EAAE,aAAa,EAAE,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Engine } from "./types.js";
|
|
2
|
+
/** Stage-1 engines. Ordered by typical latency (fast first).
|
|
3
|
+
*
|
|
4
|
+
* ``joernEngine`` and ``pysaEngine`` are here despite being expensive —
|
|
5
|
+
* that expense lives in ``aegis index --joern`` / ``aegis index --pysa``
|
|
6
|
+
* (CPG build / taint summary build). At gate time these engines just
|
|
7
|
+
* read pre-computed ``findings.jsonl`` files, so they're milliseconds. */
|
|
8
|
+
export declare const ENGINES: ReadonlyArray<Engine>;
|
|
9
|
+
/** Stage-2 engines.
|
|
10
|
+
*
|
|
11
|
+
* Both engines spend an LLM message + are gated by the orchestrator's
|
|
12
|
+
* routing predicate (only invoked when stage-1 surfaced something OR
|
|
13
|
+
* Vul-RAG signal is above threshold).
|
|
14
|
+
*
|
|
15
|
+
* ``propertyTestEngine`` PROVES bugs by generating a Hypothesis property
|
|
16
|
+
* via Claude and executing it in a WSL sandbox. A counterexample = a
|
|
17
|
+
* definitive bug (not a speculative judgement) so its findings get
|
|
18
|
+
* confidence 0.95 — effectively a hard block when severity high. */
|
|
19
|
+
export declare const STAGE2_ENGINES: ReadonlyArray<Engine>;
|
|
20
|
+
/** All engines (stage 1 + stage 2) — used by `aegis doctor` to report
|
|
21
|
+
* availability across the full set. */
|
|
22
|
+
export declare const ALL_ENGINES: ReadonlyArray<Engine>;
|
|
23
|
+
/** Subset by name — used by CLI / tests to filter. Searches stage-1 and
|
|
24
|
+
* stage-2 engines so e.g. ``engineByName("llm-critic")`` works. */
|
|
25
|
+
export declare function engineByName(name: string): Engine | undefined;
|
|
26
|
+
//# sourceMappingURL=registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/engines/registry.ts"],"names":[],"mappings":"AAmBA,OAAO,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAQpC;;;;;0EAK0E;AAC1E,eAAO,MAAM,OAAO,EAAE,aAAa,CAAC,MAAM,CAYxC,CAAC;AAEH;;;;;;;;;oEASoE;AACpE,eAAO,MAAM,cAAc,EAAE,aAAa,CAAC,MAAM,CAG/C,CAAC;AAEH;uCACuC;AACvC,eAAO,MAAM,WAAW,EAAE,aAAa,CAAC,MAAM,CAG5C,CAAC;AAEH;mEACmE;AACnE,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAE7D"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/** Registry of all engines.
|
|
2
|
+
*
|
|
3
|
+
* Engines are split into two stages:
|
|
4
|
+
* - ``ENGINES`` (stage 1): fast deterministic — run in parallel on every file.
|
|
5
|
+
* Latency budget ≤ 500 ms p95.
|
|
6
|
+
* - ``STAGE2_ENGINES`` (stage 2): the LLM critic. Runs only when the
|
|
7
|
+
* orchestrator's routing predicate decides it's worth the LLM cost. Sees
|
|
8
|
+
* the merged stage-1 findings + project context + Vul-RAG hits.
|
|
9
|
+
*
|
|
10
|
+
* Keeping the two arrays separate makes the orchestrator's two-stage loop
|
|
11
|
+
* obvious and lets ad-hoc callers (tests, CLI) skip stage 2 trivially.
|
|
12
|
+
*/
|
|
13
|
+
import { AiSinksEngine } from "./ai-sinks.js";
|
|
14
|
+
import { joernEngine } from "./joern.js";
|
|
15
|
+
import { JsSinksEngine } from "./js-sinks.js";
|
|
16
|
+
import { llmCriticEngine } from "./llm-critic.js";
|
|
17
|
+
import { propertyTestEngine } from "./property-test.js";
|
|
18
|
+
import { pysaEngine } from "./pysa.js";
|
|
19
|
+
import { PythonSinksEngine } from "./python-sinks.js";
|
|
20
|
+
import { ESLintEngine } from "./eslint.js";
|
|
21
|
+
import { PyrightEngine } from "./pyright.js";
|
|
22
|
+
import { SecretScanEngine } from "./secret-scan.js";
|
|
23
|
+
import { SemgrepEngine } from "./semgrep.js";
|
|
24
|
+
import { TreeSitterEngine } from "./treesitter.js";
|
|
25
|
+
import { TscEngine } from "./tsc.js";
|
|
26
|
+
/** Stage-1 engines. Ordered by typical latency (fast first).
|
|
27
|
+
*
|
|
28
|
+
* ``joernEngine`` and ``pysaEngine`` are here despite being expensive —
|
|
29
|
+
* that expense lives in ``aegis index --joern`` / ``aegis index --pysa``
|
|
30
|
+
* (CPG build / taint summary build). At gate time these engines just
|
|
31
|
+
* read pre-computed ``findings.jsonl`` files, so they're milliseconds. */
|
|
32
|
+
export const ENGINES = Object.freeze([
|
|
33
|
+
new SecretScanEngine(),
|
|
34
|
+
new PythonSinksEngine(),
|
|
35
|
+
new JsSinksEngine(),
|
|
36
|
+
new AiSinksEngine(),
|
|
37
|
+
new TreeSitterEngine(),
|
|
38
|
+
new ESLintEngine(),
|
|
39
|
+
new PyrightEngine(),
|
|
40
|
+
new TscEngine(),
|
|
41
|
+
new SemgrepEngine(),
|
|
42
|
+
joernEngine,
|
|
43
|
+
pysaEngine,
|
|
44
|
+
]);
|
|
45
|
+
/** Stage-2 engines.
|
|
46
|
+
*
|
|
47
|
+
* Both engines spend an LLM message + are gated by the orchestrator's
|
|
48
|
+
* routing predicate (only invoked when stage-1 surfaced something OR
|
|
49
|
+
* Vul-RAG signal is above threshold).
|
|
50
|
+
*
|
|
51
|
+
* ``propertyTestEngine`` PROVES bugs by generating a Hypothesis property
|
|
52
|
+
* via Claude and executing it in a WSL sandbox. A counterexample = a
|
|
53
|
+
* definitive bug (not a speculative judgement) so its findings get
|
|
54
|
+
* confidence 0.95 — effectively a hard block when severity high. */
|
|
55
|
+
export const STAGE2_ENGINES = Object.freeze([
|
|
56
|
+
llmCriticEngine,
|
|
57
|
+
propertyTestEngine,
|
|
58
|
+
]);
|
|
59
|
+
/** All engines (stage 1 + stage 2) — used by `aegis doctor` to report
|
|
60
|
+
* availability across the full set. */
|
|
61
|
+
export const ALL_ENGINES = Object.freeze([
|
|
62
|
+
...ENGINES,
|
|
63
|
+
...STAGE2_ENGINES,
|
|
64
|
+
]);
|
|
65
|
+
/** Subset by name — used by CLI / tests to filter. Searches stage-1 and
|
|
66
|
+
* stage-2 engines so e.g. ``engineByName("llm-critic")`` works. */
|
|
67
|
+
export function engineByName(name) {
|
|
68
|
+
return ALL_ENGINES.find((e) => e.name === name);
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/engines/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAEtD,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAErC;;;;;0EAK0E;AAC1E,MAAM,CAAC,MAAM,OAAO,GAA0B,MAAM,CAAC,MAAM,CAAC;IAC1D,IAAI,gBAAgB,EAAE;IACtB,IAAI,iBAAiB,EAAE;IACvB,IAAI,aAAa,EAAE;IACnB,IAAI,aAAa,EAAE;IACnB,IAAI,gBAAgB,EAAE;IACtB,IAAI,YAAY,EAAE;IAClB,IAAI,aAAa,EAAE;IACnB,IAAI,SAAS,EAAE;IACf,IAAI,aAAa,EAAE;IACnB,WAAW;IACX,UAAU;CACX,CAAC,CAAC;AAEH;;;;;;;;;oEASoE;AACpE,MAAM,CAAC,MAAM,cAAc,GAA0B,MAAM,CAAC,MAAM,CAAC;IACjE,eAAe;IACf,kBAAkB;CACnB,CAAC,CAAC;AAEH;uCACuC;AACvC,MAAM,CAAC,MAAM,WAAW,GAA0B,MAAM,CAAC,MAAM,CAAC;IAC9D,GAAG,OAAO;IACV,GAAG,cAAc;CAClB,CAAC,CAAC;AAEH;mEACmE;AACnE,MAAM,UAAU,YAAY,CAAC,IAAY;IACvC,OAAO,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;AAClD,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Embedded secret scanner — no external binary.
|
|
3
|
+
*
|
|
4
|
+
* Rules adapted from the public `gitleaks` ruleset (MIT) — covers the
|
|
5
|
+
* highest-volume real-world leak shapes: AWS keys, GitHub/GitLab/Slack
|
|
6
|
+
* tokens, Stripe, JWT, generic private keys, and high-entropy
|
|
7
|
+
* `*KEY|*TOKEN|*SECRET|*PASS*` assignments.
|
|
8
|
+
*
|
|
9
|
+
* False-positive mitigation: a value containing `EXAMPLE`, `PLACEHOLDER`,
|
|
10
|
+
* `<your-...>`, `xxxx...`, or fewer than 10 effectively-unique chars is
|
|
11
|
+
* skipped — empirically these are all template / docs.
|
|
12
|
+
*/
|
|
13
|
+
import { Engine, EngineRunInput, EngineRunResult } from "./types.js";
|
|
14
|
+
import { Lang } from "../lang.js";
|
|
15
|
+
export declare class SecretScanEngine implements Engine {
|
|
16
|
+
readonly name = "secret-scan";
|
|
17
|
+
readonly languages: "all";
|
|
18
|
+
available(): Promise<boolean>;
|
|
19
|
+
run(input: EngineRunInput): Promise<EngineRunResult>;
|
|
20
|
+
}
|
|
21
|
+
export declare const SECRET_SCAN_LANGS: ReadonlyArray<Lang>;
|
|
22
|
+
//# sourceMappingURL=secret-scan.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"secret-scan.d.ts","sourceRoot":"","sources":["../../src/engines/secret-scan.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAErE,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AA+GlC,qBAAa,gBAAiB,YAAW,MAAM;IAC7C,QAAQ,CAAC,IAAI,iBAAiB;IAC9B,QAAQ,CAAC,SAAS,EAAG,KAAK,CAAU;IAE9B,SAAS,IAAI,OAAO,CAAC,OAAO,CAAC;IAI7B,GAAG,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO,CAAC,eAAe,CAAC;CAgD3D;AAQD,eAAO,MAAM,iBAAiB,EAAE,aAAa,CAAC,IAAI,CAkBjD,CAAC"}
|