diff --git a/apps/sim/app/api/credentials/route.ts b/apps/sim/app/api/credentials/route.ts index 64a3d3f951..1317ecea18 100644 --- a/apps/sim/app/api/credentials/route.ts +++ b/apps/sim/app/api/credentials/route.ts @@ -22,7 +22,7 @@ import { normalizeAtlassianDomain, validateAtlassianServiceAccount, } from '@/lib/credentials/atlassian-service-account' -import { getWorkspaceMemberUserIds } from '@/lib/credentials/environment' +import { getWorkspaceAdminUserIds, getWorkspaceMemberUserIds } from '@/lib/credentials/environment' import { syncWorkspaceOAuthCredentialsForUser } from '@/lib/credentials/oauth' import { getServiceConfigByProviderId } from '@/lib/oauth' import { @@ -535,7 +535,10 @@ export const POST = withRouteHandler(async (request: NextRequest) => { }) if ((type === 'env_workspace' || type === 'service_account') && workspaceRow?.ownerId) { - const workspaceUserIds = await getWorkspaceMemberUserIds(workspaceId) + const [workspaceUserIds, adminUserIds] = await Promise.all([ + getWorkspaceMemberUserIds(workspaceId), + getWorkspaceAdminUserIds(workspaceId), + ]) if (workspaceUserIds.length > 0) { for (const memberUserId of workspaceUserIds) { await tx.insert(credentialMember).values({ @@ -543,7 +546,7 @@ export const POST = withRouteHandler(async (request: NextRequest) => { credentialId, userId: memberUserId, role: - memberUserId === workspaceRow.ownerId || memberUserId === session.user.id + adminUserIds.has(memberUserId) || memberUserId === session.user.id ? 'admin' : 'member', status: 'active', diff --git a/apps/sim/lib/credentials/environment.ts b/apps/sim/lib/credentials/environment.ts index 0ace988407..c0e239129a 100644 --- a/apps/sim/lib/credentials/environment.ts +++ b/apps/sim/lib/credentials/environment.ts @@ -37,6 +37,31 @@ export async function getWorkspaceMemberUserIds(workspaceId: string): Promise> { + const [workspaceRows, adminPermissionRows] = await Promise.all([ + db + .select({ ownerId: workspace.ownerId }) + .from(workspace) + .where(eq(workspace.id, workspaceId)) + .limit(1), + db + .select({ userId: permissions.userId }) + .from(permissions) + .where( + and( + eq(permissions.entityType, 'workspace'), + eq(permissions.entityId, workspaceId), + eq(permissions.permissionType, 'admin') + ) + ), + ]) + const adminIds = new Set(adminPermissionRows.map((row) => row.userId)) + if (workspaceRows[0]?.ownerId) { + adminIds.add(workspaceRows[0].ownerId) + } + return adminIds +} + export async function getUserWorkspaceIds(userId: string): Promise { const [permissionRows, ownedWorkspaceRows] = await Promise.all([ db @@ -64,7 +89,8 @@ export async function getUserWorkspaceIds(userId: string): Promise { async function ensureWorkspaceCredentialMemberships( credentialId: string, memberUserIds: string[], - ownerUserId: string + ownerUserId: string, + adminUserIds: Set ) { if (!memberUserIds.length) return @@ -87,7 +113,7 @@ async function ensureWorkspaceCredentialMemberships( const now = new Date() for (const memberUserId of memberUserIds) { - const targetRole = memberUserId === ownerUserId ? 'admin' : 'member' + const targetRole = adminUserIds.has(memberUserId) ? 'admin' : 'member' const existing = byUserId.get(memberUserId) if (existing) { if (existing.status === 'revoked') { @@ -126,13 +152,14 @@ export async function syncWorkspaceEnvCredentials(params: { actingUserId: string }) { const { workspaceId, envKeys, actingUserId } = params - const [[workspaceRow], memberUserIds] = await Promise.all([ + const [[workspaceRow], memberUserIds, adminUserIds] = await Promise.all([ db .select({ ownerId: workspace.ownerId }) .from(workspace) .where(eq(workspace.id, workspaceId)) .limit(1), getWorkspaceMemberUserIds(workspaceId), + getWorkspaceAdminUserIds(workspaceId), ]) if (!workspaceRow) return @@ -182,7 +209,7 @@ export async function syncWorkspaceEnvCredentials(params: { } for (const credentialId of credentialIdsToEnsureMembership) { - await ensureWorkspaceCredentialMemberships(credentialId, memberUserIds, workspaceRow.ownerId) + await ensureWorkspaceCredentialMemberships(credentialId, memberUserIds, workspaceRow.ownerId, adminUserIds) } if (normalizedKeys.length > 0) { @@ -216,13 +243,14 @@ export async function createWorkspaceEnvCredentials(params: { const keys = Array.from(new Set(newKeys.filter(Boolean))) if (keys.length === 0) return - const [[workspaceRow], memberUserIds] = await Promise.all([ + const [[workspaceRow], memberUserIds, adminUserIds] = await Promise.all([ db .select({ ownerId: workspace.ownerId }) .from(workspace) .where(eq(workspace.id, workspaceId)) .limit(1), getWorkspaceMemberUserIds(workspaceId), + getWorkspaceAdminUserIds(workspaceId), ]) if (!workspaceRow) return @@ -259,7 +287,7 @@ export async function createWorkspaceEnvCredentials(params: { id: generateId(), credentialId, userId: memberUserId, - role: (memberUserId === ownerUserId ? 'admin' : 'member') as 'admin' | 'member', + role: (adminUserIds.has(memberUserId) ? 'admin' : 'member') as 'admin' | 'member', status: 'active' as const, joinedAt: now, invitedBy: ownerUserId,