zizmor 1.2.1__tar.gz → 1.2.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of zizmor might be problematic. Click here for more details.

Files changed (196) hide show
  1. {zizmor-1.2.1 → zizmor-1.2.2}/.github/workflows/zizmor.yml +2 -0
  2. {zizmor-1.2.1 → zizmor-1.2.2}/Cargo.lock +3 -3
  3. {zizmor-1.2.1 → zizmor-1.2.2}/Cargo.toml +2 -2
  4. {zizmor-1.2.1 → zizmor-1.2.2}/PKG-INFO +1 -1
  5. {zizmor-1.2.1 → zizmor-1.2.2}/docs/release-notes.md +11 -0
  6. {zizmor-1.2.1 → zizmor-1.2.2}/docs/usage.md +1 -1
  7. {zizmor-1.2.1 → zizmor-1.2.2}/src/audit/excessive_permissions.rs +39 -22
  8. {zizmor-1.2.1 → zizmor-1.2.2}/src/github_api.rs +11 -1
  9. {zizmor-1.2.1 → zizmor-1.2.2}/src/main.rs +11 -2
  10. {zizmor-1.2.1 → zizmor-1.2.2}/src/models.rs +20 -2
  11. {zizmor-1.2.1 → zizmor-1.2.2}/src/registry.rs +1 -1
  12. {zizmor-1.2.1 → zizmor-1.2.2}/tests/snapshot.rs +19 -0
  13. zizmor-1.2.2/tests/snapshots/snapshot__excessive_permissions-10.snap +21 -0
  14. zizmor-1.2.2/tests/snapshots/snapshot__excessive_permissions-11.snap +19 -0
  15. zizmor-1.2.2/tests/snapshots/snapshot__excessive_permissions-12.snap +47 -0
  16. zizmor-1.2.2/tests/test-data/excessive-permissions/issue-472-repro.yml +23 -0
  17. zizmor-1.2.2/tests/test-data/excessive-permissions/reusable-workflow-call.yml +9 -0
  18. zizmor-1.2.2/tests/test-data/excessive-permissions/reusable-workflow-other-triggers.yml +21 -0
  19. {zizmor-1.2.1 → zizmor-1.2.2}/.github/ISSUE_TEMPLATE/bug-report.yml +0 -0
  20. {zizmor-1.2.1 → zizmor-1.2.2}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  21. {zizmor-1.2.1 → zizmor-1.2.2}/.github/ISSUE_TEMPLATE/feature-request.yml +0 -0
  22. {zizmor-1.2.1 → zizmor-1.2.2}/.github/dependabot.yml +0 -0
  23. {zizmor-1.2.1 → zizmor-1.2.2}/.github/workflows/ci.yml +0 -0
  24. {zizmor-1.2.1 → zizmor-1.2.2}/.github/workflows/pypi.yml +0 -0
  25. {zizmor-1.2.1 → zizmor-1.2.2}/.github/workflows/release.yml +0 -0
  26. {zizmor-1.2.1 → zizmor-1.2.2}/.github/workflows/site.yml +0 -0
  27. {zizmor-1.2.1 → zizmor-1.2.2}/.gitignore +0 -0
  28. {zizmor-1.2.1 → zizmor-1.2.2}/CONTRIBUTING.md +0 -0
  29. {zizmor-1.2.1 → zizmor-1.2.2}/LICENSE +0 -0
  30. {zizmor-1.2.1 → zizmor-1.2.2}/Makefile +0 -0
  31. {zizmor-1.2.1 → zizmor-1.2.2}/README.md +0 -0
  32. {zizmor-1.2.1 → zizmor-1.2.2}/docs/assets/favicon48x48.png +0 -0
  33. {zizmor-1.2.1 → zizmor-1.2.2}/docs/assets/rainbow.svg +0 -0
  34. {zizmor-1.2.1 → zizmor-1.2.2}/docs/assets/zizmor-demo.gif +0 -0
  35. {zizmor-1.2.1 → zizmor-1.2.2}/docs/audits.md +0 -0
  36. {zizmor-1.2.1 → zizmor-1.2.2}/docs/configuration.md +0 -0
  37. {zizmor-1.2.1 → zizmor-1.2.2}/docs/development.md +0 -0
  38. {zizmor-1.2.1 → zizmor-1.2.2}/docs/index.md +0 -0
  39. {zizmor-1.2.1 → zizmor-1.2.2}/docs/installation.md +0 -0
  40. {zizmor-1.2.1 → zizmor-1.2.2}/docs/magiclink.css +0 -0
  41. {zizmor-1.2.1 → zizmor-1.2.2}/docs/quickstart.md +0 -0
  42. {zizmor-1.2.1 → zizmor-1.2.2}/docs/snippets/help.txt +0 -0
  43. {zizmor-1.2.1 → zizmor-1.2.2}/docs/snippets/render-sponsors.py +0 -0
  44. {zizmor-1.2.1 → zizmor-1.2.2}/docs/snippets/render-trophies.py +0 -0
  45. {zizmor-1.2.1 → zizmor-1.2.2}/docs/snippets/sponsors.html +0 -0
  46. {zizmor-1.2.1 → zizmor-1.2.2}/docs/snippets/sponsors.json +0 -0
  47. {zizmor-1.2.1 → zizmor-1.2.2}/docs/snippets/trophies.md +0 -0
  48. {zizmor-1.2.1 → zizmor-1.2.2}/docs/snippets/trophies.txt +0 -0
  49. {zizmor-1.2.1 → zizmor-1.2.2}/docs/trophy-case.md +0 -0
  50. {zizmor-1.2.1 → zizmor-1.2.2}/mkdocs.yml +0 -0
  51. {zizmor-1.2.1 → zizmor-1.2.2}/pyproject.toml +0 -0
  52. {zizmor-1.2.1 → zizmor-1.2.2}/src/audit/artipacked.rs +0 -0
  53. {zizmor-1.2.1 → zizmor-1.2.2}/src/audit/bot_conditions.rs +0 -0
  54. {zizmor-1.2.1 → zizmor-1.2.2}/src/audit/cache_poisoning.rs +0 -0
  55. {zizmor-1.2.1 → zizmor-1.2.2}/src/audit/dangerous_triggers.rs +0 -0
  56. {zizmor-1.2.1 → zizmor-1.2.2}/src/audit/github_env.rs +0 -0
  57. {zizmor-1.2.1 → zizmor-1.2.2}/src/audit/hardcoded_container_credentials.rs +0 -0
  58. {zizmor-1.2.1 → zizmor-1.2.2}/src/audit/impostor_commit.rs +0 -0
  59. {zizmor-1.2.1 → zizmor-1.2.2}/src/audit/insecure_commands.rs +0 -0
  60. {zizmor-1.2.1 → zizmor-1.2.2}/src/audit/known_vulnerable_actions.rs +0 -0
  61. {zizmor-1.2.1 → zizmor-1.2.2}/src/audit/mod.rs +0 -0
  62. {zizmor-1.2.1 → zizmor-1.2.2}/src/audit/ref_confusion.rs +0 -0
  63. {zizmor-1.2.1 → zizmor-1.2.2}/src/audit/secrets_inherit.rs +0 -0
  64. {zizmor-1.2.1 → zizmor-1.2.2}/src/audit/self_hosted_runner.rs +0 -0
  65. {zizmor-1.2.1 → zizmor-1.2.2}/src/audit/template_injection.rs +0 -0
  66. {zizmor-1.2.1 → zizmor-1.2.2}/src/audit/unpinned_uses.rs +0 -0
  67. {zizmor-1.2.1 → zizmor-1.2.2}/src/audit/use_trusted_publishing.rs +0 -0
  68. {zizmor-1.2.1 → zizmor-1.2.2}/src/config.rs +0 -0
  69. {zizmor-1.2.1 → zizmor-1.2.2}/src/expr/expr.pest +0 -0
  70. {zizmor-1.2.1 → zizmor-1.2.2}/src/expr/mod.rs +0 -0
  71. {zizmor-1.2.1 → zizmor-1.2.2}/src/finding/locate.rs +0 -0
  72. {zizmor-1.2.1 → zizmor-1.2.2}/src/finding/mod.rs +0 -0
  73. {zizmor-1.2.1 → zizmor-1.2.2}/src/models/coordinate.rs +0 -0
  74. {zizmor-1.2.1 → zizmor-1.2.2}/src/models/uses.rs +0 -0
  75. {zizmor-1.2.1 → zizmor-1.2.2}/src/render.rs +0 -0
  76. {zizmor-1.2.1 → zizmor-1.2.2}/src/sarif.rs +0 -0
  77. {zizmor-1.2.1 → zizmor-1.2.2}/src/state.rs +0 -0
  78. {zizmor-1.2.1 → zizmor-1.2.2}/src/utils.rs +0 -0
  79. {zizmor-1.2.1 → zizmor-1.2.2}/tests/acceptance.rs +0 -0
  80. {zizmor-1.2.1 → zizmor-1.2.2}/tests/common.rs +0 -0
  81. {zizmor-1.2.1 → zizmor-1.2.2}/tests/snapshots/snapshot__artipacked-2.snap +0 -0
  82. {zizmor-1.2.1 → zizmor-1.2.2}/tests/snapshots/snapshot__artipacked-3.snap +0 -0
  83. {zizmor-1.2.1 → zizmor-1.2.2}/tests/snapshots/snapshot__artipacked-4.snap +0 -0
  84. {zizmor-1.2.1 → zizmor-1.2.2}/tests/snapshots/snapshot__artipacked.snap +0 -0
  85. {zizmor-1.2.1 → zizmor-1.2.2}/tests/snapshots/snapshot__bot_conditions.snap +0 -0
  86. {zizmor-1.2.1 → zizmor-1.2.2}/tests/snapshots/snapshot__cache_poisoning-10.snap +0 -0
  87. {zizmor-1.2.1 → zizmor-1.2.2}/tests/snapshots/snapshot__cache_poisoning-11.snap +0 -0
  88. {zizmor-1.2.1 → zizmor-1.2.2}/tests/snapshots/snapshot__cache_poisoning-12.snap +0 -0
  89. {zizmor-1.2.1 → zizmor-1.2.2}/tests/snapshots/snapshot__cache_poisoning-13.snap +0 -0
  90. {zizmor-1.2.1 → zizmor-1.2.2}/tests/snapshots/snapshot__cache_poisoning-14.snap +0 -0
  91. {zizmor-1.2.1 → zizmor-1.2.2}/tests/snapshots/snapshot__cache_poisoning-2.snap +0 -0
  92. {zizmor-1.2.1 → zizmor-1.2.2}/tests/snapshots/snapshot__cache_poisoning-3.snap +0 -0
  93. {zizmor-1.2.1 → zizmor-1.2.2}/tests/snapshots/snapshot__cache_poisoning-4.snap +0 -0
  94. {zizmor-1.2.1 → zizmor-1.2.2}/tests/snapshots/snapshot__cache_poisoning-5.snap +0 -0
  95. {zizmor-1.2.1 → zizmor-1.2.2}/tests/snapshots/snapshot__cache_poisoning-6.snap +0 -0
  96. {zizmor-1.2.1 → zizmor-1.2.2}/tests/snapshots/snapshot__cache_poisoning-7.snap +0 -0
  97. {zizmor-1.2.1 → zizmor-1.2.2}/tests/snapshots/snapshot__cache_poisoning-8.snap +0 -0
  98. {zizmor-1.2.1 → zizmor-1.2.2}/tests/snapshots/snapshot__cache_poisoning-9.snap +0 -0
  99. {zizmor-1.2.1 → zizmor-1.2.2}/tests/snapshots/snapshot__cache_poisoning.snap +0 -0
  100. {zizmor-1.2.1 → zizmor-1.2.2}/tests/snapshots/snapshot__cant_retrieve.snap +0 -0
  101. {zizmor-1.2.1 → zizmor-1.2.2}/tests/snapshots/snapshot__conflicting_online_options-2.snap +0 -0
  102. {zizmor-1.2.1 → zizmor-1.2.2}/tests/snapshots/snapshot__conflicting_online_options-3.snap +0 -0
  103. {zizmor-1.2.1 → zizmor-1.2.2}/tests/snapshots/snapshot__conflicting_online_options.snap +0 -0
  104. {zizmor-1.2.1 → zizmor-1.2.2}/tests/snapshots/snapshot__excessive_permissions-2.snap +0 -0
  105. {zizmor-1.2.1 → zizmor-1.2.2}/tests/snapshots/snapshot__excessive_permissions-3.snap +0 -0
  106. {zizmor-1.2.1 → zizmor-1.2.2}/tests/snapshots/snapshot__excessive_permissions-4.snap +0 -0
  107. {zizmor-1.2.1 → zizmor-1.2.2}/tests/snapshots/snapshot__excessive_permissions-5.snap +0 -0
  108. {zizmor-1.2.1 → zizmor-1.2.2}/tests/snapshots/snapshot__excessive_permissions-6.snap +0 -0
  109. {zizmor-1.2.1 → zizmor-1.2.2}/tests/snapshots/snapshot__excessive_permissions-7.snap +0 -0
  110. {zizmor-1.2.1 → zizmor-1.2.2}/tests/snapshots/snapshot__excessive_permissions-8.snap +0 -0
  111. {zizmor-1.2.1 → zizmor-1.2.2}/tests/snapshots/snapshot__excessive_permissions-9.snap +0 -0
  112. {zizmor-1.2.1 → zizmor-1.2.2}/tests/snapshots/snapshot__excessive_permissions.snap +0 -0
  113. {zizmor-1.2.1 → zizmor-1.2.2}/tests/snapshots/snapshot__github_env-2.snap +0 -0
  114. {zizmor-1.2.1 → zizmor-1.2.2}/tests/snapshots/snapshot__github_env-3.snap +0 -0
  115. {zizmor-1.2.1 → zizmor-1.2.2}/tests/snapshots/snapshot__github_env.snap +0 -0
  116. {zizmor-1.2.1 → zizmor-1.2.2}/tests/snapshots/snapshot__insecure_commands-2.snap +0 -0
  117. {zizmor-1.2.1 → zizmor-1.2.2}/tests/snapshots/snapshot__insecure_commands-3.snap +0 -0
  118. {zizmor-1.2.1 → zizmor-1.2.2}/tests/snapshots/snapshot__insecure_commands.snap +0 -0
  119. {zizmor-1.2.1 → zizmor-1.2.2}/tests/snapshots/snapshot__secrets_inherit.snap +0 -0
  120. {zizmor-1.2.1 → zizmor-1.2.2}/tests/snapshots/snapshot__self_hosted-2.snap +0 -0
  121. {zizmor-1.2.1 → zizmor-1.2.2}/tests/snapshots/snapshot__self_hosted-3.snap +0 -0
  122. {zizmor-1.2.1 → zizmor-1.2.2}/tests/snapshots/snapshot__self_hosted-4.snap +0 -0
  123. {zizmor-1.2.1 → zizmor-1.2.2}/tests/snapshots/snapshot__self_hosted-5.snap +0 -0
  124. {zizmor-1.2.1 → zizmor-1.2.2}/tests/snapshots/snapshot__self_hosted-6.snap +0 -0
  125. {zizmor-1.2.1 → zizmor-1.2.2}/tests/snapshots/snapshot__self_hosted-7.snap +0 -0
  126. {zizmor-1.2.1 → zizmor-1.2.2}/tests/snapshots/snapshot__self_hosted-8.snap +0 -0
  127. {zizmor-1.2.1 → zizmor-1.2.2}/tests/snapshots/snapshot__self_hosted.snap +0 -0
  128. {zizmor-1.2.1 → zizmor-1.2.2}/tests/snapshots/snapshot__template_injection-2.snap +0 -0
  129. {zizmor-1.2.1 → zizmor-1.2.2}/tests/snapshots/snapshot__template_injection-3.snap +0 -0
  130. {zizmor-1.2.1 → zizmor-1.2.2}/tests/snapshots/snapshot__template_injection-4.snap +0 -0
  131. {zizmor-1.2.1 → zizmor-1.2.2}/tests/snapshots/snapshot__template_injection-5.snap +0 -0
  132. {zizmor-1.2.1 → zizmor-1.2.2}/tests/snapshots/snapshot__template_injection-6.snap +0 -0
  133. {zizmor-1.2.1 → zizmor-1.2.2}/tests/snapshots/snapshot__template_injection-7.snap +0 -0
  134. {zizmor-1.2.1 → zizmor-1.2.2}/tests/snapshots/snapshot__template_injection-8.snap +0 -0
  135. {zizmor-1.2.1 → zizmor-1.2.2}/tests/snapshots/snapshot__template_injection.snap +0 -0
  136. {zizmor-1.2.1 → zizmor-1.2.2}/tests/snapshots/snapshot__unpinned_uses-2.snap +0 -0
  137. {zizmor-1.2.1 → zizmor-1.2.2}/tests/snapshots/snapshot__unpinned_uses-3.snap +0 -0
  138. {zizmor-1.2.1 → zizmor-1.2.2}/tests/snapshots/snapshot__unpinned_uses-4.snap +0 -0
  139. {zizmor-1.2.1 → zizmor-1.2.2}/tests/snapshots/snapshot__unpinned_uses.snap +0 -0
  140. {zizmor-1.2.1 → zizmor-1.2.2}/tests/test-data/artipacked/issue-447-repro.yml +0 -0
  141. {zizmor-1.2.1 → zizmor-1.2.2}/tests/test-data/artipacked.yml +0 -0
  142. {zizmor-1.2.1 → zizmor-1.2.2}/tests/test-data/bot-conditions.yml +0 -0
  143. {zizmor-1.2.1 → zizmor-1.2.2}/tests/test-data/cache-poisoning/caching-disabled-by-default.yml +0 -0
  144. {zizmor-1.2.1 → zizmor-1.2.2}/tests/test-data/cache-poisoning/caching-enabled-by-default.yml +0 -0
  145. {zizmor-1.2.1 → zizmor-1.2.2}/tests/test-data/cache-poisoning/caching-not-configurable.yml +0 -0
  146. {zizmor-1.2.1 → zizmor-1.2.2}/tests/test-data/cache-poisoning/caching-opt-in-boolean-toggle.yml +0 -0
  147. {zizmor-1.2.1 → zizmor-1.2.2}/tests/test-data/cache-poisoning/caching-opt-in-boolish-toggle.yml +0 -0
  148. {zizmor-1.2.1 → zizmor-1.2.2}/tests/test-data/cache-poisoning/caching-opt-in-expression.yml +0 -0
  149. {zizmor-1.2.1 → zizmor-1.2.2}/tests/test-data/cache-poisoning/caching-opt-in-multi-value-toggle.yml +0 -0
  150. {zizmor-1.2.1 → zizmor-1.2.2}/tests/test-data/cache-poisoning/caching-opt-out.yml +0 -0
  151. {zizmor-1.2.1 → zizmor-1.2.2}/tests/test-data/cache-poisoning/issue-343-repro.yml +0 -0
  152. {zizmor-1.2.1 → zizmor-1.2.2}/tests/test-data/cache-poisoning/issue-378-repro.yml +0 -0
  153. {zizmor-1.2.1 → zizmor-1.2.2}/tests/test-data/cache-poisoning/no-cache-aware-steps.yml +0 -0
  154. {zizmor-1.2.1 → zizmor-1.2.2}/tests/test-data/cache-poisoning/publisher-step.yml +0 -0
  155. {zizmor-1.2.1 → zizmor-1.2.2}/tests/test-data/cache-poisoning/workflow-release-branch-trigger.yml +0 -0
  156. {zizmor-1.2.1 → zizmor-1.2.2}/tests/test-data/cache-poisoning/workflow-tag-trigger.yml +0 -0
  157. {zizmor-1.2.1 → zizmor-1.2.2}/tests/test-data/cache-poisoning.yml +0 -0
  158. {zizmor-1.2.1 → zizmor-1.2.2}/tests/test-data/excessive-permissions/issue-336-repro.yml +0 -0
  159. {zizmor-1.2.1 → zizmor-1.2.2}/tests/test-data/excessive-permissions/jobs-broaden-permissions.yml +0 -0
  160. {zizmor-1.2.1 → zizmor-1.2.2}/tests/test-data/excessive-permissions/workflow-default-perms-all-jobs-explicit.yml +0 -0
  161. {zizmor-1.2.1 → zizmor-1.2.2}/tests/test-data/excessive-permissions/workflow-default-perms.yml +0 -0
  162. {zizmor-1.2.1 → zizmor-1.2.2}/tests/test-data/excessive-permissions/workflow-empty-perms.yml +0 -0
  163. {zizmor-1.2.1 → zizmor-1.2.2}/tests/test-data/excessive-permissions/workflow-read-all.yml +0 -0
  164. {zizmor-1.2.1 → zizmor-1.2.2}/tests/test-data/excessive-permissions/workflow-write-all.yml +0 -0
  165. {zizmor-1.2.1 → zizmor-1.2.2}/tests/test-data/excessive-permissions/workflow-write-explicit.yml +0 -0
  166. {zizmor-1.2.1 → zizmor-1.2.2}/tests/test-data/excessive-permissions.yml +0 -0
  167. {zizmor-1.2.1 → zizmor-1.2.2}/tests/test-data/github-env/action.yml +0 -0
  168. {zizmor-1.2.1 → zizmor-1.2.2}/tests/test-data/github-env/github-path.yml +0 -0
  169. {zizmor-1.2.1 → zizmor-1.2.2}/tests/test-data/github-env/issue-397-repro.yml +0 -0
  170. {zizmor-1.2.1 → zizmor-1.2.2}/tests/test-data/github_env.yml +0 -0
  171. {zizmor-1.2.1 → zizmor-1.2.2}/tests/test-data/hardcoded-credentials.yml +0 -0
  172. {zizmor-1.2.1 → zizmor-1.2.2}/tests/test-data/inlined-ignores.yml +0 -0
  173. {zizmor-1.2.1 → zizmor-1.2.2}/tests/test-data/insecure-commands/action.yml +0 -0
  174. {zizmor-1.2.1 → zizmor-1.2.2}/tests/test-data/insecure-commands.yml +0 -0
  175. {zizmor-1.2.1 → zizmor-1.2.2}/tests/test-data/secrets-inherit.yml +0 -0
  176. {zizmor-1.2.1 → zizmor-1.2.2}/tests/test-data/self-hosted/issue-283-repro.yml +0 -0
  177. {zizmor-1.2.1 → zizmor-1.2.2}/tests/test-data/self-hosted/self-hosted-matrix-dimension.yml +0 -0
  178. {zizmor-1.2.1 → zizmor-1.2.2}/tests/test-data/self-hosted/self-hosted-matrix-exclusion.yml +0 -0
  179. {zizmor-1.2.1 → zizmor-1.2.2}/tests/test-data/self-hosted/self-hosted-matrix-inclusion.yml +0 -0
  180. {zizmor-1.2.1 → zizmor-1.2.2}/tests/test-data/self-hosted/self-hosted-runner-group.yml +0 -0
  181. {zizmor-1.2.1 → zizmor-1.2.2}/tests/test-data/self-hosted/self-hosted-runner-label.yml +0 -0
  182. {zizmor-1.2.1 → zizmor-1.2.2}/tests/test-data/self-hosted.yml +0 -0
  183. {zizmor-1.2.1 → zizmor-1.2.2}/tests/test-data/template-injection/issue-22-repro.yml +0 -0
  184. {zizmor-1.2.1 → zizmor-1.2.2}/tests/test-data/template-injection/issue-339-repro.yml +0 -0
  185. {zizmor-1.2.1 → zizmor-1.2.2}/tests/test-data/template-injection/issue-418-repro.yml +0 -0
  186. {zizmor-1.2.1 → zizmor-1.2.2}/tests/test-data/template-injection/pr-317-repro.yml +0 -0
  187. {zizmor-1.2.1 → zizmor-1.2.2}/tests/test-data/template-injection/pr-425-backstop/action.yml +0 -0
  188. {zizmor-1.2.1 → zizmor-1.2.2}/tests/test-data/template-injection/static-env.yml +0 -0
  189. {zizmor-1.2.1 → zizmor-1.2.2}/tests/test-data/template-injection/template-injection-dynamic-matrix.yml +0 -0
  190. {zizmor-1.2.1 → zizmor-1.2.2}/tests/test-data/template-injection/template-injection-static-matrix.yml +0 -0
  191. {zizmor-1.2.1 → zizmor-1.2.2}/tests/test-data/template-injection.yml +0 -0
  192. {zizmor-1.2.1 → zizmor-1.2.2}/tests/test-data/unpinned-uses/action.yml +0 -0
  193. {zizmor-1.2.1 → zizmor-1.2.2}/tests/test-data/unpinned-uses/issue-433-repro.yml +0 -0
  194. {zizmor-1.2.1 → zizmor-1.2.2}/tests/test-data/unpinned-uses.yml +0 -0
  195. {zizmor-1.2.1 → zizmor-1.2.2}/tests/test-data/use-trusted-publishing.yml +0 -0
  196. {zizmor-1.2.1 → zizmor-1.2.2}/uv.lock +0 -0
@@ -6,6 +6,8 @@ on:
6
6
  pull_request:
7
7
  branches: ["*"]
8
8
 
9
+ permissions: {}
10
+
9
11
  jobs:
10
12
  zizmor:
11
13
  name: zizmor latest via Cargo
@@ -616,9 +616,9 @@ checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
616
616
 
617
617
  [[package]]
618
618
  name = "github-actions-models"
619
- version = "0.21.0"
619
+ version = "0.22.0"
620
620
  source = "registry+https://github.com/rust-lang/crates.io-index"
621
- checksum = "768ea1269c648e6eb2e2fc9143e609609a1587150f0ad3342305ae2ae2d217ca"
621
+ checksum = "ea4c30fa8bf11e002d3ca72233e7a7bac33ffce4dc50877d63a8f5a161e0cd84"
622
622
  dependencies = [
623
623
  "indexmap",
624
624
  "serde",
@@ -3108,7 +3108,7 @@ dependencies = [
3108
3108
 
3109
3109
  [[package]]
3110
3110
  name = "zizmor"
3111
- version = "1.2.1"
3111
+ version = "1.2.2"
3112
3112
  dependencies = [
3113
3113
  "annotate-snippets",
3114
3114
  "anstream",
@@ -1,7 +1,7 @@
1
1
  [package]
2
2
  name = "zizmor"
3
3
  description = "Static analysis for GitHub Actions"
4
- version = "1.2.1"
4
+ version = "1.2.2"
5
5
  edition = "2021"
6
6
  repository = "https://github.com/woodruffw/zizmor"
7
7
  homepage = "https://github.com/woodruffw/zizmor"
@@ -23,7 +23,7 @@ clap-verbosity-flag = { version = "3.0.2", features = [
23
23
  ], default-features = false }
24
24
  etcetera = "0.8.0"
25
25
  flate2 = "1.0.35"
26
- github-actions-models = "0.21.0"
26
+ github-actions-models = "0.22.0"
27
27
  http-cache-reqwest = "0.15.0"
28
28
  human-panic = "2.0.1"
29
29
  indexmap = "2.7.0"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: zizmor
3
- Version: 1.2.1
3
+ Version: 1.2.2
4
4
  License-File: LICENSE
5
5
  Summary: Static analysis for GitHub Actions
6
6
  Keywords: cli,github-actions,static-analysis,security
@@ -11,6 +11,17 @@ of `zizmor`.
11
11
 
12
12
  Nothing to see here (yet!)
13
13
 
14
+ ## v1.2.2
15
+
16
+ ### Bug Fixes 🐛
17
+
18
+ * The [excessive-permissions] audit is now more precise about both
19
+ reusable workflows and reusable workflow calls (#473)
20
+
21
+ ### Improvements 🌱
22
+
23
+ * Fetch failures when running `zizmor org/repo` are now more informative (#475)
24
+
14
25
  ## v1.2.1
15
26
 
16
27
  This is a small corrective release for some SARIF behavior that
@@ -457,7 +457,7 @@ To do so, add the following to your `.pre-commit-config.yaml` `repos` section:
457
457
 
458
458
  ```yaml
459
459
  - repo: https://github.com/woodruffw/zizmor-pre-commit
460
- rev: v1.2.1 # (1)!
460
+ rev: v1.2.2 # (1)!
461
461
  hooks:
462
462
  - id: zizmor
463
463
  ```
@@ -57,12 +57,9 @@ impl Audit for ExcessivePermissions {
57
57
 
58
58
  let all_jobs_have_permissions = workflow
59
59
  .jobs()
60
- .filter_map(|job| {
61
- let Job::NormalJob(job) = job else {
62
- return None;
63
- };
64
-
65
- Some(&job.permissions)
60
+ .map(|job| match job {
61
+ Job::NormalJob(job) => &job.permissions,
62
+ Job::ReusableWorkflowCallJob(job) => &job.permissions,
66
63
  })
67
64
  .all(|perm| !matches!(perm, Permissions::Base(BasePermission::Default)));
68
65
 
@@ -71,17 +68,21 @@ impl Audit for ExcessivePermissions {
71
68
  Permissions::Base(BasePermission::Default)
72
69
  );
73
70
 
74
- // Top-level permissions are a minor issue if there's only one
75
- // job in the workflow, since they're equivalent to job-level
76
- // permissions in that case. Emit only pedantic findings in
77
- // that case.
78
- // Similarly, if all jobs in the workflow have their own explicit
79
- // permissions, then any permissions set at the top-level are moot.
80
- let persona = if workflow.jobs.len() == 1 || all_jobs_have_permissions {
81
- Persona::Pedantic
82
- } else {
83
- Persona::Regular
84
- };
71
+ let workflow_is_reusable_only =
72
+ workflow.has_workflow_call() && workflow.has_single_trigger();
73
+
74
+ // Top-level permissions are a pedantic finding under the following
75
+ // conditions:
76
+ //
77
+ // 1. The workflow has only one job.
78
+ // 2. All jobs in the workflow have their own explicit permissions.
79
+ // 3. The workflow is reusable and has only one trigger.
80
+ let workflow_finding_persona =
81
+ if workflow.jobs.len() == 1 || all_jobs_have_permissions || workflow_is_reusable_only {
82
+ Persona::Pedantic
83
+ } else {
84
+ Persona::Regular
85
+ };
85
86
 
86
87
  // Handle top-level permissions.
87
88
  let location = workflow.location().primary();
@@ -93,20 +94,35 @@ impl Audit for ExcessivePermissions {
93
94
  Self::finding()
94
95
  .severity(severity)
95
96
  .confidence(confidence)
96
- .persona(persona)
97
+ .persona(workflow_finding_persona)
97
98
  .add_location(perm_location)
98
99
  .build(workflow)?,
99
100
  );
100
101
  }
101
102
 
102
103
  for job in workflow.jobs() {
103
- let Job::NormalJob(job) = &job else {
104
- continue;
104
+ let (permissions, job_location, job_finding_persona) = match job {
105
+ Job::NormalJob(job) => {
106
+ // For normal jobs: if the workflow is reusable-only, we
107
+ // emit pedantic findings.
108
+ let persona = if workflow_is_reusable_only {
109
+ Persona::Pedantic
110
+ } else {
111
+ Persona::Regular
112
+ };
113
+
114
+ (&job.permissions, job.location(), persona)
115
+ }
116
+ Job::ReusableWorkflowCallJob(job) => {
117
+ // For reusable jobs: the caller is always responsible for
118
+ // permissions, so we emit regular findings even if
119
+ // the workflow is reusable-only.
120
+ (&job.permissions, job.location(), Persona::Regular)
121
+ }
105
122
  };
106
123
 
107
- let job_location = job.location();
108
124
  if let Some((severity, confidence, perm_location)) = self.check_job_permissions(
109
- &job.permissions,
125
+ permissions,
110
126
  explicit_parent_permissions,
111
127
  job_location.clone(),
112
128
  ) {
@@ -114,6 +130,7 @@ impl Audit for ExcessivePermissions {
114
130
  Self::finding()
115
131
  .severity(severity)
116
132
  .confidence(confidence)
133
+ .persona(job_finding_persona)
117
134
  .add_location(job_location)
118
135
  .add_location(perm_location.primary())
119
136
  .build(workflow)?,
@@ -12,6 +12,7 @@ use github_actions_models::common::RepositoryUses;
12
12
  use http_cache_reqwest::{
13
13
  CACacheManager, Cache, CacheMode, CacheOptions, HttpCache, HttpCacheOptions,
14
14
  };
15
+ use owo_colors::OwoColorize;
15
16
  use reqwest::{
16
17
  header::{HeaderMap, ACCEPT, AUTHORIZATION, USER_AGENT},
17
18
  StatusCode,
@@ -399,7 +400,16 @@ impl Client {
399
400
  // TODO: Could probably make this slightly faster by
400
401
  // streaming asynchronously into the decompression,
401
402
  // probably with the async-compression crate.
402
- let contents = self.http.get(url).send().await?.bytes().await?;
403
+ let resp = self.http.get(&url).send().await?;
404
+
405
+ if !resp.status().is_success() {
406
+ return Err(anyhow!(
407
+ "failed to fetch {url}: {status}",
408
+ status = resp.status().red()
409
+ ));
410
+ }
411
+
412
+ let contents = resp.bytes().await?;
403
413
  let tar = GzDecoder::new(contents.deref());
404
414
 
405
415
  let mut archive = Archive::new(tar);
@@ -258,7 +258,16 @@ fn collect_from_repo_slug(
258
258
  registry.register_input(workflow.into())?;
259
259
  }
260
260
  } else {
261
- let inputs = client.fetch_audit_inputs(&slug)?;
261
+ let inputs = client.fetch_audit_inputs(&slug).with_context(|| {
262
+ tip(
263
+ format!(
264
+ "couldn't collect inputs from https://github.com/{owner}/{repo}",
265
+ owner = slug.owner,
266
+ repo = slug.repo
267
+ ),
268
+ "confirm the repository exists and that you have access to it",
269
+ )
270
+ })?;
262
271
 
263
272
  tracing::info!(
264
273
  "collected {len} inputs from {owner}/{repo}",
@@ -267,7 +276,7 @@ fn collect_from_repo_slug(
267
276
  repo = slug.repo
268
277
  );
269
278
 
270
- for input in client.fetch_audit_inputs(&slug)? {
279
+ for input in inputs {
271
280
  registry.register_input(input)?;
272
281
  }
273
282
  }
@@ -135,7 +135,7 @@ impl Workflow {
135
135
  Jobs::new(self)
136
136
  }
137
137
 
138
- /// Whether this workflow's is triggered by pull_request_target.
138
+ /// Whether this workflow is triggered by pull_request_target.
139
139
  pub(crate) fn has_pull_request_target(&self) -> bool {
140
140
  match &self.on {
141
141
  Trigger::BareEvent(event) => *event == BareEvent::PullRequestTarget,
@@ -144,7 +144,7 @@ impl Workflow {
144
144
  }
145
145
  }
146
146
 
147
- /// Whether this workflow's is triggered by workflow_run.
147
+ /// Whether this workflow is triggered by workflow_run.
148
148
  pub(crate) fn has_workflow_run(&self) -> bool {
149
149
  match &self.on {
150
150
  Trigger::BareEvent(event) => *event == BareEvent::WorkflowRun,
@@ -152,6 +152,24 @@ impl Workflow {
152
152
  Trigger::Events(events) => !matches!(events.workflow_run, OptionalBody::Missing),
153
153
  }
154
154
  }
155
+
156
+ /// Whether this workflow is triggered by workflow_call.
157
+ pub(crate) fn has_workflow_call(&self) -> bool {
158
+ match &self.on {
159
+ Trigger::BareEvent(event) => *event == BareEvent::WorkflowCall,
160
+ Trigger::BareEvents(events) => events.contains(&BareEvent::WorkflowCall),
161
+ Trigger::Events(events) => !matches!(events.workflow_call, OptionalBody::Missing),
162
+ }
163
+ }
164
+
165
+ /// Whether this workflow is triggered by exactly one event.
166
+ pub(crate) fn has_single_trigger(&self) -> bool {
167
+ match &self.on {
168
+ Trigger::BareEvent(_) => true,
169
+ Trigger::BareEvents(events) => events.len() == 1,
170
+ Trigger::Events(events) => events.count() == 1,
171
+ }
172
+ }
155
173
  }
156
174
 
157
175
  /// Common behavior across both normal and reusable jobs.
@@ -99,7 +99,7 @@ impl InputKey {
99
99
  InputKey::Local(local) => local
100
100
  .prefix
101
101
  .as_ref()
102
- .and_then(|pfx| local.given_path.strip_prefix(dbg!(pfx)).ok())
102
+ .and_then(|pfx| local.given_path.strip_prefix(pfx).ok())
103
103
  .unwrap_or_else(|| &local.given_path)
104
104
  .as_str(),
105
105
  InputKey::Remote(remote) => remote.path.as_str(),
@@ -436,6 +436,25 @@ fn excessive_permissions() -> Result<()> {
436
436
  "excessive-permissions/workflow-default-perms-all-jobs-explicit.yml"
437
437
  ))
438
438
  .run()?);
439
+
440
+ insta::assert_snapshot!(zizmor()
441
+ .workflow(workflow_under_test(
442
+ "excessive-permissions/issue-472-repro.yml"
443
+ ))
444
+ .run()?);
445
+
446
+ insta::assert_snapshot!(zizmor()
447
+ .workflow(workflow_under_test(
448
+ "excessive-permissions/reusable-workflow-call.yml"
449
+ ))
450
+ .run()?);
451
+
452
+ insta::assert_snapshot!(zizmor()
453
+ .workflow(workflow_under_test(
454
+ "excessive-permissions/reusable-workflow-other-triggers.yml"
455
+ ))
456
+ .run()?);
457
+
439
458
  Ok(())
440
459
  }
441
460
 
@@ -0,0 +1,21 @@
1
+ ---
2
+ source: tests/snapshot.rs
3
+ expression: "zizmor().workflow(workflow_under_test(\"excessive-permissions/issue-472-repro.yml\")).run()?"
4
+ snapshot_kind: text
5
+ ---
6
+ warning[excessive-permissions]: overly broad permissions
7
+ --> @@INPUT@@:19:3
8
+ |
9
+ 19 | / job2:
10
+ 20 | | # normal permissions finding here, since callers are always
11
+ 21 | | # responsible for setting permissions, even if the workflow
12
+ 22 | | # is reusable-only
13
+ 23 | | uses: ./.github/workflows/fake.yml
14
+ | | -
15
+ | |_______________________________________|
16
+ | this job
17
+ | default permissions used due to no permissions: block
18
+ |
19
+ = note: audit confidence → Medium
20
+
21
+ 3 findings (2 suppressed): 0 unknown, 0 informational, 0 low, 1 medium, 0 high
@@ -0,0 +1,19 @@
1
+ ---
2
+ source: tests/snapshot.rs
3
+ expression: "zizmor().workflow(workflow_under_test(\"excessive-permissions/reusable-workflow-call.yml\")).run()?"
4
+ snapshot_kind: text
5
+ ---
6
+ warning[excessive-permissions]: overly broad permissions
7
+ --> @@INPUT@@:7:3
8
+ |
9
+ 7 | / job1:
10
+ 8 | | # finding: reusable jobs should always specify their permissions
11
+ 9 | | uses: ./.github/workflows/zizmor-child.yml
12
+ | | -
13
+ | |_______________________________________________|
14
+ | this job
15
+ | default permissions used due to no permissions: block
16
+ |
17
+ = note: audit confidence → Medium
18
+
19
+ 2 findings (1 suppressed): 0 unknown, 0 informational, 0 low, 1 medium, 0 high
@@ -0,0 +1,47 @@
1
+ ---
2
+ source: tests/snapshot.rs
3
+ expression: "zizmor().workflow(workflow_under_test(\"excessive-permissions/reusable-workflow-other-triggers.yml\")).run()?"
4
+ snapshot_kind: text
5
+ ---
6
+ warning[excessive-permissions]: overly broad permissions
7
+ --> @@INPUT@@:1:1
8
+ |
9
+ 1 | / name: reusable-workflow-other-triggers
10
+ 2 | |
11
+ ... |
12
+ 20 | | # responsible for setting permissions
13
+ 21 | | uses: ./.github/workflows/fake.yml
14
+ | |_______________________________________- default permissions used due to no permissions: block
15
+ |
16
+ = note: audit confidence → Medium
17
+
18
+ warning[excessive-permissions]: overly broad permissions
19
+ --> @@INPUT@@:11:3
20
+ |
21
+ 11 | / job1:
22
+ 12 | | # regular job-level finding, since we can be triggered by
23
+ ... |
24
+ 15 | | steps:
25
+ 16 | | - run: echo hello
26
+ | | -
27
+ | |_______________________|
28
+ | this job
29
+ | default permissions used due to no permissions: block
30
+ |
31
+ = note: audit confidence → Medium
32
+
33
+ warning[excessive-permissions]: overly broad permissions
34
+ --> @@INPUT@@:18:3
35
+ |
36
+ 18 | / job2:
37
+ 19 | | # normal permissions finding here, since callers are always
38
+ 20 | | # responsible for setting permissions
39
+ 21 | | uses: ./.github/workflows/fake.yml
40
+ | | -
41
+ | |_______________________________________|
42
+ | this job
43
+ | default permissions used due to no permissions: block
44
+ |
45
+ = note: audit confidence → Medium
46
+
47
+ 3 findings: 0 unknown, 0 informational, 0 low, 3 medium, 0 high
@@ -0,0 +1,23 @@
1
+ # repro case for https://github.com/woodruffw/zizmor/issues/472
2
+
3
+ name: issue-472-repro
4
+
5
+ on:
6
+ workflow_call:
7
+
8
+ # no non-pedantic top-level permissions finding, since
9
+ # the workflow is reusable-only
10
+
11
+ jobs:
12
+ job1:
13
+ # no non-pedantic job-level permissions finding, since
14
+ # the workflow is reusable-only
15
+ runs-on: ubuntu-24.04
16
+ steps:
17
+ - run: echo hello
18
+
19
+ job2:
20
+ # normal permissions finding here, since callers are always
21
+ # responsible for setting permissions, even if the workflow
22
+ # is reusable-only
23
+ uses: ./.github/workflows/fake.yml
@@ -0,0 +1,9 @@
1
+ name: reusable-workflow-call
2
+
3
+ on:
4
+ workflow_dispatch:
5
+
6
+ jobs:
7
+ job1:
8
+ # finding: reusable jobs should always specify their permissions
9
+ uses: ./.github/workflows/zizmor-child.yml
@@ -0,0 +1,21 @@
1
+ name: reusable-workflow-other-triggers
2
+
3
+ on:
4
+ workflow_call:
5
+ push:
6
+
7
+ # regular top-level finding, since we can be triggered by
8
+ # either a workflow call or a push
9
+
10
+ jobs:
11
+ job1:
12
+ # regular job-level finding, since we can be triggered by
13
+ # either a workflow call or a push
14
+ runs-on: ubuntu-24.04
15
+ steps:
16
+ - run: echo hello
17
+
18
+ job2:
19
+ # normal permissions finding here, since callers are always
20
+ # responsible for setting permissions
21
+ uses: ./.github/workflows/fake.yml
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes