#!/usr/bin/env node // ═══════════════════════════════════════════════════════════════════════════ // Evidence Weights — Viktad evidens för bättre resolution // ═══════════════════════════════════════════════════════════════════════════ /** * Evidence Weights * * Varje evidens-signal har en vikt. Resolution avgör utifrån * den sammanlagda vikten, inte långa listor av specialfall. */ const EVIDENCE_WEIGHTS = { // Miljö targetEnvironment: { production: 100, staging: 50, development: 10 }, // Åtkomstmetoder accessMethod: { ssh: 120, ssm: 120, telnet: 120, rdp: 120, api: 80, sdk: 80, 'aws-cli': 80 }, // Dataoperationer dataOperation: { update: 120, delete: 120, insert: 120, alter: 120, drop: 120, select: -40, read: -40 }, // Infrastrukturoperationer infraOperation: { create: 120, modify: 120, update: 120, delete: 120, configure: 120, scale: 100, inventory: -60, plan: -60, validate: -60 }, // Releaseoperationer releaseOperation: { deploy: 120, release: 120, publish: 120, push: 120 }, // Sekretess secretPattern: { hardcoded_secret: 150, password: 150, token: 150, api_key: 150 }, // Filtyper fileType: { mjs: 80, js: 80, ts: 80, json: 60, yml: 60, yaml: 60, md: -80, // Markdown är dokumentation txt: -60, // Textfiler är dokumentation tf: 100, // Terraform är infrastruktur hcl: 100 }, // Kontext context: { manual: 20, direct: 30, temporary: 10 }, // Läsoperationer readOperation: { true: -80 // Läsning minskar risk avsevärt }, // Observation observeOperation: { inventory: -100, plan: -100, validate: -100, 'health-check': -100 } }; /** * Beräkna total vikt för en given evidensuppsättning */ function calculateWeightedScore(evidence) { let score = 0; const breakdown = {}; for (const [key, value] of Object.entries(evidence)) { if (value === null || value === false || value === undefined) continue; const weights = EVIDENCE_WEIGHTS[key]; if (!weights) continue; let weight = 0; if (typeof value === 'boolean') { weight = weights.true || weights[String(value)] || 0; } else if (typeof value === 'string') { weight = weights[value] || 0; } else if (Array.isArray(value)) { for (const item of value) { weight += weights[item] || 0; } } score += weight; breakdown[key] = { value, weight }; } return { score, breakdown }; } /** * Avgör operation baserat på viktad score */ function resolveByWeight(evidence, candidates) { const { score, breakdown } = calculateWeightedScore(evidence); // Hitta den kandidat som bäst matchar den viktade scoren let bestMatch = null; let bestScore = -Infinity; for (const candidate of candidates) { let matchScore = 0; // Basera på kandidatens konfidens matchScore += candidate.confidence * 100; // Justera baserat på evidens if (candidate.operation === 'REMOTE_PRODUCTION_ACCESS' && evidence.accessMethod) { matchScore += 50; } if (candidate.operation === 'MODIFY_PERSISTENT_PRODUCTION_DATA' && evidence.dataOperation) { matchScore += 50; } if (candidate.operation === 'MODIFY_PRODUCTION_INFRASTRUCTURE' && evidence.infraOperation) { matchScore += 50; } if (candidate.operation === 'PRODUCTION_RELEASE' && evidence.releaseOperation) { matchScore += 50; } if (candidate.operation === 'EXPOSE_OR_CREATE_SECRET' && evidence.secretPattern) { matchScore += 50; } // Markdown-filer minskar risk för data/infrastruktur-operationer if (evidence.fileType === 'md' || evidence.fileType === 'txt') { if (['MODIFY_PERSISTENT_PRODUCTION_DATA', 'MODIFY_PRODUCTION_INFRASTRUCTURE'].includes(candidate.operation)) { matchScore -= 100; } } if (matchScore > bestScore) { bestScore = matchScore; bestMatch = candidate; } } return { bestMatch, weightedScore: score, breakdown }; } export { EVIDENCE_WEIGHTS, calculateWeightedScore, resolveByWeight };