From cae61dc9122a2dbdde6fde1dffbf2f62eb3a17a8 Mon Sep 17 00:00:00 2001 From: Luigi Navarro Date: Wed, 24 Jun 2026 19:49:07 +0200 Subject: [PATCH] fix: solve npm publishing with provenance Signed-off-by: Luigi Navarro --- .github/workflows/300-flow-ats-publish.yaml | 2 +- .github/workflows/301-flow-mp-publish.yaml | 205 ++++++++++++++++++++ 2 files changed, 206 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/301-flow-mp-publish.yaml diff --git a/.github/workflows/300-flow-ats-publish.yaml b/.github/workflows/300-flow-ats-publish.yaml index a5f92da78d..33859c3943 100644 --- a/.github/workflows/300-flow-ats-publish.yaml +++ b/.github/workflows/300-flow-ats-publish.yaml @@ -197,7 +197,7 @@ jobs: - name: Publish npm packages run: | echo "::group::Set publish parameters" - PUBLISH_ARGS="--access=public" + PUBLISH_ARGS="--access=public --no-provenance" if [[ "${{ inputs.dry-run-enabled }}" == "true" ]]; then PUBLISH_ARGS="${PUBLISH_ARGS} --dry-run" fi diff --git a/.github/workflows/301-flow-mp-publish.yaml b/.github/workflows/301-flow-mp-publish.yaml new file mode 100644 index 0000000000..7c0ddd0391 --- /dev/null +++ b/.github/workflows/301-flow-mp-publish.yaml @@ -0,0 +1,205 @@ +name: "300: [FLOW] MP Publish" + +on: + # Manual trigger with dry-run option + workflow_dispatch: + inputs: + dry-run-enabled: + description: "Run npm publish with dry-run flag" + required: false + type: boolean + default: false + + # Tag push trigger - simpler and automatic (no need to create GitHub release) + push: + tags: + - "v*-mp" + - "v*-MP" + +defaults: + run: + shell: bash + +permissions: + contents: read + id-token: write + +jobs: + build-mass-payout: + name: Build Mass Payout Packages + runs-on: token-studio-linux-large + timeout-minutes: 15 + # Only run if manual trigger OR tag push (already filtered by v*-mp pattern) + if: ${{ github.event_name == 'workflow_dispatch' || github.event_name == 'push' }} + + steps: + - name: Harden Runner + uses: step-security/harden-runner@58077d3c7e43986b6b15fba718e8ea69e387dfcc # v2.15.1 + with: + egress-policy: audit + + - name: Checkout repository + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + with: + ref: ${{ github.ref }} + fetch-depth: 0 + + - name: Setup NodeJS Environment + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 + with: + node-version: 22.20.0 + registry-url: https://registry.npmjs.org + + - name: Update npm + run: npm install -g npm@11.7.0 + + - name: Install dependencies + run: npm ci + + - name: Install NestJS CLI globally + run: npm install -g @nestjs/cli + + - name: Build Mass Payout packages + run: npm run mass-payout:build + + - name: Pack Valid Packages + id: pack + run: | + # Create a clean directory for artifacts + mkdir -p dist-artifacts + + # Loop through all directories in mass-payout + for package_dir in packages/mass-payout/*/; do + if [[ -d "${package_dir}" ]] && [[ -f "${package_dir}package.json" ]]; then + + pushd "${package_dir}" > /dev/null + PACKAGE_NAME=$(basename "${package_dir}") + + # Check if private + IS_PRIVATE=$(node -p "require('./package.json').private || false") + + if [[ "$IS_PRIVATE" == "true" ]]; then + echo "⏭️ Skipping private package: ${PACKAGE_NAME}" + else + echo "📦 Packing Mass Payout package: ${PACKAGE_NAME}" + + # Calculate expected filename for verification + JSON_NAME=$(node -p "require('./package.json').name.replace('@', '').replace('/', '-')") + JSON_VERSION=$(node -p "require('./package.json').version") + EXPECTED_FILENAME="${JSON_NAME}-${JSON_VERSION}.tgz" + + npm pack + + if [[ ! -f "$EXPECTED_FILENAME" ]]; then + echo "::error::Expected package file $EXPECTED_FILENAME not found in $package_dir" + exit 1 + fi + + # Move to the staging folder + # Full path to dist-artifacts relative to where we are + mv "$EXPECTED_FILENAME" "../../../dist-artifacts/" + echo "✅ Packed $PACKAGE_NAME to dist-artifacts" + fi + + popd > /dev/null + fi + done + + # Verify successful packing + if [[ -z "$(ls -A dist-artifacts)" ]]; then + echo "::warning::No public packages were found to pack." + else + echo "::group::Contents of dist-artifacts" + ls -la dist-artifacts + echo "::endgroup::" + fi + + - name: Upload Artifacts + uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 + with: + name: mass-payout-tarballs + path: dist-artifacts/*.tgz + if-no-files-found: ignore # If all are private + + publish-mass-payout: + name: Publish Mass Payout Packages + needs: build-mass-payout + runs-on: ubuntu-latest + timeout-minutes: 15 + env: + DRY_RUN: ${{ inputs.dry-run-enabled }} + + steps: + - name: Harden Runner + uses: step-security/harden-runner@58077d3c7e43986b6b15fba718e8ea69e387dfcc # v2.15.1 + with: + egress-policy: audit + + - name: Setup NodeJS Environment + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 + with: + node-version: 22.20.0 + registry-url: https://registry.npmjs.org + + - name: Update npm + run: npm install -g npm@11.7.0 + + - name: Download Artifacts + uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0 + with: + name: mass-payout-tarballs + path: ./dist + + - name: Publish Packages + run: | + # Check if directory exists and is not empty + if [[ ! -d "./dist" ]] || [[ -z "$(ls -A ./dist)" ]]; then + echo "⚠️ No artifacts found to publish. Skipping." + exit 0 + fi + + # Iterate through every tarball in the dist folder + for FILE in ./dist/*.tgz; do + [[ -e "$FILE" ]] || continue + + echo "🚀 Processing $FILE" + + PUBLISH_ARGS="--access=public --no-provenance" + + if [[ "${DRY_RUN}" == "true" ]]; then + PUBLISH_ARGS+=("--dry-run") + echo "🔍 DRY RUN MODE: Would publish $FILE" + else + echo "🚀 Publishing $FILE..." + fi + + if ! npm publish "$FILE" "${PUBLISH_ARGS[@]}"; then + echo "❌ Failed to publish package: $FILE" + exit 1 + fi + done + + summary: + name: Publish Summary + runs-on: token-studio-linux-large + timeout-minutes: 5 + needs: + - publish-mass-payout + if: ${{ always() }} + steps: + - name: Harden the runner (Audit all outbound calls) + uses: step-security/harden-runner@58077d3c7e43986b6b15fba718e8ea69e387dfcc # v2.15.1 + with: + egress-policy: audit + + - name: Report Results + run: | + echo "## Mass Payout Publish Results" >> "${GITHUB_STEP_SUMMARY}" + echo "| Package Type | Status |" >> "${GITHUB_STEP_SUMMARY}" + echo "| --- | --- |" >> "${GITHUB_STEP_SUMMARY}" + echo "| Mass Payout | ${{ needs.publish-mass-payout.result }} |" >> "${GITHUB_STEP_SUMMARY}" + + if [[ "${{ inputs.dry-run-enabled }}" == "true" ]]; then + echo "" >> "${GITHUB_STEP_SUMMARY}" + echo "🔍 **DRY RUN MODE** - No packages were actually published" >> "${GITHUB_STEP_SUMMARY}" + fi