Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(zizmor): add a reusable workflow for zizmor GitHub Actions static analysis #605

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion .github/workflows/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,10 @@

This folder contains some workflows that can be re-used from other repositories:

- [publish-techdocs](./publish-techdocs.md): Publish your project's documentation to EngHub
- [`publish-techdocs`](./publish-techdocs.md): Publish your project's
documentation to EngHub

- [`reusable-zizmor`](./reusable-zizmor.md): Run [zizmor] static analysis on
your GitHub Actions workflow files.

[zizmor]: https://woodruffw.github.io/zizmor/
86 changes: 86 additions & 0 deletions .github/workflows/reusable-zizmor.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# Reusable workflow: zizmor

This is a [reusable workflow] which runs the [`zizmor`][zizmor] static analysis
tool on a repo's GitHub Actions workflow files. This will report things such as
whether there is potential for untrusted code to be injected via a template. See
a full list of checks in [the documentation][zizmor-checks].

This workflow will run zizmor, upload results to GitHub's code scanning service
(requires an Advanced Security subscription for private repositories), and
comment on the pull request with the results. The comment will be re-posted on
each run - and previous comments hidden - so the most recent comment will always
show the current results.

[reusable workflow]: https://docs.github.com/en/actions/using-workflows/reusing-workflows
[zizmor]: https://woodruffw.github.io/zizmor/
[zizmor-checks]: https://woodruffw.github.io/zizmor/audits/

```yaml
name: Zizmor GitHub Actions static analysis
on:
pull_request:

push:
branches:
- main

jobs:
scorecard:
name: Analyse

permissions:
actions: read
contents: read

# required to comment on pull requests with the results of the check
pull-requests: write
# required to upload the results to GitHub's code scanning service
security-events: write

uses: grafana/shared-workflows/.github/workflows/reusable-zizmor.yml@<some sha>
with:
# example: fail if there are any findings
fail-severity: any
```

## Inputs

| Name | Type | Description | Default Value | Required |
| -------------- | ------ | ------------------------------------------------------------------------------------------------------------------------- | ------------- | -------- |
| min-severity | string | Only show results at or above this severity [possible values: unknown, informational, low, medium, high] | medium | false |
| min-confidence | string | Only show results at or above this confidence level [possible values: unknown, low, medium, high] | low | false |
| fail-severity | string | Fail the build if any result is at or above this severity [possible values: never, any, informational, low, medium, high] | high | false |
| runs-on | string | The runner to use for jobs. Configure this to use self-hosted runners. | ubuntu-latest | false |

## Getting started

This workflow uses quite strict settings by default. It isn't always practical
to introduce this workflow and fix all of the issues at once. There are a few
ways to get started if this is the case:

1. Set `fail-severity: never` to run the check without failing the build.
Results will still be posted to pull requests but they won't be blocking.
2. Adopt an incremental approach to fixing issues. For example, start with
`min-severity: high`. Once all high severity issues are resolved, lower the
severity to `medium` and then onwards to `low`.

After the initial setup, we recommend running with the default settings.

## Ignore findings

Findings can be ignored by [adding a comment to the line with the finding][zizmor-ignore-comment].

```yaml
uses: actions/checkout@v3 # zizmor: ignore[artipacked]
```

[zizmor-ignore-comment]: https://woodruffw.github.io/zizmor/usage/#with-comments

## Configuration

zizmor [can be configured][zizmor-config] with a `zizmor.yml` or
`.github/zizmor.yml` file in the repository. With this, [findings or entire
files can be ignored][zizmor-ignore-config].

[zizmor-config]: https://woodruffw.github.io/zizmor/configuration/
[zizmor-ignore-config]: https://woodruffw.github.io/zizmor/usage/#with-zizmoryml
186 changes: 186 additions & 0 deletions .github/workflows/reusable-zizmor.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
name: zizmor (reusable)

on:
workflow_call:
inputs:
min-severity:
description: "Only show results at or above this severity [possible values: unknown, informational, low, medium, high]"
required: false
type: string
default: "low"

min-confidence:
description: "Only show results at or above this confidence level [possible values: unknown, low, medium, high]"
required: false
type: string
default: "low"

fail-severity:
description: "Fail the build if any result is at or above this severity [possible values: never, any, informational, low, medium, high]"
required: false
type: string
default: "high"

runs-on:
description: "The runner to use for jobs"
required: false
type: string
default: "ubuntu-latest"

permissions: {}

jobs:
analysis:
name: Generate and upload zizmor results 🌈

runs-on: ${{ inputs.runs-on }}

permissions:
actions: read
contents: read

# comment with the results
pull-requests: write
# upload the results to code-scanning dashboard.
security-events: write

env:
MIN_SEVERITY: ${{ inputs.min-severity }}
MIN_CONFIDENCE: ${{ inputs.min-confidence }}

steps:
- name: Checkout code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
persist-credentials: false

- name: Setup Rust
uses: actions-rust-lang/setup-rust-toolchain@11df97af8e8102fd60b60a77dfbf58d40cd843b8 # v1.10.1
with:
cache-on-failure: true

- name: Get zizmor
Fixed Show fixed Hide fixed
shell: sh
# This is a commit with the `unpinned-uses` action available, which is something we want.
env:
ZIZMOR_COMMIT: fc5683c0f457f5766c3f175fad705dc8b0515bd7
run: >-
RUSTFLAGS=-Awarnings
cargo
install
--git https://github.com/woodruffw/zizmor
--rev "${ZIZMOR_COMMIT}"
zizmor

- name: Run zizmor
Fixed Show fixed Hide fixed
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
shell: sh
run: >-
zizmor
--format sarif
--min-severity "${MIN_SEVERITY}"
--min-confidence "${MIN_CONFIDENCE}"
${RUNNER_DEBUG:+"--verbose"}
.
> results.sarif

- name: Upload artifact
uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3
with:
name: SARIF file
path: results.sarif
retention-days: 5

- name: Upload to code-scanning
uses: github/codeql-action/upload-sarif@f09c1c0a94de965c15400f5634aa42fac8fb8f88 # v3.27.5
with:
sarif_file: results.sarif
category: zizmor

- name: Run zizmor with plain output
Fixed Show fixed Hide fixed
id: zizmor-plain
shell: bash
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
set -o pipefail

echo "zizmor-results<<EOF" >> "${GITHUB_OUTPUT}"
# don't fail the build if zizmor fails - we want to capture the output
# and the exit code
set +e
zizmor \
--format plain \
--min-severity "${MIN_SEVERITY}" \
--min-confidence "${MIN_CONFIDENCE}" \
${RUNNER_DEBUG:+"--verbose"} \
. \
| tee -a "${GITHUB_OUTPUT}"
zizmor_exit_code=$?
set -e
echo "EOF" >> "${GITHUB_OUTPUT}"

# Error 1 is a failure of zizmor itself
if [ "${zizmor_exit_code}" -eq 1 ]; then
echo "zizmor itself failed - check the above output. failing the workflow."
exit 1
fi

echo "zizmor-exit-code=${zizmor_exit_code}" | tee -a "${GITHUB_OUTPUT}"

- name: Hide any previous comments
id: hide-comments
uses: int128/hide-comment-action@dafbbede100206f5401d06fa852a1c6997984cb3 # v1.37.0
with:
ends-with: "<!-- comment-action/${{ github.workflow }}/${{ github.job }} -->"

- name: Comment with zizmor results
if: steps.zizmor-plain.outputs.zizmor-exit-code != 0
uses: int128/comment-action@a20dbdebd79ab886a1e7a20d16bfa7dbaa732e5a # v1.33.0
with:
post: |
:cry: zizmor failed with exit code ${{ steps.zizmor-plain.outputs.zizmor-exit-code }}.

<details>
<summary>Expand for full output</summary>

```
${{ steps.zizmor-plain.outputs.zizmor-results }}
```
</details>
${{ steps.hide-comments.outputs.ends-with }}

- name: Fail the build
if: inputs.fail-severity != 'never' && steps.zizmor-plain.outputs.zizmor-exit-code != 0
shell: sh
env:
FAIL_LEVEL: ${{ inputs.fail-severity }}
EXIT_CODE: ${{ steps.zizmor-plain.outputs.zizmor-exit-code }}
run: |
case "${FAIL_LEVEL}" in
any)
FAIL_EXIT_CODE=10
;;
informational)
FAIL_EXIT_CODE=11
;;
low)
FAIL_EXIT_CODE=12
;;
medium)
FAIL_EXIT_CODE=13
;;
high)
FAIL_EXIT_CODE=14
;;
*)
echo "Unknown fail level: ${FAIL_LEVEL}"
exit 1
;;
esac

if [ "${EXIT_CODE}" -ge "${FAIL_EXIT_CODE}" ]; then
echo "Failing the build due to findings at or above ${FAIL_LEVEL} severity."
exit 1
fi
26 changes: 26 additions & 0 deletions .github/workflows/self-zizmor.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
name: zizmor GitHub Actions static analysis
on:
push:
branches:
- main

pull_request:
paths:
- .github/workflows/reusable-zizmor.yml
- .github/workflows/self-zizmor.yml

jobs:
zizmor:
name: Generate

permissions:
actions: read
contents: read

pull-requests: write
security-events: write

uses: ./.github/workflows/reusable-zizmor.yml
with:
# Don't fail the build while we are working on fixing the results.
fail-severity: never
6 changes: 6 additions & 0 deletions .markdownlint.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"$schema": "https://raw.githubusercontent.com/DavidAnson/markdownlint/v0.36.1/schema/markdownlint-config-schema.json",
"line-length": {
"tables": false
}
}
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
# shared-workflows

[![OpenSSF Scorecard][scorecard image]][scorecard]

A public-facing, centralized place to store reusable GitHub workflows and action
used by Grafana Labs. See the `actions/` directory for the individual actions
themselves.

[scorecard]: https://scorecard.dev/viewer/?uri=github.com/grafana/shared-workflows
[scorecard image]: https://api.scorecard.dev/projects/github.com/grafana/shared-workflows/badge

## Notes

### Configure your IDE to run Prettier
Expand Down
Loading