fix(vulns): fix various vulnerabilities and enhanced code security (#1611)

* fix(vulns): fix SSRF vulnerabilities

* cleanup

* cleanup

* regen docs

* remove unused deps

* fix failing tests

* cleanup

* update deps

* regen bun lock
This commit is contained in:
Waleed
2025-10-11 22:14:31 -07:00
committed by GitHub
parent 1de6f09069
commit 8f06aec68b
100 changed files with 1865 additions and 1696 deletions

View File

@@ -168,7 +168,7 @@ describe('Copilot Checkpoints Revert API Route', () => {
// Mock checkpoint found but workflow not found
const mockCheckpoint = {
id: 'checkpoint-123',
workflowId: 'workflow-456',
workflowId: 'a1b2c3d4-e5f6-4a78-b9c0-d1e2f3a4b5c6',
userId: 'user-123',
workflowState: { blocks: {}, edges: [] },
}
@@ -196,13 +196,13 @@ describe('Copilot Checkpoints Revert API Route', () => {
// Mock checkpoint found but workflow belongs to different user
const mockCheckpoint = {
id: 'checkpoint-123',
workflowId: 'workflow-456',
workflowId: 'b2c3d4e5-f6a7-4b89-a0d1-e2f3a4b5c6d7',
userId: 'user-123',
workflowState: { blocks: {}, edges: [] },
}
const mockWorkflow = {
id: 'workflow-456',
id: 'b2c3d4e5-f6a7-4b89-a0d1-e2f3a4b5c6d7',
userId: 'different-user',
}
@@ -228,7 +228,7 @@ describe('Copilot Checkpoints Revert API Route', () => {
const mockCheckpoint = {
id: 'checkpoint-123',
workflowId: 'workflow-456',
workflowId: 'c3d4e5f6-a7b8-4c09-a1e2-f3a4b5c6d7e8',
userId: 'user-123',
workflowState: {
blocks: { block1: { type: 'start' } },
@@ -241,7 +241,7 @@ describe('Copilot Checkpoints Revert API Route', () => {
}
const mockWorkflow = {
id: 'workflow-456',
id: 'c3d4e5f6-a7b8-4c09-a1e2-f3a4b5c6d7e8',
userId: 'user-123',
}
@@ -274,7 +274,7 @@ describe('Copilot Checkpoints Revert API Route', () => {
const responseData = await response.json()
expect(responseData).toEqual({
success: true,
workflowId: 'workflow-456',
workflowId: 'c3d4e5f6-a7b8-4c09-a1e2-f3a4b5c6d7e8',
checkpointId: 'checkpoint-123',
revertedAt: '2024-01-01T00:00:00.000Z',
checkpoint: {
@@ -293,7 +293,7 @@ describe('Copilot Checkpoints Revert API Route', () => {
// Verify fetch was called with correct parameters
expect(global.fetch).toHaveBeenCalledWith(
'http://localhost:3000/api/workflows/workflow-456/state',
'http://localhost:3000/api/workflows/c3d4e5f6-a7b8-4c09-a1e2-f3a4b5c6d7e8/state',
{
method: 'PUT',
headers: {
@@ -319,7 +319,7 @@ describe('Copilot Checkpoints Revert API Route', () => {
const mockCheckpoint = {
id: 'checkpoint-with-date',
workflowId: 'workflow-456',
workflowId: 'd4e5f6a7-b8c9-4d10-a2e3-a4b5c6d7e8f9',
userId: 'user-123',
workflowState: {
blocks: {},
@@ -330,7 +330,7 @@ describe('Copilot Checkpoints Revert API Route', () => {
}
const mockWorkflow = {
id: 'workflow-456',
id: 'd4e5f6a7-b8c9-4d10-a2e3-a4b5c6d7e8f9',
userId: 'user-123',
}
@@ -360,7 +360,7 @@ describe('Copilot Checkpoints Revert API Route', () => {
const mockCheckpoint = {
id: 'checkpoint-invalid-date',
workflowId: 'workflow-456',
workflowId: 'e5f6a7b8-c9d0-4e11-a3f4-b5c6d7e8f9a0',
userId: 'user-123',
workflowState: {
blocks: {},
@@ -371,7 +371,7 @@ describe('Copilot Checkpoints Revert API Route', () => {
}
const mockWorkflow = {
id: 'workflow-456',
id: 'e5f6a7b8-c9d0-4e11-a3f4-b5c6d7e8f9a0',
userId: 'user-123',
}
@@ -401,7 +401,7 @@ describe('Copilot Checkpoints Revert API Route', () => {
const mockCheckpoint = {
id: 'checkpoint-null-values',
workflowId: 'workflow-456',
workflowId: 'f6a7b8c9-d0e1-4f23-a4b5-c6d7e8f9a0b1',
userId: 'user-123',
workflowState: {
blocks: null,
@@ -413,7 +413,7 @@ describe('Copilot Checkpoints Revert API Route', () => {
}
const mockWorkflow = {
id: 'workflow-456',
id: 'f6a7b8c9-d0e1-4f23-a4b5-c6d7e8f9a0b1',
userId: 'user-123',
}
@@ -452,13 +452,13 @@ describe('Copilot Checkpoints Revert API Route', () => {
const mockCheckpoint = {
id: 'checkpoint-123',
workflowId: 'workflow-456',
workflowId: 'a7b8c9d0-e1f2-4a34-b5c6-d7e8f9a0b1c2',
userId: 'user-123',
workflowState: { blocks: {}, edges: [] },
}
const mockWorkflow = {
id: 'workflow-456',
id: 'a7b8c9d0-e1f2-4a34-b5c6-d7e8f9a0b1c2',
userId: 'user-123',
}
@@ -510,7 +510,7 @@ describe('Copilot Checkpoints Revert API Route', () => {
const mockCheckpoint = {
id: 'checkpoint-123',
workflowId: 'workflow-456',
workflowId: 'b8c9d0e1-f2a3-4b45-a6d7-e8f9a0b1c2d3',
userId: 'user-123',
workflowState: { blocks: {}, edges: [] },
}
@@ -537,13 +537,13 @@ describe('Copilot Checkpoints Revert API Route', () => {
const mockCheckpoint = {
id: 'checkpoint-123',
workflowId: 'workflow-456',
workflowId: 'c9d0e1f2-a3b4-4c56-a7e8-f9a0b1c2d3e4',
userId: 'user-123',
workflowState: { blocks: {}, edges: [] },
}
const mockWorkflow = {
id: 'workflow-456',
id: 'c9d0e1f2-a3b4-4c56-a7e8-f9a0b1c2d3e4',
userId: 'user-123',
}
@@ -594,13 +594,13 @@ describe('Copilot Checkpoints Revert API Route', () => {
const mockCheckpoint = {
id: 'checkpoint-123',
workflowId: 'workflow-456',
workflowId: 'd0e1f2a3-b4c5-4d67-a8f9-a0b1c2d3e4f5',
userId: 'user-123',
workflowState: { blocks: {}, edges: [] },
}
const mockWorkflow = {
id: 'workflow-456',
id: 'd0e1f2a3-b4c5-4d67-a8f9-a0b1c2d3e4f5',
userId: 'user-123',
}
@@ -626,7 +626,7 @@ describe('Copilot Checkpoints Revert API Route', () => {
await POST(req)
expect(global.fetch).toHaveBeenCalledWith(
'http://localhost:3000/api/workflows/workflow-456/state',
'http://localhost:3000/api/workflows/d0e1f2a3-b4c5-4d67-a8f9-a0b1c2d3e4f5/state',
{
method: 'PUT',
headers: {
@@ -644,13 +644,13 @@ describe('Copilot Checkpoints Revert API Route', () => {
const mockCheckpoint = {
id: 'checkpoint-123',
workflowId: 'workflow-456',
workflowId: 'e1f2a3b4-c5d6-4e78-a9a0-b1c2d3e4f5a6',
userId: 'user-123',
workflowState: { blocks: {}, edges: [] },
}
const mockWorkflow = {
id: 'workflow-456',
id: 'e1f2a3b4-c5d6-4e78-a9a0-b1c2d3e4f5a6',
userId: 'user-123',
}
@@ -677,7 +677,7 @@ describe('Copilot Checkpoints Revert API Route', () => {
expect(response.status).toBe(200)
expect(global.fetch).toHaveBeenCalledWith(
'http://localhost:3000/api/workflows/workflow-456/state',
'http://localhost:3000/api/workflows/e1f2a3b4-c5d6-4e78-a9a0-b1c2d3e4f5a6/state',
{
method: 'PUT',
headers: {
@@ -695,7 +695,7 @@ describe('Copilot Checkpoints Revert API Route', () => {
const mockCheckpoint = {
id: 'checkpoint-complex',
workflowId: 'workflow-456',
workflowId: 'f2a3b4c5-d6e7-4f89-a0b1-c2d3e4f5a6b7',
userId: 'user-123',
workflowState: {
blocks: {
@@ -723,7 +723,7 @@ describe('Copilot Checkpoints Revert API Route', () => {
}
const mockWorkflow = {
id: 'workflow-456',
id: 'f2a3b4c5-d6e7-4f89-a0b1-c2d3e4f5a6b7',
userId: 'user-123',
}

View File

@@ -11,6 +11,7 @@ import {
createUnauthorizedResponse,
} from '@/lib/copilot/auth'
import { createLogger } from '@/lib/logs/console/logger'
import { validateUUID } from '@/lib/security/input-validation'
const logger = createLogger('CheckpointRevertAPI')
@@ -36,7 +37,6 @@ export async function POST(request: NextRequest) {
logger.info(`[${tracker.requestId}] Reverting to checkpoint ${checkpointId}`)
// Get the checkpoint and verify ownership
const checkpoint = await db
.select()
.from(workflowCheckpoints)
@@ -47,7 +47,6 @@ export async function POST(request: NextRequest) {
return createNotFoundResponse('Checkpoint not found or access denied')
}
// Verify user still has access to the workflow
const workflowData = await db
.select()
.from(workflowTable)
@@ -62,10 +61,8 @@ export async function POST(request: NextRequest) {
return createUnauthorizedResponse()
}
// Apply the checkpoint state to the workflow using the existing state endpoint
const checkpointState = checkpoint.workflowState as any // Cast to any for property access
// Clean the checkpoint state to remove any null/undefined values that could cause validation errors
const cleanedState = {
blocks: checkpointState?.blocks || {},
edges: checkpointState?.edges || [],
@@ -74,7 +71,6 @@ export async function POST(request: NextRequest) {
isDeployed: checkpointState?.isDeployed || false,
deploymentStatuses: checkpointState?.deploymentStatuses || {},
lastSaved: Date.now(),
// Only include deployedAt if it's a valid date string that can be converted
...(checkpointState?.deployedAt &&
checkpointState.deployedAt !== null &&
checkpointState.deployedAt !== undefined &&
@@ -90,13 +86,19 @@ export async function POST(request: NextRequest) {
isDeployed: cleanedState.isDeployed,
})
const workflowIdValidation = validateUUID(checkpoint.workflowId, 'workflowId')
if (!workflowIdValidation.isValid) {
logger.error(`[${tracker.requestId}] Invalid workflow ID: ${workflowIdValidation.error}`)
return NextResponse.json({ error: 'Invalid workflow ID format' }, { status: 400 })
}
const stateResponse = await fetch(
`${request.nextUrl.origin}/api/workflows/${checkpoint.workflowId}/state`,
{
method: 'PUT',
headers: {
'Content-Type': 'application/json',
Cookie: request.headers.get('Cookie') || '', // Forward auth cookies
Cookie: request.headers.get('Cookie') || '',
},
body: JSON.stringify(cleanedState),
}
@@ -123,7 +125,7 @@ export async function POST(request: NextRequest) {
revertedAt: new Date().toISOString(),
checkpoint: {
id: checkpoint.id,
workflowState: cleanedState, // Return the reverted state for frontend use
workflowState: cleanedState,
},
})
} catch (error) {