Repository navigation
Conversation
Bun now reads certfile and keyfile options from .npmrc and uses them to configure client certificate authentication when connecting to npm registries over HTTPS. Previously these options were parsed but silently ignored with a warning. Now they are passed through to the HTTP client SSL configuration, enabling mutual TLS (mTLS) authentication with private registries. Supported per-registry and per-scope, matching npm syntax: //registry.example.com/:certfile=/path/to/cert.pem //registry.example.com/:keyfile=/path/to/key.pem - Add certfile/keyfile fields to NpmRegistry and Scope structs - Wire SSLConfig creation through registry_tls_config() helper - Pass TLS config in all CLI commands that talk to npm registries (install, publish, view, audit, whoami) - Add certfile/keyfile to the loadNpmrc test API for JS-level testing - Add Rust unit tests for registry_tls_config - Update npmrc documentation with new supported options
… reciprocal keyfile-only test
…ly and keep it across retries The TLS client identity from .npmrc is stripped on a cross-origin redirect only under the install credential policy. fetch() keeps its tls option across redirects, as before. The HTTP-thread clone owns its own reference to tls_props. When the clone is torn down, the original's bits are put back, so the copy into the task's own request in NetworkTask::notify keeps the client certificate for a retry.
Collaborator
Author
|
Updated 12:14 AM PT - Nov 9th, 2026
⏳ @robobun, your commit 184ea45 is still building in
|
Collaborator
Author
|
Closing: #31000 covers this work and its author is active on it. The two changes this branch made on top (an install-only redirect predicate in src/http/lib.rs so fetch() keeps its tls option across redirects, and a single-site tls_props restore in the AsyncHTTP teardown) are in commit 8491338 on robobun/a4c80bea/npmrc-certfile-keyfile for reference. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #48322
Problem
bun installignores the.npmrcoptionscertfileandkeyfile.src/ini/lib.rs:1577warnscertfile is not supported; ignoring this .npmrc optionand drops them. Against a registry that requires a client certificate the install fails witherror: TLSHandshakeFailed downloading package manifest(orConnectionClosed).Fix
Scopegetscertfileandkeyfile.PackageManager::registry_tls_configbuilds an internedSSLConfig(client cert and key plus the existingcaandcafile) and every registry request passes it: manifest, tarball, publish, audit, view, diff, whoami. Relative paths resolve against the.npmrcdirectory.credentials_of_keyfollows npm'shasAuth: a complete pair stops the key walk, a lone file does not, and the pair combines with_authToken,_author Basic.RedirectCredentialsPolicy::HttpsUpgrade).fetch({ tls })keeps its identity across redirects, as undici does, so fetch() behaviour is unchanged.AsyncHTTP::on_async_http_callback_raw, the HTTP-thread clone releases its owntls_propsreference and then puts the original's bits back.NetworkTask::notifycopies the clone over the task's own request, so without this a retry ran without the client certificate (TLSHandshakeFailed) and oneArcreference leaked per request.test/cli/install/npmrc.test.ts("npmrc client TLS identity", 17 tests, one new for retries; the unfixed build fails the retry test). Alsobun-install.test.ts(redirects),bun-install-retry.test.ts,bun-audit.test.ts,bun-install-registry.test.ts(CA),fetch.tls.test.ts.Background
.npmrccredential line//host/path/:key=valueis aConfigItem.credentials_of_keycollapses the items of one URL key into anNpmRegistry, in the order of npm'shasAuth.tls_propson an HTTP client is anArc<SSLConfig>from a global intern table. The HTTP thread keys its per-configSSL_CTXcache by that pointer, so requests with the same cert and key share one context.AsyncHTTP. Fields that existed at copy time are shared and must not be dropped by the copy. The copy ownstls_propsbecause a redirect can replace it, so it is the one field that is released and then restored.Downsides
SSLConfigand one intern lookup per request (manifest or tarball). Requests withoutcertfiletake twois_emptychecks and passNone. No allocation, no syscall.tarball_credentialslets a project name that origin in.npmrcto opt in.booltoInternalStateFlagsand twoBox<[u8]>perScope.Notes
src/http/lib.rsis!hop.same_origin && !hop.https_upgrade && redirect_credentials == HttpsUpgrade && tls_props.is_some(). It mirrorsstrip_credentialsfor the headers one block above, restricted to the install policy.start_queued_taskgives the clone its own strong reference (ManuallyDropof the shared bits, thencloned()). The teardown drops that reference andptr::writes the original's bits back, the same wayheader_entriesandremaining_redirect_countare restored. The rawdeallocbelow never drops the field.retried manifest and tarball requests keep the client identityfails witherror: TLSHandshakeFailed downloading package manifest retried.fetch.tls.test.tshas one failure on main in this container (trusts a self-issued certificate without keyCertSign:CERT_SIGNATURE_FAILUREinstead ofUNABLE_TO_VERIFY_LEAF_SIGNATURE) with the released binary too. Unrelated to this change.docs/pm/npmrc.mdxgains the two options and a section on them.docs/runtime/networking/fetch.mdxis unchanged.