Skip to content

Feat/file block write#3665

Merged
TheodoreSpeaks merged 15 commits intostagingfrom
feat/file-block-write
Mar 30, 2026
Merged

Feat/file block write#3665
TheodoreSpeaks merged 15 commits intostagingfrom
feat/file-block-write

Conversation

@TheodoreSpeaks
Copy link
Copy Markdown
Collaborator

@TheodoreSpeaks TheodoreSpeaks commented Mar 19, 2026

Summary

Added operations write and append for the file block. This allows workflows to create and append to mothership file resources.

Type of Change

  • Bug fix
  • New feature
  • Breaking change
  • Documentation
  • Other: ___________

Testing

  • Validated file write adds new mothership file
  • Validated writing to existing file name appends dedupe number to file name
  • Validated append doesn't overwrite file and throws on non-existent file.

Checklist

  • Code follows project style guidelines
  • Self-reviewed my changes
  • Tests added/updated and passing
  • No new warnings introduced
  • I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)

Screenshots/Videos

image image

@vercel
Copy link
Copy Markdown

vercel bot commented Mar 19, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
docs Skipped Skipped Mar 30, 2026 9:48pm

Request Review

@TheodoreSpeaks
Copy link
Copy Markdown
Collaborator Author

@cursor review

@cursor
Copy link
Copy Markdown

cursor bot commented Mar 19, 2026

PR Summary

Medium Risk
Adds new API and tool paths that create and mutate persisted workspace files, including a read-modify-write append flow with locking. Risk is mainly around data integrity (concurrent appends, large file buffering) and permission/auth assumptions for workspace/user IDs.

Overview
Extends the FileV3Block from read-only parsing to read/write/append operations, adding UI params and wiring tool selection based on an operation dropdown.

Introduces a new internal API endpoint POST /api/tools/file/manage that supports write (creates a workspace file with MIME type inference) and append (fetches a file by name, locks it via Redis, downloads existing content, and updates the file).

Updates workspace file storage utilities to add getWorkspaceFileByName and removes a few dynamic imports, and registers the new file_write and file_append tools in the tool registry.

Written by Cursor Bugbot for commit c18d1db. This will update automatically on new commits. Configure here.

Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Autofix Details

Bugbot Autofix prepared a fix for the issue found in the latest run.

  • ✅ Fixed: Silent error masking causes incorrect create-vs-update routing
    • getWorkspaceFileByName now rethrows database lookup errors instead of returning null, so write-by-name no longer misroutes to create when lookup fails.

Create PR

Or push these changes by commenting:

@cursor push ee6f7d15f4
Preview (ee6f7d15f4)
diff --git a/apps/sim/lib/uploads/contexts/workspace/workspace-file-manager.ts b/apps/sim/lib/uploads/contexts/workspace/workspace-file-manager.ts
--- a/apps/sim/lib/uploads/contexts/workspace/workspace-file-manager.ts
+++ b/apps/sim/lib/uploads/contexts/workspace/workspace-file-manager.ts
@@ -320,7 +320,7 @@
     }
   } catch (error) {
     logger.error(`Failed to get workspace file by name "${fileName}":`, error)
-    return null
+    throw error
   }
 }

This Bugbot Autofix run was free. To enable autofix for future PRs, go to the Cursor dashboard.

@TheodoreSpeaks TheodoreSpeaks marked this pull request as ready for review March 30, 2026 19:00
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Mar 30, 2026

Greptile Summary

This PR adds write and append operations to the existing FileV3Block, extending it from a read-only file parser into a full read/write/append block. It introduces two new tools (file_write, file_append), a shared API route (/api/tools/file/manage), a new getWorkspaceFileByName DB helper, and wires everything into the block's operation dropdown with conditional sub-blocks.

Key changes:

  • FileV3Block gains an operation dropdown (Read / Write / Append) with conditional inputs that appear based on the selected mode
  • file_write creates a new workspace file, returning its ID, name, size, and URL; fails if the file already exists
  • file_append downloads an existing file, concatenates new content, and re-uploads in-place using the same storage key
  • getWorkspaceFileByName provides a scoped DB lookup (workspace context, non-deleted) used by both write (conflict check) and append (file retrieval)
  • Storage quota is enforced by the existing updateWorkspaceFileContent helper

Issues found:

  • P1 — TOCTOU race condition in write: The existence check (getWorkspaceFileByName) and file creation (uploadWorkspaceFile) are not atomic. Under concurrent requests for the same file name, the second caller can slip past the 409 guard and uploadWorkspaceFile's internal rename logic will silently create data (1).csv instead of returning an error, breaking the documented "fails if already exists" contract.
  • P2 — contentType silently dropped on append: fileAppendTool declares and forwards a contentType param, but the API route's append case never reads it from the body and never passes it to updateWorkspaceFileContent.

Confidence Score: 4/5

  • Safe to merge after addressing the TOCTOU race in the write path; all other findings are minor.
  • One P1 finding: the check-then-create in the write operation is not atomic, meaning concurrent requests can bypass the 409 guard and silently create a renamed file, breaking the documented contract. The P2 finding (contentType silently dropped on append) is low-impact but should be cleaned up. All remaining code is well-structured and consistent with existing patterns.
  • apps/sim/app/api/tools/file/manage/route.ts — write operation TOCTOU and append contentType handling

Important Files Changed

Filename Overview
apps/sim/app/api/tools/file/manage/route.ts New API route handling write/append operations. Has a TOCTOU race condition in the write path (check-then-create is not atomic) and silently drops the contentType param in the append path.
apps/sim/tools/file/write.ts New tool definition for file write. Clean structure, correct visibility annotations, properly forwards workspaceId from context.
apps/sim/tools/file/append.ts New tool definition for file append. The contentType param is declared and sent to the API but the route's append case doesn't use it.
apps/sim/lib/uploads/contexts/workspace/workspace-file-manager.ts Adds getWorkspaceFileByName helper — straightforward DB lookup with proper scoping (workspaceId, context='workspace', deletedAt IS NULL), consistent with existing patterns.
apps/sim/blocks/blocks/file.ts Extends FileV3Block with operation dropdown (Read/Write/Append), conditional sub-blocks, and dynamic fetchOptions for workspace files. Output descriptions for id/name/size/url are labeled "(write)" but also apply to append.
apps/sim/tools/file/index.ts Exports the two new tools; follows existing export conventions.
apps/sim/tools/registry.ts Registers file_write and file_append tools in the global registry; clean, consistent additions.

Sequence Diagram

sequenceDiagram
    participant Block as FileV3Block (UI)
    participant Tool as file_write / file_append Tool
    participant API as /api/tools/file/manage
    participant DB as workspace-file-manager (DB)
    participant Storage as Storage Service

    Note over Block,Storage: Write operation
    Block->>Tool: operation=write, fileName, content, workspaceId
    Tool->>API: POST {operation:"write", fileName, content, workspaceId}
    API->>DB: getWorkspaceFileByName(workspaceId, fileName)
    DB-->>API: null (not found)
    API->>Storage: uploadWorkspaceFile(...)
    Storage-->>API: {id, name, url, key}
    API-->>Tool: {success:true, data:{id, name, size, url}}
    Tool-->>Block: output {id, name, size, url}

    Note over Block,Storage: Append operation
    Block->>Tool: operation=append, fileName, content, workspaceId
    Tool->>API: POST {operation:"append", fileName, content, workspaceId}
    API->>DB: getWorkspaceFileByName(workspaceId, fileName)
    DB-->>API: existingRecord
    API->>Storage: downloadWorkspaceFile(existingRecord)
    Storage-->>API: existingBuffer
    API->>Storage: updateWorkspaceFileContent(workspaceId, id, userId, newBuffer)
    Storage-->>API: updatedRecord
    API-->>Tool: {success:true, data:{id, name, size, url}}
    Tool-->>Block: output {id, name, size, url}
Loading

Reviews (1): Last reviewed commit: "Address feedback" | Re-trigger Greptile

Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

@TheodoreSpeaks TheodoreSpeaks merged commit e1359b0 into staging Mar 30, 2026
12 checks passed
@TheodoreSpeaks TheodoreSpeaks deleted the feat/file-block-write branch March 30, 2026 22:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant