@stackmemoryai/stackmemory 0.3.8 → 0.3.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +53 -0
- package/dist/agents/core/agent-task-manager.js +12 -1
- package/dist/agents/core/agent-task-manager.js.map +3 -3
- package/dist/agents/testing-agent.js +610 -0
- package/dist/agents/testing-agent.js.map +7 -0
- package/dist/cli/claude-sm.js +2 -2
- package/dist/cli/claude-sm.js.map +2 -2
- package/dist/cli/codex-sm.js +2 -2
- package/dist/cli/codex-sm.js.map +2 -2
- package/dist/cli/commands/handoff.js +65 -18
- package/dist/cli/commands/handoff.js.map +3 -3
- package/dist/cli/commands/onboard.js +3 -3
- package/dist/cli/commands/onboard.js.map +2 -2
- package/dist/cli/commands/quality.js +2 -2
- package/dist/cli/commands/quality.js.map +2 -2
- package/dist/cli/commands/skills.js +113 -28
- package/dist/cli/commands/skills.js.map +2 -2
- package/dist/cli/commands/test.js +282 -0
- package/dist/cli/commands/test.js.map +7 -0
- package/dist/cli/commands/worktree.js +28 -10
- package/dist/cli/commands/worktree.js.map +2 -2
- package/dist/cli/index.js +2 -0
- package/dist/cli/index.js.map +2 -2
- package/dist/core/config/config-manager.js +26 -0
- package/dist/core/config/config-manager.js.map +3 -3
- package/dist/core/context/frame-manager.js +139 -0
- package/dist/core/context/frame-manager.js.map +2 -2
- package/dist/core/context/recursive-context-manager.js +582 -0
- package/dist/core/context/recursive-context-manager.js.map +7 -0
- package/dist/core/context/refactored-frame-manager.js +180 -1
- package/dist/core/context/refactored-frame-manager.js.map +2 -2
- package/dist/core/execution/parallel-executor.js +254 -0
- package/dist/core/execution/parallel-executor.js.map +7 -0
- package/dist/core/utils/update-checker.js +2 -2
- package/dist/core/utils/update-checker.js.map +2 -2
- package/dist/integrations/anthropic/client.js +259 -0
- package/dist/integrations/anthropic/client.js.map +7 -0
- package/dist/integrations/claude-code/subagent-client-stub.js +16 -0
- package/dist/integrations/claude-code/subagent-client-stub.js.map +7 -0
- package/dist/integrations/claude-code/subagent-client.js +404 -0
- package/dist/integrations/claude-code/subagent-client.js.map +7 -0
- package/dist/skills/claude-skills.js +191 -0
- package/dist/skills/claude-skills.js.map +2 -2
- package/dist/skills/recursive-agent-orchestrator.js +559 -0
- package/dist/skills/recursive-agent-orchestrator.js.map +7 -0
- package/dist/skills/security-secrets-scanner.js +280 -0
- package/dist/skills/security-secrets-scanner.js.map +7 -0
- package/dist/skills/unified-rlm-orchestrator.js +400 -0
- package/dist/skills/unified-rlm-orchestrator.js.map +7 -0
- package/package.json +3 -2
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { execFileSync } from "child_process";
|
|
3
|
+
import fs from "fs";
|
|
4
|
+
import { glob } from "glob";
|
|
5
|
+
const SECRET_PATTERNS = [
|
|
6
|
+
{
|
|
7
|
+
pattern: /lin_api_[a-zA-Z0-9]{40}/,
|
|
8
|
+
name: "Linear API Key",
|
|
9
|
+
envVar: "LINEAR_API_KEY"
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
pattern: /lin_oauth_[a-zA-Z0-9]{64}/,
|
|
13
|
+
name: "Linear OAuth Token",
|
|
14
|
+
envVar: "LINEAR_OAUTH_TOKEN"
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
pattern: /sk-[a-zA-Z0-9]{48}/,
|
|
18
|
+
name: "OpenAI API Key",
|
|
19
|
+
envVar: "OPENAI_API_KEY"
|
|
20
|
+
},
|
|
21
|
+
{ pattern: /npm_[a-zA-Z0-9]{36}/, name: "NPM Token", envVar: "NPM_TOKEN" },
|
|
22
|
+
{
|
|
23
|
+
pattern: /ghp_[a-zA-Z0-9]{36}/,
|
|
24
|
+
name: "GitHub Token",
|
|
25
|
+
envVar: "GITHUB_TOKEN"
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
pattern: /ghs_[a-zA-Z0-9]{36}/,
|
|
29
|
+
name: "GitHub Secret",
|
|
30
|
+
envVar: "GITHUB_SECRET"
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
pattern: /pk_live_[a-zA-Z0-9]{24,}/,
|
|
34
|
+
name: "Stripe Live Key",
|
|
35
|
+
envVar: "STRIPE_LIVE_KEY"
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
pattern: /sk_live_[a-zA-Z0-9]{24,}/,
|
|
39
|
+
name: "Stripe Secret Key",
|
|
40
|
+
envVar: "STRIPE_SECRET_KEY"
|
|
41
|
+
}
|
|
42
|
+
];
|
|
43
|
+
class SecuritySecretsScanner {
|
|
44
|
+
detectedSecrets = /* @__PURE__ */ new Map();
|
|
45
|
+
/**
|
|
46
|
+
* Scan files for hardcoded secrets
|
|
47
|
+
*/
|
|
48
|
+
async scanForSecrets(patterns = [
|
|
49
|
+
"**/*.js",
|
|
50
|
+
"**/*.ts",
|
|
51
|
+
"**/*.jsx",
|
|
52
|
+
"**/*.tsx",
|
|
53
|
+
"**/*.sh"
|
|
54
|
+
]) {
|
|
55
|
+
console.log("\u{1F50D} Scanning for hardcoded secrets...\n");
|
|
56
|
+
for (const pattern of patterns) {
|
|
57
|
+
const files = await glob(pattern, {
|
|
58
|
+
ignore: ["node_modules/**", "dist/**", "build/**", ".git/**"]
|
|
59
|
+
});
|
|
60
|
+
for (const file of files) {
|
|
61
|
+
await this.scanFile(file);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
this.reportFindings();
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Scan a single file for secrets
|
|
68
|
+
*/
|
|
69
|
+
async scanFile(filePath) {
|
|
70
|
+
const content = fs.readFileSync(filePath, "utf-8");
|
|
71
|
+
const lines = content.split("\n");
|
|
72
|
+
lines.forEach((line, index) => {
|
|
73
|
+
for (const secretPattern of SECRET_PATTERNS) {
|
|
74
|
+
if (secretPattern.pattern.test(line)) {
|
|
75
|
+
if (!this.detectedSecrets.has(filePath)) {
|
|
76
|
+
this.detectedSecrets.set(filePath, /* @__PURE__ */ new Set());
|
|
77
|
+
}
|
|
78
|
+
const secrets = this.detectedSecrets.get(filePath);
|
|
79
|
+
if (secrets) {
|
|
80
|
+
secrets.add(
|
|
81
|
+
`Line ${index + 1}: ${secretPattern.name} detected (use ${secretPattern.envVar})`
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Report findings
|
|
90
|
+
*/
|
|
91
|
+
reportFindings() {
|
|
92
|
+
if (this.detectedSecrets.size === 0) {
|
|
93
|
+
console.log("\u2705 No hardcoded secrets detected!\n");
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
console.log(
|
|
97
|
+
`\u26A0\uFE0F Found hardcoded secrets in ${this.detectedSecrets.size} files:
|
|
98
|
+
`
|
|
99
|
+
);
|
|
100
|
+
for (const [file, secrets] of this.detectedSecrets) {
|
|
101
|
+
console.log(`\u{1F4C4} ${file}:`);
|
|
102
|
+
for (const secret of secrets) {
|
|
103
|
+
console.log(` ${secret}`);
|
|
104
|
+
}
|
|
105
|
+
console.log();
|
|
106
|
+
}
|
|
107
|
+
console.log("\u{1F4DD} How to fix:");
|
|
108
|
+
console.log("1. Replace hardcoded values with process.env.VARIABLE_NAME");
|
|
109
|
+
console.log(`2. Add "import 'dotenv/config'" at the top of the file`);
|
|
110
|
+
console.log("3. Add the actual values to your .env file");
|
|
111
|
+
console.log("4. Never commit .env files to git\n");
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Auto-fix secrets in files
|
|
115
|
+
*/
|
|
116
|
+
async autoFix() {
|
|
117
|
+
console.log("\u{1F527} Auto-fixing hardcoded secrets...\n");
|
|
118
|
+
for (const [filePath] of this.detectedSecrets) {
|
|
119
|
+
let content = fs.readFileSync(filePath, "utf-8");
|
|
120
|
+
let modified = false;
|
|
121
|
+
if ((filePath.endsWith(".js") || filePath.endsWith(".ts")) && !content.includes("dotenv/config") && !content.includes("require('dotenv')")) {
|
|
122
|
+
if (content.startsWith("#!/")) {
|
|
123
|
+
const firstNewline = content.indexOf("\n");
|
|
124
|
+
content = content.slice(0, firstNewline + 1) + "\nimport 'dotenv/config';\n" + content.slice(firstNewline + 1);
|
|
125
|
+
} else {
|
|
126
|
+
content = "import 'dotenv/config';\n\n" + content;
|
|
127
|
+
}
|
|
128
|
+
modified = true;
|
|
129
|
+
}
|
|
130
|
+
for (const pattern of SECRET_PATTERNS) {
|
|
131
|
+
const regex = new RegExp(
|
|
132
|
+
`(['"\`])(${pattern.pattern.source})(['"\`])`,
|
|
133
|
+
"g"
|
|
134
|
+
);
|
|
135
|
+
const replacement = `process.env.${pattern.envVar}`;
|
|
136
|
+
if (regex.test(content)) {
|
|
137
|
+
content = content.replace(regex, replacement);
|
|
138
|
+
modified = true;
|
|
139
|
+
const varPattern = new RegExp(
|
|
140
|
+
`const\\s+(\\w+)\\s*=\\s*process\\.env\\.${pattern.envVar}`
|
|
141
|
+
);
|
|
142
|
+
const match = content.match(varPattern);
|
|
143
|
+
if (match) {
|
|
144
|
+
const varName = match[1];
|
|
145
|
+
const checkCode = `
|
|
146
|
+
if (!${varName}) {
|
|
147
|
+
console.error('\u274C ${pattern.envVar} environment variable not set');
|
|
148
|
+
console.log('Please set ${pattern.envVar} in your .env file or export it in your shell');
|
|
149
|
+
process.exit(1);
|
|
150
|
+
}
|
|
151
|
+
`;
|
|
152
|
+
const insertPos = content.indexOf(match[0]) + match[0].length;
|
|
153
|
+
content = content.slice(0, insertPos) + checkCode + content.slice(insertPos);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
if (modified) {
|
|
158
|
+
fs.writeFileSync(filePath, content);
|
|
159
|
+
console.log(`\u2705 Fixed ${filePath}`);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
console.log("\n\u{1F4CB} Next steps:");
|
|
163
|
+
console.log("1. Review the changes");
|
|
164
|
+
console.log("2. Add actual values to .env file");
|
|
165
|
+
console.log("3. Test that everything still works");
|
|
166
|
+
console.log("4. Commit the fixes\n");
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Check git history for secrets
|
|
170
|
+
*/
|
|
171
|
+
async checkGitHistory() {
|
|
172
|
+
console.log("\u{1F50D} Checking git history for secrets...\n");
|
|
173
|
+
try {
|
|
174
|
+
for (const pattern of SECRET_PATTERNS) {
|
|
175
|
+
let result;
|
|
176
|
+
try {
|
|
177
|
+
const gitOutput = execFileSync(
|
|
178
|
+
"git",
|
|
179
|
+
[
|
|
180
|
+
"log",
|
|
181
|
+
"-p",
|
|
182
|
+
"--all",
|
|
183
|
+
`-G${pattern.pattern.source}`,
|
|
184
|
+
"--format=%H %s"
|
|
185
|
+
],
|
|
186
|
+
{
|
|
187
|
+
encoding: "utf-8",
|
|
188
|
+
stdio: "pipe"
|
|
189
|
+
}
|
|
190
|
+
);
|
|
191
|
+
result = gitOutput.split("\n").slice(0, 20).join("\n").trim();
|
|
192
|
+
} catch {
|
|
193
|
+
continue;
|
|
194
|
+
}
|
|
195
|
+
if (result) {
|
|
196
|
+
console.log(`\u26A0\uFE0F Found ${pattern.name} in git history:`);
|
|
197
|
+
console.log(result.split("\n").slice(0, 3).join("\n"));
|
|
198
|
+
console.log("...\n");
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
console.log("\u{1F4DD} To clean git history:");
|
|
202
|
+
console.log("1. Use BFG Repo-Cleaner: bfg --replace-text passwords.txt");
|
|
203
|
+
console.log("2. Or interactive rebase: git rebase -i <commit>");
|
|
204
|
+
console.log("3. Or allow via GitHub: Check push error for allow URLs\n");
|
|
205
|
+
} catch {
|
|
206
|
+
console.log("Could not check git history");
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Generate pre-commit hook
|
|
211
|
+
*/
|
|
212
|
+
generatePreCommitHook() {
|
|
213
|
+
const hookContent = `#!/bin/sh
|
|
214
|
+
# Pre-commit hook to check for hardcoded secrets
|
|
215
|
+
|
|
216
|
+
echo "\u{1F50D} Checking for hardcoded secrets..."
|
|
217
|
+
|
|
218
|
+
# Patterns to check
|
|
219
|
+
patterns=(
|
|
220
|
+
"lin_api_[a-zA-Z0-9]{40}"
|
|
221
|
+
"lin_oauth_[a-zA-Z0-9]{64}"
|
|
222
|
+
"sk-[a-zA-Z0-9]{48}"
|
|
223
|
+
"npm_[a-zA-Z0-9]{36}"
|
|
224
|
+
"ghp_[a-zA-Z0-9]{36}"
|
|
225
|
+
"pk_live_[a-zA-Z0-9]{24,}"
|
|
226
|
+
"sk_live_[a-zA-Z0-9]{24,}"
|
|
227
|
+
)
|
|
228
|
+
|
|
229
|
+
# Check staged files
|
|
230
|
+
for pattern in "\${patterns[@]}"; do
|
|
231
|
+
if git diff --staged --no-color | grep -E "$pattern"; then
|
|
232
|
+
echo "\u274C Found hardcoded secret matching: $pattern"
|
|
233
|
+
echo "Please use environment variables instead!"
|
|
234
|
+
exit 1
|
|
235
|
+
fi
|
|
236
|
+
done
|
|
237
|
+
|
|
238
|
+
echo "\u2705 No hardcoded secrets detected"
|
|
239
|
+
exit 0
|
|
240
|
+
`;
|
|
241
|
+
const hookPath = ".git/hooks/pre-commit";
|
|
242
|
+
fs.writeFileSync(hookPath, hookContent);
|
|
243
|
+
fs.chmodSync(hookPath, "755");
|
|
244
|
+
console.log("\u2705 Generated pre-commit hook at .git/hooks/pre-commit");
|
|
245
|
+
console.log(
|
|
246
|
+
"This will prevent committing hardcoded secrets in the future.\n"
|
|
247
|
+
);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
251
|
+
const scanner = new SecuritySecretsScanner();
|
|
252
|
+
const command = process.argv[2];
|
|
253
|
+
(async () => {
|
|
254
|
+
switch (command) {
|
|
255
|
+
case "scan":
|
|
256
|
+
await scanner.scanForSecrets();
|
|
257
|
+
break;
|
|
258
|
+
case "fix":
|
|
259
|
+
await scanner.scanForSecrets();
|
|
260
|
+
await scanner.autoFix();
|
|
261
|
+
break;
|
|
262
|
+
case "history":
|
|
263
|
+
await scanner.checkGitHistory();
|
|
264
|
+
break;
|
|
265
|
+
case "hook":
|
|
266
|
+
scanner.generatePreCommitHook();
|
|
267
|
+
break;
|
|
268
|
+
default:
|
|
269
|
+
console.log("Usage: security-secrets-scanner [scan|fix|history|hook]");
|
|
270
|
+
console.log(" scan - Scan for hardcoded secrets");
|
|
271
|
+
console.log(" fix - Auto-fix hardcoded secrets");
|
|
272
|
+
console.log(" history - Check git history for secrets");
|
|
273
|
+
console.log(" hook - Generate pre-commit hook");
|
|
274
|
+
}
|
|
275
|
+
})();
|
|
276
|
+
}
|
|
277
|
+
export {
|
|
278
|
+
SecuritySecretsScanner
|
|
279
|
+
};
|
|
280
|
+
//# sourceMappingURL=security-secrets-scanner.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/skills/security-secrets-scanner.ts"],
|
|
4
|
+
"sourcesContent": ["#!/usr/bin/env node\n\n/**\n * Security Secrets Scanner Skill\n * Detects and fixes hardcoded secrets in code files\n */\n\nimport { execFileSync } from 'child_process';\nimport fs from 'fs';\nimport { glob } from 'glob';\n\ninterface SecretPattern {\n pattern: RegExp;\n name: string;\n envVar: string;\n}\n\nconst SECRET_PATTERNS: SecretPattern[] = [\n {\n pattern: /lin_api_[a-zA-Z0-9]{40}/,\n name: 'Linear API Key',\n envVar: 'LINEAR_API_KEY',\n },\n {\n pattern: /lin_oauth_[a-zA-Z0-9]{64}/,\n name: 'Linear OAuth Token',\n envVar: 'LINEAR_OAUTH_TOKEN',\n },\n {\n pattern: /sk-[a-zA-Z0-9]{48}/,\n name: 'OpenAI API Key',\n envVar: 'OPENAI_API_KEY',\n },\n { pattern: /npm_[a-zA-Z0-9]{36}/, name: 'NPM Token', envVar: 'NPM_TOKEN' },\n {\n pattern: /ghp_[a-zA-Z0-9]{36}/,\n name: 'GitHub Token',\n envVar: 'GITHUB_TOKEN',\n },\n {\n pattern: /ghs_[a-zA-Z0-9]{36}/,\n name: 'GitHub Secret',\n envVar: 'GITHUB_SECRET',\n },\n {\n pattern: /pk_live_[a-zA-Z0-9]{24,}/,\n name: 'Stripe Live Key',\n envVar: 'STRIPE_LIVE_KEY',\n },\n {\n pattern: /sk_live_[a-zA-Z0-9]{24,}/,\n name: 'Stripe Secret Key',\n envVar: 'STRIPE_SECRET_KEY',\n },\n];\n\nexport class SecuritySecretsScanner {\n private detectedSecrets: Map<string, Set<string>> = new Map();\n\n /**\n * Scan files for hardcoded secrets\n */\n async scanForSecrets(\n patterns: string[] = [\n '**/*.js',\n '**/*.ts',\n '**/*.jsx',\n '**/*.tsx',\n '**/*.sh',\n ]\n ): Promise<void> {\n console.log('\uD83D\uDD0D Scanning for hardcoded secrets...\\n');\n\n for (const pattern of patterns) {\n const files = await glob(pattern, {\n ignore: ['node_modules/**', 'dist/**', 'build/**', '.git/**'],\n });\n\n for (const file of files) {\n await this.scanFile(file);\n }\n }\n\n this.reportFindings();\n }\n\n /**\n * Scan a single file for secrets\n */\n private async scanFile(filePath: string): Promise<void> {\n const content = fs.readFileSync(filePath, 'utf-8');\n const lines = content.split('\\n');\n\n lines.forEach((line, index) => {\n for (const secretPattern of SECRET_PATTERNS) {\n if (secretPattern.pattern.test(line)) {\n if (!this.detectedSecrets.has(filePath)) {\n this.detectedSecrets.set(filePath, new Set());\n }\n const secrets = this.detectedSecrets.get(filePath);\n if (secrets) {\n secrets.add(\n `Line ${index + 1}: ${secretPattern.name} detected (use ${secretPattern.envVar})`\n );\n }\n }\n }\n });\n }\n\n /**\n * Report findings\n */\n private reportFindings(): void {\n if (this.detectedSecrets.size === 0) {\n console.log('\u2705 No hardcoded secrets detected!\\n');\n return;\n }\n\n console.log(\n `\u26A0\uFE0F Found hardcoded secrets in ${this.detectedSecrets.size} files:\\n`\n );\n\n for (const [file, secrets] of this.detectedSecrets) {\n console.log(`\uD83D\uDCC4 ${file}:`);\n for (const secret of secrets) {\n console.log(` ${secret}`);\n }\n console.log();\n }\n\n console.log('\uD83D\uDCDD How to fix:');\n console.log('1. Replace hardcoded values with process.env.VARIABLE_NAME');\n console.log('2. Add \"import \\'dotenv/config\\'\" at the top of the file');\n console.log('3. Add the actual values to your .env file');\n console.log('4. Never commit .env files to git\\n');\n }\n\n /**\n * Auto-fix secrets in files\n */\n async autoFix(): Promise<void> {\n console.log('\uD83D\uDD27 Auto-fixing hardcoded secrets...\\n');\n\n for (const [filePath] of this.detectedSecrets) {\n let content = fs.readFileSync(filePath, 'utf-8');\n let modified = false;\n\n // Add dotenv import if it's a JS/TS file and doesn't have it\n if (\n (filePath.endsWith('.js') || filePath.endsWith('.ts')) &&\n !content.includes('dotenv/config') &&\n !content.includes(\"require('dotenv')\")\n ) {\n // Add after shebang if present, otherwise at the top\n if (content.startsWith('#!/')) {\n const firstNewline = content.indexOf('\\n');\n content =\n content.slice(0, firstNewline + 1) +\n \"\\nimport 'dotenv/config';\\n\" +\n content.slice(firstNewline + 1);\n } else {\n content = \"import 'dotenv/config';\\n\\n\" + content;\n }\n modified = true;\n }\n\n // Replace secrets with environment variables\n for (const pattern of SECRET_PATTERNS) {\n const regex = new RegExp(\n `(['\"\\`])(${pattern.pattern.source})(['\"\\`])`,\n 'g'\n );\n const replacement = `process.env.${pattern.envVar}`;\n\n if (regex.test(content)) {\n content = content.replace(regex, replacement);\n modified = true;\n\n // Add error checking after the variable definition\n const varPattern = new RegExp(\n `const\\\\s+(\\\\w+)\\\\s*=\\\\s*process\\\\.env\\\\.${pattern.envVar}`\n );\n const match = content.match(varPattern);\n if (match) {\n const varName = match[1];\n const checkCode =\n `\\nif (!${varName}) {\\n` +\n ` console.error('\u274C ${pattern.envVar} environment variable not set');\\n` +\n ` console.log('Please set ${pattern.envVar} in your .env file or export it in your shell');\\n` +\n ` process.exit(1);\\n}\\n`;\n\n // Insert after the variable declaration\n const insertPos = content.indexOf(match[0]) + match[0].length;\n content =\n content.slice(0, insertPos) +\n checkCode +\n content.slice(insertPos);\n }\n }\n }\n\n if (modified) {\n fs.writeFileSync(filePath, content);\n console.log(`\u2705 Fixed ${filePath}`);\n }\n }\n\n console.log('\\n\uD83D\uDCCB Next steps:');\n console.log('1. Review the changes');\n console.log('2. Add actual values to .env file');\n console.log('3. Test that everything still works');\n console.log('4. Commit the fixes\\n');\n }\n\n /**\n * Check git history for secrets\n */\n async checkGitHistory(): Promise<void> {\n console.log('\uD83D\uDD0D Checking git history for secrets...\\n');\n\n try {\n for (const pattern of SECRET_PATTERNS) {\n // Use execFileSync to safely pass arguments\n let result: string;\n try {\n const gitOutput = execFileSync(\n 'git',\n [\n 'log',\n '-p',\n '--all',\n `-G${pattern.pattern.source}`,\n '--format=%H %s',\n ],\n {\n encoding: 'utf-8',\n stdio: 'pipe',\n }\n );\n\n // Manually limit output to first 20 lines for safety\n result = gitOutput.split('\\n').slice(0, 20).join('\\n').trim();\n } catch {\n // Git command failed, skip this pattern\n continue;\n }\n\n if (result) {\n console.log(`\u26A0\uFE0F Found ${pattern.name} in git history:`);\n console.log(result.split('\\n').slice(0, 3).join('\\n'));\n console.log('...\\n');\n }\n }\n\n console.log('\uD83D\uDCDD To clean git history:');\n console.log('1. Use BFG Repo-Cleaner: bfg --replace-text passwords.txt');\n console.log('2. Or interactive rebase: git rebase -i <commit>');\n console.log('3. Or allow via GitHub: Check push error for allow URLs\\n');\n } catch {\n console.log('Could not check git history');\n }\n }\n\n /**\n * Generate pre-commit hook\n */\n generatePreCommitHook(): void {\n const hookContent = `#!/bin/sh\n# Pre-commit hook to check for hardcoded secrets\n\necho \"\uD83D\uDD0D Checking for hardcoded secrets...\"\n\n# Patterns to check\npatterns=(\n \"lin_api_[a-zA-Z0-9]{40}\"\n \"lin_oauth_[a-zA-Z0-9]{64}\"\n \"sk-[a-zA-Z0-9]{48}\"\n \"npm_[a-zA-Z0-9]{36}\"\n \"ghp_[a-zA-Z0-9]{36}\"\n \"pk_live_[a-zA-Z0-9]{24,}\"\n \"sk_live_[a-zA-Z0-9]{24,}\"\n)\n\n# Check staged files\nfor pattern in \"\\${patterns[@]}\"; do\n if git diff --staged --no-color | grep -E \"$pattern\"; then\n echo \"\u274C Found hardcoded secret matching: $pattern\"\n echo \"Please use environment variables instead!\"\n exit 1\n fi\ndone\n\necho \"\u2705 No hardcoded secrets detected\"\nexit 0\n`;\n\n const hookPath = '.git/hooks/pre-commit';\n fs.writeFileSync(hookPath, hookContent);\n fs.chmodSync(hookPath, '755');\n\n console.log('\u2705 Generated pre-commit hook at .git/hooks/pre-commit');\n console.log(\n 'This will prevent committing hardcoded secrets in the future.\\n'\n );\n }\n}\n\n// CLI usage\n\nif (import.meta.url === `file://${process.argv[1]}`) {\n const scanner = new SecuritySecretsScanner();\n const command = process.argv[2];\n\n (async () => {\n switch (command) {\n case 'scan':\n await scanner.scanForSecrets();\n break;\n case 'fix':\n await scanner.scanForSecrets();\n await scanner.autoFix();\n break;\n case 'history':\n await scanner.checkGitHistory();\n break;\n case 'hook':\n scanner.generatePreCommitHook();\n break;\n default:\n console.log('Usage: security-secrets-scanner [scan|fix|history|hook]');\n console.log(' scan - Scan for hardcoded secrets');\n console.log(' fix - Auto-fix hardcoded secrets');\n console.log(' history - Check git history for secrets');\n console.log(' hook - Generate pre-commit hook');\n }\n })();\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|