Skip to content

Commit d92d9a0

Browse files
fix(permissions): cannot create workflow with read perms (#1671)
1 parent 64ede7f commit d92d9a0

File tree

2 files changed

+42
-16
lines changed
  • apps/sim/app

2 files changed

+42
-16
lines changed

apps/sim/app/api/workflows/route.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { type NextRequest, NextResponse } from 'next/server'
55
import { z } from 'zod'
66
import { getSession } from '@/lib/auth'
77
import { createLogger } from '@/lib/logs/console/logger'
8+
import { getUserEntityPermissions } from '@/lib/permissions/utils'
89
import { generateRequestId } from '@/lib/utils'
910
import { verifyWorkspaceMembership } from './utils'
1011

@@ -94,6 +95,24 @@ export async function POST(req: NextRequest) {
9495
const body = await req.json()
9596
const { name, description, color, workspaceId, folderId } = CreateWorkflowSchema.parse(body)
9697

98+
if (workspaceId) {
99+
const workspacePermission = await getUserEntityPermissions(
100+
session.user.id,
101+
'workspace',
102+
workspaceId
103+
)
104+
105+
if (!workspacePermission || workspacePermission === 'read') {
106+
logger.warn(
107+
`[${requestId}] User ${session.user.id} attempted to create workflow in workspace ${workspaceId} without write permissions`
108+
)
109+
return NextResponse.json(
110+
{ error: 'Write or Admin access required to create workflows in this workspace' },
111+
{ status: 403 }
112+
)
113+
}
114+
}
115+
97116
const workflowId = crypto.randomUUID()
98117
const now = new Date()
99118

apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/create-menu/create-menu.tsx

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -323,9 +323,12 @@ export function CreateMenu({ onCreateWorkflow, isCreatingWorkflow = false }: Cre
323323
>
324324
{/* New Workflow */}
325325
<button
326-
className={cn(menuItemClassName, isCreatingWorkflow && 'cursor-not-allowed opacity-50')}
326+
className={cn(
327+
menuItemClassName,
328+
(isCreatingWorkflow || !userPermissions.canEdit) && 'cursor-not-allowed opacity-50'
329+
)}
327330
onClick={handleCreateWorkflow}
328-
disabled={isCreatingWorkflow}
331+
disabled={isCreatingWorkflow || !userPermissions.canEdit}
329332
>
330333
<Plus className={iconClassName} />
331334
<span className={textClassName}>
@@ -335,27 +338,31 @@ export function CreateMenu({ onCreateWorkflow, isCreatingWorkflow = false }: Cre
335338

336339
{/* New Folder */}
337340
<button
338-
className={cn(menuItemClassName, isCreating && 'cursor-not-allowed opacity-50')}
341+
className={cn(
342+
menuItemClassName,
343+
(isCreating || !userPermissions.canEdit) && 'cursor-not-allowed opacity-50'
344+
)}
339345
onClick={handleCreateFolder}
340-
disabled={isCreating}
346+
disabled={isCreating || !userPermissions.canEdit}
341347
>
342348
<Folder className={iconClassName} />
343349
<span className={textClassName}>{isCreating ? 'Creating...' : 'New folder'}</span>
344350
</button>
345351

346352
{/* Import Workflow */}
347-
{userPermissions.canEdit && (
348-
<button
349-
className={cn(menuItemClassName, isImporting && 'cursor-not-allowed opacity-50')}
350-
onClick={handleImportWorkflow}
351-
disabled={isImporting}
352-
>
353-
<Download className={iconClassName} />
354-
<span className={textClassName}>
355-
{isImporting ? 'Importing...' : 'Import workflow'}
356-
</span>
357-
</button>
358-
)}
353+
<button
354+
className={cn(
355+
menuItemClassName,
356+
(isImporting || !userPermissions.canEdit) && 'cursor-not-allowed opacity-50'
357+
)}
358+
onClick={handleImportWorkflow}
359+
disabled={isImporting || !userPermissions.canEdit}
360+
>
361+
<Download className={iconClassName} />
362+
<span className={textClassName}>
363+
{isImporting ? 'Importing...' : 'Import workflow'}
364+
</span>
365+
</button>
359366
</PopoverContent>
360367
</Popover>
361368

0 commit comments

Comments
 (0)