#!/usr/bin/env node // ═══════════════════════════════════════════════════════════════════════════ // Semantic Policy Engine — Förstå avsikt, inte bara nyckelord // ═══════════════════════════════════════════════════════════════════════════ /** * Semantic Policy Engine * * Istället för att matcha exakta nyckelord, analyserar vi: * 1. Avsikt (vad försöker användaren göra?) * 2. Kontext (vilken miljö?) * 3. Konsekvens (vad blir resultatet?) */ // Semantiska mönster för olika typer av åtgärder const SEMANTIC_PATTERNS = { // Produktionsåtkomst — alla sätt att komma åt en server PRODUCTION_ACCESS: { keywords: ['ssh', 'ssm', 'shell', 'tunnel', 'login', 'connect', 'session', 'access', 'anslut', 'logga in', 'öppna', 'komma åt'], actions: ['ssh', 'ssm', 'shell', 'tunnel', 'login', 'connect', 'session', 'access'], intent: 'Direktåtkomst till server/miljö', consequence: 'Möjlighet att köra godtycklig kod' }, // Hemligheter — alla sätt att lagra känslig data SECRETS: { keywords: ['password', 'secret', 'token', 'key', 'credential', 'api_key', 'private_key', 'lösenord', 'nyckel', 'hemlig', 'autentisering'], patterns: [ /password\s*[:=]/i, /secret\s*[:=]/i, /token\s*[:=]/i, /key\s*[:=]/i, /credential\s*[:=]/i, /api[_-]?key/i, /private[_-]?key/i, /lösenord/i, /nyckel/i, /hemlig/i ], intent: 'Lagring av känslig autentiseringsdata', consequence: 'Exponering av hemligheter' }, // Deployment — alla sätt att publicera kod DEPLOYMENT: { keywords: ['deploy', 'publish', 'release', 'push', 'update', 'släpp', 'publicera', 'uppdatera'], actions: ['deploy', 'publish', 'release', 'push', 'update'], intent: 'Publicering av kod till miljö', consequence: 'Förändring av körande system' }, // Databasändring — alla sätt att modifiera data DATA_MODIFICATION: { keywords: ['update', 'delete', 'insert', 'alter', 'drop', 'modify', 'change', 'correct', 'fix', 'adjust', 'ändra', 'radera', 'infoga', 'korrigera', 'fixa'], actions: ['update', 'delete', 'insert', 'alter', 'drop', 'modify', 'change', 'correct', 'fix'], intent: 'Förändring av persistent data', consequence: 'Oåterkallelig dataförändring' }, // Infrastrukturförändring — alla sätt att ändra miljö INFRASTRUCTURE_CHANGE: { keywords: ['create', 'modify', 'update', 'delete', 'change', 'configure', 'skapa', 'ändra', 'konfigurera', 'modifiera'], actions: ['create', 'modify', 'update', 'delete', 'change', 'configure'], intent: 'Förändring av infrastrukturresurser', consequence: 'Miljöförändring utan spårbarhet' } }; /** * Analysera semantisk avsikt från en uppgift */ function analyzeIntent(task) { const description = (task.description || '').toLowerCase(); const action = (task.action || '').toLowerCase(); const type = (task.type || '').toLowerCase(); const intents = []; for (const [category, pattern] of Object.entries(SEMANTIC_PATTERNS)) { let matchScore = 0; let matchedKeywords = []; // Kontrollera nyckelord i beskrivning for (const keyword of pattern.keywords) { if (description.includes(keyword.toLowerCase())) { matchScore += 2; matchedKeywords.push(keyword); } } // Kontrollera action if (pattern.actions && pattern.actions.includes(action)) { matchScore += 3; matchedKeywords.push(action); } // Kontrollera typ if (type && pattern.keywords.some(k => type.includes(k.toLowerCase()))) { matchScore += 1; } // Kontrollera regex-mönster (för secrets) if (pattern.patterns) { for (const regex of pattern.patterns) { if (regex.test(description) || regex.test(JSON.stringify(task.files || []))) { matchScore += 3; matchedKeywords.push('pattern_match'); } } } // Kontrollera filer (för secrets) if (task.files && category === 'SECRETS') { for (const file of task.files) { const content = (file.content || '').toLowerCase(); for (const keyword of pattern.keywords) { if (content.includes(keyword.toLowerCase())) { matchScore += 2; matchedKeywords.push(`file:${keyword}`); } } } } if (matchScore > 0) { intents.push({ category, score: matchScore, keywords: matchedKeywords, intent: pattern.intent, consequence: pattern.consequence }); } } // Sortera efter matchningspoäng intents.sort((a, b) => b.score - a.score); return { primaryIntent: intents[0] || null, allIntents: intents, confidence: intents[0] ? Math.min(intents[0].score / 5, 1) : 0 }; } /** * Kontrollera om uppgiften är tillåten */ function checkSemanticPolicy(task) { const analysis = analyzeIntent(task); if (!analysis.primaryIntent) { return { passed: true }; // Ingen farlig avsikt identifierad } const intent = analysis.primaryIntent; const isProduction = task.target === 'production' || (task.description || '').toLowerCase().includes('produktion'); // Kontrollera om det är en tillåten observation const isObservation = task.action === 'inventory' || task.action === 'plan' || task.action === 'validate' || task.action === 'read' || task.action === 'health-check' || task.action === 'log-analysis' || (task.description || '').toLowerCase().includes('visa') || (task.description || '').toLowerCase().includes('läs'); // Kontrollera om det finns godkänd process const hasApprovedProcess = task.pipeline !== undefined || task.terraform !== undefined || task.migration !== undefined || task.approved === true; // Blockera om: // 1. Farlig avsikt identifierad // 2. Produktionsmiljö // 3. Inte observation // 4. Inte godkänd process if (isProduction && !isObservation && !hasApprovedProcess) { const policyMap = { 'PRODUCTION_ACCESS': { id: 'POL-SEC-001', rule: 'no-production-access' }, 'SECRETS': { id: 'POL-SEC-002', rule: 'no-hardcoded-secrets' }, 'DEPLOYMENT': { id: 'POL-DEP-001', rule: 'pipeline-required' }, 'DATA_MODIFICATION': { id: 'POL-DAT-001', rule: 'no-direct-production-db-write' }, 'INFRASTRUCTURE_CHANGE': { id: 'POL-INFRA-001', rule: 'no-unapproved-infra-change' } }; const policy = policyMap[intent.category]; return { passed: false, policyId: policy?.id || 'UNKNOWN', rule: policy?.rule || 'unknown', reason: `${intent.intent} är förbjudet i produktion utan godkänd process. Konsekvens: ${intent.consequence}`, severity: 'CRITICAL', action: 'STOP', evidence: { detectedIntent: intent.category, confidence: analysis.confidence, matchedKeywords: intent.keywords, hasApprovedProcess } }; } return { passed: true }; } export { analyzeIntent, checkSemanticPolicy, SEMANTIC_PATTERNS };