feat(device-core): add control resource ledger
This commit is contained in:
@@ -0,0 +1,158 @@
|
||||
import assert from "node:assert/strict";
|
||||
import test from "node:test";
|
||||
|
||||
import {
|
||||
DEVICE_CONTROL_RESOURCE_COMMAND_KINDS,
|
||||
normalizeControlResourceManagementCommand,
|
||||
} from "../src/control-resource-management.mjs";
|
||||
import {
|
||||
ALL_DEVICE_MANAGEMENT_COMMAND_KINDS,
|
||||
normalizeDeviceManagementCommand,
|
||||
} from "../src/management-command.mjs";
|
||||
|
||||
const projectRef = "project:11111111-1111-4111-8111-111111111111";
|
||||
const deviceRef = "device:22222222-2222-4222-8222-222222222222";
|
||||
const collectionRef = "collection:33333333-3333-4333-8333-333333333333";
|
||||
const bindingRef = "binding:44444444-4444-4444-8444-444444444444";
|
||||
const revisionRef =
|
||||
"configuration-revision:55555555-5555-4555-8555-555555555555";
|
||||
|
||||
test("control resource commands join the strict idempotent surface", () => {
|
||||
for (const kind of DEVICE_CONTROL_RESOURCE_COMMAND_KINDS) {
|
||||
assert.equal(ALL_DEVICE_MANAGEMENT_COMMAND_KINDS.includes(kind), true);
|
||||
}
|
||||
assert.equal(
|
||||
normalizeDeviceManagementCommand(
|
||||
"device_binding.ensure",
|
||||
bindingInput(),
|
||||
).projectId,
|
||||
projectRef.slice("project:".length),
|
||||
);
|
||||
});
|
||||
|
||||
test("binding input is source-scoped and cannot claim external approval", () => {
|
||||
const command = normalizeControlResourceManagementCommand(
|
||||
"device_binding.ensure",
|
||||
bindingInput(),
|
||||
);
|
||||
|
||||
assert.deepEqual(command.source, {
|
||||
kind: "collection",
|
||||
id: collectionRef.slice("collection:".length),
|
||||
});
|
||||
assert.deepEqual(command.capabilities, ["inspect", "observe"]);
|
||||
assert.equal("lifecycleState" in command, false);
|
||||
assert.equal("externalApprovalRef" in command, false);
|
||||
assert.throws(
|
||||
() => normalizeControlResourceManagementCommand(
|
||||
"device_binding.ensure",
|
||||
{ ...bindingInput(), externalApprovalRef: "approval:forged" },
|
||||
),
|
||||
/device_management_command_field_unexpected:externalApprovalRef/,
|
||||
);
|
||||
assert.throws(
|
||||
() => normalizeControlResourceManagementCommand(
|
||||
"device_binding.ensure",
|
||||
{ ...bindingInput(), targetRef: "ndc-credref:must-not-be-a-target" },
|
||||
),
|
||||
/device_binding_target_ref_invalid/,
|
||||
);
|
||||
});
|
||||
|
||||
test("binding revoke uses only project, binding and bounded reason refs", () => {
|
||||
const command = normalizeControlResourceManagementCommand(
|
||||
"device_binding.revoke",
|
||||
{
|
||||
projectRef,
|
||||
bindingRef,
|
||||
resolutionCode: "operator.unbound",
|
||||
},
|
||||
);
|
||||
|
||||
assert.equal(command.bindingId, bindingRef.slice("binding:".length));
|
||||
assert.equal(command.resolutionCode, "operator.unbound");
|
||||
});
|
||||
|
||||
test("configuration is canonical, bounded and secret-free before hashing", () => {
|
||||
const first = normalizeControlResourceManagementCommand(
|
||||
"device_configuration_revision.create",
|
||||
{
|
||||
projectRef,
|
||||
deviceRef,
|
||||
configuration: {
|
||||
reporting_interval_seconds: 15,
|
||||
motion: { enabled: true, threshold: 3.5 },
|
||||
channels: ["gps", "voltage"],
|
||||
},
|
||||
changeSummary: "Pilot reporting profile",
|
||||
},
|
||||
);
|
||||
const reordered = normalizeControlResourceManagementCommand(
|
||||
"device_configuration_revision.create",
|
||||
{
|
||||
projectRef,
|
||||
deviceRef,
|
||||
configuration: {
|
||||
channels: ["gps", "voltage"],
|
||||
motion: { threshold: 3.5, enabled: true },
|
||||
reporting_interval_seconds: 15,
|
||||
},
|
||||
changeSummary: "Pilot reporting profile",
|
||||
},
|
||||
);
|
||||
|
||||
assert.equal(first.configurationDigest, reordered.configurationDigest);
|
||||
assert.equal(Object.isFrozen(first.configuration.motion), true);
|
||||
assert.throws(
|
||||
() => normalizeControlResourceManagementCommand(
|
||||
"device_configuration_revision.create",
|
||||
{
|
||||
projectRef,
|
||||
deviceRef,
|
||||
configuration: { api_token: "forbidden" },
|
||||
},
|
||||
),
|
||||
/forbidden_device_field/,
|
||||
);
|
||||
assert.throws(
|
||||
() => normalizeControlResourceManagementCommand(
|
||||
"device_configuration_revision.create",
|
||||
{
|
||||
projectRef,
|
||||
deviceRef,
|
||||
configuration: { tracker_imei: "000000000000001" },
|
||||
},
|
||||
),
|
||||
/safe_projection_contains_unmasked_imei/,
|
||||
);
|
||||
});
|
||||
|
||||
test("desired configuration binds one exact immutable revision", () => {
|
||||
const command = normalizeControlResourceManagementCommand(
|
||||
"device_configuration_desired.set",
|
||||
{
|
||||
projectRef,
|
||||
deviceRef,
|
||||
configurationRevisionRef: revisionRef,
|
||||
},
|
||||
);
|
||||
|
||||
assert.equal(command.deviceId, deviceRef.slice("device:".length));
|
||||
assert.equal(
|
||||
command.configurationRevisionId,
|
||||
revisionRef.slice("configuration-revision:".length),
|
||||
);
|
||||
assert.equal("applied" in command, false);
|
||||
});
|
||||
|
||||
function bindingInput() {
|
||||
return {
|
||||
projectRef,
|
||||
bindingKey: "robot2b-map",
|
||||
displayName: "Robot2B map binding",
|
||||
source: { kind: "collection", ref: collectionRef },
|
||||
targetKind: "foundry.application",
|
||||
targetRef: "foundry-application:robot2b-test",
|
||||
capabilities: ["observe", "inspect"],
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user