Skip to content

install: use uppercase %2F for scoped package manifest URLs - #33774

Closed
erik-balfe wants to merge 1 commit into
oven-sh:mainfrom
erik-balfe:erik-balfe/fix-uppercase-percent-2F
Closed

install: use uppercase %2F for scoped package manifest URLs#33774
erik-balfe wants to merge 1 commit into
oven-sh:mainfrom
erik-balfe:erik-balfe/fix-uppercase-percent-2F

Conversation

@erik-balfe

Copy link
Copy Markdown

Fixes #30311
Fixes #26241

What does this PR do?

Re-applies the fix from #30312 for the Rust codebase (the prior PR targeted the Zig sources and was closed when Bun migrated to Rust).

Since bun 1.3.0 (from #5716), bun percent-encodes the / between scope and name for private-registry manifest requests as lowercase %2f:

GET /api/v4/packages/npm/@myorg%2fsomepackage

GitLab's npm registry returns 404 for this URL. It does not normalize %2f to / and does not treat %2f and %2F as equivalent. bun 1.2.23 sent the unencoded slash, which GitLab accepted.

Production changes (two characters):

  • src/install/NetworkTask.rs — scoped manifest URL construction for bun install (%2f%2F)
  • src/bun_core/fmt.rsDependencyUrlFormatter used by bun pm view / bun publish (%2f%2F)

This matches the npm CLI reference implementation and RFC 3986 §2.1. AWS CodeArtifact, Azure Artifacts, npmjs.org, and GitLab all accept %2F; no known registry accepts %2f but rejects %2F.

Also updates install test assertions and mock-registry URL normalization helpers to expect/accept uppercase %2F, and adds two regression tests.

How did you verify your code works?

Added regression tests in test/cli/install/bun-install-registry.test.ts:

  1. scoped package manifest url uses uppercase %2F — spins up a Bun.serve mock GitLab-style registry that 404s any URL containing lowercase %2f and serves a manifest only for uppercase %2F. Asserts bun sends %2F on the wire and bun install completes.

  2. bun pm view uses uppercase %2F for scoped names — same mock for the DependencyUrlFormatter code path via bun pm view.

Gate check (per CLAUDE.md): with the unfixed build, the new test should fail because bun sends lowercase %2f; with bun bd test test/cli/install/bun-install-registry.test.ts -t "scoped package manifest url uses uppercase", it should pass.

Note: Full bun bd build was not run in this environment (sparse checkout / missing LLVM toolchain). CI on BuildKite is the authoritative verification.

Supersedes the closed Zig PR #30312 for the current Rust tree.

Match the npm CLI and RFC 3986 §2.1 canonical form. GitLab's npm registry
returns 404 for lowercase %2f but accepts %2F. AWS CodeArtifact and Azure
Artifacts accept both.

Port of the fix from oven-sh#30312 to the Rust codebase:
- src/install/NetworkTask.rs (bun install manifest fetch)
- src/bun_core/fmt.rs (DependencyUrlFormatter for bun pm view/publish)

Adds regression tests and updates install test assertions.

Fixes oven-sh#30311
Fixes oven-sh#26241

@claude claude 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.

Claude Code Review

This pull request is from a fork — automated review is disabled. A repository maintainer can comment @claude review to run a one-time review.

@coderabbitai

coderabbitai Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: cdc353de-3094-4fe4-b3de-9dc835f3d974

📥 Commits

Reviewing files that changed from the base of the PR and between 332f744 and 61a7cbc.

📒 Files selected for processing (11)
  • src/bun_core/fmt.rs
  • src/install/NetworkTask.rs
  • test/cli/install/bun-add.test.ts
  • test/cli/install/bun-create.test.ts
  • test/cli/install/bun-install-registry.test.ts
  • test/cli/install/bun-install-security-provider.test.ts
  • test/cli/install/bun-install-tarball-integrity.test.ts
  • test/cli/install/bun-install.test.ts
  • test/cli/install/bun-update.test.ts
  • test/cli/install/bunx.test.ts
  • test/cli/install/dummy.registry.ts

Walkthrough

This PR changes scoped package name percent-encoding of "/" from lowercase %2f to uppercase %2F in DependencyUrlFormatter and NetworkTask::for_manifest. Corresponding test expectations across multiple CLI install tests are updated, mock registries normalize both cases, and new regression tests verify the uppercase encoding.

Changes

Uppercase %2F Encoding Fix

Layer / File(s) Summary
Core percent-encoding change
src/bun_core/fmt.rs, src/install/NetworkTask.rs
Scoped package name slashes are now percent-encoded as uppercase %2F instead of lowercase %2f in URL formatting and manifest request construction.
Existing test expectation updates
test/cli/install/bun-add.test.ts, test/cli/install/bun-create.test.ts, test/cli/install/bun-install.test.ts, test/cli/install/bun-update.test.ts, test/cli/install/bunx.test.ts
Expected URLs and error messages in existing tests are updated to reflect uppercase %2F encoding for scoped package names.
New regression tests for uppercase encoding
test/cli/install/bun-install-registry.test.ts
New tests spin up mock registries rejecting lowercase %2f, then run bun install and bun pm view for scoped packages, asserting manifest requests use uppercase %2F.
Mock registry request normalization
test/cli/install/dummy.registry.ts, test/cli/install/bun-install-security-provider.test.ts, test/cli/install/bun-install-tarball-integrity.test.ts
Mock registry handlers normalize both %2f and %2F to / when parsing request URLs, and related documentation comments are updated.
🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the main change to scoped package URL encoding.
Description check ✅ Passed The description includes both required sections and provides concrete implementation and verification details.
Linked Issues check ✅ Passed The code changes address the reported GitLab scoped-package URL encoding regression and add coverage for the fix.
Out of Scope Changes check ✅ Passed The added test updates and helper normalization changes are directly related to the scoped URL encoding fix.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@robobun

robobun commented Jul 8, 2026

Copy link
Copy Markdown
Collaborator

Thanks for this. I have pulled these commits onto a repo branch so CI can run, with some test cleanups layered on top: #33784. Authorship is preserved on the first commit.

@alii

alii commented Jul 9, 2026

Copy link
Copy Markdown
Member

Thanks for the PR, and sorry for the runaround here — closing this along with #33784, which carried the same change.

Short version: the premise doesn't hold. The npm CLI sends lowercase %2f, not %2Fnpm-package-arg@13.0.2 does name.replace('/', '%2f') (the comment directly above that line says %2F, which is almost certainly where the uppercase claim came from), and pacote builds the packument URL straight from it. Verified on the wire with npm 10.9.3 and 11.15.0 across view, install and pack.

And GitLab decodes both casings identically. Against live gitlab.com, %2f, %2F and a raw / all return byte-identical responses (a 302 to the same decoded name; a 401 for a namespace that actually exists). So the change can't affect GitLab either way.

Full evidence in #33784 (comment).

The underlying problem in #30311 looks like auth, not encoding — the latest report there is a 401, and I reproduced a 401 from GitLab with both casings. #26241 is about _authToken selection when multiple registries share a host with different paths. Both issues stay open, and a fix for the token-scoping side would be very welcome.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Private GitLab npm registry: scoped package resolution fails (401/404) since 1.3.x Private GitLab install errors

3 participants