Add runtime-driven canary and unstable SDK publishing - #2544
Add runtime-driven canary and unstable SDK publishing#2544MackinnonBuck wants to merge 6 commits into
Conversation
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Critical argument-validation and moderate provenance, version-comparison, and SemVer handling issues remain unresolved.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review tier: Balanced
Findings: 1
New issues introduced by this change (5)
| Severity | Finding |
|---|---|
nodejs/scripts/runtime-package-acquisition.ts — Missing or misspelled required flags are silently converted to empty strings. In particular,… |
|
.github/workflows/publish.yml — runtime_run_id is only checked for numeric syntax and then copied into the release manifest;… |
|
.github/workflows/publish.yml — This substring match can select and test a different runtime version whose output merely contains… |
|
.github/workflows/sdk-canary.yml — This is a substring check, so a different runtime version can pass (for example, expected 1.0.8… |
|
.github/workflows/sdk-canary.yml — SemVer permits build metadata. If the public latest is 1.2.3+build, this leaves PATCH=3+build;… |
What changed in this PR
Adds gated canary and unstable Node SDK publishing with deterministic versioning, runtime acquisition, integrity-aware manifests, and recovery support.
Changes:
- Adds runtime acquisition, versioning, manifest, and publishing helpers.
- Reworks canary and unstable workflows with cross-platform validation.
- Adds focused release tests and operator documentation.
| File | Description | Review |
|---|---|---|
nodejs/test/unstable-version.test.ts |
Tests deterministic unstable versions. | No unresolved comments. |
nodejs/test/runtimeArtifacts.test.ts |
Tests local runtime selection. | No unresolved comments. |
nodejs/test/runtime-package-acquisition.test.ts |
Tests runtime acquisition and validation. | No unresolved comments. |
nodejs/test/release-workflows.test.ts |
Tests workflow contracts. | No unresolved comments. |
nodejs/test/release-manifest.test.ts |
Tests manifest integrity. | No unresolved comments. |
nodejs/test/npm-release.test.ts |
Tests integrity-aware publishing. | No unresolved comments. |
nodejs/scripts/unstable-version.ts |
Calculates deterministic unstable versions. | No unresolved comments. |
nodejs/scripts/set-cli-version.js |
Adds local-package mode. | No unresolved comments. |
nodejs/scripts/runtime-package-acquisition.ts |
Acquires exact runtime packages. | Critical (1 vote): Reject unknown, duplicate, missing, and incomplete arguments before filesystem operations; a missing --output currently targets the working directory. |
nodejs/scripts/releaseArtifacts.ts |
Supports pre-acquired runtime roots. | No unresolved comments. |
nodejs/scripts/release-manifest.ts |
Creates and verifies release manifests. | No unresolved comments. |
nodejs/scripts/npm-release.js |
Publishes package sets with integrity checks. | No unresolved comments. |
nodejs/README.md |
Documents runtime package inputs. | No unresolved comments. |
nodejs/package.json |
Adds release helper commands. | No unresolved comments. |
docs/developer-docs/unstable-releases.md |
Adds the operator runbook. | No unresolved comments. |
docs/developer-docs/secrets.md |
Documents token permissions. | No unresolved comments. |
.github/workflows/sdk-canary.yml |
Reworks gated canary packaging. | Moderate (1 vote each): Strip SemVer build metadata before patch arithmetic; replace substring runtime-version checks at lines 217 and 360 with exact parsed comparisons. |
.github/workflows/publish.yml |
Adds gated unstable publishing. | Moderate (1 vote each): Validate runtime_run_id provenance against the source repository and runtime metadata; replace substring runtime-version checks at lines 535 and 686 with exact parsed comparisons. |
Suppressed comments (2)
.github/workflows/publish.yml:686
- This release gate checks only that the expected text occurs somewhere in the output, so a clean install with a different version such as
1.0.83can satisfy an expected1.0.8. Parse the runtime's reported version and require exact equality before allowing public publication.
"$RUNTIME" --version | grep -F "$RUNTIME_VERSION"
.github/workflows/sdk-canary.yml:360
- The clean-install gate uses a substring match, so it can accept the wrong embedded runtime when the requested version is a prefix of the actual one (for example,
1.0.8versus1.0.83). Parse the emitted version and require exact equality so this gate proves the package contains the selected runtime.
"$RUNTIME" --version | grep -F "$RUNTIME_VERSION"
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| function parseArguments(args: string[]): AcquireRuntimePackagesOptions { | ||
| const values = new Map<string, string>(); | ||
| for (let index = 0; index < args.length; index += 2) { | ||
| const key = args[index]; | ||
| const value = args[index + 1]; | ||
| if (!key?.startsWith("--") || !value) { | ||
| throw new Error( | ||
| "Usage: runtime-package-acquisition.ts --version <version> --sha <sha> --registry <url> --output <directory>" | ||
| ); | ||
| } | ||
| values.set(key, value); | ||
| } | ||
| return { | ||
| runtimeVersion: values.get("--version") ?? "", | ||
| runtimeSha: values.get("--sha") ?? "", | ||
| registry: values.get("--registry") ?? "", | ||
| outputDirectory: values.get("--output") ?? "", | ||
| }; | ||
| } |
| [[ "$RUNTIME_SHA" =~ ^[0-9a-f]{40}$ ]] || | ||
| { echo "::error::runtime_sha must be a lowercase full SHA."; exit 1; } | ||
| [[ "$RUNTIME_RUN_ID" =~ ^[0-9]+$ ]] || | ||
| { echo "::error::runtime_run_id must be numeric."; exit 1; } |
| set -euo pipefail | ||
| node scripts/set-cli-version.js "$RUNTIME_VERSION" --local-package | ||
| runtime_path="$(npm run --silent prepare:runtime -- --print-path)" | ||
| "$runtime_path" --version | grep -F "$RUNTIME_VERSION" |
| node "$legacy_path" --version | grep -F "$RUNTIME_VERSION" | ||
| node scripts/set-cli-version.js "$RUNTIME_VERSION" --local-package | ||
| runtime_path="$(npm run --silent prepare:runtime -- --print-path)" | ||
| "$runtime_path" --version | grep -F "$RUNTIME_VERSION" |
|
|
||
| - name: Set package and runtime versions | ||
| PUBLIC_LATEST="$(node scripts/get-version.js current)" | ||
| BASE="${PUBLIC_LATEST%%-*}" |
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
This comment has been minimized.
This comment has been minimized.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: d81fc7cf-d30a-470e-b7bf-42a02f62841d
SDK Consistency ReviewScope of PR #2544: This PR only modifies Node.js release/publishing infrastructure — GitHub Actions workflows ( No changes touch SDK client code in any language ( Conclusion: These changes concern npm-specific release/packaging mechanics (unstable version tagging, runtime binary acquisition/dispatch, publish workflow validation) that are inherently tied to the Node.js/npm ecosystem and its distribution model. This is analogous to a "language-specific optimization" — it does not need to be mirrored in other SDKs, since each language has its own independent release/packaging pipeline outside the scope of this PR. ✅ No cross-SDK consistency issues found.
|
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: d81fc7cf-d30a-470e-b7bf-42a02f62841d
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: d81fc7cf-d30a-470e-b7bf-42a02f62841d


Summary
publish.ymlas the normal stable/prerelease publisher with no runtime handoff or unstable path, and reserve thecanaryandunstableprerelease namespaces for runtime-driven releasesruntime-sdk.ymlas the unified runtime-driven Node SDK entry for canary and unstable, and as the second public npm trusted-publisher identityruntime-backed-node-release.ymlfor exact eight-platform runtime acquisition, Ubuntu/macOS/Windows tests, one nine-package build and retained manifest, and optional internal Azure publication/verificationruntime_run_idartifact ledger with serialized claiming, API provenance validation, bounded artifact-index retries, canonical-run mirroring, and collision rejectionRuntime dispatch contract
runtime-sdk.ymlacceptschannel,runtime_version,runtime_sha,runtime_source,runtime_run_id, andmode. Canary permits onlyazurewithtests-only|internal; unstable permits onlygithub-packageswithinternal. Direct manual unstable runs additionally support an optionalversion.Duplicate dispatches wait for and mirror the canonical SDK workflow run. Failed or canceled canonical runs must be rerun directly; no cross-run release recovery path exists.
Validation