From 88afd664712a58c39a819b4f2ea47713ca50484b Mon Sep 17 00:00:00 2001 From: shortstacked Date: Fri, 2 May 2025 11:05:45 +0100 Subject: [PATCH] fix: Secure input handling in release workflow (no-changelog) (#15037) --- .github/workflows/release-push-to-channel.yml | 73 +++++++++++++------ .github/workflows/units-tests-dispatch.yml | 45 ------------ 2 files changed, 52 insertions(+), 66 deletions(-) delete mode 100644 .github/workflows/units-tests-dispatch.yml diff --git a/.github/workflows/release-push-to-channel.yml b/.github/workflows/release-push-to-channel.yml index 5fe095cfdd..a94c59e0ed 100644 --- a/.github/workflows/release-push-to-channel.yml +++ b/.github/workflows/release-push-to-channel.yml @@ -4,8 +4,9 @@ on: workflow_dispatch: inputs: version: - description: 'n8n Release version to push to a channel' + description: 'n8n Release version to push to a channel (e.g., 1.2.3 or 1.2.3-beta.4)' required: true + type: string release-channel: description: 'Release channel' @@ -17,9 +18,31 @@ on: - stable jobs: + validate-inputs: + name: Validate Inputs + runs-on: ubuntu-latest + outputs: + version: ${{ steps.check_version.outputs.version }} + release_channel: ${{ github.event.inputs.release-channel }} + steps: + - name: Check Version Format + id: check_version + run: | + input_version="${{ github.event.inputs.version }}" + version_regex='^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.-]+)?$' + + if [[ "$input_version" =~ $version_regex ]]; then + echo "Version format is valid: $input_version" + echo "version=$input_version" >> $GITHUB_OUTPUT + else + echo "::error::Invalid version format provided: '$input_version'. Must match regex '$version_regex'." + exit 1 + fi + release-to-npm: name: Release to NPM runs-on: ubuntu-latest + needs: validate-inputs timeout-minutes: 5 steps: - uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0 @@ -28,19 +51,22 @@ jobs: - run: echo "//registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }}" > ~/.npmrc - - if: github.event.inputs.release-channel == 'beta' + - name: Add beta/next tags to NPM + if: needs.validate-inputs.outputs.release_channel == 'beta' run: | - npm dist-tag add n8n@${{ github.event.inputs.version }} next - npm dist-tag add n8n@${{ github.event.inputs.version }} beta + npm dist-tag add "n8n@${{ needs.validate-inputs.outputs.version }}" next + npm dist-tag add "n8n@${{ needs.validate-inputs.outputs.version }}" beta - - if: github.event.inputs.release-channel == 'stable' + - name: Add latest/stable tags to NPM + if: needs.validate-inputs.outputs.release_channel == 'stable' run: | - npm dist-tag add n8n@${{ github.event.inputs.version }} latest - npm dist-tag add n8n@${{ github.event.inputs.version }} stable + npm dist-tag add "n8n@${{ needs.validate-inputs.outputs.version }}" latest + npm dist-tag add "n8n@${{ needs.validate-inputs.outputs.version }}" stable release-to-docker-hub: name: Release to DockerHub runs-on: ubuntu-latest + needs: validate-inputs timeout-minutes: 5 steps: - uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0 @@ -48,19 +74,22 @@ jobs: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }} - - if: github.event.inputs.release-channel == 'stable' + - name: Tag stable/latest Docker image + if: needs.validate-inputs.outputs.release_channel == 'stable' run: | - docker buildx imagetools create -t ${{ secrets.DOCKER_USERNAME }}/n8n:stable ${{ secrets.DOCKER_USERNAME }}/n8n:${{ github.event.inputs.version }} - docker buildx imagetools create -t ${{ secrets.DOCKER_USERNAME }}/n8n:latest ${{ secrets.DOCKER_USERNAME }}/n8n:${{ github.event.inputs.version }} + docker buildx imagetools create -t "${{ secrets.DOCKER_USERNAME }}/n8n:stable" "${{ secrets.DOCKER_USERNAME }}/n8n:${{ needs.validate-inputs.outputs.version }}" + docker buildx imagetools create -t "${{ secrets.DOCKER_USERNAME }}/n8n:latest" "${{ secrets.DOCKER_USERNAME }}/n8n:${{ needs.validate-inputs.outputs.version }}" - - if: github.event.inputs.release-channel == 'beta' + - name: Tag beta/next Docker image + if: needs.validate-inputs.outputs.release_channel == 'beta' run: | - docker buildx imagetools create -t ${{ secrets.DOCKER_USERNAME }}/n8n:beta ${{ secrets.DOCKER_USERNAME }}/n8n:${{ github.event.inputs.version }} - docker buildx imagetools create -t ${{ secrets.DOCKER_USERNAME }}/n8n:next ${{ secrets.DOCKER_USERNAME }}/n8n:${{ github.event.inputs.version }} + docker buildx imagetools create -t "${{ secrets.DOCKER_USERNAME }}/n8n:beta" "${{ secrets.DOCKER_USERNAME }}/n8n:${{ needs.validate-inputs.outputs.version }}" + docker buildx imagetools create -t "${{ secrets.DOCKER_USERNAME }}/n8n:next" "${{ secrets.DOCKER_USERNAME }}/n8n:${{ needs.validate-inputs.outputs.version }}" release-to-github-container-registry: name: Release to GitHub Container Registry runs-on: ubuntu-latest + needs: validate-inputs timeout-minutes: 5 steps: - uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0 @@ -69,20 +98,22 @@ jobs: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - - if: github.event.inputs.release-channel == 'stable' + - name: Tag stable/latest GHCR image + if: needs.validate-inputs.outputs.release_channel == 'stable' run: | - docker buildx imagetools create -t ghcr.io/${{ github.repository_owner }}/n8n:stable ghcr.io/${{ github.repository_owner }}/n8n:${{ github.event.inputs.version }} - docker buildx imagetools create -t ghcr.io/${{ github.repository_owner }}/n8n:latest ghcr.io/${{ github.repository_owner }}/n8n:${{ github.event.inputs.version }} + docker buildx imagetools create -t "ghcr.io/${{ github.repository_owner }}/n8n:stable" "ghcr.io/${{ github.repository_owner }}/n8n:${{ needs.validate-inputs.outputs.version }}" + docker buildx imagetools create -t "ghcr.io/${{ github.repository_owner }}/n8n:latest" "ghcr.io/${{ github.repository_owner }}/n8n:${{ needs.validate-inputs.outputs.version }}" - - if: github.event.inputs.release-channel == 'beta' + - name: Tag beta/next GHCR image + if: needs.validate-inputs.outputs.release_channel == 'beta' run: | - docker buildx imagetools create -t ghcr.io/${{ github.repository_owner }}/n8n:beta ghcr.io/${{ github.repository_owner }}/n8n:${{ github.event.inputs.version }} - docker buildx imagetools create -t ghcr.io/${{ github.repository_owner }}/n8n:next ghcr.io/${{ github.repository_owner }}/n8n:${{ github.event.inputs.version }} + docker buildx imagetools create -t "ghcr.io/${{ github.repository_owner }}/n8n:beta" "ghcr.io/${{ github.repository_owner }}/n8n:${{ needs.validate-inputs.outputs.version }}" + docker buildx imagetools create -t "ghcr.io/${{ github.repository_owner }}/n8n:next" "ghcr.io/${{ github.repository_owner }}/n8n:${{ needs.validate-inputs.outputs.version }}" update-docs: name: Update latest and next in the docs runs-on: ubuntu-latest - needs: [release-to-npm, release-to-docker-hub] + needs: [validate-inputs, release-to-npm, release-to-docker-hub] steps: - continue-on-error: true - run: curl -u docsWorkflows:${{ secrets.N8N_WEBHOOK_DOCS_PASSWORD }} --request GET 'https://internal.users.n8n.cloud/webhook/update-latest-next' + run: curl -u docsWorkflows:${{ secrets.N8N_WEBHOOK_DOCS_PASSWORD }} --request GET 'https://internal.users.n8n.cloud/webhook/update-latest-next' \ No newline at end of file diff --git a/.github/workflows/units-tests-dispatch.yml b/.github/workflows/units-tests-dispatch.yml deleted file mode 100644 index 72a9db5b6a..0000000000 --- a/.github/workflows/units-tests-dispatch.yml +++ /dev/null @@ -1,45 +0,0 @@ -name: Runs unit tests for a given ref - -on: - workflow_dispatch: - inputs: - ref: - description: 'GitHub ref to test.' - required: false - default: 'master' - type: string - prNumber: - description: 'PR number to run tests for.' - required: false - type: number - skipFrontendTests: - description: 'Skip Frontend tests' - required: false - default: false - type: boolean - -jobs: - prepare: - name: Prepare - runs-on: ubuntu-latest - outputs: - branch: ${{ steps.compute-branch.outputs.branch }} - steps: - - name: Compute branch - id: compute-branch - run: | - BRANCH_NAME="" - if [[ "${{ inputs.prNumber }}" != "" && "${{ inputs.prNumber }}" != "null" ]]; then - BRANCH_NAME="refs/pull/${{ inputs.prNumber }}/merge" - else - BRANCH_NAME="${{ inputs.ref }}" - fi - echo "branch=$BRANCH_NAME" >> $GITHUB_OUTPUT - - unit-test: - name: Unit tests - needs: prepare - uses: ./.github/workflows/units-tests-reusable.yml - with: - ref: ${{ needs.prepare.outputs.branch }} - skipFrontendTests: ${{ inputs.skipFrontendTests }}