@trust-assurance-protocol/owaspscan 1.0.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/dist/analysis/ast-analyzer.d.ts +13 -0
- package/dist/analysis/ast-analyzer.d.ts.map +1 -0
- package/dist/analysis/ast-analyzer.js +58 -0
- package/dist/analysis/ast-analyzer.js.map +1 -0
- package/dist/analysis/llm-verifier.d.ts +17 -0
- package/dist/analysis/llm-verifier.d.ts.map +1 -0
- package/dist/analysis/llm-verifier.js +152 -0
- package/dist/analysis/llm-verifier.js.map +1 -0
- package/dist/analysis/result-cache.d.ts +20 -0
- package/dist/analysis/result-cache.d.ts.map +1 -0
- package/dist/analysis/result-cache.js +70 -0
- package/dist/analysis/result-cache.js.map +1 -0
- package/dist/analysis/sinks.d.ts +12 -0
- package/dist/analysis/sinks.d.ts.map +1 -0
- package/dist/analysis/sinks.js +142 -0
- package/dist/analysis/sinks.js.map +1 -0
- package/dist/analysis/sources.d.ts +8 -0
- package/dist/analysis/sources.d.ts.map +1 -0
- package/dist/analysis/sources.js +114 -0
- package/dist/analysis/sources.js.map +1 -0
- package/dist/analysis/taint-engine.d.ts +5 -0
- package/dist/analysis/taint-engine.d.ts.map +1 -0
- package/dist/analysis/taint-engine.js +187 -0
- package/dist/analysis/taint-engine.js.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +227 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/config/loader.d.ts +10 -0
- package/dist/config/loader.d.ts.map +1 -0
- package/dist/config/loader.js +81 -0
- package/dist/config/loader.js.map +1 -0
- package/dist/config/schema.d.ts +23 -0
- package/dist/config/schema.d.ts.map +1 -0
- package/dist/config/schema.js +17 -0
- package/dist/config/schema.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 +250 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/parsers/ast-parser.d.ts +38 -0
- package/dist/parsers/ast-parser.d.ts.map +1 -0
- package/dist/parsers/ast-parser.js +88 -0
- package/dist/parsers/ast-parser.js.map +1 -0
- package/dist/parsers/ast-queries.d.ts +63 -0
- package/dist/parsers/ast-queries.d.ts.map +1 -0
- package/dist/parsers/ast-queries.js +580 -0
- package/dist/parsers/ast-queries.js.map +1 -0
- package/dist/reporter/console.d.ts +8 -0
- package/dist/reporter/console.d.ts.map +1 -0
- package/dist/reporter/console.js +143 -0
- package/dist/reporter/console.js.map +1 -0
- package/dist/reporter/json.d.ts +3 -0
- package/dist/reporter/json.d.ts.map +1 -0
- package/dist/reporter/json.js +7 -0
- package/dist/reporter/json.js.map +1 -0
- package/dist/reporter/llm.d.ts +3 -0
- package/dist/reporter/llm.d.ts.map +1 -0
- package/dist/reporter/llm.js +66 -0
- package/dist/reporter/llm.js.map +1 -0
- package/dist/reporter/sarif.d.ts +3 -0
- package/dist/reporter/sarif.d.ts.map +1 -0
- package/dist/reporter/sarif.js +110 -0
- package/dist/reporter/sarif.js.map +1 -0
- package/dist/rules/owasp-a01/idor.d.ts +3 -0
- package/dist/rules/owasp-a01/idor.d.ts.map +1 -0
- package/dist/rules/owasp-a01/idor.js +48 -0
- package/dist/rules/owasp-a01/idor.js.map +1 -0
- package/dist/rules/owasp-a01/missing-auth-middleware.d.ts +3 -0
- package/dist/rules/owasp-a01/missing-auth-middleware.d.ts.map +1 -0
- package/dist/rules/owasp-a01/missing-auth-middleware.js +41 -0
- package/dist/rules/owasp-a01/missing-auth-middleware.js.map +1 -0
- package/dist/rules/owasp-a01/path-traversal.d.ts +3 -0
- package/dist/rules/owasp-a01/path-traversal.d.ts.map +1 -0
- package/dist/rules/owasp-a01/path-traversal.js +73 -0
- package/dist/rules/owasp-a01/path-traversal.js.map +1 -0
- package/dist/rules/owasp-a02/hardcoded-secrets.d.ts +3 -0
- package/dist/rules/owasp-a02/hardcoded-secrets.d.ts.map +1 -0
- package/dist/rules/owasp-a02/hardcoded-secrets.js +97 -0
- package/dist/rules/owasp-a02/hardcoded-secrets.js.map +1 -0
- package/dist/rules/owasp-a02/insecure-tls.d.ts +3 -0
- package/dist/rules/owasp-a02/insecure-tls.d.ts.map +1 -0
- package/dist/rules/owasp-a02/insecure-tls.js +75 -0
- package/dist/rules/owasp-a02/insecure-tls.js.map +1 -0
- package/dist/rules/owasp-a02/weak-hash.d.ts +3 -0
- package/dist/rules/owasp-a02/weak-hash.d.ts.map +1 -0
- package/dist/rules/owasp-a02/weak-hash.js +73 -0
- package/dist/rules/owasp-a02/weak-hash.js.map +1 -0
- package/dist/rules/owasp-a02/weak-random.d.ts +3 -0
- package/dist/rules/owasp-a02/weak-random.d.ts.map +1 -0
- package/dist/rules/owasp-a02/weak-random.js +70 -0
- package/dist/rules/owasp-a02/weak-random.js.map +1 -0
- package/dist/rules/owasp-a03/command-injection.d.ts +3 -0
- package/dist/rules/owasp-a03/command-injection.d.ts.map +1 -0
- package/dist/rules/owasp-a03/command-injection.js +79 -0
- package/dist/rules/owasp-a03/command-injection.js.map +1 -0
- package/dist/rules/owasp-a03/ldap-injection.d.ts +3 -0
- package/dist/rules/owasp-a03/ldap-injection.d.ts.map +1 -0
- package/dist/rules/owasp-a03/ldap-injection.js +56 -0
- package/dist/rules/owasp-a03/ldap-injection.js.map +1 -0
- package/dist/rules/owasp-a03/nosql-injection.d.ts +3 -0
- package/dist/rules/owasp-a03/nosql-injection.d.ts.map +1 -0
- package/dist/rules/owasp-a03/nosql-injection.js +61 -0
- package/dist/rules/owasp-a03/nosql-injection.js.map +1 -0
- package/dist/rules/owasp-a03/sql-injection.d.ts +3 -0
- package/dist/rules/owasp-a03/sql-injection.d.ts.map +1 -0
- package/dist/rules/owasp-a03/sql-injection.js +88 -0
- package/dist/rules/owasp-a03/sql-injection.js.map +1 -0
- package/dist/rules/owasp-a03/template-injection.d.ts +3 -0
- package/dist/rules/owasp-a03/template-injection.d.ts.map +1 -0
- package/dist/rules/owasp-a03/template-injection.js +64 -0
- package/dist/rules/owasp-a03/template-injection.js.map +1 -0
- package/dist/rules/owasp-a03/xss.d.ts +3 -0
- package/dist/rules/owasp-a03/xss.d.ts.map +1 -0
- package/dist/rules/owasp-a03/xss.js +74 -0
- package/dist/rules/owasp-a03/xss.js.map +1 -0
- package/dist/rules/owasp-a04/mass-assignment.d.ts +3 -0
- package/dist/rules/owasp-a04/mass-assignment.d.ts.map +1 -0
- package/dist/rules/owasp-a04/mass-assignment.js +63 -0
- package/dist/rules/owasp-a04/mass-assignment.js.map +1 -0
- package/dist/rules/owasp-a04/missing-rate-limit.d.ts +3 -0
- package/dist/rules/owasp-a04/missing-rate-limit.d.ts.map +1 -0
- package/dist/rules/owasp-a04/missing-rate-limit.js +48 -0
- package/dist/rules/owasp-a04/missing-rate-limit.js.map +1 -0
- package/dist/rules/owasp-a05/cors-wildcard.d.ts +3 -0
- package/dist/rules/owasp-a05/cors-wildcard.d.ts.map +1 -0
- package/dist/rules/owasp-a05/cors-wildcard.js +79 -0
- package/dist/rules/owasp-a05/cors-wildcard.js.map +1 -0
- package/dist/rules/owasp-a05/debug-mode.d.ts +3 -0
- package/dist/rules/owasp-a05/debug-mode.d.ts.map +1 -0
- package/dist/rules/owasp-a05/debug-mode.js +73 -0
- package/dist/rules/owasp-a05/debug-mode.js.map +1 -0
- package/dist/rules/owasp-a05/default-credentials.d.ts +3 -0
- package/dist/rules/owasp-a05/default-credentials.d.ts.map +1 -0
- package/dist/rules/owasp-a05/default-credentials.js +52 -0
- package/dist/rules/owasp-a05/default-credentials.js.map +1 -0
- package/dist/rules/owasp-a05/error-disclosure.d.ts +3 -0
- package/dist/rules/owasp-a05/error-disclosure.d.ts.map +1 -0
- package/dist/rules/owasp-a05/error-disclosure.js +70 -0
- package/dist/rules/owasp-a05/error-disclosure.js.map +1 -0
- package/dist/rules/owasp-a06/outdated-packages.d.ts +3 -0
- package/dist/rules/owasp-a06/outdated-packages.d.ts.map +1 -0
- package/dist/rules/owasp-a06/outdated-packages.js +75 -0
- package/dist/rules/owasp-a06/outdated-packages.js.map +1 -0
- package/dist/rules/owasp-a07/insecure-cookies.d.ts +3 -0
- package/dist/rules/owasp-a07/insecure-cookies.d.ts.map +1 -0
- package/dist/rules/owasp-a07/insecure-cookies.js +64 -0
- package/dist/rules/owasp-a07/insecure-cookies.js.map +1 -0
- package/dist/rules/owasp-a07/jwt-none-alg.d.ts +3 -0
- package/dist/rules/owasp-a07/jwt-none-alg.d.ts.map +1 -0
- package/dist/rules/owasp-a07/jwt-none-alg.js +81 -0
- package/dist/rules/owasp-a07/jwt-none-alg.js.map +1 -0
- package/dist/rules/owasp-a07/no-password-hashing.d.ts +3 -0
- package/dist/rules/owasp-a07/no-password-hashing.d.ts.map +1 -0
- package/dist/rules/owasp-a07/no-password-hashing.js +70 -0
- package/dist/rules/owasp-a07/no-password-hashing.js.map +1 -0
- package/dist/rules/owasp-a07/weak-session.d.ts +3 -0
- package/dist/rules/owasp-a07/weak-session.d.ts.map +1 -0
- package/dist/rules/owasp-a07/weak-session.js +64 -0
- package/dist/rules/owasp-a07/weak-session.js.map +1 -0
- package/dist/rules/owasp-a08/unsafe-deserialization.d.ts +3 -0
- package/dist/rules/owasp-a08/unsafe-deserialization.d.ts.map +1 -0
- package/dist/rules/owasp-a08/unsafe-deserialization.js +78 -0
- package/dist/rules/owasp-a08/unsafe-deserialization.js.map +1 -0
- package/dist/rules/owasp-a08/unsafe-eval.d.ts +3 -0
- package/dist/rules/owasp-a08/unsafe-eval.d.ts.map +1 -0
- package/dist/rules/owasp-a08/unsafe-eval.js +73 -0
- package/dist/rules/owasp-a08/unsafe-eval.js.map +1 -0
- package/dist/rules/owasp-a09/log-sensitive-data.d.ts +3 -0
- package/dist/rules/owasp-a09/log-sensitive-data.d.ts.map +1 -0
- package/dist/rules/owasp-a09/log-sensitive-data.js +73 -0
- package/dist/rules/owasp-a09/log-sensitive-data.js.map +1 -0
- package/dist/rules/owasp-a09/missing-error-handling.d.ts +3 -0
- package/dist/rules/owasp-a09/missing-error-handling.d.ts.map +1 -0
- package/dist/rules/owasp-a09/missing-error-handling.js +84 -0
- package/dist/rules/owasp-a09/missing-error-handling.js.map +1 -0
- package/dist/rules/owasp-a10/open-redirect.d.ts +3 -0
- package/dist/rules/owasp-a10/open-redirect.d.ts.map +1 -0
- package/dist/rules/owasp-a10/open-redirect.js +67 -0
- package/dist/rules/owasp-a10/open-redirect.js.map +1 -0
- package/dist/rules/owasp-a10/unvalidated-fetch.d.ts +3 -0
- package/dist/rules/owasp-a10/unvalidated-fetch.d.ts.map +1 -0
- package/dist/rules/owasp-a10/unvalidated-fetch.js +85 -0
- package/dist/rules/owasp-a10/unvalidated-fetch.js.map +1 -0
- package/dist/rules/registry.d.ts +20 -0
- package/dist/rules/registry.d.ts.map +1 -0
- package/dist/rules/registry.js +142 -0
- package/dist/rules/registry.js.map +1 -0
- package/dist/scanner/engine.d.ts +21 -0
- package/dist/scanner/engine.d.ts.map +1 -0
- package/dist/scanner/engine.js +260 -0
- package/dist/scanner/engine.js.map +1 -0
- package/dist/scanner/file-walker.d.ts +7 -0
- package/dist/scanner/file-walker.d.ts.map +1 -0
- package/dist/scanner/file-walker.js +81 -0
- package/dist/scanner/file-walker.js.map +1 -0
- package/dist/scanner/language-detect.d.ts +5 -0
- package/dist/scanner/language-detect.d.ts.map +1 -0
- package/dist/scanner/language-detect.js +91 -0
- package/dist/scanner/language-detect.js.map +1 -0
- package/dist/scanner/sca-scanner.d.ts +38 -0
- package/dist/scanner/sca-scanner.d.ts.map +1 -0
- package/dist/scanner/sca-scanner.js +223 -0
- package/dist/scanner/sca-scanner.js.map +1 -0
- package/dist/types/index.d.ts +114 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +25 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/pattern-matcher.d.ts +4 -0
- package/dist/utils/pattern-matcher.d.ts.map +1 -0
- package/dist/utils/pattern-matcher.js +72 -0
- package/dist/utils/pattern-matcher.js.map +1 -0
- package/dist/utils/scoring.d.ts +8 -0
- package/dist/utils/scoring.d.ts.map +1 -0
- package/dist/utils/scoring.js +76 -0
- package/dist/utils/scoring.js.map +1 -0
- package/dist/utils/suppression.d.ts +3 -0
- package/dist/utils/suppression.d.ts.map +1 -0
- package/dist/utils/suppression.js +33 -0
- package/dist/utils/suppression.js.map +1 -0
- package/package.json +94 -0
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
// ============================================================
|
|
2
|
+
// Rule Registry — central loader for all security rules
|
|
3
|
+
// Supports plugin rules via registerRules()
|
|
4
|
+
// ============================================================
|
|
5
|
+
// OWASP A01 — Broken Access Control
|
|
6
|
+
import { MissingAuthMiddleware } from './owasp-a01/missing-auth-middleware.js';
|
|
7
|
+
import { PathTraversal } from './owasp-a01/path-traversal.js';
|
|
8
|
+
import { InsecureDirectObjectRef } from './owasp-a01/idor.js';
|
|
9
|
+
// OWASP A02 — Cryptographic Failures
|
|
10
|
+
import { WeakHash } from './owasp-a02/weak-hash.js';
|
|
11
|
+
import { HardcodedSecrets } from './owasp-a02/hardcoded-secrets.js';
|
|
12
|
+
import { WeakRandom } from './owasp-a02/weak-random.js';
|
|
13
|
+
import { InsecureTLS } from './owasp-a02/insecure-tls.js';
|
|
14
|
+
// OWASP A03 — Injection
|
|
15
|
+
import { SqlInjection } from './owasp-a03/sql-injection.js';
|
|
16
|
+
import { CommandInjection } from './owasp-a03/command-injection.js';
|
|
17
|
+
import { NoSqlInjection } from './owasp-a03/nosql-injection.js';
|
|
18
|
+
import { XssReflected } from './owasp-a03/xss.js';
|
|
19
|
+
import { TemplateInjection } from './owasp-a03/template-injection.js';
|
|
20
|
+
import { LdapInjection } from './owasp-a03/ldap-injection.js';
|
|
21
|
+
// OWASP A04 — Insecure Design
|
|
22
|
+
import { MissingRateLimit } from './owasp-a04/missing-rate-limit.js';
|
|
23
|
+
import { MassAssignment } from './owasp-a04/mass-assignment.js';
|
|
24
|
+
// OWASP A05 — Security Misconfiguration
|
|
25
|
+
import { DebugMode } from './owasp-a05/debug-mode.js';
|
|
26
|
+
import { CorsWildcard } from './owasp-a05/cors-wildcard.js';
|
|
27
|
+
import { ErrorDisclosure } from './owasp-a05/error-disclosure.js';
|
|
28
|
+
import { DefaultCredentials } from './owasp-a05/default-credentials.js';
|
|
29
|
+
// OWASP A06 — Vulnerable & Outdated Components
|
|
30
|
+
import { OutdatedPackages } from './owasp-a06/outdated-packages.js';
|
|
31
|
+
// OWASP A07 — Identification & Authentication Failures
|
|
32
|
+
import { JwtNoneAlgorithm } from './owasp-a07/jwt-none-alg.js';
|
|
33
|
+
import { NoPasswordHashing } from './owasp-a07/no-password-hashing.js';
|
|
34
|
+
import { WeakSessionConfig } from './owasp-a07/weak-session.js';
|
|
35
|
+
import { InsecureCookies } from './owasp-a07/insecure-cookies.js';
|
|
36
|
+
// OWASP A08 — Software & Data Integrity Failures
|
|
37
|
+
import { UnsafeEval } from './owasp-a08/unsafe-eval.js';
|
|
38
|
+
import { UnsafeDeserialization } from './owasp-a08/unsafe-deserialization.js';
|
|
39
|
+
// OWASP A09 — Security Logging & Monitoring Failures
|
|
40
|
+
import { LogSensitiveData } from './owasp-a09/log-sensitive-data.js';
|
|
41
|
+
import { MissingErrorHandling } from './owasp-a09/missing-error-handling.js';
|
|
42
|
+
// OWASP A10 — Server-Side Request Forgery
|
|
43
|
+
import { UnvalidatedFetch } from './owasp-a10/unvalidated-fetch.js';
|
|
44
|
+
import { OpenRedirect } from './owasp-a10/open-redirect.js';
|
|
45
|
+
// Core OWASP Top 10 rules (public/open-source)
|
|
46
|
+
const CORE_RULES = [
|
|
47
|
+
// A01 — Broken Access Control
|
|
48
|
+
MissingAuthMiddleware,
|
|
49
|
+
PathTraversal,
|
|
50
|
+
InsecureDirectObjectRef,
|
|
51
|
+
// A02 — Cryptographic Failures
|
|
52
|
+
HardcodedSecrets,
|
|
53
|
+
WeakHash,
|
|
54
|
+
WeakRandom,
|
|
55
|
+
InsecureTLS,
|
|
56
|
+
// A03 — Injection
|
|
57
|
+
SqlInjection,
|
|
58
|
+
CommandInjection,
|
|
59
|
+
NoSqlInjection,
|
|
60
|
+
XssReflected,
|
|
61
|
+
TemplateInjection,
|
|
62
|
+
LdapInjection,
|
|
63
|
+
// A04 — Insecure Design
|
|
64
|
+
MissingRateLimit,
|
|
65
|
+
MassAssignment,
|
|
66
|
+
// A05 — Security Misconfiguration
|
|
67
|
+
DebugMode,
|
|
68
|
+
CorsWildcard,
|
|
69
|
+
ErrorDisclosure,
|
|
70
|
+
DefaultCredentials,
|
|
71
|
+
// A06 — Vulnerable Components
|
|
72
|
+
OutdatedPackages,
|
|
73
|
+
// A07 — Auth Failures
|
|
74
|
+
JwtNoneAlgorithm,
|
|
75
|
+
NoPasswordHashing,
|
|
76
|
+
WeakSessionConfig,
|
|
77
|
+
InsecureCookies,
|
|
78
|
+
// A08 — Data Integrity
|
|
79
|
+
UnsafeEval,
|
|
80
|
+
UnsafeDeserialization,
|
|
81
|
+
// A09 — Logging Failures
|
|
82
|
+
LogSensitiveData,
|
|
83
|
+
MissingErrorHandling,
|
|
84
|
+
// A10 — SSRF
|
|
85
|
+
UnvalidatedFetch,
|
|
86
|
+
OpenRedirect,
|
|
87
|
+
];
|
|
88
|
+
export class RuleRegistry {
|
|
89
|
+
rules;
|
|
90
|
+
_proRulesLoaded = false;
|
|
91
|
+
constructor(rules = CORE_RULES) {
|
|
92
|
+
this.rules = new Map();
|
|
93
|
+
for (const rule of rules) {
|
|
94
|
+
this.rules.set(rule.id, rule);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
/** Register additional rules (e.g., from @owaspscan/rules-pro) */
|
|
98
|
+
registerRules(rules) {
|
|
99
|
+
for (const rule of rules) {
|
|
100
|
+
this.rules.set(rule.id, rule);
|
|
101
|
+
}
|
|
102
|
+
this._proRulesLoaded = true;
|
|
103
|
+
}
|
|
104
|
+
get proRulesLoaded() {
|
|
105
|
+
return this._proRulesLoaded;
|
|
106
|
+
}
|
|
107
|
+
get coreRuleCount() {
|
|
108
|
+
return CORE_RULES.length;
|
|
109
|
+
}
|
|
110
|
+
getAll() {
|
|
111
|
+
return Array.from(this.rules.values());
|
|
112
|
+
}
|
|
113
|
+
getById(id) {
|
|
114
|
+
return this.rules.get(id);
|
|
115
|
+
}
|
|
116
|
+
getByCategory(category) {
|
|
117
|
+
return this.getAll().filter((r) => r.owasp === category);
|
|
118
|
+
}
|
|
119
|
+
getByLanguage(language) {
|
|
120
|
+
return this.getAll().filter((r) => r.languages.includes('all') || r.languages.includes(language));
|
|
121
|
+
}
|
|
122
|
+
filterByCategories(categoryPrefixes) {
|
|
123
|
+
return this.getAll().filter((rule) => {
|
|
124
|
+
// e.g., 'A01' matches 'A01:2021', 'LLM01' matches 'LLM01:2025'
|
|
125
|
+
return categoryPrefixes.some((prefix) => rule.owasp.startsWith(prefix.toUpperCase()));
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
size() {
|
|
129
|
+
return this.rules.size;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
/** Create a fresh registry, optionally with extra rules */
|
|
133
|
+
export function createRegistry(extraRules) {
|
|
134
|
+
const reg = new RuleRegistry();
|
|
135
|
+
if (extraRules) {
|
|
136
|
+
reg.registerRules(extraRules);
|
|
137
|
+
}
|
|
138
|
+
return reg;
|
|
139
|
+
}
|
|
140
|
+
// Singleton instance
|
|
141
|
+
export const registry = new RuleRegistry();
|
|
142
|
+
//# sourceMappingURL=registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/rules/registry.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { Rule, FileResult, ScanResult, SupportedLanguage, ScanOptions, FailOnLevel } from '../types/index.js';
|
|
2
|
+
import type { TaintMap } from '../analysis/ast-analyzer.js';
|
|
3
|
+
import { sortFindings } from '../utils/scoring.js';
|
|
4
|
+
import { registry } from '../rules/registry.js';
|
|
5
|
+
export interface EngineOptions {
|
|
6
|
+
rules?: string[];
|
|
7
|
+
exclude?: string[];
|
|
8
|
+
recursive: boolean;
|
|
9
|
+
failOn: FailOnLevel;
|
|
10
|
+
verbose: boolean;
|
|
11
|
+
maxFindings?: number;
|
|
12
|
+
sca?: boolean;
|
|
13
|
+
}
|
|
14
|
+
export declare function scanFile(filePath: string, rules: Rule[], crossFileSources?: TaintMap): Promise<FileResult>;
|
|
15
|
+
export declare function scanDirectory(targetPath: string, options: EngineOptions, onProgress?: (current: number, total: number, filePath: string) => void): Promise<ScanResult>;
|
|
16
|
+
export declare function scanCode(code: string, language: SupportedLanguage, filename?: string, ruleCategories?: string[]): Promise<ScanResult>;
|
|
17
|
+
export declare function buildScanOptions(partial: Partial<ScanOptions> & {
|
|
18
|
+
target: string;
|
|
19
|
+
}): EngineOptions;
|
|
20
|
+
export { registry, sortFindings };
|
|
21
|
+
//# sourceMappingURL=engine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../src/scanner/engine.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,IAAI,EAEJ,UAAU,EACV,UAAU,EACV,iBAAiB,EACjB,WAAW,EACX,WAAW,EACZ,MAAM,mBAAmB,CAAC;AAG3B,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,6BAA6B,CAAC;AAM5D,OAAO,EAAmB,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAEpE,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAiBhD,MAAM,WAAW,aAAa;IAC5B,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,SAAS,EAAE,OAAO,CAAC;IACnB,MAAM,EAAE,WAAW,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,GAAG,CAAC,EAAE,OAAO,CAAC;CACf;AAED,wBAAsB,QAAQ,CAC5B,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,IAAI,EAAE,EACb,gBAAgB,CAAC,EAAE,QAAQ,GAC1B,OAAO,CAAC,UAAU,CAAC,CAuFrB;AAED,wBAAsB,aAAa,CACjC,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,aAAa,EACtB,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI,GACtE,OAAO,CAAC,UAAU,CAAC,CA6FrB;AAED,wBAAsB,QAAQ,CAC5B,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,iBAAiB,EAC3B,QAAQ,SAAa,EACrB,cAAc,CAAC,EAAE,MAAM,EAAE,GACxB,OAAO,CAAC,UAAU,CAAC,CA6ErB;AAED,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,OAAO,CAAC,WAAW,CAAC,GAAG;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG,aAAa,CASlG;AAED,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,CAAC"}
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
// ============================================================
|
|
2
|
+
// Scan Engine — orchestrates file walking, rule application, reporting
|
|
3
|
+
// ============================================================
|
|
4
|
+
import { analyzeTaint } from '../analysis/taint-engine.js';
|
|
5
|
+
import { analyzeAST } from '../analysis/ast-analyzer.js';
|
|
6
|
+
import { parseCode } from '../parsers/ast-parser.js';
|
|
7
|
+
import { collectExportedTaintSources } from '../parsers/ast-queries.js';
|
|
8
|
+
import { detectLanguage, languageMatches } from './language-detect.js';
|
|
9
|
+
import { walkFiles, readFileSafe } from './file-walker.js';
|
|
10
|
+
import { applyPatterns } from '../utils/pattern-matcher.js';
|
|
11
|
+
import { buildScanResult, sortFindings } from '../utils/scoring.js';
|
|
12
|
+
import { runSCA } from './sca-scanner.js';
|
|
13
|
+
import { registry } from '../rules/registry.js';
|
|
14
|
+
// Auto-discover and load @trust-assurance-protocol/rules-pro if installed
|
|
15
|
+
let _proDiscoveryDone = false;
|
|
16
|
+
async function loadProRules() {
|
|
17
|
+
if (_proDiscoveryDone)
|
|
18
|
+
return;
|
|
19
|
+
_proDiscoveryDone = true;
|
|
20
|
+
try {
|
|
21
|
+
// @ts-ignore — @trust-assurance-protocol/rules-pro is an optional dependency, may not be installed
|
|
22
|
+
const mod = await import('@trust-assurance-protocol/rules-pro');
|
|
23
|
+
if (mod.proRules && Array.isArray(mod.proRules)) {
|
|
24
|
+
registry.registerRules(mod.proRules);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
// @trust-assurance-protocol/rules-pro not installed — run with core rules only
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
export async function scanFile(filePath, rules, crossFileSources) {
|
|
32
|
+
const startTime = Date.now();
|
|
33
|
+
const content = readFileSafe(filePath);
|
|
34
|
+
if (content === null) {
|
|
35
|
+
return {
|
|
36
|
+
filePath,
|
|
37
|
+
language: 'all',
|
|
38
|
+
findings: [],
|
|
39
|
+
linesScanned: 0,
|
|
40
|
+
rulesApplied: 0,
|
|
41
|
+
scanDurationMs: 0,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
const lines = content.split('\n');
|
|
45
|
+
const firstLine = lines[0] ?? '';
|
|
46
|
+
const language = detectLanguage(filePath, firstLine) ?? 'all';
|
|
47
|
+
const applicableRules = rules.filter((rule) => languageMatches(rule.languages, language));
|
|
48
|
+
const findings = [];
|
|
49
|
+
// --- Tier 2: AST analysis (runs first — highest structural confidence) ---
|
|
50
|
+
if (language === 'javascript' || language === 'typescript' || language === 'python') {
|
|
51
|
+
const astFindings = analyzeAST(content, language, filePath, rules, crossFileSources);
|
|
52
|
+
findings.push(...astFindings);
|
|
53
|
+
}
|
|
54
|
+
// --- Tier 1: Regex (covers languages without AST + rules not covered by AST) ---
|
|
55
|
+
for (const rule of applicableRules) {
|
|
56
|
+
const matches = applyPatterns(content, rule.patterns);
|
|
57
|
+
for (const match of matches) {
|
|
58
|
+
// Skip if AST already found this rule at this line (AST is higher quality)
|
|
59
|
+
const isDupe = findings.some((f) => f.ruleId === rule.id && Math.abs(f.line - match.line) <= 2);
|
|
60
|
+
if (isDupe)
|
|
61
|
+
continue;
|
|
62
|
+
findings.push({
|
|
63
|
+
ruleId: rule.id,
|
|
64
|
+
ruleName: rule.name,
|
|
65
|
+
owasp: rule.owasp,
|
|
66
|
+
cwe: rule.cwe,
|
|
67
|
+
severity: rule.severity,
|
|
68
|
+
filePath,
|
|
69
|
+
line: match.line,
|
|
70
|
+
column: match.column,
|
|
71
|
+
snippet: match.snippet,
|
|
72
|
+
message: `${rule.name} — ${rule.description.slice(0, 150)}`,
|
|
73
|
+
fix: rule.fix,
|
|
74
|
+
references: rule.references,
|
|
75
|
+
confidence: 'MEDIUM',
|
|
76
|
+
analysisMethod: 'regex',
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
// --- Tier 3: Regex taint (fallback for languages without AST support) ---
|
|
81
|
+
// For JS/TS/Python the AST already handles both direct and indirect taint detection.
|
|
82
|
+
// Regex taint runs only for other languages (Go, Java, PHP, etc.).
|
|
83
|
+
if (language !== 'javascript' && language !== 'typescript' && language !== 'python') {
|
|
84
|
+
const taintFindings = analyzeTaint(content, language, filePath, rules);
|
|
85
|
+
for (const tf of taintFindings) {
|
|
86
|
+
const isDupe = findings.some((f) => f.ruleId === tf.ruleId && Math.abs(f.line - tf.line) <= 2);
|
|
87
|
+
if (!isDupe) {
|
|
88
|
+
findings.push(tf);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
// Sort findings by line number
|
|
93
|
+
findings.sort((a, b) => a.line - b.line);
|
|
94
|
+
return {
|
|
95
|
+
filePath,
|
|
96
|
+
language: language,
|
|
97
|
+
findings,
|
|
98
|
+
linesScanned: lines.length,
|
|
99
|
+
rulesApplied: applicableRules.length,
|
|
100
|
+
scanDurationMs: Date.now() - startTime,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
export async function scanDirectory(targetPath, options, onProgress) {
|
|
104
|
+
await loadProRules();
|
|
105
|
+
const startTime = Date.now();
|
|
106
|
+
// Determine which rules to apply
|
|
107
|
+
let rules;
|
|
108
|
+
if (options.rules && options.rules.length > 0) {
|
|
109
|
+
rules = registry.filterByCategories(options.rules);
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
rules = registry.getAll();
|
|
113
|
+
}
|
|
114
|
+
// Discover all files
|
|
115
|
+
const files = await walkFiles(targetPath, {
|
|
116
|
+
recursive: options.recursive,
|
|
117
|
+
exclude: options.exclude,
|
|
118
|
+
});
|
|
119
|
+
if (options.verbose) {
|
|
120
|
+
process.stderr.write(`Found ${files.length} files to scan with ${rules.length} rules\n`);
|
|
121
|
+
}
|
|
122
|
+
// --- Cross-file taint pre-pass (JS/TS only) ---
|
|
123
|
+
// Collect exported functions that return tainted values so downstream files
|
|
124
|
+
// can treat calls to those functions as taint sources.
|
|
125
|
+
const crossFileSources = new Map();
|
|
126
|
+
for (const filePath of files) {
|
|
127
|
+
const ext = filePath.split('.').pop() ?? '';
|
|
128
|
+
if (ext !== 'js' && ext !== 'ts' && ext !== 'jsx' && ext !== 'tsx' && ext !== 'mjs' && ext !== 'cjs')
|
|
129
|
+
continue;
|
|
130
|
+
const content = readFileSafe(filePath);
|
|
131
|
+
if (!content)
|
|
132
|
+
continue;
|
|
133
|
+
const firstLine = content.split('\n')[0] ?? '';
|
|
134
|
+
const lang = detectLanguage(filePath, firstLine);
|
|
135
|
+
if (lang !== 'javascript' && lang !== 'typescript')
|
|
136
|
+
continue;
|
|
137
|
+
const tree = parseCode(content, lang);
|
|
138
|
+
if (!tree)
|
|
139
|
+
continue;
|
|
140
|
+
const exported = collectExportedTaintSources(tree.rootNode, lang);
|
|
141
|
+
for (const [k, v] of exported) {
|
|
142
|
+
crossFileSources.set(k, v);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
if (options.verbose && crossFileSources.size > 0) {
|
|
146
|
+
process.stderr.write(`Cross-file taint sources found: ${crossFileSources.size}\n`);
|
|
147
|
+
}
|
|
148
|
+
// Scan each file
|
|
149
|
+
const fileResults = [];
|
|
150
|
+
let totalFindings = 0;
|
|
151
|
+
for (let i = 0; i < files.length; i++) {
|
|
152
|
+
const filePath = files[i];
|
|
153
|
+
if (onProgress) {
|
|
154
|
+
onProgress(i + 1, files.length, filePath);
|
|
155
|
+
}
|
|
156
|
+
const result = await scanFile(filePath, rules, crossFileSources);
|
|
157
|
+
fileResults.push(result);
|
|
158
|
+
totalFindings += result.findings.length;
|
|
159
|
+
// Early exit if maxFindings exceeded
|
|
160
|
+
if (options.maxFindings && totalFindings >= options.maxFindings) {
|
|
161
|
+
if (options.verbose) {
|
|
162
|
+
process.stderr.write(`Max findings limit (${options.maxFindings}) reached. Stopping.\n`);
|
|
163
|
+
}
|
|
164
|
+
break;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
// SCA dependency scanning (opt-in)
|
|
168
|
+
if (options.sca) {
|
|
169
|
+
const scaFindings = await runSCA(targetPath);
|
|
170
|
+
if (scaFindings.length > 0) {
|
|
171
|
+
// Attach SCA findings to a synthetic "manifest" file result
|
|
172
|
+
const manifestResult = {
|
|
173
|
+
filePath: targetPath,
|
|
174
|
+
language: 'all',
|
|
175
|
+
findings: scaFindings,
|
|
176
|
+
linesScanned: 0,
|
|
177
|
+
rulesApplied: 1,
|
|
178
|
+
scanDurationMs: 0,
|
|
179
|
+
};
|
|
180
|
+
fileResults.push(manifestResult);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
return buildScanResult(targetPath, fileResults, Date.now() - startTime, options.failOn);
|
|
184
|
+
}
|
|
185
|
+
export async function scanCode(code, language, filename = '<inline>', ruleCategories) {
|
|
186
|
+
await loadProRules();
|
|
187
|
+
const startTime = Date.now();
|
|
188
|
+
let rules;
|
|
189
|
+
if (ruleCategories && ruleCategories.length > 0) {
|
|
190
|
+
rules = registry.filterByCategories(ruleCategories);
|
|
191
|
+
}
|
|
192
|
+
else {
|
|
193
|
+
rules = registry.getAll();
|
|
194
|
+
}
|
|
195
|
+
const applicableRules = rules.filter((rule) => languageMatches(rule.languages, language));
|
|
196
|
+
const lines = code.split('\n');
|
|
197
|
+
const findings = [];
|
|
198
|
+
// --- Tier 2: AST (runs first — highest structural confidence) ---
|
|
199
|
+
if (language === 'javascript' || language === 'typescript' || language === 'python') {
|
|
200
|
+
const astFindings = analyzeAST(code, language, filename, applicableRules);
|
|
201
|
+
findings.push(...astFindings);
|
|
202
|
+
}
|
|
203
|
+
// --- Tier 1: Regex (fallback for rules not covered by AST) ---
|
|
204
|
+
for (const rule of applicableRules) {
|
|
205
|
+
const matches = applyPatterns(code, rule.patterns);
|
|
206
|
+
for (const match of matches) {
|
|
207
|
+
const isDupe = findings.some((f) => f.ruleId === rule.id && Math.abs(f.line - match.line) <= 2);
|
|
208
|
+
if (isDupe)
|
|
209
|
+
continue;
|
|
210
|
+
findings.push({
|
|
211
|
+
ruleId: rule.id,
|
|
212
|
+
ruleName: rule.name,
|
|
213
|
+
owasp: rule.owasp,
|
|
214
|
+
cwe: rule.cwe,
|
|
215
|
+
severity: rule.severity,
|
|
216
|
+
filePath: filename,
|
|
217
|
+
line: match.line,
|
|
218
|
+
column: match.column,
|
|
219
|
+
snippet: match.snippet,
|
|
220
|
+
message: `${rule.name} — ${rule.description.slice(0, 150)}`,
|
|
221
|
+
fix: rule.fix,
|
|
222
|
+
references: rule.references,
|
|
223
|
+
confidence: 'MEDIUM',
|
|
224
|
+
analysisMethod: 'regex',
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
// --- Tier 3: Regex taint (fallback for non-AST languages only) ---
|
|
229
|
+
if (language !== 'javascript' && language !== 'typescript' && language !== 'python') {
|
|
230
|
+
const taintFindings = analyzeTaint(code, language, filename, applicableRules);
|
|
231
|
+
for (const tf of taintFindings) {
|
|
232
|
+
const isDupe = findings.some((f) => f.ruleId === tf.ruleId && Math.abs(f.line - tf.line) <= 2);
|
|
233
|
+
if (!isDupe) {
|
|
234
|
+
findings.push(tf);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
findings.sort((a, b) => a.line - b.line);
|
|
239
|
+
const fileResult = {
|
|
240
|
+
filePath: filename,
|
|
241
|
+
language,
|
|
242
|
+
findings,
|
|
243
|
+
linesScanned: lines.length,
|
|
244
|
+
rulesApplied: applicableRules.length,
|
|
245
|
+
scanDurationMs: Date.now() - startTime,
|
|
246
|
+
};
|
|
247
|
+
return buildScanResult(filename, [fileResult], Date.now() - startTime, 'never');
|
|
248
|
+
}
|
|
249
|
+
export function buildScanOptions(partial) {
|
|
250
|
+
return {
|
|
251
|
+
rules: partial.rules,
|
|
252
|
+
exclude: partial.exclude,
|
|
253
|
+
recursive: partial.recursive ?? true,
|
|
254
|
+
failOn: partial.failOn ?? 'never',
|
|
255
|
+
verbose: partial.verbose ?? false,
|
|
256
|
+
maxFindings: partial.maxFindings,
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
export { registry, sortFindings };
|
|
260
|
+
//# sourceMappingURL=engine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine.js","sourceRoot":"","sources":["../../src/scanner/engine.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export interface WalkOptions {
|
|
2
|
+
recursive: boolean;
|
|
3
|
+
exclude?: string[] | undefined;
|
|
4
|
+
}
|
|
5
|
+
export declare function walkFiles(targetPath: string, options: WalkOptions): Promise<string[]>;
|
|
6
|
+
export declare function readFileSafe(filePath: string): string | null;
|
|
7
|
+
//# sourceMappingURL=file-walker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-walker.d.ts","sourceRoot":"","sources":["../../src/scanner/file-walker.ts"],"names":[],"mappings":"AAmCA,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;CAChC;AAgBD,wBAAsB,SAAS,CAC7B,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,WAAW,GACnB,OAAO,CAAC,MAAM,EAAE,CAAC,CAyCnB;AAED,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAM5D"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
// ============================================================
|
|
2
|
+
// File Walker — discovers scannable files respecting .gitignore
|
|
3
|
+
// ============================================================
|
|
4
|
+
import fs from 'fs';
|
|
5
|
+
import path from 'path';
|
|
6
|
+
import { createRequire } from 'module';
|
|
7
|
+
import { glob } from 'glob';
|
|
8
|
+
import { isSupportedFile } from './language-detect.js';
|
|
9
|
+
const require = createRequire(import.meta.url);
|
|
10
|
+
// ignore is a CJS-only package — use createRequire for ESM compatibility
|
|
11
|
+
const ignoreLib = require('ignore');
|
|
12
|
+
const ALWAYS_IGNORED = [
|
|
13
|
+
'node_modules/**',
|
|
14
|
+
'dist/**',
|
|
15
|
+
'build/**',
|
|
16
|
+
'.git/**',
|
|
17
|
+
'coverage/**',
|
|
18
|
+
'**/*.min.js',
|
|
19
|
+
'**/*.bundle.js',
|
|
20
|
+
'**/*.map',
|
|
21
|
+
'**/__pycache__/**',
|
|
22
|
+
'**/*.pyc',
|
|
23
|
+
'**/.venv/**',
|
|
24
|
+
'**/venv/**',
|
|
25
|
+
'**/.tox/**',
|
|
26
|
+
'**/vendor/**',
|
|
27
|
+
'**/.cache/**',
|
|
28
|
+
];
|
|
29
|
+
function loadGitignore(dir) {
|
|
30
|
+
const ig = ignoreLib();
|
|
31
|
+
const gitignorePath = path.join(dir, '.gitignore');
|
|
32
|
+
if (fs.existsSync(gitignorePath)) {
|
|
33
|
+
const content = fs.readFileSync(gitignorePath, 'utf8');
|
|
34
|
+
ig.add(content);
|
|
35
|
+
}
|
|
36
|
+
return ig;
|
|
37
|
+
}
|
|
38
|
+
export async function walkFiles(targetPath, options) {
|
|
39
|
+
const stat = fs.statSync(targetPath);
|
|
40
|
+
// Single file — validate and return
|
|
41
|
+
if (stat.isFile()) {
|
|
42
|
+
if (isSupportedFile(targetPath)) {
|
|
43
|
+
return [path.resolve(targetPath)];
|
|
44
|
+
}
|
|
45
|
+
return [];
|
|
46
|
+
}
|
|
47
|
+
if (!stat.isDirectory()) {
|
|
48
|
+
throw new Error(`Target path is not a file or directory: ${targetPath}`);
|
|
49
|
+
}
|
|
50
|
+
const baseDir = path.resolve(targetPath);
|
|
51
|
+
const pattern = options.recursive ? '**/*' : '*';
|
|
52
|
+
const ignorePatterns = [
|
|
53
|
+
...ALWAYS_IGNORED,
|
|
54
|
+
...(options.exclude ?? []),
|
|
55
|
+
];
|
|
56
|
+
const gitignore = loadGitignore(baseDir);
|
|
57
|
+
const allFiles = await glob(pattern, {
|
|
58
|
+
cwd: baseDir,
|
|
59
|
+
ignore: ignorePatterns,
|
|
60
|
+
nodir: true,
|
|
61
|
+
absolute: false,
|
|
62
|
+
dot: false,
|
|
63
|
+
});
|
|
64
|
+
const filteredFiles = allFiles.filter((relPath) => {
|
|
65
|
+
// Apply .gitignore rules
|
|
66
|
+
if (gitignore.ignores(relPath))
|
|
67
|
+
return false;
|
|
68
|
+
const absPath = path.join(baseDir, relPath);
|
|
69
|
+
return isSupportedFile(absPath);
|
|
70
|
+
});
|
|
71
|
+
return filteredFiles.map((relPath) => path.join(baseDir, relPath));
|
|
72
|
+
}
|
|
73
|
+
export function readFileSafe(filePath) {
|
|
74
|
+
try {
|
|
75
|
+
return fs.readFileSync(filePath, 'utf8');
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=file-walker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-walker.js","sourceRoot":"","sources":["../../src/scanner/file-walker.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { SupportedLanguage } from '../types/index.js';
|
|
2
|
+
export declare function detectLanguage(filePath: string, firstLine?: string): SupportedLanguage | null;
|
|
3
|
+
export declare function isSupportedFile(filePath: string, firstLine?: string): boolean;
|
|
4
|
+
export declare function languageMatches(ruleLangs: SupportedLanguage[], fileLang: SupportedLanguage): boolean;
|
|
5
|
+
//# sourceMappingURL=language-detect.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"language-detect.d.ts","sourceRoot":"","sources":["../../src/scanner/language-detect.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AA+D3D,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,MAAM,EAChB,SAAS,CAAC,EAAE,MAAM,GACjB,iBAAiB,GAAG,IAAI,CAsB1B;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAE7E;AAGD,wBAAgB,eAAe,CAC7B,SAAS,EAAE,iBAAiB,EAAE,EAC9B,QAAQ,EAAE,iBAAiB,GAC1B,OAAO,CAOT"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
// ============================================================
|
|
2
|
+
// Language Detection — maps file extensions to SupportedLanguage
|
|
3
|
+
// ============================================================
|
|
4
|
+
import path from 'path';
|
|
5
|
+
const EXTENSION_MAP = {
|
|
6
|
+
// JavaScript / TypeScript
|
|
7
|
+
'.js': 'javascript',
|
|
8
|
+
'.mjs': 'javascript',
|
|
9
|
+
'.cjs': 'javascript',
|
|
10
|
+
'.jsx': 'javascript',
|
|
11
|
+
'.ts': 'typescript',
|
|
12
|
+
'.tsx': 'typescript',
|
|
13
|
+
'.mts': 'typescript',
|
|
14
|
+
'.cts': 'typescript',
|
|
15
|
+
// Python
|
|
16
|
+
'.py': 'python',
|
|
17
|
+
'.pyw': 'python',
|
|
18
|
+
'.pyi': 'python',
|
|
19
|
+
// Java
|
|
20
|
+
'.java': 'java',
|
|
21
|
+
// Go
|
|
22
|
+
'.go': 'go',
|
|
23
|
+
// PHP
|
|
24
|
+
'.php': 'php',
|
|
25
|
+
'.php3': 'php',
|
|
26
|
+
'.php4': 'php',
|
|
27
|
+
'.php5': 'php',
|
|
28
|
+
'.phtml': 'php',
|
|
29
|
+
// Ruby
|
|
30
|
+
'.rb': 'ruby',
|
|
31
|
+
'.rake': 'ruby',
|
|
32
|
+
'.gemspec': 'ruby',
|
|
33
|
+
// C#
|
|
34
|
+
'.cs': 'csharp',
|
|
35
|
+
// C / C++
|
|
36
|
+
'.c': 'cpp',
|
|
37
|
+
'.cc': 'cpp',
|
|
38
|
+
'.cpp': 'cpp',
|
|
39
|
+
'.cxx': 'cpp',
|
|
40
|
+
'.h': 'cpp',
|
|
41
|
+
'.hpp': 'cpp',
|
|
42
|
+
// Rust
|
|
43
|
+
'.rs': 'rust',
|
|
44
|
+
};
|
|
45
|
+
const SHEBANG_MAP = {
|
|
46
|
+
'node': 'javascript',
|
|
47
|
+
'nodejs': 'javascript',
|
|
48
|
+
'ts-node': 'typescript',
|
|
49
|
+
'tsx': 'typescript',
|
|
50
|
+
'python': 'python',
|
|
51
|
+
'python3': 'python',
|
|
52
|
+
'python2': 'python',
|
|
53
|
+
'ruby': 'ruby',
|
|
54
|
+
'php': 'php',
|
|
55
|
+
};
|
|
56
|
+
export function detectLanguage(filePath, firstLine) {
|
|
57
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
58
|
+
// Extension-based detection (fast path)
|
|
59
|
+
if (ext in EXTENSION_MAP) {
|
|
60
|
+
return EXTENSION_MAP[ext];
|
|
61
|
+
}
|
|
62
|
+
// Shebang-based detection for extensionless files
|
|
63
|
+
if (firstLine?.startsWith('#!')) {
|
|
64
|
+
const parts = firstLine.split(/\s+/);
|
|
65
|
+
const interpreter = path.basename(parts[0].replace('#!', ''));
|
|
66
|
+
if (interpreter in SHEBANG_MAP) {
|
|
67
|
+
return SHEBANG_MAP[interpreter];
|
|
68
|
+
}
|
|
69
|
+
// Handle /usr/bin/env python style shebangs
|
|
70
|
+
if (parts[1] && path.basename(parts[1]) in SHEBANG_MAP) {
|
|
71
|
+
return SHEBANG_MAP[path.basename(parts[1])];
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
export function isSupportedFile(filePath, firstLine) {
|
|
77
|
+
return detectLanguage(filePath, firstLine) !== null;
|
|
78
|
+
}
|
|
79
|
+
// Languages where JS/TS patterns also apply (superset check)
|
|
80
|
+
export function languageMatches(ruleLangs, fileLang) {
|
|
81
|
+
if (ruleLangs.includes('all'))
|
|
82
|
+
return true;
|
|
83
|
+
if (ruleLangs.includes(fileLang))
|
|
84
|
+
return true;
|
|
85
|
+
// TypeScript is a superset of JavaScript — JS rules apply to TS files
|
|
86
|
+
if (fileLang === 'typescript' && ruleLangs.includes('javascript'))
|
|
87
|
+
return true;
|
|
88
|
+
// JSX/TSX handled by javascript/typescript rules
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=language-detect.js.map
|