Skip to content

Commit 9489b18

Browse files
Add native bun.lockb patching for hosted and vendored modes (#246)
* feat(bun): support native binary lockfile patching * test: make Bundler setup checks independent of host tools * test: fix cross-platform Bun fixtures and CI isolation * fix: preserve historical Bun production installs in binary locks * ci: test historical Bun releases on Ubuntu 22.04 * docs: record complete native Bun validation results * refactor: remove Bun binary-to-text migration compatibility * test: remove obsolete Bun conversion assertions
1 parent 4b61c96 commit 9489b18

132 files changed

Lines changed: 7300 additions & 2879 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/bun-compatibility.yml

Lines changed: 78 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,11 @@ on:
1616
paths:
1717
- '.github/actions/upload-artifact/**'
1818
- '.github/workflows/bun-compatibility.yml'
19-
- 'scripts/backtest-bun.py'
19+
- 'scripts/backtest-bun*.py'
20+
- 'scripts/probe-bun-historical-linux.py'
21+
- 'scripts/bun-historical-shas.json'
22+
- 'crates/socket-patch-cli/tests/e2e_bun_lockb.rs'
23+
- 'crates/socket-patch-core/tests/fixtures/bun-lockb/**'
2024
- 'docs/testing/bun-compatibility.md'
2125
- 'Cargo.lock'
2226
- 'crates/socket-patch-core/src/vendor/**'
@@ -45,12 +49,14 @@ on:
4549
branches: [main]
4650
paths:
4751
- '.github/workflows/bun-compatibility.yml'
48-
- 'scripts/backtest-bun.py'
52+
- 'scripts/backtest-bun*.py'
53+
- 'scripts/probe-bun-historical-linux.py'
54+
- 'scripts/bun-historical-shas.json'
55+
- 'crates/socket-patch-cli/tests/e2e_bun_lockb.rs'
56+
- 'crates/socket-patch-core/tests/fixtures/bun-lockb/**'
4957
- 'Cargo.lock'
5058
- 'crates/socket-patch-core/src/vendor/**'
51-
- 'crates/socket-patch-core/src/patch/redirect/mod.rs'
52-
- 'crates/socket-patch-core/src/patch/redirect/replay.rs'
53-
- 'crates/socket-patch-core/src/patch/redirect/takeover.rs'
59+
- 'crates/socket-patch-core/src/patch/redirect/**'
5460
- 'crates/socket-patch-cli/src/commands/get.rs'
5561
- 'crates/socket-patch-cli/src/commands/scan/**'
5662
- 'crates/socket-patch-cli/src/commands/rollback.rs'
@@ -125,12 +131,15 @@ jobs:
125131
needs: build
126132
strategy:
127133
fail-fast: false
134+
# Each job runs three cells against the public patch service. Bound
135+
# concurrent jobs so the full release matrix does not flood that API.
136+
max-parallel: 6
128137
matrix:
129138
os: [ubuntu-latest, macos-latest, windows-latest]
130139
# Every lock-format and behaviour boundary the CLI has to survive:
131140
# 0.8.1 / 1.0.0 / 1.0.36 / 1.1.0 / 1.1.38 binary bun.lockb only
132141
# 1.1.39 first text lock (lockfileVersion 0, opt-in)
133-
# 1.1.43 first `--lockfile-only` (the lockb migration recipe)
142+
# 1.1.43 first `--lockfile-only`
134143
# 1.1.45 last v0 writer
135144
# 1.2.0 / 1.2.23 / 1.3.0 text default, lockfileVersion 1
136145
# 1.3.9 / 1.3.10 URL/local tarball sha512 enforcement boundary
@@ -326,4 +335,67 @@ jobs:
326335
native-bun/captures/**/cli-output.json
327336
native-bun/captures/**/tree/**
328337
native-bun/captures/**/*.log
338+
native-bun/attempts/**
339+
retention-days: 14
340+
341+
342+
binary:
343+
strategy:
344+
fail-fast: false
345+
matrix:
346+
os: [ubuntu-latest, ubuntu-22.04, macos-latest, windows-latest]
347+
runs-on: ${{ matrix.os }}
348+
timeout-minutes: 30
349+
steps:
350+
- name: Checkout
351+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
352+
with:
353+
persist-credentials: false
354+
355+
- name: Cache cargo
356+
uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1
357+
with:
358+
# Keep binaries linked against different glibc versions separate.
359+
key: bun-native-binary-${{ matrix.os }}
360+
save-if: ${{ github.ref == 'refs/heads/main' }}
361+
362+
- name: Setup Python
363+
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
364+
with:
365+
python-version: '3.12'
366+
367+
- name: Native binary writer and reader acceptance
368+
shell: bash
369+
env:
370+
MATRIX_OS: ${{ matrix.os }}
371+
run: |
372+
versions=()
373+
# Windows releases begin at 1.1.0. Ubuntu 22.04 and macOS exercise
374+
# every schema boundary, including the earliest format-1 writer.
375+
if [ "$RUNNER_OS" = "Windows" ]; then
376+
versions=(--versions 1.1.0 1.1.38 1.1.45 1.2.0 1.2.23 1.3.0 1.3.14 1.4.2)
377+
elif [ "$MATRIX_OS" = "ubuntu-latest" ]; then
378+
# Bun 0.5.9/0.6.x segfault during pristine HTTP initialization
379+
# on the Ubuntu 24.04 runner; the complete matrix remains
380+
# required on Ubuntu 22.04, with modern releases on both hosts.
381+
versions=(--versions 0.8.1 1.0.0 1.0.36 1.1.0 1.1.38 1.1.45 1.2.0 1.2.23 1.3.0 1.3.14 1.4.2)
382+
fi
383+
python3 scripts/backtest-bun-lockb.py \
384+
--tools native-binary/tools \
385+
--output native-binary/results \
386+
--jobs 2 "${versions[@]}"
387+
388+
- name: Diagnose historical Linux runtime failures
389+
if: failure() && runner.os == 'Linux'
390+
run: >-
391+
python3 scripts/probe-bun-historical-linux.py
392+
--tools native-binary/tools
393+
--output native-binary/results/linux-diagnostics
394+
395+
- name: Upload binary acceptance results
396+
if: always()
397+
uses: ./.github/actions/upload-artifact
398+
with:
399+
name: bun-binary-results-${{ matrix.os }}
400+
path: native-binary/results
329401
retention-days: 14

CHANGELOG.md

Lines changed: 16 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ into the new version's section — see docs/releasing.md.
2424
2525
### Changed (BREAKING)
2626

27+
- **Binary Bun lockfiles are patched natively in place.** Hosted and vendored
28+
modes read and rewrite `bun.lockb` formats 1–3 directly, including mode
29+
changes, repair, and scoped rollback. Binary-to-text conversion, migration
30+
ledger replay, and their warning codes and tests have been removed.
2731
- **`rollback` is now the full-state dual of `scan`.** `scan` and `rollback`
2832
are the batch primaries (`get``remove` stay the single-patch duals): a
2933
bare `rollback` restores the SYSTEM to unpatched across all three modes —
@@ -248,12 +252,8 @@ into the new version's section — see docs/releasing.md.
248252
table, staged all-or-nothing per ecosystem group, covering gem, golang,
249253
pypi, composer, bun, and the non-package rideshare edits (pnpm
250254
`trustLockfile` auto-config — pristine scaffold deleted, modified
251-
scaffold keeps the file and loses only the owned line). The bun.lockb
252-
migration marker restores the binary lock from the bytes the ledger
253-
captured (`redirect_bun_lockb_restored`; the generated `bun.lock` is kept)
254-
and warns `redirect_bun_lockb_unrestorable` naming git history only when
255-
the ledger holds no bytes and the file is absent, or a different
256-
`bun.lockb` has appeared since;
255+
scaffold keeps the file and loses only the owned line). Native `bun.lockb`
256+
package snapshots restore binary resolutions directly;
257257
maven and nuget fail closed with `hosted_revert_unsupported` guidance
258258
(their structured-metadata edits keep their ledger records; re-run
259259
`scan --mode hosted` or restore from VCS). Refused groups keep their
@@ -272,7 +272,7 @@ into the new version's section — see docs/releasing.md.
272272
an existing vendored patch, including during dry-run. Vendored preflight
273273
exemptions require live local lock tuples; a ledger retained by
274274
`rollback --preserve-state` cannot bypass a refusal or hide it in a preview.
275-
Symlinked `bun.lockb` files are refused before migration so their links
275+
Symlinked `bun.lockb` files are refused before patching so their links
276276
survive, and `vendor --silent` keeps refusal diagnostics on stderr.
277277

278278
- **Bun projects: every text-lock generation is accepted, vendored refusals
@@ -301,7 +301,7 @@ into the new version's section — see docs/releasing.md.
301301
`.socket/vendor/state.json` met by that preflight is reported as
302302
`vendor_state_unreadable` rather than a Bun lock code. `scan --mode vendored`,
303303
`get --mode vendored` (search and uuid paths) and `--detached` runs now
304-
preflight the Bun lock BEFORE any download: a binary-only, unreadable,
304+
preflight the Bun lock BEFORE any download: a malformed binary, unreadable,
305305
unsupported-version or pre-version-2 workspace lock marks the npm patches
306306
`failed` with the vendor refusal code and detail, fetches nothing and
307307
records no patch — the `scan` / `get <purl>` path still writes an unchanged
@@ -312,15 +312,10 @@ into the new version's section — see docs/releasing.md.
312312
`package_not_installed`). The refusals stay visible under `--silent`
313313
(code-tagged stderr line), `--dry-run` previews them as the additive
314314
`would_refuse` action (the human `scan` and `get` previews both print the
315-
`[would-refuse]` lines), the `bun.lockb` refusal carries one remedy on every
316-
path (`bun install --save-text-lockfile`, Bun ≥ 1.1.39), and a `scan` on a
317-
`bun.lockb`-only project warns `bun_lockb_unsupported` instead of reporting
318-
a clean empty inventory — the detail names a shadowed sibling
319-
`package-lock.json` / `yarn.lock` / `pnpm-lock.yaml` and the
320-
delete-the-stale-lockb remedy when one exists, and the warning is kept in
321-
hosted mode too (beside the driver's own `redirect_bun_lockb_*` outcome on
322-
the run that migrates) instead of being dropped on every non-empty hosted
323-
run. Hosted → vendored
315+
`[would-refuse]` lines). Valid binary locks are inventoried and patched
316+
directly without a Bun runtime; malformed binary locks report
317+
`bun_lockb_invalid`, `redirect_bun_lockb_invalid`, or
318+
`vendor_bun_lockb_invalid` at the corresponding entry point. Hosted → vendored
324319
takeover now works for bun —
325320
`scan`/`get --mode vendored` and `vendor` over a hosted-redirected `bun.lock`
326321
claim and replay that purl's hosted edit instead of refusing
@@ -329,21 +324,10 @@ into the new version's section — see docs/releasing.md.
329324
several hosted bun records; on a lock the vendored backend refuses (a
330325
pre-version-2 workspace lock) `vendor` and its dry run report the refusal
331326
BEFORE the hosted revert, leaving the purl hosted-patched instead of
332-
un-hosting it and then refusing. The hosted `bun.lockb` migration is truthful:
333-
`bun` is resolved on absolute `PATH` entries (Windows `bun.cmd` shims
334-
included, spawned directly — the standard library quotes batch-shim paths
335-
with spaces and metacharacters correctly), a stale `bun.lockb` beside a
336-
live npm / yarn / pnpm lock is left alone (`redirect_bun_lockb_sibling_lock`;
337-
the redirect follows the sibling lock) instead of converting the project to
338-
`bun.lock`, a `bun.lockb` that is not a regular file is refused before
339-
`bun` is spawned, a `bun.lockb` that Bun 1.1.43–1.1.45 keep beside the new text
340-
lock is removed by the CLI so the ledger's `removed` edit is true, the
341-
pre-migration bytes ride the ledger and `rollback` restores `bun.lockb`
342-
(`redirect_bun_lockb_restored`; the generated `bun.lock` is kept), Bun
343-
1.1.39–1.1.42 — which accept the flags but write nothing — get
344-
`redirect_bun_lockb_manual_migration` instead of a false "unavailable", and
345-
a failed spawn's `redirect_bun_lockb_unsupported` carries bun's output tail.
346-
The hosted rewrite keeps CRLF on the rewritten `bun.lock` line. Real-Bun
327+
un-hosting it and then refusing. Native `bun.lockb` edits preserve the
328+
dependency graph and unrelated package metadata while updating binary
329+
pointers, tarball integrity, and the package metadata hash. The hosted text
330+
rewrite keeps CRLF on the rewritten `bun.lock` line. Real-Bun
347331
coverage now runs in CI: the hermetic hosted and vendored suites on Linux,
348332
macOS and Windows (Bun 1.4.2, plus 1.1.45 and 1.2.23 lock-era legs), and
349333
the production native matrix — 16 releases from 0.8.1 to 1.4.2 in hosted,

README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,15 @@ Mode support varies by ecosystem — e.g. Go can't do hosted, Rush monorepos can
254254
vendored. See the full **[mode × ecosystem matrix](docs/ecosystems.md#mode--ecosystem-matrix)**
255255
for details and per-ecosystem caveats.
256256
257+
### Bun compatibility
258+
259+
Both text `bun.lock` and binary `bun.lockb` support hosted and vendored
260+
patches, mode switching, repair, and rollback. Binary locks are read and
261+
patched natively: Socket Patch does not need Bun installed to discover or
262+
rewrite them, and does not convert them to text. If both filenames exist,
263+
`bun.lock` takes precedence. See [Bun compatibility](docs/testing/bun-compatibility.md)
264+
for the tested versions, workspace behavior, and installer integrity limits.
265+
257266
### Pipenv compatibility
258267
259268
Hosted mode rewrites every `Pipfile.lock` category that pins the patched

0 commit comments

Comments
 (0)