"use strict"; const assert = require("node:assert/strict"); const crypto = require("node:crypto"); const fs = require("node:fs"); const os = require("node:os"); const path = require("node:path"); const test = require("node:test"); const { GhdrAuthorizer } = require("./ghdr-authorizer"); const { GhdrControllerBroker } = require("./ghdr-controller-broker"); test("two outbound controllers poll one email-authorized job and return independent layout signatures", async () => { const directory = fs.mkdtempSync(path.join(os.tmpdir(), "ghdr-broker-")); const now = Math.floor(Date.now() / 1000); const nodes = [ makeController("GH-CTRL-GZ-01", "tencent/ap-guangzhou/BS-GZ-006"), makeController("GH-CTRL-SG-01", "tencent/ap-singapore/ZY-SG-006"), ]; const authorizer = new GhdrAuthorizer({ privateKeyFile: path.join(directory, "authorizer.pem"), now: () => now, }); const broker = new GhdrControllerBroker({ controllers: nodes.map(item => item.binding), stateDir: path.join(directory, "jobs"), authorizer, now: () => now, waitMs: 2000, }); const plan = { schema: "guanghu.ghdr-signed-layout-plan/v1", payload: { node_id: "GH-CVM-MAIN-PROD-01", generation: 1, }, signatures: [], }; const digest = crypto.createHash("sha256").update(JSON.stringify(plan.payload)).digest("hex"); const binding = { payload_sha256: digest, resource: `GH-CVM-MAIN-PROD-01:${digest}:1`, }; try { const pending = broker.queueAndWait({ plan, binding, workorderId: "00000000-0000-4000-8000-000000000001", }); const submitted = []; for (const node of nodes) { const poll = { schema: "guanghu.ghdr-controller-poll/v1", node_id: node.binding.node_id, issued_at_unix: now, nonce: crypto.randomBytes(24).toString("base64url"), }; const body = { request: poll, request_signature_hex: crypto.sign(null, Buffer.from(JSON.stringify(poll)), node.transport.privateKey).toString("hex"), }; const job = broker.poll(body).job; assert.ok(job); assert.equal(broker.poll(body).error, "ghdr_controller_auth_replayed"); const layoutSignatureHex = crypto.sign( null, Buffer.from(JSON.stringify(plan.payload)), node.layout.privateKey, ).toString("hex"); const result = { schema: "guanghu.ghdr-controller-result/v1", node_id: node.binding.node_id, job_id: job.job_id, layout_payload_sha256: digest, signature_hex: layoutSignatureHex, issued_at_unix: now, nonce: crypto.randomBytes(24).toString("base64url"), }; const signature = { node_id: node.binding.node_id, failure_domain: node.binding.failure_domain, public_key_hex: node.binding.layout_public_key_hex, signature_hex: layoutSignatureHex, }; assert.equal(broker.submit({ request: result, request_signature_hex: crypto.sign(null, Buffer.from(JSON.stringify(result)), node.transport.privateKey).toString("hex"), signature, }).ok, true); submitted.push(signature); } const completed = await pending; assert.equal(completed.ok, true); assert.deepEqual(completed.signatures, submitted); } finally { fs.rmSync(directory, { recursive: true, force: true }); } }); function makeController(nodeId, failureDomain) { const layout = crypto.generateKeyPairSync("ed25519"); const transport = crypto.generateKeyPairSync("ed25519"); return { layout, transport, binding: { node_id: nodeId, failure_domain: failureDomain, layout_public_key_hex: rawPublic(layout.publicKey), transport_public_key_hex: rawPublic(transport.publicKey), }, }; } function rawPublic(key) { return key.export({ type: "spki", format: "der" }).subarray(-32).toString("hex"); }