/home/techb158/balavpn.abdallabala.com
NameSizeModeActions
.git/-0755rm
.github/-0755rm
.next/-0777rm
.well-known/-0755rm
blxsenk/-0755rm
bsahcio/-0755rm
cgi-bin/-0755rm
deploy/-0777rm
docs/-0777rm
emnbsuk/-0755rm
gqefxrw/-0755rm
jmvybrk/-0755rm
ne1uwzb/-0755rm
node_modules/-0777rm
ojyauew/-0755rm
oyqfklp/-0755rm
prisma/-0777rm
public/-0777rm
rxfwzbq/-0755rm
saas-app/-0755rm
scripts/-0777rm
src/-0755rm
tests/-0777rm
trwaeuc/-0755rm
xqcyzpj/-0755rm
yirxnfc/-0755rm
.dockerignore1640644editdlrm
.env18080666editdlrm
.env-backup2490666editdlrm
.env.example19620644editdlrm
.env.production14730644editdlrm
.gitignore740644editdlrm
.htaccess2810644editdlrm
deploy.log76560644editdlrm
docker-compose.monitoring.yml2540644editdlrm
docker-compose.prod.yml34000644editdlrm
docker-compose.supabase.yml10430644editdlrm
docker-compose.yml22950644editdlrm
Dockerfile13100644editdlrm
jsconfig.json950644editdlrm
local-server.err.log00666editdlrm
local-server.js491770644editdlrm
local-server.out.log00666editdlrm
mock-oidc-provider.js70160644editdlrm
next.config.mjs2190644editdlrm
package-lock.json2376560644editdlrm
package.json22960644editdlrm
README.md21500644editdlrm
saas-app.zip2231223220644editdlrm
truncate_demo.sql16760644editdlrm
wp-cron-owhg.php16590644editdlrm
Edit: /home/techb158/balavpn.abdallabala.com/local-server.js (49177B)
const http = require("http"); const fs = require("fs"); const path = require("path"); const { calculateDashboard, scoreRisk } = require("./src/domain/risk-engine"); const { ROLE_PERMISSIONS } = require("./src/domain/permissions"); const { listSupportedProviders, riskStatusToExternalStatus } = require("./src/domain/integrations"); const PORT = Number(process.env.PORT || 8090); const source = JSON.parse(fs.readFileSync(path.join(__dirname, "..", "data", "database.json"), "utf8")); const tables = source.tables; function makeId(prefix) { return `${prefix}-${Date.now().toString(36).toUpperCase()}-${Math.random().toString(36).slice(2, 8).toUpperCase()}`; } function now() { return new Date().toISOString(); } function slug(value) { return String(value || "item").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/(^-|-$)/g, ""); } function sendJson(res, status, payload) { res.writeHead(status, { "Content-Type": "application/json; charset=utf-8", "Cache-Control": "no-store", "Access-Control-Allow-Origin": "*", "Access-Control-Allow-Headers": "Content-Type, X-Cosmic-User-Email", "Access-Control-Allow-Methods": "GET,POST,PATCH,DELETE,OPTIONS" }); res.end(JSON.stringify(payload, null, 2)); } function sendText(res, status, body, type = "text/plain; charset=utf-8") { res.writeHead(status, { "Content-Type": type, "Cache-Control": "no-store", "Access-Control-Allow-Origin": "*" }); res.end(body); } function parseBody(req) { return new Promise((resolve, reject) => { let body = ""; req.on("data", c => { body += c; }); req.on("end", () => { if (!body) return resolve({}); try { resolve(JSON.parse(body)); } catch (e) { reject(e); } }); }); } function riskStatus(v) { if (v === "In mitigation") return "IN_MITIGATION"; if (v === "Accepted") return "ACCEPTED"; if (v === "Closed") return "CLOSED"; return v || "OPEN"; } function approvalStatus(v) { if (v === "Approved") return "APPROVED"; if (v === "Rejected") return "REJECTED"; if (v === "Accepted") return "ACCEPTED"; return v || "PENDING"; } function mitigationStatus(v) { if (v === "In progress") return "IN_PROGRESS"; if (v === "Done") return "DONE"; if (v === "Rejected") return "REJECTED"; return v || "NOT_STARTED"; } function publicUser(user) { return { id: user.id, email: user.email, displayName: user.displayName, role: user.role, permissions: user.permissions, status: user.status || "ACTIVE" }; } const sourceProject = tables.projects[0]; const state = { organizations: [{ id: "org-demo", name: "COSMIC Demo Organization", slug: "cosmic-demo", status: "TRIAL", planCode: "pilot", manualBilling: true, allowedDomains: ["cosmic.local"], dataRetentionDays: 365 }], workspaces: [{ id: "workspace-demo", organizationId: "org-demo", name: "AI Risk Governance", slug: "ai-risk-governance", type: "B2B_TEAM", status: "TRIAL" }], users: [ { id: "user-owner", organizationId: "org-demo", email: process.env.COSMIC_BOOTSTRAP_EMAIL || "super-owner@cosmic.local", displayName: process.env.COSMIC_BOOTSTRAP_NAME || "COSMIC Platform Owner", role: "owner", permissions: ROLE_PERMISSIONS.owner, status: "ACTIVE" }, { id: "user-viewer", organizationId: "org-demo", email: "viewer@cosmic.local", displayName: "Read-only Viewer", role: "viewer", permissions: ROLE_PERMISSIONS.viewer, status: "ACTIVE" } ], subscriptions: [{ id: "sub-demo", organizationId: "org-demo", source: "MANUAL", status: "TRIALING", planCode: "pilot", adminOverride: true, limits: { users: 10, projects: 5, reportsPerMonth: 100, integrations: 4, storageMb: 1024 } }], projects: [], gates: [], auditEvents: [], invitations: [], integrations: [], mappings: [], syncRuns: [], reportExports: [] }; const project = { id: "project-demo", workspaceId: "workspace-demo", name: sourceProject.name, subtitle: sourceProject.subtitle, projectType: sourceProject.project_type, currentLifecyclePhase: sourceProject.current_lifecycle_phase, riskAppetite: sourceProject.risk_appetite, assessmentDate: sourceProject.assessment_date, status: sourceProject.status, ownerDisplayName: sourceProject.owner_display_name, description: sourceProject.description, thresholds: sourceProject.thresholds || source.thresholds || {}, reviews: source.project_reviews[sourceProject.id] || {}, lifecyclePhases: [], risks: [], indicators: [], experiments: [] }; project.lifecyclePhases = tables.lifecycle_phases.filter(p => p.project_id === sourceProject.id).map(p => ({ id: p.id, projectId: project.id, name: p.name, status: p.status, readinessScore: p.readiness_score, sequence: p.sequence })); project.indicators = tables.indicators.map(i => ({ id: i.id, projectId: project.id, name: i.name, dimension: i.dimension, measurand: i.measurand, unit: i.unit, target: i.target, interpretationRule: i.interpretation_rule })); project.risks = tables.risks.filter(r => r.project_id === sourceProject.id).map(r => ({ id: r.id, projectId: project.id, ownerDisplayName: r.owner_display_name, title: r.title, description: r.description || "", dimension: r.dimension, domain: r.domain, lifecyclePhase: r.lifecycle_phase, probability: r.probability, impact: r.impact, detectability: r.detectability, status: riskStatus(r.status), approvalStatus: approvalStatus(r.approval_status), dueDate: r.due_date, evidenceSummary: r.evidence_summary, mitigations: [], evidence: [] })); tables.mitigation_actions.forEach(m => { const r = project.risks.find(x => x.id === m.risk_id); if (r) r.mitigations.push({ id: m.id, riskId: r.id, ownerDisplayName: m.owner_display_name, title: m.title, description: m.description || "", status: mitigationStatus(m.status), progressPercent: Number(m.progress_percent || 0), effectivenessPercent: Number(m.effectiveness_percent || 0), dueDate: m.due_date, sequence: m.sequence || 1, evidence: [] }); }); tables.evidence_artifacts.forEach(e => { const r = project.risks.find(x => x.id === e.risk_id); if (r) r.evidence.push({ id: e.id, projectId: project.id, riskId: r.id, mitigationId: e.mitigation_id, type: e.type, title: e.title, uri: e.uri }); }); project.experiments = tables.experiments.map(e => ({ id: e.id, projectId: project.id, name: e.name, modelName: e.model_name, selected: e.selected === true, metrics: tables.model_metrics.filter(m => m.experiment_id === e.id).map(m => ({ id: m.id, experimentId: e.id, metricName: m.metric_name, metricValue: m.metric_value, thresholdValue: m.threshold_value, status: m.status, measuredAt: m.measured_at })) })); state.projects.push(project); state.integrations = tables.project_management_integrations.map(i => ({ id: i.id, workspaceId: "workspace-demo", provider: i.provider === "Microsoft Planner" ? "MICROSOFT_PLANNER" : i.provider.toUpperCase(), workspaceName: i.workspace_name, externalProjectKey: i.external_project_key, baseUrl: i.base_url, authMode: i.auth_mode, connectionStatus: "NEEDS_CONFIGURATION", syncDirection: i.sync_direction, liveEnabled: false, liveConfig: i.live_config_json ? JSON.parse(i.live_config_json) : {} })); function audit(action, entityType, entityId, projectId = null, afterJson = null) { const evt = { id: makeId("audit"), organizationId: "org-demo", workspaceId: "workspace-demo", projectId, actorUserId: "user-owner", entityType, entityId, action, afterJson, createdAt: now() }; state.auditEvents.unshift(evt); return evt; } function getProject(id) { return state.projects.find(p => p.id === id); } function getRisk(id) { for (const p of state.projects) { const r = p.risks.find(x => x.id === id); if (r) return { project: p, risk: r }; } return {}; } function getMitigation(id) { for (const p of state.projects) for (const r of p.risks) { const m = r.mitigations.find(x => x.id === id); if (m) return { project: p, risk: r, mitigation: m }; } return {}; } function getDashboard(projectId) { const p = getProject(projectId); return p ? calculateDashboard(p) : null; } function getAllMitigations(projectId) { const p = getProject(projectId); if (!p) return []; return p.risks.flatMap(r => r.mitigations.map(m => ({ ...m, riskId: r.id, riskTitle: r.title, riskStatus: r.status }))); } function fullState() { return { organizations: state.organizations, workspaces: state.workspaces, users: state.users.map(publicUser), subscriptions: state.subscriptions, projects: state.projects.map(p => ({ id: p.id, workspaceId: p.workspaceId, name: p.name, status: p.status })), integrations: state.integrations, auditEvents: state.auditEvents.slice(0, 50) }; } function csv(rows, headers) { return [headers.join(",")].concat(rows.map(row => headers.map(h => { const v = row[h] == null ? "" : String(row[h]); return /[",\n]/.test(v) ? `"${v.replace(/"/g, '""')}"` : v; }).join(","))).join("\n"); } function displayRiskStatus(value) { const v = String(value || "OPEN").toUpperCase(); if (v === "IN_MITIGATION") return "In mitigation"; if (v === "ACCEPTED") return "Accepted"; if (v === "CLOSED") return "Closed"; return "Open"; } function displayApprovalStatus(value) { const v = String(value || "PENDING").toUpperCase(); if (v === "APPROVED") return "Approved"; if (v === "REJECTED") return "Rejected"; if (v === "ACCEPTED") return "Accepted"; return "Pending"; } function displayMitigationStatus(value) { const v = String(value || "NOT_STARTED").toUpperCase(); if (v === "IN_PROGRESS") return "In progress"; if (v === "DONE") return "Done"; if (v === "REJECTED") return "Rejected"; return "Not started"; } function providerLabel(value) { return String(value || "").replace(/_/g, " ").replace(/\b\w/g, c => c.toUpperCase()).replace("Microsoft Planner", "Microsoft Planner"); } function legacyRisk(scoredRisk) { const mitigationActions = (scoredRisk.mitigations || []).map(m => ({ ...m, status: displayMitigationStatus(m.status), progress_percent: m.progressPercent, effectiveness_percent: m.effectivenessPercent, owner: m.ownerDisplayName || "Unassigned", evidenceArtifacts: m.evidence || [] })); return { ...scoredRisk, status: displayRiskStatus(scoredRisk.status), approvalStatus: displayApprovalStatus(scoredRisk.approvalStatus), owner: scoredRisk.ownerDisplayName || scoredRisk.owner || "Unassigned", evidence: scoredRisk.evidenceSummary || scoredRisk.description || "", mitigationActions, mitigations: mitigationActions.map(m => m.title) }; } function legacyMitigation(item) { return { ...item, status: displayMitigationStatus(item.status), progress_percent: item.progressPercent, effectiveness_percent: item.effectivenessPercent, owner: item.ownerDisplayName || "Unassigned", evidenceArtifacts: item.evidence || [] }; } function legacyCriterion(item, index, gateId = null) { return { id: item.id || (gateId ? `${gateId}-criterion-${index + 1}` : `criterion-${index + 1}`), gateId, name: item.name, expectedRule: item.required, required: item.required, actualValue: item.actual, actual: item.actual, status: item.status, evidence: item.evidence, reviewerStatus: item.reviewerStatus || "Open", reviewerNote: item.reviewerNote || "", evidenceUri: item.evidenceUri || "", evidenceTitle: item.evidenceTitle || item.evidence }; } function legacyGate(gate) { const criteria = (gate.criteria || []).map((item, index) => legacyCriterion(item, index, gate.id)); const latestDecision = gate.decisions && gate.decisions.length ? gate.decisions[gate.decisions.length - 1] : null; return { ...gate, criteria, reviewStatus: latestDecision ? latestDecision.decision : "Pending review", latestDecision, blockingCriteria: criteria.filter(c => c.status === "Blocked").length, reviewerNotes: criteria.filter(c => c.reviewerNote).length, evidenceLinks: criteria.filter(c => c.evidenceUri).length, evaluatedAt: gate.evaluatedAt || gate.createdAt }; } function legacyDashboardPayload() { const dashboard = getDashboard("project-demo"); const p = getProject("project-demo"); const scoredRisks = dashboard.scoredRisks.map(legacyRisk); const legacyDashboard = { ...dashboard, project: { ...dashboard.project, id: p.id, name: p.name, subtitle: p.subtitle, projectType: p.projectType, lifecyclePhase: p.currentLifecyclePhase, assessmentDate: p.assessmentDate, owner: p.ownerDisplayName, riskAppetite: p.riskAppetite, description: p.description }, lifecycle: dashboard.lifecycle.map(phase => ({ ...phase, readiness: phase.readinessScore || phase.readiness || 0, status: phase.status || phase.riskLevel })), gate: { ...dashboard.gate, criteria: dashboard.gate.criteria.map((item, index) => legacyCriterion(item, index)) }, scoredRisks, topRisks: scoredRisks.slice().filter(r => r.status !== "Closed").sort((a, b) => b.residualScore - a.residualScore).slice(0, 8), mitigations: dashboard.mitigations.map(legacyMitigation), indicators: (dashboard.indicators || []).map(i => ({ ...i, interpretation: i.interpretationRule || i.interpretation })), experiments: (dashboard.experiments || []).map(e => ({ ...e, model: e.modelName, accuracy: (e.metrics.find(m => m.metricName === "accuracy") || {}).metricValue, f1: (e.metrics.find(m => m.metricName === "f1") || {}).metricValue, precision: (e.metrics.find(m => m.metricName === "precision") || {}).metricValue, recall: (e.metrics.find(m => m.metricName === "recall") || {}).metricValue, auc: (e.metrics.find(m => m.metricName === "auc") || {}).metricValue, stability: (e.metrics.find(m => m.metricName === "stability") || {}).metricValue, reproducibility: "Reviewed", biasStatus: "Pending" })) }; return { data: { project: legacyDashboard.project }, dashboard: legacyDashboard }; } function legacyAccessPayload() { const permissions = Array.from(new Set(Object.values(ROLE_PERMISSIONS).flat())); return { actor: { ...publicUser(state.users[0]), roleName: "Owner", active: true }, users: state.users.map(u => ({ ...publicUser(u), roleName: u.role.replace(/_/g, " ").replace(/\b\w/g, c => c.toUpperCase()), active: true })), roles: Object.entries(ROLE_PERMISSIONS).map(([code, perms]) => ({ id: code, name: code.replace(/_/g, " ").replace(/\b\w/g, c => c.toUpperCase()), permissions: perms })), permissions }; } function legacyIntegrations(workspaceId = "workspace-demo") { return state.integrations.filter(i => i.workspaceId === workspaceId).map(i => ({ ...i, provider: providerLabel(i.provider), connectionStatus: i.connectionStatus === "CONNECTED" ? "Connected" : "Needs configuration", capabilities: { workItemName: "Work item", riskFieldName: "COSMIC risk score", mitigationObjectName: "Mitigation action" } })); } function sendFile(res, filePath, type) { fs.readFile(filePath, (error, content) => { if (error) return sendText(res, 404, "Not found"); sendText(res, 200, content, type); }); } function staticType(pathname) { if (pathname.endsWith(".css")) return "text/css; charset=utf-8"; if (pathname.endsWith(".js")) return "application/javascript; charset=utf-8"; if (pathname.endsWith(".json")) return "application/json; charset=utf-8"; if (pathname.endsWith(".html")) return "text/html; charset=utf-8"; return "application/octet-stream"; } function appHtml() { return `COSMIC AI-Risk SaaS Local
COSMIC AI-Risk SaaS Local
Loading tenant
`; } async function handleApi(req, res, pathname) { const method = req.method; const parts = pathname.split("/").filter(Boolean); const url = new URL(req.url, `http://${req.headers.host || "localhost"}`); if (method === "GET" && pathname === "/api/health") return sendJson(res, 200, { service: "COSMIC AI-Risk SaaS Local", version: "0.2.0", status: "ok" }); if (method === "GET" && pathname === "/api/ready") return sendJson(res, 200, { ok: true, mode: "dependency-free-local", database: "prototype-seed-memory", postgresContainer: "saas-app-postgres-1" }); if (method === "GET" && pathname === "/api/dashboard") return sendJson(res, 200, legacyDashboardPayload()); if (method === "GET" && pathname === "/api/access/me") return sendJson(res, 200, legacyAccessPayload()); if (method === "GET" && parts[0] === "api" && parts[1] === "projects" && parts[3] === "integrations") return sendJson(res, 200, { integrations: legacyIntegrations() }); if (method === "GET" && parts[0] === "api" && parts[1] === "projects" && parts[3] === "integration-mappings") return sendJson(res, 200, { mappings: state.mappings }); if (method === "GET" && parts[0] === "api" && parts[1] === "projects" && parts[3] === "sync-runs") return sendJson(res, 200, { syncRuns: state.syncRuns }); if (method === "GET" && parts[0] === "api" && parts[1] === "projects" && parts[3] === "gate" && parts[4] === "history") return sendJson(res, 200, { gates: state.gates.filter(g => g.projectId === "project-demo").map(legacyGate) }); if (method === "GET" && parts[0] === "api" && parts[1] === "projects" && parts[3] === "audit") return sendJson(res, 200, { auditEvents: state.auditEvents.filter(a => !parts[2] || a.projectId === "project-demo" || a.projectId === parts[2]) }); if (method === "PATCH" && parts[0] === "api" && parts[1] === "gate-criteria") { const b = await parseBody(req); for (const gate of state.gates) { const criterion = (gate.criteria || []).find((item, index) => (item.id || `${gate.id}-criterion-${index + 1}`) === parts[2]); if (criterion) { Object.assign(criterion, b); audit("gate.criterion.update", "GateCriterion", parts[2], gate.projectId, criterion); return sendJson(res, 200, { criterion: legacyCriterion(criterion, 0, gate.id) }); } } return sendJson(res, 404, { error: "Gate criterion not found" }); } if (method === "GET" && parts[0] === "api" && parts[1] === "oauth") return sendJson(res, 200, { authorizeUrl: "/api/health", provider: parts[2], mode: "local-demo" }); if (method === "POST" && parts[0] === "api" && parts[1] === "integrations" && parts[3] === "live" && parts[4] === "test") return sendJson(res, 200, { dryRun: true, message: "Live connector test is disabled in local demo mode." }); if (method === "POST" && parts[0] === "api" && parts[1] === "integrations" && parts[3] === "live" && parts[4] === "sync") return sendJson(res, 200, { dryRun: true, message: "Live connector sync is disabled in local demo mode." }); if (method === "GET" && parts[0] === "api" && parts[1] === "projects" && parts[3] === "reports") { const payload = legacyDashboardPayload(); const type = parts[4] || "full.json"; if (type === "executive.html") return sendText(res, 200, `

${payload.dashboard.project.name}

Overall score: ${payload.dashboard.summary.overallScore}

Gate: ${payload.dashboard.summary.gateStatus}

Open risks: ${payload.dashboard.summary.openRisks}

`, "text/html; charset=utf-8"); if (type === "risk-register.csv") return sendText(res, 200, csv(payload.dashboard.scoredRisks, ["id","title","dimension","status","normalizedScore","residualScore"]), "text/csv; charset=utf-8"); if (type === "mitigations.csv") return sendText(res, 200, csv(payload.dashboard.mitigations, ["id","title","riskId","status","progress_percent","effectiveness_percent"]), "text/csv; charset=utf-8"); if (type === "gate") return sendJson(res, 200, { report: { gate: payload.dashboard.gate, gates: state.gates.map(legacyGate) } }); if (type === "audit") return sendJson(res, 200, { report: { auditEvents: state.auditEvents } }); return sendJson(res, 200, { reportType: type, data: payload.data, dashboard: payload.dashboard, report: payload }); } if (method === "GET" && pathname === "/api/local/state") return sendJson(res, 200, fullState()); if (method === "GET" && pathname === "/api/auth/me") return sendJson(res, 200, { actor: { ...publicUser(state.users[0]), memberships: [{ organizationId: "org-demo", organizationName: state.organizations[0].name, role: "owner", permissions: ROLE_PERMISSIONS.owner, status: "ACTIVE" }] } }); if (method === "POST" && pathname === "/api/auth/invite") { const b = await parseBody(req); const inv = { id: makeId("invite"), organizationId: b.organizationId || "org-demo", email: b.email, roleCode: b.roleCode || "viewer", token: makeId("token"), expiresAt: new Date(Date.now()+7*864e5).toISOString(), acceptedAt: null }; state.invitations.unshift(inv); audit("invite.create", "Invitation", inv.id, null, inv); return sendJson(res, 201, { invitation: inv }); } if (method === "POST" && pathname === "/api/auth/accept-invite") { const b = await parseBody(req); const inv = state.invitations.find(i => i.token === b.token); if (!inv) return sendJson(res, 400, { error: "Invitation is invalid or expired." }); const u = { id: makeId("user"), organizationId: inv.organizationId, email: inv.email, displayName: b.displayName || inv.email, role: inv.roleCode, permissions: ROLE_PERMISSIONS[inv.roleCode] || ROLE_PERMISSIONS.viewer, status: "ACTIVE" }; inv.acceptedAt = now(); state.users.push(u); audit("invite.accept", "User", u.id, null, publicUser(u)); return sendJson(res, 200, { user: publicUser(u), membership: { organizationId: inv.organizationId, status: "ACTIVE", role: inv.roleCode } }); } if (method === "GET" && pathname === "/api/organizations") return sendJson(res, 200, { organizations: state.organizations }); if (method === "POST" && pathname === "/api/organizations") { const b = await parseBody(req); const org = { id: makeId("org"), name: b.name, slug: b.slug || slug(b.name), status: "TRIAL", planCode: b.planCode || "pilot", manualBilling: true, allowedDomains: [], dataRetentionDays: 365 }; state.organizations.push(org); audit("organization.create", "Organization", org.id, null, org); return sendJson(res, 201, { organization: org }); } if (method === "GET" && pathname === "/api/workspaces") return sendJson(res, 200, { workspaces: state.workspaces.filter(w => !url.searchParams.get("organizationId") || w.organizationId === url.searchParams.get("organizationId")) }); if (method === "POST" && pathname === "/api/workspaces") { const b = await parseBody(req); const ws = { id: makeId("workspace"), organizationId: b.organizationId || "org-demo", name: b.name, slug: b.slug || slug(b.name), type: b.type || "B2B_TEAM", status: "TRIAL" }; state.workspaces.push(ws); audit("workspace.create", "Workspace", ws.id, null, ws); return sendJson(res, 201, { workspace: ws }); } if (method === "PATCH" && parts[0] === "api" && parts[1] === "workspaces" && parts.length === 3) { const ws = state.workspaces.find(w => w.id === parts[2]); if (!ws) return sendJson(res, 404, { error: "Workspace not found" }); Object.assign(ws, await parseBody(req)); audit("workspace.update", "Workspace", ws.id, null, ws); return sendJson(res, 200, { workspace: ws }); } if (method === "GET" && pathname === "/api/users") return sendJson(res, 200, { users: state.users.map(publicUser) }); if (method === "GET" && pathname === "/api/roles") return sendJson(res, 200, { roles: Object.entries(ROLE_PERMISSIONS).map(([code, permissions]) => ({ code, permissions })) }); if (method === "GET" && parts[0] === "api" && parts[1] === "workspaces" && parts[3] === "projects") return sendJson(res, 200, { projects: state.projects.filter(p => p.workspaceId === parts[2]) }); if (method === "POST" && parts[0] === "api" && parts[1] === "workspaces" && parts[3] === "projects") { const b = await parseBody(req); const p = { id: makeId("project"), workspaceId: parts[2], name: b.name, subtitle: b.subtitle || "COSMIC AI risk workspace", projectType: b.projectType || "AI-Enabler", currentLifecyclePhase: b.currentLifecyclePhase || "Needs identification", riskAppetite: Number(b.riskAppetite || 50), assessmentDate: now().slice(0,10), status: "Active", ownerDisplayName: "COSMIC Platform Owner", description: b.description || "", thresholds: b.thresholds || {}, reviews: b.reviews || {}, lifecyclePhases: [], risks: [], indicators: [], experiments: [] }; state.projects.push(p); audit("project.create", "Project", p.id, p.id, p); return sendJson(res, 201, { project: p }); } if (method === "GET" && parts[0] === "api" && parts[1] === "projects" && parts[3] === "dashboard") { const d = getDashboard(parts[2]); return d ? sendJson(res, 200, { dashboard: d }) : sendJson(res, 404, { error: "Project not found" }); } if (method === "GET" && parts[0] === "api" && parts[1] === "projects" && parts[3] === "risks") { const d = getDashboard(parts[2]); return d ? sendJson(res, 200, { risks: d.scoredRisks }) : sendJson(res, 404, { error: "Project not found" }); } if (method === "POST" && parts[0] === "api" && parts[1] === "projects" && parts[3] === "risks") { const b = await parseBody(req); const p = getProject(parts[2]); if (!p) return sendJson(res, 404, { error: "Project not found" }); const r = { id: makeId("risk"), projectId: p.id, ownerDisplayName: b.ownerDisplayName || "COSMIC Platform Owner", title: b.title, description: b.description || "", dimension: b.dimension || "Technical", domain: b.domain || "Technical risks", lifecyclePhase: b.lifecyclePhase || p.currentLifecyclePhase || "Needs identification", probability: Number(b.probability || 3), impact: Number(b.impact || 3), detectability: Number(b.detectability || 3), status: riskStatus(b.status), approvalStatus: approvalStatus(b.approvalStatus), dueDate: b.dueDate || null, evidenceSummary: b.evidenceSummary || "", mitigations: [], evidence: [] }; p.risks.push(r); audit("risk.create", "Risk", r.id, p.id, r); return sendJson(res, 201, { risk: scoreRisk(r) }); } if ((method === "PATCH" || method === "DELETE") && parts[0] === "api" && parts[1] === "risks" && parts.length === 3) { const found = getRisk(parts[2]); if (!found.risk) return sendJson(res, 404, { error: "Risk not found" }); if (method === "DELETE") { found.project.risks = found.project.risks.filter(r => r.id !== parts[2]); audit("risk.delete", "Risk", parts[2], found.project.id); return sendJson(res, 200, { deleted: true }); } const b = await parseBody(req); Object.assign(found.risk, b, { status: b.status ? riskStatus(b.status) : found.risk.status, approvalStatus: b.approvalStatus ? approvalStatus(b.approvalStatus) : found.risk.approvalStatus }); audit("risk.update", "Risk", found.risk.id, found.project.id, found.risk); return sendJson(res, 200, { risk: scoreRisk(found.risk) }); } if (method === "GET" && parts[0] === "api" && parts[1] === "projects" && parts[3] === "mitigations") return sendJson(res, 200, { mitigations: getAllMitigations(parts[2]) }); if (method === "POST" && parts[0] === "api" && parts[1] === "risks" && parts[3] === "mitigations") { const b = await parseBody(req); const found = getRisk(parts[2]); if (!found.risk) return sendJson(res, 404, { error: "Risk not found" }); const m = { id: makeId("mit"), riskId: found.risk.id, ownerDisplayName: b.ownerDisplayName || "COSMIC Platform Owner", title: b.title, description: b.description || "", status: mitigationStatus(b.status), progressPercent: Number(b.progressPercent || b.progress_percent || 0), effectivenessPercent: Number(b.effectivenessPercent || b.effectiveness_percent || 0), dueDate: b.dueDate || null, sequence: found.risk.mitigations.length + 1, evidence: [] }; found.risk.mitigations.push(m); if (b.evidenceTitle || b.evidenceUri) m.evidence.push({ id: makeId("evd"), title: b.evidenceTitle || b.evidenceUri, uri: b.evidenceUri || null, type: b.evidenceType || "Review" }); audit("mitigation.create", "Mitigation", m.id, found.project.id, m); return sendJson(res, 201, { mitigation: m }); } if ((method === "PATCH" || method === "DELETE") && parts[0] === "api" && parts[1] === "mitigations" && parts.length === 3) { const found = getMitigation(parts[2]); if (!found.mitigation) return sendJson(res, 404, { error: "Mitigation not found" }); if (method === "DELETE") { found.risk.mitigations = found.risk.mitigations.filter(m => m.id !== parts[2]); audit("mitigation.delete", "Mitigation", parts[2], found.project.id); return sendJson(res, 200, { deleted: true }); } const b = await parseBody(req); Object.assign(found.mitigation, b, { status: b.status ? mitigationStatus(b.status) : found.mitigation.status }); audit("mitigation.update", "Mitigation", found.mitigation.id, found.project.id, found.mitigation); return sendJson(res, 200, { mitigation: found.mitigation }); } if (method === "POST" && parts[0] === "api" && parts[1] === "mitigations" && parts[3] === "evidence") { const b = await parseBody(req); const found = getMitigation(parts[2]); if (!found.mitigation) return sendJson(res, 404, { error: "Mitigation not found" }); const ev = { id: makeId("evd"), title: b.title || b.evidenceTitle || b.uri, uri: b.uri || b.evidenceUri || null, type: b.type || "Review" }; found.mitigation.evidence.push(ev); audit("evidence.create", "Evidence", ev.id, found.project.id, ev); return sendJson(res, 201, { evidence: ev }); } if (method === "GET" && parts[0] === "api" && parts[1] === "projects" && parts[3] === "gate" && parts[4] === "history") return sendJson(res, 200, { gates: state.gates.filter(g => g.projectId === parts[2]) }); if (method === "POST" && parts[0] === "api" && parts[1] === "projects" && parts[3] === "gate" && parts[4] === "evaluate") { const d = getDashboard(parts[2]); if (!d) return sendJson(res, 404, { error: "Project not found" }); const g = { id: makeId("gate"), projectId: parts[2], status: d.gate.status, summary: d.gate.message, criteria: d.gate.criteria, decisions: [], evaluatedAt: now() }; state.gates.unshift(g); audit("gate.evaluate", "Gate", g.id, parts[2], g); return sendJson(res, 201, { gate: legacyGate(g), persistedGate: legacyGate(g) }); } if (method === "POST" && parts[0] === "api" && parts[1] === "gates" && parts[3] === "decisions") { const b = await parseBody(req); const g = state.gates.find(x => x.id === parts[2]); if (!g) return sendJson(res, 404, { error: "Gate not found" }); const d = { id: makeId("decision"), gateId: g.id, decision: b.decision || "NEEDS_CHANGES", reviewerName: b.reviewerName || "Governance Reviewer", reason: b.reason || "", decidedAt: now() }; g.decisions.push(d); audit("gate.decision", "GateDecision", d.id, g.projectId, d); return sendJson(res, 201, { decision: d }); } if (method === "GET" && parts[0] === "api" && parts[1] === "projects" && parts[3] === "audit") return sendJson(res, 200, { auditEvents: state.auditEvents.filter(a => a.projectId === parts[2]) }); if (method === "GET" && parts[0] === "api" && parts[1] === "projects" && parts[3] === "reports") { const d = getDashboard(parts[2]); if (!d) return sendJson(res, 404, { error: "Project not found" }); const type = parts[4] || "full"; state.reportExports.unshift({ id: makeId("report"), projectId: parts[2], reportType: type, createdAt: now() }); if (type === "executive.html") return sendText(res, 200, `

${d.project.name}

Overall score: ${d.summary.overallScore}

Gate: ${d.summary.gateStatus}

Open risks: ${d.summary.openRisks}

`, "text/html; charset=utf-8"); if (type === "risk-register.csv") return sendText(res, 200, csv(d.scoredRisks, ["id","title","dimension","status","normalizedScore","residualScore"]), "text/csv; charset=utf-8"); return sendJson(res, 200, { reportType: type, dashboard: d, auditEvents: state.auditEvents.filter(a => a.projectId === parts[2]) }); } if (method === "GET" && pathname === "/api/integration-providers") return sendJson(res, 200, { providers: listSupportedProviders() }); if (method === "GET" && parts[0] === "api" && parts[1] === "workspaces" && parts[3] === "integrations") return sendJson(res, 200, { integrations: state.integrations.filter(i => i.workspaceId === parts[2]) }); if (method === "POST" && parts[0] === "api" && parts[1] === "integrations" && parts[3] === "sync") { const i = state.integrations.find(x => x.id === parts[2]); if (!i) return sendJson(res, 404, { error: "Integration not found" }); const p = state.projects.find(x => x.workspaceId === i.workspaceId); const d = getDashboard(p.id); let created = 0; d.scoredRisks.forEach(r => { if (!state.mappings.find(m => m.integrationId === i.id && m.localEntityId === r.id)) { created += 1; state.mappings.push({ id: makeId("map"), integrationId: i.id, projectId: p.id, provider: i.provider, localEntityType: "Risk", localEntityId: r.id, localTitle: r.title, externalItemType: "Work item", externalItemId: `${i.provider}-${r.id}`, externalStatus: riskStatusToExternalStatus(i.provider, r), syncStatus: "Synced", lastSyncedAt: now() }); } }); const run = { id: makeId("sync"), integrationId: i.id, projectId: p.id, provider: i.provider, status: "Completed", createdCount: created, updatedCount: d.scoredRisks.length - created, failedCount: 0, summary: `${i.provider} simulated sync completed.`, startedAt: now(), finishedAt: now() }; i.connectionStatus = "CONNECTED"; i.lastSyncAt = now(); state.syncRuns.unshift(run); audit("integration.sync", "IntegrationSyncRun", run.id, p.id, run); return sendJson(res, 200, { integration: i, syncRun: run, mappings: state.mappings.filter(m => m.integrationId === i.id) }); } if (method === "GET" && parts[0] === "api" && parts[1] === "workspaces" && parts[3] === "integration-mappings") return sendJson(res, 200, { mappings: state.mappings.filter(m => state.integrations.find(i => i.id === m.integrationId && i.workspaceId === parts[2])) }); if (method === "GET" && parts[0] === "api" && parts[1] === "workspaces" && parts[3] === "sync-runs") return sendJson(res, 200, { syncRuns: state.syncRuns.filter(s => state.projects.find(p => p.id === s.projectId && p.workspaceId === parts[2])) }); if (method === "GET" && pathname === "/api/billing/subscription") return sendJson(res, 200, { subscription: state.subscriptions[0], entitlements: { active: ["TRIALING","ACTIVE"].includes(state.subscriptions[0].status), limits: state.subscriptions[0].limits } }); if (method === "PATCH" && pathname === "/api/billing/subscription") { Object.assign(state.subscriptions[0], await parseBody(req)); audit("billing.update", "Subscription", state.subscriptions[0].id, null, state.subscriptions[0]); return sendJson(res, 200, { subscription: state.subscriptions[0] }); } if (pathname === "/api/billing/checkout" || pathname === "/api/billing/portal" || pathname === "/api/billing/webhook") return sendJson(res, 200, { mode: "manual", message: "Stripe boundary placeholder active in local mode." }); return sendJson(res, 404, { error: "API route not found", pathname }); } const server = http.createServer((req, res) => { const pathname = new URL(req.url, `http://${req.headers.host || "localhost"}`).pathname; const publicDir = path.join(__dirname, "..", "public"); if (req.method === "OPTIONS") return sendJson(res, 204, {}); if (pathname === "/" || pathname === "/dashboard") return sendFile(res, path.join(publicDir, "index.html"), "text/html; charset=utf-8"); if (pathname === "/saas-local") return sendText(res, 200, appHtml(), "text/html; charset=utf-8"); if (["/styles.css","/app.js","/risk-engine.js","/oauth-trello-token.html"].includes(pathname)) return sendFile(res, path.join(publicDir, pathname.slice(1)), staticType(pathname)); if (pathname.startsWith("/data/")) return sendFile(res, path.join(__dirname, "..", pathname), staticType(pathname)); if (pathname.startsWith("/api/")) return handleApi(req, res, pathname).catch(e => sendJson(res, e.status || 500, { error: e.message })); return sendText(res, 404, "Not found"); }); if (require.main === module) server.listen(PORT, () => console.log(`COSMIC AI-Risk SaaS local platform running at http://localhost:${PORT}`)); module.exports = { server, state };