Skip to content

Fix npm registry hard-coded to internal dnceng feed (#19370) - #19388

Merged
David Pine (IEvangelist) merged 2 commits into
mainfrom
dapine/cli-npm-public-registry
Aug 14, 2026
Merged

David Pine (IEvangelist) merged 2 commits into
mainfrom
dapine/cli-npm-public-registry

Conversation

@IEvangelist

Copy link
Copy Markdown
Member

Description

PR #18858 hardened npm handling but also changed the customer-facing default registry to the internal dnceng Azure Artifacts feed (https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/). That feed is a private pull-through mirror that returns 401 anonymously for tarballs it hasn't already cached.

This breaks aspire agent init: npm install -g <local .tgz> resolves the tarball's transitive dependencies through --registry, and packages the feed hasn't mirrored (e.g. playwright / playwright-core) fail the final install step with E401. The internal feed was also shipped as the default in generated Dockerfiles and aspire new templates.

Root cause

--registry is applied to the entire resolution graph, not just the top-level package. Pointing it at an anonymous-401 private mirror means any un-mirrored transitive dependency aborts the install.

Fix

Restore the public npm registry (https://registry.npmjs.org/) as the customer-facing default, while keeping the genuine hardening introduced in #18858.

Surfaces changed:

  • CLIsrc/Aspire.Cli/Npm/NpmRunner.cs: the --registry value passed to npm view / pack / install -g now points at public npm. Commands still pass it explicitly so resolution can't inherit a project-level .npmrc that redirects to a private feed. --ignore-scripts is retained on the global install.
  • Generated Dockerfilesrc/Aspire.Hosting.JavaScript/JavaScriptHostingExtensions.cs: the NPM_REGISTRY default is public npm, and stays overridable at build time via --build-arg NPM_REGISTRY=... for operators who prefer an internal mirror.
  • Shipped aspire new template lockfilests-starter, py-starter, and aspire-ts-cs-starter/frontend package-lock.json: only the resolved URL host is swapped to public npm. Versions and integrity (SRI) hashes are unchanged — the dnceng feed is a pull-through mirror, so the path after the host is identical and the integrity hashes remain valid. This mirrors the precedent already used in [auto-sec] Consolidate Aspire JavaScript template dependency security remediations #18858 for the frontend lockfiles.
  • Tests + snapshots — updated NpmRunnerTests, AddJavaScriptAppTests, and the six JS Dockerfile snapshots; added regression guards in TemplatePackageLockTests asserting shipped lockfiles resolve only to registry.npmjs.org.

Intentionally left on the internal feed (repo-internal / CI only, not customer-facing): playground/**, tests/PolyglotAppHosts/**, tests/Aspire.Cli.EndToEnd.Tests/Fixtures/**, extension/yarn.lock, and .github/workflows/polyglot-validation/Dockerfile.typescript. Reverting these would balloon the diff and undo intended repo-internal supply-chain routing.

Security posture unchanged: --ignore-scripts, Sigstore provenance verification, and SRI integrity checks are all retained. Package authenticity is still cryptographically verified regardless of registry host, so swapping the resolved host does not weaken the supply-chain guarantees added in #18858.

Fixes #19370

Checklist

  • Is this feature complete?
    • Yes. Ready to ship.
    • No. Follow-up changes expected.
  • Are you including unit tests for the changes and scenario tests if relevant?
    • Yes
    • No
  • Did you add public API?
    • Yes
      • If yes, did you have an API Review for it?
        • Yes
        • No
      • Did you add <remarks /> and <code /> elements on your triple slash comments?
        • Yes
        • No
    • No
  • Does the change make any security assumptions or guarantees?

PR #18858 set the internal dnceng Azure Artifacts feed as the customer
default for npm operations. This breaks `aspire agent init`: npm resolves
a tarball's transitive dependencies through --registry, and the dnceng
pull-through feed returns 401 anonymously for packages it hasn't cached
(e.g. playwright / playwright-core), so `npm install -g <.tgz>` fails with
E401. It also shipped the internal feed as the default in generated
Dockerfiles and `aspire new` templates.

Restore the public npm registry (https://registry.npmjs.org/) as the
customer-facing default across:
- Aspire.Cli NpmRunner (npm view/pack/install pass --registry)
- Generated pnpm Dockerfile NPM_REGISTRY default (still overridable at
  build time via --build-arg NPM_REGISTRY=...)
- Shipped ts-starter / py-starter / aspire-ts-cs-starter template
  lockfiles (resolved URL host only; versions and integrity hashes
  are unchanged)

Security hardening is retained: --ignore-scripts on the global install
and Sigstore provenance + SRI integrity verification. Repo-internal
lockfiles and CI images intentionally remain on the internal feed.

Fixes #19370

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@github-actions

Copy link
Copy Markdown
Contributor

🚀 Dogfood this PR with:

⚠️ WARNING: Do not do this without first carefully reviewing the code of this PR to satisfy yourself it is safe.

curl -fsSL https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.sh | bash -s -- 19388

Or

  • Run remotely in PowerShell:
iex "& { $(irm https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.ps1) } 19388"

@github-actions github-actions Bot added the needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners label Aug 14, 2026
@github-actions

This comment has been minimized.

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.

Pull request overview

Restores the public npm registry for customer-facing CLI, Dockerfile, and template workflows while retaining package-integrity protections.

Changes:

  • Uses registry.npmjs.org for CLI package operations and generated Dockerfiles.
  • Updates shipped template lockfiles without changing versions or integrity hashes.
  • Adds regression tests and refreshes Dockerfile snapshots.

Reviewed changes

Copilot reviewed 11 out of 14 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
src/Aspire.Cli/Npm/NpmRunner.cs Restores the public registry for npm operations.
src/Aspire.Hosting.JavaScript/JavaScriptHostingExtensions.cs Changes generated Dockerfiles’ default registry.
src/Aspire.Cli/Templating/Templates/ts-starter/package-lock.json Repoints TypeScript starter dependencies.
src/Aspire.Cli/Templating/Templates/py-starter/package-lock.json Repoints Python starter dependencies.
src/Aspire.ProjectTemplates/templates/aspire-ts-cs-starter/frontend/package-lock.json Repoints frontend dependencies.
tests/Aspire.Cli.Tests/Npm/NpmRunnerTests.cs Verifies public-registry CLI arguments.
tests/Aspire.Cli.Tests/Templating/TemplatePackageLockTests.cs Guards shipped lockfile registry hosts.
tests/Aspire.Hosting.JavaScript.Tests/AddJavaScriptAppTests.cs Updates Dockerfile registry assertions.
tests/Aspire.Hosting.JavaScript.Tests/Snapshots/AddViteAppTests.VerifyDockerfileWhenPackageScriptUsesPnpm.verified.txt Updates pnpm Dockerfile snapshot.
tests/Aspire.Hosting.JavaScript.Tests/Snapshots/AddViteAppTests.VerifyDockerfileWhenNextJsAppUsesPnpm.verified.txt Updates Next.js snapshot.
tests/Aspire.Hosting.JavaScript.Tests/Snapshots/AddJavaScriptAppTests.VerifyPnpmDockerfileWhenPublishedAsPackageScript_hasLockFile=True.verified.txt Updates package-script snapshot.
tests/Aspire.Hosting.JavaScript.Tests/Snapshots/AddJavaScriptAppTests.VerifyPnpmDockerfileWhenPublishedAsPackageScript_hasLockFile=False.verified.txt Updates no-lockfile package-script snapshot.
tests/Aspire.Hosting.JavaScript.Tests/Snapshots/AddJavaScriptAppTests.VerifyPnpmDockerfile_hasLockFile=True.verified.txt Updates lockfile snapshot.
tests/Aspire.Hosting.JavaScript.Tests/Snapshots/AddJavaScriptAppTests.VerifyPnpmDockerfile_hasLockFile=False.verified.txt Updates no-lockfile snapshot.
Files not reviewed (3)
  • src/Aspire.Cli/Templating/Templates/py-starter/package-lock.json: Generated file
  • src/Aspire.Cli/Templating/Templates/ts-starter/package-lock.json: Generated file
  • src/Aspire.ProjectTemplates/templates/aspire-ts-cs-starter/frontend/package-lock.json: Generated file

Comment thread tests/Aspire.Cli.Tests/Templating/TemplatePackageLockTests.cs Outdated
Comment thread src/Aspire.Cli/Npm/NpmRunner.cs
Comment thread tests/Aspire.Cli.Tests/Templating/TemplatePackageLockTests.cs

@adamint Adam Ratzman (adamint) left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Reviewed cf938341.

I left two fixable findings inline: the security spec/diagnostics still describe the internal feed, and the new ProjectTemplates lockfile guard is not selected for a ProjectTemplates-only change.

Dogfood proof passed: CLI 13.6.0-pr.19388.gcf938341, aspire agent init bypassed an unreachable .npmrc, all three changed starters completed npm ci, generated Dockerfiles built with both the public default and an override, and targeted CLI/JavaScript tests passed.

@IEvangelist
David Pine (IEvangelist) enabled auto-merge (squash) August 14, 2026 17:12
…blic registry and route ProjectTemplates lockfile guard

The code fix for #19370 already restores the public npm registry as the
customer-facing default. This follow-up resolves reviewer feedback about
stale docs/comments and CI test routing that lagged behind that change:

- docs/specs/safe-npm-tool-install.md: the security spec still described
  the internal dotnet-public-npm Azure Artifacts feed as the resolution
  source (trust-anchor table, Step 1/3 actions, trust basis, limitations,
  the verification-chain diagram, and the implementation constant). Updated
  all of these to the public npm registry (registry.npmjs.org) so the spec
  matches shipped behavior.
- src/Aspire.Cli/Npm/INpmRunner.cs and
  src/Aspire.Cli/Agents/Playwright/PlaywrightCliInstaller.cs: the
  ResolvePackageAsync doc comment, a Step 1 comment, and a LogDebug message
  still said "internal npm registry". Corrected to "public npm registry".
- tests/Aspire.Cli.Tests/Templating/TemplatePackageLockTests.cs: rewrote the
  StarterAppHostPackageLock_UsesPublicNpmRegistry comment to state the current
  invariant (shipped lockfiles pin the resolved registry for deps restored in
  a generated starter, so they must resolve from the public registry) instead
  of narrating prior-PR history.
- eng/github-ci/test-trigger-map.yml: added an additive path rule routing
  src/Aspire.ProjectTemplates/templates/aspire-ts-cs-starter/frontend/package-lock.json
  to test:Aspire.Cli.Tests, so a lockfile-only edit runs the
  ProjectTemplateFrontendPackageLock_UsesPublicNpmRegistry guard (the existing
  src/Aspire.ProjectTemplates/** rule only builds Aspire.Templates.Tests).

No behavior or registry-value changes; docs/comments/CI-routing only.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: fa48dbbe-0b88-44d0-8402-3699a48cd862
Copilot AI review requested due to automatic review settings August 14, 2026 17:24
@github-actions

Copy link
Copy Markdown
Contributor

Tests selector (audit mode)

The full test matrix and all jobs still run in audit mode. The tests and jobs below are what selective CI would run under enforcement.

13 / 100 test projects · 6 jobs, from 17 changed files.

Selected test projects (13 / 100)

Aspire.Cli.EndToEnd.Tests, Aspire.Cli.Tests, Aspire.Hosting.Azure.Kubernetes.Tests, Aspire.Hosting.Azure.Tests, Aspire.Hosting.Blazor.Tests, Aspire.Hosting.CodeGeneration.TypeScript.Tests, Aspire.Hosting.Dotnet.Tests, Aspire.Hosting.JavaScript.Tests, Aspire.Hosting.Radius.Tests, Aspire.Hosting.Tests, Aspire.Playground.Tests, Aspire.Templates.Tests, Infrastructure.Tests

Selected jobs (6)

cli-starter, deployment-e2e, extension-e2e, polyglot, typescript-api-compat, typescript-sdk


How these were chosen — grouped by what changed

⚠️ 9 of the 13 selected test projects come from a single change — src/Aspire.Hosting.JavaScript/JavaScriptHostingExtensions.cs.

🔧 src/Aspire.Hosting.JavaScript/JavaScriptHostingExtensions.cs (changed source)
1 directly: Aspire.Hosting.JavaScript.Tests
8 via the project graph: Aspire.Hosting.Azure.Kubernetes.Tests (2 hops), Aspire.Hosting.Azure.Tests, Aspire.Hosting.Blazor.Tests (2 hops), Aspire.Hosting.CodeGeneration.TypeScript.Tests, Aspire.Hosting.Dotnet.Tests (2 hops), Aspire.Hosting.Radius.Tests (2 hops), Aspire.Hosting.Tests, Aspire.Playground.Tests

🔧 src/Aspire.ProjectTemplates/templates/aspire-ts-cs-starter/frontend/package-lock.json (changed source)
2 directly: Aspire.Cli.Tests, Aspire.Templates.Tests

📦 affected project Aspire.Cli
1 test: Aspire.Cli.EndToEnd.Tests

📄 eng/github-ci/test-trigger-map.yml (changed)
1 directly: Infrastructure.Tests

🧪 tests/Aspire.Cli.Tests/Npm/NpmRunnerTests.cs (changed test)
1 directly: Aspire.Cli.Tests

🧪 tests/Aspire.Cli.Tests/Templating/TemplatePackageLockTests.cs (changed test)
1 directly: Aspire.Cli.Tests

🧪 tests/Aspire.Hosting.JavaScript.Tests/AddJavaScriptAppTests.cs (changed test)
1 directly: Aspire.Hosting.JavaScript.Tests

🧪 tests/Aspire.Hosting.JavaScript.Tests/Snapshots/AddJavaScriptAppTests.VerifyPnpmDockerfileWhenPublishedAsPackageScript_hasLockFile=False.verified.txt (changed test)
1 directly: Aspire.Hosting.JavaScript.Tests

🧪 tests/Aspire.Hosting.JavaScript.Tests/Snapshots/AddJavaScriptAppTests.VerifyPnpmDockerfileWhenPublishedAsPackageScript_hasLockFile=True.verified.txt (changed test)
1 directly: Aspire.Hosting.JavaScript.Tests

🧪 tests/Aspire.Hosting.JavaScript.Tests/Snapshots/AddJavaScriptAppTests.VerifyPnpmDockerfile_hasLockFile=False.verified.txt (changed test)
1 directly: Aspire.Hosting.JavaScript.Tests

🧪 tests/Aspire.Hosting.JavaScript.Tests/Snapshots/AddJavaScriptAppTests.VerifyPnpmDockerfile_hasLockFile=True.verified.txt (changed test)
1 directly: Aspire.Hosting.JavaScript.Tests

🧪 tests/Aspire.Hosting.JavaScript.Tests/Snapshots/AddViteAppTests.VerifyDockerfileWhenNextJsAppUsesPnpm.verified.txt (changed test)
1 directly: Aspire.Hosting.JavaScript.Tests

🧪 tests/Aspire.Hosting.JavaScript.Tests/Snapshots/AddViteAppTests.VerifyDockerfileWhenPackageScriptUsesPnpm.verified.txt (changed test)
1 directly: Aspire.Hosting.JavaScript.Tests

Job reasons

Job Triggered by
cli-starter • affected project Aspire.Cli
• selected test Aspire.Cli.Tests
deployment-e2e src/Aspire.ProjectTemplates/templates/aspire-ts-cs-starter/frontend/package-lock.json
• affected project Aspire.Cli
extension-e2e src/Aspire.Cli/Agents/Playwright/PlaywrightCliInstaller.cs, src/Aspire.Cli/Npm/INpmRunner.cs, src/Aspire.Cli/Npm/NpmRunner.cs, src/Aspire.Cli/Templating/Templates/py-starter/package-lock.json, src/Aspire.Cli/Templating/Templates/ts-starter/package-lock.json, src/Aspire.Hosting.JavaScript/JavaScriptHostingExtensions.cs, tests/Aspire.Cli.Tests/Npm/NpmRunnerTests.cs, tests/Aspire.Cli.Tests/Templating/TemplatePackageLockTests.cs
• affected project Aspire.Cli
polyglot affected project Aspire.Cli
typescript-api-compat affected project Aspire.Cli
typescript-sdk src/Aspire.Cli/Templating/Templates/ts-starter/package-lock.json

Selection computed for commit 5adae2a.

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.

Pull request overview

Copilot reviewed 15 out of 18 changed files in this pull request and generated no new comments.

Files not reviewed (3)
  • src/Aspire.Cli/Templating/Templates/py-starter/package-lock.json: Generated file
  • src/Aspire.Cli/Templating/Templates/ts-starter/package-lock.json: Generated file
  • src/Aspire.ProjectTemplates/templates/aspire-ts-cs-starter/frontend/package-lock.json: Generated file

@adamint Adam Ratzman (adamint) left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Re-reviewed 5adae2ada5 against cf9383416.

Both findings are addressed: the npm trust documentation/diagnostics now match the public registry, and the exact ProjectTemplates lockfile path now selects Aspire.Cli.Tests in addition to the existing template coverage. The three threads are resolved.

TestTriggerMapTests passed 15/15, and exact selector validation includes both Aspire.Cli.Tests and Aspire.Templates.Tests. Prior dogfood proof remains valid because no user-facing npm or generated-Dockerfile behavior changed. The current failed template check is an unrelated Azure Artifacts 503 during restore, not a test or PR failure.

@github-actions

Copy link
Copy Markdown
Contributor

Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt.

@IEvangelist
David Pine (IEvangelist) merged commit 639e616 into main Aug 14, 2026
723 of 727 checks passed
@IEvangelist
David Pine (IEvangelist) deleted the dapine/cli-npm-public-registry branch August 14, 2026 18:18
@github-actions github-actions Bot added this to the 13.6 milestone Aug 14, 2026
@IEvangelist

Copy link
Copy Markdown
Member Author

/backport release/13.5

@joperezr

Copy link
Copy Markdown
Member

/backport to release/13.5

@github-actions

Copy link
Copy Markdown
Contributor

Started backporting to release/13.5 (link to workflow run)

@aspire-repo-bot

Copy link
Copy Markdown
Contributor

Jose Perez Rodriguez (@joperezr) backporting to release/13.5 failed, the patch most likely resulted in conflicts. Please backport manually!

git am output
$ git am --3way --empty=keep --ignore-whitespace --keep-non-patch changes.patch

Applying: Fix npm registry hard-coded to internal dnceng feed (#19370)
Using index info to reconstruct a base tree...
M	src/Aspire.Cli/Npm/NpmRunner.cs
M	src/Aspire.ProjectTemplates/templates/aspire-ts-cs-starter/frontend/package-lock.json
M	tests/Aspire.Cli.Tests/Npm/NpmRunnerTests.cs
M	tests/Aspire.Cli.Tests/Templating/TemplatePackageLockTests.cs
Falling back to patching base and 3-way merge...
Auto-merging src/Aspire.Cli/Npm/NpmRunner.cs
Auto-merging src/Aspire.ProjectTemplates/templates/aspire-ts-cs-starter/frontend/package-lock.json
Auto-merging tests/Aspire.Cli.Tests/Npm/NpmRunnerTests.cs
Auto-merging tests/Aspire.Cli.Tests/Templating/TemplatePackageLockTests.cs
CONFLICT (content): Merge conflict in tests/Aspire.Cli.Tests/Templating/TemplatePackageLockTests.cs
error: Failed to merge in the changes.
hint: Use 'git am --show-current-patch=diff' to see the failed patch
hint: When you have resolved this problem, run "git am --continue".
hint: If you prefer to skip this patch, run "git am --skip" instead.
hint: To restore the original branch and stop patching, run "git am --abort".
hint: Disable this message with "git config set advice.mergeConflict false"
Patch failed at 0001 Fix npm registry hard-coded to internal dnceng feed (#19370)
Error: The process '/usr/bin/git' failed with exit code 128

Link to workflow output

Jose Perez Rodriguez (joperezr) added a commit that referenced this pull request Aug 15, 2026
…19370) (#19417)

* Fix npm registry hard-coded to internal dnceng feed (#19370) (#19388)

PR #18858 set the internal dnceng Azure Artifacts feed as the customer
default for npm operations. This breaks `aspire agent init`: npm resolves
a tarball's transitive dependencies through --registry, and the dnceng
pull-through feed returns 401 anonymously for packages it hasn't cached
(e.g. playwright / playwright-core), so `npm install -g <.tgz>` fails with
E401. It also shipped the internal feed as the default in generated
Dockerfiles and `aspire new` templates.

Restore the public npm registry (https://registry.npmjs.org/) as the
customer-facing default across:
- Aspire.Cli NpmRunner (npm view/pack/install pass --registry)
- Generated pnpm Dockerfile NPM_REGISTRY default (still overridable at
  build time via --build-arg NPM_REGISTRY=...)
- Shipped ts-starter / py-starter / aspire-ts-cs-starter template
  lockfiles (resolved URL host only; versions and integrity hashes
  are unchanged)

Security hardening is retained: --ignore-scripts on the global install
and Sigstore provenance + SRI integrity verification. Repo-internal
lockfiles and CI images intentionally remain on the internal feed.

Fixes #19370

Co-authored-by: David Pine <t@t.test>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 3b7c7a65-f065-49bc-8122-83e9f9429b5f

* Use public registry for release template lockfile

The release/13.5 lockfile still contained entries from an older internal npm mirror that was no longer present on main when #19388 was merged. Convert those resolved URL hosts as well while preserving the release branch package versions, dependency graph, and integrity values.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 3b7c7a65-f065-49bc-8122-83e9f9429b5f

---------

Co-authored-by: David Pine <david.pine@microsoft.com>
Co-authored-by: David Pine <t@t.test>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 3b7c7a65-f065-49bc-8122-83e9f9429b5f
@github-actions github-actions Bot locked and limited conversation to collaborators Sep 15, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners

Projects

None yet

Development

Successfully merging this pull request may close these issues.

npm registry hard-coded to internal dnceng feed — breaks aspire agent init, and ships as the customer default

4 participants