Class: Rules::MissingEnvProtection

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

Constant Summary collapse

PUBLISH_INDICATORS =
/npm publish|pnpm publish|twine upload|gem push|docker push|railway up|cdk deploy/
OIDC_PUBLISH =
/id-token:\s*write/

Instance Method Summary collapse

Instance Method Details

#check(workflow) ⇒ Object



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
# File 'lib/rules/missing_env_protection.rb', line 10

def check(workflow)
  findings = []

  workflow.jobs.each do |job_id, job|
    next if job.key?("environment")

    steps = workflow.steps(job)
    has_publish = steps.any? { |s| s["run"]&.match?(PUBLISH_INDICATORS) }

    job_perms = workflow.permissions(scope: :job, job: job)
    has_oidc = job_perms&.to_s&.match?(OIDC_PUBLISH) ||
               workflow.permissions(scope: :workflow)&.to_s&.match?(OIDC_PUBLISH)

    if has_publish || has_oidc
      line = workflow.line_of(/^\s+#{Regexp.escape(job_id)}:/)
      findings << finding(workflow,
        line: line || 0,
        code: "#{job_id}:",
        message: "Publish/deploy job without environment protection — no human gate before publication",
        fix: "Add environment: <name> with required reviewers"
      )
    end
  end

  findings
end

#descriptionObject



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

def description = "Publish/deploy job without GitHub Environment protection"

#nameObject



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

def name = "missing-env-protection"

#severityObject



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

def severity = :medium