Skip to content

publish: accept Basic credentials from .npmrc and bunfig.toml - #38782

Closed
robobun wants to merge 1 commit into
mainfrom
farm/1498ce1a/publish-basic-auth
Closed

publish: accept Basic credentials from .npmrc and bunfig.toml#38782
robobun wants to merge 1 commit into
mainfrom
farm/1498ce1a/publish-basic-auth

Conversation

@robobun

@robobun robobun commented Aug 15, 2026

Copy link
Copy Markdown
Collaborator

Fixes #17531

Problem

  • bun publish exits with "error: missing authentication (run bunx npm login)" and uploads nothing whenever the registry is configured with Basic credentials: .npmrc //host/:username= + //host/:_password=, .npmrc //host/:_auth=, or a bunfig registry / [install.scopes] entry with username + password. bun install works with the same config, and so does npm publish. This is the shape used with registries that authenticate with Basic (Nexus, Azure DevOps feeds, Verdaccio), and it is the Basic-auth half of Cannot publish to custom registry, npm can with the same config #18670 (the publishConfig.registry half is publish: honor publishConfig.registry and publishConfig["@scope:registry"] #38322).
  • Cause: the pre-flight check in publish() (src/runtime/cli/publish_command.rs:870) only accepts scope.token or userinfo embedded in the registry URL. The Basic credential that the config loaders put in scope.auth is ignored, even though construct_publish_headers (same file) already sends Authorization: Basic <scope.auth> when there is no token, so the rest of the publish path supports it.
  • Not a regression: 1.3.14 has the same check. Listed here because it is one of the private-registry publish shapes that fails on the 1.4 release candidate.

Fix

  • The check also accepts a non-empty scope.auth. Nothing else changes: a registry with neither a token nor Basic credentials still fails with missing authentication before any request is made.
  • Tests: test/cli/install/bun-publish.test.ts, describe("basic auth"), against an in-process registry that records the PUT and its Authorization header: .npmrc username + _password, .npmrc _auth, bunfig scoped registry with username + password (the Bun Publish doesn't support token based login (Azure Devops) #17531 config), bun publish <tarball>, and the no-credentials rejection. The four positive cases fail on the current canary (missing authentication, no request) and pass with this change; all of bun-publish.test.ts (44 tests) and npmrc.test.ts pass with the debug build.
  • Incidental: the two lifecycle scripts > should run in order tests in the same file spawn six child bun processes each and take about 5s on a debug build, and their timeout kills the Verdaccio shared by the rest of the file. They now declare a 30s timeout; without it the file cannot pass under a debug build here.
  • The same one-line condition change is also part of install: resolve .npmrc credentials by path-segment ancestor #33869, which reworks .npmrc credential resolution more broadly; this PR only carries the publish check so the RC gets it independently of that work.

Background

  • A registry Scope (src/install/npm.rs) is bun's resolved registry: the URL plus one credential, either token (sent as Authorization: Bearer) or auth, the base64 user:password string (sent as Authorization: Basic). Scope::from_api builds auth from a username + password pair, and the .npmrc loader decodes _auth into that pair, so every Basic configuration ends up in scope.auth.
  • scope_for_package_name picks the default scope or the @scope:registry one for the package being published; publish() runs the credential check on that scope and then construct_publish_headers turns it into the header, which is why the header side already handled Basic while the check did not.
Repro matrix on 1.4.0-canary.1 (b7a0431), mock registry recording the PUT
.npmrc registry= + //host/:_authToken                 exit=0  ["PUT Bearer tok"]
.npmrc registry= + //host/:username + :_password      exit=1  []  error: missing authentication
.npmrc registry= + //host/:_auth                      exit=1  []  error: missing authentication
bunfig registry = { url, username, password }         exit=1  []  error: missing authentication
@corp:registry + //host/:_auth, publishing @corp/x    exit=1  []  error: missing authentication

bun install with each of the Basic shapes above:      GET /no-deps  Authorization: Basic YWxpY2U6czNjcmV0

With this change every publish row sends PUT /<name> with Authorization: Basic <base64> and exits 0.

`bun publish` refused to run with "missing authentication" unless the
registry had a token or the registry URL itself carried userinfo, even
though the Basic credential built from `//host/:username` +
`//host/:_password`, `//host/:_auth`, or a bunfig `username`/`password`
pair is what `bun install` already sends and what the publish request
headers are built from. Count that credential as authentication too.

The two lifecycle-order publish tests spawn six child bun processes
each and exceed the default timeout on debug builds, which kills the
shared Verdaccio for the rest of the file; give them their own timeout.
@coderabbitai

coderabbitai Bot commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

@robobun, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 4 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: cda16b9d-245a-4bde-a08e-d4513759931f

📥 Commits

Reviewing files that changed from the base of the PR and between 4bf3f36 and a6d8c4a.

📒 Files selected for processing (2)
  • src/runtime/cli/publish_command.rs
  • test/cli/install/bun-publish.test.ts

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

@robobun

robobun commented Aug 15, 2026

Copy link
Copy Markdown
Collaborator Author
Updated 6:06 PM PT - Aug 14th, 2026

@robobun, your commit a6d8c4a is building: #97014

@robobun

robobun commented Aug 15, 2026

Copy link
Copy Markdown
Collaborator Author

Status: closed as a duplicate of #38776, which was opened a few minutes earlier with the same one-line fix and landed first. Suggestions from this branch (scoped-registry and tarball test cases, and the lifecycle test timeout that keeps the rest of bun-publish.test.ts alive on debug builds) are noted on #38776.

@robobun

robobun commented Aug 15, 2026

Copy link
Copy Markdown
Collaborator Author

Duplicate of #38776 (same fix, opened first). Closing this one; the extra test cases from this branch are suggested over there.

@robobun robobun closed this Aug 15, 2026

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

LGTM — one-line widening of the pre-flight auth check to accept scope.auth, which construct_publish_headers already sends as Authorization: Basic.

What was reviewed:

  • Verified construct_publish_headers and check_package_version_exists in the same file already branch on !registry.auth.is_empty(), so the check was the only gap.
  • Tests cover the variant matrix (.npmrc username+_password, _auth, bunfig scoped, tarball, and the no-credentials negative), assert the exact Authorization header, and isolate HOME/USERPROFILE so a runner's ~/.npmrc can't satisfy the test.
  • The 30s timeout on the two lifecycle-script tests is justified by the comment (six child bun spawns on a debug build; a timeout there tears down the shared Verdaccio).
Extended reasoning...

Overview

The source change is a single added conjunct in the pre-flight authentication check in publish() (src/runtime/cli/publish_command.rs): it now also accepts a non-empty registry.auth (the base64 user:password Basic credential) alongside the existing registry.token and URL-embedded userinfo. construct_publish_headers and check_package_version_exists in the same file already send Authorization: Basic <auth> when token is empty and auth is not, so this check was the only piece rejecting Basic-auth configs. The test file gains a describe("basic auth") block with five test.concurrent cases against an in-process Bun.serve mock registry, plus a 30s timeout on two existing lifecycle-script tests.

Security risks

None introduced. The change loosens a pre-flight rejection to match what the header-construction code already does with the same credential — it does not add a new credential source, change how credentials are read from disk, or alter what is sent on the wire. The negative test ("no credentials is still rejected before anything is uploaded") confirms the check still fails closed when no credential is present.

Level of scrutiny

Low-to-medium. The Rust change is a one-line boolean widening whose correctness is verifiable by reading the two sibling functions in the same file that already consume registry.auth. It is a CLI pre-flight check, not a hot path or memory-owning code. The tests are the larger part of the diff and follow the repo's harness conventions (tempDir, using, bunEnv spread, port: 0, test.concurrent, stdout asserted before exit code, exact-value assertions on the recorded Authorization header).

Other factors

The tests isolate HOME/USERPROFILE/XDG_CONFIG_HOME so a real ~/.npmrc on the CI runner cannot provide a token that would make the positive tests pass without the fix — addressing the "prove the test fails for the right reason" concern. The 30s timeout bump on the two should run in order tests is commented with the reason (six child-bun spawns on a debug build; a timeout there kills the file-shared Verdaccio and cascades), which is the shape REVIEW.md asks for when a timeout is unavoidable rather than a workload that can be shrunk. No CODEOWNERS entries cover either changed file. No prior human review comments to address.

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.

Bun Publish doesn't support token based login (Azure Devops)

2 participants