feat: establish standalone Device Core repository
This commit is contained in:
@@ -0,0 +1,265 @@
|
||||
import assert from "node:assert/strict";
|
||||
import test from "node:test";
|
||||
|
||||
import {
|
||||
DEVICE_ADAPTER_ACCEPTANCE_SCHEMA,
|
||||
DEVICE_ADAPTER_MESSAGE_SCHEMA,
|
||||
DEVICE_DISCOVERY_SIGNAL_SCHEMA,
|
||||
DEVICE_PLANE_BINDING_SCHEMA,
|
||||
assertIdentifierDigest,
|
||||
assertSafeProjection,
|
||||
hashRestrictedIdentifier,
|
||||
maskRestrictedIdentifier,
|
||||
normalizeDevicePlaneBinding,
|
||||
normalizeAdapterAcceptance,
|
||||
normalizeAdapterMessage,
|
||||
normalizeDiscoverySignal,
|
||||
normalizeRestrictedIdentifier,
|
||||
normalizeRestrictedIdentifierProjection,
|
||||
normalizeRestrictedIdentifierRecord,
|
||||
toSafeDiscoveryView,
|
||||
toSafeAdapterMessageView,
|
||||
} from "../src/index.mjs";
|
||||
|
||||
const fakeImei = "000000000000001";
|
||||
const fakeSignal = {
|
||||
schemaVersion: DEVICE_DISCOVERY_SIGNAL_SCHEMA,
|
||||
sessionRef: "session:test-001",
|
||||
modelProfileRef: "arusnavi.b2.internal.v1",
|
||||
protocol: "INTERNAL",
|
||||
observedAt: "2026-07-25T00:00:00.000Z",
|
||||
identifier: {
|
||||
kind: "imei",
|
||||
value: fakeImei,
|
||||
},
|
||||
evidence: {
|
||||
transport: "tcp",
|
||||
bytesObserved: 128,
|
||||
framingStatus: "verified",
|
||||
specificationRef: "arusnavi.internal.framing.test-v1",
|
||||
},
|
||||
};
|
||||
|
||||
test("normalizes a verified discovery into quarantine with commands disabled", () => {
|
||||
const signal = normalizeDiscoverySignal(fakeSignal);
|
||||
assert.equal(signal.lifecycleState, "quarantine");
|
||||
assert.equal(signal.commandTransport, "disabled");
|
||||
assert.equal(signal.identifier.value, fakeImei);
|
||||
});
|
||||
|
||||
test("safe discovery projection masks the restricted identifier", () => {
|
||||
const view = toSafeDiscoveryView(fakeSignal, {
|
||||
discoveryRef: "discovery:test-001",
|
||||
});
|
||||
const serialized = JSON.stringify(view);
|
||||
assert.equal(view.identifier.masked, "***********0001");
|
||||
assert.equal(serialized.includes(fakeImei), false);
|
||||
assertSafeProjection(view);
|
||||
});
|
||||
|
||||
test("route-bound discovery preserves only a validated opaque route reference", () => {
|
||||
const routeRef = "route:11111111-1111-4111-8111-111111111111";
|
||||
const signal = normalizeDiscoverySignal({ ...fakeSignal, routeRef });
|
||||
const view = toSafeDiscoveryView(signal);
|
||||
|
||||
assert.equal(signal.routeRef, routeRef);
|
||||
assert.equal(view.routeRef, routeRef);
|
||||
assert.throws(
|
||||
() => normalizeDiscoverySignal({ ...fakeSignal, routeRef: "route:generic" }),
|
||||
/route_ref_invalid/,
|
||||
);
|
||||
});
|
||||
|
||||
test("identifier hashing requires a strong process-only pepper", () => {
|
||||
const identifier = { kind: "imei", value: fakeImei };
|
||||
assert.throws(
|
||||
() => hashRestrictedIdentifier(identifier, "short"),
|
||||
/identifier_pepper_invalid/,
|
||||
);
|
||||
const digest = hashRestrictedIdentifier(
|
||||
identifier,
|
||||
"test-only-pepper-with-at-least-32-bytes",
|
||||
);
|
||||
assertIdentifierDigest(digest);
|
||||
assert.equal(digest.includes(fakeImei), false);
|
||||
assert.equal(
|
||||
digest,
|
||||
hashRestrictedIdentifier(
|
||||
identifier,
|
||||
"test-only-pepper-with-at-least-32-bytes",
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
test("restricted identifier records keep digest internal and expose only a mask", () => {
|
||||
const record = normalizeRestrictedIdentifierRecord({
|
||||
kind: "vendor.serial",
|
||||
digest: `hmac-sha256:${"a".repeat(64)}`,
|
||||
masked: "********ABCD",
|
||||
});
|
||||
const projection = normalizeRestrictedIdentifierProjection({
|
||||
kind: record.kind,
|
||||
masked: record.masked,
|
||||
});
|
||||
|
||||
assert.deepEqual(projection, {
|
||||
kind: "vendor.serial",
|
||||
masked: "********ABCD",
|
||||
});
|
||||
assert.equal("digest" in projection, false);
|
||||
assertSafeProjection({ identifier: projection });
|
||||
assert.throws(
|
||||
() => normalizeRestrictedIdentifierProjection({
|
||||
kind: "vendor.serial",
|
||||
masked: "SERIAL-PLAINTEXT",
|
||||
}),
|
||||
/restricted_identifier_projection_mask_invalid/,
|
||||
);
|
||||
});
|
||||
|
||||
test("restricted identifiers support future adapter-defined hardware ids", () => {
|
||||
const identifier = normalizeRestrictedIdentifier({
|
||||
kind: "serial",
|
||||
value: "SN-TRACKER-0001",
|
||||
});
|
||||
assert.deepEqual(identifier, {
|
||||
kind: "serial",
|
||||
value: "SN-TRACKER-0001",
|
||||
});
|
||||
assert.equal(maskRestrictedIdentifier(identifier), "***********0001");
|
||||
assert.match(
|
||||
hashRestrictedIdentifier(
|
||||
identifier,
|
||||
"test-only-pepper-with-at-least-32-bytes",
|
||||
),
|
||||
/^hmac-sha256:[a-f0-9]{64}$/,
|
||||
);
|
||||
});
|
||||
|
||||
test("rejects unverified framing and command-shaped discovery input", () => {
|
||||
assert.throws(
|
||||
() => normalizeDiscoverySignal({
|
||||
...fakeSignal,
|
||||
evidence: { ...fakeSignal.evidence, framingStatus: "unverified" },
|
||||
}),
|
||||
/discovery_evidence_framing_unverified/,
|
||||
);
|
||||
assert.throws(
|
||||
() => normalizeDiscoverySignal({
|
||||
...fakeSignal,
|
||||
command: { kind: "restart" },
|
||||
}),
|
||||
/forbidden_device_field/,
|
||||
);
|
||||
});
|
||||
|
||||
test("rejects secret-like fields recursively", () => {
|
||||
assert.throws(
|
||||
() => normalizeDiscoverySignal({
|
||||
...fakeSignal,
|
||||
metadata: { devicePassword: "not-a-real-password" },
|
||||
}),
|
||||
/forbidden_device_field/,
|
||||
);
|
||||
});
|
||||
|
||||
test("normalizes an opaque Foundry control binding without device data", () => {
|
||||
const binding = normalizeDevicePlaneBinding({
|
||||
schemaVersion: DEVICE_PLANE_BINDING_SCHEMA,
|
||||
bindingRef: "binding:test-001",
|
||||
contourRef: "contour:robot2b-test",
|
||||
capabilities: ["inspect", "observe", "observe"],
|
||||
});
|
||||
assert.deepEqual(binding.capabilities, ["inspect", "observe"]);
|
||||
assertSafeProjection(binding);
|
||||
});
|
||||
|
||||
test("normalizes a bounded typed adapter message and masks its identity", () => {
|
||||
const message = {
|
||||
schemaVersion: DEVICE_ADAPTER_MESSAGE_SCHEMA,
|
||||
edgeRef: "edge:robot2b-vps-001",
|
||||
adapterRef: "arusnavi-b2",
|
||||
protocolProfileRef: "arusnavi.b2.internal.v1",
|
||||
protocol: "INTERNAL",
|
||||
sessionRef: "session:test-001",
|
||||
routeRef: "route:11111111-1111-4111-8111-111111111111",
|
||||
messageRef: "package:1:abc123",
|
||||
messageType: "telemetry.package",
|
||||
sequence: 1,
|
||||
observedAt: "2026-08-11T12:00:00.000Z",
|
||||
idempotencyKey: `sha256:${"a".repeat(64)}`,
|
||||
identifier: { kind: "imei", value: fakeImei },
|
||||
payloadSchemaRef: "arusnavi.internal.package-metadata.v1",
|
||||
payload: {
|
||||
packageNumber: 1,
|
||||
packetCount: 1,
|
||||
packageDigest: `sha256:${"b".repeat(64)}`,
|
||||
},
|
||||
};
|
||||
const normalized = normalizeAdapterMessage(message);
|
||||
const safe = toSafeAdapterMessageView(normalized);
|
||||
assert.equal(normalized.identifier.value, fakeImei);
|
||||
assert.equal(safe.identifier.masked, "***********0001");
|
||||
assert.equal(JSON.stringify(safe).includes(fakeImei), false);
|
||||
assertSafeProjection(safe);
|
||||
});
|
||||
|
||||
test("rejects oversized, untyped and secret-shaped adapter messages", () => {
|
||||
const base = {
|
||||
schemaVersion: DEVICE_ADAPTER_MESSAGE_SCHEMA,
|
||||
edgeRef: "edge:test",
|
||||
adapterRef: "generic-tracker",
|
||||
protocolProfileRef: "generic.tracker.v1",
|
||||
protocol: "GENERIC",
|
||||
sessionRef: "session:test",
|
||||
messageRef: "message:1",
|
||||
messageType: "telemetry.sample",
|
||||
sequence: 1,
|
||||
observedAt: "2026-08-11T12:00:00.000Z",
|
||||
idempotencyKey: `sha256:${"a".repeat(64)}`,
|
||||
identifier: { kind: "imei", value: fakeImei },
|
||||
payloadSchemaRef: "generic.telemetry.v1",
|
||||
payload: { value: 1 },
|
||||
};
|
||||
assert.throws(
|
||||
() => normalizeAdapterMessage({ ...base, payload: "raw" }),
|
||||
/device_adapter_message_payload_invalid/,
|
||||
);
|
||||
assert.throws(
|
||||
() => normalizeAdapterMessage({
|
||||
...base,
|
||||
payload: { devicePassword: "forbidden" },
|
||||
}),
|
||||
/forbidden_device_field/,
|
||||
);
|
||||
assert.throws(
|
||||
() => normalizeAdapterMessage({
|
||||
...base,
|
||||
payload: { value: "x".repeat(4096) },
|
||||
}, { maxBytes: 1024 }),
|
||||
/device_adapter_message_too_large/,
|
||||
);
|
||||
assert.throws(
|
||||
() => normalizeAdapterMessage({
|
||||
...base,
|
||||
idempotencyKey: "message-not-a-digest",
|
||||
}),
|
||||
/idempotency_key_invalid/,
|
||||
);
|
||||
});
|
||||
|
||||
test("accepts only an explicit durable Core acceptance contract", () => {
|
||||
const acceptance = normalizeAdapterAcceptance({
|
||||
schemaVersion: DEVICE_ADAPTER_ACCEPTANCE_SCHEMA,
|
||||
acceptanceRef: "acceptance:test-001",
|
||||
idempotencyKey: `sha256:${"a".repeat(64)}`,
|
||||
status: "accepted",
|
||||
replayed: false,
|
||||
acceptedAt: "2026-08-11T12:00:00.000Z",
|
||||
});
|
||||
assert.equal(acceptance.status, "accepted");
|
||||
assert.throws(
|
||||
() => normalizeAdapterAcceptance({ ...acceptance, status: "queued" }),
|
||||
/device_adapter_acceptance_status_invalid/,
|
||||
);
|
||||
});
|
||||
@@ -0,0 +1,123 @@
|
||||
import assert from "node:assert/strict";
|
||||
import { spawnSync } from "node:child_process";
|
||||
import { readFile } from "node:fs/promises";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import test from "node:test";
|
||||
|
||||
const contractUrl = new URL(
|
||||
"../../../deployment/device-edge-core-channel-v1.json",
|
||||
import.meta.url,
|
||||
);
|
||||
const freezeUrl = new URL(
|
||||
"../../../deployment/superseded-vps-initiated-transport-v1.json",
|
||||
import.meta.url,
|
||||
);
|
||||
const sourceAcceptanceUrl = new URL(
|
||||
"../../../deployment/device-edge-core-channel-source-v1.json",
|
||||
import.meta.url,
|
||||
);
|
||||
const edgeBuilder = fileURLToPath(new URL(
|
||||
"../../../infra/deploy-runner/build-device-edge-vps-artifact.mjs",
|
||||
import.meta.url,
|
||||
));
|
||||
const enrollmentBuilder = fileURLToPath(new URL(
|
||||
"../../../infra/deploy-runner/build-device-plane-backhaul-vps-enrollment-artifact.mjs",
|
||||
import.meta.url,
|
||||
));
|
||||
|
||||
async function readJson(url) {
|
||||
return JSON.parse(await readFile(url, "utf8"));
|
||||
}
|
||||
|
||||
test("pins a Core-initiated mutually authenticated Edge channel", async () => {
|
||||
const contract = await readJson(contractUrl);
|
||||
|
||||
assert.equal(contract.status, "accepted-design");
|
||||
assert.equal(contract.direction, "device-gateway-core-initiated");
|
||||
assert.equal(contract.transport.tls, "TLSv1.3-mutual-authentication");
|
||||
assert.equal(contract.transport.genericTcpForwarding, "forbidden");
|
||||
assert.equal(contract.networkBoundary.synologyPublicIngress, false);
|
||||
assert.equal(contract.networkBoundary.vpsInitiatedSynologyConnection, false);
|
||||
assert.equal(contract.networkBoundary.subnetRoutes, false);
|
||||
assert.equal(contract.networkBoundary.exitNode, false);
|
||||
assert.equal(contract.identity.privateKeysInArtifacts, false);
|
||||
});
|
||||
|
||||
test("requires Core acceptance before acknowledging tracker packages", async () => {
|
||||
const contract = await readJson(contractUrl);
|
||||
|
||||
assert.equal(
|
||||
contract.acknowledgement.trackerPackageAck,
|
||||
"only-after-bounded-core-acceptance",
|
||||
);
|
||||
assert.equal(
|
||||
contract.acknowledgement.coreUnavailable,
|
||||
"do-not-acknowledge-tracker-package",
|
||||
);
|
||||
assert.equal(contract.acknowledgement.deliverySemantics, "at-least-once");
|
||||
assert.equal(contract.pilotLimits.durableEdgeSpool, false);
|
||||
assert.ok(contract.pilotLimits.maxBufferedBytesPerTrackerSession <= 262144);
|
||||
assert.ok(contract.pilotLimits.maxAggregateBufferedBytes <= 33554432);
|
||||
assert.equal(contract.pilotSlo.trackerAckBeforeDurableCoreAcceptance, 0);
|
||||
assert.equal(contract.pilotSlo.lossOfCoreAcceptedPackages, 0);
|
||||
assert.ok(
|
||||
contract.pilotSlo.edgeReceiveToCoreAcceptanceP99Milliseconds <= 5000,
|
||||
);
|
||||
assert.ok(contract.pilotSlo.deadCoreDetectionHardCeilingSeconds <= 45);
|
||||
});
|
||||
|
||||
test("records source acceptance without opening an Edge or tracker port", async () => {
|
||||
const acceptance = await readJson(sourceAcceptanceUrl);
|
||||
|
||||
assert.equal(acceptance.status, "source-accepted");
|
||||
assert.equal(acceptance.transport.initiator, "device-gateway-core");
|
||||
assert.equal(acceptance.transport.tls, "TLSv1.3-mutual-authentication");
|
||||
assert.equal(acceptance.identity.privateKeysInSource, false);
|
||||
assert.equal(acceptance.identity.privateKeysInArtifact, false);
|
||||
assert.equal(
|
||||
acceptance.identity.rotation,
|
||||
"one-active-plus-one-staged-generation",
|
||||
);
|
||||
assert.equal(acceptance.identity.retiredFingerprint, "reject");
|
||||
assert.equal(acceptance.runtime.mutationInThisTransition, false);
|
||||
assert.equal(acceptance.runtime.edgePort8443Published, false);
|
||||
assert.equal(acceptance.runtime.trackerPort9921Published, false);
|
||||
assert.equal(acceptance.runtime.synologyPublicIngress, false);
|
||||
assert.equal(acceptance.runtime.commandTransport, "disabled");
|
||||
assert.equal(acceptance.runtime.gelios, "untouched");
|
||||
});
|
||||
|
||||
test("freezes the VPS-initiated Tailscale and SSH backhaul", async () => {
|
||||
const freeze = await readJson(freezeUrl);
|
||||
|
||||
assert.equal(freeze.status, "frozen");
|
||||
assert.equal(freeze.successor, "nodedc.device-edge.core-channel.v1");
|
||||
assert.equal(freeze.runtimeMutationInPhase0, false);
|
||||
assert.ok(freeze.forbiddenForNewPlanOrApply.includes(
|
||||
"nodedc.device-plane.backhaul-vps-enrollment.v1",
|
||||
));
|
||||
assert.ok(freeze.forbiddenForNewPlanOrApply.includes(
|
||||
"tailscale-userspace-key-only-ssh-local-forward",
|
||||
));
|
||||
});
|
||||
|
||||
test("superseded artifact builders fail closed outside test-only reconstruction", () => {
|
||||
const environment = { ...process.env };
|
||||
delete environment.NODEDC_ALLOW_SUPERSEDED_TRANSPORT;
|
||||
|
||||
const edge = spawnSync(
|
||||
process.execPath,
|
||||
[edgeBuilder, "backhaul", "superseded-backhaul-unit"],
|
||||
{ encoding: "utf8", env: environment },
|
||||
);
|
||||
assert.notEqual(edge.status, 0);
|
||||
assert.match(edge.stderr, /vps_initiated_transport_frozen:ADR-0001/);
|
||||
|
||||
const enrollment = spawnSync(
|
||||
process.execPath,
|
||||
[enrollmentBuilder, "superseded-enrollment-unit"],
|
||||
{ encoding: "utf8", env: environment },
|
||||
);
|
||||
assert.notEqual(enrollment.status, 0);
|
||||
assert.match(enrollment.stderr, /vps_initiated_transport_frozen:ADR-0001/);
|
||||
});
|
||||
Reference in New Issue
Block a user