Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(findings): include 'event_triggers' in finding metadata #233

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions opa/rego/rules/debug_enabled.rego
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ is_debug_enabled(var) if {
results contains poutine.finding(rule, pkg.purl, {
"path": workflow.path,
"details": var.name,
"event_triggers": [event | event := workflow.events[i].name],
}) if {
pkg := input.packages[_]
workflow := pkg.github_actions_workflows[_]
Expand All @@ -64,6 +65,7 @@ results contains poutine.finding(rule, pkg.purl, {
"job": job.id,
"details": var.name,
"line": job.lines.start,
"event_triggers": [event | event := workflow.events[i].name],
}) if {
pkg := input.packages[_]
workflow := pkg.github_actions_workflows[_]
Expand All @@ -78,6 +80,7 @@ results contains poutine.finding(rule, pkg.purl, {
"step": step_id,
"details": var.name,
"line": step.lines.start,
"event_triggers": [event | event := workflow.events[i].name],
}) if {
pkg := input.packages[_]
workflow := pkg.github_actions_workflows[_]
Expand Down
14 changes: 10 additions & 4 deletions opa/rego/rules/default_permissions_on_risky_events.rego
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
# METADATA
# title: Default permissions used on risky events
# description: |-
# The workflow and some of its jobs do not explicitely define permissions
# The workflow and some of its jobs do not explicitely define permissions
# and the workflow triggers on events that are typically used to run builds from forks.
# Because no permissions is set, the workflow inherits the default permissions
# Because no permissions is set, the workflow inherits the default permissions
# configured on the repository or the organization.
# custom:
# level: warning
Expand All @@ -20,7 +20,10 @@ github.events contains event if some event in {
"issue_comment",
}

results contains poutine.finding(rule, pkg.purl, {"path": workflow.path}) if {
results contains poutine.finding(rule, pkg.purl, {
"path": workflow.path,
"event_triggers": [event | event := workflow.events[j].name],
}) if {
pkg := input.packages[_]
workflow = pkg.github_actions_workflows[_]
job := workflow.jobs[_]
Expand All @@ -31,7 +34,10 @@ results contains poutine.finding(rule, pkg.purl, {"path": workflow.path}) if {
utils.empty(job.permissions)
}

results contains poutine.finding(rule, pkg.purl, {"path": workflow.path}) if {
results contains poutine.finding(rule, pkg.purl, {
"path": workflow.path,
"event_triggers": [event | event := workflow.events[j].name],
}) if {
pkg := input.packages[_]
workflow = pkg.github_actions_workflows[_]
job := workflow.jobs[_]
Expand Down
2 changes: 2 additions & 0 deletions opa/rego/rules/if_always_true.rego
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ if_conditions[pkg.purl] contains {
"path": workflow.path,
"line": object.get(job.lines, "if", 0),
"job": job.id,
"event_triggers": [event | event := workflow.events[j].name],
} if {
pkg := input.packages[_]
workflow = pkg.github_actions_workflows[_]
Expand All @@ -47,6 +48,7 @@ if_conditions[pkg.purl] contains {
"line": object.get(step.lines, "if", 0),
"job": job.id,
"step": step_id,
"event_triggers": [event | event := workflow.events[j].name],
} if {
pkg := input.packages[_]
workflow = pkg.github_actions_workflows[_]
Expand Down
30 changes: 15 additions & 15 deletions opa/rego/rules/injection.rego
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# METADATA
# title: Injection with Arbitrary External Contributor Input
# description: |-
# The pipeline contains an injection into bash or JavaScript with an expression
# that can contain user input. Prefer placing the expression in an environment variable
# The pipeline contains an injection into bash or JavaScript with an expression
# that can contain user input. Prefer placing the expression in an environment variable
# instead of interpolating it directly into a script.
# related_resources:
# - https://securitylab.github.com/research/github-actions-preventing-pwn-requests/
Expand Down Expand Up @@ -33,6 +33,7 @@ results contains poutine.finding(rule, pkg.purl, {
"job": job.id,
"step": i,
"details": sprintf("Sources: %s", [concat(" ", exprs)]),
"event_triggers": [event | event := workflow.events[j].name],
}) if {
pkg = input.packages[_]
workflow = pkg.github_actions_workflows[_]
Expand All @@ -47,6 +48,7 @@ results contains poutine.finding(rule, pkg.purl, {
"line": line,
"step": i,
"details": sprintf("Sources: %s", [concat(" ", exprs)]),
"event_triggers": [event | event := action.events[j].name],
}) if {
pkg = input.packages[_]
action := pkg.github_actions_metadata[_]
Expand Down Expand Up @@ -113,19 +115,17 @@ results contains poutine.finding(rule, pkg.purl, {
"path": pipeline.path,
"job": task.name,
"step": step_idx,
"line": step.lines["start"],
"line": step.lines.start,
"details": sprintf("Sources: %s", [concat(" ", exprs)]),
}) if {
pkg := input.packages[_]
pipeline := pkg.pipeline_as_code_tekton[_]
contains(pipeline.api_version, "tekton.dev")
pipeline.kind == "PipelineRun"
contains(pipeline.metadata.annotations["pipelinesascode.tekton.dev/on-event"], "pull_request")
task := pipeline.spec.pipeline_spec.tasks[_]
step := task.task_spec.steps[step_idx]

exprs := pipeline_as_code_tekton_injections(step.script)
count(exprs) > 0
pkg := input.packages[_]
pipeline := pkg.pipeline_as_code_tekton[_]
contains(pipeline.api_version, "tekton.dev")
pipeline.kind == "PipelineRun"
contains(pipeline.metadata.annotations["pipelinesascode.tekton.dev/on-event"], "pull_request")
task := pipeline.spec.pipeline_spec.tasks[_]
step := task.task_spec.steps[step_idx]

exprs := pipeline_as_code_tekton_injections(step.script)
count(exprs) > 0
}


7 changes: 4 additions & 3 deletions opa/rego/rules/job_all_secrets.rego
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
# METADATA
# title: Workflow job exposes all secrets
# description: |-
# The GitHub Actions Runner attempts to keep in memory only the secrets
# that are necessary to execute a workflow job.
# If a job converts the secrets object to JSON or accesses it using an expression,
# The GitHub Actions Runner attempts to keep in memory only the secrets
# that are necessary to execute a workflow job.
# If a job converts the secrets object to JSON or accesses it using an expression,
# all secrets will be retained in memory for the duration of the job.
# custom:
# level: warning
Expand All @@ -18,6 +18,7 @@ results contains poutine.finding(rule, pkg.purl, {
"path": workflow.path,
"job": job.id,
"line": job.lines.start,
"event_triggers": [event | event := workflow.events[i].name],
}) if {
pkg := input.packages[_]
workflow := pkg.github_actions_workflows[_]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ results contains poutine.finding(rule, pkg.purl, {
"step": i,
"osv_id": advisory.osv_id,
"details": sprintf("Package: %s", [advisory.package_name]),
"event_triggers": [event | event := workflow.events[j].name],
}) if {
pkg = input.packages[_]
workflow = pkg.github_actions_workflows[_]
Expand Down
1 change: 1 addition & 0 deletions opa/rego/rules/pr_runs_on_self_hosted.rego
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ results contains poutine.finding(rule, pkg.purl, {
"job": job.id,
"line": job.lines.runs_on,
"details": sprintf("runs-on: %s", [concat(", ", job.runs_on)]),
"event_triggers": [event | event := workflow.events[i].name],
}) if {
pkg := input.packages[_]
workflow = pkg.github_actions_workflows[_]
Expand Down
2 changes: 1 addition & 1 deletion opa/rego/rules/unpinnable_action.rego
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# METADATA
# title: Unpinnable CI component used
# description: |-
# Pinning this GitHub Action is likely ineffective
# Pinning this GitHub Action is likely ineffective
# as it depends on other mutable supply chain components.
# custom:
# level: note
Expand Down
30 changes: 17 additions & 13 deletions opa/rego/rules/untrusted_checkout_exec.rego
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,9 @@ results contains poutine.finding(rule, pkg_purl, {
"path": workflow_path,
"line": step.lines.run,
"details": sprintf("Detected usage of `%s`", [cmd]),
"event_triggers": workflow_events,
}) if {
[pkg_purl, workflow_path, step] := _steps_after_untrusted_checkout[_]
[pkg_purl, workflow_path, workflow_events, step] := _steps_after_untrusted_checkout[_]
regex.match(
sprintf("([^a-z]|^)(%v)", [concat("|", build_commands[cmd])]),
step.run,
Expand All @@ -63,24 +64,27 @@ results contains poutine.finding(rule, pkg_purl, {
"path": workflow_path,
"line": step.lines.uses,
"details": sprintf("Detected usage the GitHub Action `%s`", [step.action]),
"event_triggers": workflow_events,
}) if {
[pkg_purl, workflow_path, step] := _steps_after_untrusted_checkout[_]
[pkg_purl, workflow_path, workflow_events, step] := _steps_after_untrusted_checkout[_]
build_github_actions[step.action]
}

_steps_after_untrusted_checkout contains [pkg.purl, workflow.path, s.step] if {
_steps_after_untrusted_checkout contains [pkg.purl, workflow.path, events, s.step] if {
pkg := input.packages[_]
workflow := pkg.github_actions_workflows[_]

utils.filter_workflow_events(workflow, github.events)

events := [event | event := workflow.events[i].name]
pr_checkout := utils.find_pr_checkouts(workflow)[_]
s := utils.workflow_steps_after(pr_checkout)[_]
}

_steps_after_untrusted_checkout contains [pkg_purl, workflow.path, s.step] if {
_steps_after_untrusted_checkout contains [pkg_purl, workflow.path, events, s.step] if {
[pkg_purl, workflow] := _workflows_runs_from_pr[_]

events := [event | event := workflow.events[i].name]
pr_checkout := utils.find_pr_checkouts(workflow)[_]
s := utils.workflow_steps_after(pr_checkout)[_]
}
Expand Down Expand Up @@ -142,17 +146,17 @@ results contains poutine.finding(rule, pkg.purl, {
"path": pipeline.path,
"job": task.name,
"step": step_idx,
"line": step.lines["script"],
"line": step.lines.script,
"details": sprintf("Detected usage of `%s`", [cmd]),
}) if {
pkg := input.packages[_]
pipeline := pkg.pipeline_as_code_tekton[_]
contains(pipeline.api_version, "tekton.dev")
pipeline.kind == "PipelineRun"
contains(pipeline.metadata.annotations["pipelinesascode.tekton.dev/on-event"], "pull_request")
contains(pipeline.metadata.annotations["pipelinesascode.tekton.dev/task"], "git-clone")
task := pipeline.spec.pipeline_spec.tasks[_]
step := task.task_spec.steps[step_idx]
pkg := input.packages[_]
pipeline := pkg.pipeline_as_code_tekton[_]
contains(pipeline.api_version, "tekton.dev")
pipeline.kind == "PipelineRun"
contains(pipeline.metadata.annotations["pipelinesascode.tekton.dev/on-event"], "pull_request")
contains(pipeline.metadata.annotations["pipelinesascode.tekton.dev/task"], "git-clone")
task := pipeline.spec.pipeline_spec.tasks[_]
step := task.task_spec.steps[step_idx]
regex.match(
sprintf("([^a-z]|^)(%v)", [concat("|", build_commands[cmd])]),
step.script,
Expand Down
1 change: 1 addition & 0 deletions opa/rego/rules/unverified_script_exec.rego
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ _scripts[pkg.purl] contains {
"job": job.id,
"line": step.lines.run,
"details": details,
"event_triggers": [event | event := workflow.events[j].name],
} if {
pkg := input.packages[_]
workflow := pkg.github_actions_workflows[_]
Expand Down
13 changes: 7 additions & 6 deletions results/results.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,13 @@ type FindingsResult struct {
}

type FindingMeta struct {
Path string `json:"path,omitempty"`
Line int `json:"line,omitempty"`
Job string `json:"job,omitempty"`
Step string `json:"step,omitempty"`
OsvId string `json:"osv_id,omitempty"`
Details string `json:"details,omitempty"`
Path string `json:"path,omitempty"`
Line int `json:"line,omitempty"`
Job string `json:"job,omitempty"`
Step string `json:"step,omitempty"`
OsvId string `json:"osv_id,omitempty"`
Details string `json:"details,omitempty"`
EventTriggers []string `json:"event_triggers,omitempty"`
}

type Finding struct {
Expand Down
Loading