From 2f5f6d4d682dcebdbfee6530e56ed828f7b62936 Mon Sep 17 00:00:00 2001 From: shortstacked Date: Mon, 11 Aug 2025 10:01:37 +0100 Subject: [PATCH] ci: Add lint to Github actions (#18172) --- .github/actionlint.yaml | 4 + .github/workflows/check-run-eligibility.yml | 9 +- .github/workflows/ci-master.yml | 4 +- .github/workflows/docker-build-push.yml | 80 +++++++----- .github/workflows/e2e-reusable.yml | 2 +- .github/workflows/release-create-pr.yml | 2 +- .github/workflows/release-publish.yml | 4 +- .github/workflows/release-push-to-channel.yml | 2 +- .../security-trivy-scan-callable.yml | 122 +++++++++++------- .github/workflows/sync-public-api-docs.yml | 4 +- CONTRIBUTING.md | 10 ++ lefthook.yml | 6 + 12 files changed, 158 insertions(+), 91 deletions(-) create mode 100644 .github/actionlint.yaml diff --git a/.github/actionlint.yaml b/.github/actionlint.yaml new file mode 100644 index 0000000000..6ba9399f2d --- /dev/null +++ b/.github/actionlint.yaml @@ -0,0 +1,4 @@ +self-hosted-runner: + labels: + - blacksmith-2vcpu-ubuntu-2204 + - blacksmith-4vcpu-ubuntu-2204 diff --git a/.github/workflows/check-run-eligibility.yml b/.github/workflows/check-run-eligibility.yml index 63f7b8294c..34f738a28e 100644 --- a/.github/workflows/check-run-eligibility.yml +++ b/.github/workflows/check-run-eligibility.yml @@ -37,7 +37,7 @@ on: - '!packages/@n8n/benchmark/**' - '!**/*.md' excluded_source_branch_patterns: - description: "Newline-separated list of glob patterns for source branches to EXCLUDE." + description: 'Newline-separated list of glob patterns for source branches to EXCLUDE.' required: false type: string default: | @@ -84,6 +84,7 @@ jobs: source_branch_excluded="false" while IFS= read -r pattern; do + # shellcheck disable=SC2053 if [[ -n "$pattern" && "$HEAD_REF" == $pattern ]]; then source_branch_excluded="true" break @@ -102,8 +103,8 @@ jobs: "$source_branch_excluded" == "false" && \ "$IS_APPROVED" == "true" ]]; then echo "Decision: Conditions met. Setting should_run=true." - echo "should_run=true" >> $GITHUB_OUTPUT + echo "should_run=true" >> "$GITHUB_OUTPUT" else echo "Decision: Conditions not met. Setting should_run=false." - echo "should_run=false" >> $GITHUB_OUTPUT - fi \ No newline at end of file + echo "should_run=false" >> "$GITHUB_OUTPUT" + fi diff --git a/.github/workflows/ci-master.yml b/.github/workflows/ci-master.yml index 60e07994d8..566b138de7 100644 --- a/.github/workflows/ci-master.yml +++ b/.github/workflows/ci-master.yml @@ -13,7 +13,7 @@ jobs: matrix: node-version: [20.x, 22.x, 24.3.x] with: - ref: ${{ inputs.branch }} + ref: ${{ github.sha }} nodeVersion: ${{ matrix.node-version }} collectCoverage: ${{ matrix.node-version == '22.x' }} secrets: @@ -23,7 +23,7 @@ jobs: name: Lint uses: ./.github/workflows/linting-reusable.yml with: - ref: ${{ inputs.branch }} + ref: ${{ github.sha }} notify-on-failure: name: Notify Slack on failure diff --git a/.github/workflows/docker-build-push.yml b/.github/workflows/docker-build-push.yml index 4463cf43b3..575a282329 100644 --- a/.github/workflows/docker-build-push.yml +++ b/.github/workflows/docker-build-push.yml @@ -71,15 +71,19 @@ jobs: # Check if called by another workflow (has n8n_version input) if [[ -n "${{ inputs.n8n_version }}" ]]; then # workflow_call - used for releases - echo "release_type=${{ inputs.release_type }}" >> $GITHUB_OUTPUT - echo "n8n_version=${{ inputs.n8n_version }}" >> $GITHUB_OUTPUT - echo "push_enabled=${{ inputs.push_enabled }}" >> $GITHUB_OUTPUT + { + echo "release_type=${{ inputs.release_type }}" + echo "n8n_version=${{ inputs.n8n_version }}" + echo "push_enabled=${{ inputs.push_enabled }}" + } >> "$GITHUB_OUTPUT" elif [[ "${{ github.event_name }}" == "schedule" ]]; then # Nightly builds - echo "release_type=nightly" >> $GITHUB_OUTPUT - echo "n8n_version=snapshot" >> $GITHUB_OUTPUT - echo "push_enabled=true" >> $GITHUB_OUTPUT + { + echo "release_type=nightly" + echo "n8n_version=snapshot" + echo "push_enabled=true" + } >> "$GITHUB_OUTPUT" elif [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then # Build branches for Nathan deploy @@ -98,22 +102,26 @@ jobs: exit 1 fi - echo "release_type=branch" >> $GITHUB_OUTPUT - echo "n8n_version=branch-${SAFE_BRANCH_NAME}" >> $GITHUB_OUTPUT - echo "push_enabled=${{ inputs.push_enabled }}" >> $GITHUB_OUTPUT + { + echo "release_type=branch" + echo "n8n_version=branch-${SAFE_BRANCH_NAME}" + echo "push_enabled=${{ inputs.push_enabled }}" + } >> "$GITHUB_OUTPUT" elif [[ "${{ github.event_name }}" == "pull_request" ]]; then # Direct PR triggers for testing Dockerfile changes - echo "release_type=dev" >> $GITHUB_OUTPUT - echo "n8n_version=pr-${{ github.event.pull_request.number }}" >> $GITHUB_OUTPUT - echo "push_enabled=false" >> $GITHUB_OUTPUT + { + echo "release_type=dev" + echo "n8n_version=pr-${{ github.event.pull_request.number }}" + echo "push_enabled=false" + } >> "$GITHUB_OUTPUT" fi # Output summary for logs echo "=== Build Context Summary ===" - echo "Release type: $(grep release_type $GITHUB_OUTPUT | cut -d= -f2)" - echo "N8N version: $(grep n8n_version $GITHUB_OUTPUT | cut -d= -f2)" - echo "Push enabled: $(grep push_enabled $GITHUB_OUTPUT | cut -d= -f2)" + echo "Release type: $(grep release_type "$GITHUB_OUTPUT" | cut -d= -f2)" + echo "N8N version: $(grep n8n_version "$GITHUB_OUTPUT" | cut -d= -f2)" + echo "Push enabled: $(grep push_enabled "$GITHUB_OUTPUT" | cut -d= -f2)" - name: Determine build matrix id: matrix @@ -147,8 +155,8 @@ jobs: fi # Output matrix as single line for GITHUB_OUTPUT - echo "matrix=$(echo $MATRIX | jq -c .)" >> $GITHUB_OUTPUT - echo "Build matrix: $(echo $MATRIX | jq .)" + echo "matrix=$(echo "$MATRIX" | jq -c .)" >> "$GITHUB_OUTPUT" + echo "Build matrix: $(echo "$MATRIX" | jq .)" build-and-push-docker: name: Build App, then Build and Push Docker Image (${{ matrix.platform }}) @@ -236,16 +244,20 @@ jobs: fi echo "Generated Tags for push: $ALL_TAGS" - echo "tags<> $GITHUB_OUTPUT - echo -e "$ALL_TAGS" >> $GITHUB_OUTPUT - echo "EOF" >> $GITHUB_OUTPUT + { + echo "tags<> "$GITHUB_OUTPUT" - echo "ghcr_platform_tag=${GHCR_TAGS_FOR_PUSH}" >> $GITHUB_OUTPUT - echo "dockerhub_platform_tag=${DOCKER_TAGS_FOR_PUSH}" >> $GITHUB_OUTPUT + { + echo "ghcr_platform_tag=${GHCR_TAGS_FOR_PUSH}" + echo "dockerhub_platform_tag=${DOCKER_TAGS_FOR_PUSH}" + } >> "$GITHUB_OUTPUT" # Only output manifest tags from the first platform to avoid duplicates if [[ "$PLATFORM" == "amd64" ]]; then - echo "primary_ghcr_manifest_tag=${PRIMARY_GHCR_MANIFEST_TAG_VALUE}" >> $GITHUB_OUTPUT + echo "primary_ghcr_manifest_tag=${PRIMARY_GHCR_MANIFEST_TAG_VALUE}" >> "$GITHUB_OUTPUT" fi - name: Set up Docker Buildx @@ -309,23 +321,29 @@ jobs: # Determine if Docker Hub manifest is needed and construct the tag case "$RELEASE_TYPE" in "stable") - echo "DOCKER_MANIFEST_TAG=${DOCKER_BASE}:${N8N_VERSION}" >> $GITHUB_OUTPUT - echo "CREATE_DOCKERHUB_MANIFEST=true" >> $GITHUB_OUTPUT + { + echo "DOCKER_MANIFEST_TAG=${DOCKER_BASE}:${N8N_VERSION}" + echo "CREATE_DOCKERHUB_MANIFEST=true" + } >> "$GITHUB_OUTPUT" ;; "nightly") - echo "DOCKER_MANIFEST_TAG=${DOCKER_BASE}:nightly" >> $GITHUB_OUTPUT - echo "CREATE_DOCKERHUB_MANIFEST=true" >> $GITHUB_OUTPUT + { + 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" >> $GITHUB_OUTPUT - echo "CREATE_DOCKERHUB_MANIFEST=true" >> $GITHUB_OUTPUT + { + echo "DOCKER_MANIFEST_TAG=${DOCKER_BASE}:dev" + echo "CREATE_DOCKERHUB_MANIFEST=true" + } >> "$GITHUB_OUTPUT" else - echo "CREATE_DOCKERHUB_MANIFEST=false" >> $GITHUB_OUTPUT + echo "CREATE_DOCKERHUB_MANIFEST=false" >> "$GITHUB_OUTPUT" fi ;; *) - echo "CREATE_DOCKERHUB_MANIFEST=false" >> $GITHUB_OUTPUT + echo "CREATE_DOCKERHUB_MANIFEST=false" >> "$GITHUB_OUTPUT" ;; esac diff --git a/.github/workflows/e2e-reusable.yml b/.github/workflows/e2e-reusable.yml index 75b9a28bb5..c54d587607 100644 --- a/.github/workflows/e2e-reusable.yml +++ b/.github/workflows/e2e-reusable.yml @@ -77,7 +77,7 @@ jobs: wait-on: 'http://localhost:5678' wait-on-timeout: 120 record: ${{ inputs.record }} - parallel: ${{ fromJSON( inputs.spec == 'e2e/*' && inputs.parallel || false ) }} + parallel: ${{ inputs.spec == 'e2e/*' && inputs.parallel || false }} # We have to provide custom ci-build-id key to make sure that this workflow could be run multiple times # in the same parent workflow ci-build-id: ${{ github.run_id }}-${{ github.run_attempt }} diff --git a/.github/workflows/release-create-pr.yml b/.github/workflows/release-create-pr.yml index a5b00a3a16..bafb51461c 100644 --- a/.github/workflows/release-create-pr.yml +++ b/.github/workflows/release-create-pr.yml @@ -48,7 +48,7 @@ jobs: - name: Bump package versions run: | - echo "NEXT_RELEASE=$(node .github/scripts/bump-versions.mjs)" >> $GITHUB_ENV + echo "NEXT_RELEASE=$(node .github/scripts/bump-versions.mjs)" >> "$GITHUB_ENV" env: RELEASE_TYPE: ${{ github.event.inputs.release-type }} diff --git a/.github/workflows/release-publish.yml b/.github/workflows/release-publish.yml index d701014a55..e1b6d90f1c 100644 --- a/.github/workflows/release-publish.yml +++ b/.github/workflows/release-publish.yml @@ -37,7 +37,7 @@ jobs: - run: pnpm install --frozen-lockfile - name: Set release version in env - run: echo "RELEASE=$(node -e 'console.log(require("./package.json").version)')" >> $GITHUB_ENV + run: echo "RELEASE=$(node -e 'console.log(require("./package.json").version)')" >> "$GITHUB_ENV" - name: Build run: pnpm build @@ -67,7 +67,7 @@ jobs: continue-on-error: true - id: set-release - run: echo "release=${{ env.RELEASE }}" >> $GITHUB_OUTPUT + run: echo "release=${{ env.RELEASE }}" >> "$GITHUB_OUTPUT" publish-to-docker-hub: name: Publish to DockerHub diff --git a/.github/workflows/release-push-to-channel.yml b/.github/workflows/release-push-to-channel.yml index 3fe73de0ef..7557928d92 100644 --- a/.github/workflows/release-push-to-channel.yml +++ b/.github/workflows/release-push-to-channel.yml @@ -35,7 +35,7 @@ jobs: if [[ "$input_version" =~ $version_regex ]]; then echo "Version format is valid: $input_version" - echo "version=$input_version" >> $GITHUB_OUTPUT + echo "version=$input_version" >> "$GITHUB_OUTPUT" else echo "::error::Invalid version format provided: '$input_version'. Must match regex '$version_regex'." exit 1 diff --git a/.github/workflows/security-trivy-scan-callable.yml b/.github/workflows/security-trivy-scan-callable.yml index 51b40718e5..cce2253cea 100644 --- a/.github/workflows/security-trivy-scan-callable.yml +++ b/.github/workflows/security-trivy-scan-callable.yml @@ -14,14 +14,14 @@ on: description: 'Full image reference to scan e.g. ghcr.io/n8n-io/n8n:latest' required: true secrets: - SLACK_BOT_TOKEN: + QBOT_SLACK_TOKEN: required: true permissions: contents: read env: - SLACK_BOT_TOKEN: ${{ secrets.QBOT_SLACK_TOKEN }} + QBOT_SLACK_TOKEN: ${{ secrets.QBOT_SLACK_TOKEN }} SLACK_CHANNEL_ID: C042WDXPTEZ #mission-security jobs: @@ -43,16 +43,18 @@ jobs: - name: Calculate vulnerability counts id: process_results run: | - if [ ! -s trivy-results.json ] || [ $(jq '.Results | length' trivy-results.json) -eq 0 ]; then - echo "No high-severity vulnerabilities found." - echo "vulnerabilities_found=false" >> $GITHUB_OUTPUT + if [ ! -s trivy-results.json ] || [ "$(jq '.Results | length' trivy-results.json)" -eq 0 ]; then + echo "No vulnerabilities found." + echo "vulnerabilities_found=false" >> "$GITHUB_OUTPUT" exit 0 fi # Calculate counts by severity CRITICAL_COUNT=$(jq '([.Results[]?.Vulnerabilities[]? | select(.Severity == "CRITICAL")] | length)' trivy-results.json) HIGH_COUNT=$(jq '([.Results[]?.Vulnerabilities[]? | select(.Severity == "HIGH")] | length)' trivy-results.json) - TOTAL_VULNS=$((CRITICAL_COUNT + HIGH_COUNT)) + MEDIUM_COUNT=$(jq '([.Results[]?.Vulnerabilities[]? | select(.Severity == "MEDIUM")] | length)' trivy-results.json) + LOW_COUNT=$(jq '([.Results[]?.Vulnerabilities[]? | select(.Severity == "LOW")] | length)' trivy-results.json) + TOTAL_VULNS=$((CRITICAL_COUNT + HIGH_COUNT + MEDIUM_COUNT + LOW_COUNT)) # Get unique CVE count UNIQUE_CVES=$(jq -r '[.Results[]?.Vulnerabilities[]?.VulnerabilityID] | unique | length' trivy-results.json) @@ -60,12 +62,16 @@ jobs: # Get affected packages count AFFECTED_PACKAGES=$(jq -r '[.Results[]?.Vulnerabilities[]? | .PkgName] | unique | length' trivy-results.json) - echo "vulnerabilities_found=$( [ $TOTAL_VULNS -gt 0 ] && echo 'true' || echo 'false' )" >> $GITHUB_OUTPUT - echo "total_count=$TOTAL_VULNS" >> $GITHUB_OUTPUT - echo "critical_count=$CRITICAL_COUNT" >> $GITHUB_OUTPUT - echo "high_count=$HIGH_COUNT" >> $GITHUB_OUTPUT - echo "unique_cves=$UNIQUE_CVES" >> $GITHUB_OUTPUT - echo "affected_packages=$AFFECTED_PACKAGES" >> $GITHUB_OUTPUT + { + echo "vulnerabilities_found=$( [ "$TOTAL_VULNS" -gt 0 ] && echo 'true' || echo 'false' )" + echo "total_count=$TOTAL_VULNS" + echo "critical_count=$CRITICAL_COUNT" + echo "high_count=$HIGH_COUNT" + echo "medium_count=$MEDIUM_COUNT" + echo "low_count=$LOW_COUNT" + echo "unique_cves=$UNIQUE_CVES" + echo "affected_packages=$AFFECTED_PACKAGES" + } >> "$GITHUB_OUTPUT" - name: Generate GitHub Job Summary if: always() @@ -76,10 +82,12 @@ jobs: echo "**Image:** \`${{ inputs.image_ref }}\`" echo "**Scan Date:** $(date -u '+%Y-%m-%d %H:%M:%S UTC')" echo "" - } >> $GITHUB_STEP_SUMMARY + } >> "$GITHUB_STEP_SUMMARY" if [ "${{ steps.process_results.outputs.vulnerabilities_found }}" == "false" ]; then - echo "✅ **No critical or high severity vulnerabilities found!**" >> $GITHUB_STEP_SUMMARY + { + echo "✅ **No vulnerabilities found!**" + } >> "$GITHUB_STEP_SUMMARY" else { echo "## 📊 Summary" @@ -87,43 +95,52 @@ jobs: echo "|--------|-------|" echo "| 🔴 Critical Vulnerabilities | ${{ steps.process_results.outputs.critical_count }} |" echo "| 🟠 High Vulnerabilities | ${{ steps.process_results.outputs.high_count }} |" + echo "| 🟡 Medium Vulnerabilities | ${{ steps.process_results.outputs.medium_count }} |" + echo "| 🟡 Low Vulnerabilities | ${{ steps.process_results.outputs.low_count }} |" echo "| 📋 Unique CVEs | ${{ steps.process_results.outputs.unique_cves }} |" echo "| 📦 Affected Packages | ${{ steps.process_results.outputs.affected_packages }} |" echo "" echo "## 🚨 Top Vulnerabilities" echo "" - } >> $GITHUB_STEP_SUMMARY - - # Generate detailed vulnerability table - jq -r --arg image_ref "${{ inputs.image_ref }}" ' - # Collect all vulnerabilities - [.Results[] | select(.Vulnerabilities != null) | .Vulnerabilities[]] | - # Group by CVE ID to avoid duplicates - group_by(.VulnerabilityID) | - map({ - cve: .[0].VulnerabilityID, - severity: .[0].Severity, - cvss: (.[0].CVSS.nvd.V3Score // "N/A"), - cvss_sort: (.[0].CVSS.nvd.V3Score // 0), - packages: [.[] | "\(.PkgName)@\(.InstalledVersion)"] | unique | join(", "), - fixed: (.[0].FixedVersion // "No fix available"), - description: (.[0].Description // "No description available") | split("\n")[0] | .[0:150] - }) | - # Sort by severity (CRITICAL first) and CVSS score - sort_by((.severity == "HIGH" | if . then 1 else 0 end), -.cvss_sort) | - # Take top 15 - .[:15] | - # Generate markdown table - "| CVE | Severity | CVSS | Package(s) | Fix Version | Description |", - "|-----|----------|------|------------|-------------|-------------|", - (.[] | "| [\(.cve)](https://nvd.nist.gov/vuln/detail/\(.cve)) | \(.severity) | \(.cvss) | `\(.packages)` | `\(.fixed)` | \(.description) |") - ' trivy-results.json >> $GITHUB_STEP_SUMMARY + } >> "$GITHUB_STEP_SUMMARY" { + # Generate detailed vulnerability table + jq -r --arg image_ref "${{ inputs.image_ref }}" ' + # Collect all vulnerabilities + [.Results[] | select(.Vulnerabilities != null) | .Vulnerabilities[]] | + # Group by CVE ID to avoid duplicates + group_by(.VulnerabilityID) | + map({ + cve: .[0].VulnerabilityID, + severity: .[0].Severity, + cvss: (.[0].CVSS.nvd.V3Score // "N/A"), + cvss_sort: (.[0].CVSS.nvd.V3Score // 0), + packages: [.[] | "\(.PkgName)@\(.InstalledVersion)"] | unique | join(", "), + fixed: (.[0].FixedVersion // "No fix available"), + description: (.[0].Description // "No description available") | split("\n")[0] | .[0:150] + }) | + # Sort by severity (CRITICAL, HIGH, MEDIUM, LOW) and CVSS score + sort_by( + if .severity == "CRITICAL" then 0 + elif .severity == "HIGH" then 1 + elif .severity == "MEDIUM" then 2 + elif .severity == "LOW" then 3 + else 4 end, + -.cvss_sort + ) | + # Take top 15 + .[:15] | + # Generate markdown table + "| CVE | Severity | CVSS | Package(s) | Fix Version | Description |", + "|-----|----------|------|------------|-------------|-------------|", + (.[] | "| [\(.cve)](https://nvd.nist.gov/vuln/detail/\(.cve)) | \(.severity) | \(.cvss) | `\(.packages)` | `\(.fixed)` | \(.description) |") + ' trivy-results.json + echo "" echo "---" echo "🔍 **View detailed logs above for full analysis**" - } >> $GITHUB_STEP_SUMMARY + } >> "$GITHUB_STEP_SUMMARY" fi - name: Generate Slack Blocks JSON @@ -136,6 +153,8 @@ jobs: --arg run_url "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" \ --arg critical_count "${{ steps.process_results.outputs.critical_count }}" \ --arg high_count "${{ steps.process_results.outputs.high_count }}" \ + --arg medium_count "${{ steps.process_results.outputs.medium_count }}" \ + --arg low_count "${{ steps.process_results.outputs.low_count }}" \ --arg unique_cves "${{ steps.process_results.outputs.unique_cves }}" \ ' # Function to create a vulnerability block with emoji indicators @@ -143,7 +162,7 @@ jobs: "type": "section", "text": { "type": "mrkdwn", - "text": "\(if .Severity == "CRITICAL" then ":red_circle:" else ":large_orange_circle:" end) ** (CVSS: `\(.CVSS.nvd.V3Score // "N/A")`)\n*Package:* `\(.PkgName)@\(.InstalledVersion)` → `\(.FixedVersion // "No fix available")`" + "text": "\(if .Severity == "CRITICAL" then ":red_circle:" elif .Severity == "HIGH" then ":large_orange_circle:" elif .Severity == "MEDIUM" then ":large_yellow_circle:" else ":large_green_circle:" end) ** (CVSS: `\(.CVSS.nvd.V3Score // "N/A")`)\n*Package:* `\(.PkgName)@\(.InstalledVersion)` → `\(.FixedVersion // "No fix available")`" } }; @@ -159,7 +178,9 @@ jobs: { "type": "mrkdwn", "text": "*Repository:*\n<\($repo_url)|\($repo_name)>" }, { "type": "mrkdwn", "text": "*Image:*\n`\($image_ref)`" }, { "type": "mrkdwn", "text": "*Critical:*\n:red_circle: \($critical_count)" }, - { "type": "mrkdwn", "text": "*High:*\n:large_orange_circle: \($high_count)" } + { "type": "mrkdwn", "text": "*High:*\n:large_orange_circle: \($high_count)" }, + { "type": "mrkdwn", "text": "*Medium:*\n:large_yellow_circle: \($medium_count)" }, + { "type": "mrkdwn", "text": "*Low:*\n:large_green_circle: \($low_count)" } ] }, { @@ -175,7 +196,14 @@ jobs: [.Results[] | select(.Vulnerabilities != null) | .Vulnerabilities[]] | group_by(.VulnerabilityID) | map(.[0]) | - sort_by((.Severity == "HIGH" | if . then 1 else 0 end), -((.CVSS.nvd.V3Score // 0) | tonumber? // 0)) | + sort_by( + (if .Severity == "CRITICAL" then 0 + elif .Severity == "HIGH" then 1 + elif .Severity == "MEDIUM" then 2 + elif .Severity == "LOW" then 3 + else 4 end), + -((.CVSS.nvd.V3Score // 0) | tonumber? // 0) + ) | .[:8] | map(. | vuln_block) ) + @@ -195,15 +223,15 @@ jobs: ] ' trivy-results.json) - echo "slack_blocks=$BLOCKS_JSON" >> $GITHUB_OUTPUT + 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.SLACK_BOT_TOKEN }} + 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 vulnerabilities found in ${{ inputs.image_ref }}" + 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/sync-public-api-docs.yml b/.github/workflows/sync-public-api-docs.yml index 69f92c05f6..e28f57cb38 100644 --- a/.github/workflows/sync-public-api-docs.yml +++ b/.github/workflows/sync-public-api-docs.yml @@ -49,10 +49,10 @@ jobs: run: | if [[ -f "packages/cli/dist/public-api/v1/openapi.yml" ]]; then echo "OpenAPI file found: packages/cli/dist/public-api/v1/openapi.yml" - echo "file_exists=true" >> $GITHUB_OUTPUT + echo "file_exists=true" >> "$GITHUB_OUTPUT" else echo "ERROR: OpenAPI file not found at packages/cli/dist/public-api/v1/openapi.yml after build." - echo "file_exists=false" >> $GITHUB_OUTPUT + echo "file_exists=false" >> "$GITHUB_OUTPUT" fi - name: Generate GitHub App Token diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7a3e757f04..fdd981cefa 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -122,6 +122,16 @@ MacOS: No additional packages required. +#### actionlint (for GitHub Actions workflow development) + +If you plan to modify GitHub Actions workflow files (`.github/workflows/*.yml`), you'll need [actionlint](https://github.com/rhysd/actionlint) for workflow validation: + +**macOS (Homebrew):** +``` +brew install actionlint +``` +> **Note:** actionlint is only required if you're modifying workflow files. It runs automatically via git hooks when workflow files are changed. + ### Actual n8n setup > **IMPORTANT**: All the steps below have to get executed at least once to get the development setup up and running! diff --git a/lefthook.yml b/lefthook.yml index 055ea2d47a..09dae7bfb5 100644 --- a/lefthook.yml +++ b/lefthook.yml @@ -20,3 +20,9 @@ pre-commit: skip: - merge - rebase + actionlint_check: + glob: '.github/workflows/*.{yml,yaml}' + run: actionlint {staged_files} + skip: + - merge + - rebase