Skip to content

chore: migrate from npm to pnpm with supply chain hardening#579

Open
Kabidoye-17 wants to merge 12 commits into
mainfrom
pnpm-migration
Open

chore: migrate from npm to pnpm with supply chain hardening#579
Kabidoye-17 wants to merge 12 commits into
mainfrom
pnpm-migration

Conversation

@Kabidoye-17

@Kabidoye-17 Kabidoye-17 commented Jul 8, 2026

Copy link
Copy Markdown

Why?

This repo was surfaced in a follow-up audit as part of the org-wide effort to bring active npm repos onto a supply-chain-hardened footing (per-package script gating, install cooldown, pnpm's stricter dependency graph). Migrating to pnpm 10 aligns Intercom-OpenAPI with the target config already applied across the sibling repos in FE-3214.

How?

pnpm import was used to convert package-lock.json to pnpm-lock.yaml verbatim, preserving every resolved version so no transitive dependency drift shipped alongside the tooling swap. Supply-chain settings (minimumReleaseAge: 10080, trustPolicy: no-downgrade) live in pnpm-workspace.yaml; the es5-ext cosmetic postinstall is silenced via pnpm.ignoredBuiltDependencies. Registry-source lockdown is already handled at the infra layer by Socket Firewall, so no pnpm-side config is needed here. Disabled workflows under .github/workflows-disabled/ were updated so they continue to work if re-enabled — the new pnpm/action-setup refs are SHA-pinned. Pre-existing GHA hardening gaps (unpinned actions/checkout, missing top-level permissions: blocks) were left out of scope; whoever re-enables any workflow should run the security-review skill end-to-end first.

Follow-up

fern-api is pinned to 5.65.3 in workflows. pnpm add -g fern-api (unpinned) fails through Intercom's registry proxy because the proxy serves the fern-api manifest without a dist-tags block, and pnpm has no fallback resolver for a missing latest tag. Upstream issues, both open:

When those are fixed (or the proxy is fixed to include dist-tags), the pin can be dropped.

Generated with Claude Code

pnpm's global install has no fallback when a registry manifest lacks
dist-tags, and Intercom's Socket Firewall proxy serves the fern-api
manifest without them, so `pnpm add -g fern-api` (unpinned) fails with
ERR_PNPM_NO_MATCHING_VERSION. Pinning bypasses `latest` resolution.

Upstream: pnpm/pnpm#5564, pnpm/pnpm#9944 (both open).
@Kabidoye-17

Kabidoye-17 commented Jul 8, 2026

Copy link
Copy Markdown
Author

Local Verification — no regressions

Same fern flow run on both sides. The same 3 pre-existing spec errors and 295 warnings appear on main and on this branch — no new errors introduced by the migration.

Master (npm install)

rm -rf node_modules && npm install — 550 packages in 6s; 6 deprecation warnings; 12 vulnerabilities (4 moderate, 8 high) reported by npm audit.

master: npm install output

npm install -g fern-apifern checkfern generate --preview --group ts-sdk — 3 errors, 295 warnings.

master: fern check + generate --preview

This branch (pnpm install)

rm -rf node_modules && pnpm install — 522 packages in 3.3s; preinstall guard runs and exits 0. The ${GITHUB_TOKEN} .npmrc warning is pre-existing (harmless — no @intercom/* runtime deps consume it).

branch: pnpm install output

fern check — 3 errors, 295 warnings (identical to master).

branch: fern check

fern generate --preview --group ts-sdk — 3 errors, 295 warnings (identical to master).

branch: fern generate --preview --group ts-sdk

Errors — identical on both sides

File Error
preview/conversationsAttributes.yml CreateConversationAttributeOptionRequest already declared in preview/__package__.yml
preview/articles.yml PublishArticleDraftRequest already declared in preview/__package__.yml
preview/articles.yml UpdateArticleRequestBody is not defined

Pre-existing spec issues, unrelated to the migration.

~ Automated via Claude

@Kabidoye-17
Kabidoye-17 marked this pull request as ready for review July 8, 2026 14:12
Re-merge main (16 commits) and regenerate pnpm-lock.yaml from mains
package-lock.json. package.json + spec YAMLs auto-merged.

The regen used a one-time resolution bypass of the pnpm-workspace.yaml
trustPolicy: no-downgrade, which flags undici@5.29.0 (transitive via
@actions/core) as a provenance downgrade. undici@5.29.0 is the version main
already pins on the 5.x line; no-downgrade reads the provenance-less 5.x
backport as a downgrade from the 6.x line (same false-positive class
developer-docs documents for semver@6.3.1 / undici-types@6.20.0). trustPolicy
is left fully intact; --frozen-lockfile does not re-apply it, so CI installs
the pinned lock cleanly.

Verified on pnpm 10.23.0: pnpm install --frozen-lockfile clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
shrek-intercom[bot]

This comment was marked as outdated.

pnpm's preinstall lifecycle fires AFTER pnpm relayouts node_modules
(creates .pnpm/ and moves any npm-installed dirs to .ignored_<name>/),
so the guard's `!fs.existsSync('node_modules/.pnpm')` check is always
false by the time it runs. The branch is dead code under `pnpm install`.

The wrong-package-manager path above already catches the common
failure mode (a contributor running `npm install`), so nothing else
is needed. Verified by instrumenting the script and running each
install path.
On a fresh macOS shell, `pnpm add -g <pkg>` errors with
`ERR_PNPM_NO_GLOBAL_BIN_DIR` because PNPM_HOME isn't wired into PATH
yet. This trips up anyone regenerating an SDK from a clean clone —
including Fern-support engineers. Document the one-time `pnpm setup`
step in both the internal Development runbook (CLAUDE.md) and the
external CONTRIBUTING guide.
The CI/CD table describes intended behavior, but `.github/workflows/`
doesn't exist on main — every workflow moved to `workflows-disabled/`
as part of PR #536 (org-wide GitHub Actions enablement migration,
2026-06-03), and FERN_TOKEN / FERN_NPM_TOKEN were removed after the
2026-05-01 Fern token incident. Restoration is a separate operation
gated on both the org migration and secret re-provisioning.

Adds a leading note above the table so readers know the schedule
column is aspirational until re-enablement.
shrek-intercom[bot]

This comment was marked as outdated.

The `pnpm-install` telemetry event fired on every successful install
forever, not just during the migration window — it would keep sending
per-engineer / per-repo data to Honeycomb long after the org-wide
pnpm rollout completed, polluting the dataset with steady-state noise.

Rollout progress can be inferred from the ABSENCE of
`wrong-package-manager` events over time, so no substitute signal is
needed. The failure-path telemetry (`wrong-package-manager`) remains
in place — that's where the interesting signal lives.
shrek-intercom[bot]

This comment was marked as outdated.

@Kabidoye-17 Kabidoye-17 changed the title [FE-3214] chore: migrate from npm to pnpm with supply chain hardening chore: migrate from npm to pnpm with supply chain hardening Jul 23, 2026
Drops scripts/check-package-manager.js and its package.json preinstall
hook. The guard emitted install-time telemetry to an external endpoint,
which is out of place in a public repo and unnecessary for the pnpm
migration itself.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
shrek-intercom[bot]

This comment was marked as outdated.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
shrek-intercom[bot]

This comment was marked as outdated.

Kabidoye-17 and others added 2 commits July 23, 2026 16:48
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
shrek-intercom[bot]

This comment was marked as outdated.

shrek-intercom[bot]

This comment was marked as outdated.

Fresh machines without PNPM_HOME configured hit ERR_PNPM_NO_GLOBAL_BIN_DIR
on pnpm add -g. Add the one-time pnpm setup step in front of the fern-api
install so external contributors following CONTRIBUTING.md don't trip on it.

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

❌ PR Review Summary: NEEDS HUMAN REVIEW

Summary
🎯 Problem — The PR title and description are excellent, clearly articulating the motivation (org-wide supply chain hardening audit), referencing the broader initiative (FE-3214), and documenting key implementation decisions and follow-up considerations.
📝 Alignment — All substantive claims in the description are confirmed by the diff, including the npm-to-pnpm migration, supply-chain settings in pnpm-workspace.yaml, es5-ext silencing, SHA-pinned pnpm/action-setup in disabled workflows, fern-api pinned to 5.65.3, and explicitly scoped-out GHA hardening gaps.
ℹ️ 🧠 Correctness — Disabled for this repository.
🦺 Safety — The PR touches multiple categories requiring mandatory human review: seven CI/CD workflow files under .github/, dependency manifests and lockfiles (package.json modified, package-lock.json deleted, pnpm-lock.yaml and pnpm-workspace.yaml added), and the sensitive CLAUDE.md configuration file.
🚦 Auto-approval — Touches AI config files (CLAUDE.md); Exceeds LOC limit (10800 meaningful LOC > 150, raw 10800)
Per-criterion details

Problem

Excellent PR description that clearly explains the why (org-wide supply chain hardening audit), provides context about the broader initiative (FE-3214), and documents important follow-up considerations. While the How section is detailed, it's justified for a security-related infrastructure change where implementation decisions matter.

Alignment

The PR description claims a migration from npm to pnpm with supply chain hardening. Checking each claim against the diff:

  1. npm to pnpm migration: ✅ The diff shows package-lock.json deleted, pnpm-lock.yaml created, package.json updated with "packageManager": "pnpm@10.23.0", all workflow files changed from npm install -g fern-api to pnpm add -g fern-api@5.65.3, and documentation (CLAUDE.md, CONTRIBUTING.md) updated with pnpm commands.

  2. Supply-chain settings (minimumReleaseAge: 10080, trustPolicy: no-downgrade) in pnpm-workspace.yaml: ✅ Confirmed exactly in the new pnpm-workspace.yaml file.

  3. es5-ext silenced via pnpm.ignoredBuiltDependencies: ✅ Confirmed in the package.json changes.

  4. Disabled workflows updated with SHA-pinned pnpm/action-setup: ✅ All 7 workflow files under .github/workflows-disabled/ use pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4.1.0.

  5. Pre-existing GHA hardening gaps left out of scope: ✅ The diff shows actions/checkout@v4 and @v3 remain unpinned, consistent with the claim.

  6. fern-api pinned to 5.65.3: ✅ All workflows use pnpm add -g fern-api@5.65.3.

  7. pnpm import used: The diff shows package-lock.json deleted and pnpm-lock.yaml created as new file, consistent with this claim (we can't verify the exact command from the diff alone, but the outcome matches).

No significant changes in the diff are omitted from the description. The CONTRIBUTING.md additions (pnpm setup instructions) are a minor doc update that's implicitly part of the migration. All substantive changes are accurately described.

Safety

This PR is a tooling migration from npm to pnpm that touches multiple categories of files explicitly listed as requiring human review in the safety criteria. The changes include:

  1. CI/CD workflow files (.github/workflows-disabled/): Seven workflow files are modified. Even though they're currently in a "disabled" directory, they are under .github/ and represent CI/CD configuration.

  2. Dependency manifests and lockfiles: package.json is modified (adding packageManager field and pnpm.ignoredBuiltDependencies), package-lock.json is deleted entirely, and new pnpm-lock.yaml and pnpm-workspace.yaml files are added. These are explicitly called out as unsafe in the criteria.

  3. CLAUDE.md: The project instructions file is modified (changing npm install to pnpm install references). The criteria note that "CLAUDE.md and .claude/ config are treated as sensitive."

None of the changes touch the safe categories (Unstable/Preview spec, generated Postman collections, or general documentation like README). While CONTRIBUTING.md changes alone might qualify as safe documentation, the PR as a whole is clearly infrastructure/tooling work that requires human review.

<violated_criteria>
CI/CD and repo config — changes to files under .github/ (seven workflow files in .github/workflows-disabled/ are modified)
Dependency manifests / lockfiles — package.json modified, package-lock.json deleted, new pnpm-lock.yaml and pnpm-workspace.yaml added
CLAUDE.md modification — sensitive project configuration file edited
</violated_criteria>

Rate this comment 👍 / 👎 to help us improve 🙏 · Disagree with assessment? Establish ground truth here

@zilleeizad-inter
zilleeizad-inter enabled auto-merge (squash) July 23, 2026 16:31
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.

3 participants