Skip to content

ci: run npm through script steps instead of the Npm@1 task - #1893

Merged
wenytang-ms merged 1 commit into
mainfrom
wenyt/cfs-npm1-to-script
Jul 28, 2026
Merged

ci: run npm through script steps instead of the Npm@1 task#1893
wenytang-ms merged 1 commit into
mainfrom
wenyt/cfs-npm1-to-script

Conversation

@wenytang-ms

Copy link
Copy Markdown
Contributor

Problem

The CFS onboarding merged earlier routes npm through the Central Feed Service using two job level settings:

  • npm_config_registry — the CFS feed URL, exported as an environment variable
  • npm_config_userconfig$(Agent.TempDirectory)/.npmrc, into which NpmAuthenticate@0 writes the feed credential

The Npm@1 task is incompatible with that arrangement. It generates its own .npmrc and points npm at it by setting npm_config_userconfig itself, which discards the credential. The registry is unaffected, because it arrives as an environment variable and npm ranks environment above every config file. The task therefore requests packages from the CFS feed with no token.

Observed in build 31831248:

registry   = "https://pkgs.dev.azure.com/mseng/VSJava/_packaging/vscjava/npm/registry/"
userconfig = "/mnt/vss/_work/1/npm/31831248.npmrc"

npm error code E401
npm error Unable to authenticate, your authentication token seems to be invalid.

The three CFS steps preceding it all reported succeeded; only the Npm@1 step failed.

Change

Every Npm@1 step becomes a plain script: step, which inherits both the registry and the userconfig from the job environment.

- task: Npm@1              →   - script: npm install
  displayName: npm install         displayName: npm install
  inputs:
    verbose: false

- task: Npm@1              →   - script: npm run compile
  displayName: npm run compile     displayName: npm run compile
  inputs:
    command: custom
    verbose: false
    customCommand: run compile

Steps that do not restore packages are converted as well. They do not fail today, but they run against the CFS feed unauthenticated, so any script that later reaches the registry — an npx invocation, for example — would fail the same way. Converting all of them leaves a single mechanism in place.

displayName, workingDir, enabled and verbose are preserved on every step.

This matches the configuration already validated in microsoft/vscode-gradle, where npm is invoked from plain shell steps and build 31830854 restored 525 of 525 packages through the CFS feed.

Validation

Each affected pipeline definition was expanded through the Azure DevOps pipeline preview API on this branch; all compile and retain the CFS steps.

Context

SFI Network Isolation / MountainPass SR21, ICM 840100965.

The Npm@1 task generates its own .npmrc and points npm at it through
npm_config_userconfig, which discards the CFS credential that
NpmAuthenticate@0 writes into $(Agent.TempDirectory)/.npmrc. The CFS
registry still applies, because it is supplied through the
npm_config_registry environment variable and an environment variable
outranks every npm config file. The task therefore requests packages
from the CFS feed with no token:

    registry   = https://pkgs.dev.azure.com/mseng/VSJava/_packaging/vscjava/npm/registry/
    userconfig = /mnt/vss/_work/1/npm/<buildid>.npmrc
    npm error code E401
    npm error Unable to authenticate, your authentication token seems to be invalid.

A plain script step inherits both values from the job environment, so
the credential survives. Steps that do not restore packages are
converted as well, so that a single mechanism applies throughout and no
step is left pointing at the CFS feed unauthenticated.

Display names, working directories, and the enabled and verbose flags
are preserved.
@wenytang-ms
wenytang-ms merged commit eb8f1a8 into main Jul 28, 2026
5 checks passed
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.

2 participants