zizmor 0.9.1__tar.gz → 0.9.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 (109) hide show
  1. {zizmor-0.9.1 → zizmor-0.9.2}/Cargo.lock +1 -1
  2. {zizmor-0.9.1 → zizmor-0.9.2}/Cargo.toml +1 -1
  3. {zizmor-0.9.1 → zizmor-0.9.2}/PKG-INFO +1 -1
  4. {zizmor-0.9.1 → zizmor-0.9.2}/docs/installation.md +20 -4
  5. {zizmor-0.9.1 → zizmor-0.9.2}/docs/snippets/trophies.md +60 -0
  6. {zizmor-0.9.1 → zizmor-0.9.2}/docs/snippets/trophies.txt +10 -0
  7. {zizmor-0.9.1 → zizmor-0.9.2}/mkdocs.yml +3 -1
  8. {zizmor-0.9.1 → zizmor-0.9.2}/src/audit/template_injection.rs +6 -2
  9. {zizmor-0.9.1 → zizmor-0.9.2}/src/audit/use_trusted_publishing.rs +28 -41
  10. {zizmor-0.9.1 → zizmor-0.9.2}/src/models.rs +52 -5
  11. {zizmor-0.9.1 → zizmor-0.9.2}/tests/snapshot.rs +7 -0
  12. zizmor-0.9.2/tests/snapshots/snapshot__template_injection-3.snap +6 -0
  13. zizmor-0.9.2/tests/test-data/template-injection/issue-22-repro.yml +64 -0
  14. {zizmor-0.9.1 → zizmor-0.9.2}/.github/FUNDING.yml +0 -0
  15. {zizmor-0.9.1 → zizmor-0.9.2}/.github/ISSUE_TEMPLATE/bug-report.yml +0 -0
  16. {zizmor-0.9.1 → zizmor-0.9.2}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  17. {zizmor-0.9.1 → zizmor-0.9.2}/.github/ISSUE_TEMPLATE/feature-request.yml +0 -0
  18. {zizmor-0.9.1 → zizmor-0.9.2}/.github/dependabot.yml +0 -0
  19. {zizmor-0.9.1 → zizmor-0.9.2}/.github/release.yml +0 -0
  20. {zizmor-0.9.1 → zizmor-0.9.2}/.github/workflows/ci.yml +0 -0
  21. {zizmor-0.9.1 → zizmor-0.9.2}/.github/workflows/pypi.yml +0 -0
  22. {zizmor-0.9.1 → zizmor-0.9.2}/.github/workflows/release.yml +0 -0
  23. {zizmor-0.9.1 → zizmor-0.9.2}/.github/workflows/site.yml +0 -0
  24. {zizmor-0.9.1 → zizmor-0.9.2}/.github/workflows/zizmor.yml +0 -0
  25. {zizmor-0.9.1 → zizmor-0.9.2}/.gitignore +0 -0
  26. {zizmor-0.9.1 → zizmor-0.9.2}/CONTRIBUTING.md +0 -0
  27. {zizmor-0.9.1 → zizmor-0.9.2}/LICENSE +0 -0
  28. {zizmor-0.9.1 → zizmor-0.9.2}/Makefile +0 -0
  29. {zizmor-0.9.1 → zizmor-0.9.2}/README.md +0 -0
  30. {zizmor-0.9.1 → zizmor-0.9.2}/docs/assets/favicon48x48.png +0 -0
  31. {zizmor-0.9.1 → zizmor-0.9.2}/docs/assets/rainbow.svg +0 -0
  32. {zizmor-0.9.1 → zizmor-0.9.2}/docs/assets/zizmor-demo.gif +0 -0
  33. {zizmor-0.9.1 → zizmor-0.9.2}/docs/audits.md +0 -0
  34. {zizmor-0.9.1 → zizmor-0.9.2}/docs/configuration.md +0 -0
  35. {zizmor-0.9.1 → zizmor-0.9.2}/docs/development.md +0 -0
  36. {zizmor-0.9.1 → zizmor-0.9.2}/docs/index.md +0 -0
  37. {zizmor-0.9.1 → zizmor-0.9.2}/docs/magiclink.css +0 -0
  38. {zizmor-0.9.1 → zizmor-0.9.2}/docs/quickstart.md +0 -0
  39. {zizmor-0.9.1 → zizmor-0.9.2}/docs/snippets/help.txt +0 -0
  40. {zizmor-0.9.1 → zizmor-0.9.2}/docs/snippets/render-trophies.py +0 -0
  41. {zizmor-0.9.1 → zizmor-0.9.2}/docs/trophy-case.md +0 -0
  42. {zizmor-0.9.1 → zizmor-0.9.2}/docs/usage.md +0 -0
  43. {zizmor-0.9.1 → zizmor-0.9.2}/pyproject.toml +0 -0
  44. {zizmor-0.9.1 → zizmor-0.9.2}/site-requirements.txt +0 -0
  45. {zizmor-0.9.1 → zizmor-0.9.2}/src/audit/artipacked.rs +0 -0
  46. {zizmor-0.9.1 → zizmor-0.9.2}/src/audit/dangerous_triggers.rs +0 -0
  47. {zizmor-0.9.1 → zizmor-0.9.2}/src/audit/excessive_permissions.rs +0 -0
  48. {zizmor-0.9.1 → zizmor-0.9.2}/src/audit/github_env.rs +0 -0
  49. {zizmor-0.9.1 → zizmor-0.9.2}/src/audit/hardcoded_container_credentials.rs +0 -0
  50. {zizmor-0.9.1 → zizmor-0.9.2}/src/audit/impostor_commit.rs +0 -0
  51. {zizmor-0.9.1 → zizmor-0.9.2}/src/audit/insecure_commands.rs +0 -0
  52. {zizmor-0.9.1 → zizmor-0.9.2}/src/audit/known_vulnerable_actions.rs +0 -0
  53. {zizmor-0.9.1 → zizmor-0.9.2}/src/audit/mod.rs +0 -0
  54. {zizmor-0.9.1 → zizmor-0.9.2}/src/audit/ref_confusion.rs +0 -0
  55. {zizmor-0.9.1 → zizmor-0.9.2}/src/audit/self_hosted_runner.rs +0 -0
  56. {zizmor-0.9.1 → zizmor-0.9.2}/src/audit/unpinned_uses.rs +0 -0
  57. {zizmor-0.9.1 → zizmor-0.9.2}/src/config.rs +0 -0
  58. {zizmor-0.9.1 → zizmor-0.9.2}/src/expr/expr.pest +0 -0
  59. {zizmor-0.9.1 → zizmor-0.9.2}/src/expr/mod.rs +0 -0
  60. {zizmor-0.9.1 → zizmor-0.9.2}/src/finding/locate.rs +0 -0
  61. {zizmor-0.9.1 → zizmor-0.9.2}/src/finding/mod.rs +0 -0
  62. {zizmor-0.9.1 → zizmor-0.9.2}/src/github_api.rs +0 -0
  63. {zizmor-0.9.1 → zizmor-0.9.2}/src/main.rs +0 -0
  64. {zizmor-0.9.1 → zizmor-0.9.2}/src/registry.rs +0 -0
  65. {zizmor-0.9.1 → zizmor-0.9.2}/src/render.rs +0 -0
  66. {zizmor-0.9.1 → zizmor-0.9.2}/src/sarif.rs +0 -0
  67. {zizmor-0.9.1 → zizmor-0.9.2}/src/state.rs +0 -0
  68. {zizmor-0.9.1 → zizmor-0.9.2}/src/utils.rs +0 -0
  69. {zizmor-0.9.1 → zizmor-0.9.2}/tests/acceptance.rs +0 -0
  70. {zizmor-0.9.1 → zizmor-0.9.2}/tests/common.rs +0 -0
  71. {zizmor-0.9.1 → zizmor-0.9.2}/tests/snapshots/snapshot__artipacked-2.snap +0 -0
  72. {zizmor-0.9.1 → zizmor-0.9.2}/tests/snapshots/snapshot__artipacked-3.snap +0 -0
  73. {zizmor-0.9.1 → zizmor-0.9.2}/tests/snapshots/snapshot__artipacked.snap +0 -0
  74. {zizmor-0.9.1 → zizmor-0.9.2}/tests/snapshots/snapshot__cant_retrieve.snap +0 -0
  75. {zizmor-0.9.1 → zizmor-0.9.2}/tests/snapshots/snapshot__conflicting_online_options-2.snap +0 -0
  76. {zizmor-0.9.1 → zizmor-0.9.2}/tests/snapshots/snapshot__conflicting_online_options-3.snap +0 -0
  77. {zizmor-0.9.1 → zizmor-0.9.2}/tests/snapshots/snapshot__conflicting_online_options.snap +0 -0
  78. {zizmor-0.9.1 → zizmor-0.9.2}/tests/snapshots/snapshot__insecure_commands-2.snap +0 -0
  79. {zizmor-0.9.1 → zizmor-0.9.2}/tests/snapshots/snapshot__insecure_commands.snap +0 -0
  80. {zizmor-0.9.1 → zizmor-0.9.2}/tests/snapshots/snapshot__self_hosted-2.snap +0 -0
  81. {zizmor-0.9.1 → zizmor-0.9.2}/tests/snapshots/snapshot__self_hosted-3.snap +0 -0
  82. {zizmor-0.9.1 → zizmor-0.9.2}/tests/snapshots/snapshot__self_hosted-4.snap +0 -0
  83. {zizmor-0.9.1 → zizmor-0.9.2}/tests/snapshots/snapshot__self_hosted-5.snap +0 -0
  84. {zizmor-0.9.1 → zizmor-0.9.2}/tests/snapshots/snapshot__self_hosted-6.snap +0 -0
  85. {zizmor-0.9.1 → zizmor-0.9.2}/tests/snapshots/snapshot__self_hosted-7.snap +0 -0
  86. {zizmor-0.9.1 → zizmor-0.9.2}/tests/snapshots/snapshot__self_hosted-8.snap +0 -0
  87. {zizmor-0.9.1 → zizmor-0.9.2}/tests/snapshots/snapshot__self_hosted.snap +0 -0
  88. {zizmor-0.9.1 → zizmor-0.9.2}/tests/snapshots/snapshot__template_injection-2.snap +0 -0
  89. {zizmor-0.9.1 → zizmor-0.9.2}/tests/snapshots/snapshot__template_injection.snap +0 -0
  90. {zizmor-0.9.1 → zizmor-0.9.2}/tests/snapshots/snapshot__unpinned_uses-2.snap +0 -0
  91. {zizmor-0.9.1 → zizmor-0.9.2}/tests/snapshots/snapshot__unpinned_uses.snap +0 -0
  92. {zizmor-0.9.1 → zizmor-0.9.2}/tests/test-data/artipacked.yml +0 -0
  93. {zizmor-0.9.1 → zizmor-0.9.2}/tests/test-data/excessive-permissions.yml +0 -0
  94. {zizmor-0.9.1 → zizmor-0.9.2}/tests/test-data/github_env.yml +0 -0
  95. {zizmor-0.9.1 → zizmor-0.9.2}/tests/test-data/hardcoded-credentials.yml +0 -0
  96. {zizmor-0.9.1 → zizmor-0.9.2}/tests/test-data/inlined-ignores.yml +0 -0
  97. {zizmor-0.9.1 → zizmor-0.9.2}/tests/test-data/insecure-commands.yml +0 -0
  98. {zizmor-0.9.1 → zizmor-0.9.2}/tests/test-data/self-hosted/issue-283-repro.yml +0 -0
  99. {zizmor-0.9.1 → zizmor-0.9.2}/tests/test-data/self-hosted/self-hosted-matrix-dimension.yml +0 -0
  100. {zizmor-0.9.1 → zizmor-0.9.2}/tests/test-data/self-hosted/self-hosted-matrix-exclusion.yml +0 -0
  101. {zizmor-0.9.1 → zizmor-0.9.2}/tests/test-data/self-hosted/self-hosted-matrix-inclusion.yml +0 -0
  102. {zizmor-0.9.1 → zizmor-0.9.2}/tests/test-data/self-hosted/self-hosted-runner-group.yml +0 -0
  103. {zizmor-0.9.1 → zizmor-0.9.2}/tests/test-data/self-hosted/self-hosted-runner-label.yml +0 -0
  104. {zizmor-0.9.1 → zizmor-0.9.2}/tests/test-data/self-hosted.yml +0 -0
  105. {zizmor-0.9.1 → zizmor-0.9.2}/tests/test-data/template-injection/template-injection-dynamic-matrix.yml +0 -0
  106. {zizmor-0.9.1 → zizmor-0.9.2}/tests/test-data/template-injection/template-injection-static-matrix.yml +0 -0
  107. {zizmor-0.9.1 → zizmor-0.9.2}/tests/test-data/template-injection.yml +0 -0
  108. {zizmor-0.9.1 → zizmor-0.9.2}/tests/test-data/unpinned-uses.yml +0 -0
  109. {zizmor-0.9.1 → zizmor-0.9.2}/tests/test-data/use-trusted-publishing.yml +0 -0
@@ -2594,7 +2594,7 @@ dependencies = [
2594
2594
 
2595
2595
  [[package]]
2596
2596
  name = "zizmor"
2597
- version = "0.9.1"
2597
+ version = "0.9.2"
2598
2598
  dependencies = [
2599
2599
  "annotate-snippets",
2600
2600
  "anstream",
@@ -1,7 +1,7 @@
1
1
  [package]
2
2
  name = "zizmor"
3
3
  description = "Static analysis for GitHub Actions"
4
- version = "0.9.1"
4
+ version = "0.9.2"
5
5
  edition = "2021"
6
6
  repository = "https://github.com/woodruffw/zizmor"
7
7
  homepage = "https://github.com/woodruffw/zizmor"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: zizmor
3
- Version: 0.9.1
3
+ Version: 0.9.2
4
4
  Summary: Static analysis for GitHub Actions
5
5
  Keywords: cli,github-actions,static-analysis,security
6
6
  Home-Page: https://github.com/woodruffw/zizmor
@@ -8,7 +8,7 @@ description: Installation instructions for zizmor.
8
8
 
9
9
  `zizmor` is available within several packaging ecosystems.
10
10
 
11
- === "crates.io"
11
+ === ":simple-rust: crates.io"
12
12
 
13
13
  You can install `zizmor` from <https://crates.io> with `cargo`:
14
14
 
@@ -16,7 +16,7 @@ description: Installation instructions for zizmor.
16
16
  cargo install zizmor
17
17
  ```
18
18
 
19
- === "Homebrew"
19
+ === ":simple-homebrew: Homebrew"
20
20
 
21
21
  `zizmor` is provided by [Homebrew](https://brew.sh/):
22
22
 
@@ -24,7 +24,7 @@ description: Installation instructions for zizmor.
24
24
  brew install zizmor
25
25
  ```
26
26
 
27
- === "PyPI"
27
+ === ":simple-pypi: PyPI"
28
28
 
29
29
  !!! tip
30
30
 
@@ -49,7 +49,23 @@ description: Installation instructions for zizmor.
49
49
  uvx zizmor --help
50
50
  ```
51
51
 
52
- === "Nix"
52
+ === ":simple-anaconda: Conda"
53
+
54
+ !!! note
55
+
56
+ This is a community-maintained package.
57
+
58
+ `zizmor` is available on Anaconda's conda-forge:
59
+
60
+ ```bash
61
+ conda install conda-forge::zizmor
62
+ ```
63
+
64
+ See [conda-forge/zizmor](https://anaconda.org/conda-forge/zizmor)
65
+ for additional information.
66
+
67
+
68
+ === ":material-nix: Nix"
53
69
 
54
70
  !!! note
55
71
 
@@ -17,6 +17,12 @@
17
17
 
18
18
  Homebrew/brew#18662
19
19
 
20
+ - ![](https://github.com/NLnetLabs.png?size=40){ width="40" loading=lazy align=left } NLnetLabs/unbound
21
+
22
+ ---
23
+
24
+ NLnetLabs/unbound#1204
25
+
20
26
  - ![](https://github.com/NetApp.png?size=40){ width="40" loading=lazy align=left } NetApp/harvest
21
27
 
22
28
  ---
@@ -47,12 +53,24 @@
47
53
 
48
54
  astropy/astropy#17315
49
55
 
56
+ - ![](https://github.com/cakephp.png?size=40){ width="40" loading=lazy align=left } cakephp/cakephp
57
+
58
+ ---
59
+
60
+ cakephp/cakephp#18081
61
+
50
62
  - ![](https://github.com/danmar.png?size=40){ width="40" loading=lazy align=left } danmar/cppcheck
51
63
 
52
64
  ---
53
65
 
54
66
  danmar/cppcheck#7044
55
67
 
68
+ - ![](https://github.com/ethereum.png?size=40){ width="40" loading=lazy align=left } ethereum/hevm
69
+
70
+ ---
71
+
72
+ ethereum/hevm#615
73
+
56
74
  - ![](https://github.com/hugovk.png?size=40){ width="40" loading=lazy align=left } hugovk/em-keyboard
57
75
 
58
76
  ---
@@ -131,6 +149,18 @@
131
149
 
132
150
  matplotlib/matplotlib#29251
133
151
 
152
+ - ![](https://github.com/mne-tools.png?size=40){ width="40" loading=lazy align=left } mne-tools/mne-python
153
+
154
+ ---
155
+
156
+ mne-tools/mne-python#13011
157
+
158
+ - ![](https://github.com/oxc-project.png?size=40){ width="40" loading=lazy align=left } oxc-project/oxc
159
+
160
+ ---
161
+
162
+ oxc-project/oxc#7844
163
+
134
164
  - ![](https://github.com/praetorian-inc.png?size=40){ width="40" loading=lazy align=left } praetorian-inc/noseyparker
135
165
 
136
166
  ---
@@ -185,6 +215,36 @@
185
215
 
186
216
  python-pillow/Pillow#8526
187
217
 
218
+ - ![](https://github.com/python-poetry.png?size=40){ width="40" loading=lazy align=left } python-poetry/cleo
219
+
220
+ ---
221
+
222
+ python-poetry/cleo#462
223
+
224
+ - ![](https://github.com/python-poetry.png?size=40){ width="40" loading=lazy align=left } python-poetry/poetry-core
225
+
226
+ ---
227
+
228
+ python-poetry/poetry-core#799
229
+
230
+ - ![](https://github.com/python-poetry.png?size=40){ width="40" loading=lazy align=left } python-poetry/poetry-plugin-bundle
231
+
232
+ ---
233
+
234
+ python-poetry/poetry-plugin-bundle#125
235
+
236
+ - ![](https://github.com/python-poetry.png?size=40){ width="40" loading=lazy align=left } python-poetry/poetry-plugin-export
237
+
238
+ ---
239
+
240
+ python-poetry/poetry-plugin-export#308
241
+
242
+ - ![](https://github.com/python-telegram-bot.png?size=40){ width="40" loading=lazy align=left } python-telegram-bot/python-telegram-bot
243
+
244
+ ---
245
+
246
+ python-telegram-bot/python-telegram-bot#4606
247
+
188
248
  - ![](https://github.com/python.png?size=40){ width="40" loading=lazy align=left } python/cpython
189
249
 
190
250
  ---
@@ -6,9 +6,11 @@
6
6
  adafruit/circuitpython#9785
7
7
  astral-sh/ruff#14844
8
8
  astropy/astropy#17315
9
+ cakephp/cakephp#18081
9
10
  danmar/cppcheck#7044
10
11
  DataDog/datadog-agent#30871
11
12
  Diaoul/subliminal#1190
13
+ ethereum/hevm#615
12
14
  Homebrew/brew#18662
13
15
  hugovk/em-keyboard#148
14
16
  hugovk/norwegianblue#233
@@ -23,7 +25,10 @@ hynek/stamina#81
23
25
  hynek/structlog#663
24
26
  matplotlib/matplotlib#29251
25
27
  marcusvolz/strava_py#53
28
+ mne-tools/mne-python#13011
26
29
  NetApp/harvest#3247
30
+ NLnetLabs/unbound#1204
31
+ oxc-project/oxc#7844
27
32
  praetorian-inc/noseyparker#228
28
33
  prettytable/prettytable#339
29
34
  pyca/service-identity#75
@@ -35,6 +40,11 @@ python-attrs/attrs#1368
35
40
  python-attrs/cattrs#605
36
41
  python-humanize/humanize#221
37
42
  python-pillow/Pillow#8526
43
+ python-poetry/cleo#462
44
+ python-poetry/poetry-core#799
45
+ python-poetry/poetry-plugin-export#308
46
+ python-poetry/poetry-plugin-bundle#125
47
+ python-telegram-bot/python-telegram-bot#4606
38
48
  PyO3/pyo3#4774
39
49
  rust-lang/crates.io#10176
40
50
  rustls/rustls#2261
@@ -69,7 +69,9 @@ markdown_extensions:
69
69
  provider: github
70
70
  user: woodruffw
71
71
  repo: zizmor
72
- - pymdownx.emoji
72
+ - pymdownx.emoji:
73
+ emoji_index: !!python/name:material.extensions.emoji.twemoji
74
+ emoji_generator: !!python/name:material.extensions.emoji.to_svg
73
75
  - admonition
74
76
  - pymdownx.details
75
77
  - pymdownx.superfences
@@ -70,6 +70,8 @@ const SAFE_CONTEXTS: &[&str] = &[
70
70
  "runner.os",
71
71
  // GitHub Actions temporary directory, value controlled by the runner itself.
72
72
  "runner.temp",
73
+ // GitHub Actions cached tool directory, value controlled by the runner itself.
74
+ "runner.tool_cache",
73
75
  ];
74
76
 
75
77
  impl TemplateInjection {
@@ -185,8 +187,10 @@ impl TemplateInjection {
185
187
  // The matrix is generated by an expression, meaning
186
188
  // that it's trivially not static.
187
189
  Some(LoE::Expr(_)) => false,
188
-
189
- Some(inner) => models::Matrix::new(inner).is_static(),
190
+ // The matrix may expand to static values according to the context
191
+ Some(inner) => {
192
+ models::Matrix::new(inner).expands_to_static_values(context)
193
+ }
190
194
  // Context specifies a matrix, but there is no matrix defined.
191
195
  // This is an invalid workflow so there's no point in flagging it.
192
196
  None => continue,
@@ -7,6 +7,7 @@ use indexmap::IndexMap;
7
7
  use super::{audit_meta, WorkflowAudit};
8
8
  use crate::{
9
9
  finding::{Confidence, Severity},
10
+ models::Uses,
10
11
  state::AuditState,
11
12
  };
12
13
 
@@ -77,52 +78,38 @@ impl WorkflowAudit for UseTrustedPublishing {
77
78
  return Ok(findings);
78
79
  };
79
80
 
80
- if uses.starts_with("pypa/gh-action-pypi-publish") {
81
- if self.pypi_publish_uses_manual_credentials(with) {
82
- findings.push(
83
- Self::finding()
84
- .severity(Severity::Informational)
85
- .confidence(Confidence::High)
86
- .add_location(
87
- step.location()
88
- .with_keys(&["uses".into()])
89
- .annotated("this step"),
90
- )
91
- .add_location(
92
- step.location()
93
- .with_keys(&["with".into(), "password".into()])
94
- .annotated(USES_MANUAL_CREDENTIAL),
95
- )
96
- .build(step.workflow())?,
97
- );
98
- }
99
- } else if uses.starts_with("rubygems/release-gem") {
100
- if self.release_gem_uses_manual_credentials(with) {
101
- findings.push(
102
- Self::finding()
103
- .severity(Severity::Informational)
104
- .confidence(Confidence::High)
105
- .add_location(
106
- step.location()
107
- .with_keys(&["uses".into()])
108
- .annotated("this step"),
109
- )
110
- .add_location(step.location().annotated(USES_MANUAL_CREDENTIAL))
111
- .build(step.workflow())?,
112
- );
113
- }
114
- } else if uses.starts_with("rubygems/configure-rubygems-credential")
115
- && self.rubygems_credential_uses_manual_credentials(with)
81
+ let Some(Uses::Repository(uses)) = Uses::from_step(uses) else {
82
+ return Ok(findings);
83
+ };
84
+
85
+ let candidate = Self::finding()
86
+ .severity(Severity::Informational)
87
+ .confidence(Confidence::High)
88
+ .add_location(
89
+ step.location()
90
+ .with_keys(&["uses".into()])
91
+ .annotated("this step"),
92
+ );
93
+
94
+ if uses.matches("pypa/gh-action-pypi-publish")
95
+ && self.pypi_publish_uses_manual_credentials(with)
116
96
  {
117
97
  findings.push(
118
- Self::finding()
119
- .severity(Severity::Informational)
120
- .confidence(Confidence::High)
98
+ candidate
121
99
  .add_location(
122
100
  step.location()
123
- .with_keys(&["uses".into()])
124
- .annotated("this step"),
101
+ .with_keys(&["with".into(), "password".into()])
102
+ .annotated(USES_MANUAL_CREDENTIAL),
125
103
  )
104
+ .build(step.workflow())?,
105
+ );
106
+ } else if ((uses.matches("rubygems/release-gem"))
107
+ && self.release_gem_uses_manual_credentials(with))
108
+ || (uses.matches("rubygems/configure-rubygems-credential")
109
+ && self.rubygems_credential_uses_manual_credentials(with))
110
+ {
111
+ findings.push(
112
+ candidate
126
113
  .add_location(step.location().annotated(USES_MANUAL_CREDENTIAL))
127
114
  .build(step.workflow())?,
128
115
  );
@@ -273,11 +273,11 @@ impl<'w> Matrix<'w> {
273
273
  }
274
274
 
275
275
  /// Checks whether some expanded path leads to an expression
276
- pub(crate) fn is_static(&self) -> bool {
277
- let expands_to_expression = self
278
- .expanded_values
279
- .iter()
280
- .any(|(_, expansion)| expansion.starts_with("${{") && expansion.ends_with("}}"));
276
+ pub(crate) fn expands_to_static_values(&self, context: &str) -> bool {
277
+ let expands_to_expression = self.expanded_values.iter().any(|(path, expansion)| {
278
+ let expanded_to_expression = expansion.starts_with("${{") && expansion.ends_with("}}");
279
+ context == path && expanded_to_expression
280
+ });
281
281
 
282
282
  !expands_to_expression
283
283
  }
@@ -551,6 +551,24 @@ pub(crate) struct RepositoryUses<'a> {
551
551
  }
552
552
 
553
553
  impl RepositoryUses<'_> {
554
+ /// Returns whether this `uses:` clause "matches" the given template.
555
+ /// The template is itself formatted like a normal `uses:` clause.
556
+ ///
557
+ /// This is an asymmetrical match: `actions/checkout@v3` "matches"
558
+ /// the `actions/checkout` template but not vice versa.
559
+ pub(crate) fn matches(&self, template: &str) -> bool {
560
+ let Some(Uses::Repository(other)) = Uses::from_step(template) else {
561
+ return false;
562
+ };
563
+
564
+ self.owner == other.owner
565
+ && self.repo == other.repo
566
+ && self.subpath == other.subpath
567
+ && other
568
+ .git_ref
569
+ .map_or(true, |git_ref| Some(git_ref) == self.git_ref)
570
+ }
571
+
554
572
  pub(crate) fn ref_is_commit(&self) -> bool {
555
573
  match self.git_ref {
556
574
  Some(git_ref) => git_ref.len() == 40 && git_ref.chars().all(|c| c.is_ascii_hexdigit()),
@@ -926,4 +944,33 @@ mod tests {
926
944
  .unwrap()
927
945
  .ref_is_commit());
928
946
  }
947
+
948
+ #[test]
949
+ fn test_repositoryuses_matches() {
950
+ for (uses, template, matches) in [
951
+ // OK: `uses:` is more specific than template
952
+ ("actions/checkout@v3", "actions/checkout", true),
953
+ ("actions/checkout/foo@v3", "actions/checkout/foo", true),
954
+ // OK: equally specific
955
+ ("actions/checkout@v3", "actions/checkout@v3", true),
956
+ ("actions/checkout", "actions/checkout", true),
957
+ ("actions/checkout/foo", "actions/checkout/foo", true),
958
+ ("actions/checkout/foo@v3", "actions/checkout/foo@v3", true),
959
+ // NOT OK: owner/repo do not match
960
+ ("actions/checkout@v3", "foo/checkout", false),
961
+ ("actions/checkout@v3", "actions/bar", false),
962
+ // NOT OK: subpath does not match
963
+ ("actions/checkout/foo", "actions/checkout", false),
964
+ ("actions/checkout/foo@v3", "actions/checkout@v3", false),
965
+ // NOT OK: template is more specific than `uses:`
966
+ ("actions/checkout", "actions/checkout@v3", false),
967
+ ("actions/checkout/foo", "actions/checkout/foo@v3", false),
968
+ ] {
969
+ let Some(Uses::Repository(uses)) = Uses::from_common(uses) else {
970
+ panic!();
971
+ };
972
+
973
+ assert_eq!(uses.matches(template), matches)
974
+ }
975
+ }
929
976
  }
@@ -197,6 +197,7 @@ fn self_hosted() -> Result<()> {
197
197
  .workflow(workflow_under_test("self-hosted/issue-283-repro.yml"))
198
198
  .args(["--persona=auditor"])
199
199
  .run()?);
200
+
200
201
  Ok(())
201
202
  }
202
203
 
@@ -244,5 +245,11 @@ fn template_injection() -> Result<()> {
244
245
  .args(["--persona=auditor"])
245
246
  .run()?);
246
247
 
248
+ // Fixed regressions
249
+
250
+ insta::assert_snapshot!(zizmor()
251
+ .workflow(workflow_under_test("template-injection/issue-22-repro.yml"))
252
+ .run()?);
253
+
247
254
  Ok(())
248
255
  }
@@ -0,0 +1,6 @@
1
+ ---
2
+ source: tests/snapshot.rs
3
+ expression: "zizmor().workflow(workflow_under_test(\"template-injection/issue-22-repro.yml\")).run()?"
4
+ snapshot_kind: text
5
+ ---
6
+ No findings to report. Good job! (4 suppressed)
@@ -0,0 +1,64 @@
1
+ # Adapted from :
2
+ # https://github.com/python/cpython/blob/e2325c9db0650fc06d909eb2b5930c0573f24f71/.github/workflows/jit.yml
3
+ # See also https://github.com/woodruffw/zizmor/issues/22#issuecomment-2543128489
4
+
5
+ name: JIT
6
+ on:
7
+ pull_request:
8
+
9
+ jobs:
10
+ jit:
11
+ name: ${{ matrix.target }} (${{ matrix.debug && 'Debug' || 'Release' }})
12
+ runs-on: ${{ matrix.runner }}
13
+ strategy:
14
+ fail-fast: false
15
+ matrix:
16
+ target:
17
+ - x86_64-apple-darwin/clang
18
+ - aarch64-apple-darwin/clang
19
+ - x86_64-unknown-linux-gnu/gcc
20
+ - aarch64-unknown-linux-gnu/gcc
21
+ debug:
22
+ - true
23
+ - false
24
+ llvm:
25
+ - 19
26
+ include:
27
+ - target: aarch64-apple-darwin/clang
28
+ architecture: aarch64
29
+ runner: macos-14
30
+ - target: x86_64-unknown-linux-gnu/gcc
31
+ architecture: x86_64
32
+ runner: ubuntu-24.04
33
+ - target: aarch64-unknown-linux-gnu/gcc
34
+ architecture: aarch64
35
+ # Should not be flagged in the template injection audit
36
+ runner: ${{ github.repository_owner == 'python' && 'ubuntu-24.04-aarch64' || 'ubuntu-24.04' }}
37
+ steps:
38
+ - uses: actions/checkout@v4
39
+ with:
40
+ persist-credentials: false
41
+
42
+ - uses: actions/setup-python@v5
43
+ with:
44
+ python-version: '3.11'
45
+
46
+ - name: Native macOS
47
+ if: runner.os == 'macOS'
48
+ run: |
49
+ brew update
50
+ find /usr/local/bin -lname '*/Library/Frameworks/Python.framework/*' -delete
51
+ brew install llvm@${{ matrix.llvm }}
52
+ export SDKROOT="$(xcrun --show-sdk-path)"
53
+ ./configure --enable-experimental-jit ${{ matrix.debug && '--with-pydebug' || '' }}
54
+ make all --jobs 4
55
+ ./python.exe -m test --multiprocess 0 --timeout 4500 --verbose2 --verbose3
56
+
57
+ - name: Native Linux
58
+ if: runner.os == 'Linux' && (matrix.architecture == 'x86_64' || github.repository_owner == 'python')
59
+ run: |
60
+ sudo bash -c "$(wget -O - https://apt.llvm.org/llvm.sh)" ./llvm.sh ${{ matrix.llvm }}
61
+ export PATH="$(llvm-config-${{ matrix.llvm }} --bindir):$PATH"
62
+ ./configure --enable-experimental-jit ${{ matrix.debug && '--with-pydebug' || '' }}
63
+ make all --jobs 4
64
+ ./python -m test --multiprocess 0 --timeout 4500 --verbose2 --verbose3
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
File without changes
File without changes