Skip to content

feat(zip): add support for zip files#5788

Merged
Sg312 merged 4 commits into
stagingfrom
feat/zip-extract
Jul 21, 2026
Merged

feat(zip): add support for zip files#5788
Sg312 merged 4 commits into
stagingfrom
feat/zip-extract

Conversation

@Sg312

@Sg312 Sg312 commented Jul 21, 2026

Copy link
Copy Markdown
Collaborator

Summary

Add support for zip files

Type of Change

  • New feature

Testing

Manual

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)

Sg312 added 4 commits July 20, 2026 17:38
- Replace the whole-buffer central-directory signature scan with an
  EOCD-anchored walk (shared with zip-guard) so zips containing STORED
  nested archives are no longer falsely rejected, and report the accurate
  cap (new 'central_dir_too_large' reason) instead of 'Maximum is 1000'
- Make extraction all-or-nothing: a discarding validation pass inflates
  every entry against the caps before anything is uploaded, so lying
  headers or corrupt entries can't leave partial trees (corrupt DEFLATE
  streams now surface as ArchiveError instead of raw zlib errors)
- Single-source ArchiveError messages; callers surface err.message and
  map only status/reason (removes the three divergent message maps)
- Guard save/import against archives (saving stranded the contents),
  extend the workspace ownership check to all three operations, dedupe
  fileNames, and refuse re-extracting into a non-empty folder instead of
  duplicating the tree with ' (1)' copies
- Harden the extraction folder name (dot segments, control chars,
  separators) and compute the destination before extracting
- Sniff small '.zip'-named uploads so mislabeled text files stay
  readable instead of dead-ending between read and extract
- Scope zip acceptance to the mothership flow only (attachment list,
  accept attribute, upload/presigned gates) so execution/workspace/chat
  surfaces keep rejecting zips up front
- Don't count skipped noise entries toward the 1000-file cap; restore
  per-entry zip-slip forensics via skippedUnsafePaths logging
- Teach materialize_file(fileNames: [...]) in the extract guidance to
  match the declared schema
- Roll back already-uploaded files when an upload fails mid-extraction
  (storage/DB error, quota crossed), so callers and retries never observe
  a partial tree
- Fold reserved system folder names (.changelogs, .plans) into the
  'archive' fallback so extraction can't write into alias-backing
  namespaces or bypass the already-extracted lookup that hides them
- Align the archive byte-sniff budget with the read path's inline text
  cap (5MB), so any mislabeled '.zip' small enough to be read inline is
  sniffed and read instead of dead-ending
…act guard

The already-extracted check only looked for files directly inside the
archive root folder, so a zip whose entries are all nested (src/index.ts)
left only subfolders there and a second extract slipped past the guard,
duplicating the tree with ' (1)' suffixes. Extraction roots its whole tree
at that folder, so a prior run always leaves a direct file OR a direct
subfolder — check both.
@vercel

vercel Bot commented Jul 21, 2026

Copy link
Copy Markdown

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

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
docs Skipped Skipped Jul 21, 2026 12:47am

Request Review

@greptile-apps

greptile-apps Bot commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds ZIP attachment extraction to the mothership copilot flow. The main changes are:

  • Allows ZIP uploads in the mothership attachment UI and API.
  • Adds archive-aware read and grep guidance.
  • Adds an extract operation to materialize_file.
  • Adds shared ZIP parsing, size limits, path checks, and rollback handling.

Confidence Score: 4/5

Archive extraction can duplicate files, block retries after failed uploads, and dead-end large mislabeled files.

  • Parallel extracts can write into the same destination.
  • Failed nested extraction can leave folders that prevent retry.
  • Large non-archive files named .zip cycle between read and extract guidance.
  • ZIP traversal and expansion limits otherwise appear well contained.

apps/sim/lib/copilot/tools/handlers/materialize-file.ts; apps/sim/lib/copilot/tools/handlers/upload-file-reader.ts; apps/sim/lib/uploads/archive.ts

Important Files Changed

Filename Overview
apps/sim/lib/copilot/tools/handlers/materialize-file.ts Adds archive extraction and destination reconciliation, with race and retry bugs around the destination folder.
apps/sim/lib/uploads/archive.ts Adds a two-pass, bounded ZIP extractor with file rollback, but created folders are not rolled back.
apps/sim/lib/copilot/tools/handlers/upload-file-reader.ts Adds archive sniffing and guidance, but trusts the extension for large files and can create a read/extract loop.
apps/sim/lib/file-parsers/zip-guard.ts Adds central-directory statistics used to bound parser allocation before decompression.
apps/sim/app/api/files/upload/route.ts Allows archive extensions only for mothership uploads.

Comments Outside Diff (3)

  1. apps/sim/lib/copilot/tools/handlers/materialize-file.ts, line 926 (link)

    P1 Concurrent Extracts Duplicate Files

    Two parallel extract calls can both pass this existence check before either creates the destination. They then share the folder created by the first call, and the upload layer gives the second archive's files (1) suffixes, so both calls report success with a duplicated or merged tree.

  2. apps/sim/lib/copilot/tools/handlers/materialize-file.ts, line 951 (link)

    P1 Orphan Folders Block Retries

    If an upload fails after nested folders were created, archive rollback deletes uploaded files but leaves those folders active. A retry then finds existingSubfolder here and reports the archive as already extracted, even though the first attempt rolled back its files.

  3. apps/sim/lib/copilot/tools/handlers/upload-file-reader.ts, line 1219 (link)

    P1 Large Mislabeled Files Dead-End

    A text or CSV upload larger than 5 MB whose name ends in .zip is treated as an archive without checking its bytes. read() therefore requests extraction, extraction rejects it as invalid and points back to read(), leaving the accepted upload inaccessible through either path.

Reviews (1): Last reviewed commit: "fix(zip-uploads): detect prior nested-on..." | Re-trigger Greptile

@Sg312 Sg312 changed the title feat() feat(zip): add support for zip files Jul 21, 2026
@Sg312
Sg312 merged commit 2798467 into staging Jul 21, 2026
21 checks passed
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