Class: Rules::BuildPublishSameJob
- Defined in:
- lib/rules/build_publish_same_job.rb
Constant Summary collapse
- INSTALL_PATTERNS =
Regexp.union( # JavaScript / TypeScript /\bnpm\s+(install|ci)\b/, /\bpnpm\s+install\b/, /\byarn\s+install\b/, /\byarn\b(?!\s+(publish|add|remove|run|build|test|lint))/, /\bbun\s+install\b/, # Python /\bpip3?\s+install\b/, /\buv\s+(pip\s+install|sync)\b/, /\bpoetry\s+install\b/, /\bpipenv\s+install\b/, /\bconda\s+install\b/, # Ruby /\bbundle\s+install\b/, /\bbundle\b(?!\s+(exec|push|open|show|update|outdated|gem))/, /\bgem\s+install\b/, # Go /\bgo\s+mod\s+download\b/, /\bgo\s+get\b/, /\bgo\s+install\b/, # Rust /\bcargo\s+(build|fetch)\b/, # Java / Kotlin /\bmvn\s+(install|package)\b/, /\bgradle\s+build\b/, /\.\/gradlew\s+build\b/, # .NET /\bdotnet\s+restore\b/, /\bnuget\s+restore\b/, # PHP /\bcomposer\s+(install|update)\b/, # Elixir /\bmix\s+deps\.get\b/, # Swift /\bswift\s+package\s+resolve\b/, )
- PUBLISH_PATTERNS =
Regexp.union( # JavaScript / TypeScript /\bnpm\s+publish\b/, /\bpnpm\s+publish\b/, /\bnpx\s+pkg-pr-new\b/, /\byarn\s+publish\b/, # Python /\btwine\s+upload\b/, /\bpoetry\s+publish\b/, /\bflit\s+publish\b/, /\buv\s+publish\b/, # Ruby /\bgem\s+push\b/, /\brake\s+release\b/, # Rust /\bcargo\s+publish\b/, # Java / Kotlin /\bmvn\s+deploy\b/, /\bgradle\s+publish\b/, /\.\/gradlew\s+publish\b/, # .NET /\bdotnet\s+nuget\s+push\b/, /\bnuget\s+push\b/, # Docker /\bdocker\s+push\b/, /\bdocker\s+buildx\s+build\b.*--push/, # Homebrew /\bbrew\s+tap\b/, /\bbrew\s+bump-formula-pr\b/, )
- PUBLISH_SECRETS =
Regexp.union( # JavaScript /\bNPM_TOKEN\b/, /\bNODE_AUTH_TOKEN\b/, /\bNPM_AUTH_TOKEN\b/, # Python /\bPYPI_TOKEN\b/, /\bPYPI_API_TOKEN\b/, /\bTWINE_PASSWORD\b/, /\bPOETRY_PYPI_TOKEN_PYPI\b/, # Ruby /\bGEM_HOST_API_KEY\b/, /\bRUBYGEMS_API_KEY\b/, /\bRUBYGEMS_AUTH_TOKEN\b/, # Rust /\bCARGO_REGISTRY_TOKEN\b/, /\bCRATES_IO_TOKEN\b/, # Java / Gradle /\bMAVEN_PASSWORD\b/, /\bMAVEN_GPG_PASSPHRASE\b/, /\bGRADLE_PUBLISH_KEY\b/, /\bOSSRH_PASSWORD\b/, /\bSONATYPE_PASSWORD\b/, # .NET /\bNUGET_API_KEY\b/, /\bNUGET_AUTH_TOKEN\b/, # Docker /\bDOCKER_PASSWORD\b/, /\bDOCKER_TOKEN\b/, /\bDOCKERHUB_TOKEN\b/, # General /\bREGISTRY_TOKEN\b/, /\bPUBLISH_TOKEN\b/, )
Instance Method Summary collapse
Instance Method Details
#check(workflow) ⇒ Object
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 |
# File 'lib/rules/build_publish_same_job.rb', line 111 def check(workflow) findings = [] workflow.jobs.each do |job_id, job| steps = workflow.steps(job) has_install = steps.any? { |s| s["run"]&.match?(INSTALL_PATTERNS) } has_publish = steps.any? { |s| s["run"]&.match?(PUBLISH_PATTERNS) } next unless has_install && has_publish job_env = job["env"]&.to_s || "" step_envs = steps.map { |s| (s["env"] || {}).to_s }.join(" ") all_env = job_env + step_envs if all_env.match?(PUBLISH_SECRETS) || all_env.match?(/secrets\./) line = workflow.line_of(/#{job_id}:/) findings << finding(workflow, line: line || 0, code: "job: #{job_id}", message: "Build and publish in same job — a compromised dependency could exfiltrate publish credentials", fix: "Split into separate build (read-only) and publish (with secrets) jobs connected via artifacts" ) end end findings end |
#description ⇒ Object
4 |
# File 'lib/rules/build_publish_same_job.rb', line 4 def description = "Build and publish in same job with publish secrets available during build" |
#name ⇒ Object
3 |
# File 'lib/rules/build_publish_same_job.rb', line 3 def name = "build-publish-same-job" |
#severity ⇒ Object
5 |
# File 'lib/rules/build_publish_same_job.rb', line 5 def severity = :high |