@geminixiang/mikan 1.0.0-beta.20 → 1.0.0-beta.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +34 -0
- package/README.md +18 -11
- package/dist/adapters/buffered-responder.d.ts +60 -0
- package/dist/adapters/buffered-responder.d.ts.map +1 -0
- package/dist/adapters/buffered-responder.js +201 -0
- package/dist/adapters/buffered-responder.js.map +1 -0
- package/dist/adapters/discord/context.d.ts.map +1 -1
- package/dist/adapters/discord/context.js +42 -177
- package/dist/adapters/discord/context.js.map +1 -1
- package/dist/adapters/github/bot.d.ts +14 -76
- package/dist/adapters/github/bot.d.ts.map +1 -1
- package/dist/adapters/github/bot.js +52 -443
- package/dist/adapters/github/bot.js.map +1 -1
- package/dist/adapters/github/client.d.ts +4 -0
- package/dist/adapters/github/client.d.ts.map +1 -1
- package/dist/adapters/github/client.js +5 -0
- package/dist/adapters/github/client.js.map +1 -1
- package/dist/adapters/github/context.d.ts.map +1 -1
- package/dist/adapters/github/context.js +32 -104
- package/dist/adapters/github/context.js.map +1 -1
- package/dist/adapters/github/github-ops.d.ts +90 -0
- package/dist/adapters/github/github-ops.d.ts.map +1 -0
- package/dist/adapters/github/github-ops.js +405 -0
- package/dist/adapters/github/github-ops.js.map +1 -0
- package/dist/adapters/github/repo.d.ts +2 -0
- package/dist/adapters/github/repo.d.ts.map +1 -1
- package/dist/adapters/github/repo.js +5 -0
- package/dist/adapters/github/repo.js.map +1 -1
- package/dist/adapters/github/tools/checks.d.ts.map +1 -1
- package/dist/adapters/github/tools/checks.js +6 -17
- package/dist/adapters/github/tools/checks.js.map +1 -1
- package/dist/adapters/github/tools/issue.d.ts.map +1 -1
- package/dist/adapters/github/tools/issue.js +6 -17
- package/dist/adapters/github/tools/issue.js.map +1 -1
- package/dist/adapters/github/tools/pr.d.ts.map +1 -1
- package/dist/adapters/github/tools/pr.js +6 -17
- package/dist/adapters/github/tools/pr.js.map +1 -1
- package/dist/adapters/github/tools/read.d.ts.map +1 -1
- package/dist/adapters/github/tools/read.js +6 -17
- package/dist/adapters/github/tools/read.js.map +1 -1
- package/dist/adapters/github/tools/review-reply.d.ts.map +1 -1
- package/dist/adapters/github/tools/review-reply.js +6 -17
- package/dist/adapters/github/tools/review-reply.js.map +1 -1
- package/dist/adapters/github/tools/sync.d.ts.map +1 -1
- package/dist/adapters/github/tools/sync.js +6 -17
- package/dist/adapters/github/tools/sync.js.map +1 -1
- package/dist/adapters/slack/bot.js +1 -1
- package/dist/adapters/slack/bot.js.map +1 -1
- package/dist/adapters/telegram/context.d.ts.map +1 -1
- package/dist/adapters/telegram/context.js +33 -151
- package/dist/adapters/telegram/context.js.map +1 -1
- package/dist/agent.d.ts +0 -1
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +28 -32
- package/dist/agent.js.map +1 -1
- package/dist/cli/arg-grammar.d.ts +25 -0
- package/dist/cli/arg-grammar.d.ts.map +1 -0
- package/dist/cli/arg-grammar.js +59 -0
- package/dist/cli/arg-grammar.js.map +1 -0
- package/dist/cli/boot.d.ts +16 -0
- package/dist/cli/boot.d.ts.map +1 -0
- package/dist/cli/boot.js +119 -0
- package/dist/cli/boot.js.map +1 -0
- package/dist/cli/ext.js +9 -11
- package/dist/cli/ext.js.map +1 -1
- package/dist/commands/extensions.js +2 -2
- package/dist/commands/extensions.js.map +1 -1
- package/dist/commands/login.d.ts.map +1 -1
- package/dist/commands/login.js +5 -2
- package/dist/commands/login.js.map +1 -1
- package/dist/commands/model.d.ts.map +1 -1
- package/dist/commands/model.js +8 -8
- package/dist/commands/model.js.map +1 -1
- package/dist/commands/sandbox.d.ts.map +1 -1
- package/dist/commands/sandbox.js +7 -5
- package/dist/commands/sandbox.js.map +1 -1
- package/dist/config.d.ts +0 -2
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +8 -41
- package/dist/config.js.map +1 -1
- package/dist/env-manifest.d.ts +35 -0
- package/dist/env-manifest.d.ts.map +1 -0
- package/dist/env-manifest.js +225 -0
- package/dist/env-manifest.js.map +1 -0
- package/dist/events.d.ts +0 -10
- package/dist/events.d.ts.map +1 -1
- package/dist/events.js +9 -82
- package/dist/events.js.map +1 -1
- package/dist/execution-resolver.d.ts +1 -0
- package/dist/execution-resolver.d.ts.map +1 -1
- package/dist/execution-resolver.js +33 -36
- package/dist/execution-resolver.js.map +1 -1
- package/dist/harness/event-format.d.ts +66 -0
- package/dist/harness/event-format.d.ts.map +1 -0
- package/dist/harness/event-format.js +112 -0
- package/dist/harness/event-format.js.map +1 -0
- package/dist/harness/extensions/loader.d.ts +9 -6
- package/dist/harness/extensions/loader.d.ts.map +1 -1
- package/dist/harness/extensions/loader.js +35 -50
- package/dist/harness/extensions/loader.js.map +1 -1
- package/dist/harness/extensions/types.d.ts +10 -14
- package/dist/harness/extensions/types.d.ts.map +1 -1
- package/dist/harness/extensions/types.js.map +1 -1
- package/dist/harness/index.d.ts +1 -0
- package/dist/harness/index.d.ts.map +1 -1
- package/dist/harness/index.js +1 -0
- package/dist/harness/index.js.map +1 -1
- package/dist/harness/runner.d.ts +16 -0
- package/dist/harness/runner.d.ts.map +1 -1
- package/dist/harness/runner.js +27 -1
- package/dist/harness/runner.js.map +1 -1
- package/dist/harness/subagent-runner.d.ts +18 -1
- package/dist/harness/subagent-runner.d.ts.map +1 -1
- package/dist/harness/subagent-runner.js +62 -30
- package/dist/harness/subagent-runner.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/main.js +69 -121
- package/dist/main.js.map +1 -1
- package/dist/observability/instrument.js +6 -4
- package/dist/observability/instrument.js.map +1 -1
- package/dist/observability/sentry.d.ts.map +1 -1
- package/dist/observability/sentry.js +3 -2
- package/dist/observability/sentry.js.map +1 -1
- package/dist/runtime/conversation-runtime.js +13 -3
- package/dist/runtime/conversation-runtime.js.map +1 -1
- package/dist/runtime/types.d.ts +4 -0
- package/dist/runtime/types.d.ts.map +1 -1
- package/dist/runtime/types.js.map +1 -1
- package/dist/sandbox/cloudflare.d.ts +1 -0
- package/dist/sandbox/cloudflare.d.ts.map +1 -1
- package/dist/sandbox/cloudflare.js +4 -1
- package/dist/sandbox/cloudflare.js.map +1 -1
- package/dist/sandbox/container.d.ts +1 -0
- package/dist/sandbox/container.d.ts.map +1 -1
- package/dist/sandbox/container.js +4 -1
- package/dist/sandbox/container.js.map +1 -1
- package/dist/sandbox/firecracker.d.ts +1 -0
- package/dist/sandbox/firecracker.d.ts.map +1 -1
- package/dist/sandbox/firecracker.js +4 -1
- package/dist/sandbox/firecracker.js.map +1 -1
- package/dist/sandbox/gondolin-bootstrap.d.ts +26 -0
- package/dist/sandbox/gondolin-bootstrap.d.ts.map +1 -0
- package/dist/sandbox/gondolin-bootstrap.js +27 -0
- package/dist/sandbox/gondolin-bootstrap.js.map +1 -0
- package/dist/sandbox/gondolin-contract.d.ts +125 -0
- package/dist/sandbox/gondolin-contract.d.ts.map +1 -0
- package/dist/sandbox/gondolin-contract.js +155 -0
- package/dist/sandbox/gondolin-contract.js.map +1 -0
- package/dist/sandbox/gondolin-fleet.d.ts +1 -1
- package/dist/sandbox/gondolin-fleet.d.ts.map +1 -1
- package/dist/sandbox/gondolin-fleet.js +1 -1
- package/dist/sandbox/gondolin-fleet.js.map +1 -1
- package/dist/sandbox/gondolin-gateway.d.ts +1 -0
- package/dist/sandbox/gondolin-gateway.d.ts.map +1 -1
- package/dist/sandbox/gondolin-gateway.js +13 -6
- package/dist/sandbox/gondolin-gateway.js.map +1 -1
- package/dist/sandbox/gondolin-inventory.d.ts +2 -16
- package/dist/sandbox/gondolin-inventory.d.ts.map +1 -1
- package/dist/sandbox/gondolin-inventory.js +2 -12
- package/dist/sandbox/gondolin-inventory.js.map +1 -1
- package/dist/sandbox/gondolin-placement.d.ts +0 -2
- package/dist/sandbox/gondolin-placement.d.ts.map +1 -1
- package/dist/sandbox/gondolin-placement.js +0 -6
- package/dist/sandbox/gondolin-placement.js.map +1 -1
- package/dist/sandbox/gondolin-recovery.d.ts +33 -0
- package/dist/sandbox/gondolin-recovery.d.ts.map +1 -0
- package/dist/sandbox/gondolin-recovery.js +39 -0
- package/dist/sandbox/gondolin-recovery.js.map +1 -0
- package/dist/sandbox/gondolin-remote.d.ts +2 -5
- package/dist/sandbox/gondolin-remote.d.ts.map +1 -1
- package/dist/sandbox/gondolin-remote.js +12 -39
- package/dist/sandbox/gondolin-remote.js.map +1 -1
- package/dist/sandbox/gondolin-worker-client.d.ts +8 -12
- package/dist/sandbox/gondolin-worker-client.d.ts.map +1 -1
- package/dist/sandbox/gondolin-worker-client.js +13 -15
- package/dist/sandbox/gondolin-worker-client.js.map +1 -1
- package/dist/sandbox/gondolin-worker.d.ts +2 -40
- package/dist/sandbox/gondolin-worker.d.ts.map +1 -1
- package/dist/sandbox/gondolin-worker.js.map +1 -1
- package/dist/sandbox/gondolin.d.ts +1 -0
- package/dist/sandbox/gondolin.d.ts.map +1 -1
- package/dist/sandbox/gondolin.js +8 -4
- package/dist/sandbox/gondolin.js.map +1 -1
- package/dist/sandbox/host.d.ts +1 -0
- package/dist/sandbox/host.d.ts.map +1 -1
- package/dist/sandbox/host.js +3 -0
- package/dist/sandbox/host.js.map +1 -1
- package/dist/sandbox/index.d.ts +9 -1
- package/dist/sandbox/index.d.ts.map +1 -1
- package/dist/sandbox/index.js +14 -0
- package/dist/sandbox/index.js.map +1 -1
- package/dist/sandbox/types.d.ts +5 -0
- package/dist/sandbox/types.d.ts.map +1 -1
- package/dist/sandbox/types.js.map +1 -1
- package/dist/sandbox/utils.d.ts +1 -0
- package/dist/sandbox/utils.d.ts.map +1 -1
- package/dist/sandbox/utils.js +5 -2
- package/dist/sandbox/utils.js.map +1 -1
- package/dist/sessions/chat-history-sync.d.ts +32 -0
- package/dist/sessions/chat-history-sync.d.ts.map +1 -0
- package/dist/sessions/{agent-memory-file-manager.js → chat-history-sync.js} +24 -83
- package/dist/sessions/chat-history-sync.js.map +1 -0
- package/dist/sessions/conversation-log.d.ts +13 -0
- package/dist/sessions/conversation-log.d.ts.map +1 -0
- package/dist/sessions/conversation-log.js +47 -0
- package/dist/sessions/conversation-log.js.map +1 -0
- package/dist/sessions/rotation.d.ts +2 -0
- package/dist/sessions/rotation.d.ts.map +1 -0
- package/dist/sessions/rotation.js +39 -0
- package/dist/sessions/rotation.js.map +1 -0
- package/dist/sessions/store.d.ts.map +1 -1
- package/dist/sessions/store.js +4 -10
- package/dist/sessions/store.js.map +1 -1
- package/dist/sessions/types.d.ts +2 -2
- package/dist/sessions/types.d.ts.map +1 -1
- package/dist/sessions/types.js.map +1 -1
- package/dist/settings-mutation.d.ts +23 -0
- package/dist/settings-mutation.d.ts.map +1 -0
- package/dist/settings-mutation.js +42 -0
- package/dist/settings-mutation.js.map +1 -0
- package/dist/tools/event.d.ts.map +1 -1
- package/dist/tools/event.js +27 -46
- package/dist/tools/event.js.map +1 -1
- package/dist/tools/host-fn-tool.d.ts +21 -0
- package/dist/tools/host-fn-tool.d.ts.map +1 -0
- package/dist/tools/host-fn-tool.js +32 -0
- package/dist/tools/host-fn-tool.js.map +1 -0
- package/dist/tools/index.d.ts +1 -0
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +1 -0
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/react.d.ts.map +1 -1
- package/dist/tools/react.js +6 -17
- package/dist/tools/react.js.map +1 -1
- package/dist/tools/read.d.ts.map +1 -1
- package/dist/tools/read.js +7 -26
- package/dist/tools/read.js.map +1 -1
- package/dist/tools/sandbox.d.ts.map +1 -1
- package/dist/tools/sandbox.js +5 -2
- package/dist/tools/sandbox.js.map +1 -1
- package/dist/tools/subagent-slots.d.ts +28 -0
- package/dist/tools/subagent-slots.d.ts.map +1 -0
- package/dist/tools/subagent-slots.js +57 -0
- package/dist/tools/subagent-slots.js.map +1 -0
- package/dist/tools/subagent.d.ts +7 -2
- package/dist/tools/subagent.d.ts.map +1 -1
- package/dist/tools/subagent.js +160 -111
- package/dist/tools/subagent.js.map +1 -1
- package/dist/tools/types.d.ts +10 -9
- package/dist/tools/types.d.ts.map +1 -1
- package/dist/tools/types.js.map +1 -1
- package/dist/types.d.ts +5 -24
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/utils/date.d.ts +1 -1
- package/dist/utils/date.js +1 -1
- package/dist/utils/date.js.map +1 -1
- package/dist/vault/disabled.d.ts.map +1 -1
- package/dist/vault/disabled.js +0 -1
- package/dist/vault/disabled.js.map +1 -1
- package/dist/vault/index.d.ts +0 -2
- package/dist/vault/index.d.ts.map +1 -1
- package/dist/vault/index.js +0 -10
- package/dist/vault/index.js.map +1 -1
- package/dist/vault/injection.d.ts +20 -0
- package/dist/vault/injection.d.ts.map +1 -0
- package/dist/vault/injection.js +27 -0
- package/dist/vault/injection.js.map +1 -0
- package/dist/vault/types.d.ts +0 -2
- package/dist/vault/types.d.ts.map +1 -1
- package/dist/vault/types.js.map +1 -1
- package/dist/web/admin/portal.d.ts +3 -3
- package/dist/web/admin/portal.d.ts.map +1 -1
- package/dist/web/admin/portal.js +41 -39
- package/dist/web/admin/portal.js.map +1 -1
- package/dist/web/admin/types.d.ts +3 -0
- package/dist/web/admin/types.d.ts.map +1 -1
- package/dist/web/admin/types.js.map +1 -1
- package/dist/web/agent-events/portal.d.ts.map +1 -1
- package/dist/web/agent-events/portal.js +2 -1
- package/dist/web/agent-events/portal.js.map +1 -1
- package/package.json +1 -1
- package/dist/sessions/agent-memory-file-manager.d.ts +0 -19
- package/dist/sessions/agent-memory-file-manager.d.ts.map +0 -1
- package/dist/sessions/agent-memory-file-manager.js.map +0 -1
- package/dist/vault/routing.d.ts +0 -4
- package/dist/vault/routing.d.ts.map +0 -1
- package/dist/vault/routing.js +0 -6
- package/dist/vault/routing.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gondolin-gateway.js","sourceRoot":"","sources":["../../src/sandbox/gondolin-gateway.ts"],"names":[],"mappings":"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","sourcesContent":["import { randomBytes } from \"node:crypto\";\nimport { readFileSync } from \"node:fs\";\nimport type { Server, Socket } from \"node:net\";\nimport { hostname } from \"node:os\";\nimport { TLSSocket, createServer as createTlsServer } from \"node:tls\";\nimport * as log from \"../log.js\";\nimport type { GondolinGatewaySettings } from \"../types.js\";\nimport { gondolinFleet } from \"./gondolin-fleet.js\";\nimport { gondolinJoin } from \"./gondolin-join.js\";\nimport {\n GondolinRemoteConnection,\n GondolinWorkerUnreachableError,\n createSessionFrameParser,\n encodeSessionMessage,\n} from \"./gondolin-remote.js\";\nimport type { SessionClient, SessionClientCallbacks } from \"./gondolin-worker-client.js\";\n\nconst RPC_TIMEOUT_MS = 150_000;\nconst TUNNEL_TIMEOUT_MS = 15_000;\n\n/** What a worker announces when it dials home (mirrors the Go register frame). */\ninterface GondolinWorkerRegistration {\n name: string;\n os?: string;\n arch?: string;\n accelerator?: string;\n cpus?: number;\n memoryBytes?: number;\n maxRuntimes?: number;\n protocolVersion?: number;\n runtimes?: Array<{ sessionId: string; instanceId: string }>;\n /** Non-empty when the worker's shared workspace failed its usability probe. */\n workspaceError?: string;\n}\n\ninterface ControlFrame extends GondolinWorkerRegistration {\n type: string;\n id?: number;\n status?: number;\n body?: unknown;\n nonce?: string;\n activeRuntimes?: number;\n /** join exchange */\n token?: string;\n csr?: string;\n}\n\ninterface RegisteredWorker {\n info: GondolinWorkerRegistration;\n socket: Socket;\n connectedAt: number;\n lastSeen: number;\n activeRuntimes: number;\n workspaceError?: string;\n pendingRpc: Map<number, { resolve: (frame: ControlFrame) => void; timer: NodeJS.Timeout }>;\n nextRpcId: number;\n}\n\n/**\n * Splits a byte stream into u32be-length-prefixed JSON frames, preserving any\n * bytes after the point where the consumer stops parsing (a tunnel connection\n * switches protocols after its preamble frame).\n */\nfunction createControlFrameReader(onFrame: (frame: ControlFrame, leftover: Buffer) => void): {\n push: (chunk: Buffer) => void;\n stop: () => void;\n} {\n let buffer = Buffer.alloc(0);\n let stopped = false;\n return {\n push(chunk: Buffer) {\n if (stopped) return;\n buffer = Buffer.concat([buffer, chunk]);\n for (;;) {\n // onFrame may call stop() synchronously (a tunnel switching protocols)\n if (stopped || buffer.length < 4) return;\n const length = buffer.readUInt32BE(0);\n if (buffer.length < 4 + length) return;\n const payload = buffer.subarray(4, 4 + length);\n buffer = buffer.subarray(4 + length);\n let frame: ControlFrame;\n try {\n frame = JSON.parse(payload.toString(\"utf8\")) as ControlFrame;\n } catch {\n continue; // skip malformed frames\n }\n onFrame(frame, buffer);\n }\n },\n stop() {\n stopped = true;\n },\n };\n}\n\nfunction encodeControlFrame(frame: object): Buffer {\n return encodeSessionMessage(frame);\n}\n\ninterface GatewayOverrides {\n /** Server factory (tests substitute a plain net.Server). */\n createServer?: (onConnection: (socket: Socket) => void) => Server;\n /** mTLS verification result for a socket (tests substitute outcomes). */\n isAuthorized?: (socket: Socket) => boolean;\n leaseTtlSeconds?: number;\n rpcTimeoutMs?: number;\n tunnelTimeoutMs?: number;\n}\n\nfunction defaultIsAuthorized(socket: Socket): boolean {\n return socket instanceof TLSSocket && socket.authorized;\n}\n\n/**\n * The host side of dial-home workers: one mTLS listener that accepts worker\n * control channels (register/ping/RPC responses) and per-command dial-back\n * tunnels, keeps the registry of connected workers, and attaches each one to\n * the fleet as a regular worker connection. Placement, leases, fencing, and\n * failover are unchanged — this only reverses who dials whom.\n */\nclass GondolinWorkerGateway {\n private settings?: GondolinGatewaySettings;\n private overrides: GatewayOverrides = {};\n private server?: Server;\n private readonly workers = new Map<string, RegisteredWorker>();\n private readonly pendingTunnels = new Map<\n string,\n { resolve: (value: { socket: Socket; leftover: Buffer }) => void; timer: NodeJS.Timeout }\n >();\n\n configure(settings?: GondolinGatewaySettings, overrides?: GatewayOverrides): void {\n this.stop();\n this.settings = settings;\n this.overrides = overrides ?? {};\n }\n\n isConfigured(): boolean {\n return this.settings !== undefined;\n }\n\n /** Registered workers and their liveness (admin/observability surface). */\n list(): Array<{\n name: string;\n connected: boolean;\n activeRuntimes: number;\n workspaceError?: string;\n info: GondolinWorkerRegistration;\n }> {\n return Array.from(this.workers.values()).map((worker) => ({\n name: worker.info.name,\n connected: !worker.socket.destroyed,\n activeRuntimes: worker.activeRuntimes,\n workspaceError: worker.workspaceError,\n info: worker.info,\n }));\n }\n\n /**\n * Start the listener. Without explicit certificate settings the gateway\n * provisions its own: a private worker CA plus a server certificate signed\n * by it (required for join's CA pinning to also authenticate the host).\n */\n async start(): Promise<void> {\n if (!this.settings || this.server) return;\n const settings = this.settings;\n if (!settings.workspaceRoot) {\n // dial-home workers inherit workspaceRoot from here; without it every\n // runtime is rejected with \"escapes the workspace root\"\n throw new Error(\n \"gondolin gateway requires workspaceRoot (the worker-side shared workspace path); \" +\n \"set sandbox.gondolin.remote.gateway.workspaceRoot\",\n );\n }\n let material: { certFile: string; keyFile: string; clientCaFile: string };\n if (settings.certFile && settings.keyFile && settings.clientCaFile) {\n material = {\n certFile: settings.certFile,\n keyFile: settings.keyFile,\n clientCaFile: settings.clientCaFile,\n };\n } else {\n if (!gondolinJoin.isConfigured()) {\n throw new Error(\"gondolin gateway auto-init requires the join service to be configured\");\n }\n const issued = await gondolinJoin.ensureServerCert(settings.hostnames ?? [hostname()]);\n material = { ...issued, clientCaFile: gondolinJoin.paths().caFile };\n }\n const factory =\n this.overrides.createServer ??\n ((onConnection: (socket: Socket) => void) =>\n createTlsServer(\n {\n cert: readFileSync(material.certFile),\n key: readFileSync(material.keyFile),\n ca: readFileSync(material.clientCaFile),\n requestCert: true,\n // unauthenticated connections may only send a join frame; the\n // per-frame authorization gate enforces that below\n rejectUnauthorized: false,\n minVersion: \"TLSv1.3\",\n },\n onConnection,\n ));\n this.server = factory((socket) => this.handleConnection(socket));\n this.server.listen(this.settings.port, () => {\n log.logInfo(`Gondolin worker gateway listening on :${this.settings?.port}`);\n });\n }\n\n stop(): void {\n for (const worker of this.workers.values()) {\n worker.socket.destroy();\n for (const pending of worker.pendingRpc.values()) clearTimeout(pending.timer);\n }\n this.workers.clear();\n for (const pending of this.pendingTunnels.values()) clearTimeout(pending.timer);\n this.pendingTunnels.clear();\n this.server?.close();\n this.server = undefined;\n }\n\n /** Routes one inbound connection by its first frame: control or tunnel. */\n private handleConnection(socket: Socket): void {\n socket.setNoDelay(true);\n let routed = false;\n const authorized = (this.overrides.isAuthorized ?? defaultIsAuthorized)(socket);\n const reader = createControlFrameReader((frame, leftover) => {\n if (!routed) {\n routed = true;\n if (frame.type === \"join\") {\n void this.handleJoin(socket, frame);\n } else if (!authorized) {\n // everything except join requires a CA-signed client certificate\n socket.destroy();\n } else if (frame.type === \"register\" && frame.name) {\n this.acceptControlChannel(socket, frame, reader);\n } else if (frame.type === \"tunnel\" && frame.nonce) {\n reader.stop();\n socket.removeAllListeners(\"data\");\n this.acceptTunnel(socket, frame.nonce, leftover);\n } else {\n socket.destroy();\n }\n return;\n }\n this.handleControlFrame(socket, frame);\n });\n socket.on(\"data\", (chunk: Buffer) => reader.push(chunk));\n socket.on(\"error\", () => socket.destroy());\n }\n\n private acceptControlChannel(\n socket: Socket,\n registration: ControlFrame,\n _reader: { stop: () => void },\n ): void {\n const name = registration.name as string;\n const previous = this.workers.get(name);\n if (previous && !previous.socket.destroyed) {\n log.logInfo(`Gondolin worker '${name}' re-registered; superseding previous connection`);\n previous.socket.destroy();\n }\n const worker: RegisteredWorker = {\n info: registration,\n socket,\n connectedAt: Date.now(),\n lastSeen: Date.now(),\n activeRuntimes: registration.runtimes?.length ?? 0,\n pendingRpc: new Map(),\n nextRpcId: 1,\n };\n this.workers.set(name, worker);\n const surviving = registration.runtimes?.length ?? 0;\n log.logInfo(\n `Gondolin worker joined: ${name} (${registration.os}/${registration.arch}, ` +\n `${registration.accelerator}, ${registration.cpus} cpus, ` +\n `cap ${registration.maxRuntimes ?? \"∞\"}, ${surviving} runtimes surviving)`,\n );\n\n const overrides = this.settings?.workers?.[name];\n gondolinFleet.attachWorker(\n {\n name,\n url: `dialhome://${name}`,\n workspaceRoot: this.settings?.workspaceRoot,\n maxRuntimes: overrides?.maxRuntimes ?? registration.maxRuntimes,\n draining: overrides?.draining,\n },\n (connectionOverrides) =>\n new GondolinRemoteConnection(\n { name, url: `dialhome://${name}`, workspaceRoot: this.settings?.workspaceRoot },\n {\n ...connectionOverrides,\n ...(this.overrides.leaseTtlSeconds !== undefined\n ? { leaseTtlSeconds: this.overrides.leaseTtlSeconds }\n : {}),\n request: (method, path, body, headers) => this.rpc(name, method, path, body, headers),\n tunnel: (path, headers, callbacks) => this.openTunnel(name, path, headers, callbacks),\n },\n ),\n );\n this.applyWorkspaceHealth(worker, registration.workspaceError);\n // a worker that reconnected may carry runtimes whose placements moved\n void gondolinFleet.reconcile();\n\n socket.on(\"close\", () => {\n const current = this.workers.get(name);\n if (current !== worker) return; // superseded\n for (const pending of worker.pendingRpc.values()) clearTimeout(pending.timer);\n worker.pendingRpc.clear();\n log.logWarning(`Gondolin worker disconnected: ${name} (placements fence until lease expiry)`);\n gondolinFleet.detachWorker(name);\n this.workers.delete(name);\n });\n }\n\n private handleControlFrame(socket: Socket, frame: ControlFrame): void {\n const worker = this.workerBySocket(socket);\n if (!worker) return;\n worker.lastSeen = Date.now();\n if (frame.type === \"ping\") {\n if (typeof frame.activeRuntimes === \"number\") {\n worker.activeRuntimes = frame.activeRuntimes;\n }\n // omitted on healthy pings (Go omitempty), so absence means recovered\n this.applyWorkspaceHealth(worker, frame.workspaceError);\n socket.write(encodeControlFrame({ type: \"pong\" }));\n return;\n }\n if (frame.type === \"response\" && typeof frame.id === \"number\") {\n const pending = worker.pendingRpc.get(frame.id);\n if (!pending) return;\n worker.pendingRpc.delete(frame.id);\n clearTimeout(pending.timer);\n pending.resolve(frame);\n }\n }\n\n /**\n * Track shared-workspace health from register/ping frames and push it into\n * the fleet, logging only the transitions. A worker whose NFS mount died\n * keeps its control channel alive — this is what turns that silent state\n * into refused placements and fail-fast execs.\n */\n private applyWorkspaceHealth(worker: RegisteredWorker, error: string | undefined): void {\n const next = error || undefined;\n if (next === worker.workspaceError) {\n gondolinFleet.setWorkspaceHealth(worker.info.name, next); // attach may have reset it\n return;\n }\n if (next) {\n log.logWarning(\n `Gondolin worker '${worker.info.name}' workspace is unusable: ${next} — new placements disabled until it recovers`,\n );\n } else {\n log.logInfo(`Gondolin worker '${worker.info.name}' workspace recovered`);\n }\n worker.workspaceError = next;\n gondolinFleet.setWorkspaceHealth(worker.info.name, next);\n }\n\n /** RPC to a worker over its control channel (the reverse of HTTPS requests). */\n private rpc(\n name: string,\n method: string,\n path: string,\n body?: object,\n headers?: Record<string, string>,\n ): Promise<{ status: number; json: Record<string, unknown> }> {\n const worker = this.workers.get(name);\n if (!worker || worker.socket.destroyed) {\n return Promise.reject(\n new GondolinWorkerUnreachableError(`worker '${name}' is not connected`),\n );\n }\n const id = worker.nextRpcId++;\n return new Promise((resolve, reject) => {\n const timer = setTimeout(() => {\n worker.pendingRpc.delete(id);\n reject(\n new GondolinWorkerUnreachableError(\n `RPC to worker '${name}' timed out (${method} ${path})`,\n ),\n );\n }, this.overrides.rpcTimeoutMs ?? RPC_TIMEOUT_MS);\n timer.unref?.();\n worker.pendingRpc.set(id, {\n timer,\n resolve: (frame) =>\n resolve({\n status: frame.status ?? 0,\n json: (frame.body ?? {}) as Record<string, unknown>,\n }),\n });\n worker.socket.write(encodeControlFrame({ type: \"request\", id, method, path, body, headers }));\n });\n }\n\n /** Ask the worker to dial back a data connection for one session tunnel. */\n private openTunnel(\n name: string,\n path: string,\n headers: Record<string, string>,\n callbacks: SessionClientCallbacks,\n ): Promise<SessionClient> {\n const worker = this.workers.get(name);\n if (!worker || worker.socket.destroyed) {\n const error = new Error(`worker '${name}' is not connected`) as NodeJS.ErrnoException;\n error.code = \"ECONNREFUSED\"; // nothing executed — safe to recreate\n return Promise.reject(error);\n }\n const sessionId = path.split(\"/\")[3];\n const nonce = randomBytes(16).toString(\"hex\");\n return new Promise((resolve, reject) => {\n const timer = setTimeout(() => {\n this.pendingTunnels.delete(nonce);\n const error = new Error(\n `worker '${name}' did not dial back a tunnel`,\n ) as NodeJS.ErrnoException;\n error.code = \"ECONNREFUSED\";\n reject(error);\n }, this.overrides.tunnelTimeoutMs ?? TUNNEL_TIMEOUT_MS);\n timer.unref?.();\n this.pendingTunnels.set(nonce, {\n timer,\n resolve: ({ socket, leftover }) => {\n let closed = false;\n const parse = createSessionFrameParser(callbacks);\n if (leftover.length > 0) parse(leftover);\n socket.on(\"data\", parse);\n socket.on(\"error\", (error: Error) => {\n if (closed) return;\n closed = true;\n callbacks.onClose(error);\n });\n socket.on(\"close\", () => {\n if (closed) return;\n closed = true;\n callbacks.onClose();\n });\n resolve({\n send: (message) => {\n if (!closed) socket.write(encodeSessionMessage(message));\n },\n close: () => {\n if (closed) return;\n closed = true;\n socket.destroy();\n },\n });\n },\n });\n worker.socket.write(encodeControlFrame({ type: \"open-tunnel\", nonce, sessionId, headers }));\n });\n }\n\n /**\n * One-time token → CA-signed client certificate. The only operation an\n * unauthenticated connection may perform; the connection closes after the\n * response either way.\n */\n private async handleJoin(socket: Socket, frame: ControlFrame): Promise<void> {\n const refuse = (message: string): void => {\n log.logWarning(`Gondolin worker join refused: ${message}`);\n socket.end(encodeControlFrame({ type: \"join-error\", message }));\n };\n if (!gondolinJoin.isConfigured()) {\n refuse(\"join is not enabled on this gateway\");\n return;\n }\n if (!frame.token || !frame.csr || !frame.name) {\n refuse(\"join requires token, csr, and name\");\n return;\n }\n if (!gondolinJoin.consumeToken(frame.token)) {\n refuse(`invalid or expired join token (worker '${frame.name}')`);\n return;\n }\n try {\n const signed = await gondolinJoin.signCsr(frame.csr);\n log.logInfo(`Gondolin worker '${frame.name}' joined: client certificate issued`);\n socket.end(encodeControlFrame({ type: \"join-ok\", cert: signed.certPem, ca: signed.caPem }));\n } catch (err) {\n refuse(`certificate issuance failed: ${err instanceof Error ? err.message : String(err)}`);\n }\n }\n\n private acceptTunnel(socket: Socket, nonce: string, leftover: Buffer): void {\n const pending = this.pendingTunnels.get(nonce);\n if (!pending) {\n socket.destroy();\n return;\n }\n this.pendingTunnels.delete(nonce);\n clearTimeout(pending.timer);\n pending.resolve({ socket, leftover: Buffer.from(leftover) });\n }\n\n private workerBySocket(socket: Socket): RegisteredWorker | undefined {\n for (const worker of this.workers.values()) {\n if (worker.socket === socket) return worker;\n }\n return undefined;\n }\n}\n\nexport const gondolinGateway = new GondolinWorkerGateway();\n"]}
|
|
1
|
+
{"version":3,"file":"gondolin-gateway.js","sourceRoot":"","sources":["../../src/sandbox/gondolin-gateway.ts"],"names":[],"mappings":"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","sourcesContent":["import { randomBytes } from \"node:crypto\";\nimport { readFileSync } from \"node:fs\";\nimport type { Server, Socket } from \"node:net\";\nimport { hostname } from \"node:os\";\nimport { TLSSocket, createServer as createTlsServer } from \"node:tls\";\nimport * as log from \"../log.js\";\nimport type { GondolinGatewaySettings } from \"../types.js\";\nimport { gondolinFleet } from \"./gondolin-fleet.js\";\nimport { gondolinJoin } from \"./gondolin-join.js\";\nimport { createSessionFrameParser, encodeSessionMessage } from \"./gondolin-contract.js\";\nimport { GondolinRemoteConnection, GondolinWorkerUnreachableError } from \"./gondolin-remote.js\";\nimport type { SessionClient, SessionClientCallbacks } from \"./gondolin-worker-client.js\";\n\nconst RPC_TIMEOUT_MS = 150_000;\nconst TUNNEL_TIMEOUT_MS = 15_000;\n\n/** What a worker announces when it dials home (mirrors the Go register frame). */\ninterface GondolinWorkerRegistration {\n name: string;\n os?: string;\n arch?: string;\n accelerator?: string;\n cpus?: number;\n memoryBytes?: number;\n maxRuntimes?: number;\n protocolVersion?: number;\n runtimes?: Array<{ sessionId: string; instanceId: string }>;\n /** Non-empty when the worker's shared workspace failed its usability probe. */\n workspaceError?: string;\n}\n\ninterface ControlFrame extends GondolinWorkerRegistration {\n type: string;\n id?: number;\n status?: number;\n body?: unknown;\n nonce?: string;\n activeRuntimes?: number;\n /** join exchange */\n token?: string;\n csr?: string;\n}\n\ninterface RegisteredWorker {\n info: GondolinWorkerRegistration;\n socket: Socket;\n connectedAt: number;\n lastSeen: number;\n activeRuntimes: number;\n workspaceError?: string;\n pendingRpc: Map<\n number,\n {\n resolve: (frame: ControlFrame) => void;\n reject: (error: Error) => void;\n timer: NodeJS.Timeout;\n }\n >;\n nextRpcId: number;\n}\n\n/**\n * Splits a byte stream into u32be-length-prefixed JSON frames, preserving any\n * bytes after the point where the consumer stops parsing (a tunnel connection\n * switches protocols after its preamble frame).\n */\nfunction createControlFrameReader(onFrame: (frame: ControlFrame, leftover: Buffer) => void): {\n push: (chunk: Buffer) => void;\n stop: () => void;\n} {\n let buffer = Buffer.alloc(0);\n let stopped = false;\n return {\n push(chunk: Buffer) {\n if (stopped) return;\n buffer = Buffer.concat([buffer, chunk]);\n for (;;) {\n // onFrame may call stop() synchronously (a tunnel switching protocols)\n if (stopped || buffer.length < 4) return;\n const length = buffer.readUInt32BE(0);\n if (buffer.length < 4 + length) return;\n const payload = buffer.subarray(4, 4 + length);\n buffer = buffer.subarray(4 + length);\n let frame: ControlFrame;\n try {\n frame = JSON.parse(payload.toString(\"utf8\")) as ControlFrame;\n } catch {\n continue; // skip malformed frames\n }\n onFrame(frame, buffer);\n }\n },\n stop() {\n stopped = true;\n },\n };\n}\n\nfunction encodeControlFrame(frame: object): Buffer {\n return encodeSessionMessage(frame);\n}\n\ninterface GatewayOverrides {\n /** Server factory (tests substitute a plain net.Server). */\n createServer?: (onConnection: (socket: Socket) => void) => Server;\n /** mTLS verification result for a socket (tests substitute outcomes). */\n isAuthorized?: (socket: Socket) => boolean;\n leaseTtlSeconds?: number;\n rpcTimeoutMs?: number;\n tunnelTimeoutMs?: number;\n}\n\nfunction defaultIsAuthorized(socket: Socket): boolean {\n return socket instanceof TLSSocket && socket.authorized;\n}\n\n/**\n * The host side of dial-home workers: one mTLS listener that accepts worker\n * control channels (register/ping/RPC responses) and per-command dial-back\n * tunnels, keeps the registry of connected workers, and attaches each one to\n * the fleet as a regular worker connection. Placement, leases, fencing, and\n * failover are unchanged — this only reverses who dials whom.\n */\nclass GondolinWorkerGateway {\n private settings?: GondolinGatewaySettings;\n private overrides: GatewayOverrides = {};\n private server?: Server;\n private readonly workers = new Map<string, RegisteredWorker>();\n private readonly pendingTunnels = new Map<\n string,\n { resolve: (value: { socket: Socket; leftover: Buffer }) => void; timer: NodeJS.Timeout }\n >();\n\n configure(settings?: GondolinGatewaySettings, overrides?: GatewayOverrides): void {\n this.stop();\n this.settings = settings;\n this.overrides = overrides ?? {};\n }\n\n isConfigured(): boolean {\n return this.settings !== undefined;\n }\n\n /** Registered workers and their liveness (admin/observability surface). */\n list(): Array<{\n name: string;\n connected: boolean;\n activeRuntimes: number;\n workspaceError?: string;\n info: GondolinWorkerRegistration;\n }> {\n return Array.from(this.workers.values()).map((worker) => ({\n name: worker.info.name,\n connected: !worker.socket.destroyed,\n activeRuntimes: worker.activeRuntimes,\n workspaceError: worker.workspaceError,\n info: worker.info,\n }));\n }\n\n /**\n * Start the listener. Without explicit certificate settings the gateway\n * provisions its own: a private worker CA plus a server certificate signed\n * by it (required for join's CA pinning to also authenticate the host).\n */\n async start(): Promise<void> {\n if (!this.settings || this.server) return;\n const settings = this.settings;\n if (!settings.workspaceRoot) {\n // dial-home workers inherit workspaceRoot from here; without it every\n // runtime is rejected with \"escapes the workspace root\"\n throw new Error(\n \"gondolin gateway requires workspaceRoot (the worker-side shared workspace path); \" +\n \"set sandbox.gondolin.remote.gateway.workspaceRoot\",\n );\n }\n let material: { certFile: string; keyFile: string; clientCaFile: string };\n if (settings.certFile && settings.keyFile && settings.clientCaFile) {\n material = {\n certFile: settings.certFile,\n keyFile: settings.keyFile,\n clientCaFile: settings.clientCaFile,\n };\n } else {\n if (!gondolinJoin.isConfigured()) {\n throw new Error(\"gondolin gateway auto-init requires the join service to be configured\");\n }\n const issued = await gondolinJoin.ensureServerCert(settings.hostnames ?? [hostname()]);\n material = { ...issued, clientCaFile: gondolinJoin.paths().caFile };\n }\n const factory =\n this.overrides.createServer ??\n ((onConnection: (socket: Socket) => void) =>\n createTlsServer(\n {\n cert: readFileSync(material.certFile),\n key: readFileSync(material.keyFile),\n ca: readFileSync(material.clientCaFile),\n requestCert: true,\n // unauthenticated connections may only send a join frame; the\n // per-frame authorization gate enforces that below\n rejectUnauthorized: false,\n minVersion: \"TLSv1.3\",\n },\n onConnection,\n ));\n this.server = factory((socket) => this.handleConnection(socket));\n this.server.listen(this.settings.port, () => {\n log.logInfo(`Gondolin worker gateway listening on :${this.settings?.port}`);\n });\n }\n\n stop(): void {\n for (const worker of this.workers.values()) {\n worker.socket.destroy();\n this.rejectPendingRpc(worker, \"gateway stopped\");\n }\n this.workers.clear();\n for (const pending of this.pendingTunnels.values()) clearTimeout(pending.timer);\n this.pendingTunnels.clear();\n this.server?.close();\n this.server = undefined;\n }\n\n /** Routes one inbound connection by its first frame: control or tunnel. */\n private handleConnection(socket: Socket): void {\n socket.setNoDelay(true);\n socket.setKeepAlive(true, 30_000);\n let routed = false;\n const authorized = (this.overrides.isAuthorized ?? defaultIsAuthorized)(socket);\n const reader = createControlFrameReader((frame, leftover) => {\n if (!routed) {\n routed = true;\n if (frame.type === \"join\") {\n void this.handleJoin(socket, frame);\n } else if (!authorized) {\n // everything except join requires a CA-signed client certificate\n socket.destroy();\n } else if (frame.type === \"register\" && frame.name) {\n this.acceptControlChannel(socket, frame, reader);\n } else if (frame.type === \"tunnel\" && frame.nonce) {\n reader.stop();\n socket.removeAllListeners(\"data\");\n this.acceptTunnel(socket, frame.nonce, leftover);\n } else {\n socket.destroy();\n }\n return;\n }\n this.handleControlFrame(socket, frame);\n });\n socket.on(\"data\", (chunk: Buffer) => reader.push(chunk));\n socket.on(\"error\", () => socket.destroy());\n }\n\n private acceptControlChannel(\n socket: Socket,\n registration: ControlFrame,\n _reader: { stop: () => void },\n ): void {\n const name = registration.name as string;\n const previous = this.workers.get(name);\n if (previous && !previous.socket.destroyed) {\n log.logInfo(`Gondolin worker '${name}' re-registered; superseding previous connection`);\n previous.socket.destroy();\n }\n const worker: RegisteredWorker = {\n info: registration,\n socket,\n connectedAt: Date.now(),\n lastSeen: Date.now(),\n activeRuntimes: registration.runtimes?.length ?? 0,\n pendingRpc: new Map(),\n nextRpcId: 1,\n };\n this.workers.set(name, worker);\n const surviving = registration.runtimes?.length ?? 0;\n log.logInfo(\n `Gondolin worker joined: ${name} (${registration.os}/${registration.arch}, ` +\n `${registration.accelerator}, ${registration.cpus} cpus, ` +\n `cap ${registration.maxRuntimes ?? \"∞\"}, ${surviving} runtimes surviving)`,\n );\n\n const overrides = this.settings?.workers?.[name];\n gondolinFleet.attachWorker(\n {\n name,\n url: `dialhome://${name}`,\n workspaceRoot: this.settings?.workspaceRoot,\n maxRuntimes: overrides?.maxRuntimes ?? registration.maxRuntimes,\n draining: overrides?.draining,\n },\n (connectionOverrides) =>\n new GondolinRemoteConnection(\n { name, url: `dialhome://${name}`, workspaceRoot: this.settings?.workspaceRoot },\n {\n ...connectionOverrides,\n ...(this.overrides.leaseTtlSeconds !== undefined\n ? { leaseTtlSeconds: this.overrides.leaseTtlSeconds }\n : {}),\n request: (method, path, body, headers) => this.rpc(name, method, path, body, headers),\n tunnel: (path, headers, callbacks) => this.openTunnel(name, path, headers, callbacks),\n },\n ),\n );\n this.applyWorkspaceHealth(worker, registration.workspaceError);\n // a worker that reconnected may carry runtimes whose placements moved\n void gondolinFleet.reconcile();\n\n socket.on(\"close\", () => {\n this.rejectPendingRpc(worker, `worker '${name}' disconnected`);\n const current = this.workers.get(name);\n if (current !== worker) return; // superseded\n log.logWarning(`Gondolin worker disconnected: ${name} (placements fence until lease expiry)`);\n gondolinFleet.detachWorker(name);\n this.workers.delete(name);\n });\n }\n\n private handleControlFrame(socket: Socket, frame: ControlFrame): void {\n const worker = this.workerBySocket(socket);\n if (!worker) return;\n worker.lastSeen = Date.now();\n if (frame.type === \"ping\") {\n if (typeof frame.activeRuntimes === \"number\") {\n worker.activeRuntimes = frame.activeRuntimes;\n }\n // omitted on healthy pings (Go omitempty), so absence means recovered\n this.applyWorkspaceHealth(worker, frame.workspaceError);\n socket.write(encodeControlFrame({ type: \"pong\" }));\n return;\n }\n if (frame.type === \"response\" && typeof frame.id === \"number\") {\n const pending = worker.pendingRpc.get(frame.id);\n if (!pending) return;\n worker.pendingRpc.delete(frame.id);\n clearTimeout(pending.timer);\n pending.resolve(frame);\n }\n }\n\n /**\n * Track shared-workspace health from register/ping frames and push it into\n * the fleet, logging only the transitions. A worker whose NFS mount died\n * keeps its control channel alive — this is what turns that silent state\n * into refused placements and fail-fast execs.\n */\n private applyWorkspaceHealth(worker: RegisteredWorker, error: string | undefined): void {\n const next = error || undefined;\n if (next === worker.workspaceError) {\n gondolinFleet.setWorkspaceHealth(worker.info.name, next); // attach may have reset it\n return;\n }\n if (next) {\n log.logWarning(\n `Gondolin worker '${worker.info.name}' workspace is unusable: ${next} — new placements disabled until it recovers`,\n );\n } else {\n log.logInfo(`Gondolin worker '${worker.info.name}' workspace recovered`);\n }\n worker.workspaceError = next;\n gondolinFleet.setWorkspaceHealth(worker.info.name, next);\n }\n\n /** RPC to a worker over its control channel (the reverse of HTTPS requests). */\n private rpc(\n name: string,\n method: string,\n path: string,\n body?: object,\n headers?: Record<string, string>,\n ): Promise<{ status: number; json: Record<string, unknown> }> {\n const worker = this.workers.get(name);\n if (!worker || worker.socket.destroyed) {\n return Promise.reject(\n new GondolinWorkerUnreachableError(`worker '${name}' is not connected`),\n );\n }\n const id = worker.nextRpcId++;\n return new Promise((resolve, reject) => {\n const timer = setTimeout(() => {\n worker.pendingRpc.delete(id);\n reject(\n new GondolinWorkerUnreachableError(\n `RPC to worker '${name}' timed out (${method} ${path})`,\n ),\n );\n }, this.overrides.rpcTimeoutMs ?? RPC_TIMEOUT_MS);\n timer.unref?.();\n worker.pendingRpc.set(id, {\n timer,\n reject,\n resolve: (frame) =>\n resolve({\n status: frame.status ?? 0,\n json: (frame.body ?? {}) as Record<string, unknown>,\n }),\n });\n worker.socket.write(encodeControlFrame({ type: \"request\", id, method, path, body, headers }));\n });\n }\n\n private rejectPendingRpc(worker: RegisteredWorker, reason: string): void {\n for (const pending of worker.pendingRpc.values()) {\n clearTimeout(pending.timer);\n pending.reject(new GondolinWorkerUnreachableError(reason));\n }\n worker.pendingRpc.clear();\n }\n\n /** Ask the worker to dial back a data connection for one session tunnel. */\n private openTunnel(\n name: string,\n path: string,\n headers: Record<string, string>,\n callbacks: SessionClientCallbacks,\n ): Promise<SessionClient> {\n const worker = this.workers.get(name);\n if (!worker || worker.socket.destroyed) {\n const error = new Error(`worker '${name}' is not connected`) as NodeJS.ErrnoException;\n error.code = \"ECONNREFUSED\"; // nothing executed — safe to recreate\n return Promise.reject(error);\n }\n const sessionId = path.split(\"/\")[3];\n const nonce = randomBytes(16).toString(\"hex\");\n return new Promise((resolve, reject) => {\n const timer = setTimeout(() => {\n this.pendingTunnels.delete(nonce);\n const error = new Error(\n `worker '${name}' did not dial back a tunnel`,\n ) as NodeJS.ErrnoException;\n error.code = \"ECONNREFUSED\";\n reject(error);\n }, this.overrides.tunnelTimeoutMs ?? TUNNEL_TIMEOUT_MS);\n timer.unref?.();\n this.pendingTunnels.set(nonce, {\n timer,\n resolve: ({ socket, leftover }) => {\n let closed = false;\n const parse = createSessionFrameParser(callbacks);\n if (leftover.length > 0) parse(leftover);\n socket.on(\"data\", parse);\n socket.on(\"error\", (error: Error) => {\n if (closed) return;\n closed = true;\n callbacks.onClose(error);\n });\n socket.on(\"close\", () => {\n if (closed) return;\n closed = true;\n callbacks.onClose();\n });\n resolve({\n send: (message) => {\n if (!closed) socket.write(encodeSessionMessage(message));\n },\n close: () => {\n if (closed) return;\n closed = true;\n socket.destroy();\n },\n });\n },\n });\n worker.socket.write(encodeControlFrame({ type: \"open-tunnel\", nonce, sessionId, headers }));\n });\n }\n\n /**\n * One-time token → CA-signed client certificate. The only operation an\n * unauthenticated connection may perform; the connection closes after the\n * response either way.\n */\n private async handleJoin(socket: Socket, frame: ControlFrame): Promise<void> {\n const refuse = (message: string): void => {\n log.logWarning(`Gondolin worker join refused: ${message}`);\n socket.end(encodeControlFrame({ type: \"join-error\", message }));\n };\n if (!gondolinJoin.isConfigured()) {\n refuse(\"join is not enabled on this gateway\");\n return;\n }\n if (!frame.token || !frame.csr || !frame.name) {\n refuse(\"join requires token, csr, and name\");\n return;\n }\n if (!gondolinJoin.consumeToken(frame.token)) {\n refuse(`invalid or expired join token (worker '${frame.name}')`);\n return;\n }\n try {\n const signed = await gondolinJoin.signCsr(frame.csr);\n log.logInfo(`Gondolin worker '${frame.name}' joined: client certificate issued`);\n socket.end(encodeControlFrame({ type: \"join-ok\", cert: signed.certPem, ca: signed.caPem }));\n } catch (err) {\n refuse(`certificate issuance failed: ${err instanceof Error ? err.message : String(err)}`);\n }\n }\n\n private acceptTunnel(socket: Socket, nonce: string, leftover: Buffer): void {\n const pending = this.pendingTunnels.get(nonce);\n if (!pending) {\n socket.destroy();\n return;\n }\n this.pendingTunnels.delete(nonce);\n clearTimeout(pending.timer);\n pending.resolve({ socket, leftover: Buffer.from(leftover) });\n }\n\n private workerBySocket(socket: Socket): RegisteredWorker | undefined {\n for (const worker of this.workers.values()) {\n if (worker.socket === socket) return worker;\n }\n return undefined;\n }\n}\n\nexport const gondolinGateway = new GondolinWorkerGateway();\n"]}
|
|
@@ -4,21 +4,8 @@
|
|
|
4
4
|
* hosting it — so a crash that skips every exit hook still leaves enough
|
|
5
5
|
* behind to adopt the runtime back or stop its orphaned VM runner.
|
|
6
6
|
*/
|
|
7
|
-
export
|
|
8
|
-
|
|
9
|
-
sessionId: string;
|
|
10
|
-
/** mikan session key (vault key) the runtime was created for. */
|
|
11
|
-
instanceId: string;
|
|
12
|
-
/** Process that owns the runtime (the worker process). */
|
|
13
|
-
ownerPid: number;
|
|
14
|
-
/** Host pid of the active VM runner process (QEMU/krun), if started. */
|
|
15
|
-
runnerPid: number | null;
|
|
16
|
-
createdAt: string;
|
|
17
|
-
/** Session IPC socket for adopting the runtime from a new mikan process. */
|
|
18
|
-
socketPath?: string;
|
|
19
|
-
/** Desired-runtime fingerprint the VM was created from. */
|
|
20
|
-
fingerprint?: string;
|
|
21
|
-
}
|
|
7
|
+
export type { GondolinRuntimeRecord } from "./gondolin-contract.js";
|
|
8
|
+
import { type GondolinRuntimeRecord } from "./gondolin-contract.js";
|
|
22
9
|
interface GondolinInventoryOverrides {
|
|
23
10
|
execFile?: (cmd: string, args: string[]) => Promise<string>;
|
|
24
11
|
kill?: (pid: number, signal: NodeJS.Signals | 0) => void;
|
|
@@ -85,5 +72,4 @@ declare class GondolinRuntimeInventory {
|
|
|
85
72
|
private recordPath;
|
|
86
73
|
}
|
|
87
74
|
export declare const gondolinInventory: GondolinRuntimeInventory;
|
|
88
|
-
export {};
|
|
89
75
|
//# sourceMappingURL=gondolin-inventory.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gondolin-inventory.d.ts","sourceRoot":"","sources":["../../src/sandbox/gondolin-inventory.ts"],"names":[],"mappings":"AAMA;;;;;GAKG;
|
|
1
|
+
{"version":3,"file":"gondolin-inventory.d.ts","sourceRoot":"","sources":["../../src/sandbox/gondolin-inventory.ts"],"names":[],"mappings":"AAMA;;;;;GAKG;AAGH,YAAY,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AACpE,OAAO,EAA2B,KAAK,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAE7F,UAAU,0BAA0B;IAClC,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAC5D,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,OAAO,GAAG,CAAC,KAAK,IAAI,CAAC;IACzD,UAAU,CAAC,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;IACnC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAOD,cAAM,wBAAwB;IAC5B,OAAO,CAAC,GAAG,CAAC,CAAS;IACrB,OAAO,CAAC,YAAY,CAAc;IAClC,OAAO,CAAC,QAAQ,CACY;IAC5B,OAAO,CAAC,cAAc,CAAqB;IAC3C,OAAO,CAAC,UAAU,CAAQ;IAC1B,OAAO,CAAC,kBAAkB,CAAO;IACjC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAA4C;IAExE,SAAS,CAAC,GAAG,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,0BAA0B,GAAG,IAAI,CAQpE;IAED,MAAM,CAAC,KAAK,EAAE;QACZ,SAAS,EAAE,MAAM,CAAC;QAClB,UAAU,EAAE,MAAM,CAAC;QACnB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;QACzB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB,GAAG,IAAI,CASP;IAED,iFAAiF;IACjF,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAKzD;IAED,OAAO,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAW/B;IAED;;;;OAIG;IACG,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,qBAAqB,GAAG,SAAS,CAAC,CAWlF;IAED,0FAA0F;IACpF,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAMlD;IAED,wFAAwF;IACxF,iBAAiB,IAAI,qBAAqB,EAAE,CAI3C;IAED;;;OAGG;IACH,cAAc,IAAI,IAAI,CAWrB;IAED,aAAa,IAAI,MAAM,GAAG,SAAS,CAElC;IAED,SAAS,IAAI,MAAM,GAAG,SAAS,CAE9B;IAED;;;;;;OAMG;IACG,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC,CA8B/B;IAED;;;;OAIG;IACG,UAAU,CACd,MAAM,EAAE,qBAAqB,EAC7B,IAAI,SAAoC,GACvC,OAAO,CAAC,QAAQ,GAAG,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAC,CAUjD;IAED,OAAO,CAAC,WAAW;YA4BL,UAAU;IA6BxB,OAAO,CAAC,MAAM;IAQd,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAO/B;YAEa,WAAW;IASzB,OAAO,CAAC,KAAK;IAab,OAAO,CAAC,UAAU;CAGnB;AAED,eAAO,MAAM,iBAAiB,0BAAiC,CAAC"}
|
|
@@ -1,19 +1,9 @@
|
|
|
1
1
|
import { readdirSync, rmSync, writeFileSync } from "node:fs";
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import * as log from "../log.js";
|
|
4
|
-
import { ensureDirExists,
|
|
4
|
+
import { ensureDirExists, readJsonFileIfExists } from "../utils/file-guards.js";
|
|
5
5
|
import { execSimple } from "./utils.js";
|
|
6
|
-
|
|
7
|
-
return (isRecord(value) &&
|
|
8
|
-
typeof value.sessionId === "string" &&
|
|
9
|
-
value.sessionId.length > 0 &&
|
|
10
|
-
typeof value.instanceId === "string" &&
|
|
11
|
-
typeof value.ownerPid === "number" &&
|
|
12
|
-
(value.runnerPid === null || typeof value.runnerPid === "number") &&
|
|
13
|
-
typeof value.createdAt === "string" &&
|
|
14
|
-
(value.socketPath === undefined || typeof value.socketPath === "string") &&
|
|
15
|
-
(value.fingerprint === undefined || typeof value.fingerprint === "string"));
|
|
16
|
-
}
|
|
6
|
+
import { isGondolinRuntimeRecord } from "./gondolin-contract.js";
|
|
17
7
|
async function defaultGcSessions() {
|
|
18
8
|
const { gcSessions } = await import("@earendil-works/gondolin");
|
|
19
9
|
return gcSessions();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gondolin-inventory.js","sourceRoot":"","sources":["../../src/sandbox/gondolin-inventory.ts"],"names":[],"mappings":"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","sourcesContent":["import { readdirSync, rmSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport * as log from \"../log.js\";\nimport { ensureDirExists, isRecord, readJsonFileIfExists } from \"../utils/file-guards.js\";\nimport { execSimple } from \"./utils.js\";\n\n/**\n * Durable record of one Gondolin runtime. Written beside the state dir (never\n * inside the workspace) by whichever process owns the VM — the worker process\n * hosting it — so a crash that skips every exit hook still leaves enough\n * behind to adopt the runtime back or stop its orphaned VM runner.\n */\nexport interface GondolinRuntimeRecord {\n /** Gondolin session id (`vm.id`); also names the record file. */\n sessionId: string;\n /** mikan session key (vault key) the runtime was created for. */\n instanceId: string;\n /** Process that owns the runtime (the worker process). */\n ownerPid: number;\n /** Host pid of the active VM runner process (QEMU/krun), if started. */\n runnerPid: number | null;\n createdAt: string;\n /** Session IPC socket for adopting the runtime from a new mikan process. */\n socketPath?: string;\n /** Desired-runtime fingerprint the VM was created from. */\n fingerprint?: string;\n}\n\ninterface GondolinInventoryOverrides {\n execFile?: (cmd: string, args: string[]) => Promise<string>;\n kill?: (pid: number, signal: NodeJS.Signals | 0) => void;\n gcSessions?: () => Promise<number>;\n killWaitMs?: number;\n killPollIntervalMs?: number;\n}\n\nfunction isGondolinRuntimeRecord(value: unknown): value is GondolinRuntimeRecord {\n return (\n isRecord(value) &&\n typeof value.sessionId === \"string\" &&\n value.sessionId.length > 0 &&\n typeof value.instanceId === \"string\" &&\n typeof value.ownerPid === \"number\" &&\n (value.runnerPid === null || typeof value.runnerPid === \"number\") &&\n typeof value.createdAt === \"string\" &&\n (value.socketPath === undefined || typeof value.socketPath === \"string\") &&\n (value.fingerprint === undefined || typeof value.fingerprint === \"string\")\n );\n}\n\nasync function defaultGcSessions(): Promise<number> {\n const { gcSessions } = await import(\"@earendil-works/gondolin\");\n return gcSessions();\n}\n\nclass GondolinRuntimeInventory {\n private dir?: string;\n private execFileImpl = execSimple;\n private killImpl: (pid: number, signal: NodeJS.Signals | 0) => void = (pid, signal) =>\n process.kill(pid, signal);\n private gcSessionsImpl = defaultGcSessions;\n private killWaitMs = 2000;\n private killPollIntervalMs = 100;\n private readonly liveRecords = new Map<string, GondolinRuntimeRecord>();\n\n configure(dir?: string, overrides?: GondolinInventoryOverrides): void {\n this.dir = dir;\n this.execFileImpl = overrides?.execFile ?? execSimple;\n this.killImpl = overrides?.kill ?? ((pid, signal) => process.kill(pid, signal));\n this.gcSessionsImpl = overrides?.gcSessions ?? defaultGcSessions;\n this.killWaitMs = overrides?.killWaitMs ?? 2000;\n this.killPollIntervalMs = overrides?.killPollIntervalMs ?? 100;\n this.liveRecords.clear();\n }\n\n record(entry: {\n sessionId: string;\n instanceId: string;\n runnerPid: number | null;\n socketPath?: string;\n fingerprint?: string;\n }): void {\n if (!this.dir) return;\n const record: GondolinRuntimeRecord = {\n ...entry,\n ownerPid: process.pid,\n createdAt: new Date().toISOString(),\n };\n this.liveRecords.set(entry.sessionId, record);\n this.write(record);\n }\n\n /** Re-persist a runtime whose runner pid changed (late boot, runner restart). */\n refresh(sessionId: string, runnerPid: number | null): void {\n const record = this.liveRecords.get(sessionId);\n if (!record || record.runnerPid === runnerPid) return;\n record.runnerPid = runnerPid;\n this.write(record);\n }\n\n release(sessionId: string): void {\n this.liveRecords.delete(sessionId);\n if (!this.dir) return;\n try {\n rmSync(this.recordPath(sessionId), { force: true });\n } catch (err) {\n log.logWarning(\n `Failed to release Gondolin runtime record '${sessionId}'`,\n err instanceof Error ? err.message : String(err),\n );\n }\n }\n\n /**\n * Newest worker-owned record for a session key whose owner is still alive —\n * a candidate for adoption instead of spawning a fresh worker. Records left\n * by dead owners are reaped on the spot.\n */\n async findAdoptable(instanceId: string): Promise<GondolinRuntimeRecord | undefined> {\n let newest: GondolinRuntimeRecord | undefined;\n for (const { record, path } of this.readRecords()) {\n if (record.instanceId !== instanceId || !record.socketPath) continue;\n if (!this.isPidAlive(record.ownerPid)) {\n await this.reapRecord(record, path);\n continue;\n }\n if (!newest || record.createdAt > newest.createdAt) newest = record;\n }\n return newest;\n }\n\n /** Reap one session's record if its owner is gone (e.g. after force-killing a worker). */\n async reapSession(sessionId: string): Promise<void> {\n for (const { record, path } of this.readRecords()) {\n if (record.sessionId !== sessionId) continue;\n if (!this.isPidAlive(record.ownerPid)) await this.reapRecord(record, path);\n return;\n }\n }\n\n /** Worker-owned records with live owners (runtimes surviving from a previous mikan). */\n listWorkerRecords(): GondolinRuntimeRecord[] {\n return this.readRecords()\n .map(({ record }) => record)\n .filter((record) => record.socketPath !== undefined && this.isPidAlive(record.ownerPid));\n }\n\n /**\n * mikan liveness signal for workers: a worker whose heartbeat goes stale\n * knows every mikan that could adopt it is gone and shuts itself down.\n */\n touchHeartbeat(): void {\n if (!this.dir) return;\n try {\n ensureDirExists(this.dir);\n writeFileSync(this.heartbeatPath() as string, new Date().toISOString() + \"\\n\");\n } catch (err) {\n log.logWarning(\n \"Failed to touch Gondolin heartbeat\",\n err instanceof Error ? err.message : String(err),\n );\n }\n }\n\n heartbeatPath(): string | undefined {\n return this.dir ? join(this.dir, \"heartbeat\") : undefined;\n }\n\n directory(): string | undefined {\n return this.dir;\n }\n\n /**\n * Startup reconciliation: stop VM runners orphaned by a previous owner\n * process that died without cleanup, drop stale records, and let Gondolin\n * collect its own stale session registry entries. Runtimes whose owner is\n * still alive (workers surviving a mikan restart) are left for adoption.\n * Idempotent — a second run finds an empty inventory.\n */\n async reconcile(): Promise<void> {\n if (!this.dir) return;\n ensureDirExists(this.dir);\n let killed = 0;\n let stale = 0;\n let skipped = 0;\n for (const { record, path } of this.readRecords((badPath) => {\n rmSync(badPath, { force: true });\n stale += 1;\n })) {\n if (record.ownerPid === process.pid) continue;\n if (this.isPidAlive(record.ownerPid)) {\n skipped += 1;\n continue;\n }\n const outcome = await this.reapRecord(record, path);\n if (outcome === \"killed\") killed += 1;\n else if (outcome !== \"alive\") stale += 1;\n }\n try {\n await this.gcSessionsImpl();\n } catch (err) {\n log.logWarning(\n \"Failed to collect Gondolin session registry\",\n err instanceof Error ? err.message : String(err),\n );\n }\n log.logInfo(\n `Reconciled Gondolin runtimes (killed=${killed}, stale=${stale}, liveOwner=${skipped})`,\n );\n }\n\n /**\n * Reap one dead-owner record: stop its orphaned runner if it is still the\n * process we launched, then drop the record (kept only while the runner\n * refuses to die, so the next reconcile retries).\n */\n async reapRecord(\n record: GondolinRuntimeRecord,\n path = this.recordPath(record.sessionId),\n ): Promise<\"killed\" | \"gone\" | \"reused\" | \"alive\"> {\n const outcome = record.runnerPid === null ? \"gone\" : await this.stopOrphan(record);\n if (outcome === \"alive\") {\n log.logWarning(\n `Orphaned Gondolin runner ${record.runnerPid} survived SIGKILL; keeping record '${record.sessionId}'`,\n );\n return outcome;\n }\n rmSync(path, { force: true });\n return outcome;\n }\n\n private readRecords(\n onMalformed?: (path: string) => void,\n ): Array<{ record: GondolinRuntimeRecord; path: string }> {\n if (!this.dir) return [];\n ensureDirExists(this.dir);\n const entries: Array<{ record: GondolinRuntimeRecord; path: string }> = [];\n for (const file of readdirSync(this.dir)) {\n if (!file.endsWith(\".json\")) continue;\n const path = join(this.dir, file);\n let record: GondolinRuntimeRecord | undefined;\n try {\n record = readJsonFileIfExists(\n path,\n isGondolinRuntimeRecord,\n (detail) => `Malformed Gondolin runtime record at ${path}: ${detail}`,\n );\n } catch (err) {\n log.logWarning(\n \"Dropping malformed Gondolin runtime record\",\n err instanceof Error ? err.message : String(err),\n );\n }\n if (record) entries.push({ record, path });\n else onMalformed?.(path);\n }\n return entries;\n }\n\n private async stopOrphan(\n record: GondolinRuntimeRecord,\n ): Promise<\"killed\" | \"gone\" | \"reused\" | \"alive\"> {\n const pid = record.runnerPid as number;\n if (!this.isPidAlive(pid)) return \"gone\";\n // Guard against pid reuse: only kill processes that still look like a\n // Gondolin runner (its guest assets and overlay disk live under paths\n // containing \"gondolin\").\n let command: string;\n try {\n command = await this.execFileImpl(\"ps\", [\"-p\", String(pid), \"-o\", \"command=\"]);\n } catch {\n return \"gone\";\n }\n if (!command.toLowerCase().includes(\"gondolin\")) {\n log.logWarning(\n `Pid ${pid} from Gondolin runtime record '${record.sessionId}' no longer looks like a Gondolin runner; skipping kill`,\n );\n return \"reused\";\n }\n log.logInfo(\n `Stopping orphaned Gondolin runner ${pid} (session '${record.sessionId}', instance '${record.instanceId}')`,\n );\n this.signal(pid, \"SIGTERM\");\n if (await this.waitForExit(pid)) return \"killed\";\n this.signal(pid, \"SIGKILL\");\n return (await this.waitForExit(pid)) ? \"killed\" : \"alive\";\n }\n\n private signal(pid: number, signal: NodeJS.Signals): void {\n try {\n this.killImpl(pid, signal);\n } catch {\n // process already gone\n }\n }\n\n isPidAlive(pid: number): boolean {\n try {\n this.killImpl(pid, 0);\n return true;\n } catch {\n return false;\n }\n }\n\n private async waitForExit(pid: number): Promise<boolean> {\n const deadline = Date.now() + this.killWaitMs;\n while (this.isPidAlive(pid)) {\n if (Date.now() >= deadline) return false;\n await new Promise((resolve) => setTimeout(resolve, this.killPollIntervalMs));\n }\n return true;\n }\n\n private write(record: GondolinRuntimeRecord): void {\n if (!this.dir) return;\n try {\n ensureDirExists(this.dir);\n writeFileSync(this.recordPath(record.sessionId), JSON.stringify(record, null, 2) + \"\\n\");\n } catch (err) {\n log.logWarning(\n `Failed to persist Gondolin runtime record '${record.sessionId}'`,\n err instanceof Error ? err.message : String(err),\n );\n }\n }\n\n private recordPath(sessionId: string): string {\n return join(this.dir as string, `${sessionId}.json`);\n }\n}\n\nexport const gondolinInventory = new GondolinRuntimeInventory();\n"]}
|
|
1
|
+
{"version":3,"file":"gondolin-inventory.js","sourceRoot":"","sources":["../../src/sandbox/gondolin-inventory.ts"],"names":[],"mappings":"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","sourcesContent":["import { readdirSync, rmSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport * as log from \"../log.js\";\nimport { ensureDirExists, readJsonFileIfExists } from \"../utils/file-guards.js\";\nimport { execSimple } from \"./utils.js\";\n\n/**\n * Durable record of one Gondolin runtime. Written beside the state dir (never\n * inside the workspace) by whichever process owns the VM — the worker process\n * hosting it — so a crash that skips every exit hook still leaves enough\n * behind to adopt the runtime back or stop its orphaned VM runner.\n */\n// The record is a wire contract shape shared with the Go daemon's\n// rediscovery; its single home is gondolin-contract.ts.\nexport type { GondolinRuntimeRecord } from \"./gondolin-contract.js\";\nimport { isGondolinRuntimeRecord, type GondolinRuntimeRecord } from \"./gondolin-contract.js\";\n\ninterface GondolinInventoryOverrides {\n execFile?: (cmd: string, args: string[]) => Promise<string>;\n kill?: (pid: number, signal: NodeJS.Signals | 0) => void;\n gcSessions?: () => Promise<number>;\n killWaitMs?: number;\n killPollIntervalMs?: number;\n}\n\nasync function defaultGcSessions(): Promise<number> {\n const { gcSessions } = await import(\"@earendil-works/gondolin\");\n return gcSessions();\n}\n\nclass GondolinRuntimeInventory {\n private dir?: string;\n private execFileImpl = execSimple;\n private killImpl: (pid: number, signal: NodeJS.Signals | 0) => void = (pid, signal) =>\n process.kill(pid, signal);\n private gcSessionsImpl = defaultGcSessions;\n private killWaitMs = 2000;\n private killPollIntervalMs = 100;\n private readonly liveRecords = new Map<string, GondolinRuntimeRecord>();\n\n configure(dir?: string, overrides?: GondolinInventoryOverrides): void {\n this.dir = dir;\n this.execFileImpl = overrides?.execFile ?? execSimple;\n this.killImpl = overrides?.kill ?? ((pid, signal) => process.kill(pid, signal));\n this.gcSessionsImpl = overrides?.gcSessions ?? defaultGcSessions;\n this.killWaitMs = overrides?.killWaitMs ?? 2000;\n this.killPollIntervalMs = overrides?.killPollIntervalMs ?? 100;\n this.liveRecords.clear();\n }\n\n record(entry: {\n sessionId: string;\n instanceId: string;\n runnerPid: number | null;\n socketPath?: string;\n fingerprint?: string;\n }): void {\n if (!this.dir) return;\n const record: GondolinRuntimeRecord = {\n ...entry,\n ownerPid: process.pid,\n createdAt: new Date().toISOString(),\n };\n this.liveRecords.set(entry.sessionId, record);\n this.write(record);\n }\n\n /** Re-persist a runtime whose runner pid changed (late boot, runner restart). */\n refresh(sessionId: string, runnerPid: number | null): void {\n const record = this.liveRecords.get(sessionId);\n if (!record || record.runnerPid === runnerPid) return;\n record.runnerPid = runnerPid;\n this.write(record);\n }\n\n release(sessionId: string): void {\n this.liveRecords.delete(sessionId);\n if (!this.dir) return;\n try {\n rmSync(this.recordPath(sessionId), { force: true });\n } catch (err) {\n log.logWarning(\n `Failed to release Gondolin runtime record '${sessionId}'`,\n err instanceof Error ? err.message : String(err),\n );\n }\n }\n\n /**\n * Newest worker-owned record for a session key whose owner is still alive —\n * a candidate for adoption instead of spawning a fresh worker. Records left\n * by dead owners are reaped on the spot.\n */\n async findAdoptable(instanceId: string): Promise<GondolinRuntimeRecord | undefined> {\n let newest: GondolinRuntimeRecord | undefined;\n for (const { record, path } of this.readRecords()) {\n if (record.instanceId !== instanceId || !record.socketPath) continue;\n if (!this.isPidAlive(record.ownerPid)) {\n await this.reapRecord(record, path);\n continue;\n }\n if (!newest || record.createdAt > newest.createdAt) newest = record;\n }\n return newest;\n }\n\n /** Reap one session's record if its owner is gone (e.g. after force-killing a worker). */\n async reapSession(sessionId: string): Promise<void> {\n for (const { record, path } of this.readRecords()) {\n if (record.sessionId !== sessionId) continue;\n if (!this.isPidAlive(record.ownerPid)) await this.reapRecord(record, path);\n return;\n }\n }\n\n /** Worker-owned records with live owners (runtimes surviving from a previous mikan). */\n listWorkerRecords(): GondolinRuntimeRecord[] {\n return this.readRecords()\n .map(({ record }) => record)\n .filter((record) => record.socketPath !== undefined && this.isPidAlive(record.ownerPid));\n }\n\n /**\n * mikan liveness signal for workers: a worker whose heartbeat goes stale\n * knows every mikan that could adopt it is gone and shuts itself down.\n */\n touchHeartbeat(): void {\n if (!this.dir) return;\n try {\n ensureDirExists(this.dir);\n writeFileSync(this.heartbeatPath() as string, new Date().toISOString() + \"\\n\");\n } catch (err) {\n log.logWarning(\n \"Failed to touch Gondolin heartbeat\",\n err instanceof Error ? err.message : String(err),\n );\n }\n }\n\n heartbeatPath(): string | undefined {\n return this.dir ? join(this.dir, \"heartbeat\") : undefined;\n }\n\n directory(): string | undefined {\n return this.dir;\n }\n\n /**\n * Startup reconciliation: stop VM runners orphaned by a previous owner\n * process that died without cleanup, drop stale records, and let Gondolin\n * collect its own stale session registry entries. Runtimes whose owner is\n * still alive (workers surviving a mikan restart) are left for adoption.\n * Idempotent — a second run finds an empty inventory.\n */\n async reconcile(): Promise<void> {\n if (!this.dir) return;\n ensureDirExists(this.dir);\n let killed = 0;\n let stale = 0;\n let skipped = 0;\n for (const { record, path } of this.readRecords((badPath) => {\n rmSync(badPath, { force: true });\n stale += 1;\n })) {\n if (record.ownerPid === process.pid) continue;\n if (this.isPidAlive(record.ownerPid)) {\n skipped += 1;\n continue;\n }\n const outcome = await this.reapRecord(record, path);\n if (outcome === \"killed\") killed += 1;\n else if (outcome !== \"alive\") stale += 1;\n }\n try {\n await this.gcSessionsImpl();\n } catch (err) {\n log.logWarning(\n \"Failed to collect Gondolin session registry\",\n err instanceof Error ? err.message : String(err),\n );\n }\n log.logInfo(\n `Reconciled Gondolin runtimes (killed=${killed}, stale=${stale}, liveOwner=${skipped})`,\n );\n }\n\n /**\n * Reap one dead-owner record: stop its orphaned runner if it is still the\n * process we launched, then drop the record (kept only while the runner\n * refuses to die, so the next reconcile retries).\n */\n async reapRecord(\n record: GondolinRuntimeRecord,\n path = this.recordPath(record.sessionId),\n ): Promise<\"killed\" | \"gone\" | \"reused\" | \"alive\"> {\n const outcome = record.runnerPid === null ? \"gone\" : await this.stopOrphan(record);\n if (outcome === \"alive\") {\n log.logWarning(\n `Orphaned Gondolin runner ${record.runnerPid} survived SIGKILL; keeping record '${record.sessionId}'`,\n );\n return outcome;\n }\n rmSync(path, { force: true });\n return outcome;\n }\n\n private readRecords(\n onMalformed?: (path: string) => void,\n ): Array<{ record: GondolinRuntimeRecord; path: string }> {\n if (!this.dir) return [];\n ensureDirExists(this.dir);\n const entries: Array<{ record: GondolinRuntimeRecord; path: string }> = [];\n for (const file of readdirSync(this.dir)) {\n if (!file.endsWith(\".json\")) continue;\n const path = join(this.dir, file);\n let record: GondolinRuntimeRecord | undefined;\n try {\n record = readJsonFileIfExists(\n path,\n isGondolinRuntimeRecord,\n (detail) => `Malformed Gondolin runtime record at ${path}: ${detail}`,\n );\n } catch (err) {\n log.logWarning(\n \"Dropping malformed Gondolin runtime record\",\n err instanceof Error ? err.message : String(err),\n );\n }\n if (record) entries.push({ record, path });\n else onMalformed?.(path);\n }\n return entries;\n }\n\n private async stopOrphan(\n record: GondolinRuntimeRecord,\n ): Promise<\"killed\" | \"gone\" | \"reused\" | \"alive\"> {\n const pid = record.runnerPid as number;\n if (!this.isPidAlive(pid)) return \"gone\";\n // Guard against pid reuse: only kill processes that still look like a\n // Gondolin runner (its guest assets and overlay disk live under paths\n // containing \"gondolin\").\n let command: string;\n try {\n command = await this.execFileImpl(\"ps\", [\"-p\", String(pid), \"-o\", \"command=\"]);\n } catch {\n return \"gone\";\n }\n if (!command.toLowerCase().includes(\"gondolin\")) {\n log.logWarning(\n `Pid ${pid} from Gondolin runtime record '${record.sessionId}' no longer looks like a Gondolin runner; skipping kill`,\n );\n return \"reused\";\n }\n log.logInfo(\n `Stopping orphaned Gondolin runner ${pid} (session '${record.sessionId}', instance '${record.instanceId}')`,\n );\n this.signal(pid, \"SIGTERM\");\n if (await this.waitForExit(pid)) return \"killed\";\n this.signal(pid, \"SIGKILL\");\n return (await this.waitForExit(pid)) ? \"killed\" : \"alive\";\n }\n\n private signal(pid: number, signal: NodeJS.Signals): void {\n try {\n this.killImpl(pid, signal);\n } catch {\n // process already gone\n }\n }\n\n isPidAlive(pid: number): boolean {\n try {\n this.killImpl(pid, 0);\n return true;\n } catch {\n return false;\n }\n }\n\n private async waitForExit(pid: number): Promise<boolean> {\n const deadline = Date.now() + this.killWaitMs;\n while (this.isPidAlive(pid)) {\n if (Date.now() >= deadline) return false;\n await new Promise((resolve) => setTimeout(resolve, this.killPollIntervalMs));\n }\n return true;\n }\n\n private write(record: GondolinRuntimeRecord): void {\n if (!this.dir) return;\n try {\n ensureDirExists(this.dir);\n writeFileSync(this.recordPath(record.sessionId), JSON.stringify(record, null, 2) + \"\\n\");\n } catch (err) {\n log.logWarning(\n `Failed to persist Gondolin runtime record '${record.sessionId}'`,\n err instanceof Error ? err.message : String(err),\n );\n }\n }\n\n private recordPath(sessionId: string): string {\n return join(this.dir as string, `${sessionId}.json`);\n }\n}\n\nexport const gondolinInventory = new GondolinRuntimeInventory();\n"]}
|
|
@@ -20,8 +20,6 @@ export declare class GondolinPlacementStore {
|
|
|
20
20
|
private table;
|
|
21
21
|
configure(path?: string): void;
|
|
22
22
|
get(instanceId: string): GondolinPlacementRecord | undefined;
|
|
23
|
-
list(): GondolinPlacementRecord[];
|
|
24
|
-
countByWorker(worker: string): number;
|
|
25
23
|
set(instanceId: string, worker: string, leaseExpiresAt: number): void;
|
|
26
24
|
/** Refresh the fencing watermark without moving the placement. */
|
|
27
25
|
touch(instanceId: string, leaseExpiresAt: number): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gondolin-placement.d.ts","sourceRoot":"","sources":["../../src/sandbox/gondolin-placement.ts"],"names":[],"mappings":"AAKA;;;;;;GAMG;AACH,MAAM,WAAW,uBAAuB;IACtC,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;CACnB;AAcD;;;GAGG;AACH,qBAAa,sBAAsB;IACjC,OAAO,CAAC,IAAI,CAAC,CAAS;IACtB,OAAO,CAAC,KAAK,CAA8C;IAE3D,SAAS,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAiB7B;IAED,GAAG,CAAC,UAAU,EAAE,MAAM,GAAG,uBAAuB,GAAG,SAAS,CAE3D;IAED,
|
|
1
|
+
{"version":3,"file":"gondolin-placement.d.ts","sourceRoot":"","sources":["../../src/sandbox/gondolin-placement.ts"],"names":[],"mappings":"AAKA;;;;;;GAMG;AACH,MAAM,WAAW,uBAAuB;IACtC,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;CACnB;AAcD;;;GAGG;AACH,qBAAa,sBAAsB;IACjC,OAAO,CAAC,IAAI,CAAC,CAAS;IACtB,OAAO,CAAC,KAAK,CAA8C;IAE3D,SAAS,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAiB7B;IAED,GAAG,CAAC,UAAU,EAAE,MAAM,GAAG,uBAAuB,GAAG,SAAS,CAE3D;IAED,GAAG,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,IAAI,CAGpE;IAED,kEAAkE;IAClE,KAAK,CAAC,UAAU,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,IAAI,CAMtD;IAED,MAAM,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAE/B;IAED,OAAO,CAAC,OAAO;CAehB;AAED,eAAO,MAAM,kBAAkB,wBAA+B,CAAC"}
|
|
@@ -41,12 +41,6 @@ export class GondolinPlacementStore {
|
|
|
41
41
|
get(instanceId) {
|
|
42
42
|
return this.table.get(instanceId);
|
|
43
43
|
}
|
|
44
|
-
list() {
|
|
45
|
-
return Array.from(this.table.values());
|
|
46
|
-
}
|
|
47
|
-
countByWorker(worker) {
|
|
48
|
-
return this.list().filter((record) => record.worker === worker).length;
|
|
49
|
-
}
|
|
50
44
|
set(instanceId, worker, leaseExpiresAt) {
|
|
51
45
|
this.table.set(instanceId, { instanceId, worker, leaseExpiresAt, updatedAt: Date.now() });
|
|
52
46
|
this.persist();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gondolin-placement.js","sourceRoot":"","sources":["../../src/sandbox/gondolin-placement.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAClE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,KAAK,GAAG,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAgBpE,SAAS,gBAAgB,CAAC,KAAc;IACtC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IACnC,OAAO,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAC/B,CAAC,KAAK,EAAE,EAAE,CACR,QAAQ,CAAC,KAAK,CAAC;QACf,OAAO,KAAK,CAAC,UAAU,KAAK,QAAQ;QACpC,OAAO,KAAK,CAAC,MAAM,KAAK,QAAQ;QAChC,OAAO,KAAK,CAAC,cAAc,KAAK,QAAQ;QACxC,OAAO,KAAK,CAAC,SAAS,KAAK,QAAQ,CACtC,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,OAAO,sBAAsB;IAAnC;QAEU,UAAK,GAAG,IAAI,GAAG,EAAmC,CAAC;
|
|
1
|
+
{"version":3,"file":"gondolin-placement.js","sourceRoot":"","sources":["../../src/sandbox/gondolin-placement.ts"],"names":[],"mappings":"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","sourcesContent":["import { readFileSync, renameSync, writeFileSync } from \"node:fs\";\nimport { dirname } from \"node:path\";\nimport * as log from \"../log.js\";\nimport { ensureDirExists, isRecord } from \"../utils/file-guards.js\";\n\n/**\n * Where one conversation's runtime lives in the fleet, plus the fencing\n * watermark failover must respect: the worker-side lease cannot outlive\n * `leaseExpiresAt` (mikan clock), after which the old worker's janitor has\n * stopped the runtime and the shared-storage single-writer rule allows a\n * placement elsewhere.\n */\nexport interface GondolinPlacementRecord {\n instanceId: string;\n worker: string;\n leaseExpiresAt: number;\n updatedAt: number;\n}\n\nfunction isPlacementTable(value: unknown): value is Record<string, GondolinPlacementRecord> {\n if (!isRecord(value)) return false;\n return Object.values(value).every(\n (entry) =>\n isRecord(entry) &&\n typeof entry.instanceId === \"string\" &&\n typeof entry.worker === \"string\" &&\n typeof entry.leaseExpiresAt === \"number\" &&\n typeof entry.updatedAt === \"number\",\n );\n}\n\n/**\n * Durable instanceId → worker map. mikan is the only scheduler, so a single\n * atomically-replaced JSON file under the state dir is the source of truth.\n */\nexport class GondolinPlacementStore {\n private path?: string;\n private table = new Map<string, GondolinPlacementRecord>();\n\n configure(path?: string): void {\n this.path = path;\n this.table.clear();\n if (!path) return;\n try {\n const raw = readFileSync(path, \"utf8\");\n const parsed: unknown = JSON.parse(raw);\n if (!isPlacementTable(parsed)) throw new Error(\"unexpected placement table shape\");\n for (const record of Object.values(parsed)) this.table.set(record.instanceId, record);\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== \"ENOENT\") {\n log.logWarning(\n \"Starting with an empty Gondolin placement table\",\n err instanceof Error ? err.message : String(err),\n );\n }\n }\n }\n\n get(instanceId: string): GondolinPlacementRecord | undefined {\n return this.table.get(instanceId);\n }\n\n set(instanceId: string, worker: string, leaseExpiresAt: number): void {\n this.table.set(instanceId, { instanceId, worker, leaseExpiresAt, updatedAt: Date.now() });\n this.persist();\n }\n\n /** Refresh the fencing watermark without moving the placement. */\n touch(instanceId: string, leaseExpiresAt: number): void {\n const record = this.table.get(instanceId);\n if (!record || leaseExpiresAt <= record.leaseExpiresAt) return;\n record.leaseExpiresAt = leaseExpiresAt;\n record.updatedAt = Date.now();\n this.persist();\n }\n\n delete(instanceId: string): void {\n if (this.table.delete(instanceId)) this.persist();\n }\n\n private persist(): void {\n if (!this.path) return;\n try {\n ensureDirExists(dirname(this.path));\n const snapshot = Object.fromEntries(this.table);\n const staged = `${this.path}.tmp`;\n writeFileSync(staged, JSON.stringify(snapshot, null, 2) + \"\\n\");\n renameSync(staged, this.path);\n } catch (err) {\n log.logWarning(\n \"Failed to persist Gondolin placement table\",\n err instanceof Error ? err.message : String(err),\n );\n }\n }\n}\n\nexport const gondolinPlacements = new GondolinPlacementStore();\n"]}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The single home of gondolin's crash-recovery vocabulary. Every transport
|
|
3
|
+
* classifies failures with these errors, and every policy site decides
|
|
4
|
+
* through the named predicates — the story reads in one place:
|
|
5
|
+
*
|
|
6
|
+
* - **Gone** (isRuntimeGone): the command never reached the runtime — the
|
|
7
|
+
* session socket refused, the lease lapsed, or the hosting worker vanished.
|
|
8
|
+
* Safe to recreate the runtime and retry; `withRuntime` (gondolin.ts)
|
|
9
|
+
* retries exactly once.
|
|
10
|
+
* - **Interrupted** (isRuntimeInterrupted): the runtime died (or went silent
|
|
11
|
+
* past the idle deadline) with the command in flight. Side effects may have
|
|
12
|
+
* landed, so the failure must surface; the session is discarded only when
|
|
13
|
+
* the runtime is confirmed dead.
|
|
14
|
+
* - **Lease-fenced** (isLeaseFencedStatus): the remote daemon rejected our
|
|
15
|
+
* lease — a newer epoch superseded it (409) or it expired (410). The cached
|
|
16
|
+
* lease is dropped and re-acquired once; the fleet's failover gate
|
|
17
|
+
* (assertFailoverAllowed) separately keeps a replacement placement fenced
|
|
18
|
+
* until the old lease's watermark passes.
|
|
19
|
+
*/
|
|
20
|
+
/**
|
|
21
|
+
* The runtime is gone and the command never reached it (the session socket
|
|
22
|
+
* refused the connection) — safe to recreate the runtime and retry.
|
|
23
|
+
*/
|
|
24
|
+
export declare class GondolinRuntimeGoneError extends Error {
|
|
25
|
+
}
|
|
26
|
+
/** The runtime died with the command in flight — not safe to retry blindly. */
|
|
27
|
+
export declare class GondolinRuntimeInterruptedError extends Error {
|
|
28
|
+
}
|
|
29
|
+
export declare function isRuntimeGone(error: unknown): error is GondolinRuntimeGoneError;
|
|
30
|
+
export declare function isRuntimeInterrupted(error: unknown): error is GondolinRuntimeInterruptedError;
|
|
31
|
+
/** 409 = a newer lease epoch superseded ours; 410 = our lease expired. */
|
|
32
|
+
export declare function isLeaseFencedStatus(status: number | undefined): boolean;
|
|
33
|
+
//# sourceMappingURL=gondolin-recovery.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gondolin-recovery.d.ts","sourceRoot":"","sources":["../../src/sandbox/gondolin-recovery.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH;;;GAGG;AACH,qBAAa,wBAAyB,SAAQ,KAAK;CAAG;AAEtD,+EAA+E;AAC/E,qBAAa,+BAAgC,SAAQ,KAAK;CAAG;AAE7D,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,wBAAwB,CAE/E;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,+BAA+B,CAE7F;AAED,0EAA0E;AAC1E,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAEvE"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The single home of gondolin's crash-recovery vocabulary. Every transport
|
|
3
|
+
* classifies failures with these errors, and every policy site decides
|
|
4
|
+
* through the named predicates — the story reads in one place:
|
|
5
|
+
*
|
|
6
|
+
* - **Gone** (isRuntimeGone): the command never reached the runtime — the
|
|
7
|
+
* session socket refused, the lease lapsed, or the hosting worker vanished.
|
|
8
|
+
* Safe to recreate the runtime and retry; `withRuntime` (gondolin.ts)
|
|
9
|
+
* retries exactly once.
|
|
10
|
+
* - **Interrupted** (isRuntimeInterrupted): the runtime died (or went silent
|
|
11
|
+
* past the idle deadline) with the command in flight. Side effects may have
|
|
12
|
+
* landed, so the failure must surface; the session is discarded only when
|
|
13
|
+
* the runtime is confirmed dead.
|
|
14
|
+
* - **Lease-fenced** (isLeaseFencedStatus): the remote daemon rejected our
|
|
15
|
+
* lease — a newer epoch superseded it (409) or it expired (410). The cached
|
|
16
|
+
* lease is dropped and re-acquired once; the fleet's failover gate
|
|
17
|
+
* (assertFailoverAllowed) separately keeps a replacement placement fenced
|
|
18
|
+
* until the old lease's watermark passes.
|
|
19
|
+
*/
|
|
20
|
+
/**
|
|
21
|
+
* The runtime is gone and the command never reached it (the session socket
|
|
22
|
+
* refused the connection) — safe to recreate the runtime and retry.
|
|
23
|
+
*/
|
|
24
|
+
export class GondolinRuntimeGoneError extends Error {
|
|
25
|
+
}
|
|
26
|
+
/** The runtime died with the command in flight — not safe to retry blindly. */
|
|
27
|
+
export class GondolinRuntimeInterruptedError extends Error {
|
|
28
|
+
}
|
|
29
|
+
export function isRuntimeGone(error) {
|
|
30
|
+
return error instanceof GondolinRuntimeGoneError;
|
|
31
|
+
}
|
|
32
|
+
export function isRuntimeInterrupted(error) {
|
|
33
|
+
return error instanceof GondolinRuntimeInterruptedError;
|
|
34
|
+
}
|
|
35
|
+
/** 409 = a newer lease epoch superseded ours; 410 = our lease expired. */
|
|
36
|
+
export function isLeaseFencedStatus(status) {
|
|
37
|
+
return status === 409 || status === 410;
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=gondolin-recovery.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gondolin-recovery.js","sourceRoot":"","sources":["../../src/sandbox/gondolin-recovery.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH;;;GAGG;AACH,MAAM,OAAO,wBAAyB,SAAQ,KAAK;CAAG;AAEtD,+EAA+E;AAC/E,MAAM,OAAO,+BAAgC,SAAQ,KAAK;CAAG;AAE7D,MAAM,UAAU,aAAa,CAAC,KAAc;IAC1C,OAAO,KAAK,YAAY,wBAAwB,CAAC;AACnD,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,KAAc;IACjD,OAAO,KAAK,YAAY,+BAA+B,CAAC;AAC1D,CAAC;AAED,0EAA0E;AAC1E,MAAM,UAAU,mBAAmB,CAAC,MAA0B;IAC5D,OAAO,MAAM,KAAK,GAAG,IAAI,MAAM,KAAK,GAAG,CAAC;AAC1C,CAAC","sourcesContent":["/**\n * The single home of gondolin's crash-recovery vocabulary. Every transport\n * classifies failures with these errors, and every policy site decides\n * through the named predicates — the story reads in one place:\n *\n * - **Gone** (isRuntimeGone): the command never reached the runtime — the\n * session socket refused, the lease lapsed, or the hosting worker vanished.\n * Safe to recreate the runtime and retry; `withRuntime` (gondolin.ts)\n * retries exactly once.\n * - **Interrupted** (isRuntimeInterrupted): the runtime died (or went silent\n * past the idle deadline) with the command in flight. Side effects may have\n * landed, so the failure must surface; the session is discarded only when\n * the runtime is confirmed dead.\n * - **Lease-fenced** (isLeaseFencedStatus): the remote daemon rejected our\n * lease — a newer epoch superseded it (409) or it expired (410). The cached\n * lease is dropped and re-acquired once; the fleet's failover gate\n * (assertFailoverAllowed) separately keeps a replacement placement fenced\n * until the old lease's watermark passes.\n */\n\n/**\n * The runtime is gone and the command never reached it (the session socket\n * refused the connection) — safe to recreate the runtime and retry.\n */\nexport class GondolinRuntimeGoneError extends Error {}\n\n/** The runtime died with the command in flight — not safe to retry blindly. */\nexport class GondolinRuntimeInterruptedError extends Error {}\n\nexport function isRuntimeGone(error: unknown): error is GondolinRuntimeGoneError {\n return error instanceof GondolinRuntimeGoneError;\n}\n\nexport function isRuntimeInterrupted(error: unknown): error is GondolinRuntimeInterruptedError {\n return error instanceof GondolinRuntimeInterruptedError;\n}\n\n/** 409 = a newer lease epoch superseded ours; 410 = our lease expired. */\nexport function isLeaseFencedStatus(status: number | undefined): boolean {\n return status === 409 || status === 410;\n}\n"]}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { GondolinRemoteWorkerSettings } from "../types.js";
|
|
2
|
+
import { createSessionFrameParser, encodeSessionMessage } from "./gondolin-contract.js";
|
|
2
3
|
import { type GondolinRuntimeHandle, type GondolinRuntimeSpec, type SessionClient, type SessionClientCallbacks } from "./gondolin-worker-client.js";
|
|
3
4
|
import type { ExecResult } from "./types.js";
|
|
4
5
|
interface RemoteResponse {
|
|
@@ -16,10 +17,7 @@ export interface GondolinRemoteOverrides {
|
|
|
16
17
|
/** Reports lease grants/renewals so the fleet can persist fencing watermarks. */
|
|
17
18
|
onLeaseActivity?: (instanceId: string, expiresAtMs: number) => void;
|
|
18
19
|
}
|
|
19
|
-
|
|
20
|
-
export declare function createSessionFrameParser(callbacks: SessionClientCallbacks): (chunk: Buffer) => void;
|
|
21
|
-
/** Encodes a client-to-daemon session message: u32be length + JSON. */
|
|
22
|
-
export declare function encodeSessionMessage(message: object): Buffer;
|
|
20
|
+
export { createSessionFrameParser, encodeSessionMessage };
|
|
23
21
|
/**
|
|
24
22
|
* One mikan-worker daemon as seen from mikan: mTLS requests, per-instance
|
|
25
23
|
* fenced leases with heartbeat renewal, and per-command upgraded tunnels.
|
|
@@ -69,5 +67,4 @@ export declare class GondolinRemoteConnection {
|
|
|
69
67
|
private openTunnel;
|
|
70
68
|
private tlsOptions;
|
|
71
69
|
}
|
|
72
|
-
export {};
|
|
73
70
|
//# sourceMappingURL=gondolin-remote.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gondolin-remote.d.ts","sourceRoot":"","sources":["../../src/sandbox/gondolin-remote.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,aAAa,CAAC;AAEhE,OAAO,
|
|
1
|
+
{"version":3,"file":"gondolin-remote.d.ts","sourceRoot":"","sources":["../../src/sandbox/gondolin-remote.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,7 +3,9 @@ import { request as httpsRequest } from "node:https";
|
|
|
3
3
|
import { relative, isAbsolute, join } from "node:path";
|
|
4
4
|
import * as log from "../log.js";
|
|
5
5
|
import { SandboxError } from "./errors.js";
|
|
6
|
-
import {
|
|
6
|
+
import { createSessionFrameParser, encodeSessionMessage, } from "./gondolin-contract.js";
|
|
7
|
+
import { GondolinRuntimeGoneError, isLeaseFencedStatus } from "./gondolin-recovery.js";
|
|
8
|
+
import { execOverSessionConnect, } from "./gondolin-worker-client.js";
|
|
7
9
|
const LEASE_TTL_SECONDS = 300;
|
|
8
10
|
const REQUEST_TIMEOUT_MS = 15_000;
|
|
9
11
|
/** VM boot happens inside this request; the daemon's own handshake cap is 2 min. */
|
|
@@ -11,38 +13,9 @@ const ENSURE_TIMEOUT_MS = 150_000;
|
|
|
11
13
|
/** A request that never reached the daemon (network/TLS/timeout failure). */
|
|
12
14
|
export class GondolinWorkerUnreachableError extends Error {
|
|
13
15
|
}
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
return (chunk) => {
|
|
18
|
-
buffer = Buffer.concat([buffer, chunk]);
|
|
19
|
-
while (buffer.length >= 5) {
|
|
20
|
-
const type = buffer.readUInt8(0);
|
|
21
|
-
const length = buffer.readUInt32BE(1);
|
|
22
|
-
if (buffer.length < 5 + length)
|
|
23
|
-
return;
|
|
24
|
-
const payload = buffer.subarray(5, 5 + length);
|
|
25
|
-
buffer = buffer.subarray(5 + length);
|
|
26
|
-
if (type === 1) {
|
|
27
|
-
callbacks.onBinary(Buffer.from(payload));
|
|
28
|
-
continue;
|
|
29
|
-
}
|
|
30
|
-
try {
|
|
31
|
-
callbacks.onJson(JSON.parse(payload.toString("utf8")));
|
|
32
|
-
}
|
|
33
|
-
catch {
|
|
34
|
-
// ignore malformed frames
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
|
-
/** Encodes a client-to-daemon session message: u32be length + JSON. */
|
|
40
|
-
export function encodeSessionMessage(message) {
|
|
41
|
-
const payload = Buffer.from(JSON.stringify(message));
|
|
42
|
-
const header = Buffer.alloc(4);
|
|
43
|
-
header.writeUInt32BE(payload.length, 0);
|
|
44
|
-
return Buffer.concat([header, payload]);
|
|
45
|
-
}
|
|
16
|
+
// The framing lives with the rest of the wire contract; re-exported here for
|
|
17
|
+
// existing importers.
|
|
18
|
+
export { createSessionFrameParser, encodeSessionMessage };
|
|
46
19
|
/**
|
|
47
20
|
* One mikan-worker daemon as seen from mikan: mTLS requests, per-instance
|
|
48
21
|
* fenced leases with heartbeat renewal, and per-command upgraded tunnels.
|
|
@@ -86,15 +59,15 @@ export class GondolinRemoteConnection {
|
|
|
86
59
|
const lease = await this.leaseFor(instanceId);
|
|
87
60
|
const response = await this.request("POST", "/v1/runtimes", body, { ...this.leaseHeaders(lease), "Idempotency-Key": idempotencyKey }, ENSURE_TIMEOUT_MS);
|
|
88
61
|
if (response.status === 200) {
|
|
62
|
+
const runtime = response.json;
|
|
89
63
|
return {
|
|
90
|
-
sessionId:
|
|
64
|
+
sessionId: runtime.sessionId ?? "",
|
|
91
65
|
instanceId,
|
|
92
|
-
|
|
93
|
-
workerPid: response.json.workerPid ?? 0,
|
|
66
|
+
workerPid: runtime.workerPid ?? 0,
|
|
94
67
|
fingerprint: spec.fingerprint,
|
|
95
68
|
};
|
|
96
69
|
}
|
|
97
|
-
if ((response.status
|
|
70
|
+
if (isLeaseFencedStatus(response.status) && attempt === 0) {
|
|
98
71
|
this.dropLease(instanceId);
|
|
99
72
|
continue;
|
|
100
73
|
}
|
|
@@ -104,7 +77,7 @@ export class GondolinRemoteConnection {
|
|
|
104
77
|
async stop(handle) {
|
|
105
78
|
const lease = await this.leaseFor(handle.instanceId);
|
|
106
79
|
const response = await this.request("DELETE", `/v1/runtimes/${handle.sessionId}`, undefined, this.leaseHeaders(lease));
|
|
107
|
-
if (response.status
|
|
80
|
+
if (isLeaseFencedStatus(response.status)) {
|
|
108
81
|
this.dropLease(handle.instanceId);
|
|
109
82
|
}
|
|
110
83
|
this.releaseLease(handle.instanceId);
|
|
@@ -321,7 +294,7 @@ export class GondolinRemoteConnection {
|
|
|
321
294
|
});
|
|
322
295
|
});
|
|
323
296
|
request.on("response", (response) => {
|
|
324
|
-
if (response.statusCode
|
|
297
|
+
if (isLeaseFencedStatus(response.statusCode)) {
|
|
325
298
|
this.dropLease(instanceId);
|
|
326
299
|
}
|
|
327
300
|
const error = new Error(`tunnel refused: HTTP ${response.statusCode}`);
|