Files
boc/EOS/semantic-policy-engine.mjs
T

212 lines
7.5 KiB
JavaScript
Raw Normal View History

#!/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 };