From 1bf2dc2113619158ced8f67174331e2013191397 Mon Sep 17 00:00:00 2001 From: Scott Cazan Date: Wed, 4 Mar 2026 23:15:48 +0100 Subject: [PATCH] Default READ access on profile zone in permissions --- .../common/src/services/access/permissions.ts | 23 ++++++++++++++++- .../src/services/decision/decisionRoles.ts | 25 +++++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/packages/common/src/services/access/permissions.ts b/packages/common/src/services/access/permissions.ts index ef58f8483..7dfe107aa 100644 --- a/packages/common/src/services/access/permissions.ts +++ b/packages/common/src/services/access/permissions.ts @@ -4,7 +4,7 @@ import { accessRoles, organizationUserToAccessRoles, } from '@op/db/schema'; -import { toBitField } from 'access-zones'; +import { permission, toBitField } from 'access-zones'; import { and, eq } from 'drizzle-orm'; import { CommonError, NotFoundError } from '../../utils'; @@ -66,6 +66,27 @@ export async function createRole({ permission: toBitField(permissions), }); + // Scoped roles always get profile READ + if (zoneName !== 'profile') { + const profileZone = await tx.query.accessZones.findFirst({ + where: { name: 'profile' }, + }); + + if (profileZone) { + await tx.insert(accessRolePermissionsOnAccessZones).values({ + accessRoleId: role.id, + accessZoneId: profileZone.id, + permission: permission.READ, + }); + } + } else if (!permissions.read) { + // If creating on the profile zone but read wasn't set, force it + await tx + .update(accessRolePermissionsOnAccessZones) + .set({ permission: toBitField({ ...permissions, read: true }) }) + .where(eq(accessRolePermissionsOnAccessZones.accessRoleId, role.id)); + } + return { id: role.id, name: role.name, diff --git a/packages/common/src/services/decision/decisionRoles.ts b/packages/common/src/services/decision/decisionRoles.ts index dce2fe826..51f837ba1 100644 --- a/packages/common/src/services/decision/decisionRoles.ts +++ b/packages/common/src/services/decision/decisionRoles.ts @@ -51,6 +51,31 @@ export async function createDecisionRole({ }) { const client = tx ?? db; + // Scoped roles on a decision process always get profile READ + if (permissions['profile']) { + const existing = permissions['profile']; + if (existing.type === 'acrud') { + permissions = { + ...permissions, + profile: { type: 'acrud', value: { ...existing.value, read: true } }, + }; + } + } else { + permissions = { + ...permissions, + profile: { + type: 'acrud', + value: { + admin: false, + create: false, + read: true, + update: false, + delete: false, + }, + }, + }; + } + const zoneNames = Object.keys(permissions); const zones = await Promise.all( zoneNames.map((zoneName) =>