Skip to content

fix(sdk): cancel the source stream when a TDF write fails or is cancelled (DSPX-5146) - #1084

Merged
dmihalcik-virtru merged 1 commit into
mainfrom
DSPX-4492-source-cancel
Oct 15, 2026
Merged

dmihalcik-virtru merged 1 commit into
mainfrom
DSPX-4492-source-cancel

Conversation

@dmihalcik-virtru

@dmihalcik-virtru dmihalcik-virtru commented Oct 14, 2026 •

Copy link
Copy Markdown
Member

Fixes DSPX-5146.

What

writeStream (lib/tdf3/src/tdf.ts) calls getReader() on cfg.contentStream, which locks it, and never releases the lock. This PR does two things:

  • When pull throws, cancel the source with the error that caused the failure. Examples: the byte limit is exceeded, the cipher fails or gets its size wrong, or the upcoming IvExhaustionError from feat(sdk): throw IvExhaustionError when IV collision risk exceeds 2^-32 (DSPX-4492) #1077 is thrown. The cancel is best effort and not awaited, so a slow or failing cancel can't delay or replace the error the consumer sees. If the cancel fails with a different error, it's logged with console.warn. A source that errored on its own rejects cancel with that same error, so that case isn't logged twice.
  • Add a cancel handler to the underlying source, so a consumer that cancels the encrypted output also cancels the input.

Most of the diff is re-indentation from wrapping pull in try/catch. With whitespace ignored it's about 20 lines.

Why

Before this change, a failed or cancelled write left the input locked and open. File handles, sockets, and in-progress fetch downloads leaked, and the caller couldn't reuse the stream. Found while reviewing #1077, whose new error fires after a very long write and tells users to "split the input". This PR is independent of #1077 and is based on main.

How to test

cd lib && npm test. The new tests are in tests/mocha/encrypt-decrypt.spec.ts, under "releases the source when the write stops early":

  • When encryption fails partway through, the source is cancelled with that same error, and toBuffer() rejects with it.
  • When the consumer cancels the output, the source is cancelled with the consumer's reason.
  • When cancelling the source also fails, toBuffer() still rejects with the original error, and the cancel error is logged once with console.warn.
  • When the source itself errors, toBuffer() rejects with the source's error and nothing is logged.

Without the fix, the first two tests fail. The other two cover the logging.

Risk

Small. This touches only the write stream's error path and cancel path. Nothing changes on the wire or on the read side.

Summary by CodeRabbit

  • Bug Fixes
    • Improved stream cleanup when encryption encounters a write failure: the source stream is canceled while the original error is preserved.
    • Consumer-initiated cancellation now passes its reason to the source stream.
    • Source read failures no longer trigger a cancellation warning.

@dmihalcik-virtru
dmihalcik-virtru requested a review from a team as a code owner October 14, 2026 14:03
@coderabbitai

coderabbitai Bot commented Oct 14, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: d38cebf1-cdcc-424d-a943-31967ab5bb80
📥 Commits

Reviewing files that changed from the base of the PR and between ebc317a and e9002ad.

📒 Files selected for processing: 2
  • lib/tdf3/src/tdf.ts
  • lib/tests/mocha/encrypt-decrypt.spec.ts

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.

📝 Walkthrough

writeStream now attempts to cancel its source reader when processing fails and rethrows the original error. Its cancellation handler forwards the consumer’s reason. New tests cover processing errors, cancellation failures, source read errors, and consumer cancellation.

Changes: Source stream cancellation

Layer / File(s) Summary
Cancellation handling and tests
lib/tdf3/src/tdf.ts, lib/tests/mocha/encrypt-decrypt.spec.ts
writeStream best-effort cancels the source reader after processing failures and preserves the original error. Consumer cancellation reasons are forwarded to the source reader. Tests cover these cases and warning behavior.

Priority: ⬇️ Low

Estimated code review effort: 2 (Simple) | ~15 minutes

Change: Bug fix

Suggested reviewers: elizabethhealy

Merge Risk: ⚪ Minimal · up to e9002

This change makes the write stream release its source when a write fails or the consumer cancels. It leaves the wire format and read side unchanged. No merge-blocking risk was identified.

Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 60.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 5 functions across 2 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 passed
Check name Status Explanation
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title clearly and concisely describes the main change: canceling the source stream when a TDF write fails or is canceled.
  • Fix all pre-merge checks with AI
✨ Finishing Touches: 💡 1
📝 Generate docstrings: 💡
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

A rabbit checks the stream’s way through,
When errors come, the source gets told.
The first error stays in view,
While cancel reasons travel bold.
The rabbit hops, the tests turn gold.

Comment @coderabbitai help to get the list of available commands.

@dmihalcik-virtru dmihalcik-virtru changed the title fix(sdk): cancel the source stream when a TDF write fails or is cancelled fix(sdk): cancel the source stream when a TDF write fails or is cancelled (DSPX-5146) Oct 14, 2026
…lled

writeStream locked cfg.contentStream for its whole lifetime but never
released it. When pull threw (byte limit, cipher failure, and soon
IvExhaustionError from DSPX-4492), or the consumer cancelled the output,
the input stayed locked and open: file handles, sockets, and downloads
leaked, and callers could not reuse the stream.

Cancel the source with the failing error (best effort, so a cancel
failure cannot mask the original error), and forward consumer
cancellation to the source.

Signed-off-by: Dave Mihalcik <dmihalcik@virtru.com>
@sonarqubecloud

Copy link
Copy Markdown

@dmihalcik-virtru
dmihalcik-virtru added this pull request to the merge queue Oct 15, 2026
Merged via the queue into main with commit d3867eb Oct 15, 2026
31 checks passed
@dmihalcik-virtru
dmihalcik-virtru deleted the DSPX-4492-source-cancel branch October 15, 2026 18:57
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.

2 participants