Skip to content

Commit 7c9128d

Browse files
committed
remove user check, rely on source-of-truth permissions to display logs
1 parent 40f0a42 commit 7c9128d

File tree

7 files changed

+102
-63
lines changed

7 files changed

+102
-63
lines changed

apps/sim/app/api/logs/enhanced/route.ts

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ const QueryParamsSchema = z.object({
5656
startDate: z.string().optional(),
5757
endDate: z.string().optional(),
5858
search: z.string().optional(),
59-
workspaceId: z.string().optional(), // Filter by specific workspace ID
59+
workspaceId: z.string(),
6060
})
6161

6262
export async function GET(request: NextRequest) {
@@ -75,18 +75,12 @@ export async function GET(request: NextRequest) {
7575
const { searchParams } = new URL(request.url)
7676
const params = QueryParamsSchema.parse(Object.fromEntries(searchParams.entries()))
7777

78-
// Get workflows that user can access through direct ownership OR workspace permissions
79-
// If workspaceId is provided, filter workflows to only that workspace
80-
let workflowConditions = or(
81-
eq(workflow.userId, userId),
82-
and(eq(permissions.userId, userId), eq(permissions.entityType, 'workspace'))
78+
const workflowConditions = and(
79+
eq(workflow.workspaceId, params.workspaceId),
80+
eq(permissions.userId, userId),
81+
eq(permissions.entityType, 'workspace')
8382
)
8483

85-
// If workspaceId is specified, filter workflows to only that workspace
86-
if (params.workspaceId) {
87-
workflowConditions = and(eq(workflow.workspaceId, params.workspaceId), workflowConditions)
88-
}
89-
9084
const userWorkflows = await db
9185
.select({ id: workflow.id, folderId: workflow.folderId })
9286
.from(workflow)

apps/sim/app/api/logs/route.test.ts

Lines changed: 71 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
* @vitest-environment node
55
*/
66
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
7-
import { createMockRequest } from '@/app/api/__test-utils__/utils'
87

98
describe('Workflow Logs API Route', () => {
109
const mockWorkflowLogs = [
@@ -54,6 +53,7 @@ describe('Workflow Logs API Route', () => {
5453
{
5554
id: 'workflow-1',
5655
userId: 'user-123',
56+
workspaceId: 'workspace-123',
5757
folderId: 'folder-1',
5858
name: 'Test Workflow 1',
5959
color: '#3972F6',
@@ -65,6 +65,7 @@ describe('Workflow Logs API Route', () => {
6565
{
6666
id: 'workflow-2',
6767
userId: 'user-123',
68+
workspaceId: 'workspace-123',
6869
folderId: 'folder-2',
6970
name: 'Test Workflow 2',
7071
color: '#FF6B6B',
@@ -76,6 +77,7 @@ describe('Workflow Logs API Route', () => {
7677
{
7778
id: 'workflow-3',
7879
userId: 'user-123',
80+
workspaceId: 'workspace-123',
7981
folderId: null,
8082
name: 'Test Workflow 3',
8183
color: '#22C55E',
@@ -192,6 +194,7 @@ describe('Workflow Logs API Route', () => {
192194
workflow: {
193195
id: 'workflow.id',
194196
userId: 'workflow.userId',
197+
workspaceId: 'workflow.workspaceId',
195198
name: 'workflow.name',
196199
color: 'workflow.color',
197200
description: 'workflow.description',
@@ -212,10 +215,11 @@ describe('Workflow Logs API Route', () => {
212215
it('should return logs successfully with default parameters', async () => {
213216
setupDatabaseMock()
214217

215-
const req = createMockRequest('GET')
218+
const url = new URL('http://localhost:3000/api/logs?workspaceId=workspace-123')
219+
const req = new Request(url.toString())
216220

217221
const { GET } = await import('./route')
218-
const response = await GET(req)
222+
const response = await GET(req as any)
219223
const data = await response.json()
220224

221225
expect(response.status).toBe(200)
@@ -231,7 +235,9 @@ describe('Workflow Logs API Route', () => {
231235
it('should include workflow data when includeWorkflow=true', async () => {
232236
setupDatabaseMock()
233237

234-
const url = new URL('http://localhost:3000/api/logs?includeWorkflow=true')
238+
const url = new URL(
239+
'http://localhost:3000/api/logs?workspaceId=workspace-123&includeWorkflow=true'
240+
)
235241
const req = new Request(url.toString())
236242

237243
const { GET } = await import('./route')
@@ -248,7 +254,7 @@ describe('Workflow Logs API Route', () => {
248254
const errorLogs = mockWorkflowLogs.filter((log) => log.level === 'error')
249255
setupDatabaseMock({ logs: errorLogs })
250256

251-
const url = new URL('http://localhost:3000/api/logs?level=error')
257+
const url = new URL('http://localhost:3000/api/logs?workspaceId=workspace-123&level=error')
252258
const req = new Request(url.toString())
253259

254260
const { GET } = await import('./route')
@@ -264,7 +270,9 @@ describe('Workflow Logs API Route', () => {
264270
const workflow1Logs = mockWorkflowLogs.filter((log) => log.workflowId === 'workflow-1')
265271
setupDatabaseMock({ logs: workflow1Logs })
266272

267-
const url = new URL('http://localhost:3000/api/logs?workflowIds=workflow-1')
273+
const url = new URL(
274+
'http://localhost:3000/api/logs?workspaceId=workspace-123&workflowIds=workflow-1'
275+
)
268276
const req = new Request(url.toString())
269277

270278
const { GET } = await import('./route')
@@ -283,7 +291,9 @@ describe('Workflow Logs API Route', () => {
283291
)
284292
setupDatabaseMock({ logs: filteredLogs })
285293

286-
const url = new URL('http://localhost:3000/api/logs?workflowIds=workflow-1,workflow-2')
294+
const url = new URL(
295+
'http://localhost:3000/api/logs?workspaceId=workspace-123&workflowIds=workflow-1,workflow-2'
296+
)
287297
const req = new Request(url.toString())
288298

289299
const { GET } = await import('./route')
@@ -301,7 +311,9 @@ describe('Workflow Logs API Route', () => {
301311
)
302312
setupDatabaseMock({ logs: filteredLogs })
303313

304-
const url = new URL(`http://localhost:3000/api/logs?startDate=${startDate}`)
314+
const url = new URL(
315+
`http://localhost:3000/api/logs?workspaceId=workspace-123&startDate=${startDate}`
316+
)
305317
const req = new Request(url.toString())
306318

307319
const { GET } = await import('./route')
@@ -318,7 +330,7 @@ describe('Workflow Logs API Route', () => {
318330
)
319331
setupDatabaseMock({ logs: searchLogs })
320332

321-
const url = new URL('http://localhost:3000/api/logs?search=failed')
333+
const url = new URL('http://localhost:3000/api/logs?workspaceId=workspace-123&search=failed')
322334
const req = new Request(url.toString())
323335

324336
const { GET } = await import('./route')
@@ -334,7 +346,9 @@ describe('Workflow Logs API Route', () => {
334346
const paginatedLogs = mockWorkflowLogs.slice(1, 3)
335347
setupDatabaseMock({ logs: paginatedLogs })
336348

337-
const url = new URL('http://localhost:3000/api/logs?limit=2&offset=1')
349+
const url = new URL(
350+
'http://localhost:3000/api/logs?workspaceId=workspace-123&limit=2&offset=1'
351+
)
338352
const req = new Request(url.toString())
339353

340354
const { GET } = await import('./route')
@@ -352,10 +366,11 @@ describe('Workflow Logs API Route', () => {
352366
it('should return empty array when user has no workflows', async () => {
353367
setupDatabaseMock({ userWorkflows: [], logs: [], workflows: [] })
354368

355-
const req = createMockRequest('GET')
369+
const url = new URL('http://localhost:3000/api/logs?workspaceId=workspace-123')
370+
const req = new Request(url.toString())
356371

357372
const { GET } = await import('./route')
358-
const response = await GET(req)
373+
const response = await GET(req as any)
359374
const data = await response.json()
360375

361376
expect(response.status).toBe(200)
@@ -369,7 +384,9 @@ describe('Workflow Logs API Route', () => {
369384
userWorkflows: mockWorkflows.filter((w) => w.id !== 'unauthorized-workflow'),
370385
})
371386

372-
const url = new URL('http://localhost:3000/api/logs?workflowIds=unauthorized-workflow')
387+
const url = new URL(
388+
'http://localhost:3000/api/logs?workspaceId=workspace-123&workflowIds=unauthorized-workflow'
389+
)
373390
const req = new Request(url.toString())
374391

375392
const { GET } = await import('./route')
@@ -388,10 +405,11 @@ describe('Workflow Logs API Route', () => {
388405

389406
setupDatabaseMock()
390407

391-
const req = createMockRequest('GET')
408+
const url = new URL('http://localhost:3000/api/logs?workspaceId=workspace-123')
409+
const req = new Request(url.toString())
392410

393411
const { GET } = await import('./route')
394-
const response = await GET(req)
412+
const response = await GET(req as any)
395413
const data = await response.json()
396414

397415
expect(response.status).toBe(401)
@@ -401,7 +419,7 @@ describe('Workflow Logs API Route', () => {
401419
it('should validate query parameters', async () => {
402420
setupDatabaseMock()
403421

404-
const url = new URL('http://localhost:3000/api/logs?limit=invalid')
422+
const url = new URL('http://localhost:3000/api/logs?workspaceId=workspace-123&limit=invalid')
405423
const req = new Request(url.toString())
406424

407425
const { GET } = await import('./route')
@@ -416,10 +434,11 @@ describe('Workflow Logs API Route', () => {
416434
it('should handle database errors gracefully', async () => {
417435
setupDatabaseMock({ throwError: true })
418436

419-
const req = createMockRequest('GET')
437+
const url = new URL('http://localhost:3000/api/logs?workspaceId=workspace-123')
438+
const req = new Request(url.toString())
420439

421440
const { GET } = await import('./route')
422-
const response = await GET(req)
441+
const response = await GET(req as any)
423442
const data = await response.json()
424443

425444
expect(response.status).toBe(500)
@@ -436,7 +455,7 @@ describe('Workflow Logs API Route', () => {
436455
setupDatabaseMock({ logs: filteredLogs })
437456

438457
const url = new URL(
439-
'http://localhost:3000/api/logs?level=info&workflowIds=workflow-1&search=started'
458+
'http://localhost:3000/api/logs?workspaceId=workspace-123&level=info&workflowIds=workflow-1&search=started'
440459
)
441460
const req = new Request(url.toString())
442461

@@ -458,7 +477,9 @@ describe('Workflow Logs API Route', () => {
458477
)
459478
setupDatabaseMock({ logs: filteredLogs })
460479

461-
const url = new URL(`http://localhost:3000/api/logs?endDate=${endDate}`)
480+
const url = new URL(
481+
`http://localhost:3000/api/logs?workspaceId=workspace-123&endDate=${endDate}`
482+
)
462483
const req = new Request(url.toString())
463484

464485
const { GET } = await import('./route')
@@ -472,7 +493,9 @@ describe('Workflow Logs API Route', () => {
472493
it('should handle large offset values', async () => {
473494
setupDatabaseMock({ logs: [] })
474495

475-
const url = new URL('http://localhost:3000/api/logs?limit=10&offset=1000')
496+
const url = new URL(
497+
'http://localhost:3000/api/logs?workspaceId=workspace-123&limit=10&offset=1000'
498+
)
476499
const req = new Request(url.toString())
477500

478501
const { GET } = await import('./route')
@@ -489,7 +512,7 @@ describe('Workflow Logs API Route', () => {
489512
const searchLogs = mockWorkflowLogs.filter((log) => log.executionId?.includes('exec-1'))
490513
setupDatabaseMock({ logs: searchLogs })
491514

492-
const url = new URL('http://localhost:3000/api/logs?search=exec-1')
515+
const url = new URL('http://localhost:3000/api/logs?workspaceId=workspace-123&search=exec-1')
493516
const req = new Request(url.toString())
494517

495518
const { GET } = await import('./route')
@@ -505,7 +528,7 @@ describe('Workflow Logs API Route', () => {
505528
const apiLogs = mockWorkflowLogs.filter((log) => log.trigger === 'api')
506529
setupDatabaseMock({ logs: apiLogs })
507530

508-
const url = new URL('http://localhost:3000/api/logs?triggers=api')
531+
const url = new URL('http://localhost:3000/api/logs?workspaceId=workspace-123&triggers=api')
509532
const req = new Request(url.toString())
510533

511534
const { GET } = await import('./route')
@@ -523,7 +546,9 @@ describe('Workflow Logs API Route', () => {
523546
)
524547
setupDatabaseMock({ logs: manualAndApiLogs })
525548

526-
const url = new URL('http://localhost:3000/api/logs?triggers=manual,api')
549+
const url = new URL(
550+
'http://localhost:3000/api/logs?workspaceId=workspace-123&triggers=manual,api'
551+
)
527552
const req = new Request(url.toString())
528553

529554
const { GET } = await import('./route')
@@ -542,7 +567,7 @@ describe('Workflow Logs API Route', () => {
542567
setupDatabaseMock({ logs: filteredLogs })
543568

544569
const url = new URL(
545-
'http://localhost:3000/api/logs?triggers=manual&level=info&workflowIds=workflow-1'
570+
'http://localhost:3000/api/logs?workspaceId=workspace-123&triggers=manual&level=info&workflowIds=workflow-1'
546571
)
547572
const req = new Request(url.toString())
548573

@@ -561,7 +586,9 @@ describe('Workflow Logs API Route', () => {
561586
const folder1Logs = mockWorkflowLogs.filter((log) => log.workflowId === 'workflow-1')
562587
setupDatabaseMock({ logs: folder1Logs })
563588

564-
const url = new URL('http://localhost:3000/api/logs?folderIds=folder-1')
589+
const url = new URL(
590+
'http://localhost:3000/api/logs?workspaceId=workspace-123&folderIds=folder-1'
591+
)
565592
const req = new Request(url.toString())
566593

567594
const { GET } = await import('./route')
@@ -579,7 +606,9 @@ describe('Workflow Logs API Route', () => {
579606
)
580607
setupDatabaseMock({ logs: folder1And2Logs })
581608

582-
const url = new URL('http://localhost:3000/api/logs?folderIds=folder-1,folder-2')
609+
const url = new URL(
610+
'http://localhost:3000/api/logs?workspaceId=workspace-123&folderIds=folder-1,folder-2'
611+
)
583612
const req = new Request(url.toString())
584613

585614
const { GET } = await import('./route')
@@ -597,7 +626,7 @@ describe('Workflow Logs API Route', () => {
597626
const rootLogs = mockWorkflowLogs.filter((log) => log.workflowId === 'workflow-3')
598627
setupDatabaseMock({ logs: rootLogs })
599628

600-
const url = new URL('http://localhost:3000/api/logs?folderIds=root')
629+
const url = new URL('http://localhost:3000/api/logs?workspaceId=workspace-123&folderIds=root')
601630
const req = new Request(url.toString())
602631

603632
const { GET } = await import('./route')
@@ -616,7 +645,9 @@ describe('Workflow Logs API Route', () => {
616645
)
617646
setupDatabaseMock({ logs: rootAndFolder1Logs })
618647

619-
const url = new URL('http://localhost:3000/api/logs?folderIds=root,folder-1')
648+
const url = new URL(
649+
'http://localhost:3000/api/logs?workspaceId=workspace-123&folderIds=root,folder-1'
650+
)
620651
const req = new Request(url.toString())
621652

622653
const { GET } = await import('./route')
@@ -636,7 +667,7 @@ describe('Workflow Logs API Route', () => {
636667
setupDatabaseMock({ logs: filteredLogs })
637668

638669
const url = new URL(
639-
'http://localhost:3000/api/logs?folderIds=folder-1&workflowIds=workflow-1'
670+
'http://localhost:3000/api/logs?workspaceId=workspace-123&folderIds=folder-1&workflowIds=workflow-1'
640671
)
641672
const req = new Request(url.toString())
642673

@@ -654,7 +685,7 @@ describe('Workflow Logs API Route', () => {
654685
setupDatabaseMock({ logs: [] })
655686

656687
const url = new URL(
657-
'http://localhost:3000/api/logs?folderIds=folder-1&workflowIds=workflow-2'
688+
'http://localhost:3000/api/logs?workspaceId=workspace-123&folderIds=folder-1&workflowIds=workflow-2'
658689
)
659690
const req = new Request(url.toString())
660691

@@ -673,7 +704,9 @@ describe('Workflow Logs API Route', () => {
673704
)
674705
setupDatabaseMock({ logs: filteredLogs })
675706

676-
const url = new URL('http://localhost:3000/api/logs?folderIds=folder-1&level=info')
707+
const url = new URL(
708+
'http://localhost:3000/api/logs?workspaceId=workspace-123&folderIds=folder-1&level=info'
709+
)
677710
const req = new Request(url.toString())
678711

679712
const { GET } = await import('./route')
@@ -689,7 +722,9 @@ describe('Workflow Logs API Route', () => {
689722
it('should return empty result when no workflows match folder filter', async () => {
690723
setupDatabaseMock({ logs: [] })
691724

692-
const url = new URL('http://localhost:3000/api/logs?folderIds=non-existent-folder')
725+
const url = new URL(
726+
'http://localhost:3000/api/logs?workspaceId=workspace-123&folderIds=non-existent-folder'
727+
)
693728
const req = new Request(url.toString())
694729

695730
const { GET } = await import('./route')
@@ -705,7 +740,9 @@ describe('Workflow Logs API Route', () => {
705740
const folder1Logs = mockWorkflowLogs.filter((log) => log.workflowId === 'workflow-1')
706741
setupDatabaseMock({ logs: folder1Logs })
707742

708-
const url = new URL('http://localhost:3000/api/logs?folderIds=folder-1&includeWorkflow=true')
743+
const url = new URL(
744+
'http://localhost:3000/api/logs?workspaceId=workspace-123&folderIds=folder-1&includeWorkflow=true'
745+
)
709746
const req = new Request(url.toString())
710747

711748
const { GET } = await import('./route')

0 commit comments

Comments
 (0)