Files
boc/EOS/policy-enforcement.mjs
T
Bernt 05ed037fe8 pilot.landvex.com: HTTPS + Full Stack Verified
- 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!
2026-07-02 17:34:19 +00:00

295 lines
9.1 KiB
JavaScript

#!/usr/bin/env node
// ═══════════════════════════════════════════════════════════════════════════
// EOS Policy Enforcement — Förhindra åtgärder, inte bara logga
// Erik-krav: "Om en agent försöker deploya utan pipeline ska EOS förhindra åtgärden"
// ═══════════════════════════════════════════════════════════════════════════
import { execSync } from 'child_process';
import { existsSync, appendFileSync } from 'fs';
const ENFORCEMENT_LOG = '/home/bernt/.openclaw/workspace/EOS/enforcement-log.jsonl';
/**
* Verkställbara policyer — dessa förhindrar åtgärder
*/
const POLICIES = [
{
id: 'block-direct-prod',
name: 'Blockera direkt skrivning till produktion',
check: (action) => {
// Kontrollera om vi är på produktionsserver
const isProd = process.env.NODE_ENV === 'production' ||
existsSync('/etc/ec2-release');
const isWrite = action.type === 'write' || action.type === 'deploy';
return {
allowed: !(isProd && isWrite),
reason: isProd && isWrite ? 'Direkt skrivning till produktion blockerad' : null
};
}
},
{
id: 'block-no-pipeline-deploy',
name: 'Blockera deployment utan pipeline',
check: (action) => {
if (action.type !== 'deploy') return { allowed: true };
const hasPipeline = existsSync('/home/bernt/repos/quixzoom.com/.github/workflows') ||
existsSync('/home/bernt/repos/quixzoom.com/.gitlab-ci.yml');
return {
allowed: hasPipeline,
reason: hasPipeline ? null : 'Deployment utan CI/CD pipeline blockerad'
};
}
},
{
id: 'block-server-edit',
name: 'Blockera redigering på server',
check: (action) => {
const isServer = existsSync('/etc/ec2-release') || existsSync('/var/lib/cloud');
const isEdit = action.type === 'edit' || action.type === 'write';
return {
allowed: !(isServer && isEdit),
reason: isServer && isEdit ? 'Redigering på server blockerad' : null
};
}
},
{
id: 'block-uncommitted',
name: 'Blockera ändring utan commit',
check: (action) => {
if (action.type !== 'commit' && action.type !== 'write') return { allowed: true };
try {
const status = execSync('git status --short', {
cwd: '/home/bernt/repos/quixzoom.com',
encoding: 'utf8'
});
const hasUncommitted = status.trim().length > 0;
// Tillåt commit-action även med ocommitade filer (det är poängen)
if (action.type === 'commit') return { allowed: true };
return {
allowed: !hasUncommitted,
reason: hasUncommitted ? 'Ocommitade ändringar finns — commita först' : null
};
} catch {
return { allowed: false, reason: 'Kunde inte verifiera git-status' };
}
}
},
{
id: 'block-no-migration',
name: 'Blockera databasändring utan migration',
check: (action) => {
if (!action.target?.match(/database|db|sql/i)) return { allowed: true };
const hasMigration = existsSync('/home/bernt/repos/quixzoom.com/migrations') ||
existsSync('/home/bernt/repos/quixzoom.com/prisma');
return {
allowed: hasMigration,
reason: hasMigration ? null : 'Databasändring utan migration blockerad'
};
}
},
{
id: 'block-no-api-contract',
name: 'Blockera API-ändring utan kontrakt',
check: (action) => {
if (!action.target?.match(/api|endpoint|route/i)) return { allowed: true };
const hasContract = existsSync('/home/bernt/repos/quixzoom.com/openapi.yaml') ||
existsSync('/home/bernt/repos/quixzoom.com/openapi.json');
return {
allowed: hasContract,
reason: hasContract ? null : 'API-ändring utan kontrakt blockerad'
};
}
},
{
id: 'require-human-approval',
name: 'Kräv mänskligt godkännande för kritiska åtgärder',
check: (action) => {
const criticalActions = ['delete', 'drop', 'destroy', 'remove'];
const isCritical = criticalActions.some(a => action.type?.includes(a));
return {
allowed: !isCritical,
reason: isCritical ? 'KRITISK ÅTGÄRD — Kräver mänskligt godkännande' : null,
requiresApproval: isCritical
};
}
}
];
class PolicyEnforcement {
constructor() {
this.policies = POLICIES;
}
/**
* Validera en åtgärd mot alla policyer
*/
validateAction(action) {
console.log(`🔍 Validerar åtgärd: ${action.type} ${action.target || ''}\n`);
const violations = [];
let requiresApproval = false;
for (const policy of this.policies) {
const result = policy.check(action);
if (!result.allowed) {
violations.push({
policy: policy.id,
name: policy.name,
reason: result.reason
});
this.logEnforcement({
action,
policy: policy.id,
allowed: false,
reason: result.reason,
timestamp: new Date().toISOString()
});
}
if (result.requiresApproval) {
requiresApproval = true;
}
}
const result = {
action,
allowed: violations.length === 0,
violations,
requiresApproval,
timestamp: new Date().toISOString()
};
this.printResult(result);
return result;
}
/**
* Försök utföra en åtgärd (med policy-kontroll)
*/
executeAction(action) {
const validation = this.validateAction(action);
if (!validation.allowed) {
console.log('🔴 ÅTGÄRD BLOCKERAD\n');
for (const v of validation.violations) {
console.log(` ${v.name}`);
console.log(` ${v.reason}`);
}
console.log();
return { executed: false, validation };
}
if (validation.requiresApproval) {
console.log('🟡 ÅTGÄRD KRÄVER GODKÄNNANDE\n');
console.log(' Väntar på mänskligt godkännande...\n');
return { executed: false, pendingApproval: true, validation };
}
console.log('✅ ÅTGÄRD GODKÄND\n');
return { executed: true, validation };
}
logEnforcement(entry) {
appendFileSync(ENFORCEMENT_LOG, JSON.stringify(entry) + '\n', 'utf8');
}
printResult(result) {
if (result.allowed && !result.requiresApproval) {
console.log(`${result.action.type} — Godkänd`);
} else if (result.requiresApproval) {
console.log(`🟡 ${result.action.type} — Kräver godkännande`);
} else {
console.log(`🔴 ${result.action.type} — Blockerad`);
}
}
/**
* Visa policyer
*/
listPolicies() {
console.log('📋 POLICYER\n');
for (const policy of this.policies) {
console.log(` ${policy.name}`);
console.log(` ID: ${policy.id}`);
console.log();
}
}
/**
* Visa enforcement-logg
*/
showLog() {
if (!existsSync(ENFORCEMENT_LOG)) {
console.log('Ingen enforcement-logg hittad\n');
return;
}
const entries = readFileSync(ENFORCEMENT_LOG, 'utf8')
.split('\n')
.filter(line => line.trim())
.map(line => {
try { return JSON.parse(line); } catch { return null; }
})
.filter(Boolean);
console.log(`📊 ENFORCEMENT-LOGG (${entries.length} entries)\n`);
const blocked = entries.filter(e => !e.allowed);
console.log(` Blockerade: ${blocked.length}`);
console.log(` Godkända: ${entries.length - blocked.length}`);
console.log();
for (const entry of entries.slice(-10)) {
const icon = entry.allowed ? '✅' : '🔴';
console.log(` ${icon} ${entry.action.type} ${entry.action.target || ''}`);
if (entry.reason) {
console.log(` ${entry.reason}`);
}
}
console.log();
}
}
// ── Main ──────────────────────────────────────────────────────────────────
const enforcement = new PolicyEnforcement();
const command = process.argv[2] || '--list';
if (command === '--list') {
enforcement.listPolicies();
} else if (command === '--validate') {
const action = {
type: process.argv[3] || 'deploy',
target: process.argv[4] || 'production'
};
enforcement.validateAction(action);
} else if (command === '--execute') {
const action = {
type: process.argv[3] || 'deploy',
target: process.argv[4] || 'production'
};
enforcement.executeAction(action);
} else if (command === '--log') {
enforcement.showLog();
} else {
console.log('Användning:');
console.log(' node policy-enforcement.mjs --list # Lista policyer');
console.log(' node policy-enforcement.mjs --validate <type> [target] # Validera åtgärd');
console.log(' node policy-enforcement.mjs --execute <type> [target] # Utför med kontroll');
console.log(' node policy-enforcement.mjs --log # Visa logg');
}