/** * THE HIVE SCRUBBER * Sanitizes local rules and signals before they are broadcast to the Global Registry. * Ensures strict anonymity. */ export interface ScrubberResult { sanitizedContent: string; redactionCount: number; riskScore: number; // 0-100 (If too high, do not broadcast) } export class HiveScrubber { // Patterns that definitely identify a project and MUST be removed private static SENSITIVE_PATTERNS = [ /(api_key|secret|token|password)[\s]*[:=][\s]*['"][a-zA-Z0-9_\-]+['"]/gi, // Secrets /[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g, // Emails /(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\. (?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)/g, // IPs /postgres:\/\/[^:]+:[^@]+@/g, // DB Connection Strings ]; // Generic replacements for project-specific terms to keep the rule abstract private static ABSTRACTION_MAP: Record = { 'Vibeline': '{PROJECT_NAME}', 'Rigstate': '{FRAMEWORK}', 'Steinhofve': '{USER}', }; /** * Scrubs a string (rule content or log excerpt) of sensitive data. */ public static scrub(content: string, customTerms: string[] = []): ScrubberResult { let scrubbed = content; let count = 0; let risk = 0; // 1. Remove Hard Credentials (High Risk) this.SENSITIVE_PATTERNS.forEach(pattern => { if (pattern.test(scrubbed)) { scrubbed = scrubbed.replace(pattern, '[REDACTED_CREDENTIAL]'); count++; risk += 50; // High penalty for finding secrets } }); // 2. Abstract Project Specifics (Medium Risk) Object.entries(this.ABSTRACTION_MAP).forEach(([term, replacement]) => { const regex = new RegExp(term, 'gi'); if (regex.test(scrubbed)) { scrubbed = scrubbed.replace(regex, replacement); count++; } }); // 3. Scrub Custom Terms (e.g. Table names passed from context) customTerms.forEach(term => { const regex = new RegExp(term, 'gi'); if (regex.test(scrubbed)) { scrubbed = scrubbed.replace(regex, '{ENTITY}'); count++; } }); return { sanitizedContent: scrubbed, redactionCount: count, riskScore: Math.min(risk, 100) }; } }