Skip to content

fix(publish): forward strictSsl to libnpmpublish so self-signed registries work#12396

Merged
zkochan merged 1 commit into
mainfrom
fix/publish-strict-ssl
Jun 14, 2026
Merged

fix(publish): forward strictSsl to libnpmpublish so self-signed registries work#12396
zkochan merged 1 commit into
mainfrom
fix/publish-strict-ssl

Conversation

@mcmxcdev

@mcmxcdev mcmxcdev commented Jun 13, 2026

Copy link
Copy Markdown
Member

Summary

  • pnpm publish was silently ignoring strict-ssl=false (from .npmrc) and strictSsl: false (from pnpm-workspace.yaml) when publishing to registries that use self-signed certificates, causing a UNABLE_TO_VERIFY_LEAF_SIGNATURE error after a long timeout.
  • The root cause: createPublishOptions in publishPackedPkg.ts never included strictSSL in the options object forwarded to libnpmpublish. Since npm-registry-fetch (used internally by libnpmpublish) defaults strictSSL to true, the option had to be passed explicitly.
  • Fix: map options.strictSsl → strictSSL in publishOptions, matching the same behaviour that already works for pnpm install.

Test plan

  • New unit tests in publishConfigAccess.test.ts verify that strictSsl: false maps to strictSSL: false in the publish options object, and that strictSSL is absent when strictSsl is not set.
  • Manual verification requires a registry with a self-signed certificate (e.g. Sonatype Nexus) — see the reproduction steps in the linked issue.

Fixes pnpm/pnpm#12012.


Written by an agent (Claude Code, claude-sonnet-4-6).

Summary by CodeRabbit

  • Bug Fixes

    • Fixed pnpm publish to respect strictSsl: false configuration for registries with self-signed certificates.
  • Tests

    • Added test coverage for strict SSL configuration handling in publish options.

…tries work

`pnpm publish` was ignoring `strictSsl: false` from `.npmrc` /
`pnpm-workspace.yaml` because `createPublishOptions` never included
`strictSSL` in the options object passed to `libnpmpublish`.
`npm-registry-fetch` (used internally by `libnpmpublish`) defaults
`strictSSL` to `true`, so the flag had to be forwarded explicitly.

Fixes #12012.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 13, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

createPublishOptions in publishPackedPkg.ts is updated to explicitly pass strictSSL: options.strictSsl to the options object forwarded to libnpmpublish/npm-registry-fetch. Two tests verify the mapping behavior. A changeset documents the fix.

Changes

strictSsl forwarding fix for pnpm publish

Layer / File(s) Summary
strictSSL forwarding in createPublishOptions and tests
releasing/commands/src/publish/publishPackedPkg.ts, releasing/commands/test/publish/publishConfigAccess.test.ts
publishOptions now explicitly sets strictSSL: options.strictSsl; two new tests assert strictSsl: false maps to strictSSL: false and that omitting strictSsl leaves strictSSL as undefined.
Changeset
.changeset/fix-publish-strict-ssl.md
Documents the fix for @pnpm/releasing.commands and pnpm, noting that strict-ssl=false in .npmrc or strictSsl: false in pnpm-workspace.yaml is now honored during publish.

Estimated code review effort

🎯 1 (Trivial) | ⏱️ ~3 minutes

Possibly related PRs

  • pnpm/pnpm#11746: Also modifies createPublishOptions in publishPackedPkg.ts to forward a specific publish option (access) to libnpmpublish, the same function and pattern modified here.
  • pnpm/pnpm#11581: Modifies the publish flow in publishPackedPkg.ts to forward TLS-related and registry fetch options into the underlying dispatcher, directly related to the same code path.

Suggested reviewers

  • zkochan

🐇 A registry behind self-signed glass,
Would make pnpm publish simply not pass!
One line sets strictSSL,
And now certs won't stall—
Hop on through! The publish can now amass! 🎉

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: forwarding strictSsl to libnpmpublish to enable self-signed certificate registries, which directly addresses the issue described.
Linked Issues check ✅ Passed The PR fully implements the requirements from issue #12012: it forwards strictSsl configuration to libnpmpublish/npm-registry-fetch and includes tests verifying the configuration is correctly passed.
Out of Scope Changes check ✅ Passed All changes are directly scoped to fixing the strictSsl forwarding issue: the changeset documentation, the publishPackedPkg.ts modification, and the new unit tests are all focused on the stated objective.
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 fix/publish-strict-ssl

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint install timed out. The project may have too many dependencies for the sandbox.


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 and usage tips.

@mcmxcdev mcmxcdev marked this pull request as ready for review June 13, 2026 23:40
@mcmxcdev mcmxcdev requested a review from zkochan as a code owner June 13, 2026 23:40
@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Jun 13, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (1) 📘 Rule violations (0) 📎 Requirement gaps (0)

Context used

Grey Divider


Informational

1. Weak strictSSL absence test 🐞 Bug ⚙ Maintainability
Description
The test claims strictSSL is “absent” when strictSsl is not set, but it only asserts
opts.strictSSL is undefined, which also passes if the property exists with value undefined.
This can miss regressions where createPublishOptions stops pruning undefined keys and still
forwards a strictSSL field to downstream publish/fetch code.
Code

releasing/commands/test/publish/publishConfigAccess.test.ts[R44-50]

+  test('strictSSL is absent when strictSsl is not set', async () => {
+    const opts = await createPublishOptions(
+      { name: 'pkg', version: '1.0.0' },
+      baseOpts()
+    )
+    expect(opts.strictSSL).toBeUndefined()
+  })
Evidence
The test uses toBeUndefined(), which passes for both a missing key and a present-but-undefined
key. Meanwhile createPublishOptions() relies on pruneUndefined() to actually delete
undefined-valued keys; without an explicit “no property” assertion, the test won’t detect
regressions in that pruning behavior.

releasing/commands/test/publish/publishConfigAccess.test.ts[35-51]
releasing/commands/src/publish/publishPackedPkg.ts[194-201]
releasing/commands/src/publish/publishPackedPkg.ts[394-400]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The unit test intends to ensure `strictSSL` is not forwarded unless `strictSsl` is explicitly set, but `expect(opts.strictSSL).toBeUndefined()` cannot distinguish between a missing property and an own-property with value `undefined`.

## Issue Context
`createPublishOptions()` calls `pruneUndefined()` to delete keys with `undefined` values. If that pruning were removed/broken in the future, the current test would still pass and would not catch the regression.

## Fix Focus Areas
- releasing/commands/test/publish/publishConfigAccess.test.ts[44-50]

## Suggested change
Replace the assertion with one that checks property absence, e.g.:
- `expect(opts).not.toHaveProperty('strictSSL')` or
- `expect(Object.prototype.hasOwnProperty.call(opts, 'strictSSL')).toBe(false)`

Optionally also strengthen the first test to assert presence when set:
- `expect(opts).toHaveProperty('strictSSL', false)`

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Qodo Logo

@qodo-free-for-open-source-projects

Copy link
Copy Markdown

PR Summary by Qodo

Fix publish to honor strictSsl for self-signed registries
🐞 Bug fix 🧪 Tests 📝 Documentation 🕐 10-20 Minutes

Grey Divider

Walkthroughs

Description
• Forward strictSsl to libnpmpublish as strictSSL so publish respects .npmrc/workspace
  config.
• Prevent publish failures/timeouts against registries using self-signed certificates.
• Add unit coverage to ensure strictSSL is set only when configured.
Diagram
graph TD
  A["pnpm publish"] --> B["createPublishOptions()"] --> C{{"libnpmpublish"}} --> D{{"npm-registry-fetch"}} --> E{{"Registry (self-signed)"}}
  F["Config strictSsl"] --> B
Loading
High-Level Assessment

Forwarding options.strictSsl to strictSSL in the libnpmpublish options is the correct minimal fix, since the underlying fetch layer defaults to strict TLS verification unless explicitly overridden. Alternatives like globally relaxing TLS (e.g., via environment variables) are broader in scope and less safe/targeted than passing the explicit publish option.

Grey Divider

File Changes

Bug fix (1)
publishPackedPkg.ts Forward strictSsl to libnpmpublish as strictSSL +1/-0

Forward strictSsl to libnpmpublish as strictSSL

• Adds 'strictSSL: options.strictSsl' to the publish options object passed to 'libnpmpublish', ensuring 'npm-registry-fetch' does not fall back to its default 'strictSSL=true' behavior during publish.

releasing/commands/src/publish/publishPackedPkg.ts


Tests (1)
publishConfigAccess.test.ts Test strictSsl → strictSSL mapping in createPublishOptions +18/-0

Test strictSsl → strictSSL mapping in createPublishOptions

• Adds unit tests verifying that 'strictSsl: false' is forwarded as 'strictSSL: false', and that 'strictSSL' is omitted when 'strictSsl' is not provided.

releasing/commands/test/publish/publishConfigAccess.test.ts


Documentation (1)
fix-publish-strict-ssl.md Add changeset for strictSsl publish fix +6/-0

Add changeset for strictSsl publish fix

• Introduces a patch changeset documenting that 'pnpm publish' now respects 'strictSsl: false'/'strict-ssl=false' when publishing to registries with self-signed certificates.

.changeset/fix-publish-strict-ssl.md


Grey Divider

Qodo Logo

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

🧹 Nitpick comments (1)
releasing/commands/test/publish/publishConfigAccess.test.ts (1)

35-51: 💤 Low value

Consider adding a test case for strictSsl: true to complete the coverage.

The two tests correctly verify the critical cases (false forwarding and omitted behavior). For symmetry with the access test suite below (which covers multiple scenarios) and to ensure explicit true is also forwarded correctly, consider adding:

test('forwards strictSsl: true as strictSSL to npm-registry-fetch', async () => {
  const opts = await createPublishOptions(
    { name: 'pkg', version: '1.0.0' },
    { ...baseOpts(), strictSsl: true }
  )
  expect(opts.strictSSL).toBe(true)
})

This is optional since the default is already true and the issue was specifically about false not being honored.

🤖 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 `@releasing/commands/test/publish/publishConfigAccess.test.ts` around lines 35
- 51, Add a third test case to the createPublishOptions: strictSSL describe
block to verify that strictSsl: true is correctly forwarded as strictSSL: true
to npm-registry-fetch. This test should follow the same pattern as the existing
test for strictSsl: false, using the same createPublishOptions call structure
and verifying that opts.strictSSL equals true. This ensures complete coverage
for all three scenarios (true, false, and undefined) and maintains consistency
with similar test suites in the file.
🤖 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.

Nitpick comments:
In `@releasing/commands/test/publish/publishConfigAccess.test.ts`:
- Around line 35-51: Add a third test case to the createPublishOptions:
strictSSL describe block to verify that strictSsl: true is correctly forwarded
as strictSSL: true to npm-registry-fetch. This test should follow the same
pattern as the existing test for strictSsl: false, using the same
createPublishOptions call structure and verifying that opts.strictSSL equals
true. This ensures complete coverage for all three scenarios (true, false, and
undefined) and maintains consistency with similar test suites in the file.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 13c923cc-32df-4e37-b77d-039213ea2bcd

📥 Commits

Reviewing files that changed from the base of the PR and between 8dfe438 and 5881143.

📒 Files selected for processing (3)
  • .changeset/fix-publish-strict-ssl.md
  • releasing/commands/src/publish/publishPackedPkg.ts
  • releasing/commands/test/publish/publishConfigAccess.test.ts
📜 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). (1)
  • GitHub Check: ubuntu-latest / Node.js 24 / Test
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Use Standard Style with trailing commas, prefer functions over classes, declare functions after they are used relying on hoisting, limit function arguments to two or three with options objects for additional parameters
Follow import order: standard libraries, external dependencies (sorted alphabetically), then relative imports
Use JSDoc for function contracts (preconditions, postconditions, edge cases, why it exists) not for re-narrating the body; do not record past implementation shape or refactor history in comments

Files:

  • releasing/commands/src/publish/publishPackedPkg.ts
  • releasing/commands/test/publish/publishConfigAccess.test.ts
**/*.test.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

When checking if a caught error is an Error object in Jest, use util.types.isNativeError() instead of instanceof Error because instanceof checks can fail across VM realms

Files:

  • releasing/commands/test/publish/publishConfigAccess.test.ts
🧠 Learnings (4)
📚 Learning: 2026-05-26T21:01:06.666Z
Learnt from: zkochan
Repo: pnpm/pnpm PR: 11966
File: .changeset/require-tarball-integrity.md:6-6
Timestamp: 2026-05-26T21:01:06.666Z
Learning: In pnpm lockfile-related release notes/docs (especially changeset markdown), preserve URL hostnames exactly as they appear in pnpm-lock.yaml tarball resolution entries—keep hosts like `codeload.github.com`, `bitbucket.org`, and `gitlab.com` in lowercase. Do not “correct” them to title-case/preserve brand capitalization (e.g., LanguageTool rules like `GITHUB` capitalization) because these are literal URL fragments, not platform brand names.

Applied to files:

  • .changeset/fix-publish-strict-ssl.md
📚 Learning: 2026-05-14T09:04:00.133Z
Learnt from: zkochan
Repo: pnpm/pnpm PR: 11622
File: resolving/npm-resolver/test/publishedBy.test.ts:350-354
Timestamp: 2026-05-14T09:04:00.133Z
Learning: In the pnpm/pnpm repository, ESLint is the authoritative style linter. Do not raise review findings for missing trailing commas in multiline function calls (e.g., `fs.writeFileSync(...)`) when this repo’s ESLint configuration does not report them and lint passes. Prefer deferring to the ESLint results for this specific trailing-comma rule rather than enforcing it manually in code review.

Applied to files:

  • releasing/commands/src/publish/publishPackedPkg.ts
  • releasing/commands/test/publish/publishConfigAccess.test.ts
📚 Learning: 2026-06-05T13:47:26.046Z
Learnt from: vsumner
Repo: pnpm/pnpm PR: 12190
File: installing/deps-installer/src/install/index.ts:2337-2343
Timestamp: 2026-06-05T13:47:26.046Z
Learning: In the pnpm/pnpm codebase, `PnpmError` automatically prefixes `err.code` with `ERR_PNPM_` when you pass a code that does not already start with `ERR_PNPM_` (it normalizes `this.code` via `code.startsWith('ERR_PNPM_') ? code : `ERR_PNPM_${code}``). Therefore, during code review you should NOT flag `new PnpmError(...)` call sites for passing a bare error code (e.g., `new PnpmError('FROZEN_STORE_INCOMPATIBLE_WITH_PNPR', ...)`); the resulting `err.code` will still be `ERR_PNPM_FROZEN_STORE_INCOMPATIBLE_WITH_PNPR`.

Applied to files:

  • releasing/commands/src/publish/publishPackedPkg.ts
  • releasing/commands/test/publish/publishConfigAccess.test.ts
📚 Learning: 2026-06-05T13:47:05.929Z
Learnt from: vsumner
Repo: pnpm/pnpm PR: 12190
File: installing/deps-installer/test/install/frozenStore.ts:2-17
Timestamp: 2026-06-05T13:47:05.929Z
Learning: In the pnpm/pnpm repository, the shared Jest preset keeps `injectGlobals` at its default (`true`), so `test` and `expect` are available as Jest globals. Therefore, reviewers should not flag (or treat as TypeScript/compilation errors) missing `import { test, expect } from 'jest/globals'` when a test file uses `test`/`expect` without importing them. Importing from `jest/globals` may still be used for consistency with sibling files, but it is not required for execution in this repo unless a Jest preset is explicitly configured with `injectGlobals: false`.

Applied to files:

  • releasing/commands/test/publish/publishConfigAccess.test.ts
🔇 Additional comments (2)
releasing/commands/src/publish/publishPackedPkg.ts (1)

163-163: LGTM!

.changeset/fix-publish-strict-ssl.md (1)

1-6: LGTM!

@zkochan zkochan merged commit 7cdf9f8 into main Jun 14, 2026
15 checks passed
@zkochan zkochan deleted the fix/publish-strict-ssl branch June 14, 2026 09:48
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.

strictSsl: false not applied to pnpm publish

2 participants