From 542ddd3e5830ad7dc44e69298e5469f97f992422 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Mon, 28 Sep 2026 03:54:21 +0200 Subject: [PATCH] Bind runtime presence to route challenges --- .../cultnet-ts/src/idunn-runtime-authority.ts | 32 ++++++++++++++----- .../test/idunn-runtime-authority.test.ts | 15 +++++++-- 2 files changed, 36 insertions(+), 11 deletions(-) diff --git a/packages/cultnet-ts/src/idunn-runtime-authority.ts b/packages/cultnet-ts/src/idunn-runtime-authority.ts index af294c3f..b675d5c3 100644 --- a/packages/cultnet-ts/src/idunn-runtime-authority.ts +++ b/packages/cultnet-ts/src/idunn-runtime-authority.ts @@ -13,7 +13,7 @@ import { encodeRuntimePresenceHealth, type RuntimePresenceHealth, } from "./runtime-presence-health"; -import { encodeCultNetMessageForWire, parseCultNetMessage, type CultNetRawDocumentRecord } from "./contracts"; +import { encodeCultNetMessageForWire, parseCultNetMessage, type CultNetRawDocumentRecord, type CultNetSnapshotRequestMessage } from "./contracts"; import { CultNetRudpSession, decodeRudpPacket, encodeRudpPacket } from "./rudp"; import type { CultNetRudpPacket } from "./rudp"; import dgram from "node:dgram"; @@ -80,6 +80,7 @@ export type IdunnRuntimePresencePublisher = { readonly runtimeInstanceId: string; readonly requiresWriteLease: boolean; latestPresenceDocument(): CultNetRawDocumentRecord | null; + publishRouteObservation(request: CultNetSnapshotRequestMessage): Promise; publish(state: RuntimePresenceHealth["state"], detail: string): Promise; waitForWriteLease(options?: { pollIntervalMs?: number; signal?: AbortSignal }): Promise; assertWriteLease(): Promise; @@ -268,17 +269,32 @@ export function createIdunnRuntimePresencePublisher( return signed.canonicalSha256; }; + const copyLatestPresenceDocument = (): CultNetRawDocumentRecord | null => { + if (!latestPresenceDocument) return null; + return { + ...latestPresenceDocument, + payload: new Uint8Array(latestPresenceDocument.payload), + ...(latestPresenceDocument.tags ? { tags: [...latestPresenceDocument.tags] } : {}), + }; + }; + return { runtimeId: expected.runtimeId, runtimeInstanceId: options.authority.activation.runtimeInstanceId, requiresWriteLease: expected.writeLeaseRequired, - latestPresenceDocument() { - if (!latestPresenceDocument) return null; - return { - ...latestPresenceDocument, - payload: new Uint8Array(latestPresenceDocument.payload), - ...(latestPresenceDocument.tags ? { tags: [...latestPresenceDocument.tags] } : {}), - }; + latestPresenceDocument: copyLatestPresenceDocument, + async publishRouteObservation(request) { + if (!request.messageId || request.messageId.trim() !== request.messageId) throw new Error("Idunn route observation requires a message id."); + if ((request.schemaIds && !request.schemaIds.includes(GAMECULT_RUNTIME_PRESENCE_HEALTH_SCHEMA)) + || (request.recordKeys && !request.recordKeys.includes(expected.target)) + || request.shardId !== undefined + || request.shardEpoch !== undefined) { + throw new Error("Idunn route observation does not request this runtime presence document."); + } + await publish("active", `route-observation:${request.messageId}`); + const document = copyLatestPresenceDocument(); + if (!document) throw new Error("Idunn route observation was published without a presence document."); + return document; }, publish, async waitForWriteLease({ pollIntervalMs = 5000, signal } = {}) { diff --git a/packages/cultnet-ts/test/idunn-runtime-authority.test.ts b/packages/cultnet-ts/test/idunn-runtime-authority.test.ts index 6dcdc956..7969fde2 100644 --- a/packages/cultnet-ts/test/idunn-runtime-authority.test.ts +++ b/packages/cultnet-ts/test/idunn-runtime-authority.test.ts @@ -19,6 +19,7 @@ import { runtimePresenceActivationSigningMessage, runtimePresenceProofPayload, runtimePresenceProviderSigningMessage, + RUNTIME_PRESENCE_SLOT, } from "../src/runtime-presence-health"; const providerIdentityContext = "gamecult-provider-health-identity-v1"; @@ -53,7 +54,7 @@ test("opens Idunn identity and publishes valid CultNet data while surfacing pigg "idunn.expected_incarnation.v2", target, `sha256-${"1".repeat(64)}`, "incarnation-1", `sha256-${"2".repeat(64)}`, "https://github.com/GameCult/StreamPixels.git", "a".repeat(40), `sha256-${"3".repeat(64)}`, "streampixels-service-yggdrasil", providerIdentity, contract, - `sha256-${"4".repeat(64)}`, "service-boundary-v1", `sha256-${"5".repeat(64)}`, true, + `sha256-${"4".repeat(64)}`, "service-boundary-v1", `sha256-${"5".repeat(64)}`, false, ["streampixels-service-http", "http", "http://127.0.0.1:8831", candidate], [["streampixels.service.api", "streampixels.api.v1", "v1", 1]], [["shared-infrastructure", "odin.verse-rendezvous", "odin.verse-topology.v1", "v1", 1, "before-promotion", null, null, null, "rudp://127.0.0.1:17871"]], @@ -101,7 +102,7 @@ test("opens Idunn identity and publishes valid CultNet data while surfacing pigg }); process.env.GAMECULT_IDUNN_RUNTIME_BUNDLE = bundle; process.env.GAMECULT_IDUNN_CANDIDATE_BIND = candidate; - process.env.GAMECULT_IDUNN_PROCESS_WRITE_LEASE = path.join(directory, "lease.cc"); + delete process.env.GAMECULT_IDUNN_PROCESS_WRITE_LEASE; process.env.LISTEN_PID = String(process.pid); process.env.LISTEN_FDS = "2"; process.env.LISTEN_FDNAMES = "gamecult-idunn-runtime-activation-key:gamecult-runtime-presence-identity"; @@ -195,12 +196,20 @@ test("opens Idunn identity and publishes valid CultNet data while surfacing pigg rejectOdinAdmission = false; await publisher.publish("warming", "accepted presence"); + const snapshotDocument = await publisher.publishRouteObservation({ + schemaVersion: "cultnet.snapshot_request.v0", + messageId: "route-challenge-1", + schemaIds: ["gamecult.runtime_presence_health.v2"], + recordKeys: [target], + }); const publishedDocument = (receivedMessage as { document: { payload: Uint8Array; schemaId: string; recordKey: string } }).document; - const snapshotDocument = publisher.latestPresenceDocument(); assert.ok(snapshotDocument); assert.equal(snapshotDocument.schemaId, publishedDocument.schemaId); assert.equal(snapshotDocument.recordKey, publishedDocument.recordKey); assert.deepEqual(Buffer.from(snapshotDocument.payload), Buffer.from(publishedDocument.payload)); + const routePresence = decode(snapshotDocument.payload) as unknown[]; + assert.equal(routePresence[RUNTIME_PRESENCE_SLOT.state], "active"); + assert.equal(routePresence[RUNTIME_PRESENCE_SLOT.detail], "route-observation:route-challenge-1"); snapshotDocument.payload[0] = snapshotDocument.payload[0]! ^ 0xff; assert.deepEqual(Buffer.from(publisher.latestPresenceDocument()?.payload ?? []), Buffer.from(publishedDocument.payload), "snapshot readers cannot mutate publisher state");