diff --git a/.github/workflows/ci-pull-requests.yml b/.github/workflows/ci-pull-requests.yml index 722694991d625..1880c8b32c7df 100644 --- a/.github/workflows/ci-pull-requests.yml +++ b/.github/workflows/ci-pull-requests.yml @@ -4,12 +4,13 @@ on: pull_request: branches: - '**' - - '!release/*' + +# dummy change to trigger workflow jobs: install-and-build: name: Install & Build - runs-on: blacksmith-2vcpu-ubuntu-2204 + runs-on: ubuntu-latest env: NODE_OPTIONS: '--max-old-space-size=3072' outputs: diff --git a/.github/workflows/docker-build-push.yml b/.github/workflows/docker-build-push.yml index 28aadba74662e..c688781b856d6 100644 --- a/.github/workflows/docker-build-push.yml +++ b/.github/workflows/docker-build-push.yml @@ -10,9 +10,6 @@ env: NODE_OPTIONS: '--max-old-space-size=7168' on: - schedule: - - cron: '0 0 * * *' - workflow_call: inputs: n8n_version: @@ -44,16 +41,14 @@ on: pull_request: types: + - synchronize - opened - - ready_for_review - paths: - - '.github/workflows/docker-build-push.yml' - - 'docker/images/n8n/Dockerfile' + - edited jobs: determine-build-context: name: Determine Build Context - runs-on: ubuntu-latest + runs-on: tenki-standard-large-plus-16c-32g outputs: release_type: ${{ steps.context.outputs.release_type }} n8n_version: ${{ steps.context.outputs.n8n_version }} @@ -134,22 +129,32 @@ jobs: "platform": ["amd64"], "include": [{ "platform": "amd64", - "runner": "blacksmith-4vcpu-ubuntu-2204", + "runner": "tenki-standard-large-plus-16c-32g", "docker_platform": "linux/amd64" }] }' else # All other builds (stable, nightly, dev, PR) need both platforms + # MATRIX='{ + # "platform": ["amd64", "arm64"], + # "include": [{ + # "platform": "amd64", + # "runner": "tenki-standard-large-plus-16c-32g", + # "docker_platform": "linux/amd64" + # }, { + # "platform": "arm64", + # "runner": "blacksmith-4vcpu-ubuntu-2204-arm", + # "docker_platform": "linux/arm64" + # }] + # }' + + # Temporary: only build AMD64 (same as branch build) MATRIX='{ - "platform": ["amd64", "arm64"], + "platform": ["amd64"], "include": [{ "platform": "amd64", - "runner": "blacksmith-4vcpu-ubuntu-2204", + "runner": "tenki-standard-large-plus-16c-32g", "docker_platform": "linux/amd64" - }, { - "platform": "arm64", - "runner": "blacksmith-4vcpu-ubuntu-2204-arm", - "docker_platform": "linux/arm64" }] }' fi @@ -162,12 +167,14 @@ jobs: name: Build App, then Build and Push Docker Image (${{ matrix.platform }}) needs: determine-build-context runs-on: ${{ matrix.runner }} - timeout-minutes: 15 + # timeout-minutes: 15 strategy: matrix: ${{ fromJSON(needs.determine-build-context.outputs.build_matrix) }} outputs: image_ref: ${{ steps.determine-tags.outputs.primary_ghcr_manifest_tag }} primary_ghcr_manifest_tag: ${{ steps.determine-tags.outputs.primary_ghcr_manifest_tag }} + image_artifact: ${{ steps.artifact-meta.outputs.name }} + image_tar: ${{ steps.artifact-meta.outputs.tar }} steps: - name: Checkout code uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 @@ -184,7 +191,7 @@ jobs: run: | RELEASE_TYPE="${{ needs.determine-build-context.outputs.release_type }}" N8N_VERSION_TAG="${{ needs.determine-build-context.outputs.n8n_version }}" - GHCR_BASE="ghcr.io/${{ github.repository_owner }}/n8n" + GHCR_BASE="ghcr.io/tenkicloud/n8n" DOCKER_BASE="${{ secrets.DOCKER_USERNAME }}/n8n" PLATFORM="${{ matrix.platform }}" @@ -263,23 +270,23 @@ jobs: - name: Set up Docker Buildx uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3.10.0 - - name: Login to GitHub Container Registry - if: needs.determine-build-context.outputs.push_enabled == 'true' - uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0 - with: - registry: ghcr.io - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Login to DockerHub - if: needs.determine-build-context.outputs.push_enabled == 'true' && steps.determine-tags.outputs.dockerhub_platform_tag != '' - uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0 - with: - username: ${{ secrets.DOCKER_USERNAME }} - password: ${{ secrets.DOCKER_PASSWORD }} + # - name: Login to GitHub Container Registry + # if: needs.determine-build-context.outputs.push_enabled == 'true' + # uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0 + # with: + # registry: ghcr.io + # username: ${{ github.actor }} + # password: ${{ secrets.GITHUB_TOKEN }} + + # - name: Login to DockerHub + # if: needs.determine-build-context.outputs.push_enabled == 'true' && steps.determine-tags.outputs.dockerhub_platform_tag != '' + # uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0 + # with: + # username: ${{ secrets.DOCKER_USERNAME }} + # password: ${{ secrets.DOCKER_PASSWORD }} - name: Build and push Docker image - uses: useblacksmith/build-push-action@574eb0ee0b59c6a687ace24192f0727dfb65d6d7 # v1.2 + uses: docker/build-push-action@v6 with: context: . file: ./docker/images/n8n/Dockerfile @@ -288,127 +295,157 @@ jobs: N8N_VERSION=${{ needs.determine-build-context.outputs.n8n_version }} N8N_RELEASE_TYPE=${{ needs.determine-build-context.outputs.release_type }} platforms: ${{ matrix.docker_platform }} - provenance: true - sbom: true - push: ${{ needs.determine-build-context.outputs.push_enabled == 'true' }} - tags: ${{ steps.determine-tags.outputs.tags }} + provenance: false + sbom: false + push: false + load: true + tags: ${{ steps.determine-tags.outputs.ghcr_platform_tag }} - create_multi_arch_manifest: - name: Create Multi-Arch Manifest - needs: [determine-build-context, build-and-push-docker] - runs-on: ubuntu-latest - if: | - needs.build-and-push-docker.result == 'success' && - needs.determine-build-context.outputs.push_enabled == 'true' - steps: - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1 - - - name: Login to GitHub Container Registry - uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0 - with: - registry: ghcr.io - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Determine Docker Hub manifest tag - id: dockerhub_check + - name: Tag local image with simple name run: | - RELEASE_TYPE="${{ needs.determine-build-context.outputs.release_type }}" - N8N_VERSION="${{ needs.determine-build-context.outputs.n8n_version }}" - DOCKER_BASE="${{ secrets.DOCKER_USERNAME }}/n8n" + docker tag "${{ steps.determine-tags.outputs.ghcr_platform_tag }}" "n8n:local-${{ matrix.platform }}" + docker images - # Determine if Docker Hub manifest is needed and construct the tag - case "$RELEASE_TYPE" in - "stable") - { - echo "DOCKER_MANIFEST_TAG=${DOCKER_BASE}:${N8N_VERSION}" - echo "CREATE_DOCKERHUB_MANIFEST=true" - } >> "$GITHUB_OUTPUT" - ;; - "nightly") - { - echo "DOCKER_MANIFEST_TAG=${DOCKER_BASE}:nightly" - echo "CREATE_DOCKERHUB_MANIFEST=true" - } >> "$GITHUB_OUTPUT" - ;; - "dev") - if [[ "$N8N_VERSION" != pr-* ]]; then - { - echo "DOCKER_MANIFEST_TAG=${DOCKER_BASE}:dev" - echo "CREATE_DOCKERHUB_MANIFEST=true" - } >> "$GITHUB_OUTPUT" - else - echo "CREATE_DOCKERHUB_MANIFEST=false" >> "$GITHUB_OUTPUT" - fi - ;; - *) - echo "CREATE_DOCKERHUB_MANIFEST=false" >> "$GITHUB_OUTPUT" - ;; - esac - - - name: Login to Docker Hub - if: steps.dockerhub_check.outputs.CREATE_DOCKERHUB_MANIFEST == 'true' - uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0 - with: - username: ${{ secrets.DOCKER_USERNAME }} - password: ${{ secrets.DOCKER_PASSWORD }} - - - name: Create GHCR multi-arch manifest - if: needs.build-and-push-docker.outputs.primary_ghcr_manifest_tag != '' - run: | - MANIFEST_TAG="${{ needs.build-and-push-docker.outputs.primary_ghcr_manifest_tag }}" - RELEASE_TYPE="${{ needs.determine-build-context.outputs.release_type }}" - - echo "Creating GHCR manifest: $MANIFEST_TAG" - - # For branch builds, only AMD64 is built - if [[ "$RELEASE_TYPE" == "branch" ]]; then - docker buildx imagetools create \ - --tag $MANIFEST_TAG \ - ${MANIFEST_TAG}-amd64 - else - docker buildx imagetools create \ - --tag $MANIFEST_TAG \ - ${MANIFEST_TAG}-amd64 \ - ${MANIFEST_TAG}-arm64 - fi - - - name: Create Docker Hub multi-arch manifest - if: steps.dockerhub_check.outputs.CREATE_DOCKERHUB_MANIFEST == 'true' + - name: Save image as tar run: | - MANIFEST_TAG="${{ steps.dockerhub_check.outputs.DOCKER_MANIFEST_TAG }}" - - echo "Creating Docker Hub manifest: $MANIFEST_TAG" + docker save "n8n:local-${{ matrix.platform }}" -o "image-${{ matrix.platform }}.tar" + ls -lh "image-${{ matrix.platform }}.tar" - docker buildx imagetools create \ - --tag $MANIFEST_TAG \ - ${MANIFEST_TAG}-amd64 \ - ${MANIFEST_TAG}-arm64 + - name: Upload image tar as artifact + uses: actions/upload-artifact@v4 + with: + name: n8n-image-${{ matrix.platform }} + path: image-${{ matrix.platform }}.tar + retention-days: 5 - call-success-url: - name: Call Success URL - needs: [create_multi_arch_manifest] - runs-on: ubuntu-latest - if: needs.create_multi_arch_manifest.result == 'success' || needs.create_multi_arch_manifest.result == 'skipped' - steps: - - name: Call Success URL - env: - SUCCESS_URL: ${{ github.event.inputs.success_url }} - if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.success_url != '' }} + - name: Expose artifact metadata + id: artifact-meta run: | - echo "Calling success URL: ${{ env.SUCCESS_URL }}" - curl -v "${{ env.SUCCESS_URL }}" || echo "Failed to call success URL" - shell: bash + echo "name=n8n-image-${{ matrix.platform }}" >> "$GITHUB_OUTPUT" + echo "tar=image-${{ matrix.platform }}.tar" >> "$GITHUB_OUTPUT" + + # create_multi_arch_manifest: + # name: Create Multi-Arch Manifest + # needs: [determine-build-context, build-and-push-docker] + # runs-on: tenki-standard-large-plus-16c-32g + # # if: | + # # needs.build-and-push-docker.result == 'success' && + # # needs.determine-build-context.outputs.push_enabled == 'true' + # steps: + # - name: Set up Docker Buildx + # uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1 + + # - name: Login to GitHub Container Registry + # uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0 + # with: + # registry: ghcr.io + # username: ${{ github.actor }} + # password: ${{ secrets.GITHUB_TOKEN }} + + # - name: Determine Docker Hub manifest tag + # id: dockerhub_check + # run: | + # RELEASE_TYPE="${{ needs.determine-build-context.outputs.release_type }}" + # N8N_VERSION="${{ needs.determine-build-context.outputs.n8n_version }}" + # DOCKER_BASE="${{ secrets.DOCKER_USERNAME }}/n8n" + + # # Determine if Docker Hub manifest is needed and construct the tag + # case "$RELEASE_TYPE" in + # "stable") + # { + # echo "DOCKER_MANIFEST_TAG=${DOCKER_BASE}:${N8N_VERSION}" + # echo "CREATE_DOCKERHUB_MANIFEST=true" + # } >> "$GITHUB_OUTPUT" + # ;; + # "nightly") + # { + # echo "DOCKER_MANIFEST_TAG=${DOCKER_BASE}:nightly" + # echo "CREATE_DOCKERHUB_MANIFEST=true" + # } >> "$GITHUB_OUTPUT" + # ;; + # "dev") + # if [[ "$N8N_VERSION" != pr-* ]]; then + # { + # echo "DOCKER_MANIFEST_TAG=${DOCKER_BASE}:dev" + # echo "CREATE_DOCKERHUB_MANIFEST=true" + # } >> "$GITHUB_OUTPUT" + # else + # echo "CREATE_DOCKERHUB_MANIFEST=false" >> "$GITHUB_OUTPUT" + # fi + # ;; + # *) + # echo "CREATE_DOCKERHUB_MANIFEST=false" >> "$GITHUB_OUTPUT" + # ;; + # esac + + # # - name: Login to Docker Hub + # # if: steps.dockerhub_check.outputs.CREATE_DOCKERHUB_MANIFEST == 'true' + # # uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0 + # # with: + # # username: ${{ secrets.DOCKER_USERNAME }} + # # password: ${{ secrets.DOCKER_PASSWORD }} + + # - name: Create GHCR multi-arch manifest + # if: needs.build-and-push-docker.outputs.primary_ghcr_manifest_tag != '' + # run: | + # MANIFEST_TAG="${{ needs.build-and-push-docker.outputs.primary_ghcr_manifest_tag }}" + # RELEASE_TYPE="${{ needs.determine-build-context.outputs.release_type }}" + + # echo "Creating GHCR manifest: $MANIFEST_TAG" + + # # For branch builds, only AMD64 is built + # if [[ "$RELEASE_TYPE" == "branch" ]]; then + # docker buildx imagetools create \ + # --tag $MANIFEST_TAG \ + # ${MANIFEST_TAG}-amd64 + # else + # docker buildx imagetools create \ + # --tag $MANIFEST_TAG \ + # ${MANIFEST_TAG}-amd64 \ + # ${MANIFEST_TAG}-arm64 + # fi + + # - name: Create Docker Hub multi-arch manifest + # if: steps.dockerhub_check.outputs.CREATE_DOCKERHUB_MANIFEST == 'true' + # run: | + # MANIFEST_TAG="${{ steps.dockerhub_check.outputs.DOCKER_MANIFEST_TAG }}" + + # echo "Creating Docker Hub manifest: $MANIFEST_TAG" + + # docker buildx imagetools create \ + # --tag $MANIFEST_TAG \ + # ${MANIFEST_TAG}-amd64 \ + # ${MANIFEST_TAG}-arm64 + + # call-success-url: + # name: Call Success URL + # needs: [create_multi_arch_manifest] + # runs-on: tenki-standard-large-plus-16c-32g + # if: needs.create_multi_arch_manifest.result == 'success' || needs.create_multi_arch_manifest.result == 'skipped' + # steps: + # - name: Call Success URL + # env: + # SUCCESS_URL: ${{ github.event.inputs.success_url }} + # if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.success_url != '' }} + # run: | + # echo "Calling success URL: ${{ env.SUCCESS_URL }}" + # curl -v "${{ env.SUCCESS_URL }}" || echo "Failed to call success URL" + # shell: bash security-scan: name: Security Scan needs: [determine-build-context, build-and-push-docker] - if: | - success() && - (needs.determine-build-context.outputs.release_type == 'stable' || - needs.determine-build-context.outputs.release_type == 'nightly') + permissions: + contents: read + actions: read + # if: | + # success() && + # (needs.determine-build-context.outputs.release_type == 'stable' || + # needs.determine-build-context.outputs.release_type == 'nightly') uses: ./.github/workflows/security-trivy-scan-callable.yml with: - image_ref: ${{ needs.build-and-push-docker.outputs.image_ref }} + # image_ref: ${{ needs.build-and-push-docker.outputs.image_ref }} + input_tar_artifact: ${{ needs.build-and-push-docker.outputs.image_artifact }} + input_tar_filename: ${{ needs.build-and-push-docker.outputs.image_tar }} + artifact_run_id: ${{ github.run_id }} secrets: inherit diff --git a/.github/workflows/linting-reusable.yml b/.github/workflows/linting-reusable.yml index 4d89d34ffd882..7351b22e94812 100644 --- a/.github/workflows/linting-reusable.yml +++ b/.github/workflows/linting-reusable.yml @@ -20,7 +20,7 @@ env: jobs: lint: name: Lint - runs-on: blacksmith-4vcpu-ubuntu-2204 + runs-on: ubuntu-latest steps: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: diff --git a/.github/workflows/security-trivy-scan-callable.yml b/.github/workflows/security-trivy-scan-callable.yml index cce2253ceae06..d56079e77a378 100644 --- a/.github/workflows/security-trivy-scan-callable.yml +++ b/.github/workflows/security-trivy-scan-callable.yml @@ -5,35 +5,59 @@ on: inputs: image_ref: description: 'Full image reference to scan e.g. ghcr.io/n8n-io/n8n:latest' - required: true + required: false default: 'ghcr.io/n8n-io/n8n:latest' workflow_call: inputs: image_ref: type: string description: 'Full image reference to scan e.g. ghcr.io/n8n-io/n8n:latest' + required: false + input_tar_artifact: + type: string + description: 'Artifact name that contains a saved image tar (from docker save)' + required: false + default: '' + input_tar_filename: + type: string + description: 'Filename of the tar inside the artifact' + required: false + default: 'image-amd64.tar' + artifact_run_id: + type: string + description: 'Caller workflow run ID that produced the artifact' required: true - secrets: - QBOT_SLACK_TOKEN: - required: true + # secrets: + # QBOT_SLACK_TOKEN: + # required: true permissions: contents: read + actions: read -env: - QBOT_SLACK_TOKEN: ${{ secrets.QBOT_SLACK_TOKEN }} - SLACK_CHANNEL_ID: C042WDXPTEZ #mission-security +# env: +# QBOT_SLACK_TOKEN: ${{ secrets.QBOT_SLACK_TOKEN }} +# SLACK_CHANNEL_ID: C042WDXPTEZ #mission-security jobs: security_scan: name: Security - Scan Docker Image With Trivy - runs-on: ubuntu-latest + runs-on: tenki-standard-large-plus-16c-32g steps: + - name: Download image tar artifact (from caller run) + uses: actions/download-artifact@v4 + with: + name: ${{ inputs.input_tar_artifact }} + path: ./_image + repository: ${{ github.repository }} + run-id: ${{ inputs.artifact_run_id }} + - name: Run Trivy vulnerability scanner uses: aquasecurity/trivy-action@dc5a429b52fcf669ce959baa2c2dd26090d2a6c4 # v0.32.0 id: trivy_scan with: - image-ref: ${{ inputs.image_ref }} + # image-ref: ${{ inputs.image_ref }} + input: ./_image/${{ inputs.input_tar_filename }} format: 'json' output: 'trivy-results.json' severity: 'CRITICAL,HIGH,MEDIUM,LOW' @@ -225,13 +249,14 @@ jobs: echo "slack_blocks=$BLOCKS_JSON" >> "$GITHUB_OUTPUT" - - name: Send Slack Notification - if: steps.process_results.outputs.vulnerabilities_found == 'true' - uses: slackapi/slack-github-action@91efab103c0de0a537f72a35f6b8cda0ee76bf0a # v2.1.1 - with: - method: chat.postMessage - token: ${{ secrets.QBOT_SLACK_TOKEN }} - payload: | - channel: ${{ env.SLACK_CHANNEL_ID }} - text: "🚨 Trivy Scan: ${{ steps.process_results.outputs.critical_count }} Critical, ${{ steps.process_results.outputs.high_count }} High, ${{ steps.process_results.outputs.medium_count }} Medium, ${{ steps.process_results.outputs.low_count }} Low vulnerabilities found in ${{ inputs.image_ref }}" - blocks: ${{ steps.generate_blocks.outputs.slack_blocks }} + # - name: Send Slack Notification + # if: steps.process_results.outputs.vulnerabilities_found == 'true' + # uses: slackapi/slack-github-action@91efab103c0de0a537f72a35f6b8cda0ee76bf0a # v2.1.1 + # with: + # method: chat.postMessage + # token: ${{ secrets.QBOT_SLACK_TOKEN }} + # payload: | + # channel: ${{ env.SLACK_CHANNEL_ID }} + # text: "🚨 Trivy Scan: ${{ steps.process_results.outputs.critical_count }} Critical, ${{ steps.process_results.outputs.high_count }} High, ${{ steps.process_results.outputs.medium_count }} Medium, ${{ steps.process_results.outputs.low_count }} Low vulnerabilities found in ${{ inputs.image_ref }}" + # blocks: ${{ steps.generate_blocks.outputs.slack_blocks }} + diff --git a/.github/workflows/units-tests-reusable.yml b/.github/workflows/units-tests-reusable.yml index 6d96f164533aa..556eef85f29a1 100644 --- a/.github/workflows/units-tests-reusable.yml +++ b/.github/workflows/units-tests-reusable.yml @@ -28,7 +28,7 @@ env: jobs: unit-test: name: Unit tests - runs-on: blacksmith-4vcpu-ubuntu-2204 + runs-on: ubuntu-latest env: COVERAGE_ENABLED: ${{ inputs.collectCoverage }} steps: