From cc5694449f8a2332c363bb8cc20a8a032d6a34aa Mon Sep 17 00:00:00 2001 From: cryppadotta <34892728+cryppadotta@users.noreply.github.com> Date: Thu, 10 Sep 2026 19:32:56 +0000 Subject: [PATCH] fix(auth): preserve scoped grants on demotion --- .../access-routes-permissions-upgrade.test.ts | 22 ++++++++++--------- server/src/services/access.ts | 3 ++- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/server/src/__tests__/access-routes-permissions-upgrade.test.ts b/server/src/__tests__/access-routes-permissions-upgrade.test.ts index df764563ca..915f487f86 100644 --- a/server/src/__tests__/access-routes-permissions-upgrade.test.ts +++ b/server/src/__tests__/access-routes-permissions-upgrade.test.ts @@ -144,19 +144,21 @@ describeEmbeddedPostgres("access routes permissions upgrade compatibility", () = .then((rows) => rows[0]!); const customScope = { projectIds: ["project-1"] }; await db.insert(principalPermissionGrants).values([ - ...grantsForHumanRole("admin").map((grant) => ({ - companyId: company.id, - principalType: "user" as const, - principalId: member.principalId, - permissionKey: grant.permissionKey, - scope: grant.scope, - grantedByUserId: owner.principalId, - })), + ...grantsForHumanRole("admin") + .filter((grant) => grant.permissionKey !== "tools:use") + .map((grant) => ({ + companyId: company.id, + principalType: "user" as const, + principalId: member.principalId, + permissionKey: grant.permissionKey, + scope: grant.scope, + grantedByUserId: owner.principalId, + })), { companyId: company.id, principalType: "user" as const, principalId: member.principalId, - permissionKey: "tasks:assign_scope" as const, + permissionKey: "tools:use" as const, scope: customScope, grantedByUserId: owner.principalId, }, @@ -193,7 +195,7 @@ describeEmbeddedPostgres("access routes permissions upgrade compatibility", () = scope: null, }), expect.objectContaining({ - permissionKey: "tasks:assign_scope", + permissionKey: "tools:use", scope: customScope, grantedByUserId: owner.principalId, }), diff --git a/server/src/services/access.ts b/server/src/services/access.ts index 19fd2e23dc..e71f4be22c 100644 --- a/server/src/services/access.ts +++ b/server/src/services/access.ts @@ -1,4 +1,4 @@ -import { and, eq, inArray, ne, notInArray, sql } from "drizzle-orm"; +import { and, eq, inArray, isNull, ne, notInArray, sql } from "drizzle-orm"; import type { Db } from "@paperclipai/db"; import { companyMemberships, @@ -1137,6 +1137,7 @@ export function accessService(db: Db) { eq(principalPermissionGrants.principalType, "user"), eq(principalPermissionGrants.principalId, existing.principalId), inArray(principalPermissionGrants.permissionKey, retiredDefaultKeys), + isNull(principalPermissionGrants.scope), )); } }