fix(nodes): preserve operator name on reapproval

This commit is contained in:
Peter Steinberger
2026-08-01 12:53:05 -07:00
parent 165c968f95
commit d352beed78
2 changed files with 40 additions and 5 deletions

View File

@@ -36,11 +36,12 @@ async function seedNodeDevice(baseDir: string, nodeId: string): Promise<void> {
await approveDevicePairing(request.request.requestId, { callerScopes: [] }, baseDir);
}
async function setupPairedNode(baseDir: string): Promise<void> {
async function setupPairedNode(baseDir: string, displayName?: string): Promise<void> {
await seedNodeDevice(baseDir, "node-1");
const request = await requestNodePairing(
{
nodeId: "node-1",
displayName,
platform: "darwin",
commands: ["system.run"],
},
@@ -783,17 +784,50 @@ describe("node surface approvals", () => {
});
});
test("renames the operator-facing node name without touching approval state", async () => {
test("keeps the operator-facing node name through capability reapproval", async () => {
await withNodePairingDir(async (baseDir) => {
await setupPairedNode(baseDir);
await setupPairedNode(baseDir, "Reported iPad");
const initialGeneration = resolveNodePairingGeneration(
await getPairedDevice("node-1", baseDir),
);
if (!initialGeneration) {
throw new Error("expected initial node pairing generation");
}
const upgrade = await requestNodePairing(
{
nodeId: "node-1",
displayName: "Reported iPad (updated)",
platform: "darwin",
commands: ["system.run", "canvas.snapshot"],
},
baseDir,
);
expect(upgrade.request.displayName).toBe("Reported iPad (updated)");
const renamed = await renamePairedNode("node-1", "Living Room iPad", baseDir);
expect(renamed?.displayName).toBe("Living Room iPad");
await expect(renamePairedNode("missing", "Nope", baseDir)).resolves.toBeNull();
await expect(
approveNodePairing(
upgrade.request.requestId,
{ callerScopes: ["operator.pairing", "operator.admin", "operator.write"] },
baseDir,
),
).resolves.toMatchObject({
node: {
displayName: "Living Room iPad",
commands: ["system.run", "canvas.snapshot"],
},
});
const pairedNode = await findPairedNode("node-1", baseDir);
expect(pairedNode?.displayName).toBe("Living Room iPad");
expect(pairedNode?.commands).toEqual(["system.run"]);
expect(pairedNode?.commands).toEqual(["system.run", "canvas.snapshot"]);
expect((await listNodePairing(baseDir)).pending).toEqual([]);
expect(resolveNodePairingGeneration(await getPairedDevice("node-1", baseDir))?.key).not.toBe(
initialGeneration.key,
);
});
});
});

View File

@@ -569,7 +569,8 @@ export async function approveNodePairing(
const previousPairingGeneration = resolveNodePairingGeneration(device);
const now = Math.max(Date.now(), (device.nodeSurface?.approvedAtMs ?? -1) + 1);
device.nodeSurface = {
displayName: pending.displayName,
// Reapproval refreshes the node-declared surface without replacing the operator-owned name.
displayName: device.nodeSurface?.displayName ?? pending.displayName,
version: pending.version,
coreVersion: pending.coreVersion,
uiVersion: pending.uiVersion,