Bind runtime presence to route challenges
This commit is contained in:
parent
265f716391
commit
542ddd3e58
2 changed files with 36 additions and 11 deletions
|
|
@ -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<CultNetRawDocumentRecord>;
|
||||
publish(state: RuntimePresenceHealth["state"], detail: string): Promise<string>;
|
||||
waitForWriteLease(options?: { pollIntervalMs?: number; signal?: AbortSignal }): Promise<string>;
|
||||
assertWriteLease(): Promise<string>;
|
||||
|
|
@ -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 } = {}) {
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue