05ed037fe8
- DNS: pilot.landvex.com -> 16.170.83.169 - TLS: Let's Encrypt certificate (expires 2026-09-30) - Nginx: reverse proxy with SSL termination - API: https://pilot.landvex.com/api/v1/missions - UI: https://pilot.landvex.com/ - Upload: POST /api/v1/missions/import (multipart/form-data) Verified: ✅ https://pilot.landvex.com/health ✅ https://pilot.landvex.com/version ✅ https://pilot.landvex.com/api/v1/missions (list) ✅ https://pilot.landvex.com/api/v1/missions/:id (get) ✅ POST /api/v1/missions/import (video upload) ✅ UI loads with title 'LandveX Intelligence Lab' Next: Pilot 001 — Break the system!
150 lines
5.0 KiB
JavaScript
150 lines
5.0 KiB
JavaScript
#!/usr/bin/env node
|
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
// Evidence Quality — Normaliserad och uppdelad i delkomponenter
|
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
|
|
/**
|
|
* Evidence Quality Metrics
|
|
*
|
|
* Delas upp i:
|
|
* - Completeness: Har vi all nödvändig evidens?
|
|
* - Relevance: Är evidensen relevant för operationen?
|
|
* - Consistency: Stämmer evidensen överens?
|
|
* - Freshness: Hur aktuell är evidensen?
|
|
*
|
|
* Alla mäts på skalan 0-100 och viktas till ett totalt score.
|
|
*/
|
|
|
|
const WEIGHTS = {
|
|
completeness: 0.35,
|
|
relevance: 0.35,
|
|
consistency: 0.20,
|
|
freshness: 0.10
|
|
};
|
|
|
|
/**
|
|
* Beräkna Evidence Completeness
|
|
*
|
|
* Hur många av de nödvändiga evidenspunkterna har vi?
|
|
*/
|
|
function calculateCompleteness(evidence, operation) {
|
|
const requirements = {
|
|
REMOTE_PRODUCTION_ACCESS: ['targetEnvironment', 'accessMethod'],
|
|
MODIFY_PERSISTENT_PRODUCTION_DATA: ['targetEnvironment', 'dataOperation'],
|
|
MODIFY_PRODUCTION_INFRASTRUCTURE: ['targetEnvironment', 'infraOperation'],
|
|
PRODUCTION_RELEASE: ['targetEnvironment', 'releaseOperation'],
|
|
EXPOSE_OR_CREATE_SECRET: ['secretPattern'],
|
|
READ_PRODUCTION_DATA: ['readOperation'],
|
|
OBSERVE_INFRASTRUCTURE: ['observeOperation'],
|
|
DEVELOPMENT_TASK: [],
|
|
UNKNOWN_OPERATION: []
|
|
};
|
|
|
|
const required = requirements[operation] || [];
|
|
if (required.length === 0) return 100; // Ingen evidens krävs
|
|
|
|
let found = 0;
|
|
for (const req of required) {
|
|
if (evidence[req] !== null && evidence[req] !== false && evidence[req] !== undefined) {
|
|
found++;
|
|
}
|
|
}
|
|
|
|
return Math.round((found / required.length) * 100);
|
|
}
|
|
|
|
/**
|
|
* Beräkna Evidence Relevance
|
|
*
|
|
* Hur relevant är evidensen för den identifierade operationen?
|
|
*/
|
|
function calculateRelevance(evidence, operation, candidates) {
|
|
let score = 0;
|
|
|
|
// Om vi har en stark kandidat som matchar operationen
|
|
const matchingCandidate = candidates.find(c => c.operation === operation);
|
|
if (matchingCandidate) {
|
|
score += Math.round(matchingCandidate.confidence * 50);
|
|
}
|
|
|
|
// Om targetEnvironment är produktion och operation är produktionsrelaterad
|
|
const productionOps = ['REMOTE_PRODUCTION_ACCESS', 'MODIFY_PERSISTENT_PRODUCTION_DATA',
|
|
'MODIFY_PRODUCTION_INFRASTRUCTURE', 'PRODUCTION_RELEASE'];
|
|
if (evidence.targetEnvironment === 'production' && productionOps.includes(operation)) {
|
|
score += 30;
|
|
}
|
|
|
|
// Om vi har direkta kommandon som matchar
|
|
if (evidence.accessMethod && operation === 'REMOTE_PRODUCTION_ACCESS') score += 20;
|
|
if (evidence.dataOperation && operation === 'MODIFY_PERSISTENT_PRODUCTION_DATA') score += 20;
|
|
if (evidence.infraOperation && operation === 'MODIFY_PRODUCTION_INFRASTRUCTURE') score += 20;
|
|
if (evidence.releaseOperation && operation === 'PRODUCTION_RELEASE') score += 20;
|
|
if (evidence.secretPattern && operation === 'EXPOSE_OR_CREATE_SECRET') score += 20;
|
|
|
|
return Math.min(score, 100);
|
|
}
|
|
|
|
/**
|
|
* Beräkna Evidence Consistency
|
|
*
|
|
* Stämmer evidensen överens med sig själv?
|
|
*/
|
|
function calculateConsistency(evidence, candidates) {
|
|
let score = 100;
|
|
|
|
// Om vi har flera kandidater med liknande konfidens, minska score
|
|
if (candidates.length >= 2) {
|
|
const diff = candidates[0].confidence - candidates[1].confidence;
|
|
if (diff < 0.2) {
|
|
score -= 30; // Osäkerhet mellan toppkandidater
|
|
}
|
|
}
|
|
|
|
// Om evidensen är motstridig
|
|
if (evidence.targetEnvironment === 'production' && evidence.readOperation) {
|
|
score -= 20; // Produktion + läsning kan vara OK men är värt att flagga
|
|
}
|
|
|
|
return Math.max(score, 0);
|
|
}
|
|
|
|
/**
|
|
* Beräkna Evidence Freshness
|
|
*
|
|
* Hur aktuell är evidensen? (Placeholder — kan utökas med tidsstämplar)
|
|
*/
|
|
function calculateFreshness(evidence) {
|
|
// För närvarande: anta att all evidens är färsk
|
|
// I framtiden: jämför med tidsstämplar från git, deployment, etc.
|
|
return 100;
|
|
}
|
|
|
|
/**
|
|
* Beräkna total Evidence Quality
|
|
*/
|
|
function calculateEvidenceQuality(evidence, operation, candidates) {
|
|
const completeness = calculateCompleteness(evidence, operation);
|
|
const relevance = calculateRelevance(evidence, operation, candidates);
|
|
const consistency = calculateConsistency(evidence, candidates);
|
|
const freshness = calculateFreshness(evidence);
|
|
|
|
const total = Math.round(
|
|
completeness * WEIGHTS.completeness +
|
|
relevance * WEIGHTS.relevance +
|
|
consistency * WEIGHTS.consistency +
|
|
freshness * WEIGHTS.freshness
|
|
);
|
|
|
|
return {
|
|
total: Math.min(total, 100), // Normalisera till max 100
|
|
components: {
|
|
completeness,
|
|
relevance,
|
|
consistency,
|
|
freshness
|
|
}
|
|
};
|
|
}
|
|
|
|
export { calculateEvidenceQuality, calculateCompleteness, calculateRelevance, calculateConsistency, calculateFreshness };
|