musubix2 0.5.35 → 0.5.37
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/.musubix-managed +1 -1
- package/dist/assets/skills-manifest.json +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +300 -3
- package/dist/cli.js.map +1 -1
- package/dist/index.js +300 -3
- package/package.json +1 -1
package/.claude/.musubix-managed
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"generator":"musubix2","version":"0.5.
|
|
1
|
+
{"generator":"musubix2","version":"0.5.37","timestamp":"2026-07-09T23:55:01.391Z"}
|
package/dist/cli.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAY,KAAK,aAAa,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.js
CHANGED
|
@@ -8227,12 +8227,14 @@ __export(dist_exports5, {
|
|
|
8227
8227
|
SecretDetector: () => SecretDetector,
|
|
8228
8228
|
SecurityScanner: () => SecurityScanner,
|
|
8229
8229
|
TaintAnalyzer: () => TaintAnalyzer,
|
|
8230
|
+
TaintDataflowAnalyzer: () => TaintDataflowAnalyzer,
|
|
8230
8231
|
blankNonCode: () => blankNonCode,
|
|
8231
8232
|
createComplianceChecker: () => createComplianceChecker,
|
|
8232
8233
|
createSecretDetector: () => createSecretDetector,
|
|
8233
8234
|
createSecurityScanner: () => createSecurityScanner,
|
|
8234
8235
|
isLikelySecret: () => isLikelySecret,
|
|
8235
|
-
isNotFormatMarker: () => isNotFormatMarker
|
|
8236
|
+
isNotFormatMarker: () => isNotFormatMarker,
|
|
8237
|
+
isNotUrlPlaceholder: () => isNotUrlPlaceholder
|
|
8236
8238
|
});
|
|
8237
8239
|
function getLineNumber(code, index) {
|
|
8238
8240
|
return code.substring(0, index).split("\n").length;
|
|
@@ -8241,6 +8243,9 @@ function getSnippet(code, lineNumber) {
|
|
|
8241
8243
|
const lines = code.split("\n");
|
|
8242
8244
|
return lines[lineNumber - 1]?.trim() ?? "";
|
|
8243
8245
|
}
|
|
8246
|
+
function escapeRe(s) {
|
|
8247
|
+
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
8248
|
+
}
|
|
8244
8249
|
function shannonEntropy(s) {
|
|
8245
8250
|
if (s.length === 0)
|
|
8246
8251
|
return 0;
|
|
@@ -8292,6 +8297,14 @@ function isNotFormatMarker(matchText) {
|
|
|
8292
8297
|
return false;
|
|
8293
8298
|
return true;
|
|
8294
8299
|
}
|
|
8300
|
+
function isNotUrlPlaceholder(matchText) {
|
|
8301
|
+
const pass = matchText.match(/:\/\/[^:@/]+:([^:@/]+)@/)?.[1] ?? "";
|
|
8302
|
+
if (/^(pass(word)?|secret|changeme|example|xxx+|\*+|test)$/i.test(pass))
|
|
8303
|
+
return false;
|
|
8304
|
+
if (/[$#]\{|<|%s|:\w+$/.test(pass))
|
|
8305
|
+
return false;
|
|
8306
|
+
return true;
|
|
8307
|
+
}
|
|
8295
8308
|
function blankNonCode(code, hashComments) {
|
|
8296
8309
|
const out = code.split("");
|
|
8297
8310
|
const n = code.length;
|
|
@@ -8380,7 +8393,7 @@ function createComplianceChecker() {
|
|
|
8380
8393
|
function createSecretDetector() {
|
|
8381
8394
|
return new SecretDetector();
|
|
8382
8395
|
}
|
|
8383
|
-
var SecretDetector, TaintAnalyzer, DependencyScanner, ComplianceChecker, SecurityScanner;
|
|
8396
|
+
var SecretDetector, TaintAnalyzer, TaintDataflowAnalyzer, DependencyScanner, ComplianceChecker, SecurityScanner;
|
|
8384
8397
|
var init_dist5 = __esm({
|
|
8385
8398
|
"../security/dist/index.js"() {
|
|
8386
8399
|
"use strict";
|
|
@@ -8426,6 +8439,57 @@ var init_dist5 = __esm({
|
|
|
8426
8439
|
cweId: "CWE-798",
|
|
8427
8440
|
confidence: 0.85
|
|
8428
8441
|
},
|
|
8442
|
+
{
|
|
8443
|
+
// GitHub personal access / OAuth / server / refresh tokens.
|
|
8444
|
+
regex: /\bgh[pousr]_[A-Za-z0-9]{36,}\b/g,
|
|
8445
|
+
severity: "critical",
|
|
8446
|
+
type: "secret-leak",
|
|
8447
|
+
description: "GitHub token detected",
|
|
8448
|
+
suggestion: "Revoke the token and load it from a secrets manager",
|
|
8449
|
+
cweId: "CWE-798",
|
|
8450
|
+
confidence: 0.95
|
|
8451
|
+
},
|
|
8452
|
+
{
|
|
8453
|
+
// Slack tokens (bot/user/app/refresh/legacy).
|
|
8454
|
+
regex: /\bxox[baprs]-[A-Za-z0-9-]{10,}\b/g,
|
|
8455
|
+
severity: "critical",
|
|
8456
|
+
type: "secret-leak",
|
|
8457
|
+
description: "Slack token detected",
|
|
8458
|
+
suggestion: "Revoke the token and load it from a secrets manager",
|
|
8459
|
+
cweId: "CWE-798",
|
|
8460
|
+
confidence: 0.9
|
|
8461
|
+
},
|
|
8462
|
+
{
|
|
8463
|
+
// Stripe / similar `sk_live_` / `rk_live_` secret keys.
|
|
8464
|
+
regex: /\b[sr]k_live_[A-Za-z0-9]{16,}\b/g,
|
|
8465
|
+
severity: "critical",
|
|
8466
|
+
type: "secret-leak",
|
|
8467
|
+
description: "Stripe live secret key detected",
|
|
8468
|
+
suggestion: "Revoke the key and load it from a secrets manager",
|
|
8469
|
+
cweId: "CWE-798",
|
|
8470
|
+
confidence: 0.95
|
|
8471
|
+
},
|
|
8472
|
+
{
|
|
8473
|
+
// Google API key.
|
|
8474
|
+
regex: /\bAIza[A-Za-z0-9_\-]{35}\b/g,
|
|
8475
|
+
severity: "high",
|
|
8476
|
+
type: "secret-leak",
|
|
8477
|
+
description: "Google API key detected",
|
|
8478
|
+
suggestion: "Restrict/revoke the key and load it from a secrets manager",
|
|
8479
|
+
cweId: "CWE-798",
|
|
8480
|
+
confidence: 0.9
|
|
8481
|
+
},
|
|
8482
|
+
{
|
|
8483
|
+
// Credentials embedded in a connection URL: scheme://user:pass@host.
|
|
8484
|
+
regex: /\b[a-z][a-z0-9+.-]*:\/\/[^\s:'"@/]+:[^\s:'"@/]+@[^\s'"/]+/g,
|
|
8485
|
+
severity: "high",
|
|
8486
|
+
type: "hardcoded-credential",
|
|
8487
|
+
description: "Credentials in a connection string / URL detected",
|
|
8488
|
+
suggestion: "Move the username/password out of the URL into a secrets manager",
|
|
8489
|
+
cweId: "CWE-798",
|
|
8490
|
+
confidence: 0.75,
|
|
8491
|
+
validate: isNotUrlPlaceholder
|
|
8492
|
+
},
|
|
8429
8493
|
{
|
|
8430
8494
|
regex: /['"][A-Za-z0-9]{32,}['"]/g,
|
|
8431
8495
|
severity: "medium",
|
|
@@ -8514,6 +8578,120 @@ var init_dist5 = __esm({
|
|
|
8514
8578
|
suggestion: "Use parameterized queries instead of template literals",
|
|
8515
8579
|
cweId: "CWE-89",
|
|
8516
8580
|
confidence: 0.75
|
|
8581
|
+
},
|
|
8582
|
+
// --- Command injection ---------------------------------------------------
|
|
8583
|
+
{
|
|
8584
|
+
regex: /\bos\.system\s*\(/g,
|
|
8585
|
+
severity: "critical",
|
|
8586
|
+
type: "injection",
|
|
8587
|
+
description: "Use of os.system() \u2014 potential command injection",
|
|
8588
|
+
suggestion: "Use subprocess with an argument list and shell=False",
|
|
8589
|
+
cweId: "CWE-78",
|
|
8590
|
+
confidence: 0.85
|
|
8591
|
+
},
|
|
8592
|
+
{
|
|
8593
|
+
regex: /\bsubprocess\.\w+\([^)]*shell\s*=\s*True/g,
|
|
8594
|
+
severity: "high",
|
|
8595
|
+
type: "injection",
|
|
8596
|
+
description: "subprocess call with shell=True \u2014 potential command injection",
|
|
8597
|
+
suggestion: "Pass an argument list and use shell=False",
|
|
8598
|
+
cweId: "CWE-78",
|
|
8599
|
+
confidence: 0.8
|
|
8600
|
+
},
|
|
8601
|
+
{
|
|
8602
|
+
regex: /(?<![.\w>:])(?:shell_exec|passthru|proc_open|popen)\s*\(/g,
|
|
8603
|
+
severity: "critical",
|
|
8604
|
+
type: "injection",
|
|
8605
|
+
description: "Use of a shell-execution function \u2014 potential command injection",
|
|
8606
|
+
suggestion: "Avoid shell execution of untrusted input; use safe APIs with argument arrays",
|
|
8607
|
+
cweId: "CWE-78",
|
|
8608
|
+
confidence: 0.8
|
|
8609
|
+
},
|
|
8610
|
+
{
|
|
8611
|
+
regex: /(?<![.\w>:])(?<!\bdef\s)(?<!\bfunction\s)system\s*\(/g,
|
|
8612
|
+
severity: "high",
|
|
8613
|
+
type: "injection",
|
|
8614
|
+
description: "Use of system() \u2014 potential command injection",
|
|
8615
|
+
suggestion: "Avoid passing untrusted input to system(); use safe execution APIs",
|
|
8616
|
+
cweId: "CWE-78",
|
|
8617
|
+
confidence: 0.65
|
|
8618
|
+
},
|
|
8619
|
+
{
|
|
8620
|
+
regex: /Runtime\.getRuntime\(\)\s*\.\s*exec\s*\(/g,
|
|
8621
|
+
severity: "critical",
|
|
8622
|
+
type: "injection",
|
|
8623
|
+
description: "Runtime.exec() \u2014 potential command injection",
|
|
8624
|
+
suggestion: "Use ProcessBuilder with an argument list and validate inputs",
|
|
8625
|
+
cweId: "CWE-78",
|
|
8626
|
+
confidence: 0.8
|
|
8627
|
+
},
|
|
8628
|
+
// --- SQL injection (formatting/concatenation in DB calls) ----------------
|
|
8629
|
+
{
|
|
8630
|
+
regex: /\b(?:execute|query|raw|prepare|executemany)\s*\(\s*f['"]/g,
|
|
8631
|
+
severity: "high",
|
|
8632
|
+
type: "injection",
|
|
8633
|
+
description: "Potential SQL injection \u2014 f-string in a database call",
|
|
8634
|
+
suggestion: "Use parameterized queries; never build SQL with f-strings",
|
|
8635
|
+
cweId: "CWE-89",
|
|
8636
|
+
confidence: 0.75
|
|
8637
|
+
},
|
|
8638
|
+
{
|
|
8639
|
+
regex: /\b(?:execute|query|raw|prepare)\s*\([^)]*\.format\s*\(/g,
|
|
8640
|
+
severity: "high",
|
|
8641
|
+
type: "injection",
|
|
8642
|
+
description: "Potential SQL injection \u2014 .format() building a query",
|
|
8643
|
+
suggestion: "Use parameterized queries instead of str.format()",
|
|
8644
|
+
cweId: "CWE-89",
|
|
8645
|
+
confidence: 0.7
|
|
8646
|
+
},
|
|
8647
|
+
{
|
|
8648
|
+
regex: /\b(?:execute|query|raw)\s*\([^)]*\+/g,
|
|
8649
|
+
severity: "high",
|
|
8650
|
+
type: "injection",
|
|
8651
|
+
description: "Potential SQL injection \u2014 string concatenation in a query call",
|
|
8652
|
+
suggestion: "Use parameterized queries instead of string concatenation",
|
|
8653
|
+
cweId: "CWE-89",
|
|
8654
|
+
confidence: 0.7
|
|
8655
|
+
},
|
|
8656
|
+
// --- Insecure deserialization -------------------------------------------
|
|
8657
|
+
// --- Insecure deserialization (low severity: real but commonly intentional
|
|
8658
|
+
// in framework internals; triage with --fail-on) ------------------------
|
|
8659
|
+
{
|
|
8660
|
+
regex: /\bpickle\.loads?\s*\(/g,
|
|
8661
|
+
severity: "low",
|
|
8662
|
+
type: "injection",
|
|
8663
|
+
description: "Insecure deserialization \u2014 pickle.load(s) (unsafe on untrusted data)",
|
|
8664
|
+
suggestion: "Never unpickle untrusted data; use a safe format such as JSON",
|
|
8665
|
+
cweId: "CWE-502",
|
|
8666
|
+
confidence: 0.6
|
|
8667
|
+
},
|
|
8668
|
+
{
|
|
8669
|
+
regex: /\byaml\.load\s*\(/g,
|
|
8670
|
+
severity: "low",
|
|
8671
|
+
type: "injection",
|
|
8672
|
+
description: "Insecure deserialization \u2014 yaml.load() without SafeLoader",
|
|
8673
|
+
suggestion: "Use yaml.safe_load() instead of yaml.load()",
|
|
8674
|
+
cweId: "CWE-502",
|
|
8675
|
+
confidence: 0.6
|
|
8676
|
+
},
|
|
8677
|
+
{
|
|
8678
|
+
regex: /(?<![.\w>:])unserialize\s*\(/g,
|
|
8679
|
+
severity: "low",
|
|
8680
|
+
type: "injection",
|
|
8681
|
+
description: "Insecure deserialization \u2014 unserialize() (unsafe on untrusted data)",
|
|
8682
|
+
suggestion: "Avoid unserialize() on untrusted input; use JSON",
|
|
8683
|
+
cweId: "CWE-502",
|
|
8684
|
+
confidence: 0.6
|
|
8685
|
+
},
|
|
8686
|
+
// --- Weak cryptography (low: often used for non-security checksums) -------
|
|
8687
|
+
{
|
|
8688
|
+
regex: /\bhashlib\.(?:md5|sha1)\s*\(|createHash\s*\(\s*['"](?:md5|sha1)['"]/g,
|
|
8689
|
+
severity: "low",
|
|
8690
|
+
type: "injection",
|
|
8691
|
+
description: "Weak cryptographic hash (MD5/SHA-1) detected",
|
|
8692
|
+
suggestion: "Use SHA-256+ (or bcrypt/argon2 for passwords) instead of MD5/SHA-1",
|
|
8693
|
+
cweId: "CWE-327",
|
|
8694
|
+
confidence: 0.5
|
|
8517
8695
|
}
|
|
8518
8696
|
];
|
|
8519
8697
|
analyze(code, filePath) {
|
|
@@ -8521,6 +8699,123 @@ var init_dist5 = __esm({
|
|
|
8521
8699
|
return runPatterns(this.patterns, blankNonCode(code, hashComments), filePath, code);
|
|
8522
8700
|
}
|
|
8523
8701
|
};
|
|
8702
|
+
TaintDataflowAnalyzer = class {
|
|
8703
|
+
sinks = [
|
|
8704
|
+
{
|
|
8705
|
+
re: /\b(?:execute|executemany|query|raw|prepare)\s*\(\s*(\$?\w+)\s*[,)]/g,
|
|
8706
|
+
severity: "high",
|
|
8707
|
+
type: "injection",
|
|
8708
|
+
cweId: "CWE-89",
|
|
8709
|
+
label: "SQL injection \u2014 a dynamically-built string flows into a query",
|
|
8710
|
+
suggestion: "Use parameterized queries; never pass a formatted/concatenated string to the DB."
|
|
8711
|
+
},
|
|
8712
|
+
{
|
|
8713
|
+
re: /\bos\.system\s*\(\s*(\$?\w+)\s*\)/g,
|
|
8714
|
+
severity: "critical",
|
|
8715
|
+
type: "injection",
|
|
8716
|
+
cweId: "CWE-78",
|
|
8717
|
+
label: "Command injection \u2014 a dynamically-built string flows into os.system()",
|
|
8718
|
+
suggestion: "Pass an argument list with shell=False; never build shell strings from input."
|
|
8719
|
+
},
|
|
8720
|
+
{
|
|
8721
|
+
re: /\bsubprocess\.\w+\s*\(\s*(\$?\w+)/g,
|
|
8722
|
+
severity: "high",
|
|
8723
|
+
type: "injection",
|
|
8724
|
+
cweId: "CWE-78",
|
|
8725
|
+
label: "Command injection \u2014 a dynamically-built string flows into subprocess",
|
|
8726
|
+
suggestion: "Pass an argument list with shell=False."
|
|
8727
|
+
},
|
|
8728
|
+
{
|
|
8729
|
+
re: /(?<![.\w>:])(?:system|popen|shell_exec|passthru)\s*\(\s*(\$?\w+)\s*\)/g,
|
|
8730
|
+
severity: "critical",
|
|
8731
|
+
type: "injection",
|
|
8732
|
+
cweId: "CWE-78",
|
|
8733
|
+
label: "Command injection \u2014 a dynamically-built string flows into a shell function",
|
|
8734
|
+
suggestion: "Avoid shell execution of built strings; use safe APIs with argument arrays."
|
|
8735
|
+
},
|
|
8736
|
+
{
|
|
8737
|
+
re: /(?<![.\w>:])eval\s*\(\s*(\$?\w+)\s*\)/g,
|
|
8738
|
+
severity: "critical",
|
|
8739
|
+
type: "injection",
|
|
8740
|
+
cweId: "CWE-95",
|
|
8741
|
+
label: "Code injection \u2014 a dynamically-built string flows into eval()",
|
|
8742
|
+
suggestion: "Never eval built strings; use a safe parser/dispatch table."
|
|
8743
|
+
}
|
|
8744
|
+
];
|
|
8745
|
+
isDynamicRhs(rhs) {
|
|
8746
|
+
if (/^\s*\[/.test(rhs))
|
|
8747
|
+
return false;
|
|
8748
|
+
return /\.\s*format\s*\(/.test(rhs) || // "…".format(x)
|
|
8749
|
+
/\bf['"]/.test(rhs) || // f-string
|
|
8750
|
+
/['"]\s*%\s*[\w([]/.test(rhs) || // "…" % x
|
|
8751
|
+
/['"]\s*\+\s*[$\w]|[$\w.\])]\s*\+\s*['"]/.test(rhs) || // string + var / var + string
|
|
8752
|
+
/['"]\s*\.\s*\$\w/.test(rhs);
|
|
8753
|
+
}
|
|
8754
|
+
analyze(code, filePath) {
|
|
8755
|
+
const hashComments = /\.(py|rb|sh|php|pl|yaml|yml|r)$/i.test(filePath);
|
|
8756
|
+
const lines = blankNonCode(code, hashComments).split("\n");
|
|
8757
|
+
const orig = code.split("\n");
|
|
8758
|
+
const assignRe = /^\s*(\$?[A-Za-z_]\w*)\s*=(?!=)\s*(.+)$/;
|
|
8759
|
+
const tainted = /* @__PURE__ */ new Map();
|
|
8760
|
+
for (let pass = 0; pass < 4; pass++) {
|
|
8761
|
+
let changed = false;
|
|
8762
|
+
lines.forEach((line, i) => {
|
|
8763
|
+
const m = assignRe.exec(line);
|
|
8764
|
+
if (!m)
|
|
8765
|
+
return;
|
|
8766
|
+
const name = m[1];
|
|
8767
|
+
const rhs = m[2];
|
|
8768
|
+
if (tainted.has(name))
|
|
8769
|
+
return;
|
|
8770
|
+
let taint = this.isDynamicRhs(rhs);
|
|
8771
|
+
if (!taint) {
|
|
8772
|
+
for (const t of tainted.keys()) {
|
|
8773
|
+
if (t !== name && new RegExp(`(?<![\\w$])${escapeRe(t)}(?![\\w])`).test(rhs) && /[+%]|\.\s*format|f['"]/.test(rhs)) {
|
|
8774
|
+
taint = true;
|
|
8775
|
+
break;
|
|
8776
|
+
}
|
|
8777
|
+
}
|
|
8778
|
+
}
|
|
8779
|
+
if (taint) {
|
|
8780
|
+
tainted.set(name, i + 1);
|
|
8781
|
+
changed = true;
|
|
8782
|
+
}
|
|
8783
|
+
});
|
|
8784
|
+
if (!changed)
|
|
8785
|
+
break;
|
|
8786
|
+
}
|
|
8787
|
+
if (tainted.size === 0)
|
|
8788
|
+
return [];
|
|
8789
|
+
const findings = [];
|
|
8790
|
+
const seen = /* @__PURE__ */ new Set();
|
|
8791
|
+
lines.forEach((line, i) => {
|
|
8792
|
+
for (const sink of this.sinks) {
|
|
8793
|
+
const re = new RegExp(sink.re.source, "g");
|
|
8794
|
+
let m;
|
|
8795
|
+
while ((m = re.exec(line)) !== null) {
|
|
8796
|
+
const arg = m[1];
|
|
8797
|
+
const def = tainted.get(arg);
|
|
8798
|
+
if (def === void 0 || def >= i + 1)
|
|
8799
|
+
continue;
|
|
8800
|
+
const key = `${i}:${arg}`;
|
|
8801
|
+
if (seen.has(key))
|
|
8802
|
+
continue;
|
|
8803
|
+
seen.add(key);
|
|
8804
|
+
findings.push({
|
|
8805
|
+
type: sink.type,
|
|
8806
|
+
severity: sink.severity,
|
|
8807
|
+
location: { file: filePath, line: i + 1, snippet: (orig[i] ?? "").trim() },
|
|
8808
|
+
description: `${sink.label} (variable '${arg}' built at line ${def})`,
|
|
8809
|
+
suggestion: sink.suggestion,
|
|
8810
|
+
cweId: sink.cweId,
|
|
8811
|
+
confidence: 0.8
|
|
8812
|
+
});
|
|
8813
|
+
}
|
|
8814
|
+
}
|
|
8815
|
+
});
|
|
8816
|
+
return findings;
|
|
8817
|
+
}
|
|
8818
|
+
};
|
|
8524
8819
|
DependencyScanner = class {
|
|
8525
8820
|
patterns = [
|
|
8526
8821
|
{
|
|
@@ -8601,6 +8896,7 @@ var init_dist5 = __esm({
|
|
|
8601
8896
|
this.detectors = options?.detectors ?? [
|
|
8602
8897
|
new SecretDetector(),
|
|
8603
8898
|
new TaintAnalyzer(),
|
|
8899
|
+
new TaintDataflowAnalyzer(),
|
|
8604
8900
|
new DependencyScanner()
|
|
8605
8901
|
];
|
|
8606
8902
|
}
|
|
@@ -17782,6 +18078,7 @@ async function handleSecurity(filePath, failOn, excludeTests) {
|
|
|
17782
18078
|
}
|
|
17783
18079
|
const secrets = createSecretDetector();
|
|
17784
18080
|
const taint = new TaintAnalyzer();
|
|
18081
|
+
const dataflow = new TaintDataflowAnalyzer();
|
|
17785
18082
|
const deps = new DependencyScanner();
|
|
17786
18083
|
const allFiles = collectFiles(filePath, (ext) => ext in EXT_TO_LANG).filter((f) => !isVendorOrMinified(f));
|
|
17787
18084
|
const files = excludeTests ? allFiles.filter((f) => !isTestFile(f)) : allFiles;
|
|
@@ -17789,7 +18086,7 @@ async function handleSecurity(filePath, failOn, excludeTests) {
|
|
|
17789
18086
|
const findings = [];
|
|
17790
18087
|
for (const file of files) {
|
|
17791
18088
|
const code = readFileSync6(file, "utf-8");
|
|
17792
|
-
findings.push(...secrets.scan(code, file), ...taint.analyze(code, file), ...deps.scan(code, file));
|
|
18089
|
+
findings.push(...secrets.scan(code, file), ...taint.analyze(code, file), ...dataflow.analyze(code, file), ...deps.scan(code, file));
|
|
17793
18090
|
}
|
|
17794
18091
|
const bySeverity = /* @__PURE__ */ new Map();
|
|
17795
18092
|
for (const f of findings) {
|