GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — feat(patch): add package- and diff-level patch sources by mikolalysenko · Pull Request #67 · SocketDev/socket-patch

Conversation

@mikolalysenko

@mikolalysenko Mikola Lysenko (mikolalysenko) commented May 12, 2026

Copy link
Copy Markdown
Collaborator

Adds two new optional patch pathways to the socket-patch CLI alongside the existing per-file blob path:

  • Per-package archives at .socket/packages/<uuid>.tar.gz — a tarball of patched files for a single patch, extracted in one shot.
  • Per-file bsdiff archives at .socket/diffs/<uuid>.tar.gz — bsdiff deltas that transform before_hash content into after_hash content.

The apply pipeline tries sources in order package → diff → blob, falling through on any failure. Every strategy still post-write-verifies file git-sha256 against after_hash, so the existing safety invariant is unchanged.

A new --download-mode {diff,package,file} flag (default: diff) controls what apply, get, scan, and repair fetch when local artifacts are missing.

Why?

  • Smaller downloads — a one-line fix to a large minified bundle no longer ships the whole file (diff mode), and multi-file patches can ship as one archive (package mode).
  • One round-trip per patch instead of one per file, for users with many patches applied.

Backwards compatibility

  • Manifest schema is unchanged. Archives are keyed by the existing PatchRecord.uuid, so legacy .socket/manifest.json files Just Work.
  • The new pathways are opt-in via PatchSources; tests prove uuid = None restores the pre-2.2 behavior exactly.
  • Server-side /patch/diff/<uuid> and /patch/package/<uuid> endpoints are not live yet — 404s fall through gracefully to the file-blob path, so this is safe to ship ahead of server support.

What's in the diff

  • New core modules:
    • patch/diff.rs — qbsdiff::Bspatch wrapper plus round-trip + malformed-delta tests.
    • patch/package.rs — tar + flate2 reader with path-traversal guards, whitelist filtering against expected_files, and hard caps on cumulative decompressed bytes (MAX_TOTAL_DECOMPRESSED_BYTES = 64 MiB), per-entry size (MAX_ENTRY_BYTES = 16 MiB), and entry count (MAX_ENTRIES = 10_000) to defuse gzip-bomb / Vec::with_capacity DoS.
  • patch/apply.rs: PatchSources struct, AppliedVia enum, try_apply_from_archive / try_apply_from_diff helpers; apply_package_patch takes a PatchSources and optional uuid. try_apply_from_diff gates on the captured pre-apply current_hash so --force cannot run a diff against unexpected content.
  • api/client.rs: fetch_diff(uuid) and fetch_package(uuid) mirror fetch_blob(hash) via a new private fetch_binary helper that dedupes the proxy/auth client split and HTTP handling. is_valid_uuid validator added.
  • api/blob_fetcher.rs: DownloadMode enum + fetch_missing_sources dispatch by kind. get_missing_archives parallels get_missing_blobs.
  • utils/cleanup_blobs.rs: cleanup_unused_archives reaps orphan .tar.gzs in .socket/packages/ and .socket/diffs/, invoked from repair.
  • CLI: apply, get, scan, repair all accept --download-mode; apply's offline guard now reports per-patch source availability (one bucket per PURL) rather than a global blobs/diffs/packages count.
  • Cargo deps added: qbsdiff = "1", tar = "0.4", flate2 = "1".

Tests

  • 307 unit tests + 2 e2e gem pass (was 263 + 2). 42 new tests added across modules.
  • New coverage: diff round-trips (text + binary), package extraction safety (traversal, oversize-header, too-many-entries, decompression-bomb truncation), fallback ordering (via package/diff/blob), force-mode + diff regression (test_apply_via_diff_falls_through_when_before_hash_mismatch), dry-run safety, UUID validation, archive download/cleanup helpers.
  • All previously existing tests pass unchanged.
  • cargo clippy --all-targets --workspace is clean for code I touched (4 pre-existing map_or warnings in e2e test files remain).

Review summary

Pre-merge security + quality review run by automated reviewers. Findings:

CRITICAL fixed: tarball decompression bomb (CWE-409) — added cumulative-bytes cap via Read::take, per-entry size check, entry-count cap, and Vec::with_capacity clamp.
HIGH fixed: force-mode + diff-strategy loophole (now gated on real current_hash == before_hash), offline guard rewritten per-patch, empty-archive-fetch round eliminated when blobs are already local, cleanup_unused_archives doc reconciled with behavior.

Three new bomb-defense tests verify each cap fires before allocation.

Test plan

  • cargo test --workspace (307 unit + 2 e2e gem, 0 failures)
  • cargo clippy --all-targets --workspace (no new warnings)
  • cargo build --release
  • Smoke test: blob-only manifest → apply --offline --verbose reports (via blob) and content matches
  • Smoke test: manifest + package archive → apply --offline reports (via package)
  • Smoke test: offline + no sources → fails with per-patch report listing affected PURL

Assisted-by: Claude Code:claude-opus-4-7

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@mikolalysenko
feat(patch): add package- and diff-level patch sources
80e9401
Adds two new optional pathways to the socket-patch CLI alongside the
existing per-file blob path:

- Per-package archives at `.socket/packages/<uuid>.tar.gz` — a tarball
  of patched files for a single patch, extracted in one shot.
- Per-file bsdiff archives at `.socket/diffs/<uuid>.tar.gz` — bsdiff
  deltas that transform `before_hash` content into `after_hash` content.

The apply pipeline now tries sources in the order package → diff →
blob, falling through to the next on any failure. Every strategy
post-write-verifies the file's git-sha256 against `after_hash`, so the
existing safety invariant is unchanged.

A new `--download-mode {diff,package,file}` flag (default: `diff`)
controls what `apply`, `get`, `scan`, and `repair` fetch when local
artifacts are missing. The manifest schema is intentionally unchanged:
archives are keyed by patch UUID (already present in `PatchRecord`),
so legacy manifests keep working with no migration.

Highlights:

- New core modules `patch/diff.rs` (qbsdiff bspatch wrapper) and
  `patch/package.rs` (tar+flate2 reader with path-traversal guards,
  whitelist filtering against `expected_files`, and hard caps on
  decompressed bytes / per-entry size / entry count to defuse
  gzip-bomb and `Vec::with_capacity` allocation attacks).
- New `PatchSources` struct and `AppliedVia` enum in `patch/apply.rs`;
  `apply_package_patch` takes a `PatchSources` and an optional UUID.
  Passing `uuid = None` restores pre-2.2 blob-only behavior.
- `try_apply_from_diff` gates on the captured pre-apply `current_hash`
  rather than `VerifyStatus`, so `--force` cannot drive a diff against
  garbage content.
- `apply`'s offline guard now reports per-patch source availability
  instead of a global blobs/diffs/packages bucket count.
- `ApiClient::fetch_diff(uuid)` and `fetch_package(uuid)` mirror
  `fetch_blob(hash)`; a private `fetch_binary` helper deduplicates the
  proxy/auth client split and 200/404/error handling.
- `DownloadMode` enum + `fetch_missing_sources` in `api/blob_fetcher.rs`
  dispatch downloads by kind. `cleanup_unused_archives` in
  `utils/cleanup_blobs.rs` reaps orphaned `.socket/packages/` and
  `.socket/diffs/` files via `repair`.

Tests: 307 unit + 2 e2e gem (was 263 + 2 before this change). New
coverage spans diff round-trips, package extraction safety (traversal,
oversize-header, too-many-entries, decompression-bomb truncation),
fallback chain ordering (`via package`/`diff`/`blob`), force-mode +
diff regression, dry-run safety, UUID validation, and archive
download/cleanup helpers. All existing tests pass unchanged.

Server-side `/patch/diff/<uuid>` and `/patch/package/<uuid>` endpoints
are not live yet — 404 responses fall through gracefully to the file
blob path, so this PR ships safely ahead of server support.

Assisted-by: Claude Code:claude-opus-4-7
@socket-security

socket-security Bot commented May 12, 2026 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addedcargo/​flate2@​1.1.910010093100100
Addedcargo/​qbsdiff@​1.4.49710093100100
Addedcargo/​tar@​0.4.4510010093100100

View full report

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@mikolalysenko

Mikola Lysenko (mikolalysenko) commented May 12, 2026

Copy link
Copy Markdown
Collaborator Author

Cursor (@cursor) review

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@cursor

cursor Bot commented May 12, 2026

Copy link
Copy Markdown

Skipping Bugbot: Bugbot is disabled for this repository. Visit the Bugbot dashboard to update your settings.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@socket-security-staging

socket-security-staging Bot commented May 12, 2026 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addedcargo/​flate2@​1.1.910010093100100
Addedcargo/​qbsdiff@​1.4.49710093100100
Addedcargo/​tar@​0.4.4510010093100100

View full report

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@socket-security-staging

socket-security-staging Bot commented May 12, 2026 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown

All alerts resolved. Learn more about Socket for GitHub.

This PR previously contained dependency changes with security issues that have been resolved, removed, or ignored.

Ignoring alerts on:

  • cargo/[email protected]
  • cargo/[email protected]
  • cargo/[email protected]
  • cargo/[email protected]
  • cargo/[email protected]
  • cargo/[email protected]
  • cargo/[email protected]
  • cargo/[email protected]
  • cargo/[email protected]
  • cargo/[email protected]
  • cargo/[email protected]
  • cargo/[email protected]
  • cargo/[email protected]
  • cargo/[email protected]
  • cargo/[email protected]
  • cargo/[email protected]
  • cargo/[email protected]
  • cargo/[email protected]
  • cargo/[email protected]
  • cargo/[email protected]
  • cargo/[email protected]
  • cargo/[email protected]
  • cargo/[email protected]

View full report

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@mikolalysenko

Mikola Lysenko (mikolalysenko) commented May 12, 2026

Copy link
Copy Markdown
Collaborator Author

@socketsecurity-staging ignore-all

socket-security[bot] and socket-security-staging[bot] reacted with thumbs up emoji
All reactions
  • 👍 2 reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@mikolalysenko
chore: clean up stray dead-code markers
d91f73b
- e2e_npm.rs: NPM_PURL is actually used by 5 assertions; drop the
  stale `#[allow(dead_code)]`.
- maven_crawler.rs: remove `read_pom_in_dir`, an async helper that
  was never called and only existed under `#[allow(dead_code)]`.

No behavior change. 307 tests still pass; cargo build clean.

Assisted-by: Claude Code:opus-4-7
@mikolalysenko
Mikola Lysenko (mikolalysenko) enabled auto-merge (squash) May 15, 2026 16:52
This was referenced May 19, 2026
test(cli): foundation for CLI-contract unit-test campaign #68
Merged
test(cli): unit-test output.rs format_severity/color/confirm #69
Closed
test(cli): unit-test partition_purls ecosystem filter #70
Closed
test(cli): pin RollbackArgs flag surface + find_patches_to_rollback #71
Closed
test(cli): unit-test looks_like_uuid + parse_with_uuid_fallback #72
Closed
test(cli): pin ApplyArgs flag surface + verify_status_str #73
Closed
test(cli): pin ScanArgs flag surface (batch-size=100, download-mode=diff) #74
Closed
test(cli): pin RepairArgs flag surface (download-mode=file, gc alias) #75
Closed
test(cli): pin GetArgs flag surface, download/no-apply aliases, detect_identifier_type #76
Closed
test(cli): pin ListArgs flag surface + run() error/empty/populated paths #77
Closed
test(cli): pin RemoveArgs/SetupArgs flag surface + run() error paths #78
Closed
Wenxin-Jiang
Wenxin Jiang (Wenxin-Jiang) approved these changes May 19, 2026
View reviewed changes
@mikolalysenko
Mikola Lysenko (mikolalysenko) merged commit 6288a37 into main May 19, 2026
5 checks passed

Uh oh!

There was an error while loading. Please reload this page.

@mikolalysenko
Mikola Lysenko (mikolalysenko) deleted the feat/diff-package-pathways branch May 19, 2026 21:16
@mikolalysenko Mikola Lysenko (mikolalysenko) mentioned this pull request May 20, 2026
feat(scan): unified auto-update engine — --sync, --prune, --dry-run (v3.0) #79
Merged
3 of 5 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

@Wenxin-Jiang Wenxin Jiang (Wenxin-Jiang) Wenxin-Jiang approved these changes

Uh oh!

There was an error while loading. Please reload this page.

Assignees

No one assigned

Labels

None yet

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

Uh oh!

There was an error while loading. Please reload this page.

2 participants

@mikolalysenko @Wenxin-Jiang
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.
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.