Add Aspire CLI npm package release integration#17297
Conversation
Create pointer and RID-specific npm packages from the native CLI archives and wire npm packaging, verification, and staging into the existing native CLI package build. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add a design spec for the npm package POC and targeted comments explaining the launcher cache, generated package map, npm metadata, and package verification assumptions. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Document the npm and native package examples that shaped the Aspire CLI npm package POC, including optional platform packages, libc-specific packages, and writable-cache guidance. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Create .github/workflows/publish-npm.yml for manual npm package publishing - Support workflow_dispatch with inputs for version, run_id, dist_tag, pr_number, only_rid, skip_meta, and dry_run - Enable npm provenance via id-token: write permission for Trusted Publisher OIDC - Require admin/maintain permission for non-dry-run publishes - Download artifacts from specified GitHub Actions run_id - Publish RID packages before meta package with fail-fast: false matrix - Wait for RID packages to propagate on npm before publishing meta package - Support fallback to NPM_TOKEN secret until Trusted Publisher OIDC is configured - Include recovery options via only_rid and skip_meta inputs - Generate workflow summary with job status and next steps - Update docs/specs/npm-cli-package.md with publishing section and prerequisites Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…tion The MISSING_PACKAGES counter was incremented inside a pipeline subshell and never propagated to the parent shell, causing the verification check to always see 0 and never fail on missing tarballs. Changed from pipeline (echo | jq | while) to process substitution (while < <(echo | jq)) so the while loop runs in the main shell and variable updates are visible to the later check. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
When dry_run=true, wait-for-packages is skipped, which previously allowed publish-meta-package to start without waiting for publish-rid-packages to complete. This violated the spec requirement that RID packages must be published/validated before the meta package. Changes: - Add publish-rid-packages to publish-meta-package job needs - Update if condition to require publish-rid-packages.result == 'success' - Preserve existing behavior: wait-for-packages can be skipped (dry run) but only after RID packages complete successfully Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…eout
Address code review findings:
1. Exact version matching for tarballs:
- Replace broad patterns (microsoft-aspire-cli-$RID-*.tgz) with exact
version patterns (microsoft-aspire-cli-$RID-$VERSION.tgz)
- Apply to download verification, publish-rid-packages, and
publish-meta-package steps
- Improve error messages to show exact expected filename when missing
2. Configurable propagation timeout:
- Add propagation_timeout_seconds workflow input (default 900s = 15min)
- Validate input is positive integer in validate job
- Compute MAX_ATTEMPTS from timeout/sleep interval, rounding up
- Include timeout in workflow summary and parameter output
- Preserve bounded polling and dry-run skip behavior
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Publishing the @microsoft/aspire-cli scoped npm packages now happens via the AzDO release pipeline (eng/pipelines/release-publish-nuget.yml) using the MicroBuild ESRP publish template, instead of the previous GitHub Actions publish-npm.yml workflow. The release pipeline extends from 1ES.Official.Publish.yml@MicroBuildTemplate so it has access to the DevDivEsrpAzDoSrvConn service connection. Per-platform artifacts and the pointer package are produced and verified during the source build (azure-pipelines.yml + build_sign_native.yml), then flat-shipped via BlobArtifacts (eng/Publishing.props). The release pipeline splits them into RID and pointer pipeline-artifact folders, attaches SBOMs, and submits two MicroBuild.Publish.yml invocations (RID packages first, then pointer) with a configurable propagation delay so the pointer never resolves to a missing optional dependency. Also fixed a cross-platform path bug in eng/clipack/Common.projitems where $(RepoRoot)eng\\scripts\\pack-cli-npm-package.ps1 mixed separators in a way that breaks pwsh resolution on Linux/macOS, and added the actions/setup-node step missing from .github/workflows/build-cli-native-archives.yml now that PackDotnetTool depends on PackNpmPackage (which calls npm pack). Note: the npm contentType for MicroBuild.Publish.yml is documented in the ESRP onboarding doc but the task itself is not yet shipped for npm. The release pipeline is wired against the documented parameter shape so it can go live the moment the task is available; today's release flow can run with SkipNpmPublish=true. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Brings the npm package path to parity with the brew cask / winget manifest flows: * Add Aspire.Cli.Utils.NpmInstallDetection so 'aspire update --self' and update notifications detect global npm installs via the ASPIRE_NPM_PACKAGE/_VERSION/_RID env vars the launcher already sets, and print 'npm install -g @microsoft/aspire-cli@latest' instead of running the GitHub-binary downloader against npm-owned files. Wired into UpdateCommand (--self path and post-project-update prompt) and CliUpdateNotifier. * Tighten launcher cache freshness in eng/clipack/npm/aspire.js: compare both size and mtime so a stale cache from a prior same-version install cannot shadow a freshly extracted native binary. * Add eng/pipelines/templates/prepare-npm-cli-packages.yml that runs a real 'npm install -g <rid>.tgz && npm install -g --omit=optional <pointer>.tgz' against the just-built tarballs on a scratch npm prefix, asserts 'aspire --version' matches the build version, verifies the launcher's cache layout, uninstalls, and emits validation-summary.json. Wired into the Prepare Installers stage in azure-pipelines.yml alongside Homebrew and WinGet. * Gate release-publish-nuget.yml on the validation summary before invoking MicroBuild.Publish for npm. Download the summary from the source build, re-publish with SBOM in stage 1, then refuse to submit unless validatedByPreparePipeline is true and every required check passed. * Fix a pre-existing here-string parse bug in the 'Prepare npm Artifacts for Publishing' step. PowerShell requires the closing terminator at column 0, but YAML block scalars require every line to stay at or above the block indent. Compose the error message from an array joined with [Environment]::NewLine instead. * Drop POC framing from docs/specs/npm-cli-package.md and document the Sigstore-provenance tradeoff honestly (ESRP's npm publish path does not currently emit Sigstore attestations; integrity is anchored at the signed binary and the Microsoft1ES maintainer identity). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Two adversarial-review findings from local repro of the install-test: 1) prepare-npm-cli-packages: initialize NpmCheck* task variables to 'failed' at the start of the install-test step. If a subsequent bash command exits via 'set -e' before the matching pass marker runs, the summary JSON now records 'failed' instead of an unexpanded '$(NpmCheckXxx)' AzDO token. The release-side gate already rejects anything that is not 'passed', but 'failed' is a much higher-signal diagnostic. 2) prepare-npm-cli-packages: tighten 'aspire --version' parsing. Use a semver-shaped regex against the full output and print the raw output for diagnostics, instead of blindly trusting 'tail -n 1'. System.CommandLine's VersionOption normally just prints the version and exits, but defending against a stray warn/info line makes failures self-explanatory. 3) release-publish-nuget: defense-in-depth — the gate now explicitly rejects status values that still look like an unexpanded '$(SomeVar)' token, in addition to the '!= passed' check. This catches future schema drift in the prepare template too. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
@copilot review |
…ackage-followups # Conflicts: # docs/release-process.md # eng/pipelines/release-publish-nuget.yml # src/Aspire.Cli/Commands/UpdateCommand.cs # src/Aspire.Cli/Resources/UpdateCommandStrings.Designer.cs # src/Aspire.Cli/Resources/UpdateCommandStrings.resx # src/Aspire.Cli/Utils/CliUpdateNotifier.cs Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
🚀 Dogfood this PR with:
curl -fsSL https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.sh | bash -s -- 17297Or
iex "& { $(irm https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.ps1) } 17297" |
…i-package-followups # Conflicts: # docs/release-process.md # eng/pipelines/azure-pipelines.yml # eng/pipelines/release-publish-nuget.yml Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Block prerelease npm publishes until non-latest dist-tags are supported, validate npm install summaries across Windows/Linux/macOS, and make launcher cache replacement avoid deleting the previous executable before rename. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Use Node 22 for native CLI npm packaging and install-validation CI paths. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Fail npm publish preflight validation before any irreversible NuGet publishing step so release runs cannot partially publish NuGet packages and then fail on npm ESRP/prerelease prerequisites. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Release dry-runs do not upload GitHub release assets, so LiveRelease Homebrew validation cannot pass for a new version without mutating the release. Switch Homebrew validation to LiveArchives when DryRun=true while preserving LiveRelease for non-dry releases. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This reverts commit ddfea5c.
Add ESRP publish-template and owner invariant coverage, live npm registry smoke validation before channel promotion, a pointer-publish skip for safe reruns, and npm-installed CLI update tests. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Applies the dedicated Corepack pinning and Yarn cache seeding diff from microsoft#17630 instead of keeping a local source-build workaround on this branch. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
23f527f to
0d27405
Compare
adamint
left a comment
There was a problem hiding this comment.
PR review while validating internal CI / release dry-run end-to-end. 3 concrete issues to address:
eng/clipack/npm/aspire.js— launcher comment vs. code mismatch; concurrent first-runs can fail on Windows.eng/pipelines/release-publish-nuget.yml— registry smoke-testfinallyblock can mask a successful run on Windows.eng/clipack/npm/aspire.js— unbounded per-version cache growth; no eviction or documented cleanup.
No style / nit comments. Internal CI (build 2987420) and release pipeline 1600 dry-run still in progress — I'll comment separately with the dry-run report.
- aspire.js: when the atomic rename of a freshly copied native binary fails (e.g. concurrent first-runs racing on Windows where the cached executable is already loaded), check whether the existing target is already a valid copy of the source via needsCopy(). If it is, the other process won the race and our tmp file can be discarded without failing the launcher. Only unexpected errors propagate. - release-publish-nuget.yml: wrap the post-smoke Remove-Item cleanup in the finally block in a try/catch with -ErrorAction Stop and a Write- Warning fallback so a transient Windows file-handle lock during temp- directory teardown does not mask a successful npm registry smoke test. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
Addressed the adversarial review findings from review #4392976259 in b6350b4:
Pushed to |
GitHub Actions failures are pre-existing
|
The macOS AzDO runner executes Bash@3 tasks with /bin/bash which is
still Bash 3.2 on every shipping macOS release. The 'Locate pointer
and RID tarballs' step in 'npm install validation (macOS native RID)'
was failing with:
/Users/runner/work/_temp/<id>.sh: line 10: shopt: globstar: invalid shell option name
Bash exited with code '1'.
Two constructs in the script require Bash 4+:
- 'shopt -s globstar' (not in 3.2; we never used '**' anyway since
we enumerate with 'find')
- 'mapfile -t' (not in 3.2)
Replace both with a portable 'find | while IFS= read' loop that works
on Bash 3.2 and survives filenames containing spaces. Verified locally
under GNU bash 3.2.57.
Add a regression test in Infrastructure.Tests that fails the build if
'shopt -s globstar', 'mapfile', 'readarray', or 'declare -A' are
reintroduced into the npm install validation template.
Dry-run AzDO build 2987449 (Build def 1602) caught this on the macOS
'Prepare Installers' phase; linux-x64 and win-x64 are unaffected
because their bash is already 4+.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Dry-run progress updatePushed Why: dry-run build Root cause: macOS still ships
Fix: replaced both with a portable Added regression test in Queued dry-run build
|
Pulls in microsoft#17701 (Fix TypeScript deadlock repro E2E test) so PR GitHub Actions can complete. Main has been broken for PR events since microsoft#17575 added a test calling RunCommandFailFastAsync which microsoft#17588 renamed to RunCommandAsync. microsoft#17701 updates the call sites. No infra changes from this branch are affected by this merge. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Dry-run AzDO build 2987514 progressed past the macOS Bash 3.2 fix and
then failed the install/verify/uninstall smoke on macOS with:
Raw output: 13.5.0-preview.1.26279.34+727fe3ca9dcecbcc6d10d8b4373ae6f5779b25b4
Reported version:
##[error]aspire --version reported '' but expected '13.5.0-preview.1.26279.34'
The CLI's --version prints the InformationalVersion which is full SemVer 2.0
(MAJOR.MINOR.PATCH-PRE+BUILDMETA where BUILDMETA is the source commit SHA).
The previous regex required the line to end at the pre-release segment so
the +<sha> suffix made the whole match fail and actualVersion became empty.
Extend the regex to optionally accept '+<buildmeta>', then strip it with the
portable POSIX expansion '${var%+*}' before comparing to the npm package
version (npm SemVer intentionally ignores build metadata for equality per
https://semver.org/#spec-item-10).
The PowerShell post-publish smoke in release-publish-nuget.yml already
handles this case (line ~1298, regex ends with '(\\+.*)?$') so no change
needed there.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Dry-run progress update (2)Pushed Why: dry-run build Root cause: The CLI's Fix: extend the regex to optionally accept Linux x64 and Windows x64 npm install validation phases were in progress and would have hit the same regex bug; I cancelled the build to save runner time. Queued dry-run build
|
…ol hang The pointer package declares every supported RID as an optionalDependency pinned to the just-built version. Even with --omit=optional, npm still resolves optional dep metadata from the registry while building the dependency tree, and in network-isolated 1ES Linux/Windows pools each of the 7 lookups burns the full fetch-timeout. Dry-run build 2987581 hit a 9-minute hang on the pointer install step for that reason while macOS (unrestricted egress, fast 404) completed in 3 seconds. Pair --omit=optional with --offline so npm never touches the network for this validation: optional deps are skipped without a resolution attempt and the local tarball installs straight from disk. A short --fetch-timeout=15000 is set as belt-and-suspenders. NPM_CONFIG_CACHE already points at a fresh empty directory so --offline cannot reuse a poisoned cache. Local verification against a synthetic 8-dep pointer shows installation completes in 121ms with optional deps marked UNMET (not fetched, not installed); uninstall completes in 88ms. Apply the same args to the uninstall step so an audit/funding call cannot hang the cleanup the way it almost hung the install. Add a PrepareNpmCliPackagesScriptInstallsOfflineWithTimeout regression test to prevent a refactor from quietly removing the flags. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
Status update on the npm install validation hang: Diagnosis: Fix (
Regression test: Build 2987581 cancelled (Windows still hung on the same step). Fresh dry-run build 2987640 queued at |
Re-imports the latest Corepack install template + pinned version + Yarn preparation script from the sibling PR. Required to share the same Corepack pin between the npm-publishing release pipeline and the extension build, and to keep Bash 3.2-safe wiring in place. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* loadRidPackageNames() now runs lazily from main() and surfaces a friendly 'installation is corrupted ... Reinstall' error rather than a raw Node stack trace when the JSON map is missing or malformed. Previously the read happened at module top-level, bypassing the launcher's outer try/catch. * Detect Linux musl on arm64 and throw 'Unsupported platform' rather than silently falling through to the glibc-linked linux-arm64 binary (which crashes at exec with a dynamic-linker error). * Forward SIGINT, SIGTERM, SIGHUP and SIGQUIT to the child process. Previously `kill <wrapper-pid>` orphaned the native CLI process, which broke programmatic shutdown of long-running commands like 'aspire run' that keep an AppHost alive. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The previous expandable here-string (@"..."@) interpreted both the markdown code-span backticks AND $Rid / $PackageName as PowerShell escape sequences and interpolations. Result: the shipped README on npmjs.org rendered as 'Native Aspire CLI binary for $Rid.' with no backticks visible. Switch to a non-expanding here-string (@'...'@) plus -replace for __RID__, __PACKAGE_NAME__ and __RID_PACKAGE_NAME__ placeholders so the markdown code spans survive verbatim. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…rsion * Add 'Verify npm RID Packages Present Before Pointer Publish' step that extracts the pointer tgz, walks its optionalDependencies, and runs 'npm view <dep>@<version>' for each. If any RID dep is missing on the registry, fail the publish before ESRP submits the pointer. This closes a window where SkipNpmRidPublish=true, an operator partial run, or an ESRP RID-publish failure could ship a pointer package that resolves on install but throws 'native package was not installed' on first 'aspire' invocation. * The preflight reads RIDs from the pointer's own optionalDependencies so it does not drift if RIDs are added or removed. * In the post-publish version smoke, explicitly reject the case where 'aspire --version' exits 0 with empty stdout. The previous @(...) -notmatch sequence produced an empty array on no output, which is falsy in PowerShell and let the bad install slip past the version regex check. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Six new asserts pinning the fixes from the multi-model code review: * RID preflight is wired before the pointer publish step * Empty 'aspire --version' stdout is rejected by the post-publish smoke * Launcher throws on Linux musl arm64 * Launcher forwards SIGINT/SIGTERM/SIGHUP/SIGQUIT to the child process * Launcher loads the RID package map lazily and emits a friendly 'installation is corrupted ... Reinstall' error * pack-cli-npm-package.ps1 uses a literal here-string so markdown backticks survive in the published RID README Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
🔁 Dry-run status update — applied multi-model code-review fixes + resynced with #17630 head New commits (5):
Issues found / fixed:
Regression test coverage:
All 12 Dry-run pipeline status:
Cancelled stale build 2987640. |
Use 'MicroBuild.1ES.Official.Publish.yml@MicroBuildTemplate' (composite) instead of '1ES.Official.Publish.yml@MicroBuildTemplate' (plain). Without the 'MicroBuild.' prefix, the MicroBuildAuthorizePublishPlugin task is auto-injected without credential context, causing a 401 against devdiv.pkgs.visualstudio.com/_packaging/MicroBuildToolset. Pattern verified against microsoft/vscode-azuretools, microsoft/pyright, microsoft/vscode-python-environments, microsoft/vscode-deviceid, and microsoft/vscode-common-python-lsp release pipelines — all of which use the composite template for ESRP-based npm publishing. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…s template The MicroBuild. prefix is required so the auto-injected MicroBuildAuthorizePublishPlugin task inherits credential context for the devdiv MicroBuildToolset feed. Without it, the task fails with a 401 in the PrepareArtifacts stage before any publishing can begin. Verified against microsoft/vscode-azuretools, microsoft/pyright, and microsoft/vscode-python-environments — all use the MicroBuild. prefix. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The MicroBuild.1ES.Official.Publish.yml@MicroBuildTemplate extends template auto-injects two tasks into every job, both of which were failing in release 2987726: 1. MicroBuildAuthorizePublishPlugin@0 (start of every job) - Defaulted to fetching its nuget package from devdiv.pkgs.visualstudio.com/_packaging/MicroBuildToolset - This pipeline runs in the dnceng collection which does not have devdiv feed credentials - Result: HTTP 401 fails the stage before any customer step runs 2. MicroBuildCleanup@1 (end of every job, displayed as 'MicroBuild Telemetry') - Hard-requires a pipeline variable literally named TeamName - We had _TeamName (Arcade convention) but not TeamName Fixes (both surfaced from MicroBuildTemplate Jobs/PublishJob.yml + Jobs/Job.yml): * Add 'TeamName: dotnet-aspire' at pipeline-scope variables so MicroBuildCleanup@1 succeeds on every job. * On the only job that actually performs an ESRP publish (ReleaseJob via 1ES.PublishNuget@1 / MicroBuild.Publish.yml), set templateContext.mb.publish.feedSource to the dnceng MicroBuildToolset mirror (https://pkgs.dev.azure.com/dnceng/_packaging/MicroBuildToolset/nuget/v3/index.json). This is the same pattern dotnet/roslyn uses. The dnceng feed is accessible to builds in this collection automatically. * On every other job (PrepareJob, WinGetJob, DispatchGitHubTasksJob, PublishReleaseAssetsJob, HomebrewValidateJob), set templateContext.mb.publish.enabled: false. These jobs only download artifacts, push to GitHub via app tokens, or run validation; none of them publish via ESRP, so the publish-authorize plugin should not run at all. Adds two regression tests in ReleasePublishNugetPipelineTests so a future edit that removes TeamName or removes the publish auth overrides fails before the pipeline is queued again. Verified against MicroBuild template source pulled from dev.azure.com/devdiv/MicroBuildTemplates/MicroBuildTemplates (Stages/PublishStage.yml, Jobs/PublishJob.yml, Jobs/Job.yml). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…sanity, Node 20, CRLF strip
Multi-model code review (Aspire arch, Opus 4.8, Opus 4.7) surfaced eight items.
The highest-severity issues fixed here are:
1. CRLF regression in Windows install validation (opus-4.7 — blocker)
- prepare-npm-cli-packages.yml bash captures 'aspire --version' on Win
runners under Git Bash. System.CommandLine 2.x writes CRLF on Windows,
bash $() strips LF but NOT CR, anchored semver regex fails on \r.
- Fix: pipe through 'tr -d "\r"' before capture. This regressed in
commit debf4eb when 'tr -d [:space:]' was replaced with 'grep -Eo'.
Dry run 2987740 did NOT exercise this path because SkipNpmPublish=true
skips the consumer; Monday's real publish would have failed.
2. Preflight registry pin (opus-4.8)
- 'npm view $spec version' in pointer preflight relied on the agent's
ambient registry. 1ES images may have internal mirrors via .npmrc /
npm_config_registry which (a) could spuriously fail after a successful
public publish or (b) pass against a stale mirror and ship a broken
pointer to npmjs.
- Fix: add explicit '--registry=https://registry.npmjs.org/' pin.
3. Preflight retry loop (opus-4.8)
- Single-shot preflight could fail closed AFTER 7 RID packages are
already published, forcing manual SkipNpmRidPublish=true re-run.
- Fix: wrap in 10x30s retry, matching post-publish smoke.
4. Strict semver-shape filter on 'npm view' output (opus-4.8)
- 'npm view --loglevel=warn 2>&1' merges deprecation / peer-dep /
EBADENGINE warnings onto stdout. 'Select-Object -First 1' could latch
a warning as the version.
- Fix: filter to lines matching strict semver regex, and switch metadata
'npm view' to 2>$null.
5. PGP .sig content sanity check (opus-4.8)
- Earlier validation only checked .tgz.sig EXISTS. If Arcade SignTool
silently produced an empty/garbage sidecar (signing service hiccup,
plugin misconfig), the release would publish unverifiable sidecars.
- Fix: assert each sig >=64 bytes AND contains an OpenPGP marker
(ASCII-armored '-----BEGIN PGP SIGNATURE-----' OR binary packet
tag 2 per RFC 9580 — old-format 0x88-0x8B / new-format 0xC2).
Added to BOTH source build (BuildAndTest.yml) AND release pipeline
so failures surface at PR-time, not just release-time.
6. Node >=20 minimum (Aspire arch review)
- aspire.js wrapper uses '{ cause: error }' (Node 16.9+) and rid->arch
map covers musl-libc selector (npm >=10.7). 'engines.node = >=16'
was technically permissive enough to install on Node 16.x where
'cause' is rejected.
- Fix: bump to '>=20' (covers all Node 16.9+ + libc + ESM-safe
subprocess + Node 18 EOL was 2025-04-30).
Validation:
- All 21 Infrastructure.Tests pass locally (was 14, added 7 regression tests).
- Dry-run on release pipeline 2987740 already validated MicroBuild paths;
this batch hardens against issues that would only have surfaced when
SkipNpmPublish=false on Monday.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
✅ Monday release dry-run: HIGH confidenceCompleted comprehensive end-to-end dry-run validation against the internal Validation runs
¹ Only What was exercised end-to-end
Hardening landed (from multi-model review — Opus 4.7/4.8, GPT 5.5, Aspire-arch)
Source-build pinning gotcha (carry forward)The classic Monday checklist
Constraint compliance
|
Description
This completes the production path for distributing the Aspire CLI through npm while keeping publishing under the existing Microsoft release process.
The PR now:
@microsoft/aspire-clias the pointer package plus RID-specific packages such as@microsoft/aspire-cli-linux-x64,@microsoft/aspire-cli-win-x64, and@microsoft/aspire-cli-osx-arm64.aspire updatecan point npm-installed users atnpm update -g @microsoft/aspire-cli.docs/specs/npm-cli-package.mdanddocs/release-process.md.Security considerations
The
.tgzcontainer is not separately signed. Integrity relies on the signed native CLI payloads where platform signing applies, CI verification that npm package binaries match the signed native archives, SBOM-covered release artifacts, ESRP/MicroBuild submission controls, and npm registry integrity. Publishing does not use repository-scoped npm tokens or GitHub Actions Trusted Publisher; release operators must provide ESRP owners/approvers through the release pipeline parameters.Fixes #17045
Checklist
<remarks />and<code />elements on your triple slash comments?aspire.devissue:Validation:
./restore.sheng/pipelines/release-publish-nuget.yml,eng/pipelines/azure-pipelines.yml, andeng/pipelines/azure-pipelines-unofficial.ymleng/Publishing.propsdotnet test --project tests/Infrastructure.Tests/Infrastructure.Tests.csproj --no-launch-profile -- --filter-class "*.StageNativeCliToolPackagesTests" --filter-not-trait "quarantined=true" --filter-not-trait "outerloop=true"(12 passed)git diff --check