Unify file creation and signed upload sessions - #6264
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
PR SummaryHigh Risk Overview v2 API and clients shift workspace file creation to JSON Self-hosting docs add Azure Blob CORS for direct uploads, extra GCS exposed metadata headers, and lifecycle rules to expire staged Also documents optional Reviewed by Cursor Bugbot for commit c03fc3d. Bugbot is set up for automated code reviews on this repo. Configure here. |
Greptile SummaryThe PR replaces legacy buffered and presigned upload paths with a unified stateless signed-session model.
Confidence Score: 5/5The PR appears safe to merge based on the eligible follow-up review scope. No blocking failure remains in the available scoring findings.
|
| Filename | Overview |
|---|---|
| apps/sim/lib/uploads/upload-session/service.ts | Implements the central stateless session lifecycle, including validation, promotion, replay handling, finalization, abort, and cleanup. |
| apps/sim/lib/uploads/upload-session/provider.ts | Unifies local, S3, GCS, and Azure staging, multipart assembly, create-only promotion, and conditional deletion operations. |
| apps/sim/lib/uploads/client/upload-session.ts | Implements the shared browser PUT and multipart transfer engine with retries, cancellation, progress, and bounded concurrency. |
| apps/sim/app/api/files/uploads/finalizers.ts | Adds purpose-specific, conflict-aware finalization for workspace files and internal attachment or profile assets. |
| apps/sim/lib/table/orchestration/import-resource.ts | Migrates table imports to uploaded resources while bounding import processing and preserving retryable orchestration. |
| apps/sim/lib/api/contracts/upload-sessions.ts | Defines the shared signed-session request, transfer, completion, and purpose-result contracts. |
| apps/docs/content/docs/en/platform/self-hosting/object-storage.mdx | Documents browser CORS requirements and lifecycle cleanup for staged upload objects and abandoned multipart data. |
Sequence Diagram
sequenceDiagram
participant Client
participant API as Upload Session API
participant Store as Object Storage
participant Finalizer as Purpose Finalizer
Client->>API: Create session with file metadata
API-->>Client: Signed token and PUT or multipart transfer
Client->>Store: Upload into immutable staging key
Client->>API: Complete session
API->>Store: Verify staged object or assemble parts
API->>Store: Promote to create-only final key
API->>Finalizer: Register file, document, or import
API->>Store: Conditionally remove staging object
API-->>Client: Purpose-specific result
Reviews (2): Last reviewed commit: "fix(uploads): preserve attachment storag..." | Re-trigger Greptile
|
@cursor review |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit b1d4d63. Configure here.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 2 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit c03fc3d. Configure here.
|
|
||
| const { workspaceId, name, contentType, folderId, content, encoding } = parsed.data.body | ||
| const access = await resolveWorkspaceAccess(rateLimit, userId, workspaceId, 'write') | ||
| if (access) return v2WorkspaceAccessError(access) |
There was a problem hiding this comment.
V2 create parses before authz
Medium Severity
The new POST /api/v2/files handler runs parseRequest with a 70 MiB JSON cap before resolveWorkspaceAccess verifies workspace write permission. Callers with a valid API key but without write access can still force the server to read and validate large bodies for arbitrary workspaceId values, unlike the workspace JSON create route in the same change, which checks permissions before parsing.
Reviewed by Cursor Bugbot for commit c03fc3d. Configure here.
| if (!params.contentType.trim()) { | ||
| throw new UploadSessionError('validation', 'contentType must not be empty') | ||
| } | ||
| const minimum = params.purpose === 'workspace_file' ? 0 : 1 |
There was a problem hiding this comment.
Zero-byte session quota block
Medium Severity
Allowing workspace_file upload sessions with fileSize: 0 still runs checkStorageQuotaForBillingContext with zero additional bytes. When recorded usage is already above the payer limit, that check fails even though completion would not increase storage, so signed-session empty uploads are rejected while inline POST create paths can still add zero-byte files.
Reviewed by Cursor Bugbot for commit c03fc3d. Configure here.


Summary
Test plan
bun run lintbun run type-checkbun run check:boundariesbun run check:api-validation:strictbun run check:openapibun run check:client-boundarybun run check:utilsbun run check:zustand-v5bun run check:react-querybun run check:realtime-prunegit diff --check