feat(upgrade): add binary delta patching via TRDIFF10/bsdiff#327
Merged
Conversation
Contributor
Semver Impact of This PR🟡 Minor (new features) 📋 Changelog PreviewThis is how your changes will appear in the changelog. New Features ✨Trace
Other
Bug Fixes 🐛Api
Formatters
Setup
Other
Internal Changes 🔧Api
Other
🤖 This preview updates automatically when you update the PR. |
Contributor
Codecov Results 📊✅ 2567 passed | Total: 2567 | Pass Rate: 100% | Execution Time: 0ms 📊 Comparison with Base Branch
All tests are passing successfully. ✅ Patch coverage is 90.23%. Project has 3282 uncovered lines. Files with missing lines (3)
Coverage diff@@ Coverage Diff @@
## main #PR +/-##
==========================================
+ Coverage 81.19% 81.46% +0.27%
==========================================
Files 123 125 +2
Lines 17149 17700 +551
Branches 0 0 —
==========================================
+ Hits 13923 14418 +495
- Misses 3226 3282 +56
- Partials 0 0 —Generated by Codecov Action |
BYK
commented
Mar 3, 2026
BYK
commented
Mar 3, 2026
Download TRDIFF10 patch files instead of full binaries when upgrading,
falling back to full download when no patch is available or the chain
exceeds 60% of the full download size.
- src/lib/bspatch.ts: streaming TRDIFF10 patcher using Bun.mmap(),
DecompressionStream('zstd'), and CryptoHasher for SHA-256 verification
- src/lib/delta-upgrade.ts: patch discovery and chain resolution for
both stable (GitHub Releases) and nightly (GHCR manifest annotations)
- src/lib/ghcr.ts: add fetchManifest(), listTags(), downloadLayerBlob()
- src/lib/upgrade.ts: attempt delta path first in downloadBinaryToTemp()
- ci.yml: install zig-bsdiff, tag :nightly-<version>, generate and push
:patch-<version> manifests with from-version + sha256-<platform> annotations
- cleanup-nightlies.yml: weekly prune of old versioned nightly tags (keep 30)
…e case Split chain resolution into two phases: serial metadata discovery (lightweight manifest/release JSON) then parallel patch download via Promise.all(). Also fix offtin() returning -0 when magnitude is 0 with sign bit set.
…ddress review - Export pure computation functions from delta-upgrade.ts for testability (extractStableChain, walkNightlyChain, extractSha256, getStableTargetSha256, getPatchFromVersion, getPatchTargetSha256) - Add 41 new tests for extractStableChain (single/multi-hop, edge cases, size threshold, MAX_CHAIN_DEPTH boundary) - Add 10 new tests for walkNightlyChain (graph traversal, broken chains, threshold, depth limits) - Add 6 tests for extractSha256 (hex parsing, prefix handling) - Add 4 tests for getStableTargetSha256 (asset lookup, missing digest) - Add 6 tests for getPatchFromVersion/getPatchTargetSha256 (OCI annotations) - Add 14 new ghcr.ts tests: fetchManifest (3), listTags with pagination (8), downloadLayerBlob (2), plus prefix filtering - Address PR review: replace lazy import with static import in upgrade.ts - Total: 107 tests, 602 assertions across 4 delta-related test files
Add comprehensive tests for async orchestration functions: - fetchRecentReleases: success, HTTP error, network failure - downloadStablePatch: success, 404, network failure - resolveStableChain: single-hop, multi-hop, missing target, API failure, download failure - buildNightlyPatchGraph: graph building, missing annotations, failed manifests, empty tags - resolveNightlyChain: single-hop with GHCR mocks, empty graph - applyPatchChain: SHA-256 verification, mismatch error, multi-step, permissions Add isolated tests (mock.module for CLI_VERSION): - resolveStableDelta: chain resolution + SHA mismatch, null on failure - resolveNightlyDelta: null on missing .gz layer, null on empty graph - attemptDeltaUpgrade: cross-channel rejection, chain failure, error catching Fix orphaned extractStableChain tests that were outside their describe scope. Export remaining async functions for direct testability. 133 tests, 643 assertions across 5 delta-upgrade test files.
- HIGH: Fix multi-step patch chain corruption by alternating between
two intermediate files (A/B) instead of reading and writing the same
file. Prevents mmap invalidation for 3+ step chains.
- MEDIUM: Use versioned nightly tag (nightly-<version>) instead of
rolling :nightly tag for threshold calculation in resolveNightlyDelta.
Ensures the 60% threshold reflects the target version's binary size.
- LOW: Add missing 'await' on applyPatchChain return in
resolveNightlyDelta to preserve stack traces on rejection.
- LOW: Remove redundant chmodSync from applyPatchChain — the caller
(downloadBinaryToTemp) already sets 0o755 for both delta and full
download paths.
- CodeQL: Replace includes('api.github.com') with
startsWith('https://api.github.com/') in test mocks to prevent
incomplete URL substring sanitization.
- Move intermediate file cleanup to finally block in applyPatchChain to prevent file leaks when patching throws mid-chain - Deduplicate GITHUB_RELEASES_URL: export from upgrade.ts, import in delta-upgrade.ts instead of defining it twice - Deduplicate getPlatformBinaryName: move canonical definition to binary.ts (alongside getBinaryDownloadUrl which has identical platform logic), reuse in upgrade.ts and delta-upgrade.ts - Remove redundant try-catch in tryDeltaUpgrade: attemptDeltaUpgrade already catches all errors and returns null
- Add missing async/await in fetchNightlyManifest to preserve stack traces on rejection (per project lore on bare promise returns) - Remove redundant PREV_MANIFEST guard in CI nightly delta step that was checking the just-pushed :nightly tag (always succeeds). The real guard is the PREV_TAG check that finds the previous versioned nightly tag.
# Conflicts: # AGENTS.md
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Bun.CryptoHasher.digest('hex') always returns lowercase hex, but
SHA256_DIGEST_PATTERN with the /i flag could capture uppercase from
GitHub asset digests. Normalize to lowercase to ensure comparison
always succeeds regardless of upstream casing.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds binary delta patching to
sentry upgrade, reducing download sizes by 300–600x for consecutive releases (~50 KB patch vs ~29 MB full.gz).sentry-<platform>.patchfrom GitHub Releases, chains patches across versions until the cumulative size hits 60% of the full download, then falls back:patch-<version>manifests withfrom-version+ per-platformsha256-<platform>annotationsChanges
src/lib/bspatch.ts— streaming TRDIFF10 patcher usingBun.mmap()(zero heap for old file),DecompressionStream('zstd'), andBun.CryptoHasherfor SHA-256 verificationsrc/lib/delta-upgrade.ts— patch discovery and chain resolution for stable and nightly channelssrc/lib/ghcr.ts— addsfetchManifest(),listTags(),downloadLayerBlob()src/lib/upgrade.ts— attempts delta path first indownloadBinaryToTemp().github/workflows/ci.yml— installs zig-bsdiff v0.1.19, creates immutable:nightly-<version>tags, generates and pushes:patch-<version>manifests.github/workflows/cleanup-nightlies.yml— weekly prune keeping last 30 versioned nightly tagsTesting
bspatch.ts(offtin, parsePatchHeader, applyPatch with real TRDIFF10 fixtures)delta-upgrade.ts