feat: begin prepping zizmor's website (#78)

This commit is contained in:
William Woodruff 2024-10-30 00:26:18 -04:00 committed by GitHub
parent b25a5bf428
commit 0ce62213f4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
25 changed files with 706 additions and 411 deletions

49
.github/workflows/site.yml vendored Normal file
View file

@ -0,0 +1,49 @@
name: Deploy zizmor site
on:
push:
branches:
- main
- site-staging
workflow_dispatch:
concurrency:
group: "pages"
cancel-in-progress: false
permissions: {}
jobs:
deploy:
permissions:
contents: read
pages: write
id-token: write
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
persist-credentials: false
- name: Install the latest version of uv
uses: astral-sh/setup-uv@v3
- name: build site
run: make site
- name: Setup Pages
uses: actions/configure-pages@v5
- name: Upload artifact
uses: actions/upload-pages-artifact@v3
with:
path: site_html
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4

3
.gitignore vendored
View file

@ -1 +1,4 @@
/target
# website artifacts
/site_html

View file

@ -2,69 +2,84 @@
Thank you for your interest in contributing to `zizmor`!
The information below will help you set up a local development environment,
as well as with performing common development tasks.
This is intended to be a "high-level" guide with some suggestions
for ways to contribute. Once you've picked a contribution idea,
please see our [development docs]
for concrete guidance on specific development tasks (such as building `zizmor`
itself or the documentation website).
This is intended to be a "high-level" guide; for concrete development
goals (such as modifying an audit or contributing a new audit),
please see our [development docs](./docs/DEVELOPMENT.md).
## How to contribute
## Requirements
Here's a short list of steps you can follow to contribute:
`zizmor`'s only development requirement the Rust compiler.
1. *Figure out what you want to contribute.* See the
[contribution ideas](#contribution-ideas) section below if you're looking
for ideas!
2. *File or reply to an issue, if appropriate.* Some contributions require
new issues (like new bugs), while others involve an existing issue
(like known documentation defects). Others don't require an issue at all,
like small typo fixes. In general, if you aren't sure, *error on the side
of making or replying to an issue* — it helps maintain shared
development context.
3. *Hack away.* Once you know what you're working on, refer to our
[development docs] for help with specific development tasks. And don't be
afraid to ask for help!
You can install Rust by following the steps on [Rust's official website].
## Contribution ideas
[Rust's official website]: https://www.rust-lang.org/tools/install
Here are some ways that you can contribute to `zizmor`. These aren't the only
ways; they're just for inspiration.
## Development steps
### Good first issues
To get started, you'll need to clone the repository and perform a debug build:
We use the ["good first issue"] label to track issues that we think are
(somewhat) easy and/or straightforward, making them good choices for an
early contribution.
```bash
git clone https://github.com/woodruffw/zizmor
cd zizmor
cargo build
```
To work on one of these, **please leave a comment** on its issue before opening
a pull request to make sure nobody else duplicates your work!
Once `cargo build` completes, you should have a functional development
build of `zizmor`!
["good first issue"]: https://github.com/woodruffw/zizmor/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22
```bash
# cargo run -- --help also works
./target/debug/zizmor --help
```
### Writing documentation
## Linting
One of the best ways to help us with `zizmor` is to help us improve our
documentation!
`zizmor` is linted with `cargo clippy` and auto-formatted with `cargo fmt`.
Our CI enforces both, but you should also run them locally to minimize
unnecessary review cycles:
Here are some things we could use help with:
```bash
cargo fmt
cargo clippy --fix
```
* Improving our [CLI usage recipes](https://woodruffw.github.io/zizmor/usage/).
* Improving the detail in our
[audit documentation pages](https://woodruffw.github.io/zizmor/audits/).
* Improving our internal (Rust API) documentation, especially in conjunction
with more unit tests.
## Testing
More generally, see [issues labeled with `documentation`] for a potential
list of documentation efforts to contribute on.
`zizmor` uses `cargo test`:
[issues labeled with `documentation`]: https://github.com/woodruffw/zizmor/issues?q=is%3Aissue+is%3Aopen+label%3Adocumentation
```bash
cargo test
```
### Writing unit tests
## Development practices
We can always use more unit tests! Pick a part of the Rust codebase and
start testing.
Here are some guidelines to follow if you're working on `zizmor`:
Keep the cardinal rule of unit testing in mind: a unit test must test
**a single unit** of behavior. If it tests more than one unit, then
consider making it an integration test instead.
### Reducing false positives/negatives in audits
Static analysis is inherently imprecise, and `zizmor` is no exception.
We track imprecision bugs with the ["false positive"] and ["false negative"]
labels. These can sometimes be tricky to address, so we recommend
(but don't require) leaving an explanatory comment on the issue before
beginning a pull request.
["false positive"]: https://github.com/woodruffw/zizmor/issues?q=is%3Aopen+label%3Afalse-positive
["false negative"]: https://github.com/woodruffw/zizmor/issues?q=is%3Aopen+label%3Afalse-negative
[development docs]: https://woodruffw.github.io/zizmor/development/
* *Document internal APIs*. `zizmor` doesn't have a public Rust API (yet),
but the internal APIs should be documented *as if* they might become public
one day. Plus, well-documented internals make life easier for new
contributors.
* *Write unit tests*. It's easy for small changes in `zizmor`'s internals to
percolate into large bugs (e.g. incorrect location information); help us
catch these bugs earlier by testing your changes at the smallest unit of
behavior.
* *Test on real inputs*. If you're contributing to or adding a new audit,
make sure your analysis is reliable and accurate on non-sample inputs.

18
Makefile Normal file
View file

@ -0,0 +1,18 @@
VENV = .venv
VENV_BIN := $(VENV)/bin
.PHONY: all
all:
@echo "Run my targets individually!"
.PHONY: site
site: $(VENV)
$(VENV_BIN)/mkdocs build
.PHONY: site-live
site-live: $(VENV)
$(VENV_BIN)/mkdocs serve
$(VENV): site-requirements.txt
uv venv
uv pip install -r site-requirements.txt

128
README.md
View file

@ -1,4 +1,4 @@
# zizmor
# 🌈 zizmor
[![CI](https://github.com/woodruffw/zizmor/actions/workflows/ci.yml/badge.svg)](https://github.com/woodruffw/zizmor/actions/workflows/ci.yml)
[![Crates.io](https://img.shields.io/crates/v/zizmor)](https://crates.io/crates/zizmor)
@ -8,129 +8,17 @@ A tool for finding security issues in GitHub Actions CI/CD setups.
> [!IMPORTANT]
> `zizmor` is currently in beta. You will encounter bugs; please file them!
Quick links:
![](./docs/assets/zizmor-demo.gif)
* [Installation](#installation)
* [Quick start guide](#quickstart)
* [Usage](#usage)
* [Online and offline use](#online-and-offline-use)
* [Output formats](#output-formats)
* [Audit documentation](./docs/audit/)
* [Integration](#integration)
* [Use in GitHub Actions](#use-in-github-actions)
* [Technical details](#technical-details)
* [Contributing](#contributing)
* [The name?](#the-name)
See [`zizmor`'s documentation](https://woodruffw.github.io/zizmor/)
for [installation steps], as well as a [quickstart] and
[detailed usage recipes].
Go right to the [Quickstart](#quickstart) or [Usage](#usage) to learn
how to use `zizmor` locally or in your CI/CD.
[installation steps]: https://woodruffw.github.io/zizmor/installation/
## Installation
[quickstart]: https://woodruffw.github.io/zizmor/installation/
You can install `zizmor` from <https://crates.io> via `cargo`:
```bash
cargo install zizmor
```
or via [Homebrew](https://brew.sh/):
```bash
brew install zizmor
```
## Quickstart
You can run `zizmor` on any file(s) you have locally:
```bash
# audit a specific workflow
zizmor my-workflow.yml
# discovers .github/workflows/*.yml automatically
zizmor path/to/repo
```
By default, `zizmor` will emit a Rust-style human-friendly findings, e.g.:
```console
error[pull-request-target]: use of fundamentally insecure workflow trigger
--> /home/william/devel/gha-hazmat/.github/workflows/pull-request-target.yml:20:1
|
20 | / on:
21 | | # NOT OK: pull_request_target should almost never be used
22 | | pull_request_target:
| |______________________^ triggers include pull_request_target, which is almost always used insecurely
|
1 findings (0 unknown, 0 informational, 0 low, 0 medium, 1 high)
```
See the [Usage](#usage) for more examples, including examples of configuration.
## Usage
### Online and offline use
Some of `zizmor`'s audits require access to GitHub's API. `zizmor` will perform
online audits by default *if* the user has a `GH_TOKEN` specified
in their environment. If no `GH_TOKEN` is present, then `zizmor` will operate
in offline mode by default.
Both of these can be made explicit through their respective command-line flags:
```bash
# force offline, even if a GH_TOKEN is present
zizmor --offline workflow.yml
# passing a token explicitly will forcefully enable online mode
zizmor --gh-token ghp-... workflow.yml
```
### Output formats
`zizmor` always produces output on `stdout`. If a terminal is detected,
`zizmor` will default to a human-readable diagnostic output; if no terminal
is detected, `zizmor` will emit JSON.
Output formats can be controlled explicitly via the `--format` option:
```bash
# force diagnostic output, even if not a terminal
zizmor --format plain
# emit zizmor's own JSON format
zizmor --format json
# emit SARIF JSON instead of normal JSON
zizmor --format sarif
```
See [Integration](#integration) for suggestions on when to use each format.
## Integration
### Use in GitHub Actions
`zizmor` is trivial to use within GitHub Actions; you can run it just like
you would locally.
`zizmor --format sarif` specifies [SARIF] as the output format, which GitHub's
code scanning feature also supports.
See [GitHub's documentation] for advice on how to integrate `zizmor`'s results
directly into a repository's scanning setup.
For a specific example, see `zizmor`'s own [repository workflow scan].
GitHub's example of [running ESLint] as a security workflow provides additional
relevant links.
[SARIF]: https://sarifweb.azurewebsites.net/
[GitHub's documentation]: https://docs.github.com/en/code-security/code-scanning/integrating-with-code-scanning/uploading-a-sarif-file-to-github
[repository workflow scan]: https://github.com/woodruffw/zizmor/blob/main/.github/workflows/zizmor.yml
[running ESLint]: https://docs.github.com/en/code-security/code-scanning/integrating-with-code-scanning/uploading-a-sarif-file-to-github#example-workflow-that-runs-the-eslint-analysis-tool
[detailed usage recipes]: https://woodruffw.github.io/zizmor/installation/
## Technical details

View file

@ -1,25 +0,0 @@
# Hacking on `zizmor`
## Writing documentation
One of the best ways to help us with `zizmor` is to help us improve our
documentation!
Here are some things we could use help with:
* Improving the detail in our [audit documentation pages](./audit/).
* Improving the detail in our [README](../README.md), e.g. by adding
or improving our usage examples.
More generally, see [issues labeled with `documentation`] for a potential
list of documentation efforts to contribute on.
[issues labeled with `documentation`]: https://github.com/woodruffw/zizmor/issues?q=sort%3Aupdated-desc+is%3Aissue+is%3Aopen+label%3Adocumentation
## Adding or modifying an audit
These docs could use help.
For now, please run `cargo doc --open` and refer to our internal
documentation!

BIN
docs/assets/zizmor-demo.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

View file

@ -1,33 +0,0 @@
# `artipacked`
| Audit ID | Type | Examples |
| -------- | ---- | -------- |
| `artipacked` | Workflow | [`artipacked.yml`](https://github.com/woodruffw/gha-hazmat/blob/main/.github/workflows/artipacked.yml)
## What
Unexpected credential use and potential credential persistence,
typically via GitHub Actions artifact creation or action logs.
## Why
The default checkout action is [`actions/checkout`].
By default, using `actions/checkout` causes a credential to be persisted
in the checked-out repo's `.git/config`, so that subsequent `git` operations
can be authenticated.
Subsequent steps may accidentally publicly persist `.git/config`, e.g. by
including it in a publicly accessible artifact via [`actions/upload-artifact`].
However, even without this, persisting the credential in the `.git/config`
is non-ideal and should be disabled with `persist-credentials: false` unless
the job actually needs the persisted credential.
## Other resources
* <https://unit42.paloaltonetworks.com/github-repo-artifacts-leak-tokens/>
[`actions/checkout`]: https://github.com/actions/checkout
[`actions/upload-artifact`]: https://github.com/actions/upload-artifact

View file

@ -1,27 +0,0 @@
# `dangerous-triggers`
| Audit ID | Type | Examples |
| -------- | ---- | -------- |
| `dangerous-triggers` | Workflow | [`pull-request-target.yml`](https://github.com/woodruffw/gha-hazmat/blob/main/.github/workflows/pull-request-target.yml)
## What
Fundamentally dangerous GitHub Actions workflow triggers.
## Why
Many of GitHub's workflow triggers are difficult to use securely.
This audit checks for some of the biggest offenders:
* `pull_request_target`
* `workflow_run`
These triggers are dangerous because they run in the context of the
*target repository* rather than the *fork repository*, while also being
typically triggerable by the latter. This can lead to attacker controlled
code execution or unexpected action runs with context controlled by a malicious
fork.
## Other resources
* <https://securitylab.github.com/resources/github-actions-preventing-pwn-requests/>

View file

@ -1,16 +0,0 @@
# `excessive-permissions`
| Audit ID | Type | Examples |
| -------- | ---- | -------- |
| `excessive-permissions` | Workflow | [`excessive-permissions.yml`](https://github.com/woodruffw/gha-hazmat/blob/main/.github/workflows/excessive-permissions.yml)
## What
Looks for excessive permissions in workflows, both at
the workflow level and individual job levels.
## Why
Users frequently over-scope their workflow and job permissions,
or set broad workflow-level permissions without realizing that
all jobs inherit those permissions.

View file

@ -1,14 +0,0 @@
# `hardcoded-container-credentials`
| Audit ID | Type | Examples |
| -------- | ---- | -------- |
| `hardcoded-container-credentials` | Workflow | [`hardcoded-credentials.yml`](https://github.com/woodruffw/gha-hazmat/blob/main/.github/workflows/hardcoded-credentials.yml)
## What
GitHub Actions allows Docker credentials (usernames and passwords)
to be hardcoded in various places within workflows.
## Why
Hardcoding credentials is bad.

View file

@ -1,22 +0,0 @@
# `impostor-commit`
| Audit ID | Type | Examples |
| -------- | ---- | -------- |
| `impostor-commit` | Workflow | [`impostor-commit.yml`](https://github.com/woodruffw/gha-hazmat/blob/main/.github/workflows/impostor-commit.yml)
## What
GitHub represents a repository and its forks as a "network" of commits.
This results in ambiguity about where a commit comes from: a commit
that exists only in a fork can be referenced via its parent's
`owner/repo` slug, and vice versa.
## Why
GitHub's network design can be used to obscure a commit's true origin
in a fully-pinned `uses:` workflow reference. This can be used by an attacker
to surreptitiously introduce a backdoored action into a victim's workflows(s).
## Other resources
* <https://www.chainguard.dev/unchained/what-the-fork-imposter-commits-in-github-actions-and-ci-cd>

View file

@ -1,22 +0,0 @@
# `known-vulnerable-actions`
| Audit ID | Type | Examples |
| -------- | ---- | -------- |
| `known-vulnerable-actions` | Workflow | [`known-vulnerable-actions.yml`](https://github.com/woodruffw/gha-hazmat/blob/main/.github/workflows/known-vulnerable-actions.yml)
## What
Actions with known, publicly disclosed vulnerabilities are tracked in the
[GitHub Advisories database]. Examples of commonly disclosed vulnerabilities
in GitHub Actions include [credential disclosure] and code injection
via [template injection].
## Why
You shouldn't use actions with known vulnerabilities.
[GitHub Advisories database]: https://github.com/advisories
[credential disclosure]: ./artipacked.md
[template injection]: ./template-injection.md

View file

@ -1,19 +0,0 @@
# `ref-confusion`
| Audit ID | Type | Examples |
| -------- | ---- | -------- |
| `ref-confusion` | Workflow | [`ref-confusion.yml`](https://github.com/woodruffw/gha-hazmat/blob/main/.github/workflows/ref-confusion.yml)
## What
Like with [impostor commits], actions that are used with a symbolic ref
in their `uses:` are subject to a degree of ambiguity: a ref like
`@v1` might refer to either a branch or tag ref.
## Why
An attacker can exploit this ambiguity to publish a branch or tag ref that
takes precedence over a legitimate one, delivering a malicious action to
pre-existing consumers of that action without having to modify those consumers.
[impostor commits]: ./impostor-commits.md

View file

@ -1,19 +0,0 @@
# `self-hosted-runner`
| Audit ID | Type | Examples |
| -------- | ---- | -------- |
| `self-hosted-runner` | Workflow | [`self-hosted.yml`](https://github.com/woodruffw/gha-hazmat/blob/main/.github/workflows/self-hosted-runner.yml)
## What
GitHub supports self-hosted runners, which behave similarly to GitHub-hosted
runners but use client-managed compute resources.
## Why
Self-hosted runners are very hard to secure by default, which is why
GitHub does not recommend their use in public repositories.
## Other resources
* <https://docs.github.com/en/actions/hosting-your-own-runners/managing-self-hosted-runners/about-self-hosted-runners#self-hosted-runner-security>

View file

@ -1,24 +0,0 @@
# `template-injection`
| Audit ID | Type | Examples |
| -------- | ---- | -------- |
| `template-injection` | Workflow | [`self-hosted.yml`](https://github.com/woodruffw/gha-hazmat/blob/main/.github/workflows/template-injection.yml)
## What
GitHub Actions allows workflows to define *template expansions*, which
occur within special `${{ ... }}` delimiters. These expansions happen
before workflow and job execution, meaning the expansion
of a given expression appears verbatim in whatever context it was performed in.
## Why
Template expansions aren't syntax-aware, meaning that they can result in
unintended shell injection vectors. This is especially true when they're
used with attacker-controllable expression contexts, such as
`github.event.issue.title` (which the attacker can fully control by supplying
a new issue title).
## Other resources
* <https://securitylab.github.com/resources/github-actions-untrusted-input/>

View file

@ -1,23 +0,0 @@
# `use-trusted-publishing`
| Audit ID | Type | Examples |
| -------- | ---- | -------- |
| `use-trusted-publishing` | Workflow | [`pypi-manual-credential.yml`](https://github.com/woodruffw/gha-hazmat/blob/main/.github/workflows/pypi-manual-credential.yml)
## What
Some packaging ecosystems/indices (like PyPI and RubyGems) support
"Trusted Publishing," which is an OIDC-based "tokenless" authentication
mechanism for uploading to the index from within a CI/CD workflow.
## Why
This "tokenless" flow has significant security benefits over a traditional
manually configured API token, and should be preferred wherever supported
and possible.
## Other resources
* <https://docs.pypi.org/trusted-publishers/>
* <https://guides.rubygems.org/trusted-publishing/>
* <https://blog.trailofbits.com/2023/05/23/trusted-publishing-a-new-benchmark-for-packaging-security/>

255
docs/audits.md Normal file
View file

@ -0,0 +1,255 @@
# Audit Rules
This page documents each of the audits currently implemented in `zizmor`.
See each audit's section for its scope, behavior, and other information.
## `artipacked`
| Type | Examples | Introduced in |
| ---- | -------- | ------------- |
| Workflow | [artipacked.yml] | v0.1.0 |
[artipacked.yml]: https://github.com/woodruffw/gha-hazmat/blob/main/.github/workflows/artipacked.yml
### What
Unexpected credential use and potential credential persistence,
typically via GitHub Actions artifact creation or action logs.
### Why
The default checkout action is [`actions/checkout`].
By default, using `actions/checkout` causes a credential to be persisted
in the checked-out repo's `.git/config`, so that subsequent `git` operations
can be authenticated.
Subsequent steps may accidentally publicly persist `.git/config`, e.g. by
including it in a publicly accessible artifact via [`actions/upload-artifact`].
However, even without this, persisting the credential in the `.git/config`
is non-ideal and should be disabled with `persist-credentials: false` unless
the job actually needs the persisted credential.
### Other resources
* <https://unit42.paloaltonetworks.com/github-repo-artifacts-leak-tokens/>
[`actions/checkout`]: https://github.com/actions/checkout
[`actions/upload-artifact`]: https://github.com/actions/upload-artifact
## `dangerous-triggers`
| Type | Examples | Introduced in |
| ---- | -------- | ------------- |
| Workflow | [pull-request-target.yml] | v0.1.0 |
[pull-request-target.yml]: https://github.com/woodruffw/gha-hazmat/blob/main/.github/workflows/pull-request-target.yml
### What
Fundamentally dangerous GitHub Actions workflow triggers.
### Why
Many of GitHub's workflow triggers are difficult to use securely.
This audit checks for some of the biggest offenders:
* `pull_request_target`
* `workflow_run`
These triggers are dangerous because they run in the context of the
*target repository* rather than the *fork repository*, while also being
typically triggerable by the latter. This can lead to attacker controlled
code execution or unexpected action runs with context controlled by a malicious
fork.
### Other resources
* <https://securitylab.github.com/resources/github-actions-preventing-pwn-requests/>
## `excessive-permissions`
| Type | Examples | Introduced in |
| ---- | -------- | ------------- |
| Workflow | [excessive-permissions.yml] | v0.1.0 |
[excessive-permissions.yml]: https://github.com/woodruffw/gha-hazmat/blob/main/.github/workflows/excessive-permissions.yml
### What
Looks for excessive permissions in workflows, both at
the workflow level and individual job levels.
### Why
Users frequently over-scope their workflow and job permissions,
or set broad workflow-level permissions without realizing that
all jobs inherit those permissions.
## `hardcoded-container-credentials`
| Type | Examples | Introduced in |
| ---- | -------- | ------------- |
| Workflow | [hardcoded-credentials.yml] | v0.1.0 |
[hardcoded-credentials.yml]: https://github.com/woodruffw/gha-hazmat/blob/main/.github/workflows/hardcoded-credentials.yml
### What
GitHub Actions allows Docker credentials (usernames and passwords)
to be hardcoded in various places within workflows.
### Why
Hardcoding credentials is bad.
## `impostor-commit`
| Type | Examples | Introduced in |
| ---- | -------- | ------------- |
| Workflow | [impostor-commit.yml] | v0.1.0 |
[impostor-commit.yml]: https://github.com/woodruffw/gha-hazmat/blob/main/.github/workflows/impostor-commit.yml
### What
GitHub represents a repository and its forks as a "network" of commits.
This results in ambiguity about where a commit comes from: a commit
that exists only in a fork can be referenced via its parent's
`owner/repo` slug, and vice versa.
### Why
GitHub's network-of-forks design can be used to obscure a commit's true origin
in a fully-pinned `uses:` workflow reference. This can be used by an attacker
to surreptitiously introduce a backdoored action into a victim's workflows(s).
### Other resources
* <https://www.chainguard.dev/unchained/what-the-fork-imposter-commits-in-github-actions-and-ci-cd>
## `known-vulnerable-actions`
| Type | Examples | Introduced in |
| ---- | -------- | ------------- |
| Workflow | [known-vulnerable-actions.yml] | v0.1.0 |
[known-vulnerable-actions.yml]: https://github.com/woodruffw/gha-hazmat/blob/main/.github/workflows/known-vulnerable-actions.yml
### What
Actions with known, publicly disclosed vulnerabilities are tracked in the
[GitHub Advisories database]. Examples of commonly disclosed vulnerabilities
in GitHub Actions include [credential disclosure] and code injection
via [template injection].
### Why
You shouldn't use actions with known vulnerabilities.
[GitHub Advisories database]: https://github.com/advisories
[credential disclosure]: #artipacked
[template injection]: #template-injection
## `ref-confusion`
| Type | Examples | Introduced in |
| ---- | -------- | ------------- |
| Workflow | [ref-confusion.yml] | v0.1.0 |
[ref-confusion.yml]: https://github.com/woodruffw/gha-hazmat/blob/main/.github/workflows/ref-confusion.yml
### What
Like with [impostor commits], actions that are used with a symbolic ref
in their `uses:` are subject to a degree of ambiguity: a ref like
`@v1` might refer to either a branch or tag ref.
### Why
An attacker can exploit this ambiguity to publish a branch or tag ref that
takes precedence over a legitimate one, delivering a malicious action to
pre-existing consumers of that action without having to modify those consumers.
[impostor commits]: #impostor-commit
## `self-hosted-runner`
| Type | Examples | Introduced in |
| ---- | -------- | ------------- |
| Workflow | [self-hosted.yml] | v0.1.0 |
[self-hosted.yml]: https://github.com/woodruffw/gha-hazmat/blob/main/.github/workflows/self-hosted.yml
### What
GitHub supports self-hosted runners, which behave similarly to GitHub-hosted
runners but use client-managed compute resources.
### Why
Self-hosted runners are very hard to secure by default, which is why
GitHub does not recommend their use in public repositories.
### Other resources
* <https://docs.github.com/en/actions/hosting-your-own-runners/managing-self-hosted-runners/about-self-hosted-runners#self-hosted-runner-security>
## `template-injection`
| Type | Examples | Introduced in |
| ---- | -------- | ------------- |
| Workflow | [template-injection.yml] | v0.1.0 |
[template-injection.yml]: https://github.com/woodruffw/gha-hazmat/blob/main/.github/workflows/template-injection.yml
### What
GitHub Actions allows workflows to define *template expansions*, which
occur within special `${{ ... }}` delimiters. These expansions happen
before workflow and job execution, meaning the expansion
of a given expression appears verbatim in whatever context it was performed in.
### Why
Template expansions aren't syntax-aware, meaning that they can result in
unintended shell injection vectors. This is especially true when they're
used with attacker-controllable expression contexts, such as
`github.event.issue.title` (which the attacker can fully control by supplying
a new issue title).
### Other resources
* <https://securitylab.github.com/resources/github-actions-untrusted-input/>
## `use-trusted-publishing`
| Type | Examples | Introduced in |
| ---- | -------- | ------------- |
| Workflow | [pypi-manual-credential.yml] | v0.1.0 |
[pypi-manual-credential.yml]: https://github.com/woodruffw/gha-hazmat/blob/main/.github/workflows/pypi-manual-credential.yml
### What
Some packaging ecosystems/indices (like PyPI and RubyGems) support
"Trusted Publishing," which is an OIDC-based "tokenless" authentication
mechanism for uploading to the index from within a CI/CD workflow.
### Why
This "tokenless" flow has significant security benefits over a traditional
manually configured API token, and should be preferred wherever supported
and possible.
### Other resources
* <https://docs.pypi.org/trusted-publishers/>
* <https://guides.rubygems.org/trusted-publishing/>
* <https://blog.trailofbits.com/2023/05/23/trusted-publishing-a-new-benchmark-for-packaging-security/>

118
docs/development.md Normal file
View file

@ -0,0 +1,118 @@
# Hacking on `zizmor`
!!! important
This page contains information on specific development processes.
For more general information on *how and what* to contribute to `zizmor`,
see our [CONTRIBUTING.md].
[CONTRIBUTING.md]: https://github.com/woodruffw/zizmor/blob/main/CONTRIBUTING.md
## General development practices
Here are some guidelines to follow if you're working on `zizmor`:
* *Document internal APIs*. `zizmor` doesn't have a public Rust API (yet),
but the internal APIs should be documented *as if* they might become public
one day. Plus, well-documented internals make life easier for new
contributors.
* *Write unit tests*. It's easy for small changes in `zizmor`'s internals to
percolate into large bugs (e.g. incorrect location information); help us
catch these bugs earlier by testing your changes at the smallest unit of
behavior.
* *Test on real inputs*. If you're contributing to or adding a new audit,
make sure your analysis is reliable and accurate on non-sample inputs.
## Requirements
`zizmor`'s only development requirement the Rust compiler.
You can install Rust by following the steps on [Rust's official website].
[Rust's official website]: https://www.rust-lang.org/tools/install
## Building `zizmor` locally
`zizmor` is a pure Rust codebase, and can be built with a single `cargo build`:
```bash
git clone https://github.com/woodruffw/zizmor && cd zizmor
cargo build
# cargo run -- --help also works
./target/debug/zizmor --help
```
Similarly, you can build the developer-only documentation with
`cargo doc`:
```bash
# build only
cargo doc
# build and open in the local browser
cargo doc --open
```
### Linting
`zizmor` is linted with `cargo clippy` and auto-formatted with `cargo fmt`.
Our CI enforces both, but you should also run them locally to minimize
unnecessary review cycles:
```bash
cargo fmt
cargo clippy --fix
```
### Testing
`zizmor` uses `cargo test`:
```bash
cargo test
```
## Building the website
`zizmor`'s website is built with [MkDocs](https://www.mkdocs.org/), which
means you'll need a Python runtime to develop against it locally.
The easiest way to do this is to use [`uv`](https://github.com/astral-sh/uv),
which is what `zizmor`'s own CI uses. See
[the `uv` docs](https://docs.astral.sh/uv/getting-started/installation/) for
installation instructions.
Once you have `uv`, run `make site` in the repo root to build a local
copy of `zizmor`'s website in the `site_html` directory:
```bash
make site
```
Alternatively, for live development, you can run `make site-live`
to run a development server that'll monitor for changes to the docs:
```bash
make site-live
```
With `make site-live`, you should see something roughly like this:
```console
INFO - Building documentation...
INFO - Cleaning site directory
INFO - Documentation built in 0.40 seconds
INFO - [22:18:39] Watching paths for changes: 'docs', 'mkdocs.yml'
INFO - [22:18:39] Serving on http://127.0.0.1:9999/zizmor/
INFO - [22:18:40] Browser connected: http://127.0.0.1:9999/zizmor/development/
```
Visit the listed URL to see your live changes.
## Adding or modifying an audit
These docs could use help.
For now, please run `cargo doc --open` and refer to our internal
documentation!

22
docs/index.md Normal file
View file

@ -0,0 +1,22 @@
# Welcome to `zizmor`'s documentation!
[![CI](https://github.com/woodruffw/zizmor/actions/workflows/ci.yml/badge.svg)](https://github.com/woodruffw/zizmor/actions/workflows/ci.yml)
[![Crates.io](https://img.shields.io/crates/v/zizmor)](https://crates.io/crates/zizmor)
!!! warning
`zizmor` is currently in beta. You will encounter bugs; [please file them]!
[please file them]: https://github.com/woodruffw/zizmor/issues/new
:rainbow: Hello, and welcome to `zizmor`'s documentation! :rainbow:
`zizmor` is a tool for finding security issues in GitHub Actions setups.
Go right to our [Installation Steps](./installation.md), and then to
[Quickstart](./quickstart.md) or [Usage Recipes](./usage.md) to
learn more about how to use `zizmor` locally or in your CI/CD.
<figure markdown="1">
![](./assets/zizmor-demo.gif)
</figure>

36
docs/installation.md Normal file
View file

@ -0,0 +1,36 @@
# Installation
!!! info
Are you interested in packaging `zizmor` for another ecosystem!
Let us know by [filing an issue](https://github.com/woodruffw/zizmor/issues/new)!
## From crates.io
You can install `zizmor` from <https://crates.io> with `cargo`:
```bash
cargo install zizmor
```
## From Homebrew
`zizmor` is provided by [Homebrew](https://brew.sh/) as well:
```bash
brew install zizmor
```
## From source
!!! warning
Most ordinary users **should not** install directly from `zizmor`'s
source repository. No stability or correctness guarantees are made about
direct source installations.
You can install the latest unstable `zizmor` directly from GitHub with `cargo`:
```bash
cargo install --git https://github.com/woodruffw/zizmor
```

27
docs/quickstart.md Normal file
View file

@ -0,0 +1,27 @@
# Quickstart
You can run `zizmor` on any file(s) you have locally:
```bash
# audit a specific workflow
zizmor my-workflow.yml
# discovers .github/workflows/*.yml automatically
zizmor path/to/repo
```
By default, `zizmor` will emit a Rust-style human-friendly findings, e.g.:
```console
error[pull-request-target]: use of fundamentally insecure workflow trigger
--> /home/william/devel/gha-hazmat/.github/workflows/pull-request-target.yml:20:1
|
20 | / on:
21 | | # NOT OK: pull_request_target should almost never be used
22 | | pull_request_target:
| |______________________^ triggers include pull_request_target, which is almost always used insecurely
|
1 findings (0 unknown, 0 informational, 0 low, 0 medium, 1 high)
```
See [Usage](./usage.md) for more examples, including examples of configuration.

64
docs/usage.md Normal file
View file

@ -0,0 +1,64 @@
# Usage Recipes
## Online and offline use
Some of `zizmor`'s audits require access to GitHub's API. `zizmor` will perform
online audits by default *if* the user has a `GH_TOKEN` specified
in their environment. If no `GH_TOKEN` is present, then `zizmor` will operate
in offline mode by default.
Both of these can be made explicit through their respective command-line flags:
```bash
# force offline, even if a GH_TOKEN is present
zizmor --offline workflow.yml
# passing a token explicitly will forcefully enable online mode
zizmor --gh-token ghp-... workflow.yml
```
## Output formats
`zizmor` always produces output on `stdout`. If a terminal is detected,
`zizmor` will default to a human-readable diagnostic output; if no terminal
is detected, `zizmor` will emit JSON.
Output formats can be controlled explicitly via the `--format` option:
```bash
# force diagnostic output, even if not a terminal
zizmor --format plain
# emit zizmor's own JSON format
zizmor --format json
# emit SARIF JSON instead of normal JSON
zizmor --format sarif
```
See [Integration](#integration) for suggestions on when to use each format.
## Integration
### Use in GitHub Actions
`zizmor` is trivial to use within GitHub Actions; you can run it just like
you would locally.
`zizmor --format sarif` specifies [SARIF] as the output format, which GitHub's
code scanning feature also supports.
See [GitHub's documentation] for advice on how to integrate `zizmor`'s results
directly into a repository's scanning setup.
For a specific example, see `zizmor`'s own [repository workflow scan].
GitHub's example of [running ESLint] as a security workflow provides additional
relevant links.
[SARIF]: https://sarifweb.azurewebsites.net/
[GitHub's documentation]: https://docs.github.com/en/code-security/code-scanning/integrating-with-code-scanning/uploading-a-sarif-file-to-github
[repository workflow scan]: https://github.com/woodruffw/zizmor/blob/main/.github/workflows/zizmor.yml
[running ESLint]: https://docs.github.com/en/code-security/code-scanning/integrating-with-code-scanning/uploading-a-sarif-file-to-github#example-workflow-that-runs-the-eslint-analysis-tool

42
mkdocs.yml Normal file
View file

@ -0,0 +1,42 @@
site_name: "🌈 zizmor"
# site_description: zizmor
site_url: https://woodruffw.github.io/zizmor
docs_dir: docs
site_dir: site_html
dev_addr: "127.0.0.1:9999"
nav:
- Welcome: "index.md"
- "installation.md"
- "quickstart.md"
- "usage.md"
- "audits.md"
- "development.md"
- External links:
- "GitHub 🔗": https://github.com/woodruffw/zizmor
- "crates.io 🔗": https://crates.io/crates/zizmor
theme:
name: material
palette:
scheme: slate
features:
- navigation.expand
- navigation.sections
- navigation.tracking
markdown_extensions:
# Makes sure we render `<https://...>`-style links correctly.
- pymdownx.magiclink
- pymdownx.emoji
- admonition
- pymdownx.details
- pymdownx.superfences
- md_in_html
- toc:
permalink: 🔗
validation:
omitted_files: warn
absolute_links: warn
unrecognized_links: warn

2
site-requirements.txt Normal file
View file

@ -0,0 +1,2 @@
mkdocs ~= 1.6
mkdocs-material ~= 9.5