From 986ccbc756263b071199b9e1f059785d9472a8a0 Mon Sep 17 00:00:00 2001 From: Paul Schmiedmayer Date: Fri, 14 Aug 2026 02:47:01 -0700 Subject: [PATCH 1/2] Verify a First Publication Against the Version Document --- .github/workflows/npm-publish.yml | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/.github/workflows/npm-publish.yml b/.github/workflows/npm-publish.yml index 61b4b30..84fa4ba 100644 --- a/.github/workflows/npm-publish.yml +++ b/.github/workflows/npm-publish.yml @@ -337,6 +337,7 @@ jobs: if: ${{ !inputs.dryRun && steps.plan.outputs.bootstrap != '[]' }} env: PACKAGES: ${{ steps.plan.outputs.bootstrap }} + WORKFLOW_REF: ${{ github.workflow_ref }} run: | set -euo pipefail { @@ -347,8 +348,10 @@ jobs: echo # shellcheck disable=SC2016 node --input-type=module -e ' + // npm records the workflow that calls this one, not this workflow. + const workflow = process.env.WORKFLOW_REF.split("@")[0].split("/").pop() for (const name of JSON.parse(process.env.PACKAGES)) { - console.log(` npm trust github ${name} --repository ${process.env.GITHUB_REPOSITORY} --file deployment.yml --allow-publish --yes`) + console.log(` npm trust github ${name} --repository ${process.env.GITHUB_REPOSITORY} --file ${workflow} --allow-publish --yes`) } ' echo @@ -364,15 +367,19 @@ jobs: PACKAGE_LINES="$(node --input-type=module -e 'for (const name of JSON.parse(process.env.PACKAGES)) console.log(name)')" mapfile -t PACKAGE_NAMES <<< "$PACKAGE_LINES" for PACKAGE_NAME in "${PACKAGE_NAMES[@]}"; do - for ATTEMPT in {1..6}; do - if npm view "$PACKAGE_NAME@$PACKAGE_VERSION" version >/dev/null; then + # Read the version document rather than the package document. The release plan reads the + # package document before publishing, so for a package published for the first time the + # registry caches that 404 and keeps serving it long after the publication succeeded. + ENCODED_NAME="$(node --input-type=module -e 'console.log(encodeURIComponent(process.argv[1]))' "$PACKAGE_NAME")" + for ATTEMPT in {1..10}; do + if curl -fsS -o /dev/null "https://registry.npmjs.org/$ENCODED_NAME/$PACKAGE_VERSION"; then echo "Verified $PACKAGE_NAME@$PACKAGE_VERSION." break fi - if [ "$ATTEMPT" -eq 6 ]; then + if [ "$ATTEMPT" -eq 10 ]; then echo "Unable to verify $PACKAGE_NAME@$PACKAGE_VERSION on npm." exit 1 fi - sleep 10 + sleep "$((ATTEMPT * 5))" done done From ec7d748a3c8bfa0a085e86a524d5435d9f084b1d Mon Sep 17 00:00:00 2001 From: Paul Schmiedmayer Date: Fri, 14 Aug 2026 02:56:16 -0700 Subject: [PATCH 2/2] Bound the Publication Check With Request Timeouts and a Deadline --- .github/workflows/npm-publish.yml | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/.github/workflows/npm-publish.yml b/.github/workflows/npm-publish.yml index 84fa4ba..89d3f23 100644 --- a/.github/workflows/npm-publish.yml +++ b/.github/workflows/npm-publish.yml @@ -371,15 +371,17 @@ jobs: # package document before publishing, so for a package published for the first time the # registry caches that 404 and keeps serving it long after the publication succeeded. ENCODED_NAME="$(node --input-type=module -e 'console.log(encodeURIComponent(process.argv[1]))' "$PACKAGE_NAME")" - for ATTEMPT in {1..10}; do - if curl -fsS -o /dev/null "https://registry.npmjs.org/$ENCODED_NAME/$PACKAGE_VERSION"; then + DEADLINE="$(($(date +%s) + 300))" + while true; do + if curl -fsS --connect-timeout 10 --max-time 30 -o /dev/null \ + "https://registry.npmjs.org/$ENCODED_NAME/$PACKAGE_VERSION"; then echo "Verified $PACKAGE_NAME@$PACKAGE_VERSION." break fi - if [ "$ATTEMPT" -eq 10 ]; then + if [ "$(date +%s)" -ge "$DEADLINE" ]; then echo "Unable to verify $PACKAGE_NAME@$PACKAGE_VERSION on npm." exit 1 fi - sleep "$((ATTEMPT * 5))" + sleep 10 done done