Skip to content

Commit 888a246

Browse files
PlaneInABottleGitHub Copilot
andcommitted
fix: align workflow audit actors for API keys
Co-authored-by: GitHub Copilot <github-copilot[bot]@users.noreply.github.com>
1 parent 26efd46 commit 888a246

File tree

7 files changed

+65
-18
lines changed

7 files changed

+65
-18
lines changed

apps/sim/app/api/workflows/[id]/deploy/route.test.ts

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -149,8 +149,6 @@ describe('Workflow deploy route', () => {
149149
auth: {
150150
success: true,
151151
userId: 'api-user',
152-
userName: 'API Key User',
153-
userEmail: 'api@example.com',
154152
authType: 'api_key',
155153
},
156154
})
@@ -178,8 +176,8 @@ describe('Workflow deploy route', () => {
178176
expect(mockRecordAudit).toHaveBeenCalledWith(
179177
expect.objectContaining({
180178
actorId: 'api-user',
181-
actorName: 'API Key User',
182-
actorEmail: 'api@example.com',
179+
actorName: undefined,
180+
actorEmail: undefined,
183181
})
184182
)
185183
})
@@ -190,8 +188,6 @@ describe('Workflow deploy route', () => {
190188
auth: {
191189
success: true,
192190
userId: 'api-user',
193-
userName: 'API Key User',
194-
userEmail: 'api@example.com',
195191
authType: 'api_key',
196192
},
197193
})
@@ -211,8 +207,8 @@ describe('Workflow deploy route', () => {
211207
expect(mockRecordAudit).toHaveBeenCalledWith(
212208
expect.objectContaining({
213209
actorId: 'api-user',
214-
actorName: 'API Key User',
215-
actorEmail: 'api@example.com',
210+
actorName: undefined,
211+
actorEmail: undefined,
216212
})
217213
)
218214
})

apps/sim/app/api/workflows/[id]/deploy/route.ts

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { createLogger } from '@sim/logger'
33
import { and, desc, eq } from 'drizzle-orm'
44
import type { NextRequest } from 'next/server'
55
import type { AuthResult } from '@/lib/auth/hybrid'
6+
import { getAuditActorMetadata } from '@/lib/audit/actor-metadata'
67
import { AuditAction, AuditResourceType, recordAudit } from '@/lib/audit/log'
78
import { generateRequestId } from '@/lib/core/utils/request'
89
import { removeMcpToolsForWorkflow, syncMcpToolsForWorkflow } from '@/lib/mcp/workflow-mcp-sync'
@@ -60,6 +61,10 @@ async function validateLifecycleAdminAccess(
6061
}
6162
}
6263

64+
function getLifecycleAuditActor(auth: AuthResult | null | undefined) {
65+
return getAuditActorMetadata(auth)
66+
}
67+
6368
export async function GET(request: NextRequest, { params }: { params: Promise<{ id: string }> }) {
6469
const requestId = generateRequestId()
6570
const { id } = await params
@@ -289,11 +294,13 @@ export async function POST(request: NextRequest, { params }: { params: Promise<{
289294
// Sync MCP tools with the latest parameter schema
290295
await syncMcpToolsForWorkflow({ workflowId: id, requestId, context: 'deploy' })
291296

297+
const { actorName, actorEmail } = getLifecycleAuditActor(auth)
298+
292299
recordAudit({
293300
workspaceId: workflowData?.workspaceId || null,
294301
actorId: actorUserId,
295-
actorName: auth?.userName,
296-
actorEmail: auth?.userEmail,
302+
actorName,
303+
actorEmail,
297304
action: AuditAction.WORKFLOW_DEPLOYED,
298305
resourceType: AuditResourceType.WORKFLOW,
299306
resourceId: id,
@@ -413,11 +420,13 @@ export async function DELETE(
413420
// Silently fail
414421
}
415422

423+
const { actorName, actorEmail } = getLifecycleAuditActor(auth)
424+
416425
recordAudit({
417426
workspaceId: workflowData?.workspaceId || null,
418427
actorId: actorUserId,
419-
actorName: auth?.userName,
420-
actorEmail: auth?.userEmail,
428+
actorName,
429+
actorEmail,
421430
action: AuditAction.WORKFLOW_UNDEPLOYED,
422431
resourceType: AuditResourceType.WORKFLOW,
423432
resourceId: id,

apps/sim/app/api/workflows/[id]/deployments/[version]/revert/route.test.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ const {
1313
mockDbUpdate,
1414
mockDbWhere,
1515
mockDbWhereUpdate,
16+
mockRecordAudit,
1617
mockSaveWorkflowToNormalizedTables,
1718
mockSyncMcpToolsForWorkflow,
1819
mockValidateWorkflowAccess,
@@ -24,6 +25,7 @@ const {
2425
mockDbUpdate: vi.fn(),
2526
mockDbWhere: vi.fn(),
2627
mockDbWhereUpdate: vi.fn(),
28+
mockRecordAudit: vi.fn(),
2729
mockSaveWorkflowToNormalizedTables: vi.fn(),
2830
mockSyncMcpToolsForWorkflow: vi.fn(),
2931
mockValidateWorkflowAccess: vi.fn(),
@@ -82,7 +84,7 @@ vi.mock('@/lib/mcp/workflow-mcp-sync', () => ({
8284
vi.mock('@/lib/audit/log', () => ({
8385
AuditAction: { WORKFLOW_DEPLOYMENT_REVERTED: 'WORKFLOW_DEPLOYMENT_REVERTED' },
8486
AuditResourceType: { WORKFLOW: 'WORKFLOW' },
85-
recordAudit: vi.fn(),
87+
recordAudit: (...args: unknown[]) => mockRecordAudit(...args),
8688
}))
8789

8890
import { POST } from '@/app/api/workflows/[id]/deployments/[version]/revert/route'
@@ -132,5 +134,12 @@ describe('Workflow deployment version revert route', () => {
132134
})
133135
expect(mockSaveWorkflowToNormalizedTables).toHaveBeenCalled()
134136
expect(mockSyncMcpToolsForWorkflow).toHaveBeenCalled()
137+
expect(mockRecordAudit).toHaveBeenCalledWith(
138+
expect.objectContaining({
139+
actorId: 'api-user',
140+
actorName: undefined,
141+
actorEmail: undefined,
142+
})
143+
)
135144
})
136145
})

apps/sim/app/api/workflows/[id]/deployments/[version]/revert/route.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { db, workflow, workflowDeploymentVersion } from '@sim/db'
22
import { createLogger } from '@sim/logger'
33
import { and, eq } from 'drizzle-orm'
44
import type { NextRequest } from 'next/server'
5+
import { getAuditActorMetadata } from '@/lib/audit/actor-metadata'
56
import { AuditAction, AuditResourceType, recordAudit } from '@/lib/audit/log'
67
import { env } from '@/lib/core/config/env'
78
import { generateRequestId } from '@/lib/core/utils/request'
@@ -135,14 +136,16 @@ export async function POST(
135136
logger.error('Error sending workflow reverted event to socket server', e)
136137
}
137138

139+
const { actorName, actorEmail } = getAuditActorMetadata(auth)
140+
138141
recordAudit({
139142
workspaceId: workflowRecord?.workspaceId ?? null,
140143
actorId: actorUserId,
141144
action: AuditAction.WORKFLOW_DEPLOYMENT_REVERTED,
142145
resourceType: AuditResourceType.WORKFLOW,
143146
resourceId: id,
144-
actorName: auth?.userName ?? undefined,
145-
actorEmail: auth?.userEmail ?? undefined,
147+
actorName,
148+
actorEmail,
146149
resourceName: workflowRecord?.name ?? undefined,
147150
description: `Reverted workflow to deployment version ${version}`,
148151
request,

apps/sim/app/api/workflows/[id]/deployments/[version]/route.test.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ const {
1616
mockDbUpdate,
1717
mockDbWhere,
1818
mockDbWhereUpdate,
19+
mockRecordAudit,
1920
mockSaveTriggerWebhooksForDeploy,
2021
mockSyncMcpToolsForWorkflow,
2122
mockValidateWorkflowAccess,
@@ -30,6 +31,7 @@ const {
3031
mockDbUpdate: vi.fn(),
3132
mockDbWhere: vi.fn(),
3233
mockDbWhereUpdate: vi.fn(),
34+
mockRecordAudit: vi.fn(),
3335
mockSaveTriggerWebhooksForDeploy: vi.fn(),
3436
mockSyncMcpToolsForWorkflow: vi.fn(),
3537
mockValidateWorkflowAccess: vi.fn(),
@@ -94,7 +96,7 @@ vi.mock('@/lib/mcp/workflow-mcp-sync', () => ({
9496
vi.mock('@/lib/audit/log', () => ({
9597
AuditAction: { WORKFLOW_DEPLOYMENT_ACTIVATED: 'WORKFLOW_DEPLOYMENT_ACTIVATED' },
9698
AuditResourceType: { WORKFLOW: 'WORKFLOW' },
97-
recordAudit: vi.fn(),
99+
recordAudit: (...args: unknown[]) => mockRecordAudit(...args),
98100
}))
99101

100102
import { PATCH } from '@/app/api/workflows/[id]/deployments/[version]/route'
@@ -148,5 +150,12 @@ describe('Workflow deployment version route', () => {
148150
expect(mockSaveTriggerWebhooksForDeploy).toHaveBeenCalledWith(
149151
expect.objectContaining({ userId: 'api-user' })
150152
)
153+
expect(mockRecordAudit).toHaveBeenCalledWith(
154+
expect.objectContaining({
155+
actorId: 'api-user',
156+
actorName: undefined,
157+
actorEmail: undefined,
158+
})
159+
)
151160
})
152161
})

apps/sim/app/api/workflows/[id]/deployments/[version]/route.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { createLogger } from '@sim/logger'
33
import { and, eq } from 'drizzle-orm'
44
import type { NextRequest } from 'next/server'
55
import { z } from 'zod'
6+
import { getAuditActorMetadata } from '@/lib/audit/actor-metadata'
67
import { AuditAction, AuditResourceType, recordAudit } from '@/lib/audit/log'
78
import { generateRequestId } from '@/lib/core/utils/request'
89
import { syncMcpToolsForWorkflow } from '@/lib/mcp/workflow-mcp-sync'
@@ -319,11 +320,13 @@ export async function PATCH(
319320
}
320321
}
321322

323+
const { actorName, actorEmail } = getAuditActorMetadata(auth)
324+
322325
recordAudit({
323326
workspaceId: workflowData?.workspaceId,
324327
actorId: actorUserId,
325-
actorName: auth?.userName,
326-
actorEmail: auth?.userEmail,
328+
actorName,
329+
actorEmail,
327330
action: AuditAction.WORKFLOW_DEPLOYMENT_ACTIVATED,
328331
resourceType: AuditResourceType.WORKFLOW,
329332
resourceId: id,
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import type { AuthResult } from '@/lib/auth/hybrid'
2+
3+
export function getAuditActorMetadata(auth: AuthResult | null | undefined): {
4+
actorName: string | undefined
5+
actorEmail: string | undefined
6+
} {
7+
if (auth?.authType !== 'session') {
8+
return {
9+
actorName: undefined,
10+
actorEmail: undefined,
11+
}
12+
}
13+
14+
return {
15+
actorName: auth.userName ?? undefined,
16+
actorEmail: auth.userEmail ?? undefined,
17+
}
18+
}

0 commit comments

Comments
 (0)