feat(device-plane): add universal adapter acceptance boundary

This commit is contained in:
Codex
2026-08-11 19:11:48 +03:00
parent 227c7c26c1
commit 393741f1bd
26 changed files with 1887 additions and 127 deletions
@@ -2,6 +2,9 @@ import assert from "node:assert/strict";
import { connect } from "node:net";
import test from "node:test";
import {
DEVICE_ADAPTER_CATALOG,
} from "../../../packages/device-adapter-catalog/src/index.mjs";
import { createDeviceGatewayRuntime } from "../src/runtime.mjs";
const specificationHeader = Buffer.from(
@@ -34,7 +37,7 @@ test("baseline health exposes no public ingress and no command transport", async
}
});
test("discovery-only ingress persists HEADER2 before acknowledging packages", async () => {
test("telemetry ingress persists HEADER2 before acknowledging packages", async () => {
const captured = [];
const runtime = createDeviceGatewayRuntime({
healthPort: 0,
@@ -42,8 +45,14 @@ test("discovery-only ingress persists HEADER2 before acknowledging packages", as
tcpPort: 0,
listenEnabled: true,
publicIngressEnabled: true,
coreChannelAuthenticated: true,
now: () => new Date(0x52db95de * 1000),
onDiscovery: async (value) => captured.push(value),
...gatewayAdapterOptions(),
onDiscovery: async (value) => {
captured.push(value);
return { lifecycleState: "quarantine" };
},
onMessage: async (message) => acceptanceFor(message),
});
const addresses = await runtime.start();
const client = await connectAndCollect(addresses.tcpAddress.port);
@@ -70,17 +79,18 @@ test("discovery-only ingress persists HEADER2 before acknowledging packages", as
"7B00017D",
);
assert.equal(runtime.status().totalDiscoveries, 1);
assert.equal(runtime.status().totalMessagesAccepted, 1);
assert.equal(runtime.status().totalPackagesAcknowledged, 1);
assert.equal(runtime.status().commandTransport, "disabled");
assert.equal(runtime.status().publicIngress, "discovery-only");
assert.equal(runtime.status().publicIngress, "telemetry-ingest");
const response = await fetch(
`http://127.0.0.1:${addresses.healthAddress.port}/healthz`,
);
const body = await response.json();
assert.equal(body.framing, "verified-read-only");
assert.equal(body.tcpListener, "discovery-only");
assert.equal(body.publicIngress, "discovery-only");
assert.equal(body.tcpListener, "telemetry-ingest");
assert.equal(body.publicIngress, "telemetry-ingest");
assert.equal(body.commandTransport, "disabled");
} finally {
client.socket.destroy();
@@ -94,7 +104,12 @@ test("does not acknowledge malformed or unverified initial bytes", async () => {
healthPort: 0,
tcpPort: 0,
listenEnabled: true,
onDiscovery: async (value) => captured.push(value),
...gatewayAdapterOptions(),
onDiscovery: async (value) => {
captured.push(value);
return { lifecycleState: "quarantine" };
},
onMessage: async (message) => acceptanceFor(message),
});
const addresses = await runtime.start();
try {
@@ -110,14 +125,137 @@ test("does not acknowledge malformed or unverified initial bytes", async () => {
}
});
test("public ingress requires an authenticated discovery sink", () => {
test("does not acknowledge a header when Core rejects discovery", async () => {
const runtime = createDeviceGatewayRuntime({
healthPort: 0,
tcpPort: 0,
listenEnabled: true,
...gatewayAdapterOptions(),
onDiscovery: async () => {
throw new Error("core_unavailable");
},
onMessage: async (message) => acceptanceFor(message),
});
const addresses = await runtime.start();
try {
const received = await sendAndCollect(
addresses.tcpAddress.port,
specificationHeader,
);
assert.equal(received.length, 0);
assert.equal(runtime.status().totalDiscoveries, 0);
assert.equal(runtime.status().totalRejected, 1);
} finally {
await runtime.stop();
}
});
test("does not acknowledge a package when durable Core acceptance fails", async () => {
const runtime = createDeviceGatewayRuntime({
healthPort: 0,
tcpPort: 0,
listenEnabled: true,
now: () => new Date(0x52db95de * 1000),
...gatewayAdapterOptions(),
onDiscovery: async () => ({ lifecycleState: "quarantine" }),
onMessage: async () => {
throw new Error("core_commit_failed");
},
});
const addresses = await runtime.start();
try {
const received = await sendAndCollect(
addresses.tcpAddress.port,
Buffer.concat([specificationHeader, specificationPackage]),
);
assert.equal(
received.toString("hex").toUpperCase(),
"7B0400A0DE95DB527D",
);
assert.equal(runtime.status().totalMessagesAccepted, 0);
assert.equal(runtime.status().totalPackagesAcknowledged, 0);
assert.equal(runtime.status().totalRejected, 1);
} finally {
await runtime.stop();
}
});
test("acknowledges an idempotent Core replay as accepted delivery", async () => {
const runtime = createDeviceGatewayRuntime({
healthPort: 0,
tcpPort: 0,
listenEnabled: true,
now: () => new Date(0x52db95de * 1000),
...gatewayAdapterOptions(),
onDiscovery: async () => ({ lifecycleState: "quarantine" }),
onMessage: async (message) => acceptanceFor(message, true),
});
const addresses = await runtime.start();
try {
const received = await sendAndCollect(
addresses.tcpAddress.port,
Buffer.concat([specificationHeader, specificationPackage]),
);
assert.equal(
received.toString("hex").toUpperCase(),
"7B0400A0DE95DB527D7B00017D",
);
assert.equal(runtime.status().totalMessagesAccepted, 1);
assert.equal(runtime.status().totalPackagesAcknowledged, 1);
} finally {
await runtime.stop();
}
});
test("closes an oversized tracker buffer and releases its aggregate budget", async () => {
const runtime = createDeviceGatewayRuntime({
healthPort: 0,
tcpPort: 0,
listenEnabled: true,
maxBufferedBytes: 1024,
maxAggregateBufferedBytes: 1024,
...gatewayAdapterOptions(),
onDiscovery: async () => ({ lifecycleState: "quarantine" }),
onMessage: async (message) => acceptanceFor(message),
});
const addresses = await runtime.start();
try {
const received = await sendAndCollect(
addresses.tcpAddress.port,
Buffer.alloc(1025, 0x01),
);
assert.equal(received.length, 0);
assert.equal(runtime.status().totalRejected, 1);
assert.equal(runtime.status().totalBufferedBytes, 0);
assert.equal(runtime.status().activeSessions, 0);
} finally {
await runtime.stop();
}
});
test("public ingress requires both discovery and durable message acceptance sinks", () => {
assert.throws(
() => createDeviceGatewayRuntime({
listenEnabled: true,
publicIngressEnabled: true,
coreChannelAuthenticated: true,
tcpHost: "0.0.0.0",
}),
/device_gateway_core_acceptance_sink_required/,
);
});
test("public ingress cannot start on the legacy bearer HTTP Core client", () => {
assert.throws(
() => createDeviceGatewayRuntime({
listenEnabled: true,
publicIngressEnabled: true,
tcpHost: "0.0.0.0",
...gatewayAdapterOptions(),
onDiscovery: async () => ({ lifecycleState: "quarantine" }),
onMessage: async (message) => acceptanceFor(message),
}),
/device_gateway_discovery_sink_required/,
/device_gateway_authenticated_core_channel_required/,
);
});
@@ -126,6 +264,9 @@ test("baseline rejects non-loopback binding", () => {
() => createDeviceGatewayRuntime({
listenEnabled: true,
tcpHost: "0.0.0.0",
...gatewayAdapterOptions(),
onDiscovery: async () => ({ lifecycleState: "quarantine" }),
onMessage: async (message) => acceptanceFor(message),
}),
/device_gateway_baseline_loopback_only/,
);
@@ -192,3 +333,22 @@ function sendAndCollect(port, payload) {
socket.on("error", reject);
});
}
function gatewayAdapterOptions() {
return {
adapterRegistry: DEVICE_ADAPTER_CATALOG.registry,
protocolProfileRef: DEVICE_ADAPTER_CATALOG.defaultProfileRef,
edgeRef: "edge:test-001",
};
}
function acceptanceFor(message, replayed = false) {
return {
schemaVersion: "nodedc.device-adapter-acceptance.v1",
acceptanceRef: "acceptance:test-001",
idempotencyKey: message.idempotencyKey,
status: "accepted",
replayed,
acceptedAt: "2026-08-11T12:00:00.000Z",
};
}