diff --git a/src/gateway/method-scopes.test.ts b/src/gateway/method-scopes.test.ts index 1479611d484..18ff74509ee 100644 --- a/src/gateway/method-scopes.test.ts +++ b/src/gateway/method-scopes.test.ts @@ -18,6 +18,10 @@ describe("method scope resolution", () => { expect(resolveLeastPrivilegeOperatorScopesForMethod("poll")).toEqual(["operator.write"]); }); + it("leaves node-only pending drain outside operator scopes", () => { + expect(resolveLeastPrivilegeOperatorScopesForMethod("node.pending.drain")).toEqual([]); + }); + it("returns empty scopes for unknown methods", () => { expect(resolveLeastPrivilegeOperatorScopesForMethod("totally.unknown.method")).toEqual([]); }); diff --git a/src/gateway/method-scopes.ts b/src/gateway/method-scopes.ts index f1170c9889d..ec8279a1947 100644 --- a/src/gateway/method-scopes.ts +++ b/src/gateway/method-scopes.ts @@ -22,6 +22,7 @@ export const CLI_DEFAULT_OPERATOR_SCOPES: OperatorScope[] = [ const NODE_ROLE_METHODS = new Set([ "node.invoke.result", "node.event", + "node.pending.drain", "node.canvas.capability.refresh", "node.pending.pull", "node.pending.ack", @@ -78,7 +79,6 @@ const METHOD_SCOPE_GROUPS: Record = { "last-heartbeat", "node.list", "node.describe", - "node.pending.drain", "chat.history", "config.get", "config.schema.lookup", diff --git a/src/gateway/role-policy.test.ts b/src/gateway/role-policy.test.ts index 4c3815ec9a3..5bc3e1f1a28 100644 --- a/src/gateway/role-policy.test.ts +++ b/src/gateway/role-policy.test.ts @@ -24,7 +24,7 @@ describe("gateway role policy", () => { expect(isRoleAuthorizedForMethod("node", "node.pending.drain")).toBe(true); expect(isRoleAuthorizedForMethod("node", "status")).toBe(false); expect(isRoleAuthorizedForMethod("operator", "status")).toBe(true); - expect(isRoleAuthorizedForMethod("operator", "node.pending.drain")).toBe(true); + expect(isRoleAuthorizedForMethod("operator", "node.pending.drain")).toBe(false); expect(isRoleAuthorizedForMethod("operator", "node.event")).toBe(false); }); }); diff --git a/src/gateway/role-policy.ts b/src/gateway/role-policy.ts index 07b65eea8ca..8366cd1c6c2 100644 --- a/src/gateway/role-policy.ts +++ b/src/gateway/role-policy.ts @@ -1,7 +1,6 @@ import { isNodeRoleMethod } from "./method-scopes.js"; export const GATEWAY_ROLES = ["operator", "node"] as const; -const SHARED_ROLE_METHODS = new Set(["node.pending.drain"]); export type GatewayRole = (typeof GATEWAY_ROLES)[number]; @@ -17,9 +16,6 @@ export function roleCanSkipDeviceIdentity(role: GatewayRole, sharedAuthOk: boole } export function isRoleAuthorizedForMethod(role: GatewayRole, method: string): boolean { - if (SHARED_ROLE_METHODS.has(method)) { - return true; - } if (isNodeRoleMethod(method)) { return role === "node"; }