qraft
Version:
A powerful CLI tool to qraft structured project setups from GitHub template repositories
286 lines • 11.4 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.SensitiveFileDetector = void 0;
class SensitiveFileDetector {
constructor() {
this.sensitivePatterns = [
// Environment files - CRITICAL
{
pattern: /^\.env$/,
type: 'filename',
severity: 'critical',
description: 'Environment file with potential secrets',
suggestion: 'Use .env.example instead and add .env to .gitignore'
},
{
pattern: /^\.env\.(local|production|staging|development)$/,
type: 'filename',
severity: 'critical',
description: 'Environment-specific configuration file',
suggestion: 'Use .env.example templates and exclude from version control'
},
// API Keys and Tokens - CRITICAL
{
pattern: /api[_-]?key/i,
type: 'content',
severity: 'critical',
description: 'Potential API key in file content',
suggestion: 'Move API keys to environment variables'
},
{
pattern: /secret[_-]?key/i,
type: 'content',
severity: 'critical',
description: 'Potential secret key in file content',
suggestion: 'Use environment variables or secure key management'
},
{
pattern: /access[_-]?token/i,
type: 'content',
severity: 'critical',
description: 'Potential access token in file content',
suggestion: 'Store tokens securely, not in source code'
},
{
pattern: /bearer[_\s]+[a-zA-Z0-9_-]{20,}/i,
type: 'content',
severity: 'critical',
description: 'Bearer token found in content',
suggestion: 'Remove bearer tokens from source code'
},
// Database credentials - HIGH
{
pattern: /database[_-]?url/i,
type: 'content',
severity: 'high',
description: 'Database connection string detected',
suggestion: 'Use environment variables for database URLs'
},
{
pattern: /mongodb:\/\/[^"'\s]+/i,
type: 'content',
severity: 'high',
description: 'MongoDB connection string with credentials',
suggestion: 'Use environment variables for database connections'
},
{
pattern: /postgres:\/\/[^"'\s]+/i,
type: 'content',
severity: 'high',
description: 'PostgreSQL connection string with credentials',
suggestion: 'Use environment variables for database connections'
},
// Private keys - CRITICAL
{
pattern: /-----BEGIN (RSA )?PRIVATE KEY-----/,
type: 'content',
severity: 'critical',
description: 'Private key detected in file',
suggestion: 'Store private keys securely, never in source code'
},
{
pattern: /\.pem$/,
type: 'extension',
severity: 'high',
description: 'PEM certificate/key file',
suggestion: 'Exclude certificate files from version control'
},
{
pattern: /\.key$/,
type: 'extension',
severity: 'high',
description: 'Key file detected',
suggestion: 'Store key files securely outside of source code'
},
// AWS credentials - CRITICAL
{
pattern: /AKIA[0-9A-Z]{16}/,
type: 'content',
severity: 'critical',
description: 'AWS Access Key ID detected',
suggestion: 'Use AWS IAM roles or environment variables'
},
{
pattern: /aws[_-]?secret[_-]?access[_-]?key/i,
type: 'content',
severity: 'critical',
description: 'AWS secret access key reference',
suggestion: 'Use AWS IAM roles or secure credential management'
},
// GitHub tokens - HIGH
{
pattern: /ghp_[a-zA-Z0-9]{36}/,
type: 'content',
severity: 'high',
description: 'GitHub personal access token',
suggestion: 'Revoke token and use environment variables'
},
{
pattern: /github[_-]?token/i,
type: 'content',
severity: 'high',
description: 'GitHub token reference',
suggestion: 'Use GitHub secrets or environment variables'
},
// Password patterns - HIGH
{
pattern: /password\s*[:=]\s*["'][^"']{8,}["']/i,
type: 'content',
severity: 'high',
description: 'Hardcoded password detected',
suggestion: 'Use environment variables or secure authentication'
},
{
pattern: /passwd\s*[:=]\s*["'][^"']{6,}["']/i,
type: 'content',
severity: 'high',
description: 'Hardcoded password detected',
suggestion: 'Use environment variables or secure authentication'
},
// Configuration files that might contain secrets - MEDIUM
{
pattern: /^config\.(json|yaml|yml|toml)$/,
type: 'filename',
severity: 'medium',
description: 'Configuration file that might contain sensitive data',
suggestion: 'Review for sensitive data and use environment variables'
},
{
pattern: /^secrets\./,
type: 'filename',
severity: 'high',
description: 'File named with "secrets" prefix',
suggestion: 'Rename file and use secure secret management'
},
// SSH keys - HIGH
{
pattern: /^id_rsa$/,
type: 'filename',
severity: 'high',
description: 'SSH private key file',
suggestion: 'Exclude SSH keys from version control'
},
{
pattern: /^id_ed25519$/,
type: 'filename',
severity: 'high',
description: 'SSH private key file',
suggestion: 'Exclude SSH keys from version control'
},
// Generic sensitive patterns - LOW to MEDIUM
{
pattern: /credential/i,
type: 'content',
severity: 'medium',
description: 'Reference to credentials',
suggestion: 'Review for sensitive credential information'
},
{
pattern: /\.credentials$/,
type: 'extension',
severity: 'high',
description: 'Credentials file',
suggestion: 'Use secure credential storage instead'
}
];
}
detectSensitiveFiles(files) {
const sensitiveFiles = [];
const severityCounts = {
low: 0,
medium: 0,
high: 0,
critical: 0
};
for (const file of files) {
const result = this.analyzeFile(file);
if (result.reasons.length > 0) {
sensitiveFiles.push(result);
severityCounts[result.severity]++;
}
}
const recommendations = this.generateRecommendations(sensitiveFiles);
return {
sensitiveFiles,
totalSensitiveFiles: sensitiveFiles.length,
severityCounts,
recommendations
};
}
analyzeFile(file) {
const reasons = [];
let maxSeverity = 'low';
const suggestions = [];
for (const pattern of this.sensitivePatterns) {
let matches = false;
switch (pattern.type) {
case 'filename':
matches = this.matchesPattern(file.name, pattern.pattern);
break;
case 'extension':
matches = this.matchesPattern(file.extension, pattern.pattern);
break;
case 'path':
matches = this.matchesPattern(file.relativePath, pattern.pattern);
break;
case 'content':
if (file.content) {
matches = this.matchesPattern(file.content, pattern.pattern);
}
break;
}
if (matches) {
reasons.push(pattern.description);
suggestions.push(pattern.suggestion);
// Update severity to highest found
if (this.getSeverityLevel(pattern.severity) > this.getSeverityLevel(maxSeverity)) {
maxSeverity = pattern.severity;
}
}
}
return {
file,
reasons,
severity: maxSeverity,
suggestions: [...new Set(suggestions)] // Remove duplicates
};
}
matchesPattern(text, pattern) {
if (pattern instanceof RegExp) {
return pattern.test(text);
}
return text.includes(pattern);
}
getSeverityLevel(severity) {
const levels = { low: 1, medium: 2, high: 3, critical: 4 };
return levels[severity] || 0;
}
generateRecommendations(sensitiveFiles) {
const recommendations = [];
if (sensitiveFiles.some(f => f.severity === 'critical')) {
recommendations.push('🚨 CRITICAL: Remove all critical sensitive files before creating the box');
recommendations.push('Use environment variables for API keys, tokens, and secrets');
}
if (sensitiveFiles.some(f => f.severity === 'high')) {
recommendations.push('⚠️ HIGH: Review and secure high-risk files');
recommendations.push('Consider using .env.example files instead of actual .env files');
}
if (sensitiveFiles.length > 0) {
recommendations.push('📋 Add sensitive files to .gitignore');
recommendations.push('Use secure secret management solutions');
recommendations.push('Review all configuration files for embedded secrets');
}
return recommendations;
}
// Get patterns for a specific severity level
getPatternsBySeverity(severity) {
return this.sensitivePatterns.filter(p => p.severity === severity);
}
// Check if a specific file would be flagged as sensitive
isFileSensitive(file) {
const result = this.analyzeFile(file);
return result.reasons.length > 0;
}
}
exports.SensitiveFileDetector = SensitiveFileDetector;
//# sourceMappingURL=sensitiveFileDetector.js.map