Class: Rules::SelfHostedRunnerFork

Inherits:
Base
  • Object
show all
Defined in:
lib/rules/self_hosted_runner_fork.rb

Constant Summary collapse

FORK_TRIGGERS =
%w[pull_request pull_request_target].freeze

Instance Method Summary collapse

Instance Method Details

#check(workflow) ⇒ Object



9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# File 'lib/rules/self_hosted_runner_fork.rb', line 9

def check(workflow)
    findings = []
    triggers = workflow.triggers

    fork_trigger = detect_fork_trigger(triggers)
    return findings unless fork_trigger

    # Skip if the trigger is gated by label-based types
    if gated_by_label?(triggers, fork_trigger)
        return findings
    end

    runs_on_lines = workflow.lines_of(/runs-on:/)
    runs_on_idx = 0

    workflow.jobs.each do |job_id, job|
        runs_on = job["runs-on"]
        next unless runs_on

        runs_on_str = runs_on.is_a?(Array) ? runs_on.join(", ") : runs_on.to_s

        # Advance through runs-on lines for each job regardless of self-hosted
        line = runs_on_lines[runs_on_idx]
        runs_on_idx += 1

        next unless runs_on_str.include?("self-hosted")

        findings << finding(workflow,
            line: line || 0,
            code: "runs-on: #{runs_on_str}",
            message: "Self-hosted runner with '#{fork_trigger}' trigger — fork PRs can run arbitrary code on your infrastructure",
            fix: "Use GitHub-hosted runners for fork PR workflows, or gate with a label-based trigger"
        )
    end

    findings
end

#descriptionObject



4
# File 'lib/rules/self_hosted_runner_fork.rb', line 4

def description = "Self-hosted runner exposed to fork PRs"

#nameObject



3
# File 'lib/rules/self_hosted_runner_fork.rb', line 3

def name = "self-hosted-runner-fork"

#severityObject



5
# File 'lib/rules/self_hosted_runner_fork.rb', line 5

def severity = :critical