Skip to content

Commit c28d44c

Browse files
authored
feat: composite action support (#331)
1 parent d1c9004 commit c28d44c

31 files changed

+1002
-316
lines changed

Diff for: Cargo.lock

+75
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: Cargo.toml

+2
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ clap-verbosity-flag = { version = "3.0.2", features = [
2222
"tracing",
2323
], default-features = false }
2424
etcetera = "0.8.0"
25+
flate2 = "1.0.35"
2526
github-actions-models = "0.17.0"
2627
http-cache-reqwest = "0.15.0"
2728
human-panic = "2.0.1"
@@ -44,6 +45,7 @@ serde_json = "1.0.134"
4445
serde_yaml = "0.9.34"
4546
# TODO remove pending https://github.com/tree-sitter/tree-sitter/pull/4034
4647
streaming-iterator = "0.1.9"
48+
tar = "0.4.43"
4749
terminal-link = "0.1.0"
4850
tokio = { version = "1.42.0", features = ["rt-multi-thread"] }
4951
tracing = "0.1.41"

Diff for: docs/audits.md

+3-2
Original file line numberDiff line numberDiff line change
@@ -295,7 +295,7 @@ Use [encrypted secrets] instead of hardcoded credentials.
295295

296296
| Type | Examples | Introduced in | Works offline | Enabled by default |
297297
|----------|-----------------------|---------------|----------------|--------------------|
298-
| Workflow | [impostor-commit.yml] | v0.1.0 |||
298+
| Workflow, Action | [impostor-commit.yml] | v0.1.0 |||
299299

300300
[impostor-commit.yml]: https://github.com/woodruffw/gha-hazmat/blob/main/.github/workflows/impostor-commit.yml
301301

@@ -361,6 +361,7 @@ the action if one is available, or remove the action's usage entirely.
361361
|----------|---------------------|---------------|----------------|--------------------|
362362
| Workflow | [ref-confusion.yml] | v0.1.0 |||
363363

364+
364365
[ref-confusion.yml]: https://github.com/woodruffw/gha-hazmat/blob/main/.github/workflows/ref-confusion.yml
365366

366367
Detects actions that are pinned to confusable symbolic refs (i.e. branches
@@ -431,7 +432,7 @@ there are steps you can take to minimize their risk:
431432

432433
| Type | Examples | Introduced in | Works offline | Enabled by default |
433434
|----------|--------------------------|---------------|----------------|--------------------|
434-
| Workflow | [template-injection.yml] | v0.1.0 |||
435+
| Workflow, Action | [template-injection.yml] | v0.1.0 |||
435436

436437
[template-injection.yml]: https://github.com/woodruffw/gha-hazmat/blob/main/.github/workflows/template-injection.yml
437438

Diff for: docs/configuration.md

+5-1
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,11 @@ where `filename.yml` is the base filename of the workflow, and `line` and
5959
location to ignore. If one or both are absent, then the rule applies to the
6060
entire file or entire line.
6161

62-
By example, here is a configuration file with two different audit ignore
62+
!!! important
63+
64+
Composite action findings cannot be ignored via `zizmor.yml` currently.
65+
66+
For example, here is a configuration file with two different audit ignore
6367
rule groups:
6468

6569
```yaml title="zizmor.yml"

Diff for: docs/quickstart.md

+33-18
Original file line numberDiff line numberDiff line change
@@ -16,36 +16,47 @@ You should see something like this:
1616

1717
Here are some different ways you can run `zizmor` locally:
1818

19-
=== "On one or more files"
19+
=== "On one or more workflows"
2020

21-
You can run `zizmor` on one or more workflows as explicit inputs:
21+
You can run `zizmor` on one or more workflows or composite actions as
22+
explicit inputs:
2223

2324
```bash
24-
zizmor ci.yml tests.yml lint.yml
25+
zizmor ci.yml tests.yml lint.yml action.yml
2526
```
2627

2728
These can be in any directory as well:
2829

2930
```
30-
zizmor ./subdir/ci.yml ../sibling/tests.yml
31+
zizmor ./subdir/ci.yml ../sibling/tests.yml ./action/action.yml
3132
```
3233

33-
=== "On one or more directories"
34+
=== "On one or more local repositories"
3435

35-
If you have multiple workflows in a single directory, `zizmor` will
36-
discover them:
36+
!!! tip
3737

38-
```bash
39-
# somewhere/ contains ci.yml and tests.yml
40-
zizmor somewhere/
41-
```
38+
Composite action support was added in v1.0.0.
39+
40+
!!! tip
41+
42+
Pass `--collect=workflows-only` to disable collecting composite actions.
4243

43-
Moreover, if the specified directory contains a `.github/workflows`
44-
subdirectory, `zizmor` will discover workflows there:
44+
When given one or more local directories, `zizmor` will treat each as a
45+
GitHub repository and attempt to discover workflows defined under the
46+
`.github/workflows` subdirectory for each. `zizmor` will also walk each
47+
directory to find composite action definitions (`action.yml` in any
48+
subdirectory).
4549

4650
```bash
47-
# my-local-repo/ contains .github/workflows/{ci,tests}.yml
48-
zizmor my-local-repo/
51+
# repo-a/ contains .github/workflows/{ci,tests}.yml
52+
# as well as custom-action/action.yml
53+
zizmor repo-a/
54+
55+
# or with multiple directories
56+
zizmor repo-a/ ../../repo-b/
57+
58+
# collect only workflows, not composite actions
59+
zizmor --collect=workflows-only
4960
```
5061

5162
=== "On one or more remote repositories"
@@ -55,11 +66,15 @@ Here are some different ways you can run `zizmor` locally:
5566
Private repositories can also be audited remotely, as long
5667
as your GitHub API token has sufficient permissions.
5768

58-
`zizmor` can also fetch workflows directly from GitHub, if given a
59-
GitHub API token via `GH_TOKEN` or `--gh-token`:
69+
!!! tip
70+
71+
Pass `--collect=workflows-only` to disable collecting composite actions.
72+
73+
`zizmor` can also fetch workflows and actions directly from GitHub, if
74+
given a GitHub API token via `GH_TOKEN` or `--gh-token`:
6075

6176
```bash
62-
# audit all workflows in woodruffw/zizmor
77+
# audit all workflows and composite actions in woodruffw/zizmor
6378
# assumes you have `gh` installed
6479
zizmor --gh-token=$(gh auth token) woodruffw/zizmor
6580
```

Diff for: docs/snippets/help.txt

+2
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ Options:
3434
Filter all results below this confidence [possible values: unknown, low, medium, high]
3535
--cache-dir <CACHE_DIR>
3636
The directory to use for HTTP caching. By default, a host-appropriate user-caching directory will be used
37+
--collect <COLLECT>
38+
Control which kinds of inputs are collected for auditing [default: all] [possible values: all, workflows-only, actions-only]
3739
-h, --help
3840
Print help (see more with '--help')
3941
-V, --version

Diff for: docs/usage.md

+68-2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,72 @@ description: Usage recipes for running zizmor locally and in CI/CD.
44

55
# Usage Recipes
66

7+
## Input collection
8+
9+
Before auditing, `zizmor` performs an input collection phase.
10+
11+
There are three input sources that `zizmor` knows about:
12+
13+
1. Individual workflow and composite action files, e.g. `foo.yml` and
14+
`my-action/action.yml`;
15+
2. "Local" GitHub repositories in the form of a directory, e.g. `my-repo/`;
16+
3. "Remote" GitHub repositories in the form of a "slug", e.g.
17+
`pypa/sampleproject`.
18+
19+
!!! tip
20+
21+
By default, a remote repository will be audited from the `HEAD`
22+
of the default branch. To control this, you can append a `git`
23+
reference to the slug:
24+
25+
```bash
26+
# audit at HEAD on the default branch
27+
zizmor example/example
28+
29+
# audit at branch or tag `v1`
30+
zizmor example/example@v1
31+
32+
# audit at a specific SHA
33+
zizmor example/example@abababab...
34+
```
35+
36+
!!! tip
37+
38+
Remote auditing requires Internet access and a GitHub API token.
39+
See [Operating Modes](#operating-modes) for more information.
40+
41+
`zizmor` can audit multiple inputs in the same run, and different input
42+
sources can be mixed and matched:
43+
44+
```bash
45+
# audit a single local workflow, an entire local repository, and
46+
# a remote repository all in the same run
47+
zizmor ../example.yml ../other-repo/ example/example
48+
```
49+
50+
When auditing local and/or remote repositories, `zizmor` will collect both
51+
workflows (e.g. `.github/workflows/ci.yml`) **and** action definitions
52+
(e.g. `custom-action/foo.yml`) by default. To disable one or the other,
53+
you can use the `--collect=...` option.
54+
55+
```bash
56+
# collect everything (the default)
57+
zizmor --collect=all example/example
58+
59+
# collect only workflows
60+
zizmor --collect=workflows-only example/example
61+
62+
# collect only actions
63+
zizmor --collect=actions-only example/example
64+
```
65+
66+
!!! tip
67+
68+
`--collect=...` only controls input collection from repository input
69+
sources. In other words, `zizmor --collect=actions-only workflow.yml`
70+
*will* audit `workflow.yml`, since it was passed explicitly and not
71+
collected indirectly.
72+
773
## Operating Modes
874

975
Some of `zizmor`'s audits require access to GitHub's API.
@@ -98,8 +164,8 @@ sensitive `zizmor`'s analyses are:
98164

99165
This persona is ideal for finding things that are a good idea
100166
to clean up or resolve, but are likely not immediately actionable
101-
security findings (or are actionable, but indicate a intentional
102-
security decision by the workflow author).
167+
security findings (or are actionable, but suggest a intentional
168+
security decision by the workflow/action author).
103169

104170
For example, using the pedantic persona will flag the following
105171
with an `unpinned-uses` finding, since it uses a symbolic reference

Diff for: src/audit/artipacked.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use github_actions_models::{
77
};
88
use itertools::Itertools;
99

10-
use super::{audit_meta, WorkflowAudit};
10+
use super::{audit_meta, Audit};
1111
use crate::{
1212
finding::{Confidence, Finding, Persona, Severity},
1313
state::AuditState,
@@ -44,7 +44,7 @@ impl Artipacked {
4444
}
4545
}
4646

47-
impl WorkflowAudit for Artipacked {
47+
impl Audit for Artipacked {
4848
fn new(_state: AuditState) -> Result<Self> {
4949
Ok(Self)
5050
}

Diff for: src/audit/cache_poisoning.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::audit::{audit_meta, WorkflowAudit};
1+
use crate::audit::{audit_meta, Audit};
22
use crate::finding::{Confidence, Finding, Severity};
33
use crate::models::{Job, Step, Steps, Uses};
44
use crate::state::AuditState;
@@ -517,7 +517,7 @@ impl CachePoisoning {
517517
}
518518
}
519519

520-
impl WorkflowAudit for CachePoisoning {
520+
impl Audit for CachePoisoning {
521521
fn new(_: AuditState) -> anyhow::Result<Self>
522522
where
523523
Self: Sized,

0 commit comments

Comments
 (0)