Skip to content

fix(install): store and verify SHA-512 integrity hash for GitHub tarball dependencies - #27019

Merged
Jarred-Sumner merged 10 commits into
mainfrom
claude/fix-github-tarball-integrity
Feb 17, 2026
Merged

Jarred-Sumner merged 10 commits into
mainfrom
claude/fix-github-tarball-integrity

Conversation

@robobun

@robobun robobun commented Feb 14, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Compute SHA-512 hash of GitHub tarball bytes during extraction and store in bun.lock
  • Verify the hash on subsequent installs when re-downloading, rejecting tampered tarballs
  • Automatically upgrade old lockfiles without integrity by computing and persisting the hash
  • Maintain backward compatibility with old lockfile format (no integrity field)

Fixes GHSA-pfwx-36v6-832x

Lockfile format change

Before: ["pkg@github:user/repo#ref", {}, "resolved-commit"]
After:  ["pkg@github:user/repo#ref", {}, "resolved-commit", "sha512-..."]

The integrity field is optional for backward compatibility. Old lockfiles are automatically upgraded when the tarball is re-downloaded.

Test plan

  • Fresh install stores SHA-512 integrity hash in lockfile
  • Re-install with matching hash succeeds
  • Re-install with mismatched hash rejects the tarball
  • Old lockfile without integrity is auto-upgraded with hash on re-download
  • Cache hits still work without re-downloading
  • Existing GitHub dependency tests pass (10/10)
  • Existing git resolution snapshot test passes
  • Yarn migration snapshot tests pass

🤖 Generated with Claude Code

Claude Bot and others added 2 commits February 14, 2026 02:46
…all dependencies

GitHub git dependencies downloaded as tarballs via the GitHub API were
not having their content integrity verified against the lockfile. A
compromised api.github.com or codeload.github.com server could serve
a different tarball than expected without detection.

This change:
- Computes SHA-512 of GitHub tarball bytes during initial extraction
- Stores the hash in bun.lock alongside the resolved commit hash
- Verifies the hash on subsequent installs when re-downloading
- Maintains backward compatibility with lockfiles without integrity

The lockfile format for GitHub dependencies changes from:
  ["pkg@github:user/repo#ref", {}, "resolved-commit"]
to:
  ["pkg@github:user/repo#ref", {}, "resolved-commit", "sha512-..."]

Old lockfiles without the integrity field continue to work normally.

Co-Authored-By: Claude <noreply@anthropic.com>
When re-installing from an old lockfile that doesn't have integrity
hashes for GitHub dependencies, compute the hash from the downloaded
tarball and force-save the lockfile with the new hash.

Also adds comprehensive tests for:
- Integrity hash stored on fresh install
- Integrity verified on re-install with matching hash
- Install rejected when integrity doesn't match
- Old lockfile automatically upgraded with integrity hash
- Cache hits still work without integrity

Co-Authored-By: Claude <noreply@anthropic.com>
@robobun

robobun commented Feb 14, 2026 •

Copy link
Copy Markdown
Collaborator Author
Updated 6:48 PM PT - Feb 16th, 2026

❌ @Jarred-Sumner, your commit f7e8055 has 2 failures in Build #37408 (All Failures):


🧪   To try this PR locally:

bunx bun-pr 27019

That installs a local version of the PR into your bun-27019 executable, so you can run:

bun-27019 --bun

@coderabbitai

coderabbitai Bot commented Feb 14, 2026 •

Copy link
Copy Markdown
Contributor

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Adds SHA-512 integrity support for GitHub/Git tarball installs: extraction now attaches or reuses an integrity hash, PackageManager/PackageInstaller persist missing integrity into the lockfile and force-save it, bun.lock parsing/serialization accepts and emits an optional integrity field, and tests exercise capture, verification, mismatch, upgrade, and cache reuse. (50 words)

Changes

Cohort / File(s) Summary
Core Types & Exports
src/install/install.zig
Added integrity: Integrity to ExtractData and re-exported Integrity for use across the install flow.
Tarball Extraction
src/install/extract_tarball.zig
For GitHub tarballs: propagate an existing lockfile integrity if present; otherwise compute a SHA-512 over the tarball bytes and attach it to the returned ExtractData.
Installer Queue Handling
src/install/PackageInstaller.zig
When an enqueued install carries an integrity and the lockfile lacks one, assign that integrity into the lockfile's package meta and set a force-save flag so the lockfile will be re-saved.
Dependency Processing
src/install/PackageManager/processDependencyList.zig
For git/GitHub resolutions: after constructing the package and when a computed integrity is available, set package.meta.integrity before appending to the lockfile.
Lockfile I/O
src/install/lockfile/bun.lock.zig
Parse an optional integrity string from inline Git/GitHub resolved entries and conditionally serialize pkg.meta.integrity into the lockfile JSON when present and the tag supports it.
Tests
test/cli/install/bun-install-github-integrity.test.ts
New test suite covering integrity storage in bun.lock, re-install with matching hash, rejection on mismatch, lockfile upgrade to include integrity, and cached GitHub tarball reuse without re-download.
🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Merge Conflict Detection ⚠️ Warning ❌ Merge conflicts detected (13 files):

⚔️ src/bun.js/api/server/NodeHTTPResponse.zig (content)
⚔️ src/install/PackageInstaller.zig (content)
⚔️ src/install/PackageManager/processDependencyList.zig (content)
⚔️ src/install/extract_tarball.zig (content)
⚔️ src/install/install.zig (content)
⚔️ src/install/lockfile/bun.lock.zig (content)
⚔️ test/js/bun/http/fixtures/cert.key (content)
⚔️ test/js/bun/http/fixtures/cert.pem (content)
⚔️ test/js/bun/test/parallel/test-https-should-work-when-sending-request-with-agent-false.ts (content)
⚔️ test/js/node/http/node-http.test.ts (content)
⚔️ test/js/workerd/html-rewriter.test.js (content)
⚔️ test/regression/fixtures/cert.key (content)
⚔️ test/regression/fixtures/cert.pem (content)

These conflicts must be resolved before merging into main.
Resolve conflicts locally and push changes to this branch.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main change: storing and verifying SHA-512 integrity hashes for GitHub tarball dependencies, which aligns with the core functionality added across multiple files.
Description check ✅ Passed The description includes both required sections (What it does and How verified) with comprehensive detail about changes, test plan, and security fix, meeting template requirements.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

Tip

Issue Planner is now in beta. Read the docs and try it out! Share your feedback on Discord.


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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In `@test/regression/issue/github-tarball-integrity.test.ts`:
- Around line 70-79: The test currently spawns proc1 via Bun.spawn and awaits
proc1.exited but doesn't assert its exit code before reading bun.lock; update
the test to check proc1.exitCode (or proc1.exitStatus) is 0 immediately after
awaiting proc1.exited and fail the test (include proc1.stdout/proc1.stderr
output in the assertion message) if it is nonzero so we don't proceed after a
failed install; locate the Bun.spawn call and the await proc1.exited usage and
add the exit-code assertion before any code that reads or relies on bun.lock.
- Around line 1-7: The test file name github-tarball-integrity.test.ts in the
test/regression/issue folder violates the naming convention; rename this file to
use a real numeric GitHub issue ID (e.g., 12345.test.ts) or move it out of
test/regression/issue into an appropriate folder; update any imports or
references to the file if present (search for
"github-tarball-integrity.test.ts") so the test runner and CI pick up the
correctly named regression test.
- Around line 8-19: The clearGitHubCache function should respect a custom cache
dir and avoid scanning a missing directory: compute cacheDir from
process.env.BUN_INSTALL_CACHE_DIR || join(homedir(), ".bun", "install",
"cache"), check that cacheDir exists (e.g., with fs.existsSync or fs.stat) and
return early if not present, and only then create Bun.Glob instances and call
glob.scan / indexGlob.scan; keep the existing join(cacheDir, entry) removal
logic and preserve pattern handling in clearGitHubCache.

Comment on lines +1 to +7
import { file } from "bun";
import { describe, expect, test } from "bun:test";
import { rm } from "fs/promises";
import { bunEnv, bunExe, tempDir } from "harness";
import { homedir } from "os";
import { join } from "path";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Rename this regression test file to a real issue number (or move it out of test/regression/issue).

The filename is not a numeric issue ID, which violates the regression-test naming convention for this folder.

As per coding guidelines, "test/regression/issue/*.test.ts: Place regression tests for GitHub issues in test/regression/issue/${issueNumber}.test.ts and ensure the issue number is REAL, not a placeholder."

🤖 Prompt for AI Agents
In `@test/regression/issue/github-tarball-integrity.test.ts` around lines 1 - 7,
The test file name github-tarball-integrity.test.ts in the test/regression/issue
folder violates the naming convention; rename this file to use a real numeric
GitHub issue ID (e.g., 12345.test.ts) or move it out of test/regression/issue
into an appropriate folder; update any imports or references to the file if
present (search for "github-tarball-integrity.test.ts") so the test runner and
CI pick up the correctly named regression test.

Comment thread test/cli/install/bun-install-github-integrity.test.ts Outdated
Comment thread test/cli/install/GHSA-pfwx-36v6-832x.test.ts
@claude

claude Bot commented Feb 14, 2026 •

Copy link
Copy Markdown
Contributor

Code Review

Newest first

✅ 51919 — Looks good!

Reviewed 6 files across src/install/ and test/cli/install/: This PR adds SHA-512 integrity hash computation, storage, and verification for GitHub tarball dependencies in bun.lock, preventing supply-chain attacks where a compromised server could silently swap package tarballs.


✅ 65552 — Looks good!

Reviewed 6 files across src/install/ and test/regression/: This PR adds SHA-512 integrity hash computation, storage, and verification for GitHub tarball dependencies in Bun's package installer.


Powered by Claude Code Review

- Move test from test/regression/issue/ to test/cli/install/ since there
  is no numbered GitHub issue for this advisory
- Use BUN_INSTALL_CACHE_DIR env var with fallback, and check directory
  exists before scanning in clearGitHubCache
- Add exit code assertion after first install in the re-install test

Co-Authored-By: Claude <noreply@anthropic.com>
@robobun

robobun commented Feb 14, 2026

Copy link
Copy Markdown
Collaborator Author

Addressed all review comments in a5f00a0:

  1. Test file location: Moved from test/regression/issue/github-tarball-integrity.test.ts to test/cli/install/bun-install-github-integrity.test.ts since there's no numbered GitHub issue for this advisory.

  2. clearGitHubCache robustness: Now respects BUN_INSTALL_CACHE_DIR env var with fallback to the default path, and checks the directory exists before scanning.

  3. Exit code assertion: Added expect(exitCode1).toBe(0) after the first install in the re-install test, before reading bun.lock.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In `@test/cli/install/bun-install-github-integrity.test.ts`:
- Around line 83-88: The test currently grabs the first sha512 in the lockfile
(lockfileContent -> integrityMatch -> integrityHash) which can be from a
registry; instead, locate the GitHub entry first by matching the resolved GitHub
commit/URL (the resolved line that contains github.com and the commit hash) and
then extract the integrity value adjacent to that GitHub block; update the
regex/lookup to first find the GitHub resolved entry and then search its nearby
lines for the "sha512-..." string, and adjust the integrityMatch/integrityHash
extraction to use that matched integrity for the assertion.
- Around line 10-19: clearGitHubCache currently reads
process.env.BUN_INSTALL_CACHE_DIR but the test spawn uses bunEnv without setting
BUN_INSTALL_CACHE_DIR, causing mismatched cache locations; update the test to
create a per-test cache dir (e.g., const cacheDir = join(packageDir,
".bun-cache")), pass that path into clearGitHubCache(cacheDir) and set it on the
spawned process env by spreading bunEnv and adding BUN_INSTALL_CACHE_DIR:
cacheDir so both cleanup and installs use the same per-test cache; locate uses
of clearGitHubCache, bunEnv, and the spawn call in this test file to apply the
change.

Comment thread test/cli/install/bun-install-github-integrity.test.ts Outdated
Comment thread test/cli/install/bun-install-github-integrity.test.ts Outdated
Comment thread test/cli/install/GHSA-pfwx-36v6-832x.test.ts
- Replace clearGitHubCache with per-test BUN_INSTALL_CACHE_DIR inside
  each temp dir, matching the pattern used by other install tests
- Fix integrity regex to anchor on the GitHub resolved entry
  ("jonschlinkert-is-number-98e8ff1") to avoid matching npm hashes
- Make cache-hit test deterministic: warm cache with a first install,
  strip integrity from lockfile, then verify second install succeeds
  from cache

Co-Authored-By: Claude <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@test/cli/install/bun-install-github-integrity.test.ts`:
- Around line 70-71: Reorder the assertions for the first install so that test
output is asserted before checking the process exit; specifically, after
awaiting proc1.stdout.text(), proc1.stderr.text(), and proc1.exited into
stdout1, stderr1, exitCode1 (from proc1), add assertions on stdout1 and/or
stderr1 (e.g., expect(stdout1).toContain(...) or expect(stderr1).toBe(''))
before calling expect(exitCode1).toBe(0) to ensure stderr1 is printed when the
test fails.
- Around line 225-226: Reorder the assertions in the test that reads proc1
outputs: after awaiting stdout1, stderr1, and exitCode1, assert the process
output values (e.g., expect(stdout1).toBe(...) and/or expect(stderr1).toBe(...))
before asserting expect(exitCode1).toBe(0); update the test that uses proc1,
stdout1, stderr1, and exitCode1 so stdout/stderr expectations run prior to the
exitCode assertion to provide better failure diagnostics.

Comment thread test/cli/install/GHSA-pfwx-36v6-832x.test.ts
Comment thread test/cli/install/GHSA-pfwx-36v6-832x.test.ts
Co-Authored-By: Claude <noreply@anthropic.com>
});

const [stdout1, stderr1, exitCode1] = await Promise.all([proc1.stdout.text(), proc1.stderr.text(), proc1.exited]);
expect(stderr1).not.toContain("error:");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Test

@claude

claude Bot commented Feb 14, 2026

Copy link
Copy Markdown
Contributor

Code Review

Newest first

✅ ddec7 — Looks good!

Reviewed 12 files implementing SHA-512 integrity verification for GitHub tarball dependencies in the package manager: computes and stores content hashes in lockfiles on first install and verifies them on subsequent installs to detect tarball tampering.

Note: One minor nit (exitCode checked before stderr validation at lines 71 and 226 in the test file) was identified but already flagged by CodeRabbit in existing review threads.


Powered by Claude Code Review

Comment thread src/install/extract_tarball.zig Outdated
} else {
// First install (no integrity in the lockfile yet): compute it.
result.integrity = .{ .tag = .sha512 };
std.crypto.hash.sha2.Sha512.hash(bytes, result.integrity.value[0..std.crypto.hash.sha2.Sha512.digest_length], .{});

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use bun.sha.*, not std.crypto.

@Jarred-Sumner Jarred-Sumner left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use bun.sha not std.crypto

It must verify integrity before extracting. Not after.

Claude Bot and others added 2 commits February 14, 2026 08:54
@claude

claude Bot commented Feb 14, 2026

Copy link
Copy Markdown
Contributor

Code Review

Newest first

✅ 904c9 — Looks good!

Reviewed 33 files across src/install/, src/shell/, src/http/, and test/: Adds SHA-512 integrity hash computation and verification for GitHub tarball dependencies to prevent supply chain attacks, storing the hash in the lockfile and verifying it on subsequent installs while maintaining backward compatibility with old lockfile formats.


Powered by Claude Code Review

@claude

claude Bot commented Feb 14, 2026

Copy link
Copy Markdown
Contributor

Code Review

Newest first

✅ 904c9 — Looks good!

Reviewed 37 files across src/install/, src/shell/, src/bun.js/, and test/: Adds SHA-512 integrity hash computation and verification for GitHub tarball dependencies in the package installer to detect tampered tarballs, along with fixes for shell builtins (seq, conditional expressions) and WebSocket proxy issues.


Powered by Claude Code Review

@claude

claude Bot commented Feb 14, 2026

Copy link
Copy Markdown
Contributor

Code Review

Newest first

✅ 06a9e — Looks good!

Reviewed 5 files across src/install/ and test/cli/install/: Adds SHA-512 content integrity verification for GitHub tarball dependencies, storing hashes in the lockfile and verifying on subsequent installs to detect tampering.


Powered by Claude Code Review

@Jarred-Sumner
Jarred-Sumner merged commit f5d9819 into main Feb 17, 2026
3 of 5 checks passed
@Jarred-Sumner
Jarred-Sumner deleted the claude/fix-github-tarball-integrity branch February 17, 2026 01:53
@claude

claude Bot commented Feb 17, 2026

Copy link
Copy Markdown
Contributor

Code Review

Newest first

✅ f7e80 — Looks good!

Reviewed 6 files across src/install/ and test/cli/install/: Adds SHA-512 integrity hash verification for GitHub tarball dependencies during package installation, storing computed hashes in the lockfile to detect tampering or corruption on subsequent installs.


Powered by Claude Code Review

structwafel pushed a commit to structwafel/bun that referenced this pull request Apr 25, 2026
…all dependencies (oven-sh#27019)

## Summary

- Compute SHA-512 hash of GitHub tarball bytes during extraction and
store in `bun.lock`
- Verify the hash on subsequent installs when re-downloading, rejecting
tampered tarballs
- Automatically upgrade old lockfiles without integrity by computing and
persisting the hash
- Maintain backward compatibility with old lockfile format (no integrity
field)

Fixes GHSA-pfwx-36v6-832x

## Lockfile format change

```
Before: ["pkg@github:user/repo#ref", {}, "resolved-commit"]
After:  ["pkg@github:user/repo#ref", {}, "resolved-commit", "sha512-..."]
```

The integrity field is optional for backward compatibility. Old
lockfiles are automatically upgraded when the tarball is re-downloaded.

## Test plan

- [x] Fresh install stores SHA-512 integrity hash in lockfile
- [x] Re-install with matching hash succeeds
- [x] Re-install with mismatched hash rejects the tarball
- [x] Old lockfile without integrity is auto-upgraded with hash on
re-download
- [x] Cache hits still work without re-downloading
- [x] Existing GitHub dependency tests pass (10/10)
- [x] Existing git resolution snapshot test passes
- [x] Yarn migration snapshot tests pass

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
xhjkl pushed a commit to xhjkl/bun that referenced this pull request May 14, 2026
…all dependencies (oven-sh#27019)

## Summary

- Compute SHA-512 hash of GitHub tarball bytes during extraction and
store in `bun.lock`
- Verify the hash on subsequent installs when re-downloading, rejecting
tampered tarballs
- Automatically upgrade old lockfiles without integrity by computing and
persisting the hash
- Maintain backward compatibility with old lockfile format (no integrity
field)

Fixes GHSA-pfwx-36v6-832x

## Lockfile format change

```
Before: ["pkg@github:user/repo#ref", {}, "resolved-commit"]
After:  ["pkg@github:user/repo#ref", {}, "resolved-commit", "sha512-..."]
```

The integrity field is optional for backward compatibility. Old
lockfiles are automatically upgraded when the tarball is re-downloaded.

## Test plan

- [x] Fresh install stores SHA-512 integrity hash in lockfile
- [x] Re-install with matching hash succeeds
- [x] Re-install with mismatched hash rejects the tarball
- [x] Old lockfile without integrity is auto-upgraded with hash on
re-download
- [x] Cache hits still work without re-downloading
- [x] Existing GitHub dependency tests pass (10/10)
- [x] Existing git resolution snapshot test passes
- [x] Yarn migration snapshot tests pass

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
@robobun

robobun commented Aug 15, 2026

Copy link
Copy Markdown
Collaborator Author

The GitHub integrity test added here installed a real repository from api.github.com and failed whenever GitHub did (build 98240); #39115 serves the tarball locally instead.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants