fix(tus): fail closed on incomplete uploads without discarding safe retries - #1294
fix(tus): fail closed on incomplete uploads without discarding safe retries#1294ferhatelmas wants to merge 1 commit into
Conversation
There was a problem hiding this comment.
Pull request overview
This PR hardens the TUS upload pipeline against silently accepting truncated/incomplete requests by propagating request/cancellation context into the datastore layer, then invalidating uploads when writes are incomplete or ambiguous—while attempting to preserve safe retries when no durable mutation occurred.
Changes:
- Add an AsyncLocalStorage-backed request context and a
writeWithRequestCompletion()guard that invalidates uploads on length/offset mismatch, aborted/incomplete bodies, or write errors. - Wrap
FileStoreandS3Storewrites to apply completion checks, and add more robust S3 artifact cleanup (multipart abort + object/part/cache deletion with retries and error aggregation). - Add/extend integration and unit tests covering truncated PATCH/POST behavior, lock contention, S3 mutation failure paths, and Upload-Checksum being ignored.
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| src/storage/protocols/tus/request-context.ts | Introduces ALS request context + write completion/invalidation logic. |
| src/storage/protocols/tus/request-context.test.ts | Unit tests for invalidation/retention behavior under various request conditions. |
| src/storage/protocols/tus/file-store.ts | Wraps file writes with request-completion checks and mutation tracking. |
| src/storage/protocols/tus/file-store.test.ts | Tests safe retry vs invalidation behavior around file write stream failures and concurrency limits. |
| src/storage/protocols/tus/s3-store.ts | Wraps S3 writes, tracks mutations, and implements a more robust remove/cleanup sequence. |
| src/storage/protocols/tus/s3-store.test.ts | Tests multipart abort ordering, cleanup retries/aggregation, and mutation-tracked invalidation behavior. |
| src/storage/protocols/tus/index.ts | Re-exports the new request-context helpers. |
| src/http/routes/tus/index.ts | Wraps TUS server handling to establish ALS context and propagate internal cancellation signals. |
| src/http/routes/tus/lifecycle.test.ts | Adds coverage asserting Upload-Checksum remains ignored. |
| src/test/tus.test.ts | Adds end-to-end tests for truncated uploads and S3 edge cases (lock contention, mutation failure cleanup). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Coverage Report for CI Build 30833546350Coverage increased (+0.2%) to 80.652%Details
Uncovered Changes
Coverage Regressions1 previously-covered line in 1 file lost coverage.
Coverage Stats💛 - Coveralls |
…etries Signed-off-by: ferhat elmas <elmas.ferhat@gmail.com>
|
@claude review always |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 10 out of 10 changed files in this pull request and generated no new comments.
Suppressed comments (1)
src/test/tus.test.ts:274
- The comment says this helper waits up to 5 seconds, but the deadline is set to 10 seconds. Align the comment and implementation to avoid confusion when diagnosing test timeouts.
// It can wait up to 5 seconds for the lock.
What kind of change does this PR introduce?
Bug fix
What is the current behavior?
Upstream gracefully ends the proxy stream on request abort so the datastore sees a clean EOF and a truncated PATCH resolves a successful partial write with a phantom offset.
What is the new behavior?
Incoming message and internal cancellation signal are carried into the datastore through async local storage. After write resolves, bytes written are compared to content length, or abort/complete/cancel for chunked bodies, and accordingly upload is destroyed than resumed to prevent silent corruption.
Mutation is tracked to stay resumable if errors came before durable store changes.
Also, harden remove for genuine upstream gaps to delete part, clear cache, handle per key delete errors.
Additional context