#!/usr/bin/env node // ═══════════════════════════════════════════════════════════════════════════ // Infrastructure Knowledge Graph // Kopplar affärskapacitet till underliggande infrastruktur // ═══════════════════════════════════════════════════════════════════════════ /** * Exempel: * * Capability: Mission Management * ↓ * Service: Mission Service * ↓ * ALB → EC2 → IAM Role → Security Group → Subnet → VPC * ↓ * RDS → Secrets → CloudWatch → Backup */ class InfrastructureKnowledgeGraph { constructor() { this.nodes = new Map(); this.edges = new Map(); } addNode(id, type, properties = {}) { this.nodes.set(id, { id, type, properties, discoveredAt: new Date().toISOString(), source: properties.source || 'unknown' }); return this; } addEdge(from, to, type) { if (!this.edges.has(from)) { this.edges.set(from, []); } this.edges.get(from).push({ to, type }); return this; } getDependencies(nodeId) { const deps = []; const visited = new Set(); const visit = (id) => { if (visited.has(id)) return; visited.add(id); const edges = this.edges.get(id) || []; for (const edge of edges) { deps.push(edge.to); visit(edge.to); } }; visit(nodeId); return deps; } toJSON() { return { nodes: Array.from(this.nodes.values()), edges: Array.from(this.edges.entries()).flatMap(([from, edges]) => edges.map(e => ({ from, to: e.to, type: e.type })) ), metadata: { generatedAt: new Date().toISOString(), version: '1.0' } }; } } // Exempel: aamos-ledger function buildLedgerGraph() { const graph = new InfrastructureKnowledgeGraph(); // Capability graph.addNode('capability-ledger', 'Capability', { name: 'Accounting / Bokföring', description: 'Dubbel bokföring med BAS-konton' }); // Service graph.addNode('service-ledger', 'Service', { name: 'aamos-ledger', port: 3250, status: 'inactive' // STOP-001 }); // Compute graph.addNode('ec2-ledger', 'EC2', { instanceId: 'i-09b2204a52c2f33c9', type: 'r8g.4xlarge', status: 'running' }); // Network graph.addNode('sg-ledger', 'SecurityGroup', { name: 'aamos-ledger-sg', rules: ['3250/tcp'] }); graph.addNode('subnet-ledger', 'Subnet', { cidr: '10.0.1.0/24' }); graph.addNode('vpc-aamos', 'VPC', { id: 'vpc-0e880ea5814b9f1be', cidr: '10.0.0.0/16' }); // Database graph.addNode('rds-ledger', 'RDS', { endpoint: 'platform-identity-core.cvi0qcksmsfj.eu-north-1.rds.amazonaws.com', engine: 'postgresql' }); // Cache graph.addNode('redis-ledger', 'ElastiCache', { status: 'unknown' }); // Secrets graph.addNode('secret-jwt', 'Secret', { name: 'aamos-ledger/prod/jwt-secret', rotation: false // STOP-013 }); graph.addNode('secret-db', 'Secret', { name: 'platform/prod/ledger-db-url', rotation: false // STOP-013 }); // Observability graph.addNode('cw-ledger', 'CloudWatch', { alarms: 0, logs: 0 }); // Edges graph.addEdge('capability-ledger', 'service-ledger', 'provides'); graph.addEdge('service-ledger', 'ec2-ledger', 'runs-on'); graph.addEdge('ec2-ledger', 'sg-ledger', 'secured-by'); graph.addEdge('ec2-ledger', 'subnet-ledger', 'in'); graph.addEdge('subnet-ledger', 'vpc-aamos', 'in'); graph.addEdge('service-ledger', 'rds-ledger', 'uses'); graph.addEdge('service-ledger', 'redis-ledger', 'uses'); graph.addEdge('service-ledger', 'secret-jwt', 'authenticates-with'); graph.addEdge('service-ledger', 'secret-db', 'connects-with'); graph.addEdge('service-ledger', 'cw-ledger', 'monitored-by'); return graph; } // CLI if (process.argv[1] === new URL(import.meta.url).pathname) { const graph = buildLedgerGraph(); console.log(JSON.stringify(graph.toJSON(), null, 2)); } export { InfrastructureKnowledgeGraph, buildLedgerGraph };