Skip to content

Commit 5499177

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

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
@@ -2,6 +2,7 @@ import { db, workflow, workflowDeploymentVersion } from '@sim/db'
22
import { createLogger } from '@sim/logger'
33
import { and, desc, 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 type { AuthResult } from '@/lib/auth/hybrid'
78
import { generateRequestId } from '@/lib/core/utils/request'
@@ -61,6 +62,10 @@ async function validateLifecycleAdminAccess(
6162
}
6263
}
6364

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

310+
const { actorName, actorEmail } = getLifecycleAuditActor(auth)
311+
305312
recordAudit({
306313
workspaceId: workflowData?.workspaceId || null,
307314
actorId: actorUserId,
308-
actorName: auth?.userName,
309-
actorEmail: auth?.userEmail,
315+
actorName,
316+
actorEmail,
310317
action: AuditAction.WORKFLOW_DEPLOYED,
311318
resourceType: AuditResourceType.WORKFLOW,
312319
resourceId: id,
@@ -425,11 +432,13 @@ export async function DELETE(
425432
// Silently fail
426433
}
427434

435+
const { actorName, actorEmail } = getLifecycleAuditActor(auth)
436+
428437
recordAudit({
429438
workspaceId: workflowData?.workspaceId || null,
430439
actorId: actorUserId,
431-
actorName: auth?.userName,
432-
actorEmail: auth?.userEmail,
440+
actorName,
441+
actorEmail,
433442
action: AuditAction.WORKFLOW_UNDEPLOYED,
434443
resourceType: AuditResourceType.WORKFLOW,
435444
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'
@@ -127,14 +128,16 @@ export async function POST(
127128
logger.error('Error sending workflow reverted event to socket server', e)
128129
}
129130

131+
const { actorName, actorEmail } = getAuditActorMetadata(auth)
132+
130133
recordAudit({
131134
workspaceId: workflowRecord?.workspaceId ?? null,
132135
actorId: actorUserId,
133136
action: AuditAction.WORKFLOW_DEPLOYMENT_REVERTED,
134137
resourceType: AuditResourceType.WORKFLOW,
135138
resourceId: id,
136-
actorName: auth?.userName ?? undefined,
137-
actorEmail: auth?.userEmail ?? undefined,
139+
actorName,
140+
actorEmail,
138141
resourceName: workflowRecord?.name ?? undefined,
139142
description: `Reverted workflow to deployment version ${version}`,
140143
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)