fix(device-plane): reconcile failed manager activation

This commit is contained in:
Codex
2026-08-11 09:35:58 +03:00
parent 8defd55715
commit 37bdbebb4e
9 changed files with 735 additions and 18 deletions
@@ -0,0 +1,29 @@
export const NDC_CREDENTIAL_REFERENCE_OWNER = "ndc_l2_credentials";
const CREDENTIAL_REFERENCE_PATTERN =
/^ndc-credref:[A-Za-z0-9][A-Za-z0-9._:-]{7,240}$/;
export function normalizeNdcCredentialReference(input) {
if (!input || typeof input !== "object" || Array.isArray(input)) {
throw new TypeError("ndc_credential_reference_invalid");
}
for (const key of Object.keys(input)) {
if (!new Set(["owner", "reference"]).has(key)) {
throw new TypeError(`ndc_credential_reference_field_unexpected:${key}`);
}
}
if (input.owner !== NDC_CREDENTIAL_REFERENCE_OWNER) {
throw new TypeError("ndc_credential_reference_owner_invalid");
}
if (!isNdcCredentialReferenceValue(input.reference)) {
throw new TypeError("ndc_credential_reference_value_invalid");
}
return Object.freeze({
owner: NDC_CREDENTIAL_REFERENCE_OWNER,
reference: input.reference,
});
}
export function isNdcCredentialReferenceValue(value) {
return typeof value === "string" && CREDENTIAL_REFERENCE_PATTERN.test(value);
}
@@ -1,6 +1,6 @@
import {
normalizeNdcCredentialReference,
} from "../../../../packages/external-provider-contract/src/credential-reference.mjs";
} from "./credential-reference.mjs";
export const DEVICE_SENSITIVE_REFERENCE_COMMAND_KINDS = Object.freeze([
"device_credential_binding.upsert",
@@ -9,6 +9,12 @@ import {
ALL_DEVICE_MANAGEMENT_COMMAND_KINDS,
normalizeDeviceManagementCommand,
} from "../src/management-command.mjs";
import {
normalizeNdcCredentialReference as normalizeRuntimeCredentialReference,
} from "../src/credential-reference.mjs";
import {
normalizeNdcCredentialReference as normalizePlatformCredentialReference,
} from "../../../../packages/external-provider-contract/src/credential-reference.mjs";
const projectRef = "project:11111111-1111-4111-8111-111111111111";
const deviceRef = "device:22222222-2222-4222-8222-222222222222";
@@ -65,6 +71,52 @@ test("credential binding accepts only the platform canonical opaque ref", () =>
);
});
test("runtime credential reference adapter matches the platform contract", () => {
const accepted = [
{
owner: "ndc_l2_credentials",
reference: "ndc-credref:pilot-command-0001",
},
{
owner: "ndc_l2_credentials",
reference: "ndc-credref:A1234567",
},
];
for (const input of accepted) {
assert.deepEqual(
normalizeRuntimeCredentialReference(input),
normalizePlatformCredentialReference(input),
);
}
const rejected = [
null,
[],
{ owner: "device_core", reference: "ndc-credref:pilot-command-0001" },
{ owner: "ndc_l2_credentials", reference: "secret:test" },
{
owner: "ndc_l2_credentials",
reference: "ndc-credref:pilot-command-0001",
token: "forbidden",
},
];
for (const input of rejected) {
let runtimeError;
let platformError;
try {
normalizeRuntimeCredentialReference(input);
} catch (error) {
runtimeError = error;
}
try {
normalizePlatformCredentialReference(input);
} catch (error) {
platformError = error;
}
assert.equal(runtimeError?.message, platformError?.message);
}
});
test("credential binding rejects raw secret-shaped fields", () => {
for (const field of ["password", "token", "secretValue", "endpoint"]) {
assert.throws(