feat(device-plane): add typed B2 service ping transport

This commit is contained in:
Codex
2026-08-12 22:57:09 +03:00
parent bdb85cb4f7
commit 4b73a15765
24 changed files with 1322 additions and 88 deletions
@@ -255,6 +255,58 @@ test("management API exposes a repository idempotency conflict without retrying"
}
});
test("typed service ping accepts a transient access code and never echoes it", async () => {
const projectRef = "project:11111111-1111-4111-8111-111111111111";
const deviceRef = "device:22222222-2222-4222-8222-222222222222";
let planned;
const runtime = await startTestServer({
managementApiEnabled: true,
managementToken,
repository: {
health: async () => "ready",
executeManagementCommand: async () => ({ replayed: false, result: {} }),
},
typedCommandRuntime: {
status: () => ({ commandTransport: "typed-service-ping-v1" }),
planServicePing: async (value) => {
planned = value;
return {
replayed: false,
command: {
commandRef: "command:33333333-3333-4333-8333-333333333333",
deviceRef,
commandType: "service.ping",
lifecycleState: "queued",
},
};
},
},
});
try {
const response = await fetch(
`${runtime.baseUrl}/internal/v1/commands:service-ping`,
{
method: "POST",
headers: managementHeaders(),
body: JSON.stringify({
projectRef,
deviceRef,
accessCode: "654321",
expiresInSeconds: 300,
}),
},
);
assert.equal(response.status, 200);
const body = await response.json();
assert.equal(body.result.lifecycleState, "queued");
assert.equal(JSON.stringify(body).includes("654321"), false);
assert.equal(planned.input.accessCode, "654321");
assert.equal(planned.idempotencyKey, "phase2-test-0001");
} finally {
await runtime.close();
}
});
test("project query is service-authenticated and forwards only the trusted actor", async () => {
let queriedActor;
const runtime = await startTestServer({
@@ -424,12 +476,15 @@ test("gateway message endpoint returns acceptance only after repository commit",
acceptAdapterMessage: async (value) => {
stored = value;
return {
schemaVersion: "nodedc.device-adapter-acceptance.v1",
acceptanceRef: "acceptance:test-001",
idempotencyKey: value.safeView.idempotencyKey,
status: "accepted",
replayed: false,
acceptedAt: "2026-08-11T12:00:00.000Z",
acceptance: {
schemaVersion: "nodedc.device-adapter-acceptance.v1",
acceptanceRef: "acceptance:test-001",
idempotencyKey: value.safeView.idempotencyKey,
status: "accepted",
replayed: false,
acceptedAt: "2026-08-11T12:00:00.000Z",
},
claimedDeviceRef: "device:11111111-1111-4111-8111-111111111111",
};
},
},
@@ -25,12 +25,15 @@ test("shared gateway ingest masks identifiers for HTTP and Edge callers", async
async acceptAdapterMessage(value) {
stored.push(value);
return {
schemaVersion: "nodedc.device-adapter-acceptance.v1",
acceptanceRef: "acceptance:test",
idempotencyKey: value.safeView.idempotencyKey,
status: "accepted",
replayed: false,
acceptedAt: "2026-08-11T12:00:00.000Z",
acceptance: {
schemaVersion: "nodedc.device-adapter-acceptance.v1",
acceptanceRef: "acceptance:test",
idempotencyKey: value.safeView.idempotencyKey,
status: "accepted",
replayed: false,
acceptedAt: "2026-08-11T12:00:00.000Z",
},
claimedDeviceRef: "device:11111111-1111-4111-8111-111111111111",
};
},
},
@@ -40,7 +43,11 @@ test("shared gateway ingest masks identifiers for HTTP and Edge callers", async
const acceptance = await ingest.acceptMessage(adapterMessage());
assert.equal(discovery.value.identifier.masked, "***********0001");
assert.equal(acceptance.status, "accepted");
assert.equal(acceptance.value.status, "accepted");
assert.equal(
acceptance.claimedDeviceRef,
"device:11111111-1111-4111-8111-111111111111",
);
assert.match(stored[0].identifierDigest, /^hmac-sha256:[a-f0-9]{64}$/);
assert.match(stored[1].requestDigest, /^sha256:[a-f0-9]{64}$/);
assert.equal(JSON.stringify(stored).includes(rawImei), false);
@@ -22,10 +22,11 @@ test("commits a gateway receipt before returning Core acceptance", async () => {
const result = await acceptGatewayMessage(messageInput(client));
assert.equal(result.status, "accepted");
assert.equal(result.replayed, false);
assert.equal(result.idempotencyKey, idempotencyKey);
assert.equal(result.acceptedAt, acceptedAt.toISOString());
assert.equal(result.acceptance.status, "accepted");
assert.equal(result.acceptance.replayed, false);
assert.equal(result.acceptance.idempotencyKey, idempotencyKey);
assert.equal(result.acceptance.acceptedAt, acceptedAt.toISOString());
assert.equal(result.claimedDeviceRef, null);
assert.equal(client.remaining(), 0);
assert.equal(client.released, true);
});
@@ -47,8 +48,8 @@ test("replays one durable receipt for the same normalized request", async () =>
const result = await acceptGatewayMessage(messageInput(client));
assert.equal(result.status, "accepted");
assert.equal(result.replayed, true);
assert.equal(result.acceptance.status, "accepted");
assert.equal(result.acceptance.replayed, true);
assert.equal(client.remaining(), 0);
assert.equal(client.released, true);
});
@@ -0,0 +1,106 @@
import assert from "node:assert/strict";
import test from "node:test";
import { createTypedCommandRuntime } from "../src/typed-command-runtime.mjs";
const projectRef = "project:11111111-1111-4111-8111-111111111111";
const deviceRef = "device:22222222-2222-4222-8222-222222222222";
test("keeps the B2 access code transient and emits only a typed offer", async () => {
const planned = [];
const dispatched = [];
const runtime = createTypedCommandRuntime({
now: () => new Date("2026-08-12T18:00:00.000Z"),
repository: {
async planTypedServicePing(value) {
planned.push(value);
return {
replayed: false,
commandId: "33333333-3333-4333-8333-333333333333",
command: {
lifecycleState: "queued",
expiresAt: "2026-08-12T18:05:00.000Z",
},
};
},
async dispatchTypedCommand(value) {
dispatched.push(value);
return { lifecycleState: "dispatched" };
},
async recordTypedCommandStatus() {},
},
});
await runtime.planServicePing({
idempotencyKey: "idem-00000001",
actor: { userRef: "user:test" },
input: { projectRef, deviceRef, accessCode: "123456", expiresInSeconds: 300 },
});
assert.equal(JSON.stringify(planned).includes("123456"), false);
const offer = await runtime.offerForDevice(deviceRef);
assert.equal(offer.commandType, "service.ping");
assert.equal(offer.accessCode, "123456");
assert.match(offer.transportMessageRef, /^edge-command:/);
assert.equal(dispatched.length, 1);
});
test("expires a transient authorization through the durable ledger", async () => {
let current = new Date("2026-08-12T18:00:00.000Z");
const dispatches = [];
const runtime = createTypedCommandRuntime({
now: () => current,
repository: {
async planTypedServicePing() {
return {
replayed: false,
commandId: "33333333-3333-4333-8333-333333333333",
command: {
lifecycleState: "queued",
expiresAt: "2026-08-12T18:00:30.000Z",
},
};
},
async dispatchTypedCommand(value) {
dispatches.push(value);
return null;
},
async recordTypedCommandStatus() {},
},
});
await runtime.planServicePing({
idempotencyKey: "idem-00000002",
actor: { userRef: "user:test" },
input: { projectRef, deviceRef, accessCode: "123456", expiresInSeconds: 30 },
});
current = new Date("2026-08-12T18:00:31.000Z");
assert.equal(await runtime.offerForDevice(deviceRef), null);
assert.equal(dispatches.length, 1);
assert.equal(runtime.status().transientAuthorizations, 0);
});
test("does not recreate a transient authorization on an idempotent replay", async () => {
const runtime = createTypedCommandRuntime({
repository: {
async planTypedServicePing() {
return {
replayed: true,
commandId: "33333333-3333-4333-8333-333333333333",
command: {
lifecycleState: "queued",
expiresAt: "2026-08-12T18:05:00.000Z",
},
};
},
async dispatchTypedCommand() {
throw new Error("must_not_dispatch_replayed_secret");
},
async recordTypedCommandStatus() {},
},
});
await runtime.planServicePing({
idempotencyKey: "idem-00000003",
actor: { userRef: "user:test" },
input: { projectRef, deviceRef, accessCode: "654321", expiresInSeconds: 300 },
});
assert.equal(runtime.status().transientAuthorizations, 0);
assert.equal(await runtime.offerForDevice(deviceRef), null);
});