Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
d5945cf
Add bun.sys.sigaction with bionic-correct layout for Android (#30389)
robobun May 8, 2026
1600acc
tls: load intermediates and trusted-people from Windows system stores…
cirospaciari May 8, 2026
3457c1e
Bun.mmap: throw on non-object options instead of asserting (#30404)
robobun May 8, 2026
6d0d86b
Bun.serve: validate websocket.perMessageDeflate is a boolean or objec…
robobun May 8, 2026
fe735f8
http: arm idle timer on open so a stalled TLS handshake times out (#3…
robobun May 9, 2026
03ebdf8
chore: prevent auto-update actions from running on forks (#30464)
190n May 10, 2026
450072b
install: disable isolated global virtual store by default until no lo…
robobun May 11, 2026
ca1788c
Don't retry non-idempotent HTTP methods on keep-alive disconnect (#28…
robobun May 11, 2026
4c0a5a7
node:http: dispatch request on first write() and emit response in dup…
robobun May 11, 2026
37bfbed
YAML.stringify: quote strings that parse back as numbers (#30435)
robobun May 11, 2026
2043f9c
Upgrade WebKit to 5488984d: fix require(ESM) diamond-dep deadlock (#3…
alii May 12, 2026
314ffe3
test: pin #23139 + #22743 — repeated dynamic import of error-throwing…
alii May 12, 2026
39540fd
github-actions: pin action versions (#30575)
alii May 12, 2026
0d9b296
Bun.serve: rename `h3`/`h1` options to `http3`/`http1` (#30583)
Jarred-Sumner May 12, 2026
3bf4b33
docs(server): fix line-wrapped code span in HTTP/3 note (#30591)
alii May 12, 2026
b9c757b
http: enable TCP keepalive on fetch sockets (#30627)
cirospaciari May 13, 2026
b8ecc78
http: gate fetch TCP keepalive on the existing `keepalive` option (#3…
cirospaciari May 13, 2026
23427db
Rewrite Bun in Rust (#30412)
Jarred-Sumner May 14, 2026
19d8ade
Delete stray files
Jarred-Sumner May 14, 2026
e872030
docs: update contributing guides for the Rust rewrite (#30708)
robobun May 14, 2026
d5c692a
build: fix local WebKit configure on PIE-default distros (#30710)
dylan-conway May 14, 2026
11a2e2c
chore: inherit workspace lints in all member crates (#30707)
Boshen May 14, 2026
63035b3
collections: remove dead unsafe methods from ArrayList and SmallList …
dylan-conway May 14, 2026
fd0b6f1
http: port fetch TCP keepalive to on_open in lib.rs (#30733)
dylan-conway May 14, 2026
8093571
rust: include `target_os = "android"` in linux-kernel cfg gates (#30735)
dylan-conway May 14, 2026
952d337
jsc: gate CallFrame::describe_frame on debug_assertions (#30742)
dylan-conway May 14, 2026
175f62a
ffi: cfg-gate local tcc_delete extern to match bun_tcc_sys (#30743)
dylan-conway May 14, 2026
428f61e
Bun.serve: finish h3/h1 → http3/http1 ServerConfig rename in Rust (#3…
dylan-conway May 14, 2026
bbd3e62
bun:ffi: extract embedded shared libraries from bunfs in `dlopen()` (…
robobun May 15, 2026
fe2635b
ci: replace zig fmt with cargo fmt --all in the format workflow (#30682)
Jarred-Sumner May 15, 2026
314d044
JSON lexer: tokenize `?`/`*`/`(`/`)` so `define` auto-quote can recov…
Jarred-Sumner May 15, 2026
bb1973e
build: generate bun_core::build_options from Config (#30749)
dylan-conway May 15, 2026
4d443e5
collections: funnel multi_array_list SoA ops through Col/ColMut primi…
dylan-conway May 15, 2026
2a3d0e7
resolver: keep forward slashes when imports target is a package speci…
robobun May 16, 2026
f85020a
hooks: deny direct rustfmt, point at cargo fmt --all (#30881)
Jarred-Sumner May 16, 2026
8438ff7
resolver: split the port's module wrapper into files; type the extern…
Jarred-Sumner May 16, 2026
f7c692a
Fix worker teardown crash from missing dupeRef on synthetic-module sp…
Jarred-Sumner May 16, 2026
e520065
Harden 36 reachable security findings across runtime, install, parser…
Jarred-Sumner May 16, 2026
880ee89
Clean up Zig-port phase comments and trivial lint warnings (#30877)
Jarred-Sumner May 16, 2026
e750984
cargo fmt
Jarred-Sumner May 16, 2026
112f305
refactor: remove unsafe for static strings (#30867)
robjtede May 17, 2026
0b09afd
fix(resolver): add PermissionDenied/EPERM/EACCES to directory read er…
May 17, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
77 changes: 49 additions & 28 deletions .buildkite/ci.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -368,15 +368,19 @@ function getLinkBunAgent(platform, options) {
}

return getEc2Agent(platform, options, {
// Full LTO with bun-zig.o as bitcode peaks >31 GiB on aarch64; xlarge OOMs.
// Full LTO with libbun_rust.a as bitcode peaks >31 GiB on aarch64; xlarge OOMs.
instanceType: arch === "aarch64" ? "r8g.2xlarge" : "r7i.2xlarge",
});
}

/**
* Linux box that cross-compiles libbun_rust.a for every linux/freebsd
* target. The image must have rustup + the pinned `rust-toolchain.toml`
* nightly preinstalled (with the `rust-src` component and every target
* triple in `rustup target add` form — bootstrap.sh handles this).
* @returns {Platform}
*/
function getZigPlatform() {
function getRustPlatform() {
return {
os: "linux",
arch: "aarch64",
Expand All @@ -391,21 +395,36 @@ function getZigPlatform() {
* @param {PipelineOptions} options
* @returns {Agent}
*/
function getZigAgent(platform, options) {
function getRustAgent(platform, options) {
const { os, arch } = platform;

// Windows builds Zig natively on Azure
// Windows: cargo's `*-pc-windows-msvc` target needs the MSVC SDK
// (link.exe is not invoked for a staticlib, but `cc`-crate build
// scripts and rustc's own `lib.exe` archiver need it). Runs natively
// on a Windows agent — `cargo-xwin` would let this share the linux
// box but isn't wired into the image yet.
if (os === "windows") {
return getEc2Agent(platform, options, {
instanceType: getAzureVmSize(os, arch),
});
}

// Everything else cross-compiles from Linux aarch64. ASAN gets a wider
// box: it builds with cg=CI_ASAN_CODEGEN_THREADS (8) so it can use the
// parallel backend; release stays at cg=1 (full IPO) so 2 vCPU suffice.
return getEc2Agent(getZigPlatform(), options, {
instanceType: platform.profile === "asan" ? "r8g.2xlarge" : "r8g.large",
// Darwin: rustc cross-compiles fine but the dep graph's `cc` build
// scripts need an osxcross SDK + cctools `ar`. Runs natively on a
// mac agent until osxcross is in the linux image.
if (os === "darwin") {
return {
queue: `build-${os}`,
os,
arch,
};
}

// Linux (gnu/musl/android) and FreeBSD: cross-compile from one Linux
// aarch64 box. cargo build is wide (1 codegen unit per crate × ~80
// crates), so size for cores. ASAN doubles the IR — bigger box.
return getEc2Agent(getRustPlatform(), options, {
instanceType: platform.profile === "asan" ? "r8g.4xlarge" : "r8g.2xlarge",
});
}

Expand Down Expand Up @@ -486,7 +505,7 @@ function getTestAgent(platform, options) {
*
* @param {Target} target
* @param {PipelineOptions} options
* @param {"cpp-only" | "zig-only" | "link-only"} mode
* @param {"cpp-only" | "rust-only" | "link-only"} mode
* @returns {string}
*/
function getBuildArgs(target, options, mode) {
Expand All @@ -495,11 +514,12 @@ function getBuildArgs(target, options, mode) {

const args = [`--profile=ci-${mode}`];

// zig-only cross-compiles (linux host → all targets); os/arch/abi must
// all be explicit — host detection (detectLinuxAbi checks /etc/alpine-release)
// would report the build box's abi (Alpine→musl), not the target's.
// cpp-only/link-only: native build, host detection is correct.
if (mode === "zig-only") {
// rust-only cross-compiles (linux host → linux/freebsd targets); os/arch/abi
// must all be explicit — host detection (detectLinuxAbi checks
// /etc/alpine-release) would report the build box's abi (Alpine→musl), not
// the target's. darwin/windows rust-only run natively (see getRustAgent), so
// host detection is correct there. cpp-only/link-only: native build.
if (mode === "rust-only" && os !== "darwin" && os !== "windows") {
args.push(`--os=${os}`, `--arch=${arch}`);
if (os === "linux") args.push(`--abi=${abi ?? "gnu"}`);
} else if (abi === "musl") {
Expand Down Expand Up @@ -527,7 +547,7 @@ function getBuildArgs(target, options, mode) {
/**
* @param {Target} target
* @param {PipelineOptions} options
* @param {"cpp-only" | "zig-only" | "link-only"} mode
* @param {"cpp-only" | "rust-only" | "link-only"} mode
* @returns {string}
*/
function getBuildCommand(target, options, mode) {
Expand Down Expand Up @@ -571,16 +591,17 @@ function getBuildCppStep(platform, options) {
* @param {PipelineOptions} options
* @returns {Step}
*/
function getBuildZigStep(platform, options) {
function getBuildRustStep(platform, options) {
return {
key: `${getTargetKey(platform)}-build-zig`,
key: `${getTargetKey(platform)}-build-rust`,
retry: getRetry(),
label: `${getTargetLabel(platform)} - build-zig`,
agents: getZigAgent(platform, options),
label: `${getTargetLabel(platform)} - build-rust`,
agents: getRustAgent(platform, options),
cancel_on_build_failing: isMergeQueue(),
// zig cross-compiles via --os/--arch in build args. No separate
// toolchain file — zig handles cross-compilation natively.
command: getBuildCommand(platform, options, "zig-only"),
// cargo cross-compiles via --os/--arch (mapped to `--target <triple>`
// in build args). The agent image has the pinned nightly + `rustup
// target add` for every triple preinstalled.
command: getBuildCommand(platform, options, "rust-only"),
timeout_in_minutes: 35,
};
}
Expand All @@ -594,7 +615,7 @@ function getLinkBunStep(platform, options) {
return {
key: `${getTargetKey(platform)}-build-bun`,
label: `${getTargetLabel(platform)} - build-bun`,
depends_on: [`${getTargetKey(platform)}-build-cpp`, `${getTargetKey(platform)}-build-zig`],
depends_on: [`${getTargetKey(platform)}-build-cpp`, `${getTargetKey(platform)}-build-rust`],
agents: getLinkBunAgent(platform, options),
retry: getRetry(),
cancel_on_build_failing: isMergeQueue(),
Expand All @@ -604,7 +625,7 @@ function getLinkBunStep(platform, options) {
ASAN_OPTIONS: "allow_user_segv_handler=1:disable_coredump=0:detect_leaks=0",
},
// link-only downloads artifacts from the sibling build-cpp and
// build-zig steps (derived from BUILDKITE_STEP_KEY) before ninja runs.
// build-rust steps (derived from BUILDKITE_STEP_KEY) before ninja runs.
command: getBuildCommand(platform, options, "link-only"),
};
}
Expand Down Expand Up @@ -1378,15 +1399,15 @@ async function getPipeline(options = {}) {
steps.push(
...relevantBuildPlatforms.map(target => {
const imageKey = getImageKey(target);
const zigImageKey = getImageKey(getZigPlatform());
const dependsOn = imagePlatforms.has(zigImageKey) ? [`${zigImageKey}-build-image`] : [];
const rustImageKey = getImageKey(getRustPlatform());
const dependsOn = imagePlatforms.has(rustImageKey) ? [`${rustImageKey}-build-image`] : [];
if (imagePlatforms.has(imageKey)) {
dependsOn.push(`${imageKey}-build-image`);
}

const steps = [];
steps.push(getBuildCppStep(target, options));
steps.push(getBuildZigStep(target, options));
steps.push(getBuildRustStep(target, options));
steps.push(getLinkBunStep(target, options));

if (needsBaselineVerification(target)) {
Expand Down
3 changes: 3 additions & 0 deletions .cargo/.gitkeep
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# This directory holds .cargo/config.toml, which is GENERATED at configure
# time by scripts/build/cargo-config.ts (run `bun bd`). The generated file is
# git-ignored; this placeholder keeps the directory in the tree.
7 changes: 7 additions & 0 deletions .claude/hooks/pre-bash-zig-build.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,13 @@ if (argv0 === "zig") {
}
}

// Disallow direct `rustfmt`: it doesn't read the workspace edition from
// Cargo.toml the way `cargo fmt` does, so its output can disagree with CI's
// Format job (`cargo fmt --all --check`).
if (argv0 === "rustfmt") {
denyWithReason("error: Don't run `rustfmt` directly. Run `cargo fmt --all` — it's what CI checks.");
}

// Check if argv0 is timeout and the command is "bun bd"
if (argv0 === "timeout") {
// Find the actual command after timeout and its arguments
Expand Down
2 changes: 1 addition & 1 deletion .github/actions/bump/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ runs:
echo "version=$LATEST" >> $GITHUB_OUTPUT
echo "message=$MESSAGE" >> $GITHUB_OUTPUT
- name: Create Pull Request
uses: peter-evans/create-pull-request@v7
uses: peter-evans/create-pull-request@22a9089034f40e5a961c8808d113e2c98fb63676 # v7
with:
add-paths: |
LATEST
Expand Down
26 changes: 11 additions & 15 deletions .github/workflows/CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ This document provides guidance for maintaining the GitHub Actions workflows in

### Overview

The `format.yml` workflow runs code formatters (Prettier, clang-format, and Zig fmt) on pull requests and pushes to main. It's optimized for speed by running all formatters in parallel.
The `format.yml` workflow runs code formatters (Prettier, clang-format, and `cargo fmt`) on pull requests and pushes to main. It's optimized for speed by running all formatters in parallel.

### Key Components

Expand All @@ -32,7 +32,7 @@ The `format.yml` workflow runs code formatters (Prettier, clang-format, and Zig

The workflow runs all three formatters simultaneously:

- Each formatter outputs with a prefix (`[prettier]`, `[clang-format]`, `[zig]`)
- Each formatter outputs with a prefix (`[prettier]`, `[clang-format]`, `[rustfmt]`)
- Output is streamed in real-time without blocking
- Uses GitHub Actions groups (`::group::`) for collapsible sections

Expand All @@ -44,20 +44,18 @@ The workflow runs all three formatters simultaneously:
- Uses `--no-install-recommends --no-install-suggests` to skip unnecessary packages
- Quiet installation with `-qq` and `-o=Dpkg::Use-Pty=0`

##### Zig
##### Rustfmt

- Downloads from `oven-sh/zig` releases (musl build for static linking)
- URL: `https://github.com/oven-sh/zig/releases/download/autobuild-{COMMIT}/bootstrap-x86_64-linux-musl.zip`
- Extracts to temp directory to avoid polluting the repository
- Directory structure: `bootstrap-x86_64-linux-musl/zig`
- The pinned nightly is set via `RUSTUP_TOOLCHAIN` in the step `env:` (kept in sync with `channel` in `rust-toolchain.toml`); `cargo fmt --all` runs against the workspace at the repo root.
- `RUSTUP_TOOLCHAIN` makes rustup ignore `rust-toolchain.toml` entirely, so the workflow installs only the host toolchain + `rustfmt` (`rustup toolchain install --profile minimal --component rustfmt`) rather than the file's full cross-target list.

### Updating the Workflow

#### To update Zig version:
#### To update the Rust toolchain:

1. Find the new commit hash from https://github.com/oven-sh/zig/releases
2. Replace the hash in the wget URL (line 65 of format.yml)
3. Test that the URL is valid and the binary works
1. Bump `channel` in `rust-toolchain.toml` (and `Dockerfile`/`bootstrap.sh` to match).
2. Bump `RUSTUP_TOOLCHAIN` in the `Format Code` step's `env:` block in `format.yml` to the same value.
3. `cargo fmt` formatting can change between nightlies; run `cargo fmt --all` locally on the new toolchain and include the resulting diff in the same PR.

#### To update clang-format version:

Expand All @@ -73,9 +71,8 @@ The workflow runs all three formatters simultaneously:

1. **Parallel execution**: All formatters run simultaneously
2. **Minimal installations**: Only required packages, no extras
3. **Temp directories**: Tools downloaded to temp dirs, cleaned up after use
4. **Streaming output**: Real-time feedback without buffering
5. **Early start**: Formatting begins immediately after each tool is ready
3. **Streaming output**: Real-time feedback without buffering
4. **Early start**: Formatting begins immediately after each tool is ready

### Troubleshooting

Expand Down Expand Up @@ -114,5 +111,4 @@ export LLVM_VERSION_MAJOR=19

- The script defaults to **format** mode (modifies files)
- Always test locally before pushing workflow changes
- The musl Zig build works on glibc systems due to static linking
- Keep the exclusion list updated as new third-party code is added
2 changes: 1 addition & 1 deletion .github/workflows/auto-close-duplicates.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:

steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4

- name: Setup Bun
uses: ./.github/actions/setup-bun
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/auto-label-claude-prs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:
pull-requests: write
steps:
- name: Add claude label to PRs from robobun
uses: actions/github-script@v7
uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7
with:
script: |
github.rest.issues.addLabels({
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/bun-types.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ jobs:
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Setup Bun
uses: ./.github/actions/setup-bun
with:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/claude-dedupe-issues.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ jobs:

steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4

- name: Run Claude Code slash command
uses: anthropics/claude-code-base-action@98d41f9809750c4c96f2cd285746ecef889f14bc
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/claude-find-issues-for-pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ jobs:

steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4

- name: Find issues this PR may fix
uses: anthropics/claude-code-base-action@98d41f9809750c4c96f2cd285746ecef889f14bc
Expand Down
46 changes: 29 additions & 17 deletions .github/workflows/format.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ jobs:
cancel-in-progress: true
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Configure Git
run: |
git config --global core.autocrlf true
Expand All @@ -36,10 +36,19 @@ jobs:
run: |
bun install
- name: Format Code
env:
# Pin the toolchain explicitly so rustup ignores rust-toolchain.toml's
# `targets` list (11 cross triples ≈ 450 MB of prebuilt std we don't
# need just to run rustfmt). Keep this in sync with `channel` there.
RUSTUP_TOOLCHAIN: nightly-2026-05-06
run: |
# Without pipefail, `cmd | sed` always reports sed's exit status, so a
# failing formatter is invisible to the `wait $PID` checks below.
set -o pipefail

# Start prettier in background with prefixed output
echo "::group::Prettier"
(bun run prettier 2>&1 | sed 's/^/[prettier] /' || echo "[prettier] Failed with exit code $?") &
(bun run prettier 2>&1 | sed 's/^/[prettier] /') &
PRETTIER_PID=$!

# Start clang-format installation and formatting in background with prefixed output
Expand All @@ -55,21 +64,17 @@ jobs:
) &
CLANG_PID=$!

# Setup Zig in temp directory and run zig fmt in background with prefixed output
echo "::group::Zig fmt"
# Run cargo fmt in background with prefixed output. RUSTUP_TOOLCHAIN
# (step env) overrides rust-toolchain.toml, so install only the host
# toolchain + rustfmt instead of the file's 11 cross-target std libs.
echo "::group::Cargo fmt"
(
ZIG_TEMP=$(mktemp -d)
echo "[zig] Downloading Zig (musl build)..."
wget -q -O "$ZIG_TEMP/zig.zip" https://github.com/oven-sh/zig/releases/download/autobuild-e0b7c318f318196c5f81fdf3423816a7b5bb3112/bootstrap-x86_64-linux-musl.zip
unzip -q -d "$ZIG_TEMP" "$ZIG_TEMP/zig.zip"
export PATH="$ZIG_TEMP/bootstrap-x86_64-linux-musl:$PATH"
echo "[zig] Running zig fmt..."
zig fmt src 2>&1 | sed 's/^/[zig] /'
./scripts/sort-imports.ts src 2>&1 | sed 's/^/[zig] /'
zig fmt src 2>&1 | sed 's/^/[zig] /'
rm -rf "$ZIG_TEMP"
echo "[rustfmt] Installing toolchain $RUSTUP_TOOLCHAIN..."
rustup toolchain install "$RUSTUP_TOOLCHAIN" --profile minimal --component rustfmt --no-self-update 2>&1 | sed 's/^/[rustfmt] /'
echo "[rustfmt] Running cargo fmt --all..."
cargo fmt --all 2>&1 | sed 's/^/[rustfmt] /'
) &
ZIG_PID=$!
RUST_PID=$!

# Wait for all formatting tasks to complete
echo ""
Expand All @@ -88,8 +93,8 @@ jobs:
fi
echo "::endgroup::"

if ! wait $ZIG_PID; then
echo "::error::Zig fmt failed"
if ! wait $RUST_PID; then
echo "::error::cargo fmt failed"
FAILED=1
fi
echo "::endgroup::"
Expand All @@ -104,4 +109,11 @@ jobs:
- name: Ban Words
run: |
bun ./test/internal/ban-words.test.ts
- name: Verify checked-in codegen
# `*.generated.rs` are deterministic outputs of `*.string-map.ts`; the
# source `.ts` is the truth. This step regenerates and fails if the
# committed `.generated.rs` is stale, so a forgotten regen surfaces in
# CI rather than as a confusing behaviour diff later.
run: |
bun run codegen:verify
- uses: autofix-ci/action@635ffb0c9798bd160680f18fd73371e355b85f27
Loading
Loading