SIGN IN SIGN UP
oven-sh / bun UNCLAIMED

Incredibly fast JavaScript runtime, bundler, test runner, and package manager – all in one

0 0 150 Rust

install: bump default lockfileVersion to 2, gate stricter parse checks behind it (#31539)

## What

Introduces text `lockfileVersion` 2, makes it the default, and gates two
parse-time checks — added after the Rust rewrite — behind it so that
older lockfiles keep loading.

## Background

Two checks landed in `src/install/lockfile/bun.lock.rs` that *reject* a
text lockfile the earlier versions accepted:

1. **Off-registry npm tarball integrity** — an npm package resolved to a
tarball URL that is not under the configured/default registry must carry
a supported integrity hash, otherwise parsing fails with `Missing
integrity hash for npm package resolved to a tarball URL outside the
configured registry`.
2. **Unsafe git `.bun-tag`** — a git/github `.bun-tag` that is not a
safe single path component (`is_safe_resolved_tag`) is rejected at parse
with `Invalid git dependency tag`.

Both are breaking: a `bun.lock` written before these checks existed
(e.g. an npm entry with an off-registry tarball and no integrity hash)
now fails to parse.

## Change

- Add `Version::V2` and an `at_least()` helper; bump `Version::CURRENT`
from V1 to V2. The writer always emits the current version, so fresh
lockfiles are now `"lockfileVersion": 2`.
- Gate both parse-time rejections behind
`lockfile_version.at_least(Version::V2)`. For v0/v1 lockfiles the checks
are skipped (the pre-check behavior), so existing lockfiles keep
loading.

### Security note

The git `.bun-tag` check is a path-traversal / checkout-arg guard. It is
**re-validated at the point of use** in `Repository::checkout`
(`src/install/repository.rs`) with the same `is_safe_resolved_tag`,
before any cache directory path is built or `git` is invoked — and a git
dependency can only reach the cache through `checkout`. Skipping the
*parse-time* rejection for older lockfile versions therefore does not
reopen the vulnerability; an unsafe tag still cannot be checked out or
turned into a traversal path.

The off-registry integrity gate restores, for v0/v1 only, the behavior
Bun shipped before the check was added. Lockfiles written at v2 always
carry integrity for off-registry tarballs, so enforcement there is
unaffected.

## Verification

New offline test `test/cli/install/lockfile-version-2.test.ts` (uses
`file:` deps, no registry):

- a freshly written text lockfile defaults to version 2
- an existing v1 lockfile still loads
- off-registry npm tarball integrity is enforced only at version 2 (v2
rejects at parse; v1 does not)
- unsafe git `.bun-tag` is rejected only at version 2

Fail-before/pass-after confirmed by building with the `src/` change
stashed: the three version-gated tests fail (v2 is an unknown version /
v1 still rejects), and pass with the change applied.

Also updated the existing off-registry-integrity test in
`test/cli/install/bun-lock.test.ts` to assert the v2 behavior, and
regenerated the written-lockfile snapshots (`lockfileVersion` 1 → 2).
Input-fixture lockfiles in tests are deliberately left at version 1 to
keep exercising backward-compatible loading.

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
R
robobun committed
973d1de8b519c569f8da1a1cc025750110926ecd
Parent: 3e033ea
Committed by GitHub <noreply@github.com> on 5/29/2026, 2:24:19 AM