#!/usr/bin/env node // ═══════════════════════════════════════════════════════════════════════════ // Semantic Policy Engine v2 — Förbättrad med fler mönster // ═══════════════════════════════════════════════════════════════════════════ 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', 'nå', 'kommunicera', 'automatisera', 'felsöka', 'debug', 'loggar', 'visa', 'aws cli', 'sdk', 'api', 'konsol', 'verktyg' ], actions: ['ssh', 'ssm', 'shell', 'tunnel', 'login', 'connect', 'session', 'access', 'automate', 'debug', 'logs'], 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', 'auth', 'hårdkoda', 'hardcode', 'variabel', 'konfiguration', 'testning' ], 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, /hårdkoda/i, /hardcode/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', 'buggfix', 'snabbfix', 'temporär', 'liten ändring' ], 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', 'justera', 'datafel', 'engångsfix', 'post-deploy' ], actions: ['update', 'delete', 'insert', 'alter', 'drop', 'modify', 'change', 'correct', 'fix', 'adjust'], 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', 'justera', 'skala', 'scale', 'temporär', 'trafik', 'molnet' ], actions: ['create', 'modify', 'update', 'delete', 'change', 'configure', 'scale'], intent: 'Förändring av infrastrukturresurser', consequence: 'Miljöförändring utan spårbarhet' }, // Rollförvirring — försök kringgå via roll ROLE_CONFUSION: { keywords: [ 'operator', 'admin', 'root', 'sudo', 'du är', 'som admin', 'som root', 'behörighet' ], intent: 'Försök att kringgå policy via rolltilldelning', consequence: 'Obehörig åtkomst' } }; 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 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 if (task.files && (category === 'SECRETS' || category === 'PRODUCTION_ACCESS')) { 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}`); } } } } // Special: Rollförvirring if (category === 'ROLE_CONFUSION') { const rolePatterns = [ /du är (nu )?(operator|admin|root)/i, /som (operator|admin|root)/i, /behöver (operator|admin|root)-behörighet/i ]; for (const regex of rolePatterns) { if (regex.test(description)) { matchScore += 5; matchedKeywords.push('role_confusion'); } } } if (matchScore > 0) { intents.push({ category, score: matchScore, keywords: matchedKeywords, intent: pattern.intent, consequence: pattern.consequence }); } } 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 }; } function checkSemanticPolicy(task) { const analysis = analyzeIntent(task); if (!analysis.primaryIntent) { return { passed: true }; } 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') || (task.description || '').toLowerCase().includes('loggar') && task.action === 'read'; // Kontrollera om det finns godkänd process const hasApprovedProcess = task.pipeline !== undefined || task.terraform !== undefined || task.migration !== undefined || task.approved === true; 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' }, 'ROLE_CONFUSION': { id: 'POL-SEC-001', rule: 'no-production-access' } }; 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 };