devibe
Version:
Intelligent repository cleanup with auto mode, AI learning, markdown consolidation, auto-consolidate workflow, context-aware classification, and cost optimization
86 lines • 3.29 kB
JavaScript
import * as fs from 'fs/promises';
import { BUILT_IN_PATTERNS } from './secret-patterns.js';
export class SecretScanner {
async scanFiles(files) {
const startTime = Date.now();
const allFindings = [];
for (const file of files) {
const content = await fs.readFile(file, 'utf-8');
const findings = this.matchPatterns(content, file);
allFindings.push(...findings);
}
const summary = {
critical: allFindings.filter((f) => f.severity === 'critical').length,
high: allFindings.filter((f) => f.severity === 'high').length,
medium: allFindings.filter((f) => f.severity === 'medium').length,
low: allFindings.filter((f) => f.severity === 'low').length,
};
return {
filesScanned: files.length,
secretsFound: allFindings.length,
duration: Date.now() - startTime,
findings: allFindings,
summary,
};
}
matchPatterns(content, file = '') {
const findings = [];
const lines = content.split('\n');
for (const pattern of BUILT_IN_PATTERNS) {
for (let lineIndex = 0; lineIndex < lines.length; lineIndex++) {
const line = lines[lineIndex];
const regex = new RegExp(pattern.pattern.source, pattern.pattern.flags);
let match;
while ((match = regex.exec(line)) !== null) {
const matchedText = match[0];
const context = this.truncateContext(line, matchedText);
findings.push({
file,
line: lineIndex + 1,
column: match.index + 1,
type: pattern.name,
pattern: pattern.id,
severity: pattern.severity,
context,
recommendation: pattern.recommendation,
confidence: 0.9,
});
}
}
}
return findings;
}
truncateContext(line, secret) {
const maxLength = 80;
const replacement = '****';
// Replace the secret with asterisks
let truncated = line.replace(secret, secret.substring(0, 8) + replacement);
// Truncate if too long
if (truncated.length > maxLength) {
truncated = truncated.substring(0, maxLength) + '...';
}
return truncated.trim();
}
hasHighEntropy(value) {
const entropy = this.calculateEntropy(value);
return entropy > 4.0;
}
calculateEntropy(value) {
if (value.length === 0)
return 0;
const frequencies = new Map();
// Count character frequencies
for (const char of value) {
frequencies.set(char, (frequencies.get(char) || 0) + 1);
}
// Calculate Shannon entropy
let entropy = 0;
const length = value.length;
for (const count of frequencies.values()) {
const probability = count / length;
entropy -= probability * Math.log2(probability);
}
return entropy;
}
}
//# sourceMappingURL=secret-scanner.js.map