awesome-slash 2.4.4 → 2.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +6 -6
- package/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +123 -1
- package/README.md +186 -159
- package/SECURITY.md +25 -81
- package/adapters/codex/install.sh +58 -16
- package/adapters/opencode/install.sh +92 -23
- package/lib/index.js +47 -4
- package/lib/patterns/review-patterns.js +58 -11
- package/lib/patterns/slop-patterns.js +154 -147
- package/lib/platform/detect-platform.js +99 -350
- package/lib/platform/detection-configs.js +93 -0
- package/lib/platform/state-dir.js +122 -0
- package/lib/platform/verify-tools.js +10 -78
- package/lib/schemas/README.md +195 -0
- package/lib/schemas/validator.js +247 -0
- package/lib/sources/custom-handler.js +199 -0
- package/lib/sources/policy-questions.js +239 -0
- package/lib/sources/source-cache.js +164 -0
- package/lib/state/workflow-state.js +368 -665
- package/lib/types/README.md +292 -0
- package/lib/types/agent-frontmatter.d.ts +134 -0
- package/lib/types/command-frontmatter.d.ts +107 -0
- package/lib/types/hook-frontmatter.d.ts +115 -0
- package/lib/types/index.d.ts +84 -0
- package/lib/types/plugin-manifest.d.ts +102 -0
- package/lib/types/skill-frontmatter.d.ts +89 -0
- package/lib/utils/cache-manager.js +154 -0
- package/lib/utils/context-optimizer.js +5 -36
- package/lib/utils/deprecation.js +37 -0
- package/lib/utils/shell-escape.js +88 -0
- package/mcp-server/index.js +513 -22
- package/package.json +6 -2
- package/plugins/deslop-around/.claude-plugin/plugin.json +1 -1
- package/plugins/deslop-around/lib/index.js +170 -0
- package/plugins/deslop-around/lib/patterns/review-patterns.js +58 -11
- package/plugins/deslop-around/lib/patterns/slop-patterns.js +169 -129
- package/plugins/deslop-around/lib/platform/detect-platform.js +162 -316
- package/plugins/deslop-around/lib/platform/detection-configs.js +93 -0
- package/plugins/deslop-around/lib/platform/state-dir.js +122 -0
- package/plugins/deslop-around/lib/platform/verify-tools.js +10 -78
- package/plugins/deslop-around/lib/schemas/README.md +195 -0
- package/plugins/deslop-around/lib/schemas/validator.js +247 -0
- package/plugins/deslop-around/lib/sources/custom-handler.js +199 -0
- package/plugins/deslop-around/lib/sources/policy-questions.js +239 -0
- package/plugins/deslop-around/lib/sources/source-cache.js +164 -0
- package/plugins/deslop-around/lib/state/workflow-state.js +387 -484
- package/plugins/deslop-around/lib/types/README.md +292 -0
- package/plugins/deslop-around/lib/types/agent-frontmatter.d.ts +134 -0
- package/plugins/deslop-around/lib/types/command-frontmatter.d.ts +107 -0
- package/plugins/deslop-around/lib/types/hook-frontmatter.d.ts +115 -0
- package/plugins/deslop-around/lib/types/index.d.ts +84 -0
- package/plugins/deslop-around/lib/types/plugin-manifest.d.ts +102 -0
- package/plugins/deslop-around/lib/types/skill-frontmatter.d.ts +89 -0
- package/plugins/deslop-around/lib/utils/cache-manager.js +154 -0
- package/plugins/deslop-around/lib/utils/context-optimizer.js +115 -37
- package/plugins/deslop-around/lib/utils/deprecation.js +37 -0
- package/plugins/deslop-around/lib/utils/shell-escape.js +88 -0
- package/plugins/next-task/.claude-plugin/plugin.json +1 -1
- package/plugins/next-task/agents/delivery-validator.md +2 -2
- package/plugins/next-task/agents/implementation-agent.md +3 -4
- package/plugins/next-task/agents/planning-agent.md +77 -19
- package/plugins/next-task/agents/review-orchestrator.md +21 -122
- package/plugins/next-task/agents/task-discoverer.md +164 -23
- package/plugins/next-task/commands/next-task.md +180 -14
- package/plugins/next-task/lib/index.js +170 -0
- package/plugins/next-task/lib/patterns/review-patterns.js +58 -11
- package/plugins/next-task/lib/patterns/slop-patterns.js +169 -129
- package/plugins/next-task/lib/platform/detect-platform.js +162 -316
- package/plugins/next-task/lib/platform/detection-configs.js +93 -0
- package/plugins/next-task/lib/platform/state-dir.js +122 -0
- package/plugins/next-task/lib/platform/verify-tools.js +10 -78
- package/plugins/next-task/lib/schemas/README.md +195 -0
- package/plugins/next-task/lib/schemas/validator.js +247 -0
- package/plugins/next-task/lib/sources/custom-handler.js +199 -0
- package/plugins/next-task/lib/sources/policy-questions.js +239 -0
- package/plugins/next-task/lib/sources/source-cache.js +164 -0
- package/plugins/next-task/lib/state/workflow-state.js +387 -484
- package/plugins/next-task/lib/types/README.md +292 -0
- package/plugins/next-task/lib/types/agent-frontmatter.d.ts +134 -0
- package/plugins/next-task/lib/types/command-frontmatter.d.ts +107 -0
- package/plugins/next-task/lib/types/hook-frontmatter.d.ts +115 -0
- package/plugins/next-task/lib/types/index.d.ts +84 -0
- package/plugins/next-task/lib/types/plugin-manifest.d.ts +102 -0
- package/plugins/next-task/lib/types/skill-frontmatter.d.ts +89 -0
- package/plugins/next-task/lib/utils/cache-manager.js +154 -0
- package/plugins/next-task/lib/utils/context-optimizer.js +115 -37
- package/plugins/next-task/lib/utils/deprecation.js +37 -0
- package/plugins/next-task/lib/utils/shell-escape.js +88 -0
- package/plugins/project-review/.claude-plugin/plugin.json +1 -1
- package/plugins/project-review/lib/index.js +170 -0
- package/plugins/project-review/lib/patterns/review-patterns.js +58 -11
- package/plugins/project-review/lib/patterns/slop-patterns.js +169 -129
- package/plugins/project-review/lib/platform/detect-platform.js +162 -316
- package/plugins/project-review/lib/platform/detection-configs.js +93 -0
- package/plugins/project-review/lib/platform/state-dir.js +122 -0
- package/plugins/project-review/lib/platform/verify-tools.js +10 -78
- package/plugins/project-review/lib/schemas/README.md +195 -0
- package/plugins/project-review/lib/schemas/validator.js +247 -0
- package/plugins/project-review/lib/sources/custom-handler.js +199 -0
- package/plugins/project-review/lib/sources/policy-questions.js +239 -0
- package/plugins/project-review/lib/sources/source-cache.js +164 -0
- package/plugins/project-review/lib/state/workflow-state.js +387 -484
- package/plugins/project-review/lib/types/README.md +292 -0
- package/plugins/project-review/lib/types/agent-frontmatter.d.ts +134 -0
- package/plugins/project-review/lib/types/command-frontmatter.d.ts +107 -0
- package/plugins/project-review/lib/types/hook-frontmatter.d.ts +115 -0
- package/plugins/project-review/lib/types/index.d.ts +84 -0
- package/plugins/project-review/lib/types/plugin-manifest.d.ts +102 -0
- package/plugins/project-review/lib/types/skill-frontmatter.d.ts +89 -0
- package/plugins/project-review/lib/utils/cache-manager.js +154 -0
- package/plugins/project-review/lib/utils/context-optimizer.js +115 -37
- package/plugins/project-review/lib/utils/deprecation.js +37 -0
- package/plugins/project-review/lib/utils/shell-escape.js +88 -0
- package/plugins/reality-check/.claude-plugin/plugin.json +1 -1
- package/plugins/reality-check/agents/code-explorer.md +1 -1
- package/plugins/ship/.claude-plugin/plugin.json +1 -1
- package/plugins/ship/lib/index.js +170 -0
- package/plugins/ship/lib/patterns/review-patterns.js +58 -11
- package/plugins/ship/lib/patterns/slop-patterns.js +169 -129
- package/plugins/ship/lib/platform/detect-platform.js +162 -316
- package/plugins/ship/lib/platform/detection-configs.js +93 -0
- package/plugins/ship/lib/platform/state-dir.js +122 -0
- package/plugins/ship/lib/platform/verify-tools.js +10 -78
- package/plugins/ship/lib/schemas/README.md +195 -0
- package/plugins/ship/lib/schemas/validator.js +247 -0
- package/plugins/ship/lib/sources/custom-handler.js +199 -0
- package/plugins/ship/lib/sources/policy-questions.js +239 -0
- package/plugins/ship/lib/sources/source-cache.js +164 -0
- package/plugins/ship/lib/state/workflow-state.js +387 -484
- package/plugins/ship/lib/types/README.md +292 -0
- package/plugins/ship/lib/types/agent-frontmatter.d.ts +134 -0
- package/plugins/ship/lib/types/command-frontmatter.d.ts +107 -0
- package/plugins/ship/lib/types/hook-frontmatter.d.ts +115 -0
- package/plugins/ship/lib/types/index.d.ts +84 -0
- package/plugins/ship/lib/types/plugin-manifest.d.ts +102 -0
- package/plugins/ship/lib/types/skill-frontmatter.d.ts +89 -0
- package/plugins/ship/lib/utils/cache-manager.js +154 -0
- package/plugins/ship/lib/utils/context-optimizer.js +115 -37
- package/plugins/ship/lib/utils/deprecation.js +37 -0
- package/plugins/ship/lib/utils/shell-escape.js +88 -0
- package/scripts/install/codex.sh +216 -72
- package/scripts/install/opencode.sh +197 -21
- package/lib/state/workflow-state.schema.json +0 -282
- package/plugins/deslop-around/lib/state/workflow-state.schema.json +0 -282
- package/plugins/next-task/agents/policy-selector.md +0 -248
- package/plugins/next-task/lib/state/tasks-registry.schema.json +0 -85
- package/plugins/next-task/lib/state/workflow-state.schema.json +0 -282
- package/plugins/next-task/lib/state/worktree-status.schema.json +0 -219
- package/plugins/project-review/lib/state/workflow-state.schema.json +0 -282
- package/plugins/ship/lib/state/workflow-state.schema.json +0 -282
|
@@ -8,22 +8,34 @@
|
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* Deep freeze an object for V8 optimization and immutability
|
|
11
|
+
* Optimized: uses for-of instead of forEach to avoid function call overhead
|
|
11
12
|
* @param {Object} obj - Object to freeze
|
|
12
13
|
* @returns {Object} Frozen object
|
|
13
14
|
*/
|
|
14
15
|
function deepFreeze(obj) {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
// Freeze the object first (fast path)
|
|
17
|
+
Object.freeze(obj);
|
|
18
|
+
|
|
19
|
+
// Then recursively freeze nested objects (only if needed)
|
|
20
|
+
// Use Object.keys() for cleaner iteration over own properties
|
|
21
|
+
for (const key of Object.keys(obj)) {
|
|
22
|
+
const value = obj[key];
|
|
23
|
+
if (value && typeof value === 'object' && !(value instanceof RegExp)) {
|
|
24
|
+
deepFreeze(value);
|
|
18
25
|
}
|
|
19
|
-
}
|
|
20
|
-
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return obj;
|
|
21
29
|
}
|
|
22
30
|
|
|
23
31
|
// Pre-compiled regex cache for performance (limited to prevent memory growth)
|
|
24
32
|
const MAX_PATTERN_CACHE_SIZE = 50;
|
|
25
33
|
const _compiledExcludePatterns = new Map();
|
|
26
34
|
|
|
35
|
+
// Exclude result cache for directory-level caching (limited to prevent memory growth)
|
|
36
|
+
const MAX_EXCLUDE_RESULT_CACHE_SIZE = 200;
|
|
37
|
+
const _excludeResultCache = new Map();
|
|
38
|
+
|
|
27
39
|
/**
|
|
28
40
|
* Maximum allowed wildcards in a glob pattern to prevent ReDoS
|
|
29
41
|
*/
|
|
@@ -32,40 +44,66 @@ const MAX_GLOB_WILDCARDS = 10;
|
|
|
32
44
|
/**
|
|
33
45
|
* Get a compiled regex for an exclude pattern (cached)
|
|
34
46
|
* Uses safe regex construction to prevent catastrophic backtracking
|
|
47
|
+
* Optimized: uses Map.get() instead of has() + get() (eliminates redundant lookup)
|
|
35
48
|
* @param {string} pattern - Glob pattern to compile
|
|
36
49
|
* @returns {RegExp} Compiled regex
|
|
37
50
|
*/
|
|
38
51
|
function getCompiledPattern(pattern) {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
}
|
|
52
|
+
// Try to get cached pattern (O(1) lookup)
|
|
53
|
+
let cached = _compiledExcludePatterns.get(pattern);
|
|
54
|
+
if (cached) {
|
|
55
|
+
return cached;
|
|
56
|
+
}
|
|
45
57
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
return _compiledExcludePatterns.get(pattern);
|
|
52
|
-
}
|
|
58
|
+
// Enforce cache size limit using FIFO eviction
|
|
59
|
+
if (_compiledExcludePatterns.size >= MAX_PATTERN_CACHE_SIZE) {
|
|
60
|
+
const firstKey = _compiledExcludePatterns.keys().next().value;
|
|
61
|
+
_compiledExcludePatterns.delete(firstKey);
|
|
62
|
+
}
|
|
53
63
|
|
|
54
|
-
|
|
55
|
-
|
|
64
|
+
// Count wildcards to prevent overly complex patterns
|
|
65
|
+
const wildcardCount = (pattern.match(/\*/g) || []).length;
|
|
66
|
+
if (wildcardCount > MAX_GLOB_WILDCARDS) {
|
|
67
|
+
// Too many wildcards - use a safe fallback that matches nothing dangerous
|
|
68
|
+
const safeRegex = /^$/;
|
|
69
|
+
_compiledExcludePatterns.set(pattern, safeRegex);
|
|
70
|
+
return safeRegex;
|
|
71
|
+
}
|
|
56
72
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
73
|
+
// Escape all regex metacharacters except *
|
|
74
|
+
const escaped = pattern.replace(/[.+?^${}()|[\]\\]/g, '\\$&');
|
|
75
|
+
|
|
76
|
+
// Convert glob patterns to regex:
|
|
77
|
+
// - Both * and ** use .* for backward compatibility (patterns match anywhere in path)
|
|
78
|
+
// - ReDoS protection is provided by MAX_GLOB_WILDCARDS limit above
|
|
79
|
+
let regexStr = escaped
|
|
80
|
+
.replace(/\*\*/g, '\0GLOBSTAR\0') // Temporarily mark globstar
|
|
81
|
+
.replace(/\*/g, '.*') // Single star: match anything (backward compatible)
|
|
82
|
+
.replace(/\0GLOBSTAR\0/g, '.*'); // Globstar: match anything
|
|
83
|
+
|
|
84
|
+
regexStr = '^' + regexStr + '$';
|
|
85
|
+
const compiledRegex = new RegExp(regexStr);
|
|
86
|
+
_compiledExcludePatterns.set(pattern, compiledRegex);
|
|
87
|
+
return compiledRegex;
|
|
88
|
+
}
|
|
64
89
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
90
|
+
/**
|
|
91
|
+
* Helper to create secret detection pattern with common metadata
|
|
92
|
+
* Reduces duplication across similar secret patterns (all have same severity/autoFix/language)
|
|
93
|
+
* @param {RegExp} pattern - Detection regex pattern
|
|
94
|
+
* @param {string} description - Human-readable description
|
|
95
|
+
* @param {Array<string>} [additionalExcludes=[]] - Extra files to exclude beyond standard test files
|
|
96
|
+
* @returns {Object} Complete pattern object
|
|
97
|
+
*/
|
|
98
|
+
function createSecretPattern(pattern, description, additionalExcludes = []) {
|
|
99
|
+
return {
|
|
100
|
+
pattern,
|
|
101
|
+
exclude: ['*.test.*', '*.spec.*', '*.example.*', ...additionalExcludes],
|
|
102
|
+
severity: 'critical',
|
|
103
|
+
autoFix: 'flag',
|
|
104
|
+
language: null,
|
|
105
|
+
description
|
|
106
|
+
};
|
|
69
107
|
}
|
|
70
108
|
|
|
71
109
|
/**
|
|
@@ -280,146 +318,99 @@ const slopPatterns = {
|
|
|
280
318
|
/**
|
|
281
319
|
* JWT tokens (eyJ prefix indicates base64 JSON header)
|
|
282
320
|
*/
|
|
283
|
-
jwt_tokens:
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
autoFix: 'flag',
|
|
288
|
-
language: null,
|
|
289
|
-
description: 'Hardcoded JWT token'
|
|
290
|
-
},
|
|
321
|
+
jwt_tokens: createSecretPattern(
|
|
322
|
+
/eyJ[A-Za-z0-9_-]{10,}\.eyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}/,
|
|
323
|
+
'Hardcoded JWT token'
|
|
324
|
+
),
|
|
291
325
|
|
|
292
326
|
/**
|
|
293
327
|
* OpenAI API keys (sk-... format)
|
|
294
328
|
*/
|
|
295
|
-
openai_api_key:
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
autoFix: 'flag',
|
|
300
|
-
language: null,
|
|
301
|
-
description: 'Hardcoded OpenAI API key'
|
|
302
|
-
},
|
|
329
|
+
openai_api_key: createSecretPattern(
|
|
330
|
+
/sk-[a-zA-Z0-9]{32,}/,
|
|
331
|
+
'Hardcoded OpenAI API key'
|
|
332
|
+
),
|
|
303
333
|
|
|
304
334
|
/**
|
|
305
335
|
* GitHub tokens (personal access tokens, fine-grained tokens, OAuth)
|
|
306
336
|
*/
|
|
307
|
-
github_token:
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
autoFix: 'flag',
|
|
312
|
-
language: null,
|
|
313
|
-
description: 'Hardcoded GitHub token'
|
|
314
|
-
},
|
|
337
|
+
github_token: createSecretPattern(
|
|
338
|
+
/(ghp_[a-zA-Z0-9]{36}|gho_[a-zA-Z0-9]{36}|ghu_[a-zA-Z0-9]{36}|ghs_[a-zA-Z0-9]{36}|ghr_[a-zA-Z0-9]{36}|github_pat_[a-zA-Z0-9]{22}_[a-zA-Z0-9]{59})/,
|
|
339
|
+
'Hardcoded GitHub token'
|
|
340
|
+
),
|
|
315
341
|
|
|
316
342
|
/**
|
|
317
343
|
* AWS credentials (access key IDs and secret keys)
|
|
318
344
|
*/
|
|
319
|
-
aws_credentials:
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
autoFix: 'flag',
|
|
324
|
-
language: null,
|
|
325
|
-
description: 'Hardcoded AWS credentials'
|
|
326
|
-
},
|
|
345
|
+
aws_credentials: createSecretPattern(
|
|
346
|
+
/(AKIA[0-9A-Z]{16}|aws_secret_access_key\s*[:=]\s*["'`][A-Za-z0-9/+=]{40}["'`])/i,
|
|
347
|
+
'Hardcoded AWS credentials'
|
|
348
|
+
),
|
|
327
349
|
|
|
328
350
|
/**
|
|
329
351
|
* Google Cloud / Firebase API keys and service accounts
|
|
330
352
|
*/
|
|
331
|
-
google_api_key:
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
autoFix: 'flag',
|
|
336
|
-
language: null,
|
|
337
|
-
description: 'Hardcoded Google/Firebase API key'
|
|
338
|
-
},
|
|
353
|
+
google_api_key: createSecretPattern(
|
|
354
|
+
/(AIza[0-9A-Za-z_-]{35}|[0-9]+-[a-z0-9_]{32}\.apps\.googleusercontent\.com)/,
|
|
355
|
+
'Hardcoded Google/Firebase API key'
|
|
356
|
+
),
|
|
339
357
|
|
|
340
358
|
/**
|
|
341
359
|
* Stripe API keys (live and test)
|
|
342
360
|
*/
|
|
343
|
-
stripe_api_key:
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
autoFix: 'flag',
|
|
348
|
-
language: null,
|
|
349
|
-
description: 'Hardcoded Stripe API key'
|
|
350
|
-
},
|
|
361
|
+
stripe_api_key: createSecretPattern(
|
|
362
|
+
/(sk_live_[a-zA-Z0-9]{24,}|sk_test_[a-zA-Z0-9]{24,}|rk_live_[a-zA-Z0-9]{24,}|rk_test_[a-zA-Z0-9]{24,})/,
|
|
363
|
+
'Hardcoded Stripe API key'
|
|
364
|
+
),
|
|
351
365
|
|
|
352
366
|
/**
|
|
353
367
|
* Slack tokens (bot, user, webhook)
|
|
354
368
|
*/
|
|
355
|
-
slack_token:
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
autoFix: 'flag',
|
|
360
|
-
language: null,
|
|
361
|
-
description: 'Hardcoded Slack token or webhook URL'
|
|
362
|
-
},
|
|
369
|
+
slack_token: createSecretPattern(
|
|
370
|
+
/(xoxb-[0-9]{10,}-[0-9]{10,}-[a-zA-Z0-9]{24}|xoxp-[0-9]{10,}-[0-9]{10,}-[a-zA-Z0-9]{24}|xoxa-[0-9]{10,}-[a-zA-Z0-9]{24}|https:\/\/hooks\.slack\.com\/services\/T[A-Z0-9]{8}\/B[A-Z0-9]{8,}\/[a-zA-Z0-9]{24})/,
|
|
371
|
+
'Hardcoded Slack token or webhook URL'
|
|
372
|
+
),
|
|
363
373
|
|
|
364
374
|
/**
|
|
365
375
|
* Discord tokens and webhook URLs
|
|
366
376
|
*/
|
|
367
|
-
discord_token:
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
autoFix: 'flag',
|
|
372
|
-
language: null,
|
|
373
|
-
description: 'Hardcoded Discord token or webhook'
|
|
374
|
-
},
|
|
377
|
+
discord_token: createSecretPattern(
|
|
378
|
+
/(discord.*["'`][A-Za-z0-9_-]{24}\.[A-Za-z0-9_-]{6}\.[A-Za-z0-9_-]{27}["'`]|https:\/\/discord(?:app)?\.com\/api\/webhooks\/[0-9]+\/[A-Za-z0-9_-]+)/i,
|
|
379
|
+
'Hardcoded Discord token or webhook'
|
|
380
|
+
),
|
|
375
381
|
|
|
376
382
|
/**
|
|
377
383
|
* SendGrid API key
|
|
378
384
|
*/
|
|
379
|
-
sendgrid_api_key:
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
autoFix: 'flag',
|
|
384
|
-
language: null,
|
|
385
|
-
description: 'Hardcoded SendGrid API key'
|
|
386
|
-
},
|
|
385
|
+
sendgrid_api_key: createSecretPattern(
|
|
386
|
+
/SG\.[a-zA-Z0-9_-]{22}\.[a-zA-Z0-9_-]{43}/,
|
|
387
|
+
'Hardcoded SendGrid API key'
|
|
388
|
+
),
|
|
387
389
|
|
|
388
390
|
/**
|
|
389
391
|
* Twilio credentials
|
|
390
392
|
*/
|
|
391
|
-
twilio_credentials:
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
autoFix: 'flag',
|
|
396
|
-
language: null,
|
|
397
|
-
description: 'Hardcoded Twilio credentials'
|
|
398
|
-
},
|
|
393
|
+
twilio_credentials: createSecretPattern(
|
|
394
|
+
/(AC[a-f0-9]{32}|SK[a-f0-9]{32})/,
|
|
395
|
+
'Hardcoded Twilio credentials'
|
|
396
|
+
),
|
|
399
397
|
|
|
400
398
|
/**
|
|
401
399
|
* NPM tokens
|
|
402
400
|
*/
|
|
403
|
-
npm_token:
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
autoFix: 'flag',
|
|
408
|
-
language: null,
|
|
409
|
-
description: 'Hardcoded NPM token'
|
|
410
|
-
},
|
|
401
|
+
npm_token: createSecretPattern(
|
|
402
|
+
/npm_[a-zA-Z0-9]{36}/,
|
|
403
|
+
'Hardcoded NPM token'
|
|
404
|
+
),
|
|
411
405
|
|
|
412
406
|
/**
|
|
413
407
|
* Private keys (RSA, DSA, EC, PGP)
|
|
414
408
|
*/
|
|
415
|
-
private_key:
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
language: null,
|
|
421
|
-
description: 'Private key in source code'
|
|
422
|
-
},
|
|
409
|
+
private_key: createSecretPattern(
|
|
410
|
+
/-----BEGIN\s+(RSA\s+)?PRIVATE\s+KEY-----/,
|
|
411
|
+
'Private key in source code',
|
|
412
|
+
['*.pem.example'] // Additional excludes beyond standard test files
|
|
413
|
+
),
|
|
423
414
|
|
|
424
415
|
/**
|
|
425
416
|
* Generic high-entropy strings (potential secrets)
|
|
@@ -582,6 +573,7 @@ function getPatternsByAutoFix(autoFix) {
|
|
|
582
573
|
|
|
583
574
|
/**
|
|
584
575
|
* Get patterns matching multiple criteria (language AND severity)
|
|
576
|
+
* Optimized: single-pass filtering instead of chained Object.entries
|
|
585
577
|
* @param {Object} criteria - Filter criteria
|
|
586
578
|
* @param {string} [criteria.language] - Language filter
|
|
587
579
|
* @param {string} [criteria.severity] - Severity filter
|
|
@@ -589,27 +581,25 @@ function getPatternsByAutoFix(autoFix) {
|
|
|
589
581
|
* @returns {Object} Patterns matching all criteria
|
|
590
582
|
*/
|
|
591
583
|
function getPatternsByCriteria(criteria = {}) {
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
const langPatterns = getPatternsForLanguage(criteria.language);
|
|
596
|
-
result = Object.fromEntries(
|
|
597
|
-
Object.entries(result).filter(([name]) => name in langPatterns)
|
|
598
|
-
);
|
|
584
|
+
// Fast path: no criteria means return all patterns
|
|
585
|
+
if (!criteria.language && !criteria.severity && !criteria.autoFix) {
|
|
586
|
+
return { ...slopPatterns };
|
|
599
587
|
}
|
|
600
588
|
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
589
|
+
// Pre-fetch filter sets (O(1) Map lookups)
|
|
590
|
+
const langPatterns = criteria.language ? getPatternsForLanguage(criteria.language) : null;
|
|
591
|
+
const severityPatterns = criteria.severity ? getPatternsBySeverity(criteria.severity) : null;
|
|
592
|
+
const autoFixPatterns = criteria.autoFix ? getPatternsByAutoFix(criteria.autoFix) : null;
|
|
593
|
+
|
|
594
|
+
// Single-pass filter: check all criteria at once
|
|
595
|
+
const result = {};
|
|
596
|
+
for (const [name, pattern] of Object.entries(slopPatterns)) {
|
|
597
|
+
// Check all criteria in one pass (short-circuit on first failure)
|
|
598
|
+
if (langPatterns && !(name in langPatterns)) continue;
|
|
599
|
+
if (severityPatterns && !(name in severityPatterns)) continue;
|
|
600
|
+
if (autoFixPatterns && !(name in autoFixPatterns)) continue;
|
|
607
601
|
|
|
608
|
-
|
|
609
|
-
const autoFixPatterns = getPatternsByAutoFix(criteria.autoFix);
|
|
610
|
-
result = Object.fromEntries(
|
|
611
|
-
Object.entries(result).filter(([name]) => name in autoFixPatterns)
|
|
612
|
-
);
|
|
602
|
+
result[name] = pattern;
|
|
613
603
|
}
|
|
614
604
|
|
|
615
605
|
return result;
|
|
@@ -642,7 +632,7 @@ function hasLanguage(language) {
|
|
|
642
632
|
|
|
643
633
|
/**
|
|
644
634
|
* Check if a file should be excluded based on pattern rules
|
|
645
|
-
* Uses pre-compiled regex cache for performance
|
|
635
|
+
* Uses pre-compiled regex cache and result cache for performance
|
|
646
636
|
* @param {string} filePath - File path to check
|
|
647
637
|
* @param {Array<string>} excludePatterns - Exclude patterns
|
|
648
638
|
* @returns {boolean} True if file should be excluded
|
|
@@ -650,10 +640,27 @@ function hasLanguage(language) {
|
|
|
650
640
|
function isFileExcluded(filePath, excludePatterns) {
|
|
651
641
|
if (!excludePatterns || excludePatterns.length === 0) return false;
|
|
652
642
|
|
|
653
|
-
|
|
643
|
+
// Create cache key using JSON.stringify for collision-resistant format
|
|
644
|
+
const cacheKey = JSON.stringify([filePath, excludePatterns]);
|
|
645
|
+
|
|
646
|
+
// Check cache first (O(1) lookup)
|
|
647
|
+
const cached = _excludeResultCache.get(cacheKey);
|
|
648
|
+
if (cached !== undefined) return cached;
|
|
649
|
+
|
|
650
|
+
// Compute result
|
|
651
|
+
const result = excludePatterns.some(pattern => {
|
|
654
652
|
const regex = getCompiledPattern(pattern);
|
|
655
653
|
return regex.test(filePath);
|
|
656
654
|
});
|
|
655
|
+
|
|
656
|
+
// Store in cache with FIFO eviction
|
|
657
|
+
if (_excludeResultCache.size >= MAX_EXCLUDE_RESULT_CACHE_SIZE) {
|
|
658
|
+
const firstKey = _excludeResultCache.keys().next().value;
|
|
659
|
+
_excludeResultCache.delete(firstKey);
|
|
660
|
+
}
|
|
661
|
+
_excludeResultCache.set(cacheKey, result);
|
|
662
|
+
|
|
663
|
+
return result;
|
|
657
664
|
}
|
|
658
665
|
|
|
659
666
|
module.exports = {
|