From cead96b3a06f68f5c482d940de4e040a4d94b376 Mon Sep 17 00:00:00 2001 From: Sergey Zelenov Date: Mon, 18 May 2026 12:28:06 +0200 Subject: [PATCH 1/3] chore(NODE-7562): migrate 6.x release workflows to npm trusted publishers Replace NPM_TOKEN with OIDC dispatch to npm-publish.yml in release-6.x.yml, release-alpha.yml, and release-nightly.yml; add dispatch-and-wait.mjs; remove dormant release-6.8.yml. --- .github/scripts/dispatch-and-wait.mjs | 73 +++++++++++++++++ .github/workflows/release-6.8.yml | 113 -------------------------- .github/workflows/release-6.x.yml | 14 ++-- .github/workflows/release-alpha.yml | 15 ++-- .github/workflows/release-nightly.yml | 12 ++- 5 files changed, 99 insertions(+), 128 deletions(-) create mode 100644 .github/scripts/dispatch-and-wait.mjs delete mode 100644 .github/workflows/release-6.8.yml diff --git a/.github/scripts/dispatch-and-wait.mjs b/.github/scripts/dispatch-and-wait.mjs new file mode 100644 index 00000000000..8f40a2bf754 --- /dev/null +++ b/.github/scripts/dispatch-and-wait.mjs @@ -0,0 +1,73 @@ +// @ts-check +// TODO(NODE-7570): replace with workflow_call once GitHub/npm resolve the OIDC +// workflow_ref mismatch (https://github.com/npm/documentation/issues/1755). +// +// Dispatch a workflow_dispatch-triggered GitHub Actions workflow and wait for +// the resulting run to complete (propagating its exit status). +// +// `gh workflow run` prints the created workflow run URL on stdout when the +// server returns it (current github.com API version does); we parse the run +// id out of the URL and pass it to `gh run watch`. +// +// Usage: +// node dispatch-and-wait.mjs [key=value ...] +// +// For npm-publish.yml specifically: +// node dispatch-and-wait.mjs npm-publish.yml tag= version= ref= +// +// Arguments: +// Filename of the target workflow under .github/workflows/ +// in the same repo. Must declare `on: workflow_dispatch:`. +// key=value ... Inputs forwarded to the dispatched workflow. Valid keys +// and which of them are required are determined by the +// target workflow's `on.workflow_dispatch.inputs`; the +// dispatch fails if any required input is missing or any +// unknown input is passed. For `npm-publish.yml`, all of +// `tag`, `version`, and `ref` are required. +// Example: tag=nightly version=1.2.3 ref=abc1234 +// +// Environment: +// GH_TOKEN (required) used by the gh CLI; in a workflow set +// this to ${{ github.token }}. +// DISPATCH_WORKFLOW_REF (optional, default `main`) git ref the target +// workflow file is loaded from. Hardcoded to main by +// default so callers on backport branches don't have +// to keep a copy of the target workflow on their +// branch. +import * as child_process from 'node:child_process'; +import * as process from 'node:process'; + +const [, , workflow, ...inputArgs] = process.argv; +if (!workflow) { + console.error('usage: dispatch-and-wait.mjs [key=value ...]'); + process.exit(2); +} + +const dispatchRef = process.env.DISPATCH_WORKFLOW_REF || 'main'; + +const ghArgs = [ + 'workflow', 'run', workflow, + '--ref', dispatchRef, + ...inputArgs.flatMap(kv => ['-f', kv]) +]; +console.log(`Dispatching ${workflow} from ref ${dispatchRef}`); + +const dispatch = child_process.spawnSync('gh', ghArgs, { + encoding: 'utf8', + stdio: ['inherit', 'pipe', 'inherit'] +}); +if (dispatch.status !== 0) process.exit(dispatch.status ?? 1); + +// gh prints e.g. "https://github.com/owner/repo/actions/runs/" +const match = dispatch.stdout.match(/\/actions\/runs\/(\d+)/); +if (!match) { + console.error('Could not extract run id from gh workflow run output:', dispatch.stdout); + process.exit(1); +} +const runId = match[1]; +console.log(`Dispatched run ${runId}`); + +const watch = child_process.spawnSync('gh', ['run', 'watch', runId, '--exit-status'], { + stdio: 'inherit' +}); +process.exit(watch.status ?? 1); diff --git a/.github/workflows/release-6.8.yml b/.github/workflows/release-6.8.yml deleted file mode 100644 index 418c53f0b06..00000000000 --- a/.github/workflows/release-6.8.yml +++ /dev/null @@ -1,113 +0,0 @@ -on: - push: - branches: ['6.8'] - workflow_dispatch: {} - -permissions: - contents: write - pull-requests: write - id-token: write - -name: release-68 - -jobs: - release_please: - runs-on: ubuntu-latest - outputs: - release_created: ${{ steps.release.outputs.release_created }} - steps: - - id: release - uses: googleapis/release-please-action@v4 - with: - target-branch: '6.8' - - build: - needs: [release_please] - name: 'Perform any build or bundling steps, as necessary.' - uses: ./.github/workflows/build.yml - - ssdlc: - needs: [release_please, build] - permissions: - # required for all workflows - security-events: write - id-token: write - contents: write - environment: release - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v5 - with: - ref: '6.8' - - - name: Install Node and dependencies - uses: mongodb-labs/drivers-github-tools/node/setup@v2 - with: - ignore_install_scripts: false - - - name: Load version and package info - uses: mongodb-labs/drivers-github-tools/node/get_version_info@v2 - with: - npm_package_name: mongodb - - - name: actions/compress_sign_and_upload - uses: mongodb-labs/drivers-github-tools/node/sign_node_package@v2 - with: - aws_role_arn: ${{ secrets.AWS_ROLE_ARN }} - aws_region_name: us-east-1 - aws_secret_id: ${{ secrets.AWS_SECRET_ID }} - npm_package_name: mongodb - dry_run: ${{ needs.release_please.outputs.release_created == '' }} - - - name: Copy sbom file to release assets - shell: bash - if: ${{ '' == '' }} - run: cp sbom.json ${{ env.S3_ASSETS }}/sbom.json - - # only used for mongodb-client-encryption - - name: Augment SBOM and copy to release assets - if: ${{ '' != '' }} - uses: mongodb-labs/drivers-github-tools/sbom@v2 - with: - silk_asset_group: '' - sbom_file_name: sbom.json - - - name: Generate authorized pub report - uses: mongodb-labs/drivers-github-tools/full-report@v2 - with: - release_version: ${{ env.package_version }} - product_name: mongodb - sarif_report_target_ref: '6.8' - third_party_dependency_tool: n/a - dist_filenames: artifacts/* - token: ${{ github.token }} - sbom_file_name: sbom.json - evergreen_project: mongo-node-driver-next - evergreen_commit: ${{ env.commit }} - - - uses: mongodb-labs/drivers-github-tools/upload-s3-assets@v2 - with: - version: ${{ env.package_version }} - product_name: mongodb - dry_run: ${{ needs.release_please.outputs.release_created == '' }} - - publish: - needs: [release_please, ssdlc, build] - environment: release - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v5 - with: - ref: '6.8' - - - name: Install Node and dependencies - uses: mongodb-labs/drivers-github-tools/node/setup@v2 - - # Just picking a string to put here so that releases from this branch are not marked "latest", - # we should go and rm-dist-tag after this is published, no reason to keep it tagged. - - run: | - npm publish --provenance --tag=tag-for-publishing-older-releases - npm dist-tag rm mongodb tag-for-publishing-older-releases - if: ${{ needs.release_please.outputs.release_created }} - env: - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/.github/workflows/release-6.x.yml b/.github/workflows/release-6.x.yml index eb3366ecf2c..452e6abdc42 100644 --- a/.github/workflows/release-6.x.yml +++ b/.github/workflows/release-6.x.yml @@ -6,7 +6,7 @@ on: permissions: contents: write pull-requests: write - id-token: write + actions: write name: release-6.x @@ -96,10 +96,12 @@ jobs: steps: - uses: actions/checkout@v5 - - name: Install Node and dependencies - uses: mongodb-labs/drivers-github-tools/node/setup@v2 - - - run: npm publish --provenance --tag=6x + - name: Dispatch npm-publish workflow if: ${{ needs.release_please.outputs.release_created }} env: - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + GH_TOKEN: ${{ github.token }} + run: | + node ./.github/scripts/dispatch-and-wait.mjs npm-publish.yml \ + tag=6x \ + version="$(node -p "require('./package.json').version")" \ + ref="${{ github.sha }}" diff --git a/.github/workflows/release-alpha.yml b/.github/workflows/release-alpha.yml index 4dd76014ae2..cd0f5b903c7 100644 --- a/.github/workflows/release-alpha.yml +++ b/.github/workflows/release-alpha.yml @@ -9,7 +9,8 @@ on: type: string permissions: - id-token: write + actions: write + contents: read name: release-alpha @@ -26,9 +27,11 @@ jobs: exit 1 fi - uses: actions/checkout@v5 - - name: Install Node and dependencies - uses: mongodb-labs/drivers-github-tools/node/setup@v2 - - run: npm version "${{ inputs.alphaVersion }}" --git-tag-version=false - - run: npm publish --provenance --tag=alpha + - name: Dispatch npm-publish workflow env: - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + GH_TOKEN: ${{ github.token }} + run: | + node ./.github/scripts/dispatch-and-wait.mjs npm-publish.yml \ + tag=alpha \ + version="${{ inputs.alphaVersion }}" \ + ref="${{ github.sha }}" diff --git a/.github/workflows/release-nightly.yml b/.github/workflows/release-nightly.yml index 000118a2f04..ac524e1bb6a 100644 --- a/.github/workflows/release-nightly.yml +++ b/.github/workflows/release-nightly.yml @@ -11,7 +11,8 @@ on: workflow_dispatch: {} permissions: - id-token: write + actions: write + contents: read name: release-nightly @@ -25,6 +26,11 @@ jobs: - id: build_nightly run: npm run build:nightly - if: ${{ steps.build_nightly.outputs.publish == 'yes' }} - run: npm publish --provenance --tag=nightly + name: Dispatch npm-publish workflow env: - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + GH_TOKEN: ${{ github.token }} + run: | + node ./.github/scripts/dispatch-and-wait.mjs npm-publish.yml \ + tag=nightly \ + version="$(node -p "require('./package.json').version")" \ + ref="${{ github.sha }}" From 15ab807c99349cd1bdf0afeec176cbc092817857 Mon Sep 17 00:00:00 2001 From: Sergey Zelenov Date: Mon, 18 May 2026 12:53:33 +0200 Subject: [PATCH 2/3] fix(NODE-7562): avoid shell injection in release-alpha workflow Move alphaVersion input to an env var so bash does not perform command substitution on user-controlled input (semgrep finding). --- .github/workflows/release-alpha.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release-alpha.yml b/.github/workflows/release-alpha.yml index cd0f5b903c7..759de2b282b 100644 --- a/.github/workflows/release-alpha.yml +++ b/.github/workflows/release-alpha.yml @@ -19,10 +19,12 @@ jobs: runs-on: ubuntu-latest steps: - shell: bash + env: + ALPHA_VERSION: ${{ inputs.alphaVersion }} run: | ALPHA_SEMVER_REGEXP="-alpha(\.([0-9]|[1-9][0-9]+))?$" - if ! [[ "${{ inputs.alphaVersion }}" =~ $ALPHA_SEMVER_REGEXP ]]; then + if ! [[ "$ALPHA_VERSION" =~ $ALPHA_SEMVER_REGEXP ]]; then echo "Invalid alphaVersion string" exit 1 fi @@ -30,8 +32,9 @@ jobs: - name: Dispatch npm-publish workflow env: GH_TOKEN: ${{ github.token }} + ALPHA_VERSION: ${{ inputs.alphaVersion }} run: | node ./.github/scripts/dispatch-and-wait.mjs npm-publish.yml \ tag=alpha \ - version="${{ inputs.alphaVersion }}" \ + version="$ALPHA_VERSION" \ ref="${{ github.sha }}" From 9ed9b985341fe1fc70e0dc370924390424b913a3 Mon Sep 17 00:00:00 2001 From: Sergey Zelenov Date: Mon, 18 May 2026 13:43:59 +0200 Subject: [PATCH 3/3] fix: move actions:write to publish job level (least-privilege) --- .github/workflows/release-6.x.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release-6.x.yml b/.github/workflows/release-6.x.yml index 452e6abdc42..6623a4e3725 100644 --- a/.github/workflows/release-6.x.yml +++ b/.github/workflows/release-6.x.yml @@ -6,7 +6,6 @@ on: permissions: contents: write pull-requests: write - actions: write name: release-6.x @@ -91,6 +90,9 @@ jobs: publish: needs: [release_please, ssdlc, build] + permissions: + actions: write + contents: read environment: release runs-on: ubuntu-latest steps: