112 lines
3.5 KiB
JavaScript
112 lines
3.5 KiB
JavaScript
import assert from "node:assert/strict";
|
|
import test from "node:test";
|
|
|
|
import {
|
|
DEVICE_LIFECYCLE_COMMAND_KINDS,
|
|
normalizeLifecycleManagementCommand,
|
|
} from "../src/lifecycle-management.mjs";
|
|
import {
|
|
ALL_DEVICE_MANAGEMENT_COMMAND_KINDS,
|
|
normalizeDeviceManagementCommand,
|
|
} from "../src/management-command.mjs";
|
|
|
|
const projectRef = "project:11111111-1111-4111-8111-111111111111";
|
|
const targetProjectRef = "project:22222222-2222-4222-8222-222222222222";
|
|
const discoveryRef = "discovery:33333333-3333-4333-8333-333333333333";
|
|
const enrollmentIntentRef =
|
|
"enrollment-intent:44444444-4444-4444-8444-444444444444";
|
|
const deviceRef = "device:55555555-5555-4555-8555-555555555555";
|
|
|
|
test("lifecycle commands join the same strict management command surface", () => {
|
|
for (const kind of DEVICE_LIFECYCLE_COMMAND_KINDS) {
|
|
assert.equal(ALL_DEVICE_MANAGEMENT_COMMAND_KINDS.includes(kind), true);
|
|
}
|
|
assert.equal(
|
|
normalizeDeviceManagementCommand("device.claim", claimInput()).projectId,
|
|
projectRef.slice("project:".length),
|
|
);
|
|
});
|
|
|
|
test("claim accepts only opaque evidence references and presentation fields", () => {
|
|
const command = normalizeLifecycleManagementCommand(
|
|
"device.claim",
|
|
claimInput(),
|
|
);
|
|
|
|
assert.equal(
|
|
command.enrollmentIntentId,
|
|
enrollmentIntentRef.slice("enrollment-intent:".length),
|
|
);
|
|
assert.equal(command.discoveryId, discoveryRef.slice("discovery:".length));
|
|
assert.equal(command.deviceKey, "pilot-device");
|
|
assert.equal("identifier" in command, false);
|
|
assert.equal("credentialRef" in command, false);
|
|
});
|
|
|
|
test("claim rejects raw identity and credential-shaped input", () => {
|
|
assert.throws(
|
|
() => normalizeLifecycleManagementCommand("device.claim", {
|
|
...claimInput(),
|
|
identifier: "000000000000001",
|
|
}),
|
|
/device_management_command_field_unexpected:identifier/,
|
|
);
|
|
assert.throws(
|
|
() => normalizeLifecycleManagementCommand("device.claim", {
|
|
...claimInput(),
|
|
credentialRef: "secret:test",
|
|
}),
|
|
/device_management_command_field_unexpected:credentialRef/,
|
|
);
|
|
});
|
|
|
|
test("transfer binds both project boundaries and rejects a no-op", () => {
|
|
const command = normalizeLifecycleManagementCommand("device.transfer", {
|
|
deviceRef,
|
|
sourceProjectRef: projectRef,
|
|
targetProjectRef,
|
|
targetDeviceKey: "transferred-device",
|
|
});
|
|
|
|
assert.equal(command.deviceId, deviceRef.slice("device:".length));
|
|
assert.notEqual(command.sourceProjectId, command.targetProjectId);
|
|
assert.throws(
|
|
() => normalizeLifecycleManagementCommand("device.transfer", {
|
|
deviceRef,
|
|
sourceProjectRef: projectRef,
|
|
targetProjectRef: projectRef,
|
|
targetDeviceKey: "same-project",
|
|
}),
|
|
/device_transfer_target_same_as_source/,
|
|
);
|
|
});
|
|
|
|
test("reject and expire require bounded machine-readable resolution codes", () => {
|
|
for (const kind of ["discovery.reject", "discovery.expire"]) {
|
|
const command = normalizeLifecycleManagementCommand(kind, {
|
|
projectRef,
|
|
discoveryRef,
|
|
resolutionCode: "operator.identity_mismatch",
|
|
});
|
|
assert.equal(command.resolutionCode, "operator.identity_mismatch");
|
|
}
|
|
assert.throws(
|
|
() => normalizeLifecycleManagementCommand("discovery.reject", {
|
|
projectRef,
|
|
discoveryRef,
|
|
resolutionCode: "free form reason is forbidden",
|
|
}),
|
|
/device_discovery_resolution_code_invalid/,
|
|
);
|
|
});
|
|
|
|
function claimInput() {
|
|
return {
|
|
projectRef,
|
|
enrollmentIntentRef,
|
|
discoveryRef,
|
|
deviceKey: "pilot-device",
|
|
displayName: "Pilot device",
|
|
};
|
|
}
|