fix(device-core): bind edge telemetry to enrolled route
This commit is contained in:
@@ -8,13 +8,14 @@ import {
|
||||
test("supervisor reconciles one in-process client per active Edge", async () => {
|
||||
let registrations = [registration("channel-generation:1")];
|
||||
const clients = [];
|
||||
const ingestCalls = [];
|
||||
const supervisor = createDeviceEdgeChannelSupervisor({
|
||||
repository: {
|
||||
listActiveEdgeChannelRegistrations: async () => registrations,
|
||||
},
|
||||
gatewayIngest: {
|
||||
observeDiscovery: async () => ({}),
|
||||
acceptMessage: async () => ({}),
|
||||
observeDiscovery: async (...args) => ingestCalls.push(["discovery", ...args]),
|
||||
acceptMessage: async (...args) => ingestCalls.push(["message", ...args]),
|
||||
},
|
||||
coreIdentity: {
|
||||
identityRef: "workload:device-control-core",
|
||||
@@ -38,6 +39,20 @@ test("supervisor reconciles one in-process client per active Edge", async () =>
|
||||
assert.equal(clients.length, 1);
|
||||
assert.equal(supervisor.status().accepted, 1);
|
||||
assert.equal(clients[0].options.registration.channelGeneration, "channel-generation:1");
|
||||
await clients[0].options.observeDiscovery({ signal: true });
|
||||
await clients[0].options.acceptMessage({ message: true });
|
||||
assert.deepEqual(ingestCalls, [
|
||||
[
|
||||
"discovery",
|
||||
{ signal: true },
|
||||
{ authenticatedEdgeRef: "edge:pilot" },
|
||||
],
|
||||
[
|
||||
"message",
|
||||
{ message: true },
|
||||
{ authenticatedEdgeRef: "edge:pilot" },
|
||||
],
|
||||
]);
|
||||
|
||||
await supervisor.reconcile();
|
||||
assert.equal(clients.length, 1);
|
||||
|
||||
@@ -53,6 +53,55 @@ test("shared gateway ingest masks identifiers for HTTP and Edge callers", async
|
||||
assert.equal(JSON.stringify(stored).includes(rawImei), false);
|
||||
});
|
||||
|
||||
test("authenticated Edge identity resolves the allowlisted project route", async () => {
|
||||
const stored = [];
|
||||
const resolutions = [];
|
||||
const authenticatedEdgeRef = "edge:11111111-1111-4111-8111-111111111111";
|
||||
const routeRef = "route:22222222-2222-4222-8222-222222222222";
|
||||
const ingest = createDeviceGatewayIngest({
|
||||
identifierPepper,
|
||||
repository: {
|
||||
async resolveInboundRoute(value) {
|
||||
resolutions.push(value);
|
||||
return routeRef;
|
||||
},
|
||||
async upsertQuarantineDiscovery(value) {
|
||||
stored.push(value);
|
||||
return {
|
||||
created: false,
|
||||
value: { ...value.safeView, discoveryRef: "discovery:test" },
|
||||
};
|
||||
},
|
||||
async acceptAdapterMessage(value) {
|
||||
stored.push(value);
|
||||
return {
|
||||
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: null,
|
||||
};
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await ingest.observeDiscovery(discoverySignal(), { authenticatedEdgeRef });
|
||||
await ingest.acceptMessage(adapterMessage(), { authenticatedEdgeRef });
|
||||
|
||||
assert.equal(resolutions.length, 2);
|
||||
assert.equal(resolutions[0].edgeRef, authenticatedEdgeRef);
|
||||
assert.match(resolutions[0].identifierDigest, /^hmac-sha256:[a-f0-9]{64}$/);
|
||||
assert.equal(stored[0].safeView.routeRef, routeRef);
|
||||
assert.equal(stored[1].safeView.routeRef, routeRef);
|
||||
assert.equal(stored[1].safeView.edgeRef, authenticatedEdgeRef);
|
||||
assert.notEqual(stored[1].safeView.edgeRef, adapterMessage().edgeRef);
|
||||
assert.equal(JSON.stringify(resolutions).includes(rawImei), false);
|
||||
});
|
||||
|
||||
function discoverySignal() {
|
||||
return {
|
||||
schemaVersion: DEVICE_DISCOVERY_SIGNAL_SCHEMA,
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
import assert from "node:assert/strict";
|
||||
import test from "node:test";
|
||||
|
||||
import {
|
||||
resolveInboundRoute,
|
||||
} from "../src/inbound-route-repository.mjs";
|
||||
|
||||
const edgeRef = "edge:11111111-1111-4111-8111-111111111111";
|
||||
const routeId = "22222222-2222-4222-8222-222222222222";
|
||||
const identifierDigest = `hmac-sha256:${"a".repeat(64)}`;
|
||||
|
||||
test("inbound route resolution is scoped by authenticated Edge and enrollment", async () => {
|
||||
const queries = [];
|
||||
const client = {
|
||||
async query(sql, values) {
|
||||
queries.push({ sql, values });
|
||||
return { rows: [{ id: routeId }] };
|
||||
},
|
||||
};
|
||||
|
||||
const result = await resolveInboundRoute(client, input());
|
||||
|
||||
assert.equal(result, `route:${routeId}`);
|
||||
assert.equal(queries.length, 1);
|
||||
assert.match(queries[0].sql, /device_enrollment_intents/);
|
||||
assert.match(queries[0].sql, /r\.edge_id = \$1/);
|
||||
assert.match(queries[0].sql, /ei\.expected_identifier_digest = \$5/);
|
||||
assert.deepEqual(queries[0].values, [
|
||||
edgeRef.slice("edge:".length),
|
||||
"arusnavi.b2.internal.v1",
|
||||
"INTERNAL",
|
||||
"imei",
|
||||
identifierDigest,
|
||||
"2026-08-13T09:00:00.000Z",
|
||||
]);
|
||||
});
|
||||
|
||||
test("inbound route resolution leaves unknown identifiers quarantined", async () => {
|
||||
const result = await resolveInboundRoute(
|
||||
{ query: async () => ({ rows: [] }) },
|
||||
input(),
|
||||
);
|
||||
assert.equal(result, null);
|
||||
});
|
||||
|
||||
test("inbound route resolution fails closed on ambiguous ownership", async () => {
|
||||
await assert.rejects(
|
||||
() => resolveInboundRoute(
|
||||
{ query: async () => ({ rows: [{ id: routeId }, { id: routeId }] }) },
|
||||
input(),
|
||||
),
|
||||
(error) => {
|
||||
assert.equal(error.message, "device_inbound_route_ambiguous");
|
||||
assert.equal(error.statusCode, 409);
|
||||
return true;
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
function input() {
|
||||
return {
|
||||
edgeRef,
|
||||
modelProfileRef: "arusnavi.b2.internal.v1",
|
||||
protocol: "INTERNAL",
|
||||
identifierKind: "imei",
|
||||
identifierDigest,
|
||||
observedAt: "2026-08-13T09:00:00.000Z",
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user