mirror of
https://github.com/n8n-io/n8n
synced 2026-04-21 07:37:20 +00:00
ci: Add poutine custom rule for unpinned GitHub Actions detection (#24577)
This commit is contained in:
parent
2b4596eb66
commit
924817d9fd
9 changed files with 65 additions and 8 deletions
43
.github/poutine-rules/unpinned_action.rego
vendored
Normal file
43
.github/poutine-rules/unpinned_action.rego
vendored
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
# METADATA
|
||||
# title: Unpinned GitHub Action
|
||||
# description: |-
|
||||
# GitHub Action not pinned to full commit SHA.
|
||||
# Pin actions to SHA for supply chain security.
|
||||
# custom:
|
||||
# level: error
|
||||
package rules.unpinned_action
|
||||
|
||||
import data.poutine
|
||||
import rego.v1
|
||||
|
||||
rule := poutine.rule(rego.metadata.chain())
|
||||
|
||||
# Match 40-character hex SHA (Git) or 64-character sha256 digest (Docker)
|
||||
is_sha_pinned(uses) if {
|
||||
regex.match(`@(sha256:[a-f0-9]{64}|[a-f0-9]{40})`, uses)
|
||||
}
|
||||
|
||||
# Check if it's a local action (starts with ./)
|
||||
is_local_action(uses) if {
|
||||
startswith(uses, "./")
|
||||
}
|
||||
|
||||
# Check if it's a reusable workflow call
|
||||
is_reusable_workflow(uses) if {
|
||||
contains(uses, ".github/workflows/")
|
||||
}
|
||||
|
||||
results contains poutine.finding(rule, pkg.purl, {
|
||||
"path": workflow.path,
|
||||
"job": job.id,
|
||||
"step": i,
|
||||
"details": sprintf("Action '%s' should be pinned to a full commit SHA", [step.uses]),
|
||||
}) if {
|
||||
pkg := input.packages[_]
|
||||
workflow := pkg.github_actions_workflows[_]
|
||||
job := workflow.jobs[_]
|
||||
step := job.steps[i]
|
||||
step.uses
|
||||
not is_sha_pinned(step.uses)
|
||||
not is_local_action(step.uses)
|
||||
}
|
||||
|
|
@ -18,7 +18,7 @@ jobs:
|
|||
steps:
|
||||
- name: Validate user permissions and collect PR data
|
||||
id: check_permissions
|
||||
uses: actions/github-script@v7
|
||||
uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
script: |
|
||||
|
|
|
|||
4
.github/workflows/ci-manual-unit-tests.yml
vendored
4
.github/workflows/ci-manual-unit-tests.yml
vendored
|
|
@ -25,7 +25,7 @@ jobs:
|
|||
steps:
|
||||
- name: Create pending check run on PR
|
||||
id: create
|
||||
uses: actions/github-script@v7
|
||||
uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
script: |
|
||||
|
|
@ -88,7 +88,7 @@ jobs:
|
|||
steps:
|
||||
- name: Update check run on PR (if triggered from PR comment)
|
||||
if: inputs.pr_number != ''
|
||||
uses: actions/github-script@v7
|
||||
uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
script: |
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ jobs:
|
|||
contents: write
|
||||
pull-requests: write
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Validate inputs
|
||||
|
|
|
|||
10
.github/workflows/sec-poutine-reusable.yml
vendored
10
.github/workflows/sec-poutine-reusable.yml
vendored
|
|
@ -27,6 +27,16 @@ jobs:
|
|||
- name: Run Poutine Security Scanner
|
||||
uses: boostsecurityio/poutine-action@84c0a0d32e8d57ae12651222be1eb15351429228 # v0.15.2
|
||||
|
||||
- name: Fail on error-level findings
|
||||
run: |
|
||||
# Check SARIF for error-level findings
|
||||
if jq -e '.runs[].results[] | select(.level == "error")' results.sarif > /dev/null 2>&1; then
|
||||
echo "::error::Poutine found error-level security findings:"
|
||||
jq -r '.runs[].results[] | select(.level == "error") | " - \(.ruleId): \(.message.text)"' results.sarif
|
||||
exit 1
|
||||
fi
|
||||
echo "No error-level findings detected"
|
||||
|
||||
- name: Upload SARIF results
|
||||
uses: github/codeql-action/upload-sarif@48ab28a6f5dbc2a99bf1e0131198dd8f1df78169 # v3.28.0
|
||||
if: always()
|
||||
|
|
|
|||
2
.github/workflows/test-visual-chromatic.yml
vendored
2
.github/workflows/test-visual-chromatic.yml
vendored
|
|
@ -16,7 +16,7 @@ jobs:
|
|||
runs-on: blacksmith-2vcpu-ubuntu-2204
|
||||
steps:
|
||||
- name: Determine changed files
|
||||
uses: tomi/paths-filter-action@v3.0.2
|
||||
uses: tomi/paths-filter-action@32c62f5ca100c1110406e3477d5b3ecef4666fec # v3.0.2
|
||||
id: changed
|
||||
if: github.event_name == 'pull_request_review'
|
||||
with:
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ jobs:
|
|||
steps:
|
||||
- name: Validate User, Get PR Details, and React
|
||||
id: pr_check_and_details
|
||||
uses: actions/github-script@v7
|
||||
uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
script: |
|
||||
|
|
|
|||
4
.github/workflows/util-claude.yml
vendored
4
.github/workflows/util-claude.yml
vendored
|
|
@ -25,12 +25,12 @@ jobs:
|
|||
id-token: write
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
||||
with:
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Run Claude PR Action
|
||||
uses: anthropics/claude-code-action@beta
|
||||
uses: anthropics/claude-code-action@de8e0b9c42c6cb58e904c857f164aa072244c1ac # beta
|
||||
with:
|
||||
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
|
||||
# Or use OAuth token instead:
|
||||
|
|
|
|||
|
|
@ -4,6 +4,10 @@
|
|||
# This file defines skip rules for known-safe patterns.
|
||||
# Add new entries only after security review.
|
||||
|
||||
# Custom rules for additional security checks
|
||||
include:
|
||||
- path: .github/poutine-rules
|
||||
|
||||
skip:
|
||||
# === SELF-HOSTED RUNNERS ===
|
||||
# We use Blacksmith (trusted CI provider) for self-hosted runners.
|
||||
|
|
|
|||
Loading…
Reference in a new issue