guardrail-security 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/attack-surface/analyzer.d.ts +50 -0
- package/dist/attack-surface/analyzer.d.ts.map +1 -0
- package/dist/attack-surface/analyzer.js +83 -0
- package/dist/attack-surface/index.d.ts +5 -0
- package/dist/attack-surface/index.d.ts.map +1 -0
- package/dist/attack-surface/index.js +20 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +33 -0
- package/dist/languages/index.d.ts +21 -0
- package/dist/languages/index.d.ts.map +1 -0
- package/dist/languages/index.js +78 -0
- package/dist/languages/java-analyzer.d.ts +72 -0
- package/dist/languages/java-analyzer.d.ts.map +1 -0
- package/dist/languages/java-analyzer.js +417 -0
- package/dist/languages/python-analyzer.d.ts +70 -0
- package/dist/languages/python-analyzer.d.ts.map +1 -0
- package/dist/languages/python-analyzer.js +425 -0
- package/dist/license/compatibility-matrix.d.ts +28 -0
- package/dist/license/compatibility-matrix.d.ts.map +1 -0
- package/dist/license/compatibility-matrix.js +323 -0
- package/dist/license/engine.d.ts +77 -0
- package/dist/license/engine.d.ts.map +1 -0
- package/dist/license/engine.js +264 -0
- package/dist/license/index.d.ts +6 -0
- package/dist/license/index.d.ts.map +1 -0
- package/dist/license/index.js +21 -0
- package/dist/sbom/generator.d.ts +108 -0
- package/dist/sbom/generator.d.ts.map +1 -0
- package/dist/sbom/generator.js +271 -0
- package/dist/sbom/index.d.ts +5 -0
- package/dist/sbom/index.d.ts.map +1 -0
- package/dist/sbom/index.js +20 -0
- package/dist/secrets/guardian.d.ts +113 -0
- package/dist/secrets/guardian.d.ts.map +1 -0
- package/dist/secrets/guardian.js +334 -0
- package/dist/secrets/index.d.ts +10 -0
- package/dist/secrets/index.d.ts.map +1 -0
- package/dist/secrets/index.js +30 -0
- package/dist/secrets/patterns.d.ts +42 -0
- package/dist/secrets/patterns.d.ts.map +1 -0
- package/dist/secrets/patterns.js +165 -0
- package/dist/secrets/pre-commit.d.ts +39 -0
- package/dist/secrets/pre-commit.d.ts.map +1 -0
- package/dist/secrets/pre-commit.js +127 -0
- package/dist/secrets/vault-integration.d.ts +83 -0
- package/dist/secrets/vault-integration.d.ts.map +1 -0
- package/dist/secrets/vault-integration.js +295 -0
- package/dist/secrets/vault-providers.d.ts +110 -0
- package/dist/secrets/vault-providers.d.ts.map +1 -0
- package/dist/secrets/vault-providers.js +417 -0
- package/dist/supply-chain/detector.d.ts +80 -0
- package/dist/supply-chain/detector.d.ts.map +1 -0
- package/dist/supply-chain/detector.js +168 -0
- package/dist/supply-chain/index.d.ts +11 -0
- package/dist/supply-chain/index.d.ts.map +1 -0
- package/dist/supply-chain/index.js +26 -0
- package/dist/supply-chain/malicious-db.d.ts +41 -0
- package/dist/supply-chain/malicious-db.d.ts.map +1 -0
- package/dist/supply-chain/malicious-db.js +82 -0
- package/dist/supply-chain/script-analyzer.d.ts +54 -0
- package/dist/supply-chain/script-analyzer.d.ts.map +1 -0
- package/dist/supply-chain/script-analyzer.js +160 -0
- package/dist/supply-chain/typosquat.d.ts +58 -0
- package/dist/supply-chain/typosquat.d.ts.map +1 -0
- package/dist/supply-chain/typosquat.js +257 -0
- package/dist/supply-chain/vulnerability-db.d.ts +114 -0
- package/dist/supply-chain/vulnerability-db.d.ts.map +1 -0
- package/dist/supply-chain/vulnerability-db.js +310 -0
- package/package.json +34 -0
- package/src/__tests__/license/engine.test.ts +250 -0
- package/src/__tests__/supply-chain/typosquat.test.ts +191 -0
- package/src/attack-surface/analyzer.ts +152 -0
- package/src/attack-surface/index.ts +5 -0
- package/src/index.ts +21 -0
- package/src/languages/index.ts +91 -0
- package/src/languages/java-analyzer.ts +490 -0
- package/src/languages/python-analyzer.ts +498 -0
- package/src/license/compatibility-matrix.ts +366 -0
- package/src/license/engine.ts +345 -0
- package/src/license/index.ts +6 -0
- package/src/sbom/generator.ts +355 -0
- package/src/sbom/index.ts +5 -0
- package/src/secrets/guardian.ts +448 -0
- package/src/secrets/index.ts +10 -0
- package/src/secrets/patterns.ts +186 -0
- package/src/secrets/pre-commit.ts +158 -0
- package/src/secrets/vault-integration.ts +360 -0
- package/src/secrets/vault-providers.ts +446 -0
- package/src/supply-chain/detector.ts +252 -0
- package/src/supply-chain/index.ts +11 -0
- package/src/supply-chain/malicious-db.ts +103 -0
- package/src/supply-chain/script-analyzer.ts +194 -0
- package/src/supply-chain/typosquat.ts +302 -0
- package/src/supply-chain/vulnerability-db.ts +386 -0
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.secretsGuardian = exports.SecretsGuardian = exports.SecretType = void 0;
|
|
4
|
+
const database_1 = require("@guardrail/database");
|
|
5
|
+
const core_1 = require("@guardrail/core");
|
|
6
|
+
const patterns_1 = require("./patterns");
|
|
7
|
+
const fs_1 = require("fs");
|
|
8
|
+
const glob_1 = require("glob");
|
|
9
|
+
const path_1 = require("path");
|
|
10
|
+
// Define SecretType locally since it's not exported from database
|
|
11
|
+
var SecretType;
|
|
12
|
+
(function (SecretType) {
|
|
13
|
+
SecretType["API_KEY"] = "api_key";
|
|
14
|
+
SecretType["PASSWORD"] = "password";
|
|
15
|
+
SecretType["TOKEN"] = "token";
|
|
16
|
+
SecretType["CERTIFICATE"] = "certificate";
|
|
17
|
+
SecretType["PRIVATE_KEY"] = "private_key";
|
|
18
|
+
SecretType["DATABASE_URL"] = "database_url";
|
|
19
|
+
SecretType["JWT_SECRET"] = "jwt_secret";
|
|
20
|
+
SecretType["AWS_ACCESS_KEY"] = "aws_access_key";
|
|
21
|
+
SecretType["OTHER"] = "other";
|
|
22
|
+
SecretType["AWS_SECRET_KEY"] = "aws_secret_key";
|
|
23
|
+
SecretType["GITHUB_TOKEN"] = "github_token";
|
|
24
|
+
SecretType["GOOGLE_API_KEY"] = "google_api_key";
|
|
25
|
+
SecretType["STRIPE_KEY"] = "stripe_key";
|
|
26
|
+
SecretType["JWT_TOKEN"] = "jwt_token";
|
|
27
|
+
SecretType["SLACK_TOKEN"] = "slack_token";
|
|
28
|
+
SecretType["API_KEY_GENERIC"] = "api_key_generic";
|
|
29
|
+
SecretType["PASSWORD_GENERIC"] = "password_generic";
|
|
30
|
+
})(SecretType || (exports.SecretType = SecretType = {}));
|
|
31
|
+
/**
|
|
32
|
+
* Secrets & Credential Guardian
|
|
33
|
+
*
|
|
34
|
+
* Detects exposed secrets and credentials in code
|
|
35
|
+
*/
|
|
36
|
+
class SecretsGuardian {
|
|
37
|
+
/**
|
|
38
|
+
* Scan content for secrets
|
|
39
|
+
*/
|
|
40
|
+
async scanContent(content, filePath, options = {}) {
|
|
41
|
+
const detections = [];
|
|
42
|
+
const lines = content.split('\n');
|
|
43
|
+
for (const pattern of patterns_1.SECRET_PATTERNS) {
|
|
44
|
+
const matches = [...content.matchAll(new RegExp(pattern.pattern, 'g'))];
|
|
45
|
+
for (const match of matches) {
|
|
46
|
+
if (!match.index)
|
|
47
|
+
continue;
|
|
48
|
+
// Extract the secret value (first capturing group)
|
|
49
|
+
const value = match[1] || match[0];
|
|
50
|
+
// Calculate entropy
|
|
51
|
+
const entropy = this.calculateEntropy(value);
|
|
52
|
+
// Check minimum entropy requirement
|
|
53
|
+
if (pattern.minEntropy && entropy < pattern.minEntropy) {
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
// Find line number and column
|
|
57
|
+
const beforeMatch = content.substring(0, match.index);
|
|
58
|
+
const lineNumber = beforeMatch.split('\n').length;
|
|
59
|
+
const lineStart = beforeMatch.lastIndexOf('\n') + 1;
|
|
60
|
+
const column = match.index - lineStart + 1;
|
|
61
|
+
// Get context
|
|
62
|
+
const snippet = lines[lineNumber - 1] || '';
|
|
63
|
+
// Check if it's a test value
|
|
64
|
+
const isTest = this.isTestValue(value, snippet);
|
|
65
|
+
// Check for false positives
|
|
66
|
+
const isFalsePositive = this.isFalsePositive(value, pattern.type, snippet);
|
|
67
|
+
if (isFalsePositive) {
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
// Calculate confidence
|
|
71
|
+
const confidence = this.calculateConfidence(value, pattern, entropy, isTest);
|
|
72
|
+
// Skip if below minimum confidence
|
|
73
|
+
if (options.minConfidence && confidence < options.minConfidence) {
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
// Skip if excluding tests
|
|
77
|
+
if (options.excludeTests && isTest) {
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
// Mask the value
|
|
81
|
+
const maskedValue = this.maskValue(value);
|
|
82
|
+
// Generate recommendation
|
|
83
|
+
const recommendation = this.generateRecommendation(pattern.type, isTest);
|
|
84
|
+
// Create detection object
|
|
85
|
+
const detection = {
|
|
86
|
+
id: undefined, // Will be set when saved to database
|
|
87
|
+
filePath,
|
|
88
|
+
secretType: pattern.type,
|
|
89
|
+
maskedValue,
|
|
90
|
+
location: {
|
|
91
|
+
line: lineNumber,
|
|
92
|
+
column,
|
|
93
|
+
snippet: snippet.trim(),
|
|
94
|
+
},
|
|
95
|
+
confidence,
|
|
96
|
+
entropy,
|
|
97
|
+
isTest,
|
|
98
|
+
isRevoked: false,
|
|
99
|
+
recommendation,
|
|
100
|
+
};
|
|
101
|
+
detections.push(detection);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return detections;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Scan entire project
|
|
108
|
+
*/
|
|
109
|
+
async scanProject(projectPath, projectId, options = {}) {
|
|
110
|
+
const excludePatterns = [
|
|
111
|
+
'**/node_modules/**',
|
|
112
|
+
'**/dist/**',
|
|
113
|
+
'**/build/**',
|
|
114
|
+
'**/.git/**',
|
|
115
|
+
'**/coverage/**',
|
|
116
|
+
'**/*.min.js',
|
|
117
|
+
...(options.excludePatterns || []),
|
|
118
|
+
];
|
|
119
|
+
// Find all files to scan
|
|
120
|
+
const files = await (0, glob_1.glob)('**/*', {
|
|
121
|
+
cwd: projectPath,
|
|
122
|
+
ignore: excludePatterns,
|
|
123
|
+
nodir: true,
|
|
124
|
+
});
|
|
125
|
+
const allDetections = [];
|
|
126
|
+
let scannedFiles = 0;
|
|
127
|
+
for (const file of files) {
|
|
128
|
+
try {
|
|
129
|
+
const fullPath = (0, path_1.join)(projectPath, file);
|
|
130
|
+
const content = (0, fs_1.readFileSync)(fullPath, 'utf-8');
|
|
131
|
+
const detections = await this.scanContent(content, file, options);
|
|
132
|
+
// Save to database
|
|
133
|
+
for (const detection of detections) {
|
|
134
|
+
try {
|
|
135
|
+
// @ts-ignore - secretDetection may not exist in schema yet
|
|
136
|
+
await database_1.prisma.secretDetection.create({
|
|
137
|
+
data: {
|
|
138
|
+
projectId: 'default',
|
|
139
|
+
filePath: detection.filePath
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
catch (error) {
|
|
144
|
+
// Table may not exist - continue
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
allDetections.push(...detections);
|
|
148
|
+
scannedFiles++;
|
|
149
|
+
}
|
|
150
|
+
catch (error) {
|
|
151
|
+
// Skip files that can't be read
|
|
152
|
+
continue;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
// Generate summary
|
|
156
|
+
const byType = {};
|
|
157
|
+
const byRisk = { high: 0, medium: 0, low: 0 };
|
|
158
|
+
for (const detection of allDetections) {
|
|
159
|
+
byType[detection.secretType] = (byType[detection.secretType] || 0) + 1;
|
|
160
|
+
if (detection.confidence >= 0.8) {
|
|
161
|
+
byRisk.high++;
|
|
162
|
+
}
|
|
163
|
+
else if (detection.confidence >= 0.5) {
|
|
164
|
+
byRisk.medium++;
|
|
165
|
+
}
|
|
166
|
+
else {
|
|
167
|
+
byRisk.low++;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
return {
|
|
171
|
+
projectId,
|
|
172
|
+
totalFiles: files.length,
|
|
173
|
+
scannedFiles,
|
|
174
|
+
detections: allDetections,
|
|
175
|
+
summary: {
|
|
176
|
+
totalSecrets: allDetections.length,
|
|
177
|
+
byType,
|
|
178
|
+
byRisk,
|
|
179
|
+
},
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Calculate entropy for randomness detection
|
|
184
|
+
*/
|
|
185
|
+
calculateEntropy(str) {
|
|
186
|
+
return (0, core_1.calculateEntropy)(str);
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Check if likely test/example value
|
|
190
|
+
*/
|
|
191
|
+
isTestValue(value, context) {
|
|
192
|
+
const lowerValue = value.toLowerCase();
|
|
193
|
+
const lowerContext = context.toLowerCase();
|
|
194
|
+
// Check value itself
|
|
195
|
+
for (const pattern of patterns_1.TEST_PATTERNS) {
|
|
196
|
+
if (pattern.test(lowerValue)) {
|
|
197
|
+
return true;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
// Check context
|
|
201
|
+
if (lowerContext.includes('test') ||
|
|
202
|
+
lowerContext.includes('example') ||
|
|
203
|
+
lowerContext.includes('demo') ||
|
|
204
|
+
lowerContext.includes('fixture') ||
|
|
205
|
+
lowerContext.includes('mock')) {
|
|
206
|
+
return true;
|
|
207
|
+
}
|
|
208
|
+
return false;
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Check for false positives
|
|
212
|
+
*/
|
|
213
|
+
isFalsePositive(value, type, _context) {
|
|
214
|
+
const lowerValue = value.toLowerCase();
|
|
215
|
+
// Check against known false positives
|
|
216
|
+
if (patterns_1.FALSE_POSITIVE_VALUES.has(lowerValue)) {
|
|
217
|
+
return true;
|
|
218
|
+
}
|
|
219
|
+
// Check for placeholder patterns
|
|
220
|
+
if (/^(x+|0+|1+|a+)$/i.test(value)) {
|
|
221
|
+
return true;
|
|
222
|
+
}
|
|
223
|
+
// Check for repeated characters (likely placeholder)
|
|
224
|
+
if (/(.)\1{10,}/.test(value)) {
|
|
225
|
+
return true;
|
|
226
|
+
}
|
|
227
|
+
// JWT-specific false positive checks
|
|
228
|
+
if (type === SecretType.JWT_TOKEN) {
|
|
229
|
+
// Very simple/short payload might be example
|
|
230
|
+
try {
|
|
231
|
+
const parts = value.split('.');
|
|
232
|
+
if (parts.length === 3 && parts[1]) {
|
|
233
|
+
const payload = Buffer.from(parts[1], 'base64').toString();
|
|
234
|
+
if (payload.length < 20) {
|
|
235
|
+
return true;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
catch {
|
|
240
|
+
// Invalid JWT, might be false positive
|
|
241
|
+
return true;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
return false;
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Calculate confidence score
|
|
248
|
+
*/
|
|
249
|
+
calculateConfidence(value, pattern, entropy, isTest) {
|
|
250
|
+
let confidence = 0.7; // Base confidence
|
|
251
|
+
// Increase confidence for high entropy
|
|
252
|
+
if (entropy > 4.5) {
|
|
253
|
+
confidence += 0.2;
|
|
254
|
+
}
|
|
255
|
+
else if (entropy > 4.0) {
|
|
256
|
+
confidence += 0.1;
|
|
257
|
+
}
|
|
258
|
+
// Decrease confidence for test values
|
|
259
|
+
if (isTest) {
|
|
260
|
+
confidence -= 0.3;
|
|
261
|
+
}
|
|
262
|
+
// Pattern-specific adjustments
|
|
263
|
+
if (pattern.type === SecretType.AWS_ACCESS_KEY && value.startsWith('AKIA')) {
|
|
264
|
+
confidence += 0.1;
|
|
265
|
+
}
|
|
266
|
+
if (pattern.type === SecretType.GITHUB_TOKEN && /^gh[pos]_/.test(value)) {
|
|
267
|
+
confidence += 0.1;
|
|
268
|
+
}
|
|
269
|
+
return Math.max(0, Math.min(1, confidence));
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* Mask secret for safe logging
|
|
273
|
+
*/
|
|
274
|
+
maskValue(value) {
|
|
275
|
+
return (0, core_1.maskSensitiveValue)(value);
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* Generate recommendation
|
|
279
|
+
*/
|
|
280
|
+
generateRecommendation(type, isTest) {
|
|
281
|
+
if (isTest) {
|
|
282
|
+
return {
|
|
283
|
+
action: 'remove',
|
|
284
|
+
reason: 'Test credential detected in code',
|
|
285
|
+
remediation: 'Remove test credentials and use mocking instead',
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
// High-risk secrets require rotation
|
|
289
|
+
const highRiskTypes = [
|
|
290
|
+
'AWS_SECRET_KEY',
|
|
291
|
+
'GITHUB_TOKEN',
|
|
292
|
+
'STRIPE_KEY',
|
|
293
|
+
'PRIVATE_KEY',
|
|
294
|
+
];
|
|
295
|
+
if (highRiskTypes.includes(type)) {
|
|
296
|
+
return {
|
|
297
|
+
action: 'revoke_and_rotate',
|
|
298
|
+
reason: 'High-risk credential exposed in code',
|
|
299
|
+
remediation: 'Immediately revoke this credential and rotate to a new one. Store in secure vault or environment variables.',
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
// Medium-risk can use env vars
|
|
303
|
+
return {
|
|
304
|
+
action: 'move_to_env',
|
|
305
|
+
reason: 'Credential should not be hardcoded',
|
|
306
|
+
remediation: 'Move to environment variables or secure vault (e.g., AWS Secrets Manager, HashiCorp Vault)',
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
/**
|
|
310
|
+
* Get project secrets report
|
|
311
|
+
*/
|
|
312
|
+
async getProjectReport(projectId) {
|
|
313
|
+
// @ts-ignore - secretDetection may not exist in schema yet
|
|
314
|
+
const detections = await database_1.prisma.secretDetection.findMany({
|
|
315
|
+
where: { projectId },
|
|
316
|
+
orderBy: { createdAt: 'desc' },
|
|
317
|
+
});
|
|
318
|
+
return detections.map((s) => ({
|
|
319
|
+
id: s.id,
|
|
320
|
+
filePath: s.filePath,
|
|
321
|
+
secretType: s.secretType,
|
|
322
|
+
maskedValue: s.maskedValue,
|
|
323
|
+
location: s.location,
|
|
324
|
+
confidence: s.confidence,
|
|
325
|
+
entropy: s.entropy,
|
|
326
|
+
isTest: s.isTest,
|
|
327
|
+
isRevoked: s.isRevoked,
|
|
328
|
+
recommendation: s.recommendation,
|
|
329
|
+
}));
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
exports.SecretsGuardian = SecretsGuardian;
|
|
333
|
+
// Export singleton
|
|
334
|
+
exports.secretsGuardian = new SecretsGuardian();
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Secrets & Credential Guardian
|
|
3
|
+
*
|
|
4
|
+
* Detects and prevents exposure of secrets and credentials
|
|
5
|
+
*/
|
|
6
|
+
export * from './patterns';
|
|
7
|
+
export { secretsGuardian, SecretsGuardian } from './guardian';
|
|
8
|
+
export { preCommitHook } from './pre-commit';
|
|
9
|
+
export { vaultIntegration } from './vault-integration';
|
|
10
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/secrets/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAC9D,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Secrets & Credential Guardian
|
|
4
|
+
*
|
|
5
|
+
* Detects and prevents exposure of secrets and credentials
|
|
6
|
+
*/
|
|
7
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
8
|
+
if (k2 === undefined) k2 = k;
|
|
9
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
10
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
11
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
12
|
+
}
|
|
13
|
+
Object.defineProperty(o, k2, desc);
|
|
14
|
+
}) : (function(o, m, k, k2) {
|
|
15
|
+
if (k2 === undefined) k2 = k;
|
|
16
|
+
o[k2] = m[k];
|
|
17
|
+
}));
|
|
18
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
19
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
20
|
+
};
|
|
21
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
22
|
+
exports.vaultIntegration = exports.preCommitHook = exports.SecretsGuardian = exports.secretsGuardian = void 0;
|
|
23
|
+
__exportStar(require("./patterns"), exports);
|
|
24
|
+
var guardian_1 = require("./guardian");
|
|
25
|
+
Object.defineProperty(exports, "secretsGuardian", { enumerable: true, get: function () { return guardian_1.secretsGuardian; } });
|
|
26
|
+
Object.defineProperty(exports, "SecretsGuardian", { enumerable: true, get: function () { return guardian_1.SecretsGuardian; } });
|
|
27
|
+
var pre_commit_1 = require("./pre-commit");
|
|
28
|
+
Object.defineProperty(exports, "preCommitHook", { enumerable: true, get: function () { return pre_commit_1.preCommitHook; } });
|
|
29
|
+
var vault_integration_1 = require("./vault-integration");
|
|
30
|
+
Object.defineProperty(exports, "vaultIntegration", { enumerable: true, get: function () { return vault_integration_1.vaultIntegration; } });
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
export declare enum SecretType {
|
|
2
|
+
API_KEY = "api_key",
|
|
3
|
+
PASSWORD = "password",
|
|
4
|
+
TOKEN = "token",
|
|
5
|
+
CERTIFICATE = "certificate",
|
|
6
|
+
PRIVATE_KEY = "private_key",
|
|
7
|
+
DATABASE_URL = "database_url",
|
|
8
|
+
JWT_SECRET = "jwt_secret",
|
|
9
|
+
AWS_ACCESS_KEY = "aws_access_key",
|
|
10
|
+
OTHER = "other",
|
|
11
|
+
AWS_SECRET_KEY = "aws_secret_key",
|
|
12
|
+
GITHUB_TOKEN = "github_token",
|
|
13
|
+
GOOGLE_API_KEY = "google_api_key",
|
|
14
|
+
STRIPE_KEY = "stripe_key",
|
|
15
|
+
JWT_TOKEN = "jwt_token",
|
|
16
|
+
SLACK_TOKEN = "slack_token",
|
|
17
|
+
API_KEY_GENERIC = "api_key_generic"
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Secret detection pattern
|
|
21
|
+
*/
|
|
22
|
+
export interface SecretPattern {
|
|
23
|
+
type: SecretType;
|
|
24
|
+
name: string;
|
|
25
|
+
pattern: RegExp;
|
|
26
|
+
minEntropy?: number;
|
|
27
|
+
description: string;
|
|
28
|
+
examples: string[];
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Comprehensive secret detection patterns
|
|
32
|
+
*/
|
|
33
|
+
export declare const SECRET_PATTERNS: SecretPattern[];
|
|
34
|
+
/**
|
|
35
|
+
* Test/example value patterns (to exclude false positives)
|
|
36
|
+
*/
|
|
37
|
+
export declare const TEST_PATTERNS: RegExp[];
|
|
38
|
+
/**
|
|
39
|
+
* Common false positive values
|
|
40
|
+
*/
|
|
41
|
+
export declare const FALSE_POSITIVE_VALUES: Set<string>;
|
|
42
|
+
//# sourceMappingURL=patterns.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"patterns.d.ts","sourceRoot":"","sources":["../../src/secrets/patterns.ts"],"names":[],"mappings":"AACA,oBAAY,UAAU;IACpB,OAAO,YAAY;IACnB,QAAQ,aAAa;IACrB,KAAK,UAAU;IACf,WAAW,gBAAgB;IAC3B,WAAW,gBAAgB;IAC3B,YAAY,iBAAiB;IAC7B,UAAU,eAAe;IACzB,cAAc,mBAAmB;IACjC,KAAK,UAAU;IACf,cAAc,mBAAmB;IACjC,YAAY,iBAAiB;IAC7B,cAAc,mBAAmB;IACjC,UAAU,eAAe;IACzB,SAAS,cAAc;IACvB,WAAW,gBAAgB;IAC3B,eAAe,oBAAoB;CACpC;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,UAAU,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED;;GAEG;AACH,eAAO,MAAM,eAAe,EAAE,aAAa,EAyG1C,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,aAAa,UAkBzB,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,qBAAqB,aAiBhC,CAAC"}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FALSE_POSITIVE_VALUES = exports.TEST_PATTERNS = exports.SECRET_PATTERNS = exports.SecretType = void 0;
|
|
4
|
+
// Define SecretType locally since it's not exported from database
|
|
5
|
+
var SecretType;
|
|
6
|
+
(function (SecretType) {
|
|
7
|
+
SecretType["API_KEY"] = "api_key";
|
|
8
|
+
SecretType["PASSWORD"] = "password";
|
|
9
|
+
SecretType["TOKEN"] = "token";
|
|
10
|
+
SecretType["CERTIFICATE"] = "certificate";
|
|
11
|
+
SecretType["PRIVATE_KEY"] = "private_key";
|
|
12
|
+
SecretType["DATABASE_URL"] = "database_url";
|
|
13
|
+
SecretType["JWT_SECRET"] = "jwt_secret";
|
|
14
|
+
SecretType["AWS_ACCESS_KEY"] = "aws_access_key";
|
|
15
|
+
SecretType["OTHER"] = "other";
|
|
16
|
+
SecretType["AWS_SECRET_KEY"] = "aws_secret_key";
|
|
17
|
+
SecretType["GITHUB_TOKEN"] = "github_token";
|
|
18
|
+
SecretType["GOOGLE_API_KEY"] = "google_api_key";
|
|
19
|
+
SecretType["STRIPE_KEY"] = "stripe_key";
|
|
20
|
+
SecretType["JWT_TOKEN"] = "jwt_token";
|
|
21
|
+
SecretType["SLACK_TOKEN"] = "slack_token";
|
|
22
|
+
SecretType["API_KEY_GENERIC"] = "api_key_generic";
|
|
23
|
+
})(SecretType || (exports.SecretType = SecretType = {}));
|
|
24
|
+
/**
|
|
25
|
+
* Comprehensive secret detection patterns
|
|
26
|
+
*/
|
|
27
|
+
exports.SECRET_PATTERNS = [
|
|
28
|
+
// AWS Access Keys
|
|
29
|
+
{
|
|
30
|
+
type: 'AWS_ACCESS_KEY',
|
|
31
|
+
name: 'AWS Access Key ID',
|
|
32
|
+
pattern: /(AKIA[0-9A-Z]{16})/,
|
|
33
|
+
minEntropy: 3.5,
|
|
34
|
+
description: 'AWS Access Key ID (starts with AKIA)',
|
|
35
|
+
examples: ['AKIAIOSFODNN7EXAMPLE'],
|
|
36
|
+
},
|
|
37
|
+
// AWS Secret Keys
|
|
38
|
+
{
|
|
39
|
+
type: 'AWS_SECRET_KEY',
|
|
40
|
+
name: 'AWS Secret Access Key',
|
|
41
|
+
pattern: /aws[_\s]*secret[_\s]*access[_\s]*key[_\s]*[=:]\s*['"]?([A-Za-z0-9/+=]{40})['"]?/i,
|
|
42
|
+
minEntropy: 4.5,
|
|
43
|
+
description: 'AWS Secret Access Key (40 characters)',
|
|
44
|
+
examples: ['aws_secret_access_key = wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY'],
|
|
45
|
+
},
|
|
46
|
+
// GitHub Personal Access Tokens
|
|
47
|
+
{
|
|
48
|
+
type: 'GITHUB_TOKEN',
|
|
49
|
+
name: 'GitHub Personal Access Token',
|
|
50
|
+
pattern: /(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})/,
|
|
51
|
+
description: 'GitHub Personal Access Token (ghp_, gho_, ghu_, ghs_, ghr_)',
|
|
52
|
+
examples: ['ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'],
|
|
53
|
+
},
|
|
54
|
+
// Google API Keys
|
|
55
|
+
{
|
|
56
|
+
type: 'GOOGLE_API_KEY',
|
|
57
|
+
name: 'Google API Key',
|
|
58
|
+
pattern: /(AIza[0-9A-Za-z\-_]{35})/,
|
|
59
|
+
description: 'Google API Key (starts with AIza)',
|
|
60
|
+
examples: ['AIzaSyDaGmWKa4JsXZ-HjGw7ISLn_3namBGewQe'],
|
|
61
|
+
},
|
|
62
|
+
// Stripe API Keys
|
|
63
|
+
{
|
|
64
|
+
type: 'STRIPE_KEY',
|
|
65
|
+
name: 'Stripe API Key',
|
|
66
|
+
pattern: /(sk_live_[0-9a-zA-Z]{24,}|pk_live_[0-9a-zA-Z]{24,}|rk_live_[0-9a-zA-Z]{24,})/,
|
|
67
|
+
description: 'Stripe Live API Key',
|
|
68
|
+
examples: ['sk_live_1234567890abcdefghijklmn'],
|
|
69
|
+
},
|
|
70
|
+
// JWT Tokens
|
|
71
|
+
{
|
|
72
|
+
type: 'JWT_TOKEN',
|
|
73
|
+
name: 'JWT Token',
|
|
74
|
+
pattern: /(eyJ[a-zA-Z0-9_-]*\.eyJ[a-zA-Z0-9_-]*\.[a-zA-Z0-9_-]+)/,
|
|
75
|
+
minEntropy: 4.0,
|
|
76
|
+
description: 'JSON Web Token (JWT)',
|
|
77
|
+
examples: ['eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.dozjgNryP4J3jVmNHl0w5N_XgL0n3I9PlFUP0THsR8U'],
|
|
78
|
+
},
|
|
79
|
+
// Private Keys
|
|
80
|
+
{
|
|
81
|
+
type: 'PRIVATE_KEY',
|
|
82
|
+
name: 'Private Key',
|
|
83
|
+
pattern: /(-----BEGIN (RSA |EC |OPENSSH |DSA )?PRIVATE KEY-----[\s\S]*?-----END (RSA |EC |OPENSSH |DSA )?PRIVATE KEY-----)/,
|
|
84
|
+
description: 'Private Key (RSA, EC, OpenSSH, DSA)',
|
|
85
|
+
examples: ['-----BEGIN PRIVATE KEY-----\\nMIIEvQIBADANBgk...\\n-----END PRIVATE KEY-----'],
|
|
86
|
+
},
|
|
87
|
+
// Database URLs with credentials
|
|
88
|
+
{
|
|
89
|
+
type: 'DATABASE_URL',
|
|
90
|
+
name: 'Database URL with Password',
|
|
91
|
+
pattern: /(postgres|mysql|mongodb|redis):\/\/[a-zA-Z0-9_-]+:([a-zA-Z0-9!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]+)@[a-zA-Z0-9.-]+:[0-9]+/,
|
|
92
|
+
minEntropy: 3.0,
|
|
93
|
+
description: 'Database connection string with embedded password',
|
|
94
|
+
examples: ['postgresql://user:password123@localhost:5432/dbname'],
|
|
95
|
+
},
|
|
96
|
+
// Slack Tokens
|
|
97
|
+
{
|
|
98
|
+
type: 'SLACK_TOKEN',
|
|
99
|
+
name: 'Slack Token',
|
|
100
|
+
pattern: /(xox[pboa]-[0-9]{10,13}-[0-9]{10,13}-[0-9]{10,13}-[a-z0-9]{32})/,
|
|
101
|
+
description: 'Slack Bot/User/App Token',
|
|
102
|
+
examples: ['xoxb-0000000000-0000000000-0000000000-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'],
|
|
103
|
+
},
|
|
104
|
+
// Generic API Keys (high entropy)
|
|
105
|
+
{
|
|
106
|
+
type: 'API_KEY_GENERIC',
|
|
107
|
+
name: 'Generic API Key',
|
|
108
|
+
pattern: /(?:api[_\s-]?key|apikey|access[_\s-]?token|auth[_\s-]?token|secret[_\s-]?key)[_\s]*[=:]\s*['"]?([a-zA-Z0-9_\-]{32,})['"]?/i,
|
|
109
|
+
minEntropy: 4.0,
|
|
110
|
+
description: 'Generic API key or access token (high entropy)',
|
|
111
|
+
examples: ['api_key = abcdef1234567890abcdef1234567890'],
|
|
112
|
+
},
|
|
113
|
+
// Generic Passwords
|
|
114
|
+
{
|
|
115
|
+
type: 'PASSWORD_GENERIC',
|
|
116
|
+
name: 'Generic Password',
|
|
117
|
+
pattern: /(?:password|passwd|pwd)[_\s]*[=:]\s*['"]([^'"]{8,})['"]|(?:password|passwd|pwd)[_\s]*[=:]\s*([^\s]{8,})/i,
|
|
118
|
+
minEntropy: 3.0,
|
|
119
|
+
description: 'Generic password in configuration',
|
|
120
|
+
examples: ['password = "MySecretP@ssw0rd"'],
|
|
121
|
+
},
|
|
122
|
+
];
|
|
123
|
+
/**
|
|
124
|
+
* Test/example value patterns (to exclude false positives)
|
|
125
|
+
*/
|
|
126
|
+
exports.TEST_PATTERNS = [
|
|
127
|
+
/test/i,
|
|
128
|
+
/example/i,
|
|
129
|
+
/sample/i,
|
|
130
|
+
/demo/i,
|
|
131
|
+
/fake/i,
|
|
132
|
+
/dummy/i,
|
|
133
|
+
/placeholder/i,
|
|
134
|
+
/\*{3,}/,
|
|
135
|
+
/x{3,}/i,
|
|
136
|
+
/0{5,}/,
|
|
137
|
+
/1{5,}/,
|
|
138
|
+
/abc{3,}/i,
|
|
139
|
+
/qwerty/i,
|
|
140
|
+
/password123/i,
|
|
141
|
+
/changeme/i,
|
|
142
|
+
/your[_-]?key/i,
|
|
143
|
+
/your[_-]?secret/i,
|
|
144
|
+
];
|
|
145
|
+
/**
|
|
146
|
+
* Common false positive values
|
|
147
|
+
*/
|
|
148
|
+
exports.FALSE_POSITIVE_VALUES = new Set([
|
|
149
|
+
'example',
|
|
150
|
+
'test',
|
|
151
|
+
'sample',
|
|
152
|
+
'demo',
|
|
153
|
+
'placeholder',
|
|
154
|
+
'your_key_here',
|
|
155
|
+
'your_secret_here',
|
|
156
|
+
'xxx',
|
|
157
|
+
'yyy',
|
|
158
|
+
'zzz',
|
|
159
|
+
'***',
|
|
160
|
+
'000000000000',
|
|
161
|
+
'111111111111',
|
|
162
|
+
'abcdefghijklmnopqrstuvwxyz',
|
|
163
|
+
'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
|
|
164
|
+
'1234567890',
|
|
165
|
+
]);
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Staged file info
|
|
3
|
+
*/
|
|
4
|
+
export interface StagedFile {
|
|
5
|
+
path: string;
|
|
6
|
+
content: string;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Pre-commit scan result
|
|
10
|
+
*/
|
|
11
|
+
export interface PreCommitScanResult {
|
|
12
|
+
passed: boolean;
|
|
13
|
+
detections: number;
|
|
14
|
+
files: string[];
|
|
15
|
+
message: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Pre-Commit Hook for Secrets Detection
|
|
19
|
+
*/
|
|
20
|
+
export declare class PreCommitHook {
|
|
21
|
+
/**
|
|
22
|
+
* Generate pre-commit hook script
|
|
23
|
+
*/
|
|
24
|
+
generateHookScript(): string;
|
|
25
|
+
/**
|
|
26
|
+
* Scan staged files
|
|
27
|
+
*/
|
|
28
|
+
scanStagedFiles(gitRoot: string): Promise<PreCommitScanResult>;
|
|
29
|
+
/**
|
|
30
|
+
* Get staged files from git
|
|
31
|
+
*/
|
|
32
|
+
private getStagedFiles;
|
|
33
|
+
/**
|
|
34
|
+
* Install pre-commit hook
|
|
35
|
+
*/
|
|
36
|
+
installHook(gitRoot: string): void;
|
|
37
|
+
}
|
|
38
|
+
export declare const preCommitHook: PreCommitHook;
|
|
39
|
+
//# sourceMappingURL=pre-commit.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pre-commit.d.ts","sourceRoot":"","sources":["../../src/secrets/pre-commit.ts"],"names":[],"mappings":"AAKA;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,OAAO,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,qBAAa,aAAa;IACxB;;OAEG;IACH,kBAAkB,IAAI,MAAM;IAoB5B;;OAEG;IACG,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC;IA+CpE;;OAEG;IACH,OAAO,CAAC,cAAc;IAqCtB;;OAEG;IACH,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;CAWnC;AAGD,eAAO,MAAM,aAAa,eAAsB,CAAC"}
|