@continum/cli 0.1.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/README.md +481 -0
- package/SETUP.md +517 -0
- package/dist/api/client.d.ts +17 -0
- package/dist/api/client.d.ts.map +1 -0
- package/dist/api/client.js +70 -0
- package/dist/api/client.js.map +1 -0
- package/dist/commands/init.d.ts +4 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +104 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/login.d.ts +2 -0
- package/dist/commands/login.d.ts.map +1 -0
- package/dist/commands/login.js +217 -0
- package/dist/commands/login.js.map +1 -0
- package/dist/commands/patterns.d.ts +3 -0
- package/dist/commands/patterns.d.ts.map +1 -0
- package/dist/commands/patterns.js +67 -0
- package/dist/commands/patterns.js.map +1 -0
- package/dist/commands/scan.d.ts +11 -0
- package/dist/commands/scan.d.ts.map +1 -0
- package/dist/commands/scan.js +219 -0
- package/dist/commands/scan.js.map +1 -0
- package/dist/commands/status.d.ts +2 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +61 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/uninstall.d.ts +2 -0
- package/dist/commands/uninstall.d.ts.map +1 -0
- package/dist/commands/uninstall.js +87 -0
- package/dist/commands/uninstall.js.map +1 -0
- package/dist/config/default-config.d.ts +3 -0
- package/dist/config/default-config.d.ts.map +1 -0
- package/dist/config/default-config.js +25 -0
- package/dist/config/default-config.js.map +1 -0
- package/dist/config/loader.d.ts +11 -0
- package/dist/config/loader.d.ts.map +1 -0
- package/dist/config/loader.js +96 -0
- package/dist/config/loader.js.map +1 -0
- package/dist/git/git-utils.d.ts +8 -0
- package/dist/git/git-utils.d.ts.map +1 -0
- package/dist/git/git-utils.js +130 -0
- package/dist/git/git-utils.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +63 -0
- package/dist/index.js.map +1 -0
- package/dist/scanner/local-scan.d.ts +15 -0
- package/dist/scanner/local-scan.d.ts.map +1 -0
- package/dist/scanner/local-scan.js +227 -0
- package/dist/scanner/local-scan.js.map +1 -0
- package/dist/scanner/pattern-updater.d.ts +12 -0
- package/dist/scanner/pattern-updater.d.ts.map +1 -0
- package/dist/scanner/pattern-updater.js +110 -0
- package/dist/scanner/pattern-updater.js.map +1 -0
- package/dist/scanner/patterns.d.ts +5 -0
- package/dist/scanner/patterns.d.ts.map +1 -0
- package/dist/scanner/patterns.js +145 -0
- package/dist/scanner/patterns.js.map +1 -0
- package/dist/types.d.ts +59 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/package.json +40 -0
- package/src/api/client.ts +77 -0
- package/src/commands/init.ts +113 -0
- package/src/commands/login.ts +205 -0
- package/src/commands/patterns.ts +68 -0
- package/src/commands/scan.ts +257 -0
- package/src/commands/status.ts +57 -0
- package/src/commands/uninstall.ts +55 -0
- package/src/config/default-config.ts +23 -0
- package/src/config/loader.ts +67 -0
- package/src/git/git-utils.ts +95 -0
- package/src/index.ts +72 -0
- package/src/scanner/local-scan.ts +222 -0
- package/src/scanner/pattern-updater.ts +94 -0
- package/src/scanner/patterns.ts +156 -0
- package/src/types.ts +64 -0
- package/tsconfig.json +19 -0
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.LocalScanner = void 0;
|
|
37
|
+
const fs = __importStar(require("fs"));
|
|
38
|
+
const patterns_1 = require("./patterns");
|
|
39
|
+
class LocalScanner {
|
|
40
|
+
constructor(config, customPatterns = []) {
|
|
41
|
+
this.patterns = [];
|
|
42
|
+
this.config = config;
|
|
43
|
+
this.patterns = [...patterns_1.BUILTIN_PATTERNS, ...customPatterns];
|
|
44
|
+
// Add custom regex patterns from config
|
|
45
|
+
if (config.patterns?.custom) {
|
|
46
|
+
config.patterns.custom.forEach((pattern, index) => {
|
|
47
|
+
this.patterns.push({
|
|
48
|
+
pattern,
|
|
49
|
+
patternType: 'CUSTOM',
|
|
50
|
+
description: `Custom Pattern ${index + 1}`,
|
|
51
|
+
severity: 'HIGH'
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
async scanFiles(files) {
|
|
57
|
+
const violations = [];
|
|
58
|
+
const unknownPatterns = [];
|
|
59
|
+
let filesScanned = 0;
|
|
60
|
+
for (const file of files) {
|
|
61
|
+
// Skip ignored files
|
|
62
|
+
if (this.shouldIgnore(file)) {
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
try {
|
|
66
|
+
const content = fs.readFileSync(file, 'utf-8');
|
|
67
|
+
const lines = content.split('\n');
|
|
68
|
+
filesScanned++;
|
|
69
|
+
// Scan with known patterns
|
|
70
|
+
const fileViolations = this.scanContent(content, file, lines);
|
|
71
|
+
violations.push(...fileViolations);
|
|
72
|
+
// Detect high-entropy strings that might be credentials
|
|
73
|
+
const possibleCredentials = this.detectHighEntropyStrings(content, file, lines);
|
|
74
|
+
unknownPatterns.push(...possibleCredentials);
|
|
75
|
+
}
|
|
76
|
+
catch (error) {
|
|
77
|
+
// Skip files that can't be read (binary, etc.)
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return {
|
|
82
|
+
violations,
|
|
83
|
+
unknownPatterns,
|
|
84
|
+
filesScanned,
|
|
85
|
+
clean: violations.length === 0 && unknownPatterns.length === 0
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
scanContent(content, file, lines) {
|
|
89
|
+
const violations = [];
|
|
90
|
+
for (const pattern of this.patterns) {
|
|
91
|
+
const regex = new RegExp(pattern.pattern, 'gi');
|
|
92
|
+
let match;
|
|
93
|
+
while ((match = regex.exec(content)) !== null) {
|
|
94
|
+
const lineNumber = this.getLineNumber(content, match.index);
|
|
95
|
+
violations.push({
|
|
96
|
+
file,
|
|
97
|
+
line: lineNumber,
|
|
98
|
+
type: pattern.patternType,
|
|
99
|
+
pattern: pattern.pattern,
|
|
100
|
+
value: match[0],
|
|
101
|
+
severity: pattern.severity,
|
|
102
|
+
message: pattern.description
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return violations;
|
|
107
|
+
}
|
|
108
|
+
detectHighEntropyStrings(content, file, lines) {
|
|
109
|
+
const unknownPatterns = [];
|
|
110
|
+
// Look for string assignments with high entropy
|
|
111
|
+
const stringPatterns = [
|
|
112
|
+
/(\w+)\s*[:=]\s*["']([a-zA-Z0-9_\-+=\/]{16,})["']/g,
|
|
113
|
+
/const\s+(\w+)\s*=\s*["']([a-zA-Z0-9_\-+=\/]{16,})["']/g,
|
|
114
|
+
/let\s+(\w+)\s*=\s*["']([a-zA-Z0-9_\-+=\/]{16,})["']/g,
|
|
115
|
+
/var\s+(\w+)\s*=\s*["']([a-zA-Z0-9_\-+=\/]{16,})["']/g
|
|
116
|
+
];
|
|
117
|
+
for (const pattern of stringPatterns) {
|
|
118
|
+
let match;
|
|
119
|
+
while ((match = pattern.exec(content)) !== null) {
|
|
120
|
+
const variableName = match[1];
|
|
121
|
+
const value = match[2];
|
|
122
|
+
const lineNumber = this.getLineNumber(content, match.index);
|
|
123
|
+
// Get surrounding context
|
|
124
|
+
const contextStart = Math.max(0, lineNumber - 3);
|
|
125
|
+
const contextEnd = Math.min(lines.length, lineNumber + 2);
|
|
126
|
+
const surroundingCode = lines.slice(contextStart, contextEnd).join('\n');
|
|
127
|
+
// Check if this looks like a credential
|
|
128
|
+
if ((0, patterns_1.isHighEntropyCredential)(value, variableName + ' ' + surroundingCode)) {
|
|
129
|
+
// Check if it matches any known pattern
|
|
130
|
+
const matchesKnown = this.patterns.some(p => new RegExp(p.pattern, 'i').test(value));
|
|
131
|
+
if (!matchesKnown) {
|
|
132
|
+
const suggestedPattern = this.extractPattern(value);
|
|
133
|
+
const confidence = this.calculateConfidence(value, variableName);
|
|
134
|
+
unknownPatterns.push({
|
|
135
|
+
value,
|
|
136
|
+
suggestedPattern,
|
|
137
|
+
confidence,
|
|
138
|
+
context: {
|
|
139
|
+
file,
|
|
140
|
+
line: lineNumber,
|
|
141
|
+
variableName,
|
|
142
|
+
surroundingCode
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
return unknownPatterns;
|
|
150
|
+
}
|
|
151
|
+
extractPattern(value) {
|
|
152
|
+
// Try to extract a pattern from the value
|
|
153
|
+
const hasPrefix = /^[a-z]{2,}_/.test(value);
|
|
154
|
+
if (hasPrefix) {
|
|
155
|
+
const prefix = value.match(/^[a-z_]+/)?.[0] || '';
|
|
156
|
+
const rest = value.slice(prefix.length);
|
|
157
|
+
// Determine character set
|
|
158
|
+
const hasUppercase = /[A-Z]/.test(rest);
|
|
159
|
+
const hasLowercase = /[a-z]/.test(rest);
|
|
160
|
+
const hasDigits = /[0-9]/.test(rest);
|
|
161
|
+
const hasSpecial = /[_\-]/.test(rest);
|
|
162
|
+
let charSet = '';
|
|
163
|
+
if (hasUppercase)
|
|
164
|
+
charSet += 'A-Z';
|
|
165
|
+
if (hasLowercase)
|
|
166
|
+
charSet += 'a-z';
|
|
167
|
+
if (hasDigits)
|
|
168
|
+
charSet += '0-9';
|
|
169
|
+
if (hasSpecial)
|
|
170
|
+
charSet += '_\\-';
|
|
171
|
+
return `${prefix}[${charSet}]{${rest.length}}`;
|
|
172
|
+
}
|
|
173
|
+
// No clear prefix, just match character set and length
|
|
174
|
+
const hasUppercase = /[A-Z]/.test(value);
|
|
175
|
+
const hasLowercase = /[a-z]/.test(value);
|
|
176
|
+
const hasDigits = /[0-9]/.test(value);
|
|
177
|
+
const hasSpecial = /[_\-+=\/]/.test(value);
|
|
178
|
+
let charSet = '';
|
|
179
|
+
if (hasUppercase)
|
|
180
|
+
charSet += 'A-Z';
|
|
181
|
+
if (hasLowercase)
|
|
182
|
+
charSet += 'a-z';
|
|
183
|
+
if (hasDigits)
|
|
184
|
+
charSet += '0-9';
|
|
185
|
+
if (hasSpecial)
|
|
186
|
+
charSet += '_\\-+=\\/';
|
|
187
|
+
return `[${charSet}]{${value.length}}`;
|
|
188
|
+
}
|
|
189
|
+
calculateConfidence(value, variableName) {
|
|
190
|
+
const entropy = (0, patterns_1.calculateEntropy)(value);
|
|
191
|
+
const suspiciousNames = ['key', 'token', 'secret', 'password', 'credential', 'auth', 'api'];
|
|
192
|
+
const hasSuspiciousName = suspiciousNames.some(name => variableName.toLowerCase().includes(name));
|
|
193
|
+
if (entropy > 5.0 && hasSuspiciousName)
|
|
194
|
+
return 'HIGH';
|
|
195
|
+
if (entropy > 4.5 && hasSuspiciousName)
|
|
196
|
+
return 'MEDIUM';
|
|
197
|
+
if (entropy > 5.5)
|
|
198
|
+
return 'MEDIUM';
|
|
199
|
+
return 'LOW';
|
|
200
|
+
}
|
|
201
|
+
getLineNumber(content, index) {
|
|
202
|
+
return content.substring(0, index).split('\n').length;
|
|
203
|
+
}
|
|
204
|
+
shouldIgnore(file) {
|
|
205
|
+
const normalizedFile = file.replace(/\\/g, '/');
|
|
206
|
+
return this.config.ignore.some(pattern => {
|
|
207
|
+
// Convert glob pattern to regex
|
|
208
|
+
const regexPattern = pattern
|
|
209
|
+
.replace(/\*\*/g, '.*')
|
|
210
|
+
.replace(/\*/g, '[^/]*')
|
|
211
|
+
.replace(/\?/g, '.');
|
|
212
|
+
const regex = new RegExp(regexPattern);
|
|
213
|
+
return regex.test(normalizedFile);
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
redactValue(value) {
|
|
217
|
+
if (value.length <= 8) {
|
|
218
|
+
return '•'.repeat(value.length);
|
|
219
|
+
}
|
|
220
|
+
const visibleChars = 4;
|
|
221
|
+
const start = value.substring(0, visibleChars);
|
|
222
|
+
const redacted = '•'.repeat(Math.min(10, value.length - visibleChars));
|
|
223
|
+
return start + redacted;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
exports.LocalScanner = LocalScanner;
|
|
227
|
+
//# sourceMappingURL=local-scan.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"local-scan.js","sourceRoot":"","sources":["../../src/scanner/local-scan.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,uCAAyB;AAGzB,yCAAyF;AAEzF,MAAa,YAAY;IAIvB,YAAY,MAAsB,EAAE,iBAA4B,EAAE;QAH1D,aAAQ,GAAc,EAAE,CAAC;QAI/B,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,QAAQ,GAAG,CAAC,GAAG,2BAAgB,EAAE,GAAG,cAAc,CAAC,CAAC;QAEzD,wCAAwC;QACxC,IAAI,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,CAAC;YAC5B,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,KAAK,EAAE,EAAE;gBAChD,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;oBACjB,OAAO;oBACP,WAAW,EAAE,QAAQ;oBACrB,WAAW,EAAE,kBAAkB,KAAK,GAAG,CAAC,EAAE;oBAC1C,QAAQ,EAAE,MAAM;iBACjB,CAAC,CAAC;YACL,CAAC,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,KAAK,CAAC,SAAS,CAAC,KAAe;QAC7B,MAAM,UAAU,GAAgB,EAAE,CAAC;QACnC,MAAM,eAAe,GAAqB,EAAE,CAAC;QAC7C,IAAI,YAAY,GAAG,CAAC,CAAC;QAErB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,qBAAqB;YACrB,IAAI,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC5B,SAAS;YACX,CAAC;YAED,IAAI,CAAC;gBACH,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;gBAC/C,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;gBAElC,YAAY,EAAE,CAAC;gBAEf,2BAA2B;gBAC3B,MAAM,cAAc,GAAG,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;gBAC9D,UAAU,CAAC,IAAI,CAAC,GAAG,cAAc,CAAC,CAAC;gBAEnC,wDAAwD;gBACxD,MAAM,mBAAmB,GAAG,IAAI,CAAC,wBAAwB,CAAC,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;gBAChF,eAAe,CAAC,IAAI,CAAC,GAAG,mBAAmB,CAAC,CAAC;YAC/C,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,+CAA+C;gBAC/C,SAAS;YACX,CAAC;QACH,CAAC;QAED,OAAO;YACL,UAAU;YACV,eAAe;YACf,YAAY;YACZ,KAAK,EAAE,UAAU,CAAC,MAAM,KAAK,CAAC,IAAI,eAAe,CAAC,MAAM,KAAK,CAAC;SAC/D,CAAC;IACJ,CAAC;IAEO,WAAW,CAAC,OAAe,EAAE,IAAY,EAAE,KAAe;QAChE,MAAM,UAAU,GAAgB,EAAE,CAAC;QAEnC,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YACpC,MAAM,KAAK,GAAG,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;YAChD,IAAI,KAAK,CAAC;YAEV,OAAO,CAAC,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;gBAC9C,MAAM,UAAU,GAAG,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;gBAE5D,UAAU,CAAC,IAAI,CAAC;oBACd,IAAI;oBACJ,IAAI,EAAE,UAAU;oBAChB,IAAI,EAAE,OAAO,CAAC,WAAW;oBACzB,OAAO,EAAE,OAAO,CAAC,OAAO;oBACxB,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC;oBACf,QAAQ,EAAE,OAAO,CAAC,QAAQ;oBAC1B,OAAO,EAAE,OAAO,CAAC,WAAW;iBAC7B,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,OAAO,UAAU,CAAC;IACpB,CAAC;IAEO,wBAAwB,CAAC,OAAe,EAAE,IAAY,EAAE,KAAe;QAC7E,MAAM,eAAe,GAAqB,EAAE,CAAC;QAE7C,gDAAgD;QAChD,MAAM,cAAc,GAAG;YACrB,mDAAmD;YACnD,wDAAwD;YACxD,sDAAsD;YACtD,sDAAsD;SACvD,CAAC;QAEF,KAAK,MAAM,OAAO,IAAI,cAAc,EAAE,CAAC;YACrC,IAAI,KAAK,CAAC;YACV,OAAO,CAAC,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;gBAChD,MAAM,YAAY,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;gBAC9B,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;gBACvB,MAAM,UAAU,GAAG,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;gBAE5D,0BAA0B;gBAC1B,MAAM,YAAY,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,UAAU,GAAG,CAAC,CAAC,CAAC;gBACjD,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,EAAE,UAAU,GAAG,CAAC,CAAC,CAAC;gBAC1D,MAAM,eAAe,GAAG,KAAK,CAAC,KAAK,CAAC,YAAY,EAAE,UAAU,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBAEzE,wCAAwC;gBACxC,IAAI,IAAA,kCAAuB,EAAC,KAAK,EAAE,YAAY,GAAG,GAAG,GAAG,eAAe,CAAC,EAAE,CAAC;oBACzE,wCAAwC;oBACxC,MAAM,YAAY,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAC1C,IAAI,MAAM,CAAC,CAAC,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CACvC,CAAC;oBAEF,IAAI,CAAC,YAAY,EAAE,CAAC;wBAClB,MAAM,gBAAgB,GAAG,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;wBACpD,MAAM,UAAU,GAAG,IAAI,CAAC,mBAAmB,CAAC,KAAK,EAAE,YAAY,CAAC,CAAC;wBAEjE,eAAe,CAAC,IAAI,CAAC;4BACnB,KAAK;4BACL,gBAAgB;4BAChB,UAAU;4BACV,OAAO,EAAE;gCACP,IAAI;gCACJ,IAAI,EAAE,UAAU;gCAChB,YAAY;gCACZ,eAAe;6BAChB;yBACF,CAAC,CAAC;oBACL,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;QAED,OAAO,eAAe,CAAC;IACzB,CAAC;IAEO,cAAc,CAAC,KAAa;QAClC,0CAA0C;QAC1C,MAAM,SAAS,GAAG,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAE5C,IAAI,SAAS,EAAE,CAAC;YACd,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;YAClD,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YAExC,0BAA0B;YAC1B,MAAM,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACxC,MAAM,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACxC,MAAM,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACrC,MAAM,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAEtC,IAAI,OAAO,GAAG,EAAE,CAAC;YACjB,IAAI,YAAY;gBAAE,OAAO,IAAI,KAAK,CAAC;YACnC,IAAI,YAAY;gBAAE,OAAO,IAAI,KAAK,CAAC;YACnC,IAAI,SAAS;gBAAE,OAAO,IAAI,KAAK,CAAC;YAChC,IAAI,UAAU;gBAAE,OAAO,IAAI,MAAM,CAAC;YAElC,OAAO,GAAG,MAAM,IAAI,OAAO,KAAK,IAAI,CAAC,MAAM,GAAG,CAAC;QACjD,CAAC;QAED,uDAAuD;QACvD,MAAM,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACzC,MAAM,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACzC,MAAM,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACtC,MAAM,UAAU,GAAG,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAE3C,IAAI,OAAO,GAAG,EAAE,CAAC;QACjB,IAAI,YAAY;YAAE,OAAO,IAAI,KAAK,CAAC;QACnC,IAAI,YAAY;YAAE,OAAO,IAAI,KAAK,CAAC;QACnC,IAAI,SAAS;YAAE,OAAO,IAAI,KAAK,CAAC;QAChC,IAAI,UAAU;YAAE,OAAO,IAAI,WAAW,CAAC;QAEvC,OAAO,IAAI,OAAO,KAAK,KAAK,CAAC,MAAM,GAAG,CAAC;IACzC,CAAC;IAEO,mBAAmB,CAAC,KAAa,EAAE,YAAoB;QAC7D,MAAM,OAAO,GAAG,IAAA,2BAAgB,EAAC,KAAK,CAAC,CAAC;QACxC,MAAM,eAAe,GAAG,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC;QAC5F,MAAM,iBAAiB,GAAG,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CACpD,YAAY,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAC1C,CAAC;QAEF,IAAI,OAAO,GAAG,GAAG,IAAI,iBAAiB;YAAE,OAAO,MAAM,CAAC;QACtD,IAAI,OAAO,GAAG,GAAG,IAAI,iBAAiB;YAAE,OAAO,QAAQ,CAAC;QACxD,IAAI,OAAO,GAAG,GAAG;YAAE,OAAO,QAAQ,CAAC;QACnC,OAAO,KAAK,CAAC;IACf,CAAC;IAEO,aAAa,CAAC,OAAe,EAAE,KAAa;QAClD,OAAO,OAAO,CAAC,SAAS,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;IACxD,CAAC;IAEO,YAAY,CAAC,IAAY;QAC/B,MAAM,cAAc,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;QAEhD,OAAO,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE;YACvC,gCAAgC;YAChC,MAAM,YAAY,GAAG,OAAO;iBACzB,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC;iBACtB,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC;iBACvB,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;YAEvB,MAAM,KAAK,GAAG,IAAI,MAAM,CAAC,YAAY,CAAC,CAAC;YACvC,OAAO,KAAK,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QACpC,CAAC,CAAC,CAAC;IACL,CAAC;IAED,WAAW,CAAC,KAAa;QACvB,IAAI,KAAK,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC;YACtB,OAAO,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QAClC,CAAC;QACD,MAAM,YAAY,GAAG,CAAC,CAAC;QACvB,MAAM,KAAK,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC,EAAE,YAAY,CAAC,CAAC;QAC/C,MAAM,QAAQ,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,KAAK,CAAC,MAAM,GAAG,YAAY,CAAC,CAAC,CAAC;QACvE,OAAO,KAAK,GAAG,QAAQ,CAAC;IAC1B,CAAC;CACF;AAxND,oCAwNC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { ContinumApiClient } from '../api/client';
|
|
2
|
+
import { Pattern } from '../types';
|
|
3
|
+
export declare class PatternUpdater {
|
|
4
|
+
private client;
|
|
5
|
+
private cacheFile;
|
|
6
|
+
constructor(client: ContinumApiClient);
|
|
7
|
+
updatePatterns(force?: boolean): Promise<void>;
|
|
8
|
+
loadPatterns(): Pattern[];
|
|
9
|
+
private loadCache;
|
|
10
|
+
private saveCache;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=pattern-updater.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pattern-updater.d.ts","sourceRoot":"","sources":["../../src/scanner/pattern-updater.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAWnC,qBAAa,cAAc;IACzB,OAAO,CAAC,MAAM,CAAoB;IAClC,OAAO,CAAC,SAAS,CAAS;gBAEd,MAAM,EAAE,iBAAiB;IAK/B,cAAc,CAAC,KAAK,GAAE,OAAe,GAAG,OAAO,CAAC,IAAI,CAAC;IA+B3D,YAAY,IAAI,OAAO,EAAE;IASzB,OAAO,CAAC,SAAS;IAuBjB,OAAO,CAAC,SAAS;CAQlB"}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.PatternUpdater = void 0;
|
|
37
|
+
const fs = __importStar(require("fs"));
|
|
38
|
+
const loader_1 = require("../config/loader");
|
|
39
|
+
const patterns_1 = require("./patterns");
|
|
40
|
+
class PatternUpdater {
|
|
41
|
+
constructor(client) {
|
|
42
|
+
this.client = client;
|
|
43
|
+
this.cacheFile = (0, loader_1.getCacheFile)();
|
|
44
|
+
}
|
|
45
|
+
async updatePatterns(force = false) {
|
|
46
|
+
const cache = this.loadCache();
|
|
47
|
+
// Update every 24 hours, or on force
|
|
48
|
+
if (!force && Date.now() - cache.lastUpdate < 86400000) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
try {
|
|
52
|
+
// Fetch patterns from API
|
|
53
|
+
const patterns = await this.client.getPatternLibrary();
|
|
54
|
+
// Separate customer and global patterns
|
|
55
|
+
const customerPatterns = patterns.filter(p => !('isGlobal' in p) || !p.isGlobal);
|
|
56
|
+
const globalPatterns = patterns.filter(p => p.isGlobal);
|
|
57
|
+
// Update cache
|
|
58
|
+
const newCache = {
|
|
59
|
+
builtin: patterns_1.BUILTIN_PATTERNS,
|
|
60
|
+
customer: customerPatterns,
|
|
61
|
+
global: globalPatterns,
|
|
62
|
+
lastUpdate: Date.now()
|
|
63
|
+
};
|
|
64
|
+
this.saveCache(newCache);
|
|
65
|
+
}
|
|
66
|
+
catch (error) {
|
|
67
|
+
// If update fails, continue with cached patterns
|
|
68
|
+
console.warn('Failed to update patterns, using cache');
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
loadPatterns() {
|
|
72
|
+
const cache = this.loadCache();
|
|
73
|
+
return [
|
|
74
|
+
...cache.builtin,
|
|
75
|
+
...cache.customer,
|
|
76
|
+
...cache.global
|
|
77
|
+
];
|
|
78
|
+
}
|
|
79
|
+
loadCache() {
|
|
80
|
+
if (!fs.existsSync(this.cacheFile)) {
|
|
81
|
+
return {
|
|
82
|
+
builtin: patterns_1.BUILTIN_PATTERNS,
|
|
83
|
+
customer: [],
|
|
84
|
+
global: [],
|
|
85
|
+
lastUpdate: 0
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
try {
|
|
89
|
+
const content = fs.readFileSync(this.cacheFile, 'utf-8');
|
|
90
|
+
return JSON.parse(content);
|
|
91
|
+
}
|
|
92
|
+
catch (error) {
|
|
93
|
+
return {
|
|
94
|
+
builtin: patterns_1.BUILTIN_PATTERNS,
|
|
95
|
+
customer: [],
|
|
96
|
+
global: [],
|
|
97
|
+
lastUpdate: 0
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
saveCache(cache) {
|
|
102
|
+
const cacheDir = (0, loader_1.getCacheDir)();
|
|
103
|
+
if (!fs.existsSync(cacheDir)) {
|
|
104
|
+
fs.mkdirSync(cacheDir, { recursive: true });
|
|
105
|
+
}
|
|
106
|
+
fs.writeFileSync(this.cacheFile, JSON.stringify(cache, null, 2));
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
exports.PatternUpdater = PatternUpdater;
|
|
110
|
+
//# sourceMappingURL=pattern-updater.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pattern-updater.js","sourceRoot":"","sources":["../../src/scanner/pattern-updater.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { Pattern } from '../types';
|
|
2
|
+
export declare const BUILTIN_PATTERNS: Pattern[];
|
|
3
|
+
export declare function calculateEntropy(str: string): number;
|
|
4
|
+
export declare function isHighEntropyCredential(value: string, context: string): boolean;
|
|
5
|
+
//# sourceMappingURL=patterns.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"patterns.d.ts","sourceRoot":"","sources":["../../src/scanner/patterns.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAGnC,eAAO,MAAM,gBAAgB,EAAE,OAAO,EAoHrC,CAAC;AAGF,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAepD;AAGD,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAe/E"}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.BUILTIN_PATTERNS = void 0;
|
|
4
|
+
exports.calculateEntropy = calculateEntropy;
|
|
5
|
+
exports.isHighEntropyCredential = isHighEntropyCredential;
|
|
6
|
+
// Built-in credential patterns
|
|
7
|
+
exports.BUILTIN_PATTERNS = [
|
|
8
|
+
// AWS
|
|
9
|
+
{
|
|
10
|
+
pattern: 'AKIA[0-9A-Z]{16}',
|
|
11
|
+
patternType: 'AWS_ACCESS_KEY',
|
|
12
|
+
description: 'AWS Access Key ID',
|
|
13
|
+
severity: 'CRITICAL'
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
pattern: 'aws_secret_access_key\\s*=\\s*["\']?([A-Za-z0-9/+=]{40})["\']?',
|
|
17
|
+
patternType: 'AWS_SECRET_KEY',
|
|
18
|
+
description: 'AWS Secret Access Key',
|
|
19
|
+
severity: 'CRITICAL'
|
|
20
|
+
},
|
|
21
|
+
// Stripe
|
|
22
|
+
{
|
|
23
|
+
pattern: 'sk_live_[0-9a-zA-Z]{24,}',
|
|
24
|
+
patternType: 'STRIPE_LIVE_KEY',
|
|
25
|
+
description: 'Stripe Live Secret Key',
|
|
26
|
+
severity: 'CRITICAL'
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
pattern: 'rk_live_[0-9a-zA-Z]{24,}',
|
|
30
|
+
patternType: 'STRIPE_RESTRICTED_KEY',
|
|
31
|
+
description: 'Stripe Restricted Key',
|
|
32
|
+
severity: 'HIGH'
|
|
33
|
+
},
|
|
34
|
+
// GitHub
|
|
35
|
+
{
|
|
36
|
+
pattern: 'ghp_[0-9a-zA-Z]{36}',
|
|
37
|
+
patternType: 'GITHUB_PAT',
|
|
38
|
+
description: 'GitHub Personal Access Token',
|
|
39
|
+
severity: 'CRITICAL'
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
pattern: 'gho_[0-9a-zA-Z]{36}',
|
|
43
|
+
patternType: 'GITHUB_OAUTH',
|
|
44
|
+
description: 'GitHub OAuth Token',
|
|
45
|
+
severity: 'CRITICAL'
|
|
46
|
+
},
|
|
47
|
+
// Anthropic
|
|
48
|
+
{
|
|
49
|
+
pattern: 'sk-ant-api03-[0-9a-zA-Z_-]{95}',
|
|
50
|
+
patternType: 'ANTHROPIC_API_KEY',
|
|
51
|
+
description: 'Anthropic API Key',
|
|
52
|
+
severity: 'CRITICAL'
|
|
53
|
+
},
|
|
54
|
+
// OpenAI
|
|
55
|
+
{
|
|
56
|
+
pattern: 'sk-[a-zA-Z0-9]{48}',
|
|
57
|
+
patternType: 'OPENAI_API_KEY',
|
|
58
|
+
description: 'OpenAI API Key',
|
|
59
|
+
severity: 'CRITICAL'
|
|
60
|
+
},
|
|
61
|
+
// Database Connection Strings
|
|
62
|
+
{
|
|
63
|
+
pattern: 'postgresql://[^\\s:]+:[^\\s@]+@[^\\s/]+',
|
|
64
|
+
patternType: 'POSTGRES_CONNECTION',
|
|
65
|
+
description: 'PostgreSQL Connection String with Password',
|
|
66
|
+
severity: 'CRITICAL'
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
pattern: 'mysql://[^\\s:]+:[^\\s@]+@[^\\s/]+',
|
|
70
|
+
patternType: 'MYSQL_CONNECTION',
|
|
71
|
+
description: 'MySQL Connection String with Password',
|
|
72
|
+
severity: 'CRITICAL'
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
pattern: 'mongodb(\\+srv)?://[^\\s:]+:[^\\s@]+@[^\\s/]+',
|
|
76
|
+
patternType: 'MONGODB_CONNECTION',
|
|
77
|
+
description: 'MongoDB Connection String with Password',
|
|
78
|
+
severity: 'CRITICAL'
|
|
79
|
+
},
|
|
80
|
+
// Private Keys
|
|
81
|
+
{
|
|
82
|
+
pattern: '-----BEGIN (RSA |EC |OPENSSH )?PRIVATE KEY-----',
|
|
83
|
+
patternType: 'PRIVATE_KEY',
|
|
84
|
+
description: 'Private Key (PEM format)',
|
|
85
|
+
severity: 'CRITICAL'
|
|
86
|
+
},
|
|
87
|
+
// Generic API Keys (high entropy)
|
|
88
|
+
{
|
|
89
|
+
pattern: '(api[_-]?key|apikey|api[_-]?secret)\\s*[:=]\\s*["\']([a-zA-Z0-9_\\-]{32,})["\']',
|
|
90
|
+
patternType: 'GENERIC_API_KEY',
|
|
91
|
+
description: 'Generic API Key',
|
|
92
|
+
severity: 'HIGH'
|
|
93
|
+
},
|
|
94
|
+
// JWT Tokens
|
|
95
|
+
{
|
|
96
|
+
pattern: 'eyJ[a-zA-Z0-9_-]*\\.eyJ[a-zA-Z0-9_-]*\\.[a-zA-Z0-9_-]*',
|
|
97
|
+
patternType: 'JWT_TOKEN',
|
|
98
|
+
description: 'JWT Token',
|
|
99
|
+
severity: 'HIGH'
|
|
100
|
+
},
|
|
101
|
+
// UK PII
|
|
102
|
+
{
|
|
103
|
+
pattern: '\\b[A-Z]{2}[0-9]{6}[A-Z]?\\b',
|
|
104
|
+
patternType: 'NHS_NUMBER',
|
|
105
|
+
description: 'NHS Number',
|
|
106
|
+
severity: 'HIGH'
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
pattern: '\\b[A-Z]{2}\\s?[0-9]{2}\\s?[0-9]{2}\\s?[0-9]{2}\\s?[A-Z]\\b',
|
|
110
|
+
patternType: 'NI_NUMBER',
|
|
111
|
+
description: 'National Insurance Number',
|
|
112
|
+
severity: 'HIGH'
|
|
113
|
+
}
|
|
114
|
+
];
|
|
115
|
+
// Calculate entropy of a string (measure of randomness)
|
|
116
|
+
function calculateEntropy(str) {
|
|
117
|
+
const len = str.length;
|
|
118
|
+
const frequencies = {};
|
|
119
|
+
for (const char of str) {
|
|
120
|
+
frequencies[char] = (frequencies[char] || 0) + 1;
|
|
121
|
+
}
|
|
122
|
+
let entropy = 0;
|
|
123
|
+
for (const char in frequencies) {
|
|
124
|
+
const p = frequencies[char] / len;
|
|
125
|
+
entropy -= p * Math.log2(p);
|
|
126
|
+
}
|
|
127
|
+
return entropy;
|
|
128
|
+
}
|
|
129
|
+
// Check if a string looks like a credential based on entropy and context
|
|
130
|
+
function isHighEntropyCredential(value, context) {
|
|
131
|
+
// Must be long enough
|
|
132
|
+
if (value.length < 16)
|
|
133
|
+
return false;
|
|
134
|
+
// Must have high entropy (randomness)
|
|
135
|
+
const entropy = calculateEntropy(value);
|
|
136
|
+
if (entropy < 4.5)
|
|
137
|
+
return false;
|
|
138
|
+
// Must be in a suspicious context
|
|
139
|
+
const suspiciousPatterns = [
|
|
140
|
+
/\b(key|token|secret|password|credential|auth|api)\b/i,
|
|
141
|
+
/\b(access|private|bearer|jwt)\b/i
|
|
142
|
+
];
|
|
143
|
+
return suspiciousPatterns.some(pattern => pattern.test(context));
|
|
144
|
+
}
|
|
145
|
+
//# sourceMappingURL=patterns.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"patterns.js","sourceRoot":"","sources":["../../src/scanner/patterns.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
export interface ContinumConfig {
|
|
2
|
+
scanOnCommit: boolean;
|
|
3
|
+
sandbox: string;
|
|
4
|
+
apiUrl?: string;
|
|
5
|
+
apiKey?: string;
|
|
6
|
+
block: RiskLevel[];
|
|
7
|
+
warn: RiskLevel[];
|
|
8
|
+
ignore: string[];
|
|
9
|
+
patterns?: {
|
|
10
|
+
custom?: string[];
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
export type RiskLevel = 'CRITICAL' | 'HIGH' | 'MEDIUM' | 'LOW';
|
|
14
|
+
export interface Violation {
|
|
15
|
+
file: string;
|
|
16
|
+
line: number;
|
|
17
|
+
type: string;
|
|
18
|
+
pattern: string;
|
|
19
|
+
value: string;
|
|
20
|
+
severity: RiskLevel;
|
|
21
|
+
message?: string;
|
|
22
|
+
}
|
|
23
|
+
export interface UnknownPattern {
|
|
24
|
+
value: string;
|
|
25
|
+
suggestedPattern: string;
|
|
26
|
+
confidence: 'HIGH' | 'MEDIUM' | 'LOW';
|
|
27
|
+
context: {
|
|
28
|
+
file: string;
|
|
29
|
+
line: number;
|
|
30
|
+
variableName?: string;
|
|
31
|
+
surroundingCode?: string;
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
export interface ScanResult {
|
|
35
|
+
violations: Violation[];
|
|
36
|
+
unknownPatterns: UnknownPattern[];
|
|
37
|
+
filesScanned: number;
|
|
38
|
+
clean: boolean;
|
|
39
|
+
}
|
|
40
|
+
export interface Pattern {
|
|
41
|
+
pattern: string;
|
|
42
|
+
patternType: string;
|
|
43
|
+
description: string;
|
|
44
|
+
severity: RiskLevel;
|
|
45
|
+
}
|
|
46
|
+
export interface ApprovePatternDto {
|
|
47
|
+
pattern: string;
|
|
48
|
+
patternType: string;
|
|
49
|
+
description: string;
|
|
50
|
+
severity: RiskLevel;
|
|
51
|
+
exampleValue: string;
|
|
52
|
+
confidence: string;
|
|
53
|
+
context: {
|
|
54
|
+
file: string;
|
|
55
|
+
line: number;
|
|
56
|
+
variableName?: string;
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,cAAc;IAC7B,YAAY,EAAE,OAAO,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,SAAS,EAAE,CAAC;IACnB,IAAI,EAAE,SAAS,EAAE,CAAC;IAClB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,QAAQ,CAAC,EAAE;QACT,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;KACnB,CAAC;CACH;AAED,MAAM,MAAM,SAAS,GAAG,UAAU,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC;AAE/D,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,SAAS,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,gBAAgB,EAAE,MAAM,CAAC;IACzB,UAAU,EAAE,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC;IACtC,OAAO,EAAE;QACP,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;QACb,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,eAAe,CAAC,EAAE,MAAM,CAAC;KAC1B,CAAC;CACH;AAED,MAAM,WAAW,UAAU;IACzB,UAAU,EAAE,SAAS,EAAE,CAAC;IACxB,eAAe,EAAE,cAAc,EAAE,CAAC;IAClC,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,WAAW,OAAO;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,SAAS,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE;QACP,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;QACb,YAAY,CAAC,EAAE,MAAM,CAAC;KACvB,CAAC;CACH"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
package/package.json
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@continum/cli",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Continum CLI - Pre-commit credential scanner and pattern learning tool",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"continum": "./dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"build": "tsc",
|
|
11
|
+
"dev": "tsc --watch",
|
|
12
|
+
"prepublishOnly": "npm run build"
|
|
13
|
+
},
|
|
14
|
+
"keywords": [
|
|
15
|
+
"security",
|
|
16
|
+
"credentials",
|
|
17
|
+
"git",
|
|
18
|
+
"pre-commit",
|
|
19
|
+
"scanner"
|
|
20
|
+
],
|
|
21
|
+
"author": "Continum",
|
|
22
|
+
"license": "MIT",
|
|
23
|
+
"dependencies": {
|
|
24
|
+
"chalk": "^4.1.2",
|
|
25
|
+
"commander": "^11.1.0",
|
|
26
|
+
"prompts": "^2.4.2",
|
|
27
|
+
"ora": "^5.4.1",
|
|
28
|
+
"node-fetch": "^2.7.0",
|
|
29
|
+
"open": "^8.4.2"
|
|
30
|
+
},
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"@types/node": "^20.0.0",
|
|
33
|
+
"@types/node-fetch": "^2.6.11",
|
|
34
|
+
"@types/prompts": "^2.4.9",
|
|
35
|
+
"typescript": "^5.3.3"
|
|
36
|
+
},
|
|
37
|
+
"engines": {
|
|
38
|
+
"node": ">=16.0.0"
|
|
39
|
+
}
|
|
40
|
+
}
|