CultLib/packages/cultnet-ts/test/idunn-runtime-authority.test.ts
Meta Vens 564d5bf732
Some checks failed
CultMesh portability and performance / ubuntu-latest one-command multiplayer onboarding (push) Has been cancelled
CultMesh portability and performance / windows-latest one-command multiplayer onboarding (push) Has been cancelled
CultMesh portability and performance / ubuntu-latest reactive semantics and leases (push) Has been cancelled
CultMesh portability and performance / windows-latest reactive semantics and leases (push) Has been cancelled
Fix Idunn runtime presence RUDP publication
2026-09-28 02:11:12 +02:00

223 lines
11 KiB
TypeScript

import { mock, test } from "node:test";
import assert from "node:assert/strict";
import crypto from "node:crypto";
import dgram from "node:dgram";
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
import { mkdtempSync, rmSync, writeFileSync } from "node:fs";
import { decode, encode } from "@msgpack/msgpack";
import {
createIdunnRuntimePresencePublisher,
loadIdunnRuntimeAuthorityFromEnvironment,
signIdunnRuntimePresence,
systemdListenPidMatches,
} from "../src/idunn-runtime-authority";
import { CultNetRudpSession, decodeRudpPacket, encodeRudpPacket } from "../src/rudp";
import {
runtimePresenceActivationSigningMessage,
runtimePresenceProofPayload,
runtimePresenceProviderSigningMessage,
} from "../src/runtime-presence-health";
const providerIdentityContext = "gamecult-provider-health-identity-v1";
const providerIdDomain = Buffer.from("gamecult.provider-health.identity.v1\0", "utf8");
const activationIdDomain = Buffer.from("idunn.runtime-activation.id.v1\0", "utf8");
test("matches systemd's host PID for the private PID namespace init only", () => {
assert.equal(systemdListenPidMatches(String(process.pid), process.pid), true);
assert.equal(systemdListenPidMatches("1725346", 1), true);
assert.equal(systemdListenPidMatches("1725346", 2), false);
assert.equal(systemdListenPidMatches("not-a-pid", 1), false);
assert.equal(systemdListenPidMatches(undefined, 1), false);
});
test("opens Idunn identity and publishes valid CultNet data while surfacing piggybacked application errors", async (context) => {
const directory = mkdtempSync(path.join(os.tmpdir(), "cultnet-runtime-authority-"));
context.after(() => rmSync(directory, { recursive: true, force: true }));
const machineId = "1234567890abcdef1234567890abcdef";
const providerSeed = Buffer.alloc(32, 0x31);
const activationSeed = Buffer.alloc(32, 0x72);
const providerKey = privateKeyFromSeed(providerSeed);
const activationKey = privateKeyFromSeed(activationSeed);
const providerPublic = rawPublic(crypto.createPublicKey(providerKey));
const activationPublic = rawPublic(crypto.createPublicKey(activationKey));
const providerIdentity = sha256Hex(Buffer.concat([providerIdDomain, providerPublic]));
const activationIdentity = sha256Hex(Buffer.concat([activationIdDomain, activationPublic]));
const target = "streampixels-service";
const contract = "streampixels-service.cultnet-rudp-service-health";
const candidate = "http://127.0.0.1:18831";
const expectedValues = [
"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,
["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"]],
];
const expectedBytes = Buffer.from(encode(expectedValues));
const expectedSha = `sha256-${sha256Hex(expectedBytes)}`;
const activationValues = [
"idunn.runtime_activation.v2", expectedSha, "streampixels-service-yggdrasil",
`sha256-${"6".repeat(64)}`, activationIdentity, activationPublic, Date.now(),
"7".repeat(64), "ed25519", new Uint8Array(64).fill(0x17),
];
const bundle = path.join(directory, "bundle");
fs.mkdirSync(bundle);
writeFileSync(path.join(bundle, "expected.cc"), cultCacheStore(
"idunn.expected_incarnation", "idunn.expected_incarnation.v2", "expected", expectedBytes,
));
writeFileSync(path.join(bundle, "activation.cc"), cultCacheStore(
"idunn.runtime_activation", "idunn.runtime_activation.v2", "activation", Buffer.from(encode(activationValues)),
));
const binding = `${providerIdentityContext}:machine-id-sha256:${sha256Hex(Buffer.from(machineId))}`;
const mask = crypto.createHash("sha256").update(Buffer.concat([
Buffer.from("gamecult-linux-service-seed-v1\0", "utf8"),
Buffer.from(providerIdentityContext, "utf8"),
Buffer.from(binding, "utf8"),
])).digest();
const protectedSeed = Buffer.from(providerSeed.map((value, index) => value ^ mask[index]!));
const providerCredential = Buffer.from(encode([[
"gamecult-provider-health-identity",
"gamecult.provider_health_identity.private.v1",
Buffer.from(encode([
"gamecult.provider_health_identity.private.v1", providerIdentity, Array.from(providerPublic), Array.from(protectedSeed),
"linux_file_mode_machine_id_binding", binding, "v1", "os_installation_file_bound_cloneable_baseline",
"2026-01-01T00:00:00Z", Array(32).fill(0x2a),
])),
"2026-01-01T00:00:00Z",
"gamecult.provider_health_identity.private.v1",
]]));
let descriptorProviderCredential = providerCredential;
const originalEnvironment = { ...process.env };
context.after(() => {
for (const key of Object.keys(process.env)) if (!(key in originalEnvironment)) delete process.env[key];
Object.assign(process.env, originalEnvironment);
});
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");
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";
const realReadFileSync = fs.readFileSync.bind(fs);
mock.method(fs, "readFileSync", (filePath: fs.PathOrFileDescriptor, ...args: unknown[]) => {
if (filePath === 3) return activationSeed;
if (filePath === 4) return descriptorProviderCredential;
if (filePath === "/etc/machine-id") return machineId;
return realReadFileSync(filePath as never, ...args as never[]);
});
const authority = loadIdunnRuntimeAuthorityFromEnvironment(target, contract, "127.0.0.1:17871");
const signed = signIdunnRuntimePresence(authority, {
capabilities: [{ capability: "streampixels.service.api", schema: "streampixels.api.v1", compatibility: "v1", capacity: 1 }],
state: "warming",
detail: "starting",
writeLeaseSha256: null,
publisherSequence: 1,
observedAtUnixMillis: Date.now(),
});
const proof = runtimePresenceProofPayload(signed.presence);
assert.equal((decode(expectedBytes) as unknown[]).length, 18);
assert.equal(signed.presence.expectedProjectionSha256, expectedSha);
const signedRecord = decode(signed.payload) as unknown[];
assert.equal(crypto.verify(null, runtimePresenceProviderSigningMessage(proof), crypto.createPublicKey(providerKey), Buffer.from(signedRecord[21] as Uint8Array)), true);
assert.equal(crypto.verify(null, runtimePresenceActivationSigningMessage(proof), crypto.createPublicKey(activationKey), Buffer.from(signedRecord[23] as Uint8Array)), true);
const peer = dgram.createSocket("udp4");
await new Promise<void>((resolve, reject) => {
peer.once("error", reject);
peer.bind(0, "127.0.0.1", resolve);
});
context.after(() => peer.close());
const address = peer.address();
assert.equal(typeof address, "object");
const peerPort = (address as { port: number }).port;
let serverSession: CultNetRudpSession | undefined;
let receivedMessage: unknown;
let responseAck: number | undefined;
let peerFailure: Error | undefined;
peer.on("message", (wire, remote) => {
try {
const packet = decodeRudpPacket(wire);
if (packet.packetType === "connect") {
serverSession = new CultNetRudpSession({ connectionId: packet.connectionId, initialSequence: 100 });
const accept = serverSession.acceptConnect(packet, Date.now());
peer.send(encodeRudpPacket(accept), remote.port, remote.address);
return;
}
if (!serverSession) throw new Error("Publisher sent data before establishing RUDP.");
const result = serverSession.receive(packet, Date.now());
const frame = result.delivered.find((candidate) => candidate.channelId === "schema");
if (!frame) return;
receivedMessage = decode(frame.payload);
const errorPayload = encode({
schemaVersion: "cultnet.error.v0",
error: "test admission denied",
routingHint: null,
code: null,
details: null,
});
const [response] = serverSession.sendMany("schema", errorPayload, {
reliable: true,
ordered: true,
nowMs: Date.now(),
});
assert.ok(response);
responseAck = response.ack;
peer.send(encodeRudpPacket(response), remote.port, remote.address);
} catch (error) {
peerFailure = error as Error;
}
});
const publisher = createIdunnRuntimePresencePublisher({
authority,
endpoint: `rudp://127.0.0.1:${peerPort}`,
healthContract: contract,
capabilities: [{ capability: "streampixels.service.api", schema: "streampixels.api.v1", compatibility: "v1", capacity: 1 }],
});
await assert.rejects(publisher.publish("warming", "local RUDP integration"), /Odin rejected runtime presence: test admission denied/);
assert.deepEqual(receivedMessage && (receivedMessage as { schemaVersion?: string }).schemaVersion, "cultnet.document_put_raw.v0");
assert.ok(Buffer.from(encode(receivedMessage)).byteLength > 0);
assert.equal(responseAck, 2, "the response data packet must acknowledge the publisher's reliable schema packet");
assert.equal(peerFailure, undefined, peerFailure?.message);
descriptorProviderCredential = Buffer.from(encode([
...(decode(providerCredential) as unknown[][]),
...(decode(providerCredential) as unknown[][]),
]));
assert.throws(
() => loadIdunnRuntimeAuthorityFromEnvironment(target, contract, "127.0.0.1:17871"),
/exactly one envelope/,
);
});
function cultCacheStore(type: string, schemaId: string, key: string, payload: Uint8Array): Buffer {
return Buffer.from(encode([
"cultcache.store.v1",
[[schemaId, type, `${schemaId}.v1`, schemaId, "{}", [schemaId], []]],
[[key, schemaId, "2026-01-01T00:00:00Z", payload]],
]));
}
function privateKeyFromSeed(seed: Uint8Array): crypto.KeyObject {
return crypto.createPrivateKey({
key: Buffer.concat([Buffer.from("302e020100300506032b657004220420", "hex"), Buffer.from(seed)]),
format: "der",
type: "pkcs8",
});
}
function rawPublic(key: crypto.KeyObject): Buffer {
const der = key.export({ type: "spki", format: "der" }) as Buffer;
return Buffer.from(der.subarray(der.length - 32));
}
function sha256Hex(bytes: Uint8Array): string {
return crypto.createHash("sha256").update(bytes).digest("hex");
}