From 4e58a00bb702aaaab6c6e5f90acf4d432995291d Mon Sep 17 00:00:00 2001 From: admin-raintree <277948009+admin-raintree@users.noreply.github.com> Date: Wed, 22 Jul 2026 18:04:40 -0700 Subject: [PATCH] Make PolicyStrata npm releases retry-safe --- .github/workflows/publish.yml | 19 +++++++++++++++---- scripts/release-smoke.mjs | 3 ++- tests/test_security_posture.py | 13 +++++++++++++ 3 files changed, 30 insertions(+), 5 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 907be0e..638aa17 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -35,6 +35,7 @@ concurrency: jobs: build-python: name: Build Python distribution + if: ${{ !contains(github.ref_name, '-npm.') && (github.event_name == 'push' || inputs.publish_pypi) }} runs-on: ubuntu-24.04 timeout-minutes: 30 @@ -113,6 +114,7 @@ jobs: build-node: name: Build Node distribution + if: ${{ github.event_name == 'push' || inputs.publish_npm }} runs-on: ubuntu-24.04 timeout-minutes: 30 @@ -155,6 +157,7 @@ jobs: build-gateway: name: Build Gateway distribution + if: ${{ github.event_name == 'push' || inputs.publish_gateway_npm }} runs-on: ubuntu-24.04 timeout-minutes: 30 @@ -289,15 +292,19 @@ jobs: run: mise x node@24.18.0 bun@1.3.11 -- bun pm pack --dry-run - name: Check Node package version is unpublished + id: npm-version run: | package_name="$(mise x node@24.18.0 bun@1.3.11 -- node -p "require('./packages/node/package.json').name")" package_version="$(mise x node@24.18.0 bun@1.3.11 -- node -p "require('./packages/node/package.json').version")" if mise x node@24.18.0 bun@1.3.11 -- npm view "${package_name}@${package_version}" version >/dev/null 2>&1; then - echo "${package_name}@${package_version} already exists on npm" >&2 - exit 1 + echo "${package_name}@${package_version} already exists on npm; skipping publish" + echo "published=true" >> "$GITHUB_OUTPUT" + else + echo "published=false" >> "$GITHUB_OUTPUT" fi - name: Publish Node package to npm + if: ${{ steps.npm-version.outputs.published != 'true' }} working-directory: packages/node run: mise x node@24.18.0 bun@1.3.11 -- npm publish --provenance @@ -342,15 +349,19 @@ jobs: run: mise x node@24.18.0 bun@1.3.11 -- bun pm pack --dry-run - name: Check Gateway package version is unpublished + id: npm-version run: | package_name="$(mise x node@24.18.0 bun@1.3.11 -- node -p "require('./packages/gateway/package.json').name")" package_version="$(mise x node@24.18.0 bun@1.3.11 -- node -p "require('./packages/gateway/package.json').version")" if mise x node@24.18.0 bun@1.3.11 -- npm view "${package_name}@${package_version}" version >/dev/null 2>&1; then - echo "${package_name}@${package_version} already exists on npm" >&2 - exit 1 + echo "${package_name}@${package_version} already exists on npm; skipping publish" + echo "published=true" >> "$GITHUB_OUTPUT" + else + echo "published=false" >> "$GITHUB_OUTPUT" fi - name: Publish Gateway package to npm + if: ${{ steps.npm-version.outputs.published != 'true' }} working-directory: packages/gateway run: mise x node@24.18.0 bun@1.3.11 -- npm publish --provenance --access public diff --git a/scripts/release-smoke.mjs b/scripts/release-smoke.mjs index 8709b06..9c0543d 100644 --- a/scripts/release-smoke.mjs +++ b/scripts/release-smoke.mjs @@ -21,6 +21,7 @@ Environment overrides: POLICYSTRATA_PYPI_VERSION POLICYSTRATA_NPM_VERSION POLICYSTRATA_GATEWAY_VERSION + POLICYSTRATA_RELEASE_SMOKE_RETRIES `); process.exit(flags.has("--help") ? 0 : 2); } @@ -340,7 +341,7 @@ function packPackage(directory) { } function retry(operation) { - const attempts = Number(process.env.POLICYSTRATA_RELEASE_SMOKE_RETRIES || "6"); + const attempts = Number(process.env.POLICYSTRATA_RELEASE_SMOKE_RETRIES || "10"); let lastError; for (let attempt = 1; attempt <= attempts; attempt += 1) { try { diff --git a/tests/test_security_posture.py b/tests/test_security_posture.py index bb83499..0921819 100644 --- a/tests/test_security_posture.py +++ b/tests/test_security_posture.py @@ -82,3 +82,16 @@ def test_fixture_emails_use_reserved_example_domains() -> None: findings.append(f"{path}: {match.group(0)}") assert findings == [] + + +def test_publish_workflow_routes_release_artifacts_and_supports_safe_retries() -> None: + workflow = Path(".github/workflows/publish.yml").read_text(encoding="utf-8") + smoke = Path("scripts/release-smoke.mjs").read_text(encoding="utf-8") + + assert "!contains(github.ref_name, '-npm.')" in workflow + assert "github.event_name == 'push' || inputs.publish_pypi" in workflow + assert "github.event_name == 'push' || inputs.publish_npm" in workflow + assert "github.event_name == 'push' || inputs.publish_gateway_npm" in workflow + assert workflow.count("id: npm-version") == 2 + assert workflow.count("steps.npm-version.outputs.published != 'true'") == 2 + assert 'POLICYSTRATA_RELEASE_SMOKE_RETRIES || "10"' in smoke