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("device update keeps display name and integration identity as separate presentation fields", () => { const command = normalizeLifecycleManagementCommand("device.update", { projectRef, deviceRef, displayName: " Trike 8028 ", integrationDeviceId: " 8028 ", }); assert.equal(command.projectId, projectRef.slice("project:".length)); assert.equal(command.deviceId, deviceRef.slice("device:".length)); assert.equal(command.displayName, "Trike 8028"); assert.equal(command.integrationDeviceId, "8028"); assert.throws( () => normalizeLifecycleManagementCommand("device.update", { projectRef, deviceRef, displayName: "Trike 8028", integrationDeviceId: "8028", identifier: "000000000000001", }), /device_management_command_field_unexpected:identifier/, ); }); test("legacy device update does not implicitly clear the integration identity", () => { const command = normalizeLifecycleManagementCommand("device.update", { projectRef, deviceRef, displayName: "Trike 8028", }); assert.equal(command.integrationDeviceId, undefined); }); 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", }; }