mirror of
https://github.com/n8n-io/n8n
synced 2026-04-21 15:47:20 +00:00
43 lines
1 KiB
Rego
43 lines
1 KiB
Rego
# 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)
|
|
}
|