From 6e8efad50c22add2aa4d6773201dcf7209436936 Mon Sep 17 00:00:00 2001 From: SaladDay <1203511142@qq.com> Date: Sat, 26 Sep 2026 01:00:59 +0000 Subject: [PATCH] Require the enrollment ID on every sandbox node in the client Core always sends enrollment_id on /core/v1/sandbox/nodes list and detail reads: a string, or null for nodes enrolled before Core recorded it. The client typed it as optional only until Web's fixtures included it (#145), so SandboxNode.enrollment_id is now a required string | null. --- packages/agents-client/src/sandbox-client.test.ts | 9 +++++++++ packages/agents-client/src/sandbox-client.ts | 7 ++----- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/packages/agents-client/src/sandbox-client.test.ts b/packages/agents-client/src/sandbox-client.test.ts index 5a26ccf7c..b7ac20b6c 100644 --- a/packages/agents-client/src/sandbox-client.test.ts +++ b/packages/agents-client/src/sandbox-client.test.ts @@ -30,6 +30,15 @@ describe("Core sandbox credential boundaries", () => { expect(data[0]?.diagnostic).toBe("kvm_unavailable"); expectTypeOf().toEqualTypeOf(); }); + it("requires each node's enrollment ID: a string, or null for nodes enrolled before Core recorded it", async () => { + const fetch = vi.fn().mockResolvedValue(response({ data: [{ id: "enrolled", enrollment_id: "3b0c1f4e-8a2d-4c6b-9e7f-1a2b3c4d5e6f" }, { id: "legacy", enrollment_id: null }] })); + const { data } = await new SandboxAdminClient({ fetch }).listNodes(); + expect(data.map((node) => node.enrollment_id)).toEqual(["3b0c1f4e-8a2d-4c6b-9e7f-1a2b3c4d5e6f", null]); + expectTypeOf().toEqualTypeOf(); + expectTypeOf<{ enrollment_id: string }>().toExtend>(); + expectTypeOf<{ enrollment_id: null }>().toExtend>(); + expectTypeOf>().not.toExtend(); + }); it("does not retry an enrollment write with an uncertain outcome", async () => { const fetch = vi.fn().mockRejectedValue(new TypeError("Network failed")); const client = new SandboxAdminClient({ baseUrl: "/core/v1/sandbox", fetch }); diff --git a/packages/agents-client/src/sandbox-client.ts b/packages/agents-client/src/sandbox-client.ts index 7eb4dda35..567e6053a 100644 --- a/packages/agents-client/src/sandbox-client.ts +++ b/packages/agents-client/src/sandbox-client.ts @@ -75,11 +75,8 @@ export interface SandboxNode { created_at: string; /** Read-only: the Core address this node enrolled with. When it differs from the installation public URL, the node receives no new sandboxes and must be re-added. */ readonly core_url: string; - /** - * Read-only: the `enrollment_id` of the command that registered this node; null for nodes enrolled - * before Core recorded it. Core always sends the member; it is optional here only until Web's fixtures include it. - */ - readonly enrollment_id?: string | null; + /** Read-only: the `enrollment_id` of the command that registered this node; null for nodes enrolled before Core recorded it. Core always sends the member. */ + readonly enrollment_id: string | null; } /** A one-time node enrollment command issued by Core. */ export interface SandboxEnrollment {