( userId: string, workflowId: string )
| 196 | * caller can report them as retryable instead of a permanent access denial. |
| 197 | */ |
| 198 | export async function verifyWorkflowAccess( |
| 199 | userId: string, |
| 200 | workflowId: string |
| 201 | ): Promise<{ hasAccess: boolean; role?: string; workspaceId?: string }> { |
| 202 | try { |
| 203 | const workflowData = await db |
| 204 | .select({ |
| 205 | workspaceId: workflow.workspaceId, |
| 206 | name: workflow.name, |
| 207 | }) |
| 208 | .from(workflow) |
| 209 | .where(and(eq(workflow.id, workflowId), isNull(workflow.archivedAt))) |
| 210 | .limit(1) |
| 211 | |
| 212 | if (!workflowData.length) { |
| 213 | logger.warn(`Workflow ${workflowId} not found`) |
| 214 | return { hasAccess: false } |
| 215 | } |
| 216 | |
| 217 | const { workspaceId, name: workflowName } = workflowData[0] |
| 218 | const authorization = await authorizeWorkflowByWorkspacePermission({ |
| 219 | workflowId, |
| 220 | userId, |
| 221 | action: 'read', |
| 222 | }) |
| 223 | |
| 224 | if (!authorization.allowed || !authorization.workspacePermission) { |
| 225 | logger.warn( |
| 226 | `User ${userId} is not permitted to access workflow ${workflowId}: ${authorization.message}` |
| 227 | ) |
| 228 | return { hasAccess: false } |
| 229 | } |
| 230 | |
| 231 | logger.debug( |
| 232 | `User ${userId} has ${authorization.workspacePermission} access to workflow ${workflowId} (${workflowName}) via workspace ${workspaceId}` |
| 233 | ) |
| 234 | return { |
| 235 | hasAccess: true, |
| 236 | role: authorization.workspacePermission, |
| 237 | workspaceId: workspaceId || undefined, |
| 238 | } |
| 239 | } catch (error) { |
| 240 | logger.error( |
| 241 | `Error verifying workflow access for user ${userId}, workflow ${workflowId}:`, |
| 242 | error |
| 243 | ) |
| 244 | throw error |
| 245 | } |
| 246 | } |
no test coverage detected