feat(config): support an _auth setting for registry authentication#12559
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds trusted JSON auth support for registry credentials and scope routing, plus precedence updates, bootstrap propagation, and tests in pnpm11 and pacquet. ChangesJSON env auth feature
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Assessment against linked issues
Out-of-scope changes
Possibly related PRs
Suggested reviewers
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
PR Summary by Qodofeat(config): add structured Description
Diagram
High-Level Assessment
Files changed (12)
|
Code Review by Qodo
Context used 1. Warnings leak URL secrets
|
199923c to
67b5502
Compare
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
pacquet/crates/config/src/tests.rs (1)
449-472: ⚡ Quick winTrim test doc comments to contract-level intent and remove implementation-history prose.
These
///blocks mostly restate the test body and include historical context (for example “mirrors TS-side merge” / “regression for review-found bug”). In this file, concise test names already carry the scenario; keep comments only for non-obvious invariants.As per coding guidelines, “Tests are documentation. Do not duplicate test scenarios … in doc comments” and “Do not record past implementation shape/refactor history in source comments.”
Also applies to: 499-555
🤖 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 `@pacquet/crates/config/src/tests.rs` around lines 449 - 472, Trim the doc comment blocks (the `///` comments) for the test functions json_env_auth_token_is_used_and_outranks_project_npmrc and other tests in the noted range (around lines 499-555) to contain only the contract-level intent. Remove any prose that restates the test body implementation, historical context about past refactors or regressions, or implementation-specific details like "mirrors pnpm's TS-side merge". Keep comments only if they describe non-obvious invariants that aren't already clear from the test name and body.Source: Coding guidelines
🤖 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.
Inline comments:
In `@pacquet/crates/config/src/lib.rs`:
- Around line 1884-1903: The issue is that scoped_registries are extracted from
env_json_auth via std::mem::take before env_json_source is created, leaving
env_json_source with empty scoped_registries. This causes
PackageManagerBootstrap to be built without the JSON env scoped registries. To
fix this, reorder the code so that env_json_source is created from the complete
env_json_auth (with scoped_registries still intact) before std::mem::take is
called to extract the registries into env_json_registries. This ensures
trusted_sources receives the full env_json_source with all registry information
for proper bootstrap construction.
In `@pacquet/crates/config/src/tests.rs`:
- Around line 549-572: The test
`json_env_warnings_survive_when_no_creds_present` documents that it verifies
warning emission for malformed JSON, but only asserts the absence of credentials
and registries. Add an assertion to verify that a tracing warn event is actually
emitted when the malformed `pnpm_config_auth` environment variable with an
invalid `registries` field is processed during the `load_with_fake_env` call.
This will ensure the test properly validates the warning path and prevent
regressions where warnings could be silently dropped.
---
Nitpick comments:
In `@pacquet/crates/config/src/tests.rs`:
- Around line 449-472: Trim the doc comment blocks (the `///` comments) for the
test functions json_env_auth_token_is_used_and_outranks_project_npmrc and other
tests in the noted range (around lines 499-555) to contain only the
contract-level intent. Remove any prose that restates the test body
implementation, historical context about past refactors or regressions, or
implementation-specific details like "mirrors pnpm's TS-side merge". Keep
comments only if they describe non-obvious invariants that aren't already clear
from the test name and body.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: 5723f6e9-5bc6-4b42-8b27-86ee4cccd576
📒 Files selected for processing (8)
.changeset/json-env-auth.mdpacquet/crates/config/src/lib.rspacquet/crates/config/src/npmrc_auth.rspacquet/crates/config/src/npmrc_auth/tests.rspacquet/crates/config/src/tests.rspnpm11/config/reader/src/index.tspnpm11/config/reader/src/loadNpmrcFiles.tspnpm11/config/reader/test/index.ts
|
Code review by qodo was updated up to the latest commit 67b5502 |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #12559 +/- ##
==========================================
+ Coverage 88.58% 88.74% +0.15%
==========================================
Files 339 342 +3
Lines 49171 50442 +1271
==========================================
+ Hits 43557 44763 +1206
- Misses 5614 5679 +65 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
Code review by qodo was updated up to the latest commit 67b5502 |
Integrated-Benchmark Report (Linux)Commit: Each scenario reports direct installs and pnpr installs. Bencher consumes pacquet@HEAD and pnpr@HEAD. Scenario: Isolated linker: fresh restore, cold cache + cold store
BENCHMARK_REPORT.json{
"results": [
{
"command": "pacquet@HEAD",
"mean": 4.537346464780001,
"stddev": 0.10144930975702958,
"median": 4.54011224908,
"user": 4.1105765,
"system": 2.1562740000000007,
"min": 4.39304046558,
"max": 4.6528624375800005,
"times": [
4.43271964958,
4.49969419158,
4.63783095758,
4.63357072358,
4.63038972858,
4.6528624375800005,
4.41693853858,
4.49588764858,
4.39304046558,
4.58053030658
]
},
{
"command": "pacquet@main",
"mean": 4.37711796748,
"stddev": 0.12813898112042194,
"median": 4.32565030658,
"user": 4.1013989,
"system": 2.1513273,
"min": 4.26305122558,
"max": 4.64265380258,
"times": [
4.31629294758,
4.37236635958,
4.26912552658,
4.26655808758,
4.26305122558,
4.53629735958,
4.64265380258,
4.45353375258,
4.33493681658,
4.31636379658
]
},
{
"command": "pnpr@HEAD",
"mean": 2.78057984868,
"stddev": 0.1403011410959097,
"median": 2.8140635655799997,
"user": 2.9652217,
"system": 1.8517778,
"min": 2.55310008958,
"max": 2.9933366025800003,
"times": [
2.55310008958,
2.92363187658,
2.62369272958,
2.67615034458,
2.87675167958,
2.9933366025800003,
2.80486774858,
2.68788567058,
2.84312236258,
2.82325938258
]
},
{
"command": "pnpr@main",
"mean": 2.68484094858,
"stddev": 0.11368150713576404,
"median": 2.65461673408,
"user": 3.0037651,
"system": 1.8446908,
"min": 2.56376748358,
"max": 2.88572451758,
"times": [
2.61581492158,
2.56398671858,
2.63381952658,
2.88572451758,
2.56376748358,
2.78390103958,
2.57284904258,
2.78175601058,
2.67541394158,
2.77137628358
]
}
]
}Scenario: Isolated linker: fresh restore, hot cache + hot store
BENCHMARK_REPORT.json{
"results": [
{
"command": "pacquet@HEAD",
"mean": 0.46717864016000005,
"stddev": 0.005389466998655165,
"median": 0.4679907078600001,
"user": 0.37421995999999996,
"system": 0.77918126,
"min": 0.45841776286,
"max": 0.47397616186,
"times": [
0.46914151886000005,
0.46652882886,
0.46683989686000005,
0.45864525886000007,
0.45841776286,
0.46429341886000003,
0.47157700186000007,
0.47031577486000004,
0.47205077786000005,
0.47397616186
]
},
{
"command": "pacquet@main",
"mean": 0.48262665286000006,
"stddev": 0.014141719941792516,
"median": 0.4817822138600001,
"user": 0.38343156,
"system": 0.78372766,
"min": 0.46668340086000004,
"max": 0.51381761386,
"times": [
0.51381761386,
0.47547922386,
0.49412525486000003,
0.48276678986000005,
0.48652067686000006,
0.48684507086000006,
0.48079763786000007,
0.46691172786000007,
0.47231913186,
0.46668340086000004
]
},
{
"command": "pnpr@HEAD",
"mean": 0.5507436175600001,
"stddev": 0.10415855091342356,
"median": 0.49637608686,
"user": 0.39117166000000003,
"system": 0.79283046,
"min": 0.48190139486000005,
"max": 0.7585019878600001,
"times": [
0.49136478986000004,
0.49410398586000004,
0.52613850386,
0.49205945986000005,
0.49864818786000004,
0.48190139486000005,
0.7585019878600001,
0.73157544886,
0.5411223218600001,
0.49202009486000003
]
},
{
"command": "pnpr@main",
"mean": 0.50431486226,
"stddev": 0.013591432365786964,
"median": 0.50312823586,
"user": 0.39078685999999996,
"system": 0.79480756,
"min": 0.48618494786000005,
"max": 0.53205694786,
"times": [
0.50500331186,
0.51199073486,
0.53205694786,
0.5030921808600001,
0.49848680986000005,
0.49087895886000005,
0.48618494786000005,
0.5179947838600001,
0.50316429086,
0.49429565586000007
]
}
]
}Scenario: Isolated linker: fresh install, cold cache + cold store
BENCHMARK_REPORT.json{
"results": [
{
"command": "pacquet@HEAD",
"mean": 4.572638960480001,
"stddev": 0.028222241784826702,
"median": 4.57866007028,
"user": 4.1407922,
"system": 2.10669308,
"min": 4.52537453828,
"max": 4.60526496428,
"times": [
4.60526496428,
4.53459193728,
4.60124746428,
4.55504946928,
4.52537453828,
4.5941465282800005,
4.59516379728,
4.58338302628,
4.57393711428,
4.55823076528
]
},
{
"command": "pacquet@main",
"mean": 4.60294087918,
"stddev": 0.03694440202885979,
"median": 4.60249315128,
"user": 4.1689612,
"system": 2.0991494799999995,
"min": 4.52829531128,
"max": 4.65067539128,
"times": [
4.60354409028,
4.52829531128,
4.60144221228,
4.62696766928,
4.56048143728,
4.63392198928,
4.59019219128,
4.65067539128,
4.60057037728,
4.63331812228
]
},
{
"command": "pnpr@HEAD",
"mean": 3.04138917098,
"stddev": 0.1559610096950626,
"median": 3.0488560207799997,
"user": 3.1196079,
"system": 1.95139088,
"min": 2.82171180828,
"max": 3.29146374328,
"times": [
3.02205933628,
3.22024178228,
2.86273351128,
2.89980997328,
2.96750369128,
3.16325179128,
3.29146374328,
3.07565270528,
3.08946336728,
2.82171180828
]
},
{
"command": "pnpr@main",
"mean": 3.11753402358,
"stddev": 0.08330417949297174,
"median": 3.1070207717800002,
"user": 3.152282,
"system": 1.99138408,
"min": 3.01191053228,
"max": 3.2617328632800002,
"times": [
3.03471200228,
3.06572733828,
3.2617328632800002,
3.01191053228,
3.21397234328,
3.15451637028,
3.14831420528,
3.05962761728,
3.0579057992800003,
3.16692116428
]
}
]
}Scenario: Isolated linker: fresh install, hot cache + hot store
BENCHMARK_REPORT.json{
"results": [
{
"command": "pacquet@HEAD",
"mean": 1.16216958934,
"stddev": 0.007294062230137246,
"median": 1.16176860674,
"user": 1.32895618,
"system": 0.99932316,
"min": 1.1539191597399998,
"max": 1.17442052474,
"times": [
1.15843292374,
1.15553790874,
1.15569664274,
1.16510428974,
1.1539191597399998,
1.17442052474,
1.16983710174,
1.16540460674,
1.1552499507399998,
1.16809278474
]
},
{
"command": "pacquet@main",
"mean": 1.1907129164399997,
"stddev": 0.029828340165716193,
"median": 1.1856789612399998,
"user": 1.3616857800000002,
"system": 1.0252956599999998,
"min": 1.1633904707399998,
"max": 1.27118523774,
"times": [
1.1916543207399999,
1.17091071974,
1.18342204774,
1.19248550374,
1.1633904707399998,
1.18793587474,
1.27118523774,
1.19032394174,
1.17828503074,
1.17753601674
]
},
{
"command": "pnpr@HEAD",
"mean": 1.2701999501399999,
"stddev": 0.03067899566143035,
"median": 1.26620158274,
"user": 0.5686285799999998,
"system": 0.94170026,
"min": 1.2352922977399998,
"max": 1.35223836174,
"times": [
1.26717658174,
1.2710945727399998,
1.2652265837399999,
1.26744397374,
1.26369123074,
1.25714019474,
1.2687657697399999,
1.35223836174,
1.25392993474,
1.2352922977399998
]
},
{
"command": "pnpr@main",
"mean": 1.2667068689399998,
"stddev": 0.029217496993396208,
"median": 1.25547943274,
"user": 0.58211578,
"system": 0.92733566,
"min": 1.24430904574,
"max": 1.34406848974,
"times": [
1.27285098474,
1.27219041874,
1.24430904574,
1.24910345474,
1.34406848974,
1.25337804874,
1.27253741974,
1.25026652474,
1.25758081674,
1.25078348574
]
}
]
}Scenario: Isolated linker: fresh install, cold cache + hot store
BENCHMARK_REPORT.json{
"results": [
{
"command": "pacquet@HEAD",
"mean": 2.8560379334799997,
"stddev": 0.0180669815772258,
"median": 2.8469383087799995,
"user": 1.81970992,
"system": 1.2155314,
"min": 2.83548129378,
"max": 2.88316795978,
"times": [
2.84711476578,
2.87452021678,
2.83548129378,
2.84331345478,
2.86102541178,
2.88316795978,
2.88309968078,
2.8467618517799997,
2.84518487178,
2.84070982778
]
},
{
"command": "pacquet@main",
"mean": 2.86350872008,
"stddev": 0.038312883767762214,
"median": 2.85711376428,
"user": 1.8403183200000002,
"system": 1.2138078,
"min": 2.79826782078,
"max": 2.94522790878,
"times": [
2.85153856878,
2.83265913878,
2.88727045978,
2.85649510878,
2.79826782078,
2.85773241978,
2.85135980578,
2.8752550117799998,
2.87928095778,
2.94522790878
]
},
{
"command": "pnpr@HEAD",
"mean": 1.24577843868,
"stddev": 0.02004338000189225,
"median": 1.24419524278,
"user": 0.5639707199999999,
"system": 0.9284816000000001,
"min": 1.22174664678,
"max": 1.29122857678,
"times": [
1.2520121107800002,
1.2500170887800002,
1.22174664678,
1.22716232178,
1.24492542078,
1.26061781278,
1.29122857678,
1.2372752477800002,
1.22933409578,
1.24346506478
]
},
{
"command": "pnpr@main",
"mean": 1.2747315779800001,
"stddev": 0.07518041745490753,
"median": 1.25352221028,
"user": 0.57423942,
"system": 0.9285940000000001,
"min": 1.2172435807800002,
"max": 1.4829446987800001,
"times": [
1.2779255707800001,
1.2544390847800002,
1.24650532078,
1.23946488778,
1.25260533578,
1.2557604017800001,
1.2172435807800002,
1.4829446987800001,
1.27566995078,
1.24475694778
]
}
]
} |
|
| Branch | pr/12559 |
| Testbed | pacquet |
Click to view all benchmark results
| Benchmark | Latency | Benchmark Result milliseconds (ms) (Result Δ%) | Upper Boundary milliseconds (ms) (Limit %) |
|---|---|---|---|
| isolated-linker.fresh-install.cold-cache.cold-store | 📈 view plot 🚷 view threshold | 4,572.64 ms(-4.77%)Baseline: 4,801.62 ms | 5,761.94 ms (79.36%) |
| isolated-linker.fresh-install.cold-cache.hot-store | 📈 view plot 🚷 view threshold | 2,856.04 ms(-6.29%)Baseline: 3,047.90 ms | 3,657.48 ms (78.09%) |
| isolated-linker.fresh-install.hot-cache.hot-store | 📈 view plot 🚷 view threshold | 1,162.17 ms(-14.55%)Baseline: 1,360.01 ms | 1,632.01 ms (71.21%) |
| isolated-linker.fresh-restore.cold-cache.cold-store | 📈 view plot 🚷 view threshold | 4,537.35 ms(-4.03%)Baseline: 4,728.02 ms | 5,673.62 ms (79.97%) |
| isolated-linker.fresh-restore.hot-cache.hot-store | 📈 view plot 🚷 view threshold | 467.18 ms(-26.94%)Baseline: 639.48 ms | 767.38 ms (60.88%) |
|
| Branch | pr/12559 |
| Testbed | pnpr |
⚠️ WARNING: No Threshold found!Without a Threshold, no Alerts will ever be generated.
Click here to create a new Threshold
For more information, see the Threshold documentation.
To only post results if a Threshold exists, set the--ci-only-thresholdsflag.
Click to view all benchmark results
| Benchmark | Latency | milliseconds (ms) |
|---|---|---|
| isolated-linker.fresh-install.cold-cache.cold-store | 📈 view plot | 3,041.39 ms |
| isolated-linker.fresh-install.cold-cache.hot-store | 📈 view plot | 1,245.78 ms |
| isolated-linker.fresh-install.hot-cache.hot-store | 📈 view plot | 1,270.20 ms |
| isolated-linker.fresh-restore.cold-cache.cold-store | 📈 view plot | 2,780.58 ms |
| isolated-linker.fresh-restore.hot-cache.hot-store | 📈 view plot | 550.74 ms |
CodeRabbit/Codecov flagged 8 uncovered lines in npmrc_auth.rs on PR pnpm#12559. Two targeted tests close the gap: - json_env_warns_when_a_registry_url_is_not_a_string: exercises the per-scope non-string value branch (lines 268-271) — e.g. `{"registries":{"@bad":123}}`. Confirms the warning fires and a neighboring valid scope still parses. - json_type_label_names_every_variant: direct unit test of the pure helper across all six serde_json::Value variants (covers lines 1051, 1052, 1053, 1056 — Null/Bool/Number/Object). from_json_env only reaches the helper on the non-Object error path, so the Null/Bool/ Number arms never got hit through integration tests; Object is structurally unreachable from current callers (they only call the helper after an Object check failed) but kept for exhaustive match. Also fixes a clippy unnecessary_get_then_check warning introduced by the first test (.get().is_none() -> !.contains_key()). Patch coverage for npmrc_auth.rs is now 100%; the remaining uncovered lines in the file are pre-existing code outside this PR's diff.
…eset Code review flagged two minor concerns on PR pnpm#12559: 1. **Asymmetric non-string handling**: `pnpm_config_auth.registries[scope]` pushed a warning when the value wasn't a string, but `pnpm_config_auth.auth[key]` silently dropped it. Same asymmetry on both sides (TS + Rust). A user typo'ing `{"auth":{"//host/:_authToken":123}}` got zero feedback. 2. **Changeset gap**: the release note didn't mention that `registries.default` updates the top-level default registry (not just `registries["default"]`). This is a real behavior extension — the existing URL-scoped env vars don't expose it — and users reading the release notes wouldn't know they can override the default registry via the JSON envelope. Fixes: - TS (`loadNpmrcFiles.ts`): push a per-key "value must be a string" warning in `readJsonAuthEnvAuth`, matching the registries-side behavior. Kept the tokenHelper and `//`-prefix filters above the type check so intentional drops stay silent. - Rust (`npmrc_auth.rs`): same warning in `from_json_env`'s auth walker. - Tests: renamed `json_env_ignores_non_string_auth_value` (Rust) to `json_env_warns_when_an_auth_value_is_not_a_string` and tightened assertions to check the warning. New TS test `a non-string value inside pnpm_config_auth.auth warns and is dropped`. - Changeset: one sentence noting that `registries.default` updates the top-level default registry, mirroring `pnpm-workspace.yaml`'s `registries.default`.
|
Code review by qodo was updated up to the latest commit 6953236 |
1 similar comment
|
Code review by qodo was updated up to the latest commit 6953236 |
…warn on inert :registry keys Two review-driven fixes on PR pnpm#12559: 1. **packageManagerRegistries gap**: `pnpm_config_auth.registries` was applied only to `pnpmConfig.registries` (used by normal installs), not to `pnpmConfig.packageManagerRegistries` (the separate map pnpm uses when bootstrapping itself — self-download / version switching). The bootstrap map is built from `trustedAuthConfig`, which doesn't carry the env JSON `registries` sub-field. Result: a JSON env registry routing influenced normal installs but silently missed the bootstrap path. Fix: after the main `pnpmConfig.registries` merge, fold env JSON registries into `packageManagerRegistries` too (URL-normalized). `cliScopedRegistries` re-applied last to preserve the same "CLI > env" precedence. Test: `pnpm_config_auth.registries flows into packageManagerRegistries (bootstrap path)`. 2. **Inert `//host/:registry` keys**: my filter admitted any `//`-prefixed key in `auth`, so `//host/:registry` passed through into `authConfig` and sat there — `getNetworkConfigs` only processes `@scope:registry` keys, not URL-scoped `:registry`. Now warns and redirects the user to the `registries` sub-field with a real scope. Applied on both sides for parity. Tests: TS `a URL-scoped :registry key inside pnpm_config_auth.auth warns and is dropped` + Rust equivalent. Also reverted the earlier defensive switch of `cliScopedRegistries` iteration from raw `cliOptions` to `explicitlySetKeys`. `explicitlySetKeys` is built from `configFromCliOpts` which camelcases keys — `@org-a:registry` becomes `@orgA:registry` and the scoped-registry pattern no longer matches. The existing test `CLI --@scope:registry overrides pnpm_config_auth` caught this immediately. Raw `cliOptions` iteration is correct (and matches how `cliOptions` is used elsewhere in `index.ts`); a comment now documents why `explicitlySetKeys` isn't suitable here.
|
Code review by qodo was updated up to the latest commit de06ec0 |
1 similar comment
|
Code review by qodo was updated up to the latest commit de06ec0 |
Both failures on PR pnpm#12559 are environmental: - Rust CI / Test / macos: install step failed fetching ts-toolbelt from npmjs.org (network/registry flake before any test ran). - TS CI / Test / windows / Node 22: EBUSY file-lock during cleanup of a dlx e2e test in node_modules. Known intermittent on Windows. Same test suites passed on ubuntu (Rust + TS) and Rust/windows, so this is not a code regression. Pushing an empty commit to trigger fresh runs.
|
Code review by qodo was updated up to the latest commit 16b2bfa |
Adds two tests for branches that llvm-cov flagged as untested in PR pnpm#12559: - json_env_warns_when_host_key_has_non_http_scheme: a pnpm_config_auth key with a non-http(s) scheme (ftp://) hits the scheme-check rejection in is_valid_json_auth_registry_url, distinct from the missing-separator path already covered. - env_registry_override_appends_missing_trailing_slash: a PNPM_CONFIG_REGISTRY value without a trailing slash exercises the format! normalization arm in Config::load, asserting config.registry, config.registries["default"], and package_manager_bootstrap.registries["default"] all receive the normalized form.
16b2bfa to
976f449
Compare
|
Code review by qodo was updated up to the latest commit 976f449 |
1 similar comment
|
Code review by qodo was updated up to the latest commit 976f449 |
Add an `_auth` setting that carries registry authentication as one structured, URL-keyed value instead of many `//host/:_authToken=…` keys. GitHub Actions silently drops env vars whose names contain `/`, `:`, or `.` (and bash/zsh reject them outright), which broke the `pnpm_config_//host/:_authToken=…` form on CI (pnpm#12314). The `pnpm_config__auth` env var — the env projection of the `_auth` setting — sidesteps the runner-level filter while preserving host scoping. The same value can be set in the global pnpm config.yaml as a native YAML map. Design: - `_auth` is honored only from the env var and the global config.yaml — never a project pnpm-workspace.yaml / .npmrc — so repo-controlled config can never supply registry auth. The env var wins over the global config on a conflicting key. - The value is host-keyed: `{ "https://registry.example": { "@": {...}, "@org": {...} } }`. The host and credential arrive in one trusted value, so the same entry is a safe source of registry routing — repo config cannot redirect an env token to a different host. Routes inferred from `_auth` are applied after workspace yaml (env/global wins over repo config) and before PNPM_CONFIG_* so an explicit registry override still wins — matching pnpm's "CLI > _auth > yaml" precedence. - Reuses npm's deprecated `_auth` key name on purpose: pnpm reads the structured form only from its own yaml (and the env projection), so it never collides with npm's legacy `.npmrc` `_auth` scalar, and it is already covered by the existing protected-settings redaction (prints as `(protected)`). - Only `authToken` is accepted (maps byte-for-byte to the existing `//host/:_authToken` .npmrc key), so the parser is a thin adapter onto the existing auth pipeline. The deprecated `basicAuth` / `username` + `password` forms and `tokenHelper` are excluded — dropped with a warning. - Malformed values, non-object shapes, non-URL keys, non-http(s) schemes, URLs carrying credentials/query/fragment, invalid scopes, and unsupported auth fields each push a distinct warning and are skipped without aborting the load. Warnings never leak raw URL credentials. Parity: implemented on both sides (TS CLI + pacquet). Both support the single credential field `authToken`. Closes pnpm#12314. --------- Co-authored-by: Zoltan Kochan <z@kochan.io>
976f449 to
36dda4f
Compare
|
Code review by qodo was updated up to the latest commit 36dda4f |
1 similar comment
|
Code review by qodo was updated up to the latest commit 36dda4f |
KSXGitHub
left a comment
There was a problem hiding this comment.
I have some requests/suggestions.
Some of them are about styling.
Others are about design decisions.
…nput
Per review, `_auth` now parses strictly: a malformed value (bad JSON,
wrong shape, invalid registry URL or scope, an unsupported credential
field, a missing/non-string `authToken`) is a hard error instead of a
warn-and-skip. Both sources are user-controlled, so a typo surfaces
immediately rather than silently dropping auth.
pacquet: model the value as `serde::Deserialize` types — a `url::Url`-
validated registry key, a scope enum, and a creds struct with
`deny_unknown_fields` — which replaces the hand-rolled JSON validation.
Errors never echo the raw URL key (it can embed secrets). `from_json_sources`
returns `Result`, surfaced as `LoadWorkspaceYamlError::InvalidJsonAuth`.
TS: `parseJsonAuth` throws `PnpmError('INVALID_AUTH_SETTING')` on any
malformed entry; `_auth` is still read only from the env var and global
config (project files never reach the strict parser).
Also applies the review's style fixes: pipe-trait the `from_json_sources`
call, import `NpmrcAuth`, and extract the env-json gate into a variable.
|
Thanks for the review @KSXGitHub — addressed in Design: error-tolerant → strict. Agreed, and switched both stacks to fail-fast. A malformed
Secret-safe errors. The error messages never echo the raw URL key (it can carry userinfo/query secrets) — they use a credential-free Style fixes: Rationale in doc comments / warning-message format: both moot now — the verbose rationale was already moved to the changeset, and the warning-message concern disappears with strict parsing (no warnings; serde/ Written by an agent (Claude Code, claude-opus-4-8). |
|
Code review by qodo was updated up to the latest commit 47a4a28 |
|
Code review by qodo was updated up to the latest commit 47a4a28 |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
pnpm11/config/reader/src/loadNpmrcFiles.ts (1)
276-276: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winUse an options object for
jsonAuthTokencontext.
jsonAuthTokennow takes 4 positional arguments, which violates the repo’s TypeScript convention to keep functions to 2–3 args and use an options object beyond that.Suggested refactor
- const token = jsonAuthToken(rawCreds as Record<string, unknown>, registry, scope, source) + const token = jsonAuthToken(rawCreds as Record<string, unknown>, { registry, scope, source })function jsonAuthToken ( creds: Record<string, unknown>, - registry: JsonAuthRegistry, - scope: string, - source: string + opts: { registry: JsonAuthRegistry, scope: string, source: string } ): string { + const { registry, scope, source } = optsAlso applies to: 348-353
🤖 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 `@pnpm11/config/reader/src/loadNpmrcFiles.ts` at line 276, The `jsonAuthToken` call in `loadNpmrcFiles` is using 4 positional arguments, which breaks the repo’s convention; update the `jsonAuthToken` API and its call sites to pass the context as a single options object instead of separate `registry`, `scope`, and `source` parameters. Make the change in the `jsonAuthToken` usage(s) referenced by `loadNpmrcFiles` so the function signature stays within the 2–3 argument guideline while preserving the same values in the options object.Source: Coding guidelines
🤖 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.
Inline comments:
In `@pacquet/crates/config/src/npmrc_auth.rs`:
- Around line 255-273: The auth/env route precedence in apply_json_auth is being
altered by BTreeMap-style reordering, so duplicate "@"/@scope entries do not
follow pnpm’s “last entry wins” behavior. Update the parsed JSON auth
representation and iteration so the outer registry entries preserve their
original order (instead of sorting) before apply_json_auth processes parsed.0,
ensuring json_env_registries and the creds updates reflect pnpm’s exact
precedence semantics for duplicate routes.
---
Nitpick comments:
In `@pnpm11/config/reader/src/loadNpmrcFiles.ts`:
- Line 276: The `jsonAuthToken` call in `loadNpmrcFiles` is using 4 positional
arguments, which breaks the repo’s convention; update the `jsonAuthToken` API
and its call sites to pass the context as a single options object instead of
separate `registry`, `scope`, and `source` parameters. Make the change in the
`jsonAuthToken` usage(s) referenced by `loadNpmrcFiles` so the function
signature stays within the 2–3 argument guideline while preserving the same
values in the options object.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: 2d2d7f0d-b16a-4e56-a010-85dff4ba950b
⛔ Files ignored due to path filters (1)
Cargo.lockis excluded by!**/*.lock,!Cargo.lock
📒 Files selected for processing (12)
.changeset/json-env-auth.mdpacquet/crates/cli/src/config_overrides.rspacquet/crates/cli/src/config_overrides/tests.rspacquet/crates/config/Cargo.tomlpacquet/crates/config/src/lib.rspacquet/crates/config/src/npmrc_auth.rspacquet/crates/config/src/npmrc_auth/tests.rspacquet/crates/config/src/tests.rspacquet/crates/config/src/workspace_yaml.rspnpm11/config/reader/src/index.tspnpm11/config/reader/src/loadNpmrcFiles.tspnpm11/config/reader/test/index.ts
🚧 Files skipped from review as they are similar to previous changes (6)
- pacquet/crates/config/src/workspace_yaml.rs
- pacquet/crates/cli/src/config_overrides.rs
- pacquet/crates/config/Cargo.toml
- pacquet/crates/cli/src/config_overrides/tests.rs
- pnpm11/config/reader/src/index.ts
- pacquet/crates/config/src/lib.rs
Looking for bugs?Check back in a few minutes. Qodo's review agents are on it. |
Summary
Adds an
_authsetting that configures registry authentication as a single structured (URL-keyed) value, instead of many//host/:_authToken=…keys. It can be set in two trusted places:config.yaml), as a native YAML map, andpnpm_config__authenvironment variable, as a JSON string — the CI-friendly form, since GitHub Actions / bash / zsh silently drop env vars whose names contain/,:, or.(which broke the oldpnpm_config_//host/:_authToken=…form on CI)._authis never read from a project.npmrc/pnpm-workspace.yaml, so repository-controlled config can never supply registry credentials. (npm's deprecated.npmrc_authscalar keeps its legacy meaning there — no collision, because pnpm only reads the structured_authfrom its own yaml and the env projection.)Example env form:
Equivalent in the global
config.yaml:httporhttpsand must not include credentials, query strings, or fragments.@means registry-wide/default credentials and package scopes like@orgbind credentials to that scope on the same host.authToken(maps to//host/:_authToken/ bearer auth). The deprecatedbasicAuth/username+passwordforms are intentionally not accepted in this new setting and are dropped with a warning;tokenHelperis likewise unsupported (executable paths must not come from this setting).@routes the default registry and@orgroutes that scope. Because the credential and its destination host arrive in one trusted value, repo-controlled config cannot redirect the token to a different host.--registry,--@scope:registry) >pnpm_config__auth> globalconfig.yaml_auth>pnpm-workspace.yaml. The env var wins over the globalconfig.yamlon a conflicting key.pnpm_config__auth(lowercase, documented) andPNPM_CONFIG__AUTH(all-caps shell convention) are honored; lowercase wins unless empty._authname means the value is already covered by the existing protected-settings redaction, so it prints as(protected)inpnpm config list.Closes #12314. Related to pnpm/pnpm.io#827 (docs PR will follow in the
pnpm.iorepo).Squash Commit Body
Checklist
pacquet/port. (Both sides implemented.).changeset/json-env-auth.md— minor bump forpnpmand
@pnpm/config.reader).env-over-yaml precedence, and project-yaml-ignored tests in
pnpm11/config/reader/test/index.ts. Pacquet: unit + end-to-end tests innpmrc_auth/tests.rsandtests.rsfor the env rename, globalconfig.yaml_auth, env-wins precedence, and the project-yaml trust boundary.)repo — a follow-up PR there will document the
_authsetting (Recommendation to set environment variable with special characters in name is misleading pnpm.io#827).)Written by an agent (Claude Code, claude-opus-4-8).
Summary by CodeRabbit
New Features
Bug Fixes