diff --git a/.github/workflows/codeql-self-scan.yml b/.github/workflows/codeql-self-scan.yml index 03dc5d2..3929460 100644 --- a/.github/workflows/codeql-self-scan.yml +++ b/.github/workflows/codeql-self-scan.yml @@ -16,6 +16,6 @@ jobs: actions: read contents: read security-events: write - uses: ./.github/workflows/codeql.yml + uses: $/.github/workflows/codeql.yml with: languages: '["actions"]' diff --git a/.github/workflows/zizmor-self-scan.yml b/.github/workflows/zizmor-self-scan.yml new file mode 100644 index 0000000..23a98d9 --- /dev/null +++ b/.github/workflows/zizmor-self-scan.yml @@ -0,0 +1,17 @@ +name: GitHub Actions Security Analysis (self-scan) + +on: + push: + branches: [main] + pull_request: + branches: ["**"] + +permissions: {} + +jobs: + zizmor: + permissions: + actions: read + contents: read + security-events: write + uses: $/.github/workflows/zizmor.yml diff --git a/.github/workflows/zizmor.yml b/.github/workflows/zizmor.yml index 8735b5c..52aba5d 100644 --- a/.github/workflows/zizmor.yml +++ b/.github/workflows/zizmor.yml @@ -1,23 +1,29 @@ name: GitHub Actions Security Analysis on: - push: - branches: [main] - pull_request: - branches: ["**"] - -permissions: {} + workflow_call: + inputs: + advanced-security: + description: >- + true uploads the results to the repository's Security tab. false reports them as + annotations and fails the job on any finding, which is what a required check needs, + since zizmor exits 0 when it writes SARIF. + required: false + type: boolean + default: true jobs: + # No permissions block, so the job gets the caller's. Callers should grant contents: read, plus + # security-events: write (and actions: read in a private repo) when advanced-security is true. zizmor: + name: zizmor runs-on: ubuntu-latest - permissions: - security-events: write - contents: read - actions: read steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: false - name: Run zizmor - uses: zizmorcore/zizmor-action@3dc1ecc9bcb9e94e9b2c709687979e1298497054 # v0.6.2 + uses: zizmorcore/zizmor-action@cc914d7f3750a2d13d75c7f184a1060aa0e9d482 # v0.6.4 + with: + advanced-security: ${{ inputs.advanced-security }} + annotations: ${{ !inputs.advanced-security }} diff --git a/README.md b/README.md index 5aee035..14f66bb 100644 --- a/README.md +++ b/README.md @@ -14,12 +14,15 @@ These workflows are called from individual gem repos via `uses: rubyatscale/shar | **CD** (`cd.yml`) | Publishes the gem to RubyGems and creates a GitHub Release on successful main builds. | | **Stale** (`stale.yml`) | Marks issues and PRs as stale after 180 days of inactivity, then closes them after 7 more days. | | **Triage** (`triage.yml`) | Labels new issues with `triage`. | +| **CodeQL** (`codeql.yml`) | Runs [CodeQL](https://codeql.github.com) analysis for the given languages and uploads the results to the Security tab. | +| **zizmor** (`zizmor.yml`) | Runs the [zizmor](https://github.com/zizmorcore/zizmor) security linter against the calling repo's workflows, actions, and Dependabot config. | ### Repository workflows | Workflow | Description | |----------|-------------| -| **zizmor** (`zizmor.yml`) | Runs the [zizmor](https://github.com/zizmorcore/zizmor) security linter against all workflow files on every push and PR. | +| **CodeQL self-scan** (`codeql-self-scan.yml`) | Runs `codeql.yml` against this repo's workflows on pushes and PRs to main, and weekly. | +| **zizmor self-scan** (`zizmor-self-scan.yml`) | Runs `zizmor.yml` against this repo on every push and PR. | ## Usage @@ -46,6 +49,71 @@ jobs: | `test-command` | `bundle exec rspec` | Command to run tests | | `linter-command` | `bundle exec rubocop` | Command to run the linter | +### CodeQL + +The job requests `actions: read`, `contents: read` and `security-events: write`, so the calling job must grant all three. + +```yaml +# .github/workflows/codeql.yml +name: CodeQL + +on: + push: + branches: [main] + pull_request: + branches: [main] + schedule: + - cron: '30 1 * * 0' + +permissions: {} + +jobs: + analyze: + permissions: + actions: read + contents: read + security-events: write + uses: rubyatscale/shared-config/.github/workflows/codeql.yml@main # zizmor: ignore[unpinned-uses] internal reusable workflow tracked at @main by convention + with: + languages: '["actions","ruby"]' +``` + +| Input | Default | Description | +|-------|---------|-------------| +| `languages` | (required) | JSON array of [CodeQL languages](https://codeql.github.com/docs/codeql-overview/supported-languages-and-frameworks/) to analyze, e.g. `'["actions","ruby"]'` | + +### zizmor + +By default the results go to the repository's Security tab, and the job passes whatever zizmor finds. To make zizmor a required check, set `advanced-security: false`: findings are then reported as annotations and fail the job. The check is named ` / zizmor`, so require `zizmor / zizmor` with the example below. The job takes its permissions from the caller. + +```yaml +# .github/workflows/zizmor.yml +name: zizmor + +on: + push: + branches: [main] + pull_request: + +permissions: {} + +jobs: + zizmor: + permissions: + contents: read + uses: rubyatscale/shared-config/.github/workflows/zizmor.yml@main # zizmor: ignore[unpinned-uses] internal reusable workflow tracked at @main by convention + with: + advanced-security: false +``` + +With the default `advanced-security: true`, grant `security-events: write` as well, plus `actions: read` in a private repo. + +Callers track `@main`, so when this repo upgrades zizmor-action, new audits can start failing the check in every caller at once. + +| Input | Default | Description | +|-------|---------|-------------| +| `advanced-security` | `true` | Upload results to the Security tab (`true`), or annotate and fail on findings (`false`) | + ### Required secrets The **CD** workflow requires the following secrets in the calling repo: