Skip to content
This repository was archived by the owner on May 14, 2026. It is now read-only.

feat(config,network,tarball,registry): per-registry TLS overrides#502

Merged
zkochan merged 3 commits into
mainfrom
feat/per-registry-tls
May 13, 2026
Merged

feat(config,network,tarball,registry): per-registry TLS overrides#502
zkochan merged 3 commits into
mainfrom
feat/per-registry-tls

Conversation

@zkochan

@zkochan zkochan commented May 13, 2026

Copy link
Copy Markdown
Member

Closes #497.

Summary

Adds per-registry TLS overrides keyed by nerf-darted .npmrc URI, the natural follow-up to #490's top-level TLS keys. Corporate environments running a private Verdaccio (or any registry with its own self-signed cert) can now pin scoped :cafile=… / :cert=… / :key=… per host without disabling strict-ssl globally.

Three commits, layered:

  • feat(network) (eff1248): adds RegistryTls + PerRegistryTls types in pacquet-network plus the lookup machinery — pick_for_url ports pnpm's 5-step pickSettingByUrl exactly (exact > nerf-dart > no-port > shorter prefix > recursive no-port retry). ThrottledClient::for_installs gains a third &PerRegistryTls parameter and pre-builds one reqwest Client per non-empty override. New acquire_for_url(url: &str) routes per-request; acquire() keeps the default-client behavior for callers without a URL.

  • feat(config) (4e69868): NpmrcAuth parses the six per-registry TLS suffixes (:ca, :cafile, :cert, :certfile, :key, :keyfile) matching pnpm's SSL_SUFFIX_RE and applies onto Config.tls_by_uri. *file variants read from disk at parse time (silent on error); inline values get \\n\n expansion. :cert and :certfile share the same tls.cert slot — last-write-wins inside one .npmrc.

  • refactor(tarball,registry) (5f9cae9): three production call sites (registry metadata + version-tag fetches, plus two tarball download paths) move from acquire() to acquire_for_url(url) so the per-registry routing actually fires.

Parity policy

Bug-for-bug with pnpm v11 (SHA 94240bc046):

  • Field-by-field override, not replace-all. Each scoped ca / cert / key overrides its top-level counterpart independently (mirroring upstream's { ...opts, ...sslConfig } spread at dispatcher.ts:143,264). strict_ssl and local_address stay top-level-only — pnpm's regex doesn't recognize scoped versions.
  • ca as Option<String>, not Vec<String>: per-registry ca is a single string (possibly with concatenated -----END CERTIFICATE----- delimiters) — reqwest::Certificate::from_pem accepts both shapes.
  • Inline \\n expansion only on per-registry: pnpm applies value.replace(/\\n/g, '\n') to scoped values but not to top-level ca=. The divergence is intentional and matches upstream.
  • Lax URI prefix check: foo:cert=… (no // prefix) is accepted into the map with uri_prefix = "foo". It never matches a real nerf-darted URL so the entry is dropped at lookup time, but storing it keeps byte-for-byte parsing parity with tryParseSslKey.

Reviewer flags

  • Per-registry clients duplicate connection pools. Each unique override gets its own reqwest::Client and therefore its own connection pool. With N per-registry overrides the worker holds N+1 pools instead of one. The semaphore still bounds concurrent in-flight requests globally, but socket churn between registries with different TLS configs is now per-client. In practice most users have ≤2 overrides; if this becomes an issue we'd need to switch to rustls + custom certificate verifier (tracked under feat(network): support PKCS#1 client keys (currently PKCS#8 only) #499).
  • acquire_for_url takes &str rather than &Url so the existing format!("{registry}{name}") call sites don't need to round-trip through Url::parse. The lookup itself works on the raw string form via nerf_dart.

Test plan

  • cargo nextest run -p pacquet-network — 64 tests pass (added 11 per-registry routing tests in tls/tests.rs + 4 end-to-end routing tests in tests.rs)
  • cargo nextest run -p pacquet-config — 146 tests pass (added 8 per-registry parse tests)
  • cargo nextest run --workspace — 1155 tests pass
  • just ready clean
  • taplo format --check clean
  • RUSTDOCFLAGS=-D warnings cargo doc --no-deps --workspace --document-private-items clean
  • just dylint clean

Out of scope

References


Written by an agent (Claude Code, claude-opus-4-7).

Summary by CodeRabbit

  • New Features
    • Added support for per-registry TLS configuration in .npmrc files, allowing users to specify custom CA certificates, client certificates, and keys for individual registries.
    • HTTP client selection now respects per-registry TLS overrides alongside global TLS settings, with compatibility for pnpm's configuration fallback chain.

Review Change Stack

zkochan added 3 commits May 13, 2026 23:57
Adds `PerRegistryTls` + `RegistryTls` types in `pacquet-network` next
to the existing `TlsConfig` / `ProxyConfig`, plus the lookup machinery
needed to dispatch HTTP requests to a per-registry reqwest `Client`
that carries a different TLS configuration than the default.

The shape mirrors pnpm v11 (SHA 94240bc046):

- `PerRegistryTls` is a `HashMap<NerfDartUri, RegistryTls>` with the
  same key shape pnpm writes in
  `configByUri[<uri>].tls` ([`getNetworkConfigs.ts:34-40`](https://github.com/pnpm/pnpm/blob/94240bc046/config/reader/src/getNetworkConfigs.ts#L34-L40)).
- `RegistryTls` carries `(ca: Option<String>, cert: Option<String>,
  key: Option<String>)` — three independently-overridable fields,
  not a single replace-all blob. Pnpm uses object spread
  (`{ ...opts, ...sslConfig }` at [`dispatcher.ts:143,264`](https://github.com/pnpm/pnpm/blob/94240bc046/network/fetch/src/dispatcher.ts#L143))
  to layer per-registry over top-level field-by-field; pacquet's
  `merge_tls` helper does the same.
- `PerRegistryTls::pick_for_url` ports pnpm's
  [`pickSettingByUrl`](https://github.com/pnpm/pnpm/blob/94240bc046/network/fetch/src/dispatcher.ts#L338-L375)
  exactly: exact URL > nerf-darted > host-without-port > progressively
  shorter nerf-dart path prefixes > recursive retry without port.
  The 5-step fallback is the contract for how a multi-registry .npmrc
  resolves to a TLS config at request time.

`ThrottledClient::for_installs` gains a third parameter and pre-builds
one reqwest `Client` per non-empty per-registry override (each carrying
its own merged TLS state on top of the top-level proxy + TLS config).
The new `acquire_for_url(url: &str)` routes per-request via
`pick_for_url`, falling back to the default client when no override
matches. The semaphore is shared across all clients so the global
concurrency cap stays intact regardless of which registry a request
targets.

`pick_for_url` takes `&str` rather than `&Url` so the existing
`format!("{registry}{name}")` call sites in `tarball` / `registry`
don't need to round-trip through `Url::parse` just for routing.

Tests cover: empty-default short-circuit, exact-match precedence,
nerf-dart fallback, shorter-prefix walk, port-strip retry, miss on
host mismatch, miss on path-prefix mismatch, `strip_port` shapes
(plain, with userinfo, IPv6 literal), `for_installs` builds with
per-registry overrides, invalid per-registry CA surfaces as
`InvalidCa { index: 0 }`, and end-to-end `acquire_for_url` returns
distinct clients for scoped vs default URLs.

The cli temporarily passes `&PerRegistryTls::default()` so the
workspace still compiles in isolation; the next commit wires
`Config.tls_by_uri` through so the override actually flows from
`.npmrc`.
Extends `NpmrcAuth` to capture the six per-registry TLS suffixes pnpm
recognizes in `.npmrc` (`//host[:port]/path/:ca`, `:cafile`, `:cert`,
`:certfile`, `:key`, `:keyfile`) into a `tls_by_uri:
HashMap<String, RegistryTls>`, then applies the resolved map onto a
new `Config.tls_by_uri: PerRegistryTls` field. The cli's
`State::init` now passes `&config.tls_by_uri` to
`ThrottledClient::for_installs` (replacing the
`&PerRegistryTls::default()` placeholder from the preceding commit),
so per-registry overrides actually flow from `.npmrc` to the install
client.

Parity policy follows the upstream brief (pnpm v11, SHA 94240bc046):

- Suffix matching mirrors `SSL_SUFFIX_RE = /:(?<id>cert|key|ca)(?<kind>file)?$/`
  from [`getNetworkConfigs.ts:94`](https://github.com/pnpm/pnpm/blob/94240bc046/config/reader/src/getNetworkConfigs.ts#L94).
  Order matters: `:certfile` matches before `:cert` so the `*file`
  variants don't get parsed as the inline form with a trailing
  `file` artifact in the URI prefix.
- The `*file` variants are read from disk at parse time (matching
  pnpm's [`fs.readFileSync` at `getNetworkConfigs.ts:38`](https://github.com/pnpm/pnpm/blob/94240bc046/config/reader/src/getNetworkConfigs.ts#L38)).
  An unreadable `*file` is silently dropped — the entry is simply
  not written, and `PerRegistryTls::from_map` later filters
  all-`None` entries so the lookup never returns a hit that would
  suppress the top-level fallback.
- Inline values go through `\\n` → `\n` expansion (matching pnpm's
  `value.replace(/\\n/g, '\n')` at the same call site). Top-level
  `ca=` does **not** get this treatment; the divergence is
  intentional and matches upstream.
- `:cert` and `:certfile` write to the same `tls.cert` slot —
  last-write-wins inside one `.npmrc`. Same for `:key`/`:keyfile`
  and `:ca`/`:cafile`.
- The split is deliberately lax about the `//` prefix: pnpm's regex
  doesn't enforce it either, so `foo:cert=…` keys land in the map
  with `uri_prefix = "foo"`. They never match a real nerf-darted
  URL so the entry is dropped at lookup time, but storing it keeps
  byte-for-byte parsing parity.

Tests cover each suffix arm, `\\n` expansion on inline-only,
`*file` reading and silent-drop, the last-wins slot semantics
between `:cert` and `:certfile`, and that top-level `ca=` doesn't
collide with the per-registry parser (test:
`scoped_tls_keys_dont_collide_with_top_level`).

Touches `crates/package-manager/src/install_package_from_registry/tests.rs`
for the new `Config.tls_by_uri` field (`Default::default()`).
Replaces three production `ThrottledClient::acquire()` call sites with
`acquire_for_url(url)` so per-registry TLS overrides (added in the two
preceding commits) actually route requests through the per-registry
reqwest `Client` when one matches.

- `crates/registry/src/package.rs` (metadata fetch — has `url` from
  `format!("{registry}{name}")`).
- `crates/registry/src/package_version.rs` (tag-pinned metadata
  fetch — same `url` shape).
- `crates/tarball/src/lib.rs` (two sites: regular tarball download
  and the runtime-artifact fetch path). Both have `package_url:
  &str` in scope, threaded down from the install graph; tarball
  hosts that differ from the metadata host still pick up the right
  per-registry client because the 5-step `pickSettingByUrl` lookup
  matches on the tarball URL just like it does on the metadata URL.

When no per-registry overrides exist (the common case), the routing
table is empty and `acquire_for_url` short-circuits to the default
client — same observable behavior as the old `acquire()`. The
semaphore is unchanged so the global concurrency cap stays intact.

Test sites that don't care about per-URL routing
(`crates/network/src/tests.rs`, `crates/tarball/src/tests.rs`) keep
using `acquire()` — the API stays available as the implicit default
for callers without a URL.
Copilot AI review requested due to automatic review settings May 13, 2026 21:58
@coderabbitai

coderabbitai Bot commented May 13, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

Per-registry TLS overrides enable registry-scoped CA certificate, client cert, and client key configuration via .npmrc. The implementation adds per-registry TLS types with nerf-darted URL routing, parses per-registry suffixes from .npmrc, builds per-registry HTTP clients in ThrottledClient, and routes requests using URL-aware client selection.

Changes

Per-Registry TLS Overrides

Layer / File(s) Summary
Per-registry TLS types and URL routing
crates/network/src/tls.rs, crates/network/src/tls/tests.rs
Introduces PerRegistryTls and RegistryTls public types for modeling per-registry TLS overrides keyed by nerf-darted URI prefixes, implements pnpm v11's 5-step fallback lookup chain via pick_for_url, includes strip_port helper for port-aware URL matching, and comprehensive tests covering routing logic and edge cases.
.npmrc per-registry TLS parsing and Config wiring
crates/config/src/npmrc_auth.rs, crates/config/src/npmrc_auth/tests.rs, crates/config/src/lib.rs
Extends .npmrc parsing to recognize per-registry TLS suffixes (:ca, :cafile, :cert, :certfile, :key, :keyfile), expands inline \n escapes for non-file variants, reads file variants from disk, stores parsed overrides in NpmrcAuth::tls_by_uri, and applies them to Config::tls_by_uri via PerRegistryTls::from_map.
ThrottledClient per-registry client routing
crates/network/src/lib.rs, crates/network/src/tests.rs
Extends ThrottledClient with per-registry client storage and nerf-darted routing state, updates for_installs to build per-registry clients via TLS merge logic, adds acquire_for_url method for URL-aware semaphore acquisition and client selection, implements merge_tls to compute effective per-registry TLS configuration, and adds comprehensive tests for per-registry client construction and URL routing.
Request-time per-registry client selection
crates/cli/src/state.rs, crates/registry/src/package.rs, crates/registry/src/package_version.rs, crates/tarball/src/lib.rs, crates/package-manager/src/install_package_from_registry/tests.rs
Wires per-registry client routing into actual HTTP request code paths: updates State::init to pass config.tls_by_uri to ThrottledClient::for_installs, modifies registry package fetch methods and tarball downloads to use acquire_for_url instead of generic acquire, and updates test helpers to initialize Config::tls_by_uri.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related issues

  • Implements the feature requested in pnpm/pacquet#497: per-registry TLS override support for .npmrc keys ending in :ca, :cafile, :cert, :certfile, :key, :keyfile with nerf-darted URI routing and pnpm v11 fallback precedence.

Possibly related PRs

  • pnpm/pacquet#490: Introduces top-level TLS keys (ca, cafile, cert, key) that this PR extends with per-registry overrides in the same config infrastructure.
  • pnpm/pacquet#476: Updates State::init and ThrottledClient::for_installs for proxy-based client construction that this PR extends with per-registry TLS routing.
  • pnpm/pacquet#337: Modifies registry request setup via auth_headers.for_url(&url) in the same request-building paths that this PR updates to use acquire_for_url.

Suggested reviewers

  • anonrig

Poem

🐰 Registry routes now flow with grace,
Each TLS cert finds its rightful place.
Nerf-darted keys in .npmrc stored,
Per-registry clients eagerly poured.
From parsing to request, the path runs true—
One client per host, just like pnpm do! 🔐

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat(config,network,tarball,registry): per-registry TLS overrides' directly summarizes the main feature added across these crates: per-registry TLS override support.
Description check ✅ Passed The PR description is comprehensive and covers Summary, Linked issue (#497), Upstream reference, and addresses all template checklist items with specific details on parity policy, reviewer flags, test plan results, and out-of-scope items.
Linked Issues check ✅ Passed The PR fully implements all technical requirements from #497: parses six scoped TLS suffixes with proper \n expansion and file reading, implements the 5-step pickSettingByUrl lookup faithfully, applies per-registry overrides as field-by-field changes, routes requests via acquire_for_url with per-client strategy, and includes comprehensive tests across all affected crates.
Out of Scope Changes check ✅ Passed All changes are directly aligned with #497 requirements: per-registry TLS parsing in config, lookup routing in network, and production call-site wiring in tarball/registry. The PR explicitly notes out-of-scope items (rustls backend, per-registry strict-ssl/local-address) and does not include them.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/per-registry-tls

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

Copilot AI 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.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@codecov

codecov Bot commented May 13, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 96.73203% with 5 lines in your changes missing coverage. Please review.
✅ Project coverage is 88.50%. Comparing base (55083a4) to head (5f9cae9).
⚠️ Report is 3 commits behind head on main.

Files with missing lines Patch % Lines
crates/network/src/tls.rs 96.77% 2 Missing ⚠️
crates/config/src/npmrc_auth.rs 96.00% 1 Missing ⚠️
crates/network/src/lib.rs 98.24% 1 Missing ⚠️
crates/tarball/src/lib.rs 50.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #502      +/-   ##
==========================================
+ Coverage   88.40%   88.50%   +0.09%     
==========================================
  Files         121      122       +1     
  Lines       12966    13102     +136     
==========================================
+ Hits        11463    11596     +133     
- Misses       1503     1506       +3     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@zkochan zkochan requested a review from Copilot May 13, 2026 22:04

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
crates/config/src/npmrc_auth.rs (1)

33-35: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Remove outdated “per-registry TLS unparsed” note.

This comment is no longer true after the new scoped TLS parsing landed, so it should be updated to prevent incorrect maintenance assumptions.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/config/src/npmrc_auth.rs` around lines 33 - 35, Update the doc-comment
in the npmrc parsing module to remove the outdated sentence claiming
"per-registry TLS ... remain unparsed" — locate the comment block that currently
reads "Other `.npmrc` knobs (scoped `@scope:registry`, per-registry TLS like
`//host:cafile=`, etc.) remain unparsed for now." (in crates::config::npmrc_auth
module) and either delete that clause or replace it with a short accurate note
stating that scoped per-registry TLS settings are now parsed; keep the
surrounding context about remaining unparsed knobs if any other knobs still
apply.
crates/config/src/lib.rs (1)

633-639: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Update stale .npmrc behavior docs in Config::current.

This section still says per-registry TLS overrides are ignored, but this PR now parses and applies them. Please update/remove this note to avoid future confusion.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/config/src/lib.rs` around lines 633 - 639, The comment in the docs for
Config::current incorrectly says per-registry TLS overrides in `.npmrc` are
ignored; update the documentation inside the Config::current docstring to remove
or revise that sentence so it reflects the new behavior (per-registry TLS
overrides like `//host:cafile=`, `//host:ca=`, `//host:cert=`, `//host:key=` are
now parsed and applied). Keep the rest of the note about project-structural
settings coming from `pnpm-workspace.yaml` or CLI flags, but delete or reword
the clause claiming TLS overrides are silently ignored to prevent future
confusion.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@crates/config/src/lib.rs`:
- Around line 633-639: The comment in the docs for Config::current incorrectly
says per-registry TLS overrides in `.npmrc` are ignored; update the
documentation inside the Config::current docstring to remove or revise that
sentence so it reflects the new behavior (per-registry TLS overrides like
`//host:cafile=`, `//host:ca=`, `//host:cert=`, `//host:key=` are now parsed and
applied). Keep the rest of the note about project-structural settings coming
from `pnpm-workspace.yaml` or CLI flags, but delete or reword the clause
claiming TLS overrides are silently ignored to prevent future confusion.

In `@crates/config/src/npmrc_auth.rs`:
- Around line 33-35: Update the doc-comment in the npmrc parsing module to
remove the outdated sentence claiming "per-registry TLS ... remain unparsed" —
locate the comment block that currently reads "Other `.npmrc` knobs (scoped
`@scope:registry`, per-registry TLS like `//host:cafile=`, etc.) remain unparsed
for now." (in crates::config::npmrc_auth module) and either delete that clause
or replace it with a short accurate note stating that scoped per-registry TLS
settings are now parsed; keep the surrounding context about remaining unparsed
knobs if any other knobs still apply.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: ee98d90d-5e11-4521-a878-336c40bee3b4

📥 Commits

Reviewing files that changed from the base of the PR and between 7fd7ab3 and 5f9cae9.

📒 Files selected for processing (12)
  • crates/cli/src/state.rs
  • crates/config/src/lib.rs
  • crates/config/src/npmrc_auth.rs
  • crates/config/src/npmrc_auth/tests.rs
  • crates/network/src/lib.rs
  • crates/network/src/tests.rs
  • crates/network/src/tls.rs
  • crates/network/src/tls/tests.rs
  • crates/package-manager/src/install_package_from_registry/tests.rs
  • crates/registry/src/package.rs
  • crates/registry/src/package_version.rs
  • crates/tarball/src/lib.rs
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
  • GitHub Check: copilot-pull-request-reviewer
  • GitHub Check: Lint and Test (ubuntu-latest)
  • GitHub Check: Lint and Test (windows-latest)
  • GitHub Check: Run benchmark on ubuntu-latest
  • GitHub Check: Code Coverage
  • GitHub Check: Run benchmark on ubuntu-latest
🧰 Additional context used
📓 Path-based instructions (1)
**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

**/*.rs: Preserve existing method chains and pipe-trait chains; do not break them into intermediate let bindings unless there is a concrete justification such as a compilation failure, borrow checker rejection, meaningful performance improvement, or other technical necessity. Refactoring for style alone is not sufficient justification.
Choose owned vs. borrowed parameters to minimize copies; prefer borrowed types (&Path over &PathBuf, &str over &String) when it does not force extra copies.
Prefer Arc::clone(&x) and Rc::clone(&x) over x.clone() for reference-counted types to make the cost visible at the call site.
Do not use star imports inside module bodies. Write use super::{Foo, bar} instead of use super::*; for any glob whose target is a module you control. External-crate preludes (e.g., use rayon::prelude::*;) and root-of-module re-exports (e.g., pub use submodule::*; in lib.rs) are exceptions.
Follow Rust API Guidelines for naming, as documented in https://rust-lang.github.io/api-guidelines/naming.html.
Declare a newtype wrapper for any branded string type being ported from TypeScript pnpm. Do not collapse the brand into a plain String or &str; give the type its own struct so misuse is a type error.
When porting branded string types where upstream TypeScript always validates before construction, validate in the Rust port too. Construct the wrapper only via TryFrom<String> and/or FromStr; do not provide an infallible public constructor that takes an arbitrary string.
For branded string types where upstream TypeScript never validates (used purely for type-safety to prevent confusion between string slots), expose an infallible From<String> and From<&str> constructor in the Rust wrapper.
When upstream TypeScript occasionally constructs a branded type without validation (via bare as assertion), add a from_str_unchecked (or similarly named) constructor on the Rust side. Keep the validating constructor as well; `from_str_u...

Files:

  • crates/registry/src/package_version.rs
  • crates/config/src/lib.rs
  • crates/package-manager/src/install_package_from_registry/tests.rs
  • crates/registry/src/package.rs
  • crates/cli/src/state.rs
  • crates/config/src/npmrc_auth/tests.rs
  • crates/tarball/src/lib.rs
  • crates/network/src/tls/tests.rs
  • crates/config/src/npmrc_auth.rs
  • crates/network/src/lib.rs
  • crates/network/src/tls.rs
  • crates/network/src/tests.rs
🧠 Learnings (5)
📚 Learning: 2026-05-07T23:19:08.272Z
Learnt from: KSXGitHub
Repo: pnpm/pacquet PR: 401
File: tasks/integrated-benchmark/src/work_env.rs:343-344
Timestamp: 2026-05-07T23:19:08.272Z
Learning: When reviewing Rust code in pnpm/pacquet for deprecated API usage, do not automatically treat `serde_saphyr::to_string` as deprecated. In `serde-saphyr` v0.0.25, `serde_saphyr::to_string` has no `#[deprecated]` attribute (the `#[deprecated]` later in `serde-saphyr-0.0.25/src/lib.rs` applies to a different function). Only flag `serde_saphyr::to_string` as deprecated if the resolved dependency version’s source shows `#[deprecated]` on that specific function.

Applied to files:

  • crates/registry/src/package_version.rs
  • crates/config/src/lib.rs
  • crates/package-manager/src/install_package_from_registry/tests.rs
  • crates/registry/src/package.rs
  • crates/cli/src/state.rs
  • crates/config/src/npmrc_auth/tests.rs
  • crates/tarball/src/lib.rs
  • crates/network/src/tls/tests.rs
  • crates/config/src/npmrc_auth.rs
  • crates/network/src/lib.rs
  • crates/network/src/tls.rs
  • crates/network/src/tests.rs
📚 Learning: 2026-05-01T10:01:33.766Z
Learnt from: zkochan
Repo: pnpm/pacquet PR: 349
File: crates/reporter/src/tests.rs:121-121
Timestamp: 2026-05-01T10:01:33.766Z
Learning: In Rust test code, follow the repo’s CODE_STYLE_GUIDE test-logging rule: add logging (e.g., `eprintln!`/`eprintln!(...)`) so that useful diagnostic values are printed when a test fails, unless the assertion is `assert_eq!` (where the differing values are already included). Concretely, if you use assertions like `assert!`, `assert_ne!`, etc., ensure the test logs the relevant actual/expected values (or context) before/around the assertion so failures can be diagnosed without rerunning.

Applied to files:

  • crates/package-manager/src/install_package_from_registry/tests.rs
  • crates/config/src/npmrc_auth/tests.rs
  • crates/network/src/tls/tests.rs
  • crates/network/src/tests.rs
📚 Learning: 2026-05-13T19:22:48.951Z
Learnt from: zkochan
Repo: pnpm/pacquet PR: 478
File: crates/package-manager/src/hoisted_dep_graph.rs:51-55
Timestamp: 2026-05-13T19:22:48.951Z
Learning: When reviewing this Rust codebase, avoid introducing/using a newtype like `PkgIdWithPatchHash` in only one module (e.g., `hoisted_dep_graph.rs`) if other related pacquet modules still represent the upstream pnpm “pkg id with patch hash” as a plain `String` (e.g., `virtual_store_layout`). For type consistency, either keep `pkg_id_with_patch_hash` as `String` here, or require a workspace-wide sweep that defines/extracts the `PkgIdWithPatchHash` newtype once and updates all call sites together (otherwise defer the refactor to a coordinated follow-up PR).

Applied to files:

  • crates/package-manager/src/install_package_from_registry/tests.rs
📚 Learning: 2026-05-13T20:09:22.171Z
Learnt from: zkochan
Repo: pnpm/pacquet PR: 486
File: crates/package-manager/src/hoisted_dep_graph.rs:472-476
Timestamp: 2026-05-13T20:09:22.171Z
Learning: In pnpm/pacquet, when generating serialized `hoisted_locations` strings (used for `.modules.yaml`), normalize path separators to forward slashes (e.g., replace `\\` with `/`). This preserves cross-platform portability: the output must not use OS-native separators because upstream pnpm’s `path.relative` can return platform-specific separators, which would break consistency with pnpm/pacquet’s other serialized formats on Windows.

Applied to files:

  • crates/package-manager/src/install_package_from_registry/tests.rs
📚 Learning: 2026-05-01T10:01:33.766Z
Learnt from: zkochan
Repo: pnpm/pacquet PR: 349
File: crates/reporter/src/tests.rs:121-121
Timestamp: 2026-05-01T10:01:33.766Z
Learning: In this repo’s Rust tests (run via `cargo nextest`), stdout/stderr from passing tests is captured and is only shown when a test fails. As a result, `eprintln!` (and similar stderr logging) in these tests should generally not be flagged as CI “noise” on the happy path; CI output should only appear for failing tests.

Applied to files:

  • crates/network/src/tests.rs
🔇 Additional comments (25)
crates/network/src/tls.rs (6)

20-131: LGTM!


160-166: LGTM!


172-176: LGTM!


204-244: LGTM!


246-251: LGTM!


263-290: LGTM!

crates/network/src/tls/tests.rs (2)

7-21: LGTM!


62-166: LGTM!

crates/network/src/lib.rs (6)

7-16: LGTM!


49-63: LGTM!


164-246: LGTM!


253-261: LGTM!


338-349: LGTM!


282-291: LGTM!

crates/network/src/tests.rs (2)

157-414: LGTM!


418-515: LGTM!

crates/package-manager/src/install_package_from_registry/tests.rs (1)

17-61: LGTM!

crates/cli/src/state.rs (1)

65-70: LGTM!

crates/registry/src/package.rs (1)

30-61: LGTM!

crates/tarball/src/lib.rs (2)

1361-1396: LGTM!


1985-2011: LGTM!

crates/config/src/lib.rs (1)

289-298: LGTM!

crates/config/src/npmrc_auth/tests.rs (1)

676-789: LGTM!

crates/registry/src/package_version.rs (1)

40-43: LGTM!

crates/config/src/npmrc_auth.rs (1)

236-254: LGTM!

Also applies to: 294-299, 561-610

@github-actions

Copy link
Copy Markdown

Micro-Benchmark Results

Linux

group                          main                                   pr
-----                          ----                                   --
tarball/download_dependency    1.00     16.1±0.07ms   269.3 KB/sec    1.01     16.2±0.49ms   267.9 KB/sec

Copilot AI 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.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@github-actions

Copy link
Copy Markdown

Integrated-Benchmark Report (Linux)

Scenario: Frozen Lockfile

Command Mean [s] Min [s] Max [s] Relative
pacquet@HEAD 2.724 ± 0.193 2.521 3.228 1.03 ± 0.08
pacquet@main 2.639 ± 0.081 2.561 2.802 1.00
pnpm 6.354 ± 0.058 6.275 6.501 2.41 ± 0.08
BENCHMARK_REPORT.json
{
  "results": [
    {
      "command": "pacquet@HEAD",
      "mean": 2.72372125168,
      "stddev": 0.1934450775057152,
      "median": 2.68921932728,
      "user": 2.6561994199999996,
      "system": 3.7251190999999997,
      "min": 2.5211045422800002,
      "max": 3.22764497028,
      "times": [
        2.6892740182800003,
        2.81913868028,
        2.68916463628,
        3.22764497028,
        2.62737898628,
        2.5211045422800002,
        2.70604490428,
        2.60328779628,
        2.64656594328,
        2.70760803928
      ]
    },
    {
      "command": "pacquet@main",
      "mean": 2.6392875518800003,
      "stddev": 0.08123439502170784,
      "median": 2.6261268612800004,
      "user": 2.5917730199999998,
      "system": 3.7200777,
      "min": 2.56082056628,
      "max": 2.80207482828,
      "times": [
        2.80207482828,
        2.61569945528,
        2.75205276228,
        2.64045350828,
        2.66251749128,
        2.56082056628,
        2.56982950428,
        2.63655426728,
        2.56672283828,
        2.58615029728
      ]
    },
    {
      "command": "pnpm",
      "mean": 6.354169235079999,
      "stddev": 0.058258466583422326,
      "median": 6.3449898962799995,
      "user": 9.324323119999999,
      "system": 4.5807832,
      "min": 6.2745189542799995,
      "max": 6.50103526928,
      "times": [
        6.2745189542799995,
        6.35146134928,
        6.361154775279999,
        6.33030146428,
        6.346254119279999,
        6.32344997628,
        6.33379567228,
        6.37599509728,
        6.50103526928,
        6.34372567328
      ]
    }
  ]
}

Scenario: Frozen Lockfile (Hot Cache)

Command Mean [ms] Min [ms] Max [ms] Relative
pacquet@HEAD 746.3 ± 27.3 703.9 796.1 1.00
pacquet@main 808.0 ± 32.0 766.0 857.6 1.08 ± 0.06
pnpm 2660.5 ± 93.6 2549.8 2841.3 3.56 ± 0.18
BENCHMARK_REPORT.json
{
  "results": [
    {
      "command": "pacquet@HEAD",
      "mean": 0.74631892158,
      "stddev": 0.027291944734382644,
      "median": 0.74556090668,
      "user": 0.37919294,
      "system": 1.6122701200000003,
      "min": 0.7039093536800001,
      "max": 0.7960529146800001,
      "times": [
        0.7960529146800001,
        0.72209898068,
        0.73582453268,
        0.7039093536800001,
        0.7469717126800001,
        0.74415010068,
        0.72323423468,
        0.75726630468,
        0.75600722668,
        0.77767385468
      ]
    },
    {
      "command": "pacquet@main",
      "mean": 0.8080482158800001,
      "stddev": 0.03200593997589197,
      "median": 0.80251881368,
      "user": 0.40604834,
      "system": 1.6232694199999997,
      "min": 0.76603662168,
      "max": 0.85760172168,
      "times": [
        0.78830029368,
        0.8092201076800001,
        0.76603662168,
        0.80703612368,
        0.85760172168,
        0.8453065736800001,
        0.79800150368,
        0.76767876968,
        0.79646257268,
        0.84483787068
      ]
    },
    {
      "command": "pnpm",
      "mean": 2.6605204906799997,
      "stddev": 0.0936227975421545,
      "median": 2.62142731868,
      "user": 3.255981539999999,
      "system": 2.2513308200000006,
      "min": 2.54981912468,
      "max": 2.8412781686799997,
      "times": [
        2.8412781686799997,
        2.76324892768,
        2.65104284768,
        2.62780808068,
        2.6031888516799997,
        2.54981912468,
        2.6113859326799997,
        2.61504655668,
        2.5867863066799996,
        2.75560010968
      ]
    }
  ]
}

@zkochan zkochan merged commit 65f9e66 into main May 13, 2026
15 of 18 checks passed
@zkochan zkochan deleted the feat/per-registry-tls branch May 13, 2026 22:35
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(config,network): per-registry TLS overrides (//host:cafile, //host:ca, //host:cert, //host:key)

2 participants