mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-16 09:36:44 +00:00
ci: Add lint to Github actions (#18172)
This commit is contained in:
4
.github/actionlint.yaml
vendored
Normal file
4
.github/actionlint.yaml
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
self-hosted-runner:
|
||||||
|
labels:
|
||||||
|
- blacksmith-2vcpu-ubuntu-2204
|
||||||
|
- blacksmith-4vcpu-ubuntu-2204
|
||||||
7
.github/workflows/check-run-eligibility.yml
vendored
7
.github/workflows/check-run-eligibility.yml
vendored
@@ -37,7 +37,7 @@ on:
|
|||||||
- '!packages/@n8n/benchmark/**'
|
- '!packages/@n8n/benchmark/**'
|
||||||
- '!**/*.md'
|
- '!**/*.md'
|
||||||
excluded_source_branch_patterns:
|
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
|
required: false
|
||||||
type: string
|
type: string
|
||||||
default: |
|
default: |
|
||||||
@@ -84,6 +84,7 @@ jobs:
|
|||||||
|
|
||||||
source_branch_excluded="false"
|
source_branch_excluded="false"
|
||||||
while IFS= read -r pattern; do
|
while IFS= read -r pattern; do
|
||||||
|
# shellcheck disable=SC2053
|
||||||
if [[ -n "$pattern" && "$HEAD_REF" == $pattern ]]; then
|
if [[ -n "$pattern" && "$HEAD_REF" == $pattern ]]; then
|
||||||
source_branch_excluded="true"
|
source_branch_excluded="true"
|
||||||
break
|
break
|
||||||
@@ -102,8 +103,8 @@ jobs:
|
|||||||
"$source_branch_excluded" == "false" && \
|
"$source_branch_excluded" == "false" && \
|
||||||
"$IS_APPROVED" == "true" ]]; then
|
"$IS_APPROVED" == "true" ]]; then
|
||||||
echo "Decision: Conditions met. Setting should_run=true."
|
echo "Decision: Conditions met. Setting should_run=true."
|
||||||
echo "should_run=true" >> $GITHUB_OUTPUT
|
echo "should_run=true" >> "$GITHUB_OUTPUT"
|
||||||
else
|
else
|
||||||
echo "Decision: Conditions not met. Setting should_run=false."
|
echo "Decision: Conditions not met. Setting should_run=false."
|
||||||
echo "should_run=false" >> $GITHUB_OUTPUT
|
echo "should_run=false" >> "$GITHUB_OUTPUT"
|
||||||
fi
|
fi
|
||||||
4
.github/workflows/ci-master.yml
vendored
4
.github/workflows/ci-master.yml
vendored
@@ -13,7 +13,7 @@ jobs:
|
|||||||
matrix:
|
matrix:
|
||||||
node-version: [20.x, 22.x, 24.3.x]
|
node-version: [20.x, 22.x, 24.3.x]
|
||||||
with:
|
with:
|
||||||
ref: ${{ inputs.branch }}
|
ref: ${{ github.sha }}
|
||||||
nodeVersion: ${{ matrix.node-version }}
|
nodeVersion: ${{ matrix.node-version }}
|
||||||
collectCoverage: ${{ matrix.node-version == '22.x' }}
|
collectCoverage: ${{ matrix.node-version == '22.x' }}
|
||||||
secrets:
|
secrets:
|
||||||
@@ -23,7 +23,7 @@ jobs:
|
|||||||
name: Lint
|
name: Lint
|
||||||
uses: ./.github/workflows/linting-reusable.yml
|
uses: ./.github/workflows/linting-reusable.yml
|
||||||
with:
|
with:
|
||||||
ref: ${{ inputs.branch }}
|
ref: ${{ github.sha }}
|
||||||
|
|
||||||
notify-on-failure:
|
notify-on-failure:
|
||||||
name: Notify Slack on failure
|
name: Notify Slack on failure
|
||||||
|
|||||||
80
.github/workflows/docker-build-push.yml
vendored
80
.github/workflows/docker-build-push.yml
vendored
@@ -71,15 +71,19 @@ jobs:
|
|||||||
# Check if called by another workflow (has n8n_version input)
|
# Check if called by another workflow (has n8n_version input)
|
||||||
if [[ -n "${{ inputs.n8n_version }}" ]]; then
|
if [[ -n "${{ inputs.n8n_version }}" ]]; then
|
||||||
# workflow_call - used for releases
|
# workflow_call - used for releases
|
||||||
echo "release_type=${{ inputs.release_type }}" >> $GITHUB_OUTPUT
|
{
|
||||||
echo "n8n_version=${{ inputs.n8n_version }}" >> $GITHUB_OUTPUT
|
echo "release_type=${{ inputs.release_type }}"
|
||||||
echo "push_enabled=${{ inputs.push_enabled }}" >> $GITHUB_OUTPUT
|
echo "n8n_version=${{ inputs.n8n_version }}"
|
||||||
|
echo "push_enabled=${{ inputs.push_enabled }}"
|
||||||
|
} >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
elif [[ "${{ github.event_name }}" == "schedule" ]]; then
|
elif [[ "${{ github.event_name }}" == "schedule" ]]; then
|
||||||
# Nightly builds
|
# Nightly builds
|
||||||
echo "release_type=nightly" >> $GITHUB_OUTPUT
|
{
|
||||||
echo "n8n_version=snapshot" >> $GITHUB_OUTPUT
|
echo "release_type=nightly"
|
||||||
echo "push_enabled=true" >> $GITHUB_OUTPUT
|
echo "n8n_version=snapshot"
|
||||||
|
echo "push_enabled=true"
|
||||||
|
} >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
elif [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
|
elif [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
|
||||||
# Build branches for Nathan deploy
|
# Build branches for Nathan deploy
|
||||||
@@ -98,22 +102,26 @@ jobs:
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "release_type=branch" >> $GITHUB_OUTPUT
|
{
|
||||||
echo "n8n_version=branch-${SAFE_BRANCH_NAME}" >> $GITHUB_OUTPUT
|
echo "release_type=branch"
|
||||||
echo "push_enabled=${{ inputs.push_enabled }}" >> $GITHUB_OUTPUT
|
echo "n8n_version=branch-${SAFE_BRANCH_NAME}"
|
||||||
|
echo "push_enabled=${{ inputs.push_enabled }}"
|
||||||
|
} >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
elif [[ "${{ github.event_name }}" == "pull_request" ]]; then
|
elif [[ "${{ github.event_name }}" == "pull_request" ]]; then
|
||||||
# Direct PR triggers for testing Dockerfile changes
|
# 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 "release_type=dev"
|
||||||
echo "push_enabled=false" >> $GITHUB_OUTPUT
|
echo "n8n_version=pr-${{ github.event.pull_request.number }}"
|
||||||
|
echo "push_enabled=false"
|
||||||
|
} >> "$GITHUB_OUTPUT"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Output summary for logs
|
# Output summary for logs
|
||||||
echo "=== Build Context Summary ==="
|
echo "=== Build Context Summary ==="
|
||||||
echo "Release type: $(grep release_type $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 "N8N version: $(grep n8n_version "$GITHUB_OUTPUT" | cut -d= -f2)"
|
||||||
echo "Push enabled: $(grep push_enabled $GITHUB_OUTPUT | cut -d= -f2)"
|
echo "Push enabled: $(grep push_enabled "$GITHUB_OUTPUT" | cut -d= -f2)"
|
||||||
|
|
||||||
- name: Determine build matrix
|
- name: Determine build matrix
|
||||||
id: matrix
|
id: matrix
|
||||||
@@ -147,8 +155,8 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# Output matrix as single line for GITHUB_OUTPUT
|
# Output matrix as single line for GITHUB_OUTPUT
|
||||||
echo "matrix=$(echo $MATRIX | jq -c .)" >> $GITHUB_OUTPUT
|
echo "matrix=$(echo "$MATRIX" | jq -c .)" >> "$GITHUB_OUTPUT"
|
||||||
echo "Build matrix: $(echo $MATRIX | jq .)"
|
echo "Build matrix: $(echo "$MATRIX" | jq .)"
|
||||||
|
|
||||||
build-and-push-docker:
|
build-and-push-docker:
|
||||||
name: Build App, then Build and Push Docker Image (${{ matrix.platform }})
|
name: Build App, then Build and Push Docker Image (${{ matrix.platform }})
|
||||||
@@ -236,16 +244,20 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
echo "Generated Tags for push: $ALL_TAGS"
|
echo "Generated Tags for push: $ALL_TAGS"
|
||||||
echo "tags<<EOF" >> $GITHUB_OUTPUT
|
{
|
||||||
echo -e "$ALL_TAGS" >> $GITHUB_OUTPUT
|
echo "tags<<EOF"
|
||||||
echo "EOF" >> $GITHUB_OUTPUT
|
echo -e "$ALL_TAGS"
|
||||||
|
echo "EOF"
|
||||||
|
} >> "$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
|
# Only output manifest tags from the first platform to avoid duplicates
|
||||||
if [[ "$PLATFORM" == "amd64" ]]; then
|
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
|
fi
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
@@ -309,23 +321,29 @@ jobs:
|
|||||||
# Determine if Docker Hub manifest is needed and construct the tag
|
# Determine if Docker Hub manifest is needed and construct the tag
|
||||||
case "$RELEASE_TYPE" in
|
case "$RELEASE_TYPE" in
|
||||||
"stable")
|
"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")
|
"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")
|
"dev")
|
||||||
if [[ "$N8N_VERSION" != pr-* ]]; then
|
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
|
else
|
||||||
echo "CREATE_DOCKERHUB_MANIFEST=false" >> $GITHUB_OUTPUT
|
echo "CREATE_DOCKERHUB_MANIFEST=false" >> "$GITHUB_OUTPUT"
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
echo "CREATE_DOCKERHUB_MANIFEST=false" >> $GITHUB_OUTPUT
|
echo "CREATE_DOCKERHUB_MANIFEST=false" >> "$GITHUB_OUTPUT"
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
|
|||||||
2
.github/workflows/e2e-reusable.yml
vendored
2
.github/workflows/e2e-reusable.yml
vendored
@@ -77,7 +77,7 @@ jobs:
|
|||||||
wait-on: 'http://localhost:5678'
|
wait-on: 'http://localhost:5678'
|
||||||
wait-on-timeout: 120
|
wait-on-timeout: 120
|
||||||
record: ${{ inputs.record }}
|
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
|
# 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
|
# in the same parent workflow
|
||||||
ci-build-id: ${{ github.run_id }}-${{ github.run_attempt }}
|
ci-build-id: ${{ github.run_id }}-${{ github.run_attempt }}
|
||||||
|
|||||||
2
.github/workflows/release-create-pr.yml
vendored
2
.github/workflows/release-create-pr.yml
vendored
@@ -48,7 +48,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Bump package versions
|
- name: Bump package versions
|
||||||
run: |
|
run: |
|
||||||
echo "NEXT_RELEASE=$(node .github/scripts/bump-versions.mjs)" >> $GITHUB_ENV
|
echo "NEXT_RELEASE=$(node .github/scripts/bump-versions.mjs)" >> "$GITHUB_ENV"
|
||||||
env:
|
env:
|
||||||
RELEASE_TYPE: ${{ github.event.inputs.release-type }}
|
RELEASE_TYPE: ${{ github.event.inputs.release-type }}
|
||||||
|
|
||||||
|
|||||||
4
.github/workflows/release-publish.yml
vendored
4
.github/workflows/release-publish.yml
vendored
@@ -37,7 +37,7 @@ jobs:
|
|||||||
- run: pnpm install --frozen-lockfile
|
- run: pnpm install --frozen-lockfile
|
||||||
|
|
||||||
- name: Set release version in env
|
- 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
|
- name: Build
|
||||||
run: pnpm build
|
run: pnpm build
|
||||||
@@ -67,7 +67,7 @@ jobs:
|
|||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
|
|
||||||
- id: set-release
|
- id: set-release
|
||||||
run: echo "release=${{ env.RELEASE }}" >> $GITHUB_OUTPUT
|
run: echo "release=${{ env.RELEASE }}" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
publish-to-docker-hub:
|
publish-to-docker-hub:
|
||||||
name: Publish to DockerHub
|
name: Publish to DockerHub
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ jobs:
|
|||||||
|
|
||||||
if [[ "$input_version" =~ $version_regex ]]; then
|
if [[ "$input_version" =~ $version_regex ]]; then
|
||||||
echo "Version format is valid: $input_version"
|
echo "Version format is valid: $input_version"
|
||||||
echo "version=$input_version" >> $GITHUB_OUTPUT
|
echo "version=$input_version" >> "$GITHUB_OUTPUT"
|
||||||
else
|
else
|
||||||
echo "::error::Invalid version format provided: '$input_version'. Must match regex '$version_regex'."
|
echo "::error::Invalid version format provided: '$input_version'. Must match regex '$version_regex'."
|
||||||
exit 1
|
exit 1
|
||||||
|
|||||||
122
.github/workflows/security-trivy-scan-callable.yml
vendored
122
.github/workflows/security-trivy-scan-callable.yml
vendored
@@ -14,14 +14,14 @@ on:
|
|||||||
description: 'Full image reference to scan e.g. ghcr.io/n8n-io/n8n:latest'
|
description: 'Full image reference to scan e.g. ghcr.io/n8n-io/n8n:latest'
|
||||||
required: true
|
required: true
|
||||||
secrets:
|
secrets:
|
||||||
SLACK_BOT_TOKEN:
|
QBOT_SLACK_TOKEN:
|
||||||
required: true
|
required: true
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
|
|
||||||
env:
|
env:
|
||||||
SLACK_BOT_TOKEN: ${{ secrets.QBOT_SLACK_TOKEN }}
|
QBOT_SLACK_TOKEN: ${{ secrets.QBOT_SLACK_TOKEN }}
|
||||||
SLACK_CHANNEL_ID: C042WDXPTEZ #mission-security
|
SLACK_CHANNEL_ID: C042WDXPTEZ #mission-security
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
@@ -43,16 +43,18 @@ jobs:
|
|||||||
- name: Calculate vulnerability counts
|
- name: Calculate vulnerability counts
|
||||||
id: process_results
|
id: process_results
|
||||||
run: |
|
run: |
|
||||||
if [ ! -s trivy-results.json ] || [ $(jq '.Results | length' trivy-results.json) -eq 0 ]; then
|
if [ ! -s trivy-results.json ] || [ "$(jq '.Results | length' trivy-results.json)" -eq 0 ]; then
|
||||||
echo "No high-severity vulnerabilities found."
|
echo "No vulnerabilities found."
|
||||||
echo "vulnerabilities_found=false" >> $GITHUB_OUTPUT
|
echo "vulnerabilities_found=false" >> "$GITHUB_OUTPUT"
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Calculate counts by severity
|
# Calculate counts by severity
|
||||||
CRITICAL_COUNT=$(jq '([.Results[]?.Vulnerabilities[]? | select(.Severity == "CRITICAL")] | length)' trivy-results.json)
|
CRITICAL_COUNT=$(jq '([.Results[]?.Vulnerabilities[]? | select(.Severity == "CRITICAL")] | length)' trivy-results.json)
|
||||||
HIGH_COUNT=$(jq '([.Results[]?.Vulnerabilities[]? | select(.Severity == "HIGH")] | 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
|
# Get unique CVE count
|
||||||
UNIQUE_CVES=$(jq -r '[.Results[]?.Vulnerabilities[]?.VulnerabilityID] | unique | length' trivy-results.json)
|
UNIQUE_CVES=$(jq -r '[.Results[]?.Vulnerabilities[]?.VulnerabilityID] | unique | length' trivy-results.json)
|
||||||
@@ -60,12 +62,16 @@ jobs:
|
|||||||
# Get affected packages count
|
# Get affected packages count
|
||||||
AFFECTED_PACKAGES=$(jq -r '[.Results[]?.Vulnerabilities[]? | .PkgName] | unique | length' trivy-results.json)
|
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 "vulnerabilities_found=$( [ "$TOTAL_VULNS" -gt 0 ] && echo 'true' || echo 'false' )"
|
||||||
echo "critical_count=$CRITICAL_COUNT" >> $GITHUB_OUTPUT
|
echo "total_count=$TOTAL_VULNS"
|
||||||
echo "high_count=$HIGH_COUNT" >> $GITHUB_OUTPUT
|
echo "critical_count=$CRITICAL_COUNT"
|
||||||
echo "unique_cves=$UNIQUE_CVES" >> $GITHUB_OUTPUT
|
echo "high_count=$HIGH_COUNT"
|
||||||
echo "affected_packages=$AFFECTED_PACKAGES" >> $GITHUB_OUTPUT
|
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
|
- name: Generate GitHub Job Summary
|
||||||
if: always()
|
if: always()
|
||||||
@@ -76,10 +82,12 @@ jobs:
|
|||||||
echo "**Image:** \`${{ inputs.image_ref }}\`"
|
echo "**Image:** \`${{ inputs.image_ref }}\`"
|
||||||
echo "**Scan Date:** $(date -u '+%Y-%m-%d %H:%M:%S UTC')"
|
echo "**Scan Date:** $(date -u '+%Y-%m-%d %H:%M:%S UTC')"
|
||||||
echo ""
|
echo ""
|
||||||
} >> $GITHUB_STEP_SUMMARY
|
} >> "$GITHUB_STEP_SUMMARY"
|
||||||
|
|
||||||
if [ "${{ steps.process_results.outputs.vulnerabilities_found }}" == "false" ]; then
|
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
|
else
|
||||||
{
|
{
|
||||||
echo "## 📊 Summary"
|
echo "## 📊 Summary"
|
||||||
@@ -87,43 +95,52 @@ jobs:
|
|||||||
echo "|--------|-------|"
|
echo "|--------|-------|"
|
||||||
echo "| 🔴 Critical Vulnerabilities | ${{ steps.process_results.outputs.critical_count }} |"
|
echo "| 🔴 Critical Vulnerabilities | ${{ steps.process_results.outputs.critical_count }} |"
|
||||||
echo "| 🟠 High Vulnerabilities | ${{ steps.process_results.outputs.high_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 "| 📋 Unique CVEs | ${{ steps.process_results.outputs.unique_cves }} |"
|
||||||
echo "| 📦 Affected Packages | ${{ steps.process_results.outputs.affected_packages }} |"
|
echo "| 📦 Affected Packages | ${{ steps.process_results.outputs.affected_packages }} |"
|
||||||
echo ""
|
echo ""
|
||||||
echo "## 🚨 Top Vulnerabilities"
|
echo "## 🚨 Top Vulnerabilities"
|
||||||
echo ""
|
echo ""
|
||||||
} >> $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 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
|
|
||||||
|
|
||||||
{
|
{
|
||||||
|
# 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 "---"
|
echo "---"
|
||||||
echo "🔍 **View detailed logs above for full analysis**"
|
echo "🔍 **View detailed logs above for full analysis**"
|
||||||
} >> $GITHUB_STEP_SUMMARY
|
} >> "$GITHUB_STEP_SUMMARY"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Generate Slack Blocks JSON
|
- name: Generate Slack Blocks JSON
|
||||||
@@ -136,6 +153,8 @@ jobs:
|
|||||||
--arg run_url "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" \
|
--arg run_url "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" \
|
||||||
--arg critical_count "${{ steps.process_results.outputs.critical_count }}" \
|
--arg critical_count "${{ steps.process_results.outputs.critical_count }}" \
|
||||||
--arg high_count "${{ steps.process_results.outputs.high_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 }}" \
|
--arg unique_cves "${{ steps.process_results.outputs.unique_cves }}" \
|
||||||
'
|
'
|
||||||
# Function to create a vulnerability block with emoji indicators
|
# Function to create a vulnerability block with emoji indicators
|
||||||
@@ -143,7 +162,7 @@ jobs:
|
|||||||
"type": "section",
|
"type": "section",
|
||||||
"text": {
|
"text": {
|
||||||
"type": "mrkdwn",
|
"type": "mrkdwn",
|
||||||
"text": "\(if .Severity == "CRITICAL" then ":red_circle:" else ":large_orange_circle:" end) *<https://nvd.nist.gov/vuln/detail/\(.VulnerabilityID)|\(.VulnerabilityID)>* (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) *<https://nvd.nist.gov/vuln/detail/\(.VulnerabilityID)|\(.VulnerabilityID)>* (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": "*Repository:*\n<\($repo_url)|\($repo_name)>" },
|
||||||
{ "type": "mrkdwn", "text": "*Image:*\n`\($image_ref)`" },
|
{ "type": "mrkdwn", "text": "*Image:*\n`\($image_ref)`" },
|
||||||
{ "type": "mrkdwn", "text": "*Critical:*\n:red_circle: \($critical_count)" },
|
{ "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[]] |
|
[.Results[] | select(.Vulnerabilities != null) | .Vulnerabilities[]] |
|
||||||
group_by(.VulnerabilityID) |
|
group_by(.VulnerabilityID) |
|
||||||
map(.[0]) |
|
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] |
|
.[:8] |
|
||||||
map(. | vuln_block)
|
map(. | vuln_block)
|
||||||
) +
|
) +
|
||||||
@@ -195,15 +223,15 @@ jobs:
|
|||||||
]
|
]
|
||||||
' trivy-results.json)
|
' trivy-results.json)
|
||||||
|
|
||||||
echo "slack_blocks=$BLOCKS_JSON" >> $GITHUB_OUTPUT
|
echo "slack_blocks=$BLOCKS_JSON" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
- name: Send Slack Notification
|
- name: Send Slack Notification
|
||||||
if: steps.process_results.outputs.vulnerabilities_found == 'true'
|
if: steps.process_results.outputs.vulnerabilities_found == 'true'
|
||||||
uses: slackapi/slack-github-action@91efab103c0de0a537f72a35f6b8cda0ee76bf0a # v2.1.1
|
uses: slackapi/slack-github-action@91efab103c0de0a537f72a35f6b8cda0ee76bf0a # v2.1.1
|
||||||
with:
|
with:
|
||||||
method: chat.postMessage
|
method: chat.postMessage
|
||||||
token: ${{ secrets.SLACK_BOT_TOKEN }}
|
token: ${{ secrets.QBOT_SLACK_TOKEN }}
|
||||||
payload: |
|
payload: |
|
||||||
channel: ${{ env.SLACK_CHANNEL_ID }}
|
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 }}
|
blocks: ${{ steps.generate_blocks.outputs.slack_blocks }}
|
||||||
|
|||||||
4
.github/workflows/sync-public-api-docs.yml
vendored
4
.github/workflows/sync-public-api-docs.yml
vendored
@@ -49,10 +49,10 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
if [[ -f "packages/cli/dist/public-api/v1/openapi.yml" ]]; then
|
if [[ -f "packages/cli/dist/public-api/v1/openapi.yml" ]]; then
|
||||||
echo "OpenAPI file found: packages/cli/dist/public-api/v1/openapi.yml"
|
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
|
else
|
||||||
echo "ERROR: OpenAPI file not found at packages/cli/dist/public-api/v1/openapi.yml after build."
|
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
|
fi
|
||||||
|
|
||||||
- name: Generate GitHub App Token
|
- name: Generate GitHub App Token
|
||||||
|
|||||||
@@ -122,6 +122,16 @@ MacOS:
|
|||||||
|
|
||||||
No additional packages required.
|
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
|
### Actual n8n setup
|
||||||
|
|
||||||
> **IMPORTANT**: All the steps below have to get executed at least once to get the development setup up and running!
|
> **IMPORTANT**: All the steps below have to get executed at least once to get the development setup up and running!
|
||||||
|
|||||||
@@ -20,3 +20,9 @@ pre-commit:
|
|||||||
skip:
|
skip:
|
||||||
- merge
|
- merge
|
||||||
- rebase
|
- rebase
|
||||||
|
actionlint_check:
|
||||||
|
glob: '.github/workflows/*.{yml,yaml}'
|
||||||
|
run: actionlint {staged_files}
|
||||||
|
skip:
|
||||||
|
- merge
|
||||||
|
- rebase
|
||||||
|
|||||||
Reference in New Issue
Block a user