├── .cargo └── config.toml ├── .github ├── ISSUE_TEMPLATE │ ├── bug-report.yml │ ├── config.yml │ └── feature-request.yml ├── dependabot.yml ├── pinact.yml └── workflows │ ├── ci.yml │ ├── codegen.yml │ ├── release-binaries.yml │ ├── release-docker.yml │ ├── release-pypi.yml │ ├── release-support-crate.yml │ ├── release-zizmor-crate.yml │ ├── site.yml │ ├── test-output.yml │ ├── wolfi-update-check.yml │ └── zizmor.yml ├── .gitignore ├── CONTRIBUTING.md ├── Cargo.lock ├── Cargo.toml ├── Dockerfile ├── LICENSE ├── Makefile ├── README.md ├── crates ├── README.md ├── github-actions-expressions │ ├── Cargo.toml │ ├── README.md │ └── src │ │ ├── context.rs │ │ ├── expr.pest │ │ └── lib.rs ├── github-actions-models │ ├── Cargo.toml │ ├── LICENSE │ ├── README.md │ ├── src │ │ ├── action.rs │ │ ├── common.rs │ │ ├── common │ │ │ └── expr.rs │ │ ├── dependabot │ │ │ ├── mod.rs │ │ │ └── v2.rs │ │ ├── lib.rs │ │ └── workflow │ │ │ ├── event.rs │ │ │ ├── job.rs │ │ │ └── mod.rs │ └── tests │ │ ├── sample-actions │ │ ├── gh-action-pip-audit.yml │ │ ├── gh-action-pypi-publish.yml │ │ ├── gh-action-sigstore-python.yml │ │ ├── no-input-output-descriptions.yml │ │ └── setup-python.yml │ │ ├── sample-dependabot │ │ └── v2 │ │ │ ├── pip-audit.yml │ │ │ └── sigstore-python.yml │ │ ├── sample-workflows │ │ ├── adafruit-circuitpython-run-tests.yml │ │ ├── false-condition.yml │ │ ├── gh-action-sigstore-python-selftest.yml │ │ ├── git-annex-built-windows.yaml │ │ ├── guacsec-guac-ci.yml │ │ ├── homebrew-core-automerge-triggers.yml │ │ ├── homebrew-core-dispatch-rebottle.yml │ │ ├── intel-llvm-sycl-linux-run-tests.yml │ │ ├── issue-35.yml │ │ ├── jazzband-tablib-docs-lint.yml │ │ ├── letsencrypt-boulder-boulder-ci.yml │ │ ├── mhils-workflows-python-deploy.yml │ │ ├── openbao-openbao-test-go.yml │ │ ├── pip-api-test.yml │ │ ├── pip-audit-ci.yml │ │ ├── pip-audit-scorecards.yml │ │ ├── pwn-requests.yml │ │ ├── pyca-cryptography-ci.yml │ │ ├── pypi-attestations-release.yml │ │ ├── reusable-workflow-unpinned.yml │ │ ├── rnpgp-rnp-centos-and-fedora.yml │ │ ├── runs-on-expr.yml │ │ ├── runs-on-group-only.yml │ │ ├── scalar-trigger-type.yml │ │ ├── vil02-puzzle_generator-check_examples.yml │ │ ├── zizmor-issue-646.yml │ │ └── zizmor-issue-650.yml │ │ ├── test_action.rs │ │ ├── test_dependabot_v2.rs │ │ └── test_workflow.rs ├── yamlpath │ ├── Cargo.toml │ ├── LICENSE │ ├── README.md │ ├── src │ │ └── lib.rs │ └── tests │ │ ├── integration_test.rs │ │ └── testcases │ │ ├── basic.yml │ │ ├── comments.yml │ │ ├── directives.yml │ │ ├── flow.yml │ │ ├── interceding-comment.yml │ │ └── quoted-key.yml └── zizmor │ ├── Cargo.toml │ ├── build.rs │ ├── data │ ├── codeql-injection-sinks.json │ └── context-capabilities.csv │ ├── src │ ├── audit │ │ ├── artipacked.rs │ │ ├── bot_conditions.rs │ │ ├── cache_poisoning.rs │ │ ├── dangerous_triggers.rs │ │ ├── excessive_permissions.rs │ │ ├── forbidden_uses.rs │ │ ├── github_env.rs │ │ ├── hardcoded_container_credentials.rs │ │ ├── impostor_commit.rs │ │ ├── insecure_commands.rs │ │ ├── known_vulnerable_actions.rs │ │ ├── mod.rs │ │ ├── obfuscation.rs │ │ ├── overprovisioned_secrets.rs │ │ ├── ref_confusion.rs │ │ ├── secrets_inherit.rs │ │ ├── self_hosted_runner.rs │ │ ├── stale_action_refs.rs │ │ ├── template_injection.rs │ │ ├── unpinned_images.rs │ │ ├── unpinned_uses.rs │ │ ├── unredacted_secrets.rs │ │ ├── unsound_contains.rs │ │ └── use_trusted_publishing.rs │ ├── config.rs │ ├── data │ │ ├── github-action.json │ │ └── github-workflow.json │ ├── finding │ │ └── mod.rs │ ├── fix.rs │ ├── github_api.rs │ ├── main.rs │ ├── models.rs │ ├── models │ │ ├── coordinate.rs │ │ └── uses.rs │ ├── output │ │ ├── github.rs │ │ ├── mod.rs │ │ ├── plain.rs │ │ └── sarif.rs │ ├── registry.rs │ ├── state.rs │ ├── utils.rs │ └── yaml_patch │ │ └── mod.rs │ └── tests │ └── integration │ ├── acceptance.rs │ ├── common.rs │ ├── e2e.rs │ ├── main.rs │ ├── snapshot.rs │ ├── snapshots │ ├── integration__e2e__gha_hazmat.snap │ ├── integration__e2e__invalid_config_file.snap │ ├── integration__e2e__invalid_inputs-10.snap │ ├── integration__e2e__invalid_inputs-2.snap │ ├── integration__e2e__invalid_inputs-3.snap │ ├── integration__e2e__invalid_inputs-4.snap │ ├── integration__e2e__invalid_inputs-5.snap │ ├── integration__e2e__invalid_inputs-6.snap │ ├── integration__e2e__invalid_inputs-7.snap │ ├── integration__e2e__invalid_inputs-8.snap │ ├── integration__e2e__invalid_inputs-9.snap │ ├── integration__e2e__invalid_inputs.snap │ ├── integration__e2e__issue_569.snap │ ├── integration__e2e__issue_612_repro.snap │ ├── integration__e2e__issue_726.snap │ ├── integration__e2e__menagerie-2.snap │ ├── integration__e2e__menagerie.snap │ ├── integration__snapshot__artipacked-2.snap │ ├── integration__snapshot__artipacked-3.snap │ ├── integration__snapshot__artipacked-4.snap │ ├── integration__snapshot__artipacked.snap │ ├── integration__snapshot__bot_conditions.snap │ ├── integration__snapshot__cache_poisoning-10.snap │ ├── integration__snapshot__cache_poisoning-11.snap │ ├── integration__snapshot__cache_poisoning-12.snap │ ├── integration__snapshot__cache_poisoning-13.snap │ ├── integration__snapshot__cache_poisoning-14.snap │ ├── integration__snapshot__cache_poisoning-15.snap │ ├── integration__snapshot__cache_poisoning-2.snap │ ├── integration__snapshot__cache_poisoning-3.snap │ ├── integration__snapshot__cache_poisoning-4.snap │ ├── integration__snapshot__cache_poisoning-5.snap │ ├── integration__snapshot__cache_poisoning-6.snap │ ├── integration__snapshot__cache_poisoning-7.snap │ ├── integration__snapshot__cache_poisoning-8.snap │ ├── integration__snapshot__cache_poisoning-9.snap │ ├── integration__snapshot__cache_poisoning.snap │ ├── integration__snapshot__cant_retrieve.snap │ ├── integration__snapshot__excessive_permissions-10.snap │ ├── integration__snapshot__excessive_permissions-11.snap │ ├── integration__snapshot__excessive_permissions-12.snap │ ├── integration__snapshot__excessive_permissions-2.snap │ ├── integration__snapshot__excessive_permissions-3.snap │ ├── integration__snapshot__excessive_permissions-4.snap │ ├── integration__snapshot__excessive_permissions-5.snap │ ├── integration__snapshot__excessive_permissions-6.snap │ ├── integration__snapshot__excessive_permissions-7.snap │ ├── integration__snapshot__excessive_permissions-8.snap │ ├── integration__snapshot__excessive_permissions-9.snap │ ├── integration__snapshot__excessive_permissions.snap │ ├── integration__snapshot__forbidden_uses-2.snap │ ├── integration__snapshot__forbidden_uses-3.snap │ ├── integration__snapshot__forbidden_uses-4.snap │ ├── integration__snapshot__forbidden_uses-5.snap │ ├── integration__snapshot__forbidden_uses-6.snap │ ├── integration__snapshot__forbidden_uses.snap │ ├── integration__snapshot__github_env-2.snap │ ├── integration__snapshot__github_env-3.snap │ ├── integration__snapshot__github_env.snap │ ├── integration__snapshot__github_output.snap │ ├── integration__snapshot__insecure_commands-2.snap │ ├── integration__snapshot__insecure_commands-3.snap │ ├── integration__snapshot__insecure_commands-4.snap │ ├── integration__snapshot__insecure_commands.snap │ ├── integration__snapshot__obfuscation.snap │ ├── integration__snapshot__overprovisioned_secrets.snap │ ├── integration__snapshot__ref_confusion-2.snap │ ├── integration__snapshot__ref_confusion.snap │ ├── integration__snapshot__secrets_inherit.snap │ ├── integration__snapshot__self_hosted-2.snap │ ├── integration__snapshot__self_hosted-3.snap │ ├── integration__snapshot__self_hosted-4.snap │ ├── integration__snapshot__self_hosted-5.snap │ ├── integration__snapshot__self_hosted-6.snap │ ├── integration__snapshot__self_hosted-7.snap │ ├── integration__snapshot__self_hosted-8.snap │ ├── integration__snapshot__self_hosted.snap │ ├── integration__snapshot__stale_action_refs.snap │ ├── integration__snapshot__template_injection-10.snap │ ├── integration__snapshot__template_injection-11.snap │ ├── integration__snapshot__template_injection-12.snap │ ├── integration__snapshot__template_injection-13.snap │ ├── integration__snapshot__template_injection-2.snap │ ├── integration__snapshot__template_injection-3.snap │ ├── integration__snapshot__template_injection-4.snap │ ├── integration__snapshot__template_injection-5.snap │ ├── integration__snapshot__template_injection-6.snap │ ├── integration__snapshot__template_injection-7.snap │ ├── integration__snapshot__template_injection-8.snap │ ├── integration__snapshot__template_injection-9.snap │ ├── integration__snapshot__template_injection.snap │ ├── integration__snapshot__unpinned-uses-composite-config-2.snap │ ├── integration__snapshot__unpinned-uses-composite-config.snap │ ├── integration__snapshot__unpinned-uses-default-config.snap │ ├── integration__snapshot__unpinned-uses-empty-config.snap │ ├── integration__snapshot__unpinned-uses-hash-pin-everything-config.snap │ ├── integration__snapshot__unpinned-uses-ref-pin-everything-config.snap │ ├── integration__snapshot__unpinned_images.snap │ ├── integration__snapshot__unpinned_uses-10.snap │ ├── integration__snapshot__unpinned_uses-11.snap │ ├── integration__snapshot__unpinned_uses-12.snap │ ├── integration__snapshot__unpinned_uses-2.snap │ ├── integration__snapshot__unpinned_uses-3.snap │ ├── integration__snapshot__unpinned_uses-4.snap │ ├── integration__snapshot__unpinned_uses-5.snap │ ├── integration__snapshot__unpinned_uses-6.snap │ ├── integration__snapshot__unpinned_uses-7.snap │ ├── integration__snapshot__unpinned_uses-8.snap │ ├── integration__snapshot__unpinned_uses-9.snap │ ├── integration__snapshot__unpinned_uses.snap │ ├── integration__snapshot__unredacted_secrets.snap │ └── integration__snapshot__unsound_contains.snap │ └── test-data │ ├── artipacked.yml │ ├── artipacked │ └── issue-447-repro.yml │ ├── bot-conditions.yml │ ├── cache-poisoning.yml │ ├── cache-poisoning │ ├── caching-disabled-by-default.yml │ ├── caching-enabled-by-default.yml │ ├── caching-not-configurable.yml │ ├── caching-opt-in-boolean-toggle.yml │ ├── caching-opt-in-boolish-toggle.yml │ ├── caching-opt-in-expression.yml │ ├── caching-opt-in-multi-value-toggle.yml │ ├── caching-opt-out.yml │ ├── issue-343-repro.yml │ ├── issue-378-repro.yml │ ├── issue-642-repro.yml │ ├── no-cache-aware-steps.yml │ ├── publisher-step.yml │ ├── workflow-release-branch-trigger.yml │ └── workflow-tag-trigger.yml │ ├── e2e-menagerie │ ├── .github │ │ ├── dummy-action-2 │ │ │ └── action.yml │ │ └── workflows │ │ │ ├── another-dummy.yml │ │ │ ├── dummy.yml │ │ │ └── ignored.yaml │ ├── .gitignore │ ├── README.md │ └── dummy-action-1 │ │ └── action.yaml │ ├── excessive-permissions.yml │ ├── excessive-permissions │ ├── issue-336-repro.yml │ ├── issue-472-repro.yml │ ├── jobs-broaden-permissions.yml │ ├── reusable-workflow-call.yml │ ├── reusable-workflow-other-triggers.yml │ ├── workflow-default-perms-all-jobs-explicit.yml │ ├── workflow-default-perms.yml │ ├── workflow-empty-perms.yml │ ├── workflow-read-all.yml │ ├── workflow-write-all.yml │ └── workflow-write-explicit.yml │ ├── forbidden-uses │ ├── configs │ │ ├── allow-all.yml │ │ ├── allow-some-refs.yml │ │ ├── allow-some.yml │ │ ├── deny-all.yml │ │ ├── deny-some-refs.yml │ │ └── deny-some.yml │ └── forbidden-uses-menagerie.yml │ ├── github-env │ ├── action.yml │ ├── github-path.yml │ └── issue-397-repro.yml │ ├── github_env.yml │ ├── hardcoded-credentials.yml │ ├── inlined-ignores.yml │ ├── insecure-commands.yml │ ├── insecure-commands │ ├── action.yml │ └── issue-839-repro.yml │ ├── invalid │ ├── bad-yaml-1.yml │ ├── bad-yaml-2.yml │ ├── blank.yml │ ├── comment-only.yml │ ├── empty-action │ │ └── action.yml │ ├── empty.yml │ ├── invalid-action-1 │ │ └── action.yml │ ├── invalid-action-2 │ │ └── action.yml │ ├── invalid-workflow-2.yml │ └── invalid-workflow.yml │ ├── issue-612-repro │ └── action.yml │ ├── obfuscation.yml │ ├── overprovisioned-secrets.yml │ ├── ref-confusion.yml │ ├── ref-confusion │ └── issue-518-repro.yml │ ├── secrets-inherit.yml │ ├── self-hosted.yml │ ├── self-hosted │ ├── issue-283-repro.yml │ ├── self-hosted-matrix-dimension.yml │ ├── self-hosted-matrix-exclusion.yml │ ├── self-hosted-matrix-inclusion.yml │ ├── self-hosted-runner-group.yml │ └── self-hosted-runner-label.yml │ ├── several-vulnerabilities.yml │ ├── stale-action-refs.yml │ ├── template-injection.yml │ ├── template-injection │ ├── codeql-sinks.yml │ ├── dataflow.yml │ ├── false-positive-menagerie.yml │ ├── issue-22-repro.yml │ ├── issue-339-repro.yml │ ├── issue-418-repro.yml │ ├── issue-749-repro.yml │ ├── issue-883-repro │ │ └── action.yml │ ├── patterns.yml │ ├── pr-317-repro.yml │ ├── pr-425-backstop │ │ └── action.yml │ ├── pwsh-script.yml │ ├── static-env.yml │ ├── template-injection-dynamic-matrix.yml │ └── template-injection-static-matrix.yml │ ├── unpinned-images.yml │ ├── unpinned-uses.yml │ ├── unpinned-uses │ ├── action.yml │ ├── configs │ │ ├── composite-2.yml │ │ ├── composite.yml │ │ ├── empty.yml │ │ ├── hash-pin-everything.yml │ │ ├── invalid-policy-syntax-1.yml │ │ ├── invalid-policy-syntax-2.yml │ │ ├── invalid-policy-syntax-3.yml │ │ ├── invalid-policy-syntax-4.yml │ │ ├── invalid-policy-syntax-5.yml │ │ ├── invalid-policy-syntax-6.yml │ │ ├── invalid-wrong-policy-object.yml │ │ └── ref-pin-everything.yml │ ├── issue-433-repro.yml │ ├── issue-659-repro.yml │ └── menagerie-of-uses.yml │ ├── unredacted-secrets.yml │ ├── unsound-contains.yml │ └── use-trusted-publishing.yml ├── docs ├── assets │ ├── favicon48x48.png │ ├── magiclink.css │ ├── rainbow.svg │ └── zizmor-demo.gif ├── audits.md ├── configuration.md ├── development.md ├── index.md ├── installation.md ├── quickstart.md ├── release-notes.md ├── snippets │ ├── help.txt │ ├── render-sponsors.py │ ├── render-trophies.py │ ├── sponsors.html │ ├── sponsors.json │ ├── trophies.md │ └── trophies.txt ├── trophy-case.md └── usage.md ├── mkdocs.yml ├── pyproject.toml ├── support ├── archive-release.sh ├── codeql-injection-sinks.py ├── known-safe-contexts.txt ├── webhooks-to-contexts.py └── wolfi-update-check.sh └── uv.lock /.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [target.'cfg(all(target_env = "msvc", target_os = "windows"))'] 2 | rustflags = ["-C", "target-feature=+crt-static"] 3 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: true 2 | contact_links: 3 | - name: Discord 4 | url: https://discord.com/invite/PGU3zGZuGG 5 | about: Join our Discord server to chat with the community. 6 | - name: Discussions Forum 7 | url: https://github.com/zizmorcore/zizmor/discussions 8 | about: You can use our GitHub Discussions forum to ask questions and share ideas. 9 | - name: Security Reports 10 | url: https://github.com/zizmorcore/zizmor/security/advisories 11 | about: Please report potential security vulnerabilities here. 12 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature-request.yml: -------------------------------------------------------------------------------- 1 | name: Feature request 2 | description: Suggest an idea or enhancement for zizmor 3 | title: "Feature: " 4 | labels: 5 | - enhancement 6 | - triage 7 | body: 8 | - type: markdown 9 | attributes: 10 | value: | 11 | Thanks for making a `zizmor` feature request! 12 | 13 | Please read the following parts of this form carefully. 14 | Invalid or incomplete submissions take longer to triage, 15 | and may be given a lower priority or closed outright 16 | if not actionable. 17 | 18 | - type: checkboxes 19 | attributes: 20 | label: Pre-submission checks 21 | description: | 22 | By submitting this issue, you affirm that you've satisfied the following conditions. 23 | options: 24 | - label: >- 25 | I am **not** reporting a bug (crash, false positive/negative, etc). 26 | These must be filed via the bug report template. 27 | required: true 28 | - label: >- 29 | I have looked through the open issues for a duplicate request. 30 | required: true 31 | 32 | - type: textarea 33 | attributes: 34 | label: What's the problem this feature will solve? 35 | description: | 36 | A clear and concise description of the problem. 37 | placeholder: | 38 | I'm always frustrated when ... 39 | validations: 40 | required: true 41 | 42 | - type: textarea 43 | attributes: 44 | label: Describe the solution you'd like 45 | description: A clear and concise description of what you want to happen. 46 | validations: 47 | required: true 48 | 49 | - type: textarea 50 | attributes: 51 | label: Additional context 52 | description: | 53 | Any additional context, screenshots, or other material about the feature request. 54 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: cargo 4 | directory: "/" 5 | schedule: 6 | interval: weekly 7 | groups: 8 | cargo: 9 | patterns: 10 | - "*" 11 | 12 | - package-ecosystem: github-actions 13 | directory: / 14 | schedule: 15 | interval: weekly 16 | groups: 17 | github-actions: 18 | patterns: 19 | - "*" 20 | 21 | - package-ecosystem: docker 22 | directory: "/" 23 | schedule: 24 | interval: "weekly" 25 | groups: 26 | docker: 27 | patterns: 28 | - "*" 29 | -------------------------------------------------------------------------------- /.github/pinact.yml: -------------------------------------------------------------------------------- 1 | version: 3 2 | 3 | files: 4 | # NOTE: we intentionally only update docs with pinact. 5 | # All non-doc workflows and actions are updated through Dependabot. 6 | - pattern: ../docs/*.md 7 | -------------------------------------------------------------------------------- /.github/workflows/release-support-crate.yml: -------------------------------------------------------------------------------- 1 | name: Release support crates to crates.io 📦 2 | 3 | on: 4 | push: 5 | tags: 6 | # NOTE: additional non-zizmor crate tag patterns get added here 7 | - 'github-actions-expressions/v*' 8 | - 'github-actions-models/v*' 9 | - 'yamlpath/v*' 10 | workflow_dispatch: 11 | inputs: 12 | package-name: 13 | description: 'The name of the package to publish' 14 | required: true 15 | 16 | permissions: {} 17 | 18 | jobs: 19 | crates: 20 | runs-on: ubuntu-latest 21 | steps: 22 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 23 | with: 24 | persist-credentials: false 25 | 26 | - name: Get package name from tag 27 | if: ${{ github.event_name == 'push' }} 28 | id: get-package-name 29 | run: | 30 | echo PACKAGE_NAME="$(echo ${GITHUB_REF_NAME} | cut -d/ -f1)" >> ${GITHUB_OUTPUT} 31 | 32 | - name: publish to crates.io 33 | run: | 34 | echo "::notice::Publishing package ${PACKAGE_NAME} (dry-run: ${DRY_RUN})" 35 | cargo publish ${DRY_RUN} -p ${PACKAGE_NAME} 36 | env: 37 | CARGO_REGISTRY_TOKEN: "${{ secrets.CARGO_REGISTRY_TOKEN }}" 38 | # workflow_dispatch always causes a dry run 39 | DRY_RUN: "${{ github.event_name == 'workflow_dispatch' && '--dry-run' || '' }}" 40 | PACKAGE_NAME: "${{ steps.get-package-name.outputs.PACKAGE_NAME || github.event.inputs.package-name }}" 41 | -------------------------------------------------------------------------------- /.github/workflows/release-zizmor-crate.yml: -------------------------------------------------------------------------------- 1 | name: Release zizmor to crates.io 📦 2 | 3 | on: 4 | release: 5 | types: 6 | - published 7 | 8 | permissions: {} 9 | 10 | jobs: 11 | crates: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 15 | with: 16 | persist-credentials: false 17 | 18 | - name: publish to crates.io 19 | run: cargo publish -p zizmor 20 | env: 21 | CARGO_REGISTRY_TOKEN: "${{ secrets.CARGO_REGISTRY_TOKEN }}" 22 | 23 | -------------------------------------------------------------------------------- /.github/workflows/site.yml: -------------------------------------------------------------------------------- 1 | name: Deploy zizmor site 🌐 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | workflow_dispatch: 9 | 10 | concurrency: 11 | group: "pages" 12 | cancel-in-progress: false 13 | 14 | permissions: {} 15 | 16 | jobs: 17 | deploy: 18 | permissions: 19 | contents: read 20 | pages: write 21 | id-token: write 22 | environment: 23 | name: github-pages 24 | url: ${{ steps.deployment.outputs.page_url }} 25 | 26 | runs-on: ubuntu-latest 27 | steps: 28 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 29 | with: 30 | persist-credentials: false 31 | 32 | - name: Install the latest version of uv 33 | uses: astral-sh/setup-uv@f0ec1fc3b38f5e7cd731bb6ce540c5af426746bb # v6.1.0 34 | 35 | - name: build site 36 | run: make site 37 | 38 | - name: Setup Pages 39 | if: github.repository_owner == 'zizmorcore' 40 | uses: actions/configure-pages@983d7736d9b0ae728b81ab479565c72886d7745b # v5.0.0 41 | 42 | - name: Upload artifact 43 | uses: actions/upload-pages-artifact@56afc609e74202658d3ffba0e8f6dda462b719fa # v3.0.1 44 | with: 45 | path: site_html 46 | 47 | - name: Deploy to GitHub Pages 48 | if: github.repository_owner == 'zizmorcore' 49 | id: deployment 50 | uses: actions/deploy-pages@d6db90164ac5ed86f2b6aed7e0febac5b3c0c03e # v4.0.5 51 | -------------------------------------------------------------------------------- /.github/workflows/wolfi-update-check.yml: -------------------------------------------------------------------------------- 1 | name: Check for a new zizmor version in Wolfi OS 2 | 3 | on: 4 | schedule: 5 | - cron: '0 */12 * * *' # every 12 hours 6 | workflow_dispatch: 7 | 8 | permissions: {} 9 | 10 | jobs: 11 | check-for-new-version: 12 | runs-on: ubuntu-latest 13 | # this job does not make sense on forks 14 | if: ${{ github.repository_owner == 'zizmorcore' }} 15 | 16 | permissions: 17 | packages: read # to read the current Docker image version 18 | issues: write # to create an issue if a new version is found 19 | 20 | steps: 21 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 22 | with: 23 | persist-credentials: false 24 | sparse-checkout: support/ 25 | 26 | - name: Check for new zizmor version in Wolfi OS 27 | run: | 28 | ./support/wolfi-update-check.sh 29 | env: 30 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 31 | GH_REPO: ${{ github.repository }} 32 | -------------------------------------------------------------------------------- /.github/workflows/zizmor.yml: -------------------------------------------------------------------------------- 1 | name: GitHub Actions Security Analysis with zizmor 🌈 2 | 3 | on: 4 | push: 5 | branches: ["main"] 6 | pull_request: 7 | branches: ["**"] 8 | 9 | permissions: {} 10 | 11 | jobs: 12 | zizmor: 13 | runs-on: ubuntu-latest 14 | permissions: 15 | security-events: write 16 | steps: 17 | - name: Checkout repository 18 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 19 | with: 20 | persist-credentials: false 21 | 22 | - name: Run zizmor 🌈 23 | uses: zizmorcore/zizmor-action@2520132f44b3ed84916048d32e5c7153fc739fe7 # v0.0.3 24 | with: 25 | # intentionally not scanning the entire repository, 26 | # since it contains integration tests. 27 | inputs: ./.github/ 28 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | 3 | # website artifacts 4 | /site_html 5 | .cache 6 | 7 | # IDEs / Editors 8 | .idea 9 | .DS_STORE 10 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # ------------------------------------------------------------------------------ 2 | # Runtime image 3 | # ------------------------------------------------------------------------------ 4 | 5 | FROM cgr.dev/chainguard/wolfi-base:latest 6 | 7 | # Wolfi zizmor version to install 8 | # https://edu.chainguard.dev/open-source/wolfi/apk-version-selection/ 9 | # (set as an argument to pair with zizmor releases) 10 | ARG ZIZMOR_VERSION 11 | 12 | RUN set -eux && \ 13 | apk update && \ 14 | apk add zizmor=~${ZIZMOR_VERSION} && \ 15 | zizmor --version 16 | 17 | # Set the entrypoint to zizmor 18 | ENTRYPOINT ["/usr/bin/zizmor"] 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2024 William Woodruff 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all 2 | all: 3 | @echo "Run my targets individually!" 4 | 5 | .PHONY: site 6 | site: 7 | uv run --only-group docs mkdocs build 8 | 9 | .PHONY: site-live 10 | site-live: 11 | uv run --only-group docs mkdocs serve 12 | 13 | .PHONY: snippets 14 | snippets: trophies sponsors 15 | cargo run -- -h > docs/snippets/help.txt 16 | 17 | .PHONY: trophies 18 | trophies: docs/snippets/trophies.md 19 | 20 | docs/snippets/trophies.md: docs/snippets/trophies.txt docs/snippets/render-trophies.py 21 | uv run --no-project docs/snippets/render-trophies.py > $@ 22 | 23 | .PHONY: sponsors 24 | sponsors: docs/snippets/sponsors.html 25 | 26 | docs/snippets/sponsors.html: docs/snippets/sponsors.json docs/snippets/render-sponsors.py 27 | uv run --no-project docs/snippets/render-sponsors.py > $@ 28 | 29 | .PHONY: refresh-schemas 30 | refresh-schemas: 31 | curl https://json.schemastore.org/github-workflow.json > crates/zizmor/src/data/github-workflow.json 32 | curl https://json.schemastore.org/github-action.json > crates/zizmor/src/data/github-action.json 33 | 34 | .PHONY: webhooks-to-contexts 35 | webhooks-to-contexts: support/known-safe-contexts.txt 36 | 37 | support/known-safe-contexts.txt: support/webhooks-to-contexts.py 38 | $< 39 | 40 | .PHONY: codeql-injection-sinks 41 | codeql-injection-sinks: crates/zizmor/data/codeql-injection-sinks.json 42 | 43 | crates/zizmor/data/codeql-injection-sinks.json: support/codeql-injection-sinks.py 44 | $< > $@ 45 | 46 | .PHONY: pinact 47 | pinact: 48 | pinact run --update --verify 49 | -------------------------------------------------------------------------------- /crates/github-actions-expressions/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "github-actions-expressions" 3 | description = "GitHub Actions expression parser and data types" 4 | repository = "https://github.com/zizmorcore/zizmor/tree/main/crates/github-actions-expressions" 5 | version = "0.0.4" 6 | readme = "README.md" 7 | 8 | homepage.workspace = true 9 | license.workspace = true 10 | authors.workspace = true 11 | edition.workspace = true 12 | 13 | [lints] 14 | workspace = true 15 | 16 | [dependencies] 17 | anyhow.workspace = true 18 | pest.workspace = true 19 | pest_derive.workspace = true 20 | itertools.workspace = true 21 | 22 | [dev-dependencies] 23 | pretty_assertions.workspace = true 24 | -------------------------------------------------------------------------------- /crates/github-actions-expressions/README.md: -------------------------------------------------------------------------------- 1 | # github-actions-expressions 2 | 3 | [![CI](https://github.com/zizmorcore/zizmor/actions/workflows/ci.yml/badge.svg)](https://github.com/zizmorcore/zizmor/actions/workflows/ci.yml) 4 | [![Crates.io](https://img.shields.io/crates/v/github-actions-expressions)](https://crates.io/crates/github-actions-expressions) 5 | [![docs.rs](https://img.shields.io/docsrs/github-actions-expressions)](https://docs.rs/github-actions-expressions) 6 | [![GitHub Sponsors](https://img.shields.io/github/sponsors/woodruffw?style=flat&logo=githubsponsors&labelColor=white&color=white)](https://github.com/sponsors/woodruffw) 7 | [![Discord](https://img.shields.io/badge/Discord-%235865F2.svg?logo=discord&logoColor=white)](https://discord.com/invite/PGU3zGZuGG) 8 | 9 | `github-actions-expressions` is a parser and library for GitHub Actions expressions. 10 | 11 | See the [documentation] for more details. 12 | 13 | This library is part of [zizmor]. 14 | 15 | [documentation]: https://docs.rs/github-actions-expressions 16 | [zizmor]: https://docs.zizmor.sh 17 | -------------------------------------------------------------------------------- /crates/github-actions-models/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "github-actions-models" 3 | version = "0.30.0" 4 | description = "Unofficial, high-quality data models for GitHub Actions workflows, actions, and related components" 5 | repository = "https://github.com/zizmorcore/zizmor/tree/main/crates/github-actions-models" 6 | keywords = ["github", "ci"] 7 | categories = ["api-bindings"] 8 | readme = "README.md" 9 | 10 | authors.workspace = true 11 | homepage.workspace = true 12 | edition.workspace = true 13 | license.workspace = true 14 | 15 | [lints] 16 | workspace = true 17 | 18 | [dependencies] 19 | indexmap.workspace = true 20 | serde.workspace = true 21 | serde_yaml.workspace = true 22 | 23 | [dev-dependencies] 24 | -------------------------------------------------------------------------------- /crates/github-actions-models/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2024 William Woodruff 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /crates/github-actions-models/README.md: -------------------------------------------------------------------------------- 1 | github-actions-models 2 | ===================== 3 | 4 | [![CI](https://github.com/zizmorcore/zizmor/actions/workflows/ci.yml/badge.svg)](https://github.com/zizmorcore/zizmor/actions/workflows/ci.yml) 5 | [![Crates.io](https://img.shields.io/crates/v/github-actions-models)](https://crates.io/crates/github-actions-models) 6 | [![docs.rs](https://img.shields.io/docsrs/github-actions-models)](https://docs.rs/github-actions-models) 7 | [![GitHub Sponsors](https://img.shields.io/github/sponsors/woodruffw?style=flat&logo=githubsponsors&labelColor=white&color=white)](https://github.com/sponsors/woodruffw) 8 | [![Discord](https://img.shields.io/badge/Discord-%235865F2.svg?logo=discord&logoColor=white)](https://discord.com/invite/PGU3zGZuGG) 9 | 10 | Unofficial, high-quality data models for GitHub Actions workflows, actions, and related components. 11 | 12 | ## Why? 13 | 14 | I need these for [another tool], and generating them automatically from 15 | [their JSON Schemas] wasn't working both for expressiveness and tool deficiency 16 | reasons. 17 | 18 | [another tool]: https://github.com/woodruffw/zizmor 19 | 20 | [their JSON Schemas]: https://www.schemastore.org/json/ 21 | 22 | ## License 23 | 24 | MIT License. 25 | 26 | The integration tests for this crate contain sample workflows collected from 27 | various GitHub repositories; these contain comments linking them to their 28 | original repositories and are licensed under the terms there. 29 | -------------------------------------------------------------------------------- /crates/github-actions-models/src/dependabot/mod.rs: -------------------------------------------------------------------------------- 1 | //! Data models for Dependabot configuration files. 2 | 3 | pub mod v2; 4 | -------------------------------------------------------------------------------- /crates/github-actions-models/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! High-quality data models for GitHub Actions and associated machinery. 2 | 3 | #![deny(missing_debug_implementations)] 4 | #![deny(rustdoc::broken_intra_doc_links)] 5 | #![allow(clippy::redundant_field_names)] 6 | #![forbid(unsafe_code)] 7 | 8 | pub mod action; 9 | pub mod common; 10 | pub mod dependabot; 11 | pub mod workflow; 12 | -------------------------------------------------------------------------------- /crates/github-actions-models/tests/sample-actions/no-input-output-descriptions.yml: -------------------------------------------------------------------------------- 1 | # ensures that we parse actions without input/output descriptions correctly 2 | # see: https://github.com/woodruffw/zizmor/issues/501 3 | 4 | inputs: 5 | foo: 6 | default: "lol" 7 | outputs: 8 | bar: 9 | value: "hmm" 10 | 11 | runs: 12 | using: "composite" 13 | steps: 14 | - name: say hello 15 | run: echo hello 16 | shell: bash 17 | -------------------------------------------------------------------------------- /crates/github-actions-models/tests/sample-dependabot/v2/pip-audit.yml: -------------------------------------------------------------------------------- 1 | # https://github.com/pypa/pip-audit/blob/cea0e0276f1208cfcbda0c5d69b4fc0c084747b2/.github/dependabot.yml 2 | version: 2 3 | 4 | updates: 5 | - package-ecosystem: pip 6 | directory: / 7 | schedule: 8 | interval: daily 9 | 10 | - package-ecosystem: github-actions 11 | directory: / 12 | schedule: 13 | interval: daily 14 | -------------------------------------------------------------------------------- /crates/github-actions-models/tests/sample-dependabot/v2/sigstore-python.yml: -------------------------------------------------------------------------------- 1 | # https://github.com/sigstore/sigstore-python/blob/e0168a781b87d059fde05dfdfe0ce82e564ce095/.github/dependabot.yml 2 | 3 | # Copyright 2022 The Sigstore Authors 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | version: 2 18 | 19 | updates: 20 | - package-ecosystem: pip 21 | directory: / 22 | schedule: 23 | interval: daily 24 | 25 | - package-ecosystem: github-actions 26 | directory: / 27 | schedule: 28 | interval: daily 29 | open-pull-requests-limit: 99 30 | rebase-strategy: "disabled" 31 | groups: 32 | actions: 33 | patterns: 34 | - "*" 35 | 36 | - package-ecosystem: github-actions 37 | directory: .github/actions/upload-coverage/ 38 | schedule: 39 | interval: daily 40 | open-pull-requests-limit: 99 41 | rebase-strategy: "disabled" 42 | groups: 43 | actions: 44 | patterns: 45 | - "*" 46 | -------------------------------------------------------------------------------- /crates/github-actions-models/tests/sample-workflows/false-condition.yml: -------------------------------------------------------------------------------- 1 | # https://github.com/woodruffw/zizmor/issues/209 2 | name: Name 3 | 4 | on: [push] 5 | 6 | jobs: 7 | build: 8 | runs-on: ubuntu-22.04 9 | steps: 10 | - name: Step 11 | if: false 12 | run: echo 13 | -------------------------------------------------------------------------------- /crates/github-actions-models/tests/sample-workflows/issue-35.yml: -------------------------------------------------------------------------------- 1 | # https://github.com/zizmorcore/github-actions-models/issues/35 2 | 3 | name: Test Workflow 4 | permissions: {} 5 | 6 | on: ["push"] 7 | 8 | # LIMIT = true|false 9 | 10 | jobs: 11 | test: 12 | name: Test job 13 | runs-on: ubuntu-24.04 14 | strategy: 15 | # max-parallel: 1 16 | max-parallel: ${{ vars.LIMIT && 1 || 8 }} 17 | steps: 18 | - name: Test step 19 | shell: bash 20 | run: | 21 | echo "Hello World!" 22 | -------------------------------------------------------------------------------- /crates/github-actions-models/tests/sample-workflows/pip-audit-ci.yml: -------------------------------------------------------------------------------- 1 | # https://github.com/pypa/pip-audit/blob/1fd67af0653a8e66b9470adab2e408a435632f19/.github/workflows/ci.yml 2 | 3 | # Copyright: 2021-2024 Alex Cameron 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | name: CI 18 | 19 | on: 20 | push: 21 | branches: 22 | - main 23 | pull_request: 24 | schedule: 25 | - cron: "0 12 * * *" 26 | 27 | jobs: 28 | test: 29 | strategy: 30 | matrix: 31 | python: 32 | - "3.8" 33 | - "3.9" 34 | - "3.10" 35 | - "3.11" 36 | - "3.12" 37 | runs-on: ubuntu-latest 38 | steps: 39 | - uses: actions/checkout@v4.1.1 40 | 41 | - uses: actions/setup-python@v5 42 | with: 43 | python-version: ${{ matrix.python }} 44 | cache: "pip" 45 | cache-dependency-path: pyproject.toml 46 | 47 | - name: test 48 | run: make test PIP_AUDIT_EXTRA=test 49 | -------------------------------------------------------------------------------- /crates/github-actions-models/tests/sample-workflows/pwn-requests.yml: -------------------------------------------------------------------------------- 1 | # from: https://securitylab.github.com/resources/github-actions-preventing-pwn-requests/ 2 | 3 | # Copyright: 2021 Jaroslav Lobačevski 4 | # License: Unknown, maybe fair use? Code comes from blog post. 5 | 6 | # INSECURE. Provided as an example only. 7 | on: pull_request_target 8 | 9 | jobs: 10 | build: 11 | name: Build and test 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v2 15 | with: 16 | ref: ${{ github.event.pull_request.head.sha }} 17 | 18 | - uses: actions/setup-node@v1 19 | - run: | 20 | npm install 21 | npm build 22 | 23 | - uses: completely/fakeaction@v2 24 | with: 25 | arg1: ${{ secrets.supersecret }} 26 | 27 | - uses: fakerepo/comment-on-pr@v1 28 | with: 29 | message: | 30 | Thank you! 31 | -------------------------------------------------------------------------------- /crates/github-actions-models/tests/sample-workflows/pypi-attestations-release.yml: -------------------------------------------------------------------------------- 1 | # https://github.com/trailofbits/pypi-attestations/blob/b5920dee025c93b2bfefbcccc6acc7eab7b8a18e/.github/workflows/release.yml 2 | 3 | # Copyright 2024 Trail of Bits 4 | # License: Apache-2.0 5 | 6 | on: 7 | release: 8 | types: 9 | - published 10 | 11 | name: release 12 | 13 | permissions: 14 | # Trusted Publishing + attestations 15 | id-token: write 16 | attestations: write 17 | 18 | jobs: 19 | pypi: 20 | name: upload release to PyPI 21 | runs-on: ubuntu-latest 22 | steps: 23 | - uses: actions/checkout@v4 24 | 25 | - uses: actions/setup-python@v5 26 | with: 27 | python-version-file: pyproject.toml 28 | cache: "pip" 29 | cache-dependency-path: pyproject.toml 30 | 31 | - name: deps 32 | run: python -m pip install -U setuptools build wheel 33 | 34 | - name: build 35 | run: python -m build 36 | 37 | - name: publish 38 | uses: pypa/gh-action-pypi-publish@release/v1 39 | 40 | - name: attest 41 | uses: actions/attest@v1 42 | with: 43 | subject-path: | 44 | ./dist/*.tar.gz 45 | ./dist/*.whl 46 | predicate-type: "https://docs.pypi.org/attestations/publish/v1" 47 | predicate: "{}" 48 | -------------------------------------------------------------------------------- /crates/github-actions-models/tests/sample-workflows/reusable-workflow-unpinned.yml: -------------------------------------------------------------------------------- 1 | # see https://github.com/woodruffw/zizmor/issues/431 2 | 3 | name: "reusable-workflow-unpinned" 4 | 5 | on: 6 | push: 7 | 8 | jobs: 9 | testcase: 10 | name: "testcase" 11 | uses: ./.github/workflows/reusable.yml 12 | -------------------------------------------------------------------------------- /crates/github-actions-models/tests/sample-workflows/runs-on-expr.yml: -------------------------------------------------------------------------------- 1 | name: runs-on-expr 2 | on: [push] 3 | jobs: 4 | check-bats-version: 5 | runs-on: ${{ matrix.runner }} 6 | steps: 7 | - uses: actions/checkout@v4 8 | - uses: actions/setup-node@v4 9 | with: 10 | node-version: "14" 11 | - run: npm install -g bats 12 | - run: bats -v 13 | -------------------------------------------------------------------------------- /crates/github-actions-models/tests/sample-workflows/runs-on-group-only.yml: -------------------------------------------------------------------------------- 1 | # https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions#choosing-runners-in-a-group 2 | 3 | # Copyright: 2024 GitHub, Inc. 4 | # License: Creative Commons Attribution 4.0 International 5 | 6 | name: learn-github-actions 7 | on: [push] 8 | jobs: 9 | check-bats-version: 10 | runs-on: 11 | group: ubuntu-runners 12 | steps: 13 | - uses: actions/checkout@v4 14 | - uses: actions/setup-node@v4 15 | with: 16 | node-version: "14" 17 | - run: npm install -g bats 18 | - run: bats -v 19 | -------------------------------------------------------------------------------- /crates/github-actions-models/tests/sample-workflows/scalar-trigger-type.yml: -------------------------------------------------------------------------------- 1 | # repro case for https://github.com/zizmorcore/github-actions-models/issues/12 2 | name: issue-12 3 | on: 4 | repository_dispatch: 5 | types: some-external-type 6 | jobs: 7 | dummy: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/checkout@v4 11 | -------------------------------------------------------------------------------- /crates/github-actions-models/tests/sample-workflows/zizmor-issue-646.yml: -------------------------------------------------------------------------------- 1 | # https://github.com/woodruffw/zizmor/issues/646 2 | 3 | name: Test 4 | 5 | on: 6 | workflow_call: 7 | secrets: 8 | my-secret: 9 | description: My secret 10 | 11 | jobs: 12 | job: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - run: echo ${{ secrets.my-secret }} 16 | -------------------------------------------------------------------------------- /crates/github-actions-models/tests/sample-workflows/zizmor-issue-650.yml: -------------------------------------------------------------------------------- 1 | # See https://github.com/woodruffw/zizmor/issues/650 2 | 3 | # Copyright © Michal Čihař 4 | # 5 | # SPDX-License-Identifier: CC0-1.0 6 | 7 | # This file is maintained in https://github.com/WeblateOrg/meta/ 8 | 9 | name: Pull request automation 10 | 11 | on: 12 | pull_request_target: 13 | types: opened 14 | 15 | permissions: 16 | contents: read 17 | 18 | jobs: 19 | weblate_automerge: 20 | permissions: 21 | pull-requests: write 22 | contents: write 23 | runs-on: ubuntu-24.04 24 | name: Weblate automerge 25 | if: github.actor == 'weblate' 26 | steps: 27 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 28 | - name: Enable Pull Request Automerge 29 | run: gh pr merge --rebase --auto "${{ github.event.pull_request.number }}" 30 | env: 31 | GH_TOKEN: ${{ secrets.WEBLATE_CI_TOKEN }} 32 | -------------------------------------------------------------------------------- /crates/github-actions-models/tests/test_action.rs: -------------------------------------------------------------------------------- 1 | use std::{env, path::Path}; 2 | 3 | use github_actions_models::{ 4 | action::{Action, Runs}, 5 | common::If, 6 | }; 7 | 8 | fn load_action(name: &str) -> Action { 9 | let action_path = Path::new(env!("CARGO_MANIFEST_DIR")) 10 | .join("tests/sample-actions") 11 | .join(name); 12 | let action_contents = std::fs::read_to_string(action_path).unwrap(); 13 | serde_yaml::from_str(&action_contents).unwrap() 14 | } 15 | 16 | #[test] 17 | fn test_load_all() { 18 | let sample_actions = Path::new(env!("CARGO_MANIFEST_DIR")).join("tests/sample-actions"); 19 | 20 | for sample_action in std::fs::read_dir(sample_actions).unwrap() { 21 | let sample_action = sample_action.unwrap().path(); 22 | let action_contents = std::fs::read_to_string(sample_action).unwrap(); 23 | serde_yaml::from_str::(&action_contents).unwrap(); 24 | } 25 | } 26 | 27 | #[test] 28 | fn test_setup_python() { 29 | let setup_python = load_action("setup-python.yml"); 30 | 31 | assert_eq!(setup_python.name.as_deref(), Some("Setup Python")); 32 | assert_eq!( 33 | setup_python.description.unwrap(), 34 | "Set up a specific version of Python and add the command-line tools to the PATH." 35 | ); 36 | assert_eq!(setup_python.author.unwrap(), "GitHub"); 37 | 38 | assert_eq!(setup_python.inputs.len(), 9); 39 | assert_eq!(setup_python.outputs.len(), 3); 40 | 41 | let Runs::JavaScript(runs) = setup_python.runs else { 42 | unreachable!(); 43 | }; 44 | assert_eq!(runs.using, "node20"); 45 | assert_eq!(runs.main, "dist/setup/index.js"); 46 | assert_eq!(runs.post.unwrap(), "dist/cache-save/index.js"); 47 | assert_eq!(runs.post_if.unwrap(), If::Expr("success()".into())); 48 | } 49 | -------------------------------------------------------------------------------- /crates/yamlpath/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "yamlpath" 3 | version = "0.19.0" 4 | description = "Format-preserving YAML feature extraction" 5 | repository = "https://github.com/zizmorcore/zizmor/tree/main/crates/yamlpath" 6 | readme = "README.md" 7 | keywords = ["yaml"] 8 | 9 | authors.workspace = true 10 | homepage.workspace = true 11 | edition.workspace = true 12 | license.workspace = true 13 | 14 | [lints] 15 | workspace = true 16 | 17 | [dependencies] 18 | thiserror.workspace = true 19 | tree-sitter.workspace = true 20 | tree-sitter-yaml = { workspace = true } 21 | 22 | [dev-dependencies] 23 | serde.workspace = true 24 | serde_yaml.workspace = true 25 | -------------------------------------------------------------------------------- /crates/yamlpath/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2024 William Woodruff 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /crates/yamlpath/tests/testcases/basic.yml: -------------------------------------------------------------------------------- 1 | testcase: 2 | foo: 3 | bar: 4 | baz: hello! 5 | 6 | emptykey: 7 | 8 | queries: 9 | - query: [foo, bar, baz] 10 | expected: |2- 11 | baz: hello! 12 | 13 | - query: [foo, bar] 14 | expected: |2- 15 | bar: 16 | baz: hello! 17 | - query: [emptykey] 18 | expected: " emptykey:" 19 | -------------------------------------------------------------------------------- /crates/yamlpath/tests/testcases/comments.yml: -------------------------------------------------------------------------------- 1 | testcase: 2 | # block layout 3 | # not captured 4 | foo: # comment here 5 | bar: 6 | - 123 # another comment 7 | 8 | flow: [1, 2, 3] # another comment 9 | 10 | indexing: 11 | - abc 12 | - def 13 | # comment doesn't interfere with indexing 14 | - ghi 15 | 16 | queries: 17 | - query: [foo] 18 | expected: " foo: # comment here\n bar:\n - 123 # another comment" 19 | 20 | - query: [foo, bar, 0] 21 | # TODO: ideally would be "- 123 # another comment" 22 | expected: "123" 23 | 24 | - query: [flow] 25 | # TODO: ideally would be "flow: [1, 2, 3] # another comment" 26 | expected: " flow: [1, 2, 3]" 27 | 28 | - query: [indexing, 2] 29 | expected: "ghi" 30 | -------------------------------------------------------------------------------- /crates/yamlpath/tests/testcases/directives.yml: -------------------------------------------------------------------------------- 1 | # presence of a directives block doesn't change anything. 2 | %YAML 1.2 3 | --- 4 | testcase: 5 | foo: 6 | bar: 7 | baz: hello! 8 | 9 | queries: 10 | - query: [foo, bar, baz] 11 | expected: |2- 12 | baz: hello! 13 | -------------------------------------------------------------------------------- /crates/yamlpath/tests/testcases/flow.yml: -------------------------------------------------------------------------------- 1 | testcase: 2 | flow1: { foo: [1, 2, 3: [4, 5, { a: b }]] } 3 | flow2: { foo: [1, { a }] } 4 | flow3: { foo: [1, { a: }] } 5 | 6 | queries: 7 | - query: [flow1, foo] 8 | expected: "foo: [1, 2, 3: [4, 5, { a: b }]]" 9 | 10 | - query: [flow1, foo, 2] 11 | # TODO: ideally would be `3: [4, 5, { a: b }]` 12 | expected: "[4, 5, { a: b }]" 13 | 14 | - query: [flow1, foo, 2, 2] 15 | expected: "{ a: b }" 16 | 17 | - query: [flow2, foo, 1] 18 | expected: "{ a }" 19 | 20 | - query: [flow3, foo, 1] 21 | expected: "{ a: }" -------------------------------------------------------------------------------- /crates/yamlpath/tests/testcases/interceding-comment.yml: -------------------------------------------------------------------------------- 1 | testcase: 2 | foo: 3 | - # hello! 4 | bar: baz 5 | 6 | multiple: 7 | - # comment 1 8 | # comment 2 9 | bar: baz 10 | 11 | many-children: 12 | - # foo 13 | foo: bar 14 | - # bar 15 | bar: baz 16 | 17 | queries: 18 | - query: [foo, 0, bar] 19 | expected: " bar: baz" 20 | 21 | - query: [multiple, 0, bar] 22 | expected: " bar: baz" 23 | 24 | - query: [many-children, 1, bar] 25 | expected: " bar: baz" 26 | -------------------------------------------------------------------------------- /crates/yamlpath/tests/testcases/quoted-key.yml: -------------------------------------------------------------------------------- 1 | testcase: 2 | 'on': test 3 | 4 | "on1": test 5 | 6 | on2: test 7 | 8 | 5: test 9 | 10 | queries: 11 | - query: [on] 12 | expected: " 'on': test" 13 | 14 | - query: [on1] 15 | expected: ' "on1": test' 16 | 17 | - query: [on2] 18 | expected: " on2: test" 19 | 20 | - query: ["5"] 21 | expected: " 5: test" 22 | -------------------------------------------------------------------------------- /crates/zizmor/data/codeql-injection-sinks.json: -------------------------------------------------------------------------------- 1 | [ 2 | [ 3 | "devorbitus/yq-action-output", 4 | [ 5 | "cmd" 6 | ] 7 | ], 8 | [ 9 | "docker/build-push-action", 10 | [ 11 | "context" 12 | ] 13 | ], 14 | [ 15 | "appleboy/ssh-action", 16 | [ 17 | "script" 18 | ] 19 | ], 20 | [ 21 | "sergeysova/jq-action", 22 | [ 23 | "cmd" 24 | ] 25 | ], 26 | [ 27 | "azure/powershell", 28 | [ 29 | "inlineScript" 30 | ] 31 | ], 32 | [ 33 | "roots/issue-closer-action", 34 | [ 35 | "issue-close-message", 36 | "pr-close-message" 37 | ] 38 | ], 39 | [ 40 | "skitionek/notify-microsoft-teams", 41 | [ 42 | "overwrite" 43 | ] 44 | ], 45 | [ 46 | "mikefarah/yq", 47 | [ 48 | "cmd" 49 | ] 50 | ], 51 | [ 52 | "lucasbento/auto-close-issues", 53 | [ 54 | "issue-close-message" 55 | ] 56 | ], 57 | [ 58 | "imjohnbo/issue-bot", 59 | [ 60 | "body", 61 | "linked-comments-previous-issue-text", 62 | "linked-comments-new-issue-text" 63 | ] 64 | ], 65 | [ 66 | "8398a7/action-slack", 67 | [ 68 | "custom_payload" 69 | ] 70 | ], 71 | [ 72 | "azure/cli", 73 | [ 74 | "inlineScript" 75 | ] 76 | ], 77 | [ 78 | "actions/github-script", 79 | [ 80 | "script" 81 | ] 82 | ], 83 | [ 84 | "gautamkrishnar/blog-post-workflow", 85 | [ 86 | "item_exec" 87 | ] 88 | ], 89 | [ 90 | "tibdex/backport", 91 | [ 92 | "body_template", 93 | "head_template", 94 | "labels_template", 95 | "title_template" 96 | ] 97 | ] 98 | ] 99 | -------------------------------------------------------------------------------- /crates/zizmor/src/audit/secrets_inherit.rs: -------------------------------------------------------------------------------- 1 | use github_actions_models::workflow::job::Secrets; 2 | 3 | use super::{Audit, AuditLoadError, AuditState, audit_meta}; 4 | use crate::{finding::Confidence, models::JobExt as _}; 5 | 6 | pub(crate) struct SecretsInherit; 7 | 8 | audit_meta!( 9 | SecretsInherit, 10 | "secrets-inherit", 11 | "secrets unconditionally inherited by called workflow" 12 | ); 13 | 14 | impl Audit for SecretsInherit { 15 | fn new(_state: &AuditState<'_>) -> Result 16 | where 17 | Self: Sized, 18 | { 19 | Ok(Self) 20 | } 21 | 22 | fn audit_reusable_job<'doc>( 23 | &self, 24 | job: &super::ReusableWorkflowCallJob<'doc>, 25 | ) -> anyhow::Result>> { 26 | let mut findings = vec![]; 27 | 28 | if matches!(job.secrets, Some(Secrets::Inherit)) { 29 | findings.push( 30 | Self::finding() 31 | .add_location( 32 | job.location() 33 | .primary() 34 | .with_keys(&["uses".into()]) 35 | .annotated("this reusable workflow"), 36 | ) 37 | .add_location( 38 | job.location() 39 | .with_keys(&["secrets".into()]) 40 | .annotated("inherits all parent secrets"), 41 | ) 42 | .confidence(Confidence::High) 43 | .severity(crate::finding::Severity::Medium) 44 | .build(job.parent())?, 45 | ); 46 | } 47 | 48 | Ok(findings) 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /crates/zizmor/src/output/mod.rs: -------------------------------------------------------------------------------- 1 | pub(crate) mod github; 2 | pub(crate) mod plain; 3 | pub(crate) mod sarif; 4 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/main.rs: -------------------------------------------------------------------------------- 1 | // TODO: These modules could stand to be cleaned up a bit. 2 | 3 | /// Basic acceptance tests. 4 | mod acceptance; 5 | /// Helpers. 6 | mod common; 7 | /// "Big picture" end-to-end tests, i.e. tests that typically exercise 8 | /// more than one audit or complex CLI functionality. 9 | mod e2e; 10 | /// General snapshot tests, including repro cases for specific audits. 11 | mod snapshot; 12 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__e2e__invalid_config_file.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: tests/integration/e2e.rs 3 | expression: "zizmor().expects_failure(true).config(if cfg!(windows) { \"NUL\" } else\n{ \"/dev/null\" }).input(input_under_test(\"e2e-menagerie\")).run()?" 4 | snapshot_kind: text 5 | --- 6 | fatal: no audit was performed 7 | error: failed to load config: missing field `rules` 8 | = note: check your configuration file for errors 9 | = note: see: https://docs.zizmor.sh/configuration/ 10 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__e2e__invalid_inputs-10.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: tests/integration/e2e.rs 3 | expression: "zizmor().expects_failure(true).input(input_under_test(&format!(\"invalid/{workflow_tc}.yml\"))).args([\"--strict-inputs\"]).run()?" 4 | snapshot_kind: text 5 | --- 6 | fatal: no audit was performed 7 | failed to load input as Action 8 | 9 | Caused by: 10 | 0: input does not match expected validation schema 11 | 1: null is not of type "object" 12 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__e2e__invalid_inputs-2.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: tests/integration/e2e.rs 3 | expression: "zizmor().expects_failure(true).input(input_under_test(&format!(\"invalid/{workflow_tc}.yml\"))).args([\"--strict-inputs\"]).run()?" 4 | snapshot_kind: text 5 | --- 6 | fatal: no audit was performed 7 | failed to load input as Workflow 8 | 9 | Caused by: 10 | 0: input does not match expected validation schema 11 | 1: on.workflow_call.inputs.input: "type" is a required property 12 | Additional properties are not allowed ('boom' was unexpected) 13 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__e2e__invalid_inputs-3.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: tests/integration/e2e.rs 3 | expression: "zizmor().expects_failure(true).input(input_under_test(&format!(\"invalid/{workflow_tc}.yml\"))).args([\"--strict-inputs\"]).run()?" 4 | snapshot_kind: text 5 | --- 6 | fatal: no audit was performed 7 | failed to load input as Workflow 8 | 9 | Caused by: 10 | 0: input does not match expected validation schema 11 | 1: null is not of type "object" 12 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__e2e__invalid_inputs-4.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: tests/integration/e2e.rs 3 | expression: "zizmor().expects_failure(true).input(input_under_test(&format!(\"invalid/{workflow_tc}.yml\"))).args([\"--strict-inputs\"]).run()?" 4 | snapshot_kind: text 5 | --- 6 | fatal: no audit was performed 7 | failed to load input as Workflow 8 | 9 | Caused by: 10 | 0: input does not match expected validation schema 11 | 1: "lol" is not of type "object" 12 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__e2e__invalid_inputs-5.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: tests/integration/e2e.rs 3 | expression: "zizmor().expects_failure(true).input(input_under_test(&format!(\"invalid/{workflow_tc}.yml\"))).args([\"--strict-inputs\"]).run()?" 4 | snapshot_kind: text 5 | --- 6 | fatal: no audit was performed 7 | failed to load input as Workflow 8 | 9 | Caused by: 10 | 0: invalid YAML syntax: mapping values are not allowed in this context at line 3 column 8 11 | 1: mapping values are not allowed in this context at line 3 column 8 12 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__e2e__invalid_inputs-6.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: tests/integration/e2e.rs 3 | expression: "zizmor().expects_failure(true).input(input_under_test(&format!(\"invalid/{workflow_tc}.yml\"))).args([\"--strict-inputs\"]).run()?" 4 | snapshot_kind: text 5 | --- 6 | fatal: no audit was performed 7 | failed to load input as Workflow 8 | 9 | Caused by: 10 | 0: input does not match expected validation schema 11 | 1: null is not of type "object" 12 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__e2e__invalid_inputs-7.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: tests/integration/e2e.rs 3 | expression: "zizmor().expects_failure(true).input(input_under_test(&format!(\"invalid/{workflow_tc}.yml\"))).args([\"--strict-inputs\"]).run()?" 4 | snapshot_kind: text 5 | --- 6 | fatal: no audit was performed 7 | failed to load input as Workflow 8 | 9 | Caused by: 10 | 0: input does not match expected validation schema 11 | 1: null is not of type "object" 12 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__e2e__invalid_inputs-8.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: crates/zizmor/tests/integration/e2e.rs 3 | expression: "zizmor().expects_failure(true).input(input_under_test(&format!(\"invalid/{workflow_tc}.yml\"))).args([\"--strict-collection\"]).run()?" 4 | --- 5 | fatal: no audit was performed 6 | failed to load input as Action 7 | 8 | Caused by: 9 | 0: input does not match expected validation schema 10 | 1: runs: Additional properties are not allowed ('image' was unexpected) 11 | runs: "using" is a required property 12 | runs: "main" is a required property 13 | runs: Additional properties are not allowed ('image' was unexpected) 14 | runs: "using" is a required property 15 | runs: "steps" is a required property 16 | runs: "using" is a required property 17 | outputs.some-output: "value" is a required property 18 | "description" is a required property 19 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__e2e__invalid_inputs-9.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: tests/integration/e2e.rs 3 | expression: "zizmor().expects_failure(true).input(input_under_test(&format!(\"invalid/{workflow_tc}.yml\"))).args([\"--strict-inputs\"]).run()?" 4 | snapshot_kind: text 5 | --- 6 | fatal: no audit was performed 7 | failed to load input as Action 8 | 9 | Caused by: 10 | 0: invalid YAML syntax: mapping values are not allowed in this context at line 3 column 8 11 | 1: mapping values are not allowed in this context at line 3 column 8 12 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__e2e__invalid_inputs.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: crates/zizmor/tests/integration/e2e.rs 3 | expression: "zizmor().expects_failure(true).input(input_under_test(&format!(\"invalid/{workflow_tc}.yml\"))).args([\"--strict-collection\"]).run()?" 4 | --- 5 | fatal: no audit was performed 6 | failed to load input as Workflow 7 | 8 | Caused by: 9 | 0: input does not match expected validation schema 10 | 1: jobs.invalid: "runs-on" is a required property 11 | jobs.invalid: Additional properties are not allowed ('steps' was unexpected) 12 | jobs.invalid: "uses" is a required property 13 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__e2e__issue_612_repro.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: crates/zizmor/tests/integration/e2e.rs 3 | expression: "zizmor().input(input_under_test(\"issue-612-repro/action.yml\")).run()?" 4 | --- 5 | No findings to report. Good job! (2 ignored, 2 suppressed) 6 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__e2e__issue_726.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: tests/integration/e2e.rs 3 | expression: "zizmor().offline(false).output(OutputMode::Both).args([\"--no-online-audits\"]).input(\"woodruffw-experiments/zizmor-bug-726@a038d1a35\").run()?" 4 | --- 5 | INFO collect_inputs: zizmor: collected 6 inputs from woodruffw-experiments/zizmor-bug-726 6 | INFO zizmor: skipping impostor-commit: offline audits only requested 7 | INFO zizmor: skipping ref-confusion: offline audits only requested 8 | INFO zizmor: skipping known-vulnerable-actions: offline audits only requested 9 | INFO zizmor: skipping forbidden-uses: audit not configured 10 | INFO zizmor: skipping stale-action-refs: offline audits only requested 11 | INFO audit: zizmor: 🌈 completed .github/actions/custom-action/action.yml 12 | INFO audit: zizmor: 🌈 completed .github/workflows/actions/custom-action/action.yml 13 | INFO audit: zizmor: 🌈 completed .github/workflows/custom-action/action.yml 14 | INFO audit: zizmor: 🌈 completed .github/workflows/hello.yml 15 | INFO audit: zizmor: 🌈 completed arbitrary/subdir/.github/workflows/hello.yml 16 | INFO audit: zizmor: 🌈 completed arbitrary/subdir/custom-action/action.yml 17 | No findings to report. Good job! 18 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__e2e__menagerie-2.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: tests/integration/e2e.rs 3 | expression: "zizmor().output(OutputMode::Both).args([\"--collect=all\"]).input(input_under_test(\"e2e-menagerie\")).run()?" 4 | --- 5 | INFO zizmor: skipping impostor-commit: can't run without a GitHub API token 6 | INFO zizmor: skipping ref-confusion: can't run without a GitHub API token 7 | INFO zizmor: skipping known-vulnerable-actions: can't run without a GitHub API token 8 | INFO zizmor: skipping forbidden-uses: audit not configured 9 | INFO zizmor: skipping stale-action-refs: can't run without a GitHub API token 10 | INFO audit: zizmor: 🌈 completed @@INPUT@@/.github/dummy-action-2/action.yml 11 | INFO audit: zizmor: 🌈 completed @@INPUT@@/.github/workflows/another-dummy.yml 12 | INFO audit: zizmor: 🌈 completed @@INPUT@@/.github/workflows/dummy.yml 13 | INFO audit: zizmor: 🌈 completed @@INPUT@@/.github/workflows/ignored.yaml 14 | INFO audit: zizmor: 🌈 completed @@INPUT@@/dummy-action-1/action.yaml 15 | error[dangerous-triggers]: use of fundamentally insecure workflow trigger 16 | --> @@INPUT@@/.github/workflows/ignored.yaml:4:1 17 | | 18 | 4 | on: pull_request_target 19 | | ^^^^^^^^^^^^^^^^^^^^^^^ pull_request_target is almost always used insecurely 20 | | 21 | = note: audit confidence → Medium 22 | 23 | 1 finding: 0 unknown, 0 informational, 0 low, 0 medium, 1 high 24 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__e2e__menagerie.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: tests/integration/e2e.rs 3 | expression: "zizmor().output(OutputMode::Both).input(input_under_test(\"e2e-menagerie\")).run()?" 4 | --- 5 | INFO zizmor: skipping impostor-commit: can't run without a GitHub API token 6 | INFO zizmor: skipping ref-confusion: can't run without a GitHub API token 7 | INFO zizmor: skipping known-vulnerable-actions: can't run without a GitHub API token 8 | INFO zizmor: skipping forbidden-uses: audit not configured 9 | INFO zizmor: skipping stale-action-refs: can't run without a GitHub API token 10 | INFO audit: zizmor: 🌈 completed @@INPUT@@/.github/dummy-action-2/action.yml 11 | INFO audit: zizmor: 🌈 completed @@INPUT@@/.github/workflows/another-dummy.yml 12 | INFO audit: zizmor: 🌈 completed @@INPUT@@/.github/workflows/dummy.yml 13 | INFO audit: zizmor: 🌈 completed @@INPUT@@/dummy-action-1/action.yaml 14 | No findings to report. Good job! 15 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__snapshot__artipacked-2.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: tests/integration/snapshot.rs 3 | expression: "zizmor().input(input_under_test(\"artipacked.yml\")).run()?" 4 | --- 5 | warning[artipacked]: credential persistence through GitHub Actions artifacts 6 | --> @@INPUT@@:15:9 7 | | 8 | 15 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # tag=v4.2.2 9 | | ---------------------------------------------------------------------------- does not set persist-credentials: false 10 | | 11 | = note: audit confidence → Low 12 | 13 | 2 findings (1 suppressed): 0 unknown, 0 informational, 0 low, 1 medium, 0 high 14 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__snapshot__artipacked-3.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: tests/integration/snapshot.rs 3 | expression: "zizmor().input(input_under_test(\"artipacked.yml\")).args([\"--persona=auditor\"]).run()?" 4 | --- 5 | warning[artipacked]: credential persistence through GitHub Actions artifacts 6 | --> @@INPUT@@:15:9 7 | | 8 | 15 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # tag=v4.2.2 9 | | ---------------------------------------------------------------------------- does not set persist-credentials: false 10 | | 11 | = note: audit confidence → Low 12 | 13 | warning[artipacked]: credential persistence through GitHub Actions artifacts 14 | --> @@INPUT@@:20:9 15 | | 16 | 20 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # tag=v4.2.2 17 | | _________- 18 | 21 | | with: 19 | 22 | | persist-credentials: true 20 | | |____________________________________- does not set persist-credentials: false 21 | | 22 | = note: audit confidence → Low 23 | 24 | 2 findings: 0 unknown, 0 informational, 0 low, 2 medium, 0 high 25 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__snapshot__artipacked-4.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: tests/integration/snapshot.rs 3 | expression: "zizmor().input(input_under_test(\"artipacked/issue-447-repro.yml\")).args([\"--persona=auditor\"]).run()?" 4 | --- 5 | warning[artipacked]: credential persistence through GitHub Actions artifacts 6 | --> @@INPUT@@:19:9 7 | | 8 | 19 | - name: true-positive 9 | | _________- 10 | 20 | | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 11 | 21 | | with: 12 | 22 | | # finding in auditor mode only 13 | 23 | | persist-credentials: "true" 14 | | |______________________________________- does not set persist-credentials: false 15 | | 16 | = note: audit confidence → Low 17 | 18 | 1 finding: 0 unknown, 0 informational, 0 low, 1 medium, 0 high 19 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__snapshot__artipacked.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: tests/integration/snapshot.rs 3 | expression: "zizmor().input(input_under_test(\"artipacked.yml\")).args([\"--persona=pedantic\"]).run()?" 4 | --- 5 | warning[artipacked]: credential persistence through GitHub Actions artifacts 6 | --> @@INPUT@@:15:9 7 | | 8 | 15 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # tag=v4.2.2 9 | | ---------------------------------------------------------------------------- does not set persist-credentials: false 10 | | 11 | = note: audit confidence → Low 12 | 13 | 2 findings (1 suppressed): 0 unknown, 0 informational, 0 low, 1 medium, 0 high 14 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__snapshot__bot_conditions.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: tests/integration/snapshot.rs 3 | expression: "zizmor().input(input_under_test(\"bot-conditions.yml\")).run()?" 4 | --- 5 | error[dangerous-triggers]: use of fundamentally insecure workflow trigger 6 | --> @@INPUT@@:1:1 7 | | 8 | 1 | on: pull_request_target 9 | | ^^^^^^^^^^^^^^^^^^^^^^^ pull_request_target is almost always used insecurely 10 | | 11 | = note: audit confidence → Medium 12 | 13 | error[bot-conditions]: spoofable bot actor check 14 | --> @@INPUT@@:8:5 15 | | 16 | 8 | if: github.actor == 'dependabot[bot]' 17 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ actor context may be spoofable 18 | | 19 | = note: audit confidence → High 20 | 21 | error[bot-conditions]: spoofable bot actor check 22 | --> @@INPUT@@:12:9 23 | | 24 | 12 | if: ${{ github.actor == 'dependabot[bot]' }} 25 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ actor context may be spoofable 26 | | 27 | = note: audit confidence → High 28 | 29 | error[bot-conditions]: spoofable bot actor check 30 | --> @@INPUT@@:16:9 31 | | 32 | 16 | if: ${{ github.actor == 'dependabot[bot]' && github.repository == 'example/example' }} 33 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ actor context may be spoofable 34 | | 35 | = note: audit confidence → Medium 36 | 37 | error[bot-conditions]: spoofable bot actor check 38 | --> @@INPUT@@:20:9 39 | | 40 | 20 | if: github.actor == 'renovate[bot]' 41 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ actor context may be spoofable 42 | | 43 | = note: audit confidence → High 44 | 45 | 5 findings: 0 unknown, 0 informational, 0 low, 0 medium, 5 high 46 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__snapshot__cache_poisoning-10.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: tests/integration/snapshot.rs 3 | expression: "zizmor().input(input_under_test(\"cache-poisoning/publisher-step.yml\")).run()?" 4 | --- 5 | error[cache-poisoning]: runtime artifacts potentially vulnerable to a cache poisoning attack 6 | --> @@INPUT@@:25:9 7 | | 8 | 18 | uses: Swatinem/rust-cache@82a92a6e8fbeee089604da2575dc567ae9ddeaab 9 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cache enabled by default here 10 | 19 | 11 | ... 12 | 24 | - name: Publish draft release on Github 13 | 25 | uses: softprops/action-gh-release@01570a1f39cb168c169c802c3bceb9e93fb10974 14 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ runtime artifacts usually published here 15 | | 16 | = note: audit confidence → Low 17 | 18 | 1 finding: 0 unknown, 0 informational, 0 low, 0 medium, 1 high 19 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__snapshot__cache_poisoning-12.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: crates/zizmor/tests/integration/snapshot.rs 3 | expression: "zizmor().input(input_under_test(\"cache-poisoning/caching-not-configurable.yml\")).run()?" 4 | --- 5 | error[cache-poisoning]: runtime artifacts potentially vulnerable to a cache poisoning attack 6 | --> @@INPUT@@:1:1 7 | | 8 | 1 | / on: 9 | 2 | | push: 10 | 3 | | tags: 11 | 4 | | - "**" 12 | | |____________^ generally used when publishing artifacts generated at runtime 13 | 5 | 14 | ... 15 | 17 | - name: Setup CI caching 16 | 18 | uses: Mozilla-Actions/sccache-action@054db53350805f83040bf3e6e9b8cf5a139aa7c9 17 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ caching always restored here 18 | | 19 | = note: audit confidence → Low 20 | 21 | 2 findings (1 suppressed): 0 unknown, 0 informational, 0 low, 0 medium, 1 high 22 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__snapshot__cache_poisoning-13.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: crates/zizmor/tests/integration/snapshot.rs 3 | expression: "zizmor().input(input_under_test(\"cache-poisoning/workflow-release-branch-trigger.yml\")).run()?" 4 | --- 5 | error[cache-poisoning]: runtime artifacts potentially vulnerable to a cache poisoning attack 6 | --> @@INPUT@@:1:1 7 | | 8 | 1 | / on: 9 | 2 | | push: 10 | 3 | | branches: 11 | 4 | | - "release-v2.0.0" 12 | | |________________________^ generally used when publishing artifacts generated at runtime 13 | 5 | 14 | ... 15 | 17 | - name: Setup CI caching 16 | 18 | uses: Swatinem/rust-cache@82a92a6e8fbeee089604da2575dc567ae9ddeaab 17 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cache enabled by default here 18 | | 19 | = note: audit confidence → Low 20 | 21 | 2 findings (1 suppressed): 0 unknown, 0 informational, 0 low, 0 medium, 1 high 22 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__snapshot__cache_poisoning-14.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: tests/integration/snapshot.rs 3 | expression: "zizmor().input(input_under_test(\"cache-poisoning/issue-378-repro.yml\")).run()?" 4 | --- 5 | No findings to report. Good job! 6 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__snapshot__cache_poisoning-15.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: tests/integration/snapshot.rs 3 | expression: "zizmor().input(input_under_test(\"cache-poisoning/issue-642-repro.yml\")).run()?" 4 | --- 5 | error[cache-poisoning]: runtime artifacts potentially vulnerable to a cache poisoning attack 6 | --> @@INPUT@@:20:9 7 | | 8 | 15 | / with: 9 | 16 | | cache-binary: true 10 | 17 | | version: latest 11 | | |_________________________^ opt-in for caching here 12 | 18 | 13 | 19 | - name: Build docker 14 | 20 | uses: docker/build-push-action@48aba3b46d1b1fec4febb7c5d0c644b249a11355 15 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ runtime artifacts usually published here 16 | | 17 | = note: audit confidence → Low 18 | 19 | 1 finding: 0 unknown, 0 informational, 0 low, 0 medium, 1 high 20 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__snapshot__cache_poisoning-2.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: crates/zizmor/tests/integration/snapshot.rs 3 | expression: "zizmor().input(input_under_test(\"cache-poisoning/caching-enabled-by-default.yml\")).run()?" 4 | --- 5 | error[cache-poisoning]: runtime artifacts potentially vulnerable to a cache poisoning attack 6 | --> @@INPUT@@:1:1 7 | | 8 | 1 | on: release 9 | | ^^^^^^^^^^^ generally used when publishing artifacts generated at runtime 10 | 2 | 11 | ... 12 | 15 | - name: Setup CI caching 13 | 16 | uses: Swatinem/rust-cache@82a92a6e8fbeee089604da2575dc567ae9ddeaab 14 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cache enabled by default here 15 | | 16 | = note: audit confidence → Low 17 | 18 | 2 findings (1 suppressed): 0 unknown, 0 informational, 0 low, 0 medium, 1 high 19 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__snapshot__cache_poisoning-3.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: crates/zizmor/tests/integration/snapshot.rs 3 | expression: "zizmor().input(input_under_test(\"cache-poisoning/caching-opt-in-boolean-toggle.yml\")).run()?" 4 | --- 5 | error[cache-poisoning]: runtime artifacts potentially vulnerable to a cache poisoning attack 6 | --> @@INPUT@@:1:1 7 | | 8 | 1 | on: release 9 | | ^^^^^^^^^^^ generally used when publishing artifacts generated at runtime 10 | 2 | 11 | ... 12 | 15 | uses: actions/setup-dotnet@3e891b0cb619bf60e2c25674b222b8940e2c1c25 13 | 16 | / with: 14 | 17 | | dotnet-version: "5.0.x" 15 | 18 | | cache: true 16 | | |_____________________^ opt-in for caching here 17 | | 18 | = note: audit confidence → Low 19 | 20 | 2 findings (1 suppressed): 0 unknown, 0 informational, 0 low, 0 medium, 1 high 21 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__snapshot__cache_poisoning-4.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: tests/integration/snapshot.rs 3 | expression: "zizmor().input(input_under_test(\"cache-poisoning/caching-opt-in-expression.yml\")).run()?" 4 | --- 5 | error[cache-poisoning]: runtime artifacts potentially vulnerable to a cache poisoning attack 6 | --> @@INPUT@@:1:1 7 | | 8 | 1 | on: release 9 | | ^^^^^^^^^^^ generally used when publishing artifacts generated at runtime 10 | 2 | 11 | ... 12 | 15 | uses: astral-sh/setup-uv@38f3f104447c67c051c4a08e39b64a148898af3a 13 | 16 | / with: 14 | 17 | | python-version: "3.12" 15 | 18 | | enable-cache: ${{ github.ref == 'refs/heads/main' }} 16 | | |______________________________________________________________^ opt-in for caching might happen here 17 | | 18 | = note: audit confidence → Low 19 | 20 | 1 finding: 0 unknown, 0 informational, 0 low, 0 medium, 1 high 21 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__snapshot__cache_poisoning-5.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: tests/integration/snapshot.rs 3 | expression: "zizmor().input(input_under_test(\"cache-poisoning/caching-opt-in-multi-value-toggle.yml\")).run()?" 4 | --- 5 | error[cache-poisoning]: runtime artifacts potentially vulnerable to a cache poisoning attack 6 | --> @@INPUT@@:1:1 7 | | 8 | 1 | on: release 9 | | ^^^^^^^^^^^ generally used when publishing artifacts generated at runtime 10 | 2 | 11 | ... 12 | 15 | uses: actions/setup-java@8df1039502a15bceb9433410b1a100fbe190c53b 13 | 16 | / with: 14 | 17 | | distribution: "zulu" 15 | 18 | | cache: "gradle" 16 | 19 | | java-version: "17" 17 | | |____________________________^ opt-in for caching here 18 | | 19 | = note: audit confidence → Low 20 | 21 | 1 finding: 0 unknown, 0 informational, 0 low, 0 medium, 1 high 22 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__snapshot__cache_poisoning-6.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: crates/zizmor/tests/integration/snapshot.rs 3 | expression: "zizmor().input(input_under_test(\"cache-poisoning/caching-opt-out.yml\")).run()?" 4 | --- 5 | No findings to report. Good job! (1 suppressed) 6 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__snapshot__cache_poisoning-7.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: crates/zizmor/tests/integration/snapshot.rs 3 | expression: "zizmor().input(input_under_test(\"cache-poisoning/no-cache-aware-steps.yml\")).run()?" 4 | --- 5 | No findings to report. Good job! (1 suppressed) 6 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__snapshot__cache_poisoning-8.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: crates/zizmor/tests/integration/snapshot.rs 3 | expression: "zizmor().input(input_under_test(\"cache-poisoning/workflow-tag-trigger.yml\")).run()?" 4 | --- 5 | error[cache-poisoning]: runtime artifacts potentially vulnerable to a cache poisoning attack 6 | --> @@INPUT@@:1:1 7 | | 8 | 1 | / on: 9 | 2 | | push: 10 | 3 | | tags: 11 | 4 | | - "**" 12 | | |____________^ generally used when publishing artifacts generated at runtime 13 | 5 | 14 | ... 15 | 17 | - name: Setup CI caching 16 | 18 | uses: Swatinem/rust-cache@82a92a6e8fbeee089604da2575dc567ae9ddeaab 17 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cache enabled by default here 18 | | 19 | = note: audit confidence → Low 20 | 21 | 2 findings (1 suppressed): 0 unknown, 0 informational, 0 low, 0 medium, 1 high 22 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__snapshot__cache_poisoning-9.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: tests/integration/snapshot.rs 3 | expression: "zizmor().input(input_under_test(\"cache-poisoning/caching-opt-in-boolish-toggle.yml\")).run()?" 4 | --- 5 | error[cache-poisoning]: runtime artifacts potentially vulnerable to a cache poisoning attack 6 | --> @@INPUT@@:4:1 7 | | 8 | 4 | on: release 9 | | ^^^^^^^^^^^ generally used when publishing artifacts generated at runtime 10 | 5 | 11 | ... 12 | 14 | uses: PyO3/maturin-action@ea5bac0f1ccd0ab11c805e2b804bfcb65dac2eab # v1 13 | 15 | / with: 14 | 16 | | target: ${{ matrix.platform.target }} 15 | 17 | | args: --release --out dist 16 | 18 | | sccache: "true" 17 | | |__________________________^ opt-in for caching here 18 | | 19 | = note: audit confidence → Low 20 | 21 | 1 finding: 0 unknown, 0 informational, 0 low, 0 medium, 1 high 22 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__snapshot__cache_poisoning.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: tests/integration/snapshot.rs 3 | expression: "zizmor().input(input_under_test(\"cache-poisoning/caching-disabled-by-default.yml\")).run()?" 4 | --- 5 | No findings to report. Good job! 6 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__snapshot__cant_retrieve.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: tests/integration/snapshot.rs 3 | expression: "zizmor().expects_failure(true).offline(true).unsetenv(\"GH_TOKEN\").args([\"pypa/sampleproject\"]).run()?" 4 | --- 5 | fatal: no audit was performed 6 | error: can't retrieve repository: pypa/sampleproject 7 | = note: try removing --offline or passing --gh-token 8 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__snapshot__excessive_permissions-10.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: tests/integration/snapshot.rs 3 | expression: "zizmor().input(input_under_test(\"excessive-permissions/issue-472-repro.yml\")).run()?" 4 | --- 5 | warning[excessive-permissions]: overly broad permissions 6 | --> @@INPUT@@:19:3 7 | | 8 | 19 | / job2: 9 | 20 | | # normal permissions finding here, since callers are always 10 | 21 | | # responsible for setting permissions, even if the workflow 11 | 22 | | # is reusable-only 12 | 23 | | uses: ./.github/workflows/fake.yml 13 | | | - 14 | | |_______________________________________| 15 | | this job 16 | | default permissions used due to no permissions: block 17 | | 18 | = note: audit confidence → Medium 19 | 20 | 3 findings (2 suppressed): 0 unknown, 0 informational, 0 low, 1 medium, 0 high 21 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__snapshot__excessive_permissions-11.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: tests/integration/snapshot.rs 3 | expression: "zizmor().input(input_under_test(\"excessive-permissions/reusable-workflow-call.yml\")).run()?" 4 | --- 5 | warning[excessive-permissions]: overly broad permissions 6 | --> @@INPUT@@:7:3 7 | | 8 | 7 | / job1: 9 | 8 | | # finding: reusable jobs should always specify their permissions 10 | 9 | | uses: ./.github/workflows/zizmor-child.yml 11 | | | - 12 | | |_______________________________________________| 13 | | this job 14 | | default permissions used due to no permissions: block 15 | | 16 | = note: audit confidence → Medium 17 | 18 | 2 findings (1 suppressed): 0 unknown, 0 informational, 0 low, 1 medium, 0 high 19 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__snapshot__excessive_permissions-12.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: tests/integration/snapshot.rs 3 | expression: "zizmor().input(input_under_test(\"excessive-permissions/reusable-workflow-other-triggers.yml\")).run()?" 4 | --- 5 | warning[excessive-permissions]: overly broad permissions 6 | --> @@INPUT@@:1:1 7 | | 8 | 1 | / name: reusable-workflow-other-triggers 9 | 2 | | 10 | ... | 11 | 20 | | # responsible for setting permissions 12 | 21 | | uses: ./.github/workflows/fake.yml 13 | | |_______________________________________- default permissions used due to no permissions: block 14 | | 15 | = note: audit confidence → Medium 16 | 17 | warning[excessive-permissions]: overly broad permissions 18 | --> @@INPUT@@:11:3 19 | | 20 | 11 | / job1: 21 | 12 | | # regular job-level finding, since we can be triggered by 22 | ... | 23 | 15 | | steps: 24 | 16 | | - run: echo hello 25 | | | - 26 | | |_______________________| 27 | | this job 28 | | default permissions used due to no permissions: block 29 | | 30 | = note: audit confidence → Medium 31 | 32 | warning[excessive-permissions]: overly broad permissions 33 | --> @@INPUT@@:18:3 34 | | 35 | 18 | / job2: 36 | 19 | | # normal permissions finding here, since callers are always 37 | 20 | | # responsible for setting permissions 38 | 21 | | uses: ./.github/workflows/fake.yml 39 | | | - 40 | | |_______________________________________| 41 | | this job 42 | | default permissions used due to no permissions: block 43 | | 44 | = note: audit confidence → Medium 45 | 46 | 3 findings: 0 unknown, 0 informational, 0 low, 3 medium, 0 high 47 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__snapshot__excessive_permissions-2.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: tests/integration/snapshot.rs 3 | expression: "zizmor().input(input_under_test(\"excessive-permissions/issue-336-repro.yml\")).args([\"--pedantic\"]).run()?" 4 | --- 5 | error[excessive-permissions]: overly broad permissions 6 | --> @@INPUT@@:4:3 7 | | 8 | 4 | contents: write 9 | | ^^^^^^^^^^^^^^^ contents: write is overly broad at the workflow level 10 | | 11 | = note: audit confidence → High 12 | 13 | 1 finding: 0 unknown, 0 informational, 0 low, 0 medium, 1 high 14 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__snapshot__excessive_permissions-3.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: tests/integration/snapshot.rs 3 | expression: "zizmor().input(input_under_test(\"excessive-permissions/workflow-default-perms.yml\")).args([\"--pedantic\"]).run()?" 4 | --- 5 | warning[excessive-permissions]: overly broad permissions 6 | --> @@INPUT@@:1:1 7 | | 8 | 1 | / # two findings in pedantic mode: one for the entire workflow for having 9 | 2 | | # implicit permissions (pedantic), and one for the 'single' job for having 10 | ... | 11 | 12 | | with: 12 | 13 | | persist-credentials: false 13 | | |_____________________________________- default permissions used due to no permissions: block 14 | | 15 | = note: audit confidence → Medium 16 | 17 | warning[excessive-permissions]: overly broad permissions 18 | --> @@INPUT@@:8:3 19 | | 20 | 8 | / single: 21 | 9 | | runs-on: ubuntu-latest 22 | ... | 23 | 12 | | with: 24 | 13 | | persist-credentials: false 25 | | | - 26 | | |_____________________________________| 27 | | this job 28 | | default permissions used due to no permissions: block 29 | | 30 | = note: audit confidence → Medium 31 | 32 | 2 findings: 0 unknown, 0 informational, 0 low, 2 medium, 0 high 33 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__snapshot__excessive_permissions-4.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: tests/integration/snapshot.rs 3 | expression: "zizmor().input(input_under_test(\"excessive-permissions/workflow-read-all.yml\")).run()?" 4 | --- 5 | warning[excessive-permissions]: overly broad permissions 6 | --> @@INPUT@@:3:1 7 | | 8 | 3 | permissions: read-all 9 | | --------------------- uses read-all permissions 10 | | 11 | = note: audit confidence → High 12 | 13 | 1 finding: 0 unknown, 0 informational, 0 low, 1 medium, 0 high 14 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__snapshot__excessive_permissions-5.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: tests/integration/snapshot.rs 3 | expression: "zizmor().input(input_under_test(\"excessive-permissions/workflow-write-all.yml\")).run()?" 4 | --- 5 | error[excessive-permissions]: overly broad permissions 6 | --> @@INPUT@@:3:1 7 | | 8 | 3 | permissions: write-all 9 | | ^^^^^^^^^^^^^^^^^^^^^^ uses write-all permissions 10 | | 11 | = note: audit confidence → High 12 | 13 | 1 finding: 0 unknown, 0 informational, 0 low, 0 medium, 1 high 14 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__snapshot__excessive_permissions-6.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: tests/integration/snapshot.rs 3 | expression: "zizmor().input(input_under_test(\"excessive-permissions/workflow-empty-perms.yml\")).run()?" 4 | --- 5 | No findings to report. Good job! 6 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__snapshot__excessive_permissions-7.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: tests/integration/snapshot.rs 3 | expression: "zizmor().input(input_under_test(\"excessive-permissions/jobs-broaden-permissions.yml\")).run()?" 4 | --- 5 | warning[excessive-permissions]: overly broad permissions 6 | --> @@INPUT@@:6:3 7 | | 8 | 6 | / job1: 9 | 7 | | runs-on: ubuntu-latest 10 | 8 | | permissions: read-all 11 | | | --------------------- uses read-all permissions 12 | 9 | | steps: 13 | 10 | | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 14 | 11 | | with: 15 | 12 | | persist-credentials: false 16 | | |____________________________________- this job 17 | | 18 | = note: audit confidence → High 19 | 20 | error[excessive-permissions]: overly broad permissions 21 | --> @@INPUT@@:14:3 22 | | 23 | 14 | / job2: 24 | 15 | | runs-on: ubuntu-latest 25 | 16 | | permissions: write-all 26 | | | ^^^^^^^^^^^^^^^^^^^^^^ uses write-all permissions 27 | 17 | | steps: 28 | 18 | | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 29 | 19 | | with: 30 | 20 | | persist-credentials: false 31 | | |_____________________________________^ this job 32 | | 33 | = note: audit confidence → High 34 | 35 | 2 findings: 0 unknown, 0 informational, 0 low, 1 medium, 1 high 36 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__snapshot__excessive_permissions-8.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: tests/integration/snapshot.rs 3 | expression: "zizmor().input(input_under_test(\"excessive-permissions/workflow-write-explicit.yml\")).run()?" 4 | --- 5 | error[excessive-permissions]: overly broad permissions 6 | --> @@INPUT@@:5:3 7 | | 8 | 5 | contents: write 9 | | ^^^^^^^^^^^^^^^ contents: write is overly broad at the workflow level 10 | | 11 | = note: audit confidence → High 12 | 13 | error[excessive-permissions]: overly broad permissions 14 | --> @@INPUT@@:6:3 15 | | 16 | 6 | id-token: write 17 | | ^^^^^^^^^^^^^^^ id-token: write is overly broad at the workflow level 18 | | 19 | = note: audit confidence → High 20 | 21 | note[excessive-permissions]: overly broad permissions 22 | --> @@INPUT@@:7:3 23 | | 24 | 7 | nonexistent: write 25 | | ------------------ note: nonexistent: write is overly broad at the workflow level 26 | | 27 | = note: audit confidence → High 28 | 29 | 3 findings: 1 unknown, 0 informational, 0 low, 0 medium, 2 high 30 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__snapshot__excessive_permissions-9.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: tests/integration/snapshot.rs 3 | expression: "zizmor().input(input_under_test(\"excessive-permissions/workflow-default-perms-all-jobs-explicit.yml\")).run()?" 4 | --- 5 | No findings to report. Good job! (1 suppressed) 6 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__snapshot__excessive_permissions.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: tests/integration/snapshot.rs 3 | expression: "zizmor().input(input_under_test(\"excessive-permissions/issue-336-repro.yml\")).run()?" 4 | --- 5 | No findings to report. Good job! (1 suppressed) 6 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__snapshot__forbidden_uses-2.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: tests/integration/snapshot.rs 3 | expression: "zizmor().config(input_under_test(&format!(\"forbidden-uses/configs/{config}.yml\"))).input(input_under_test(\"forbidden-uses/forbidden-uses-menagerie.yml\")).run()?" 4 | --- 5 | error[forbidden-uses]: forbidden action used 6 | --> @@INPUT@@:12:9 7 | | 8 | 12 | - uses: actions/setup-python@v4 9 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ use of this action is forbidden 10 | | 11 | = note: audit confidence → High 12 | 13 | error[forbidden-uses]: forbidden action used 14 | --> @@INPUT@@:13:9 15 | | 16 | 13 | - uses: pypa/gh-action-pypi-publish@release/v1 17 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ use of this action is forbidden 18 | | 19 | = note: audit confidence → High 20 | 21 | error[forbidden-uses]: forbidden action used 22 | --> @@INPUT@@:14:9 23 | | 24 | 14 | - uses: actions/checkout@v4 25 | | ^^^^^^^^^^^^^^^^^^^^^^^^^ use of this action is forbidden 26 | | 27 | = note: audit confidence → High 28 | 29 | 3 findings: 0 unknown, 0 informational, 0 low, 0 medium, 3 high 30 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__snapshot__forbidden_uses-3.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: tests/integration/snapshot.rs 3 | expression: "zizmor().config(input_under_test(&format!(\"forbidden-uses/configs/{config}.yml\"))).input(input_under_test(\"forbidden-uses/forbidden-uses-menagerie.yml\")).run()?" 4 | --- 5 | error[forbidden-uses]: forbidden action used 6 | --> @@INPUT@@:12:9 7 | | 8 | 12 | - uses: actions/setup-python@v4 9 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ use of this action is forbidden 10 | | 11 | = note: audit confidence → High 12 | 13 | 1 finding: 0 unknown, 0 informational, 0 low, 0 medium, 1 high 14 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__snapshot__forbidden_uses-4.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: tests/integration/snapshot.rs 3 | expression: "zizmor().config(input_under_test(&format!(\"forbidden-uses/configs/{config}.yml\"))).input(input_under_test(\"forbidden-uses/forbidden-uses-menagerie.yml\")).run()?" 4 | --- 5 | error[forbidden-uses]: forbidden action used 6 | --> @@INPUT@@:13:9 7 | | 8 | 13 | - uses: pypa/gh-action-pypi-publish@release/v1 9 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ use of this action is forbidden 10 | | 11 | = note: audit confidence → High 12 | 13 | error[forbidden-uses]: forbidden action used 14 | --> @@INPUT@@:14:9 15 | | 16 | 14 | - uses: actions/checkout@v4 17 | | ^^^^^^^^^^^^^^^^^^^^^^^^^ use of this action is forbidden 18 | | 19 | = note: audit confidence → High 20 | 21 | 2 findings: 0 unknown, 0 informational, 0 low, 0 medium, 2 high 22 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__snapshot__forbidden_uses-5.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: tests/integration/snapshot.rs 3 | expression: "zizmor().config(input_under_test(&format!(\"forbidden-uses/configs/{config}.yml\"))).input(input_under_test(\"forbidden-uses/forbidden-uses-menagerie.yml\")).run()?" 4 | snapshot_kind: text 5 | --- 6 | error[forbidden-uses]: forbidden action used 7 | --> @@INPUT@@:12:9 8 | | 9 | 12 | - uses: actions/setup-python@v4 10 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ use of this action is forbidden 11 | | 12 | = note: audit confidence → High 13 | 14 | error[forbidden-uses]: forbidden action used 15 | --> @@INPUT@@:13:9 16 | | 17 | 13 | - uses: pypa/gh-action-pypi-publish@release/v1 18 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ use of this action is forbidden 19 | | 20 | = note: audit confidence → High 21 | 22 | 2 findings: 0 unknown, 0 informational, 0 low, 0 medium, 2 high 23 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__snapshot__forbidden_uses-6.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: tests/integration/snapshot.rs 3 | expression: "zizmor().config(input_under_test(&format!(\"forbidden-uses/configs/{config}.yml\"))).input(input_under_test(\"forbidden-uses/forbidden-uses-menagerie.yml\")).run()?" 4 | snapshot_kind: text 5 | --- 6 | error[forbidden-uses]: forbidden action used 7 | --> @@INPUT@@:14:9 8 | | 9 | 14 | - uses: actions/checkout@v4 10 | | ^^^^^^^^^^^^^^^^^^^^^^^^^ use of this action is forbidden 11 | | 12 | = note: audit confidence → High 13 | 14 | 1 finding: 0 unknown, 0 informational, 0 low, 0 medium, 1 high 15 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__snapshot__forbidden_uses.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: tests/integration/snapshot.rs 3 | expression: "zizmor().config(input_under_test(&format!(\"forbidden-uses/configs/{config}.yml\"))).input(input_under_test(\"forbidden-uses/forbidden-uses-menagerie.yml\")).run()?" 4 | --- 5 | No findings to report. Good job! 6 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__snapshot__github_env-2.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: tests/integration/snapshot.rs 3 | expression: "zizmor().input(input_under_test(\"github-env/github-path.yml\")).run()?" 4 | --- 5 | error[github-env]: dangerous use of environment file 6 | --> @@INPUT@@:14:9 7 | | 8 | 14 | / run: | 9 | 15 | | message=$(echo "$TITLE" | grep -oP '[{\[][^}\]]+[}\]]' | sed 's/{\|}\|\[\|\]//g') 10 | 16 | | echo "$message" >> $GITHUB_PATH 11 | | |__________________________________________^ write to GITHUB_PATH may allow code execution 12 | | 13 | = note: audit confidence → Low 14 | 15 | 2 findings (1 ignored): 0 unknown, 0 informational, 0 low, 0 medium, 1 high 16 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__snapshot__github_env-3.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: tests/integration/snapshot.rs 3 | expression: "zizmor().input(input_under_test(\"github-env/issue-397-repro.yml\")).run()?" 4 | --- 5 | error[github-env]: dangerous use of environment file 6 | --> @@INPUT@@:14:9 7 | | 8 | 14 | / run: | 9 | 15 | | message=$(echo "$TITLE" | grep -oP '[{\[][^}\]]+[}\]]' | sed 's/{\|}\|\[\|\]//g') 10 | 16 | | echo "$message" >> $GITHUB_PATH 11 | | |_________________________________________^ write to GITHUB_PATH may allow code execution 12 | | 13 | = note: audit confidence → Low 14 | 15 | 2 findings (1 ignored): 0 unknown, 0 informational, 0 low, 0 medium, 1 high 16 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__snapshot__github_env.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: tests/integration/snapshot.rs 3 | expression: "zizmor().input(input_under_test(\"github-env/action.yml\")).run()?" 4 | --- 5 | error[github-env]: dangerous use of environment file 6 | --> @@INPUT@@:10:7 7 | | 8 | 10 | / run: | 9 | 11 | | echo "foo=$(bar)" >> $GITHUB_ENV 10 | | |________________________________________^ write to GITHUB_ENV may allow code execution 11 | | 12 | = note: audit confidence → Low 13 | 14 | error[github-env]: dangerous use of environment file 15 | --> @@INPUT@@:15:7 16 | | 17 | 15 | / run: | 18 | 16 | | echo "foo=$env:BAR" >> $env:GITHUB_ENV 19 | | |______________________________________________^ write to $env:GITHUB_ENV may allow code execution 20 | | 21 | = note: audit confidence → Low 22 | 23 | error[github-env]: dangerous use of environment file 24 | --> @@INPUT@@:20:7 25 | | 26 | 20 | / run: | 27 | 21 | | echo LIBRARY=%LIBRARY% >> %GITHUB_ENV% 28 | | |______________________________________________^ write to GITHUB_ENV may allow code execution 29 | | 30 | = note: audit confidence → Low 31 | 32 | 3 findings: 0 unknown, 0 informational, 0 low, 0 medium, 3 high 33 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__snapshot__github_output.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: crates/zizmor/tests/integration/snapshot.rs 3 | expression: "zizmor().offline(true).input(input_under_test(\"several-vulnerabilities.yml\")).args([\"--persona=auditor\",\n\"--format=github\"]).run()?" 4 | --- 5 | ::error file=@@INPUT@@,line=5,title=excessive-permissions::several-vulnerabilities.yml:5: overly broad permissions: uses write-all permissions 6 | ::error file=@@INPUT@@,line=11,title=excessive-permissions::several-vulnerabilities.yml:11: overly broad permissions: uses write-all permissions 7 | ::error file=@@INPUT@@,line=2,title=dangerous-triggers::several-vulnerabilities.yml:2: use of fundamentally insecure workflow trigger: pull_request_target is almost always used insecurely 8 | ::notice file=@@INPUT@@,line=15,title=template-injection::several-vulnerabilities.yml:15: code injection via template expansion: ${{ github.event.pull_request.title }} may expand into attacker-controllable code 9 | ::error file=@@INPUT@@,line=15,title=template-injection::several-vulnerabilities.yml:15: code injection via template expansion: github.event.pull_request.title may expand into attacker-controllable code 10 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__snapshot__insecure_commands-2.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: crates/zizmor/tests/integration/snapshot.rs 3 | expression: "zizmor().input(input_under_test(\"insecure-commands.yml\")).run()?" 4 | --- 5 | error[insecure-commands]: execution of insecure workflow commands is enabled 6 | --> @@INPUT@@:10:5 7 | | 8 | 10 | / env: 9 | 11 | | ACTIONS_ALLOW_UNSECURE_COMMANDS: true 10 | | |___________________________________________^ insecure commands enabled here 11 | | 12 | = note: audit confidence → High 13 | 14 | 2 findings (1 suppressed): 0 unknown, 0 informational, 0 low, 0 medium, 1 high 15 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__snapshot__insecure_commands-3.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: crates/zizmor/tests/integration/snapshot.rs 3 | expression: "zizmor().input(input_under_test(\"insecure-commands/action.yml\")).args([\"--persona=auditor\"]).run()?" 4 | --- 5 | error[insecure-commands]: execution of insecure workflow commands is enabled 6 | --> @@INPUT@@:18:7 7 | | 8 | 18 | / env: 9 | 19 | | ACTIONS_ALLOW_UNSECURE_COMMANDS: true 10 | | |_____________________________________________^ insecure commands enabled here 11 | | 12 | = note: audit confidence → High 13 | 14 | error[insecure-commands]: execution of insecure workflow commands is enabled 15 | --> @@INPUT@@:25:7 16 | | 17 | 25 | / env: 18 | 26 | | ACTIONS_ALLOW_UNSECURE_COMMANDS: true 19 | | |_____________________________________________^ insecure commands enabled here 20 | | 21 | = note: audit confidence → High 22 | 23 | error[insecure-commands]: execution of insecure workflow commands is enabled 24 | --> @@INPUT@@:32:7 25 | | 26 | 32 | env: ${{ mystery }} 27 | | ^^^^^^^^^^^^^^^^^^^ non-static environment may contain ACTIONS_ALLOW_UNSECURE_COMMANDS 28 | | 29 | = note: audit confidence → Low 30 | 31 | 3 findings: 0 unknown, 0 informational, 0 low, 0 medium, 3 high 32 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__snapshot__insecure_commands-4.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: crates/zizmor/tests/integration/snapshot.rs 3 | expression: "zizmor().input(input_under_test(\"insecure-commands/issue-839-repro.yml\")).args([\"--persona=auditor\"]).run()?" 4 | --- 5 | error[insecure-commands]: execution of insecure workflow commands is enabled 6 | --> @@INPUT@@:10:5 7 | | 8 | 10 | / env: 9 | 11 | | ACTIONS_ALLOW_UNSECURE_COMMANDS: "true" 10 | | |_____________________________________________^ insecure commands enabled here 11 | | 12 | = note: audit confidence → High 13 | 14 | error[insecure-commands]: execution of insecure workflow commands is enabled 15 | --> @@INPUT@@:24:9 16 | | 17 | 24 | env: ${{ matrix.env }} 18 | | ^^^^^^^^^^^^^^^^^^^^^^ non-static environment may contain ACTIONS_ALLOW_UNSECURE_COMMANDS 19 | | 20 | = note: audit confidence → Low 21 | 22 | 2 findings: 0 unknown, 0 informational, 0 low, 0 medium, 2 high 23 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__snapshot__insecure_commands.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: crates/zizmor/tests/integration/snapshot.rs 3 | expression: "zizmor().input(input_under_test(\"insecure-commands.yml\")).args([\"--persona=auditor\"]).run()?" 4 | --- 5 | error[insecure-commands]: execution of insecure workflow commands is enabled 6 | --> @@INPUT@@:10:5 7 | | 8 | 10 | / env: 9 | 11 | | ACTIONS_ALLOW_UNSECURE_COMMANDS: true 10 | | |___________________________________________^ insecure commands enabled here 11 | | 12 | = note: audit confidence → High 13 | 14 | error[insecure-commands]: execution of insecure workflow commands is enabled 15 | --> @@INPUT@@:24:9 16 | | 17 | 24 | env: ${{ matrix.env }} 18 | | ^^^^^^^^^^^^^^^^^^^^^^ non-static environment may contain ACTIONS_ALLOW_UNSECURE_COMMANDS 19 | | 20 | = note: audit confidence → Low 21 | 22 | 2 findings: 0 unknown, 0 informational, 0 low, 0 medium, 2 high 23 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__snapshot__overprovisioned_secrets.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: tests/integration/snapshot.rs 3 | expression: "zizmor().input(input_under_test(\"overprovisioned-secrets.yml\")).run()?" 4 | --- 5 | warning[overprovisioned-secrets]: excessively provisioned secrets 6 | --> @@INPUT@@:12:18 7 | | 8 | 12 | stuff: ${{ format('{0}', toJSON(secrets)) }} 9 | | ------------------------------------- injects the entire secrets context into the runner 10 | | 11 | = note: audit confidence → High 12 | 13 | warning[overprovisioned-secrets]: excessively provisioned secrets 14 | --> @@INPUT@@:21:25 15 | | 16 | 21 | secrets_json: ${{ toJSON(secrets) }} 17 | | ---------------------- injects the entire secrets context into the runner 18 | | 19 | = note: audit confidence → High 20 | 21 | 3 findings (1 ignored): 0 unknown, 0 informational, 0 low, 2 medium, 0 high 22 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__snapshot__ref_confusion-2.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: tests/integration/snapshot.rs 3 | expression: "zizmor().input(input_under_test(\"ref-confusion/issue-518-repro.yml\")).offline(false).run()?" 4 | --- 5 | error[unpinned-uses]: unpinned action reference 6 | --> @@INPUT@@:12:9 7 | | 8 | 12 | uses: arduino/setup-task@v2 9 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ action is not pinned to a hash (required by blanket policy) 10 | | 11 | = note: audit confidence → High 12 | 13 | 1 finding: 0 unknown, 0 informational, 0 low, 0 medium, 1 high 14 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__snapshot__ref_confusion.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: tests/integration/snapshot.rs 3 | expression: "zizmor().input(input_under_test(\"ref-confusion.yml\")).offline(false).run()?" 4 | --- 5 | warning[ref-confusion]: git ref for action with ambiguous ref type 6 | --> @@INPUT@@:11:9 7 | | 8 | 11 | - uses: woodruffw/gha-hazmat/ref-confusion@confusable 9 | | --------------------------------------------------- uses a ref that's provided by both the branch and tag namespaces 10 | | 11 | = note: audit confidence → High 12 | 13 | error[unpinned-uses]: unpinned action reference 14 | --> @@INPUT@@:11:9 15 | | 16 | 11 | - uses: woodruffw/gha-hazmat/ref-confusion@confusable 17 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ action is not pinned to a hash (required by blanket policy) 18 | | 19 | = note: audit confidence → High 20 | 21 | 2 findings: 0 unknown, 0 informational, 0 low, 1 medium, 1 high 22 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__snapshot__secrets_inherit.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: tests/integration/snapshot.rs 3 | expression: "zizmor().input(input_under_test(\"secrets-inherit.yml\")).run()?" 4 | --- 5 | warning[secrets-inherit]: secrets unconditionally inherited by called workflow 6 | --> @@INPUT@@:7:5 7 | | 8 | 7 | uses: octo-org/example-repo/.github/workflows/called-workflow.yml@main 9 | | ---------------------------------------------------------------------- this reusable workflow 10 | 8 | # NOT OK: unconditionally inherits 11 | 9 | secrets: inherit 12 | | ---------------- inherits all parent secrets 13 | | 14 | = note: audit confidence → High 15 | 16 | 1 finding: 0 unknown, 0 informational, 0 low, 1 medium, 0 high 17 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__snapshot__self_hosted-2.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: tests/integration/snapshot.rs 3 | expression: "zizmor().input(input_under_test(\"self-hosted.yml\")).run()?" 4 | --- 5 | No findings to report. Good job! (1 suppressed) 6 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__snapshot__self_hosted-3.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: tests/integration/snapshot.rs 3 | expression: "zizmor().input(input_under_test(\"self-hosted/self-hosted-runner-label.yml\")).args([\"--persona=auditor\"]).run()?" 4 | --- 5 | note[self-hosted-runner]: runs on a self-hosted runner 6 | --> @@INPUT@@:8:5 7 | | 8 | 8 | runs-on: [self-hosted, linux, arm64] 9 | | ------------------------------------ note: self-hosted runner used here 10 | | 11 | = note: audit confidence → High 12 | 13 | 1 finding: 1 unknown, 0 informational, 0 low, 0 medium, 0 high 14 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__snapshot__self_hosted-4.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: tests/integration/snapshot.rs 3 | expression: "zizmor().input(input_under_test(\"self-hosted/self-hosted-runner-group.yml\")).args([\"--persona=auditor\"]).run()?" 4 | --- 5 | note[self-hosted-runner]: runs on a self-hosted runner 6 | --> @@INPUT@@:8:5 7 | | 8 | 8 | / runs-on: 9 | 9 | | group: ubuntu-runners 10 | | |___________________________- note: runner group implies self-hosted runner 11 | | 12 | = note: audit confidence → Low 13 | 14 | 1 finding: 1 unknown, 0 informational, 0 low, 0 medium, 0 high 15 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__snapshot__self_hosted-5.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: tests/integration/snapshot.rs 3 | expression: "zizmor().input(input_under_test(\"self-hosted/self-hosted-matrix-dimension.yml\")).args([\"--persona=auditor\"]).run()?" 4 | --- 5 | note[self-hosted-runner]: runs on a self-hosted runner 6 | --> @@INPUT@@:10:5 7 | | 8 | 8 | runs-on: ${{ matrix.os }} 9 | | ------------------------- note: expression may expand into a self-hosted runner 10 | 9 | 11 | 10 | / strategy: 12 | 11 | | matrix: 13 | 12 | | os: [self-hosted, ubuntu-latest] 14 | | |________________________________________- note: matrix declares self-hosted runner 15 | | 16 | = note: audit confidence → High 17 | 18 | 1 finding: 1 unknown, 0 informational, 0 low, 0 medium, 0 high 19 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__snapshot__self_hosted-6.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: tests/integration/snapshot.rs 3 | expression: "zizmor().input(input_under_test(\"self-hosted/self-hosted-matrix-inclusion.yml\")).args([\"--persona=auditor\"]).run()?" 4 | --- 5 | note[self-hosted-runner]: runs on a self-hosted runner 6 | --> @@INPUT@@:10:5 7 | | 8 | 8 | runs-on: ${{ matrix.os }} 9 | | ------------------------- note: expression may expand into a self-hosted runner 10 | 9 | 11 | 10 | / strategy: 12 | 11 | | matrix: 13 | 12 | | os: [macOS-latest, ubuntu-latest] 14 | 13 | | include: 15 | 14 | | - os: self-hosted 16 | | |___________________________- note: matrix declares self-hosted runner 17 | | 18 | = note: audit confidence → High 19 | 20 | 1 finding: 1 unknown, 0 informational, 0 low, 0 medium, 0 high 21 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__snapshot__self_hosted-7.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: tests/integration/snapshot.rs 3 | expression: "zizmor().input(input_under_test(\"self-hosted/self-hosted-matrix-exclusion.yml\")).args([\"--persona=auditor\"]).run()?" 4 | --- 5 | No findings to report. Good job! 6 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__snapshot__self_hosted-8.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: tests/integration/snapshot.rs 3 | expression: "zizmor().input(input_under_test(\"self-hosted/issue-283-repro.yml\")).args([\"--persona=auditor\"]).run()?" 4 | --- 5 | No findings to report. Good job! 6 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__snapshot__self_hosted.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: tests/integration/snapshot.rs 3 | expression: "zizmor().input(input_under_test(\"self-hosted.yml\")).args([\"--persona=auditor\"]).run()?" 4 | --- 5 | note[self-hosted-runner]: runs on a self-hosted runner 6 | --> @@INPUT@@:10:5 7 | | 8 | 10 | runs-on: [self-hosted, my-ubuntu-box] 9 | | ------------------------------------- note: self-hosted runner used here 10 | | 11 | = note: audit confidence → High 12 | 13 | 1 finding: 1 unknown, 0 informational, 0 low, 0 medium, 0 high 14 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__snapshot__stale_action_refs.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: tests/integration/snapshot.rs 3 | expression: "zizmor().input(input_under_test(\"stale-action-refs.yml\")).offline(false).args([\"--persona=pedantic\"]).run()?" 4 | --- 5 | help[stale-action-refs]: commit hash does not point to a Git tag 6 | --> @@INPUT@@:28:7 7 | | 8 | 28 | - uses: actions/checkout@009b9ae9e446ad8d9b8c809870b0fbcc5e03573e 9 | | --------------------------------------------------------------- help: this step 10 | | 11 | = note: audit confidence → High 12 | 13 | 1 finding: 0 unknown, 0 informational, 1 low, 0 medium, 0 high 14 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__snapshot__template_injection-10.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: crates/zizmor/tests/integration/snapshot.rs 3 | expression: "zizmor().input(input_under_test(\"template-injection/issue-749-repro.yml\")).run()?" 4 | --- 5 | No findings to report. Good job! (1 suppressed) 6 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__snapshot__template_injection-11.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: crates/zizmor/tests/integration/snapshot.rs 3 | expression: "zizmor().input(input_under_test(\"template-injection/codeql-sinks.yml\")).run()?" 4 | --- 5 | error[template-injection]: code injection via template expansion 6 | --> @@INPUT@@:14:9 7 | | 8 | 14 | - uses: mikefarah/yq@b534aa9ee5d38001fba3cd8fe254a037e4847b37 # v4.45.4 9 | | _________^ 10 | 15 | | with: 11 | 16 | | cmd: ${{ github.event.pull_request.title }} 12 | | |___________^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this step 13 | | | 14 | | github.event.pull_request.title may expand into attacker-controllable code 15 | | 16 | = note: audit confidence → High 17 | 18 | 2 findings (1 suppressed): 0 unknown, 0 informational, 0 low, 0 medium, 1 high 19 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__snapshot__template_injection-12.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: crates/zizmor/tests/integration/snapshot.rs 3 | expression: "zizmor().input(input_under_test(\"template-injection/pwsh-script.yml\")).run()?" 4 | --- 5 | error[template-injection]: code injection via template expansion 6 | --> @@INPUT@@:12:9 7 | | 8 | 12 | - uses: Amadevus/pwsh-script@97a8b211a5922816aa8a69ced41fa32f23477186 # v2.0.3 9 | | __________^ 10 | 13 | | with: 11 | 14 | | script: | 12 | | | ___________^ 13 | 15 | || Write-ActionDebug "Running for pull request ${{ github.event.pull_request.title }}" 14 | | || ^ 15 | | ||________________________________________________________________________________________________| 16 | | |________________________________________________________________________________________________this step 17 | | github.event.pull_request.title may expand into attacker-controllable code 18 | | 19 | = note: audit confidence → High 20 | 21 | 2 findings (1 suppressed): 0 unknown, 0 informational, 0 low, 0 medium, 1 high 22 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__snapshot__template_injection-2.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: crates/zizmor/tests/integration/snapshot.rs 3 | expression: "zizmor().input(input_under_test(\"template-injection/template-injection-dynamic-matrix.yml\")).args([\"--persona=auditor\"]).run()?" 4 | --- 5 | note[template-injection]: code injection via template expansion 6 | --> @@INPUT@@:19:9 7 | | 8 | 19 | - name: Please dont 9 | | ----------------- note: this step 10 | 20 | / run: | 11 | 21 | | echo "doing a thing: ${{ matrix.dynamic }}" 12 | | |______________________________________________________- note: ${{ matrix.dynamic }} may expand into attacker-controllable code 13 | | 14 | = note: audit confidence → Unknown 15 | 16 | warning[template-injection]: code injection via template expansion 17 | --> @@INPUT@@:19:9 18 | | 19 | 19 | - name: Please dont 20 | | ----------------- this step 21 | 20 | / run: | 22 | 21 | | echo "doing a thing: ${{ matrix.dynamic }}" 23 | | |______________________________________________________- matrix.dynamic may expand into attacker-controllable code 24 | | 25 | = note: audit confidence → Medium 26 | 27 | 2 findings: 1 unknown, 0 informational, 0 low, 1 medium, 0 high 28 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__snapshot__template_injection-3.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: crates/zizmor/tests/integration/snapshot.rs 3 | expression: "zizmor().input(input_under_test(\"template-injection/issue-22-repro.yml\")).run()?" 4 | --- 5 | No findings to report. Good job! (5 suppressed) 6 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__snapshot__template_injection-4.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: crates/zizmor/tests/integration/snapshot.rs 3 | expression: "zizmor().input(input_under_test(\"template-injection/pr-317-repro.yml\")).run()?" 4 | --- 5 | warning[template-injection]: code injection via template expansion 6 | --> @@INPUT@@:27:9 7 | | 8 | 27 | - run: | 9 | | _________- 10 | 28 | | echo ${{ matrix.bar }} 11 | | | - 12 | | |_________________________________| 13 | | this step 14 | | matrix.bar may expand into attacker-controllable code 15 | | 16 | = note: audit confidence → Medium 17 | 18 | 2 findings (1 suppressed): 0 unknown, 0 informational, 0 low, 1 medium, 0 high 19 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__snapshot__template_injection-5.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: crates/zizmor/tests/integration/snapshot.rs 3 | expression: "zizmor().input(input_under_test(\"template-injection/static-env.yml\")).run()?" 4 | --- 5 | help[template-injection]: code injection via template expansion 6 | --> @@INPUT@@:41:9 7 | | 8 | 41 | - name: step-level-non-static 9 | | --------------------------- help: this step 10 | 42 | / run: | 11 | 43 | | echo ${{ env.bar }} 12 | | |_____________________________- help: env.bar may expand into attacker-controllable code 13 | | 14 | = note: audit confidence → High 15 | 16 | help[template-injection]: code injection via template expansion 17 | --> @@INPUT@@:48:9 18 | | 19 | 48 | - name: job-level-non-static 20 | | -------------------------- help: this step 21 | 49 | / run: | 22 | 50 | | echo ${{ env.foo }} 23 | | |_____________________________- help: env.foo may expand into attacker-controllable code 24 | | 25 | = note: audit confidence → High 26 | 27 | help[template-injection]: code injection via template expansion 28 | --> @@INPUT@@:53:9 29 | | 30 | 53 | - name: workflow-level-non-static 31 | | ------------------------------- help: this step 32 | 54 | / run: | 33 | 55 | | echo ${{ env.quux }} 34 | | |_______________________________- help: env.quux may expand into attacker-controllable code 35 | | 36 | = note: audit confidence → High 37 | 38 | 9 findings (6 suppressed): 0 unknown, 0 informational, 3 low, 0 medium, 0 high 39 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__snapshot__template_injection-6.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: crates/zizmor/tests/integration/snapshot.rs 3 | expression: "zizmor().input(input_under_test(\"template-injection/issue-339-repro.yml\")).run()?" 4 | --- 5 | info[template-injection]: code injection via template expansion 6 | --> @@INPUT@@:27:9 7 | | 8 | 27 | - name: "Record run id" 9 | | --------------------- info: this step 10 | 28 | id: run-id 11 | 29 | / run: | 12 | 30 | | echo "run-id=${{ fromJson(steps.runs.outputs.data).workflow_runs[0].id }}" >> "$GITHUB_OUTPUT" 13 | | |_________________________________________________________________________________________________________- info: fromJson(steps.runs.outputs.data).workflow_runs[0].id may expand into attacker-controllable code 14 | | 15 | = note: audit confidence → Low 16 | 17 | 2 findings (1 suppressed): 0 unknown, 1 informational, 0 low, 0 medium, 0 high 18 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__snapshot__template_injection-7.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: crates/zizmor/tests/integration/snapshot.rs 3 | expression: "zizmor().input(input_under_test(\"template-injection/issue-418-repro.yml\")).run()?" 4 | --- 5 | No findings to report. Good job! (1 suppressed) 6 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__snapshot__template_injection-9.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: crates/zizmor/tests/integration/snapshot.rs 3 | expression: "zizmor().input(input_under_test(\"template-injection/false-positive-menagerie.yml\")).run()?" 4 | --- 5 | No findings to report. Good job! (6 suppressed) 6 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__snapshot__template_injection.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: crates/zizmor/tests/integration/snapshot.rs 3 | expression: "zizmor().input(input_under_test(\"template-injection/template-injection-static-matrix.yml\")).args([\"--persona=auditor\"]).run()?" 4 | --- 5 | note[template-injection]: code injection via template expansion 6 | --> @@INPUT@@:18:9 7 | | 8 | 18 | - name: Nothing to fear 9 | | --------------------- note: this step 10 | 19 | / run: | 11 | 20 | | echo "issue created: ${{ matrix.frob }}" 12 | | |___________________________________________________- note: ${{ matrix.frob }} may expand into attacker-controllable code 13 | | 14 | = note: audit confidence → Unknown 15 | 16 | 1 finding: 1 unknown, 0 informational, 0 low, 0 medium, 0 high 17 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__snapshot__unpinned-uses-composite-config-2.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: tests/integration/snapshot.rs 3 | expression: "zizmor().config(input_under_test(\"unpinned-uses/configs/composite-2.yml\")).input(input_under_test(\"unpinned-uses/menagerie-of-uses.yml\")).run()?" 4 | --- 5 | error[unpinned-uses]: unpinned action reference 6 | --> @@INPUT@@:13:9 7 | | 8 | 13 | - uses: actions/checkout 9 | | ^^^^^^^^^^^^^^^^^^^^^^ action is not pinned to a ref or hash (required by actions/* policy) 10 | | 11 | = note: audit confidence → High 12 | 13 | error[unpinned-uses]: unpinned action reference 14 | --> @@INPUT@@:27:9 15 | | 16 | 27 | - uses: github/codeql-action/init@v3 17 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ action is not pinned to a hash (required by github/codeql-action/init policy) 18 | | 19 | = note: audit confidence → High 20 | 21 | error[unpinned-uses]: unpinned action reference 22 | --> @@INPUT@@:29:9 23 | | 24 | 29 | - uses: github/codeql-action/upload-sarif@v3 25 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ action is not pinned to a hash (required by github/codeql-action/upload-sarif policy) 26 | | 27 | = note: audit confidence → High 28 | 29 | 3 findings: 0 unknown, 0 informational, 0 low, 0 medium, 3 high 30 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__snapshot__unpinned-uses-composite-config.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: tests/integration/snapshot.rs 3 | expression: "zizmor().config(input_under_test(\"unpinned-uses/configs/composite.yml\")).input(input_under_test(\"unpinned-uses/menagerie-of-uses.yml\")).run()?" 4 | --- 5 | error[unpinned-uses]: unpinned action reference 6 | --> @@INPUT@@:11:9 7 | | 8 | 11 | - uses: actions/setup-python@v4 9 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ action is not pinned to a hash (required by actions/setup-python policy) 10 | | 11 | = note: audit confidence → High 12 | 13 | error[unpinned-uses]: unpinned action reference 14 | --> @@INPUT@@:27:9 15 | | 16 | 27 | - uses: github/codeql-action/init@v3 17 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ action is not pinned to a hash (required by blanket policy) 18 | | 19 | = note: audit confidence → High 20 | 21 | error[unpinned-uses]: unpinned action reference 22 | --> @@INPUT@@:29:9 23 | | 24 | 29 | - uses: github/codeql-action/upload-sarif@v3 25 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ action is not pinned to a hash (required by blanket policy) 26 | | 27 | = note: audit confidence → High 28 | 29 | 3 findings: 0 unknown, 0 informational, 0 low, 0 medium, 3 high 30 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__snapshot__unpinned-uses-default-config.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: tests/integration/snapshot.rs 3 | expression: "zizmor().input(input_under_test(\"unpinned-uses/menagerie-of-uses.yml\")).run()?" 4 | --- 5 | error[unpinned-uses]: unpinned action reference 6 | --> @@INPUT@@:13:9 7 | | 8 | 13 | - uses: actions/checkout 9 | | ^^^^^^^^^^^^^^^^^^^^^^ action is not pinned to a ref or hash (required by actions/* policy) 10 | | 11 | = note: audit confidence → High 12 | 13 | error[unpinned-uses]: unpinned action reference 14 | --> @@INPUT@@:25:9 15 | | 16 | 25 | - uses: pypa/gh-action-pypi-publish@release/v1 17 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ action is not pinned to a hash (required by blanket policy) 18 | | 19 | = note: audit confidence → High 20 | 21 | 2 findings: 0 unknown, 0 informational, 0 low, 0 medium, 2 high 22 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__snapshot__unpinned-uses-ref-pin-everything-config.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: tests/integration/snapshot.rs 3 | expression: "zizmor().config(input_under_test(\"unpinned-uses/configs/ref-pin-everything.yml\")).input(input_under_test(\"unpinned-uses/menagerie-of-uses.yml\")).run()?" 4 | --- 5 | error[unpinned-uses]: unpinned action reference 6 | --> @@INPUT@@:13:9 7 | | 8 | 13 | - uses: actions/checkout 9 | | ^^^^^^^^^^^^^^^^^^^^^^ action is not pinned to a ref or hash (required by blanket policy) 10 | | 11 | = note: audit confidence → High 12 | 13 | 1 finding: 0 unknown, 0 informational, 0 low, 0 medium, 1 high 14 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__snapshot__unpinned_uses-10.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: tests/integration/snapshot.rs 3 | expression: "zizmor().expects_failure(true).config(input_under_test(&format!(\"unpinned-uses/configs/{tc}.yml\",))).input(input_under_test(\"unpinned-uses/menagerie-of-uses.yml\")).run()?" 4 | snapshot_kind: text 5 | --- 6 | INFO zizmor: skipping impostor-commit: can't run without a GitHub API token 7 | INFO zizmor: skipping ref-confusion: can't run without a GitHub API token 8 | INFO zizmor: skipping known-vulnerable-actions: can't run without a GitHub API token 9 | fatal: no audit was performed 10 | error: failed to load audit: unpinned-uses 11 | = note: invalid configuration: invalid pattern: foo/b*r 12 | = note: see: https://docs.zizmor.sh/audits/#unpinned-uses 13 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__snapshot__unpinned_uses-11.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: tests/integration/snapshot.rs 3 | expression: "zizmor().expects_failure(true).config(input_under_test(&format!(\"unpinned-uses/configs/{tc}.yml\",))).input(input_under_test(\"unpinned-uses/menagerie-of-uses.yml\")).run()?" 4 | snapshot_kind: text 5 | --- 6 | INFO zizmor: skipping impostor-commit: can't run without a GitHub API token 7 | INFO zizmor: skipping ref-confusion: can't run without a GitHub API token 8 | INFO zizmor: skipping known-vulnerable-actions: can't run without a GitHub API token 9 | fatal: no audit was performed 10 | error: failed to load audit: unpinned-uses 11 | = note: invalid configuration: unknown variant `does not exist`, expected one of `any`, `ref-pin`, `hash-pin` 12 | = note: see: https://docs.zizmor.sh/audits/#unpinned-uses 13 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__snapshot__unpinned_uses-12.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: tests/integration/snapshot.rs 3 | expression: "zizmor().expects_failure(true).config(input_under_test(&format!(\"unpinned-uses/configs/{tc}.yml\",))).input(input_under_test(\"unpinned-uses/menagerie-of-uses.yml\")).run()?" 4 | snapshot_kind: text 5 | --- 6 | INFO zizmor: skipping impostor-commit: can't run without a GitHub API token 7 | INFO zizmor: skipping ref-confusion: can't run without a GitHub API token 8 | INFO zizmor: skipping known-vulnerable-actions: can't run without a GitHub API token 9 | fatal: no audit was performed 10 | error: failed to load audit: unpinned-uses 11 | = note: invalid configuration: can't use exact ref patterns here 12 | = note: see: https://docs.zizmor.sh/audits/#unpinned-uses 13 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__snapshot__unpinned_uses-2.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: tests/integration/snapshot.rs 3 | expression: "zizmor().input(input_under_test(\"unpinned-uses.yml\")).run()?" 4 | --- 5 | error[unpinned-uses]: unpinned action reference 6 | --> @@INPUT@@:11:9 7 | | 8 | 11 | - uses: actions/checkout 9 | | ^^^^^^^^^^^^^^^^^^^^^^ action is not pinned to a ref or hash (required by actions/* policy) 10 | | 11 | = note: audit confidence → High 12 | 13 | error[unpinned-uses]: unpinned action reference 14 | --> @@INPUT@@:21:9 15 | | 16 | 21 | - uses: github/codeql-action/upload-sarif 17 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ action is not pinned to a ref or hash (required by github/* policy) 18 | | 19 | = note: audit confidence → High 20 | 21 | warning[unpinned-uses]: unpinned action reference 22 | --> @@INPUT@@:24:9 23 | | 24 | 24 | - uses: docker://ubuntu 25 | | --------------------- action is not pinned to a tag, branch, or hash ref 26 | | 27 | = note: audit confidence → High 28 | 29 | warning[unpinned-uses]: unpinned action reference 30 | --> @@INPUT@@:30:9 31 | | 32 | 30 | - uses: docker://ghcr.io/pypa/gh-action-pypi-publish 33 | | -------------------------------------------------- action is not pinned to a tag, branch, or hash ref 34 | | 35 | = note: audit confidence → High 36 | 37 | 4 findings: 0 unknown, 0 informational, 0 low, 2 medium, 2 high 38 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__snapshot__unpinned_uses-3.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: tests/integration/snapshot.rs 3 | expression: "zizmor().input(input_under_test(\"unpinned-uses/action.yml\")).args([\"--pedantic\"]).run()?" 4 | --- 5 | error[unpinned-uses]: unpinned action reference 6 | --> @@INPUT@@:8:7 7 | | 8 | 8 | uses: asdf-vm/actions/setup@v3 9 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ action is not pinned to a hash (required by blanket policy) 10 | | 11 | = note: audit confidence → High 12 | 13 | error[unpinned-uses]: unpinned action reference 14 | --> @@INPUT@@:11:7 15 | | 16 | 11 | uses: asdf-vm/actions/setup@main 17 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ action is not pinned to a hash (required by blanket policy) 18 | | 19 | = note: audit confidence → High 20 | 21 | 2 findings: 0 unknown, 0 informational, 0 low, 0 medium, 2 high 22 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__snapshot__unpinned_uses-4.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: tests/integration/snapshot.rs 3 | expression: "zizmor().input(input_under_test(\"unpinned-uses/issue-433-repro.yml\")).args([\"--pedantic\"]).run()?" 4 | --- 5 | No findings to report. Good job! 6 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__snapshot__unpinned_uses-5.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: tests/integration/snapshot.rs 3 | expression: "zizmor().input(input_under_test(\"unpinned-uses/issue-659-repro.yml\")).args([\"--pedantic\"]).run()?" 4 | --- 5 | warning[excessive-permissions]: overly broad permissions 6 | --> @@INPUT@@:1:1 7 | | 8 | 1 | / # minimized from https://raw.githubusercontent.com/docker/actions-toolkit/59501e62b/.github/workflows/test.yml 9 | 2 | | name: issue-659-repro 10 | ... | 11 | 18 | | with: 12 | 19 | | node-version: ${{ env.NODE_VERSION }} 13 | | |________________________________________________- default permissions used due to no permissions: block 14 | | 15 | = note: audit confidence → Medium 16 | 17 | warning[excessive-permissions]: overly broad permissions 18 | --> @@INPUT@@:8:3 19 | | 20 | 8 | / test-itg: 21 | 9 | | runs-on: ${{ matrix.os }} 22 | ... | 23 | 18 | | with: 24 | 19 | | node-version: ${{ env.NODE_VERSION }} 25 | | | - 26 | | |________________________________________________| 27 | | this job 28 | | default permissions used due to no permissions: block 29 | | 30 | = note: audit confidence → Medium 31 | 32 | 2 findings: 0 unknown, 0 informational, 0 low, 2 medium, 0 high 33 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__snapshot__unpinned_uses-6.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: tests/integration/snapshot.rs 3 | expression: "zizmor().expects_failure(true).config(input_under_test(&format!(\"unpinned-uses/configs/{tc}.yml\",))).input(input_under_test(\"unpinned-uses/menagerie-of-uses.yml\")).run()?" 4 | snapshot_kind: text 5 | --- 6 | INFO zizmor: skipping impostor-commit: can't run without a GitHub API token 7 | INFO zizmor: skipping ref-confusion: can't run without a GitHub API token 8 | INFO zizmor: skipping known-vulnerable-actions: can't run without a GitHub API token 9 | fatal: no audit was performed 10 | error: failed to load audit: unpinned-uses 11 | = note: invalid configuration: invalid type: sequence, expected a map 12 | = note: see: https://docs.zizmor.sh/audits/#unpinned-uses 13 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__snapshot__unpinned_uses-7.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: tests/integration/snapshot.rs 3 | expression: "zizmor().expects_failure(true).config(input_under_test(&format!(\"unpinned-uses/configs/{tc}.yml\",))).input(input_under_test(\"unpinned-uses/menagerie-of-uses.yml\")).run()?" 4 | snapshot_kind: text 5 | --- 6 | INFO zizmor: skipping impostor-commit: can't run without a GitHub API token 7 | INFO zizmor: skipping ref-confusion: can't run without a GitHub API token 8 | INFO zizmor: skipping known-vulnerable-actions: can't run without a GitHub API token 9 | fatal: no audit was performed 10 | error: failed to load audit: unpinned-uses 11 | = note: invalid configuration: invalid pattern: lol 12 | = note: see: https://docs.zizmor.sh/audits/#unpinned-uses 13 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__snapshot__unpinned_uses-8.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: tests/integration/snapshot.rs 3 | expression: "zizmor().expects_failure(true).config(input_under_test(&format!(\"unpinned-uses/configs/{tc}.yml\",))).input(input_under_test(\"unpinned-uses/menagerie-of-uses.yml\")).run()?" 4 | snapshot_kind: text 5 | --- 6 | INFO zizmor: skipping impostor-commit: can't run without a GitHub API token 7 | INFO zizmor: skipping ref-confusion: can't run without a GitHub API token 8 | INFO zizmor: skipping known-vulnerable-actions: can't run without a GitHub API token 9 | fatal: no audit was performed 10 | error: failed to load audit: unpinned-uses 11 | = note: invalid configuration: invalid pattern: foo/ 12 | = note: see: https://docs.zizmor.sh/audits/#unpinned-uses 13 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__snapshot__unpinned_uses-9.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: tests/integration/snapshot.rs 3 | expression: "zizmor().expects_failure(true).config(input_under_test(&format!(\"unpinned-uses/configs/{tc}.yml\",))).input(input_under_test(\"unpinned-uses/menagerie-of-uses.yml\")).run()?" 4 | snapshot_kind: text 5 | --- 6 | INFO zizmor: skipping impostor-commit: can't run without a GitHub API token 7 | INFO zizmor: skipping ref-confusion: can't run without a GitHub API token 8 | INFO zizmor: skipping known-vulnerable-actions: can't run without a GitHub API token 9 | fatal: no audit was performed 10 | error: failed to load audit: unpinned-uses 11 | = note: invalid configuration: invalid pattern: */foo 12 | = note: see: https://docs.zizmor.sh/audits/#unpinned-uses 13 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__snapshot__unpinned_uses.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: tests/integration/snapshot.rs 3 | expression: "zizmor().input(input_under_test(\"unpinned-uses.yml\")).args([\"--pedantic\"]).run()?" 4 | --- 5 | error[unpinned-uses]: unpinned action reference 6 | --> @@INPUT@@:11:9 7 | | 8 | 11 | - uses: actions/checkout 9 | | ^^^^^^^^^^^^^^^^^^^^^^ action is not pinned to a ref or hash (required by actions/* policy) 10 | | 11 | = note: audit confidence → High 12 | 13 | error[unpinned-uses]: unpinned action reference 14 | --> @@INPUT@@:21:9 15 | | 16 | 21 | - uses: github/codeql-action/upload-sarif 17 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ action is not pinned to a ref or hash (required by github/* policy) 18 | | 19 | = note: audit confidence → High 20 | 21 | warning[unpinned-uses]: unpinned action reference 22 | --> @@INPUT@@:24:9 23 | | 24 | 24 | - uses: docker://ubuntu 25 | | --------------------- action is not pinned to a tag, branch, or hash ref 26 | | 27 | = note: audit confidence → High 28 | 29 | warning[unpinned-uses]: unpinned action reference 30 | --> @@INPUT@@:30:9 31 | | 32 | 30 | - uses: docker://ghcr.io/pypa/gh-action-pypi-publish 33 | | -------------------------------------------------- action is not pinned to a tag, branch, or hash ref 34 | | 35 | = note: audit confidence → High 36 | 37 | 4 findings: 0 unknown, 0 informational, 0 low, 2 medium, 2 high 38 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/snapshots/integration__snapshot__unredacted_secrets.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: tests/integration/snapshot.rs 3 | expression: "zizmor().input(input_under_test(\"unredacted-secrets.yml\")).run()?" 4 | --- 5 | warning[unredacted-secrets]: leaked secret values 6 | --> @@INPUT@@:14:18 7 | | 8 | 14 | stuff: ${{ fromJSON(secrets.password) }} 9 | | --------------------------------- bypasses secret redaction 10 | | 11 | = note: audit confidence → High 12 | 13 | warning[unredacted-secrets]: leaked secret values 14 | --> @@INPUT@@:17:23 15 | | 16 | 17 | otherstuff: ${{ fromJson(secrets.otherstuff).field }} 17 | | ----------------------------------------- bypasses secret redaction 18 | | 19 | = note: audit confidence → High 20 | 21 | 2 findings: 0 unknown, 0 informational, 0 low, 2 medium, 0 high 22 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/artipacked.yml: -------------------------------------------------------------------------------- 1 | # Adapted from 2 | # https://github.com/woodruffw/gha-hazmat/blob/main/.github/workflows/artipacked.yml 3 | on: 4 | push: 5 | branches: 6 | - master 7 | workflow_dispatch: 8 | 9 | permissions: {} 10 | 11 | jobs: 12 | artipacked: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # tag=v4.2.2 16 | 17 | pedantic: 18 | runs-on: ubuntu-latest 19 | steps: 20 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # tag=v4.2.2 21 | with: 22 | persist-credentials: true 23 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/artipacked/issue-447-repro.yml: -------------------------------------------------------------------------------- 1 | # see https://github.com/zizmorcore/zizmor/issues/447 2 | 3 | name: ISSUE-447-REPRO 4 | on: push 5 | 6 | permissions: {} 7 | 8 | jobs: 9 | issue-447-repro: 10 | runs-on: ubuntu-latest 11 | 12 | steps: 13 | - name: true-negative 14 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 15 | with: 16 | # no finding since GHA permits stringy bools 17 | persist-credentials: "false" 18 | 19 | - name: true-positive 20 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 21 | with: 22 | # finding in auditor mode only 23 | persist-credentials: "true" 24 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/bot-conditions.yml: -------------------------------------------------------------------------------- 1 | on: pull_request_target 2 | 3 | permissions: {} 4 | 5 | jobs: 6 | hackme: 7 | runs-on: ubuntu-latest 8 | if: github.actor == 'dependabot[bot]' 9 | steps: 10 | - name: vulnerable-1 11 | run: echo hello 12 | if: ${{ github.actor == 'dependabot[bot]' }} 13 | 14 | - name: vulnerable-2 15 | run: echo hello 16 | if: ${{ github.actor == 'dependabot[bot]' && github.repository == 'example/example' }} 17 | 18 | - name: vulnerable-3 19 | run: echo hello 20 | if: github.actor == 'renovate[bot]' 21 | 22 | - name: not-vulnerable-4 23 | run: echo hello 24 | if: github.actor == 'notabot' 25 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/cache-poisoning.yml: -------------------------------------------------------------------------------- 1 | on: release 2 | 3 | permissions: {} 4 | 5 | jobs: 6 | publish: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - name: Setup uv 10 | uses: astral-sh/setup-uv@38f3f104447c67c051c4a08e39b64a148898af3a 11 | with: 12 | python-version: "3.12" 13 | 14 | - name: Publish on Pypi 15 | run: uv build publish 16 | env: 17 | UV_PUBLISH_TOKEN: ${{ secrets.PYPI_PUBLISH_TOKEN }} 18 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/cache-poisoning/caching-disabled-by-default.yml: -------------------------------------------------------------------------------- 1 | on: release 2 | 3 | permissions: {} 4 | 5 | jobs: 6 | publish: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - name: Project Checkout 10 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 11 | with: 12 | persist-credentials: false 13 | 14 | - name: Setup JDK 15 | uses: actions/setup-java@8df1039502a15bceb9433410b1a100fbe190c53b 16 | with: 17 | distribution: "zulu" 18 | java-version: "17" 19 | 20 | - name: Publish to Maven Central 21 | run: ./gradlew publishToMavenCentral --no-configuration-cache 22 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/cache-poisoning/caching-enabled-by-default.yml: -------------------------------------------------------------------------------- 1 | on: release 2 | 3 | permissions: {} 4 | 5 | jobs: 6 | publish-crate: 7 | runs-on: ubuntu-24.04 8 | 9 | steps: 10 | - name: Project Checkout 11 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 12 | with: 13 | persist-credentials: false 14 | 15 | - name: Setup CI caching 16 | uses: Swatinem/rust-cache@82a92a6e8fbeee089604da2575dc567ae9ddeaab 17 | 18 | - name: Publish on crates.io 19 | if: false 20 | run: cargo publish --token ${{ secrets.CRATESIO_PUBLISH_TOKEN }} 21 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/cache-poisoning/caching-not-configurable.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | tags: 4 | - "**" 5 | 6 | permissions: {} 7 | 8 | jobs: 9 | publish: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Project Checkout 13 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 14 | with: 15 | persist-credentials: false 16 | 17 | - name: Setup CI caching 18 | uses: Mozilla-Actions/sccache-action@054db53350805f83040bf3e6e9b8cf5a139aa7c9 19 | 20 | - name: Publish on crates.io 21 | run: cargo publish --token ${{ secrets.CRATESIO_PUBLISH_TOKEN }} 22 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/cache-poisoning/caching-opt-in-boolean-toggle.yml: -------------------------------------------------------------------------------- 1 | on: release 2 | 3 | permissions: {} 4 | 5 | jobs: 6 | publish: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - name: Project Checkout 10 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 11 | with: 12 | persist-credentials: false 13 | 14 | - name: Setup DotNet 15 | uses: actions/setup-dotnet@3e891b0cb619bf60e2c25674b222b8940e2c1c25 16 | with: 17 | dotnet-version: "5.0.x" 18 | cache: true 19 | 20 | - name: Publish on NuGet 21 | run: | 22 | dotnet build 23 | dotnet nuget push My.Tool.1.0.0.nupkg --api-key ${{ secrets.NUGET_PUBLISH_KEY }} --source https://api.nuget.org/v3/index.json 24 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/cache-poisoning/caching-opt-in-boolish-toggle.yml: -------------------------------------------------------------------------------- 1 | # ensures that boolish toggles are treated like booleans, 2 | # i.e. the `"true"` string is treated like `true` 3 | 4 | on: release 5 | 6 | permissions: {} 7 | 8 | jobs: 9 | publish-crate: 10 | runs-on: ubuntu-24.04 11 | 12 | steps: 13 | - name: Build wheels 14 | uses: PyO3/maturin-action@ea5bac0f1ccd0ab11c805e2b804bfcb65dac2eab # v1 15 | with: 16 | target: ${{ matrix.platform.target }} 17 | args: --release --out dist 18 | sccache: "true" 19 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/cache-poisoning/caching-opt-in-expression.yml: -------------------------------------------------------------------------------- 1 | on: release 2 | 3 | permissions: {} 4 | 5 | jobs: 6 | publish: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - name: Project Checkout 10 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 11 | with: 12 | persist-credentials: false 13 | 14 | - name: Setup uv 15 | uses: astral-sh/setup-uv@38f3f104447c67c051c4a08e39b64a148898af3a 16 | with: 17 | python-version: "3.12" 18 | enable-cache: ${{ github.ref == 'refs/heads/main' }} 19 | 20 | - name: Publish on Pypi 21 | run: uv build publish 22 | env: 23 | UV_PUBLISH_TOKEN: ${{ secrets.PYPI_PUBLISH_TOKEN }} 24 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/cache-poisoning/caching-opt-in-multi-value-toggle.yml: -------------------------------------------------------------------------------- 1 | on: release 2 | 3 | permissions: {} 4 | 5 | jobs: 6 | publish: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - name: Project Checkout 10 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 11 | with: 12 | persist-credentials: false 13 | 14 | - name: Setup JDK 15 | uses: actions/setup-java@8df1039502a15bceb9433410b1a100fbe190c53b 16 | with: 17 | distribution: "zulu" 18 | cache: "gradle" 19 | java-version: "17" 20 | 21 | - name: Publish to Maven Central 22 | run: ./gradlew publishToMavenCentral --no-configuration-cache 23 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/cache-poisoning/caching-opt-out.yml: -------------------------------------------------------------------------------- 1 | on: release 2 | 3 | permissions: {} 4 | 5 | jobs: 6 | publish-crate: 7 | runs-on: ubuntu-24.04 8 | 9 | steps: 10 | - name: Project Checkout 11 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 12 | with: 13 | persist-credentials: false 14 | 15 | - name: Setup CI caching 16 | uses: Swatinem/rust-cache@82a92a6e8fbeee089604da2575dc567ae9ddeaab 17 | with: 18 | lookup-only: true 19 | 20 | - name: Publish on crates.io 21 | if: false 22 | run: cargo publish --token ${{ secrets.CRATESIO_PUBLISH_TOKEN }} 23 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/cache-poisoning/issue-343-repro.yml: -------------------------------------------------------------------------------- 1 | # minimized from https://github.com/zizmorcore/zizmor/pull/343 2 | 3 | name: Release 4 | 5 | on: 6 | push: 7 | tags: 8 | - "v*.*.*" 9 | 10 | permissions: {} 11 | 12 | jobs: 13 | goreleaser: 14 | runs-on: ubuntu-latest 15 | permissions: 16 | contents: write 17 | steps: 18 | # No finding, since cache is explicitly disabled. 19 | - name: true-negative-1 20 | uses: actions/setup-go@v5 21 | with: 22 | go-version: stable 23 | cache: false 24 | 25 | # Finding because setup-go enables cache by default 26 | - name: true-positive-2 27 | uses: actions/setup-go@v5 28 | with: 29 | go-version: stable 30 | 31 | # Finding because setup enables cache explicitly 32 | - name: true-positive-2 33 | uses: actions/setup-go@v5 34 | with: 35 | go-version: stable 36 | cache: true 37 | 38 | # Finding because setup enables cache explicitly 39 | - name: true-positive-3 40 | uses: actions/setup-go@v5 41 | with: 42 | go-version: stable 43 | cache: "true" 44 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/cache-poisoning/issue-378-repro.yml: -------------------------------------------------------------------------------- 1 | # minimized from https://github.com/zizmorcore/zizmor/issues/378 2 | 3 | name: issue-378 4 | 5 | on: push 6 | 7 | permissions: {} 8 | 9 | jobs: 10 | issue-378: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: Set up Docker Buildx 14 | uses: docker/setup-buildx-action@6524bf65af31da8d45b59e8c27de4bd072b392f5 15 | with: 16 | cache-binary: true 17 | version: latest 18 | 19 | - name: Build docker 20 | uses: docker/build-push-action@48aba3b46d1b1fec4febb7c5d0c644b249a11355 21 | with: 22 | cache-from: type=gha 23 | cache-to: type=gha,mode=max 24 | # push is explicitly disabled, so this is not a publishing 25 | # workflow and therefore no cache-poisoning finding is emitted 26 | push: false 27 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/cache-poisoning/issue-642-repro.yml: -------------------------------------------------------------------------------- 1 | # repro case for https://github.com/zizmorcore/zizmor/issues/642 2 | 3 | name: issue-642 4 | 5 | on: push 6 | 7 | permissions: {} 8 | 9 | jobs: 10 | issue-642-true-positive: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: Set up Docker Buildx 14 | uses: docker/setup-buildx-action@6524bf65af31da8d45b59e8c27de4bd072b392f5 15 | with: 16 | cache-binary: true 17 | version: latest 18 | 19 | - name: Build docker 20 | uses: docker/build-push-action@48aba3b46d1b1fec4febb7c5d0c644b249a11355 21 | with: 22 | cache-from: type=gha 23 | cache-to: type=gha,mode=max 24 | 25 | issue-642-true-negative: 26 | runs-on: ubuntu-latest 27 | steps: 28 | - name: Set up Docker Buildx 29 | uses: docker/setup-buildx-action@6524bf65af31da8d45b59e8c27de4bd072b392f5 30 | with: 31 | # cache-binary is set but version is not, meaning that 32 | # caching is not actually used. 33 | cache-binary: true 34 | 35 | - name: Build docker 36 | uses: docker/build-push-action@48aba3b46d1b1fec4febb7c5d0c644b249a11355 37 | with: 38 | cache-from: type=gha 39 | cache-to: type=gha,mode=max 40 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/cache-poisoning/no-cache-aware-steps.yml: -------------------------------------------------------------------------------- 1 | on: release 2 | 3 | permissions: {} 4 | 5 | jobs: 6 | publish-crate: 7 | runs-on: ubuntu-24.04 8 | 9 | steps: 10 | - name: Project Checkout 11 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 12 | with: 13 | persist-credentials: false 14 | 15 | - name: Publish on crates.io 16 | run: cargo publish --token ${{ secrets.CRATESIO_PUBLISH_TOKEN }} 17 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/cache-poisoning/publisher-step.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches: 4 | - main 5 | 6 | permissions: {} 7 | 8 | jobs: 9 | publish: 10 | runs-on: macos-latest 11 | steps: 12 | - name: Project Checkout 13 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 14 | with: 15 | persist-credentials: false 16 | 17 | - name: Setup CI caching 18 | uses: Swatinem/rust-cache@82a92a6e8fbeee089604da2575dc567ae9ddeaab 19 | 20 | - name: Build snapshot version of artifacts 21 | id: build 22 | run: cargo xtasks darwin-build 23 | 24 | - name: Publish draft release on Github 25 | uses: softprops/action-gh-release@01570a1f39cb168c169c802c3bceb9e93fb10974 26 | with: 27 | name: ${{ steps.build.outputs.version }} 28 | tag_name: ${{ steps.build.outputs.version }} 29 | token: ${{ secrets.GITHUB_RELEASES_TOKEN }} 30 | generate_release_notes: false 31 | draft: false 32 | files: | 33 | target/aarch64-apple-darwin/release/my-app 34 | target/x86_64-apple-darwin/release/my-app 35 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/cache-poisoning/workflow-release-branch-trigger.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches: 4 | - "release-v2.0.0" 5 | 6 | permissions: {} 7 | 8 | jobs: 9 | publish: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Project Checkout 13 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 14 | with: 15 | persist-credentials: false 16 | 17 | - name: Setup CI caching 18 | uses: Swatinem/rust-cache@82a92a6e8fbeee089604da2575dc567ae9ddeaab 19 | 20 | - name: Publish on crates.io 21 | run: cargo publish --token ${{ secrets.CRATESIO_PUBLISH_TOKEN }} 22 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/cache-poisoning/workflow-tag-trigger.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | tags: 4 | - "**" 5 | 6 | permissions: {} 7 | 8 | jobs: 9 | publish: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Project Checkout 13 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 14 | with: 15 | persist-credentials: false 16 | 17 | - name: Setup CI caching 18 | uses: Swatinem/rust-cache@82a92a6e8fbeee089604da2575dc567ae9ddeaab 19 | 20 | - name: Publish on crates.io 21 | if: true # Todo: We should handle that too! 22 | run: cargo publish --token ${{ secrets.CRATESIO_PUBLISH_TOKEN }} 23 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/e2e-menagerie/.github/dummy-action-2/action.yml: -------------------------------------------------------------------------------- 1 | name: dummy-action-2 2 | description: "does nothing in particular" 3 | runs: 4 | using: "composite" 5 | steps: 6 | - run: echo hello 7 | shell: bash 8 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/e2e-menagerie/.github/workflows/another-dummy.yml: -------------------------------------------------------------------------------- 1 | on: push 2 | name: Another Dummy 3 | permissions: {} 4 | 5 | jobs: 6 | dummy: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - run: echo 'dummy' 10 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/e2e-menagerie/.github/workflows/dummy.yml: -------------------------------------------------------------------------------- 1 | on: push 2 | name: Dummy 3 | permissions: {} 4 | 5 | jobs: 6 | dummy: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - run: echo 'dummy' 10 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/e2e-menagerie/.github/workflows/ignored.yaml: -------------------------------------------------------------------------------- 1 | # this file _should_ be ignored due to a .gitignore in the root 2 | # of the e2e-menagerie directory 3 | 4 | on: pull_request_target 5 | name: Ignored 6 | permissions: {} 7 | 8 | jobs: 9 | dummy: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - run: echo 'ignored' 13 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/e2e-menagerie/.gitignore: -------------------------------------------------------------------------------- 1 | # ignored for the purposes of testing, but still checked into the repo 2 | .github/workflows/ignored.yaml 3 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/e2e-menagerie/README.md: -------------------------------------------------------------------------------- 1 | # e2e-menagerie 2 | 3 | This directory behaves like a pseudo GitHub repository. It contains a 4 | `.github/workflows` directory with some sample workflows, as well as a 5 | handful of custom action definitions. It also contains a `.gitignore` 6 | to ensure that we handle ignored files correctly. 7 | 8 | The actual contents of these workflows and actions are not important; 9 | what's important is that they remain static so that `zizmor`'s 10 | snapshot tests don't change. 11 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/e2e-menagerie/dummy-action-1/action.yaml: -------------------------------------------------------------------------------- 1 | name: dummy-action-1 2 | description: "does nothing in particular" 3 | runs: 4 | using: "composite" 5 | steps: 6 | - run: echo hello 7 | shell: bash 8 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/excessive-permissions.yml: -------------------------------------------------------------------------------- 1 | # Adapted from 2 | # https://github.com/woodruffw/gha-hazmat/blob/main/.github/workflows/excessive-permissions.yml 3 | 4 | on: [push] 5 | 6 | jobs: 7 | excessive-permissions: 8 | runs-on: ubuntu-latest 9 | permissions: write-all 10 | steps: 11 | - run: "echo hello" 12 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/excessive-permissions/issue-336-repro.yml: -------------------------------------------------------------------------------- 1 | on: push 2 | 3 | permissions: 4 | contents: write 5 | 6 | jobs: 7 | single: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 11 | with: 12 | persist-credentials: false 13 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/excessive-permissions/issue-472-repro.yml: -------------------------------------------------------------------------------- 1 | # repro case for https://github.com/zizmorcore/zizmor/issues/472 2 | 3 | name: issue-472-repro 4 | 5 | on: 6 | workflow_call: 7 | 8 | # no non-pedantic top-level permissions finding, since 9 | # the workflow is reusable-only 10 | 11 | jobs: 12 | job1: 13 | # no non-pedantic job-level permissions finding, since 14 | # the workflow is reusable-only 15 | runs-on: ubuntu-24.04 16 | steps: 17 | - run: echo hello 18 | 19 | job2: 20 | # normal permissions finding here, since callers are always 21 | # responsible for setting permissions, even if the workflow 22 | # is reusable-only 23 | uses: ./.github/workflows/fake.yml 24 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/excessive-permissions/jobs-broaden-permissions.yml: -------------------------------------------------------------------------------- 1 | on: push 2 | 3 | permissions: {} 4 | 5 | jobs: 6 | job1: 7 | runs-on: ubuntu-latest 8 | permissions: read-all 9 | steps: 10 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 11 | with: 12 | persist-credentials: false 13 | 14 | job2: 15 | runs-on: ubuntu-latest 16 | permissions: write-all 17 | steps: 18 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 19 | with: 20 | persist-credentials: false 21 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/excessive-permissions/reusable-workflow-call.yml: -------------------------------------------------------------------------------- 1 | name: reusable-workflow-call 2 | 3 | on: 4 | workflow_dispatch: 5 | 6 | jobs: 7 | job1: 8 | # finding: reusable jobs should always specify their permissions 9 | uses: ./.github/workflows/zizmor-child.yml 10 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/excessive-permissions/reusable-workflow-other-triggers.yml: -------------------------------------------------------------------------------- 1 | name: reusable-workflow-other-triggers 2 | 3 | on: 4 | workflow_call: 5 | push: 6 | 7 | # regular top-level finding, since we can be triggered by 8 | # either a workflow call or a push 9 | 10 | jobs: 11 | job1: 12 | # regular job-level finding, since we can be triggered by 13 | # either a workflow call or a push 14 | runs-on: ubuntu-24.04 15 | steps: 16 | - run: echo hello 17 | 18 | job2: 19 | # normal permissions finding here, since callers are always 20 | # responsible for setting permissions 21 | uses: ./.github/workflows/fake.yml 22 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/excessive-permissions/workflow-default-perms-all-jobs-explicit.yml: -------------------------------------------------------------------------------- 1 | # two findings in pedantic mode: one for the entire workflow for having 2 | # implicit permissions (pedantic), and one for the 'single' job for having 3 | # implicit permissions 4 | 5 | on: push 6 | 7 | jobs: 8 | job1: 9 | runs-on: ubuntu-latest 10 | permissions: 11 | contents: write 12 | steps: 13 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 14 | with: 15 | persist-credentials: false 16 | 17 | job2: 18 | runs-on: ubuntu-latest 19 | permissions: 20 | id-token: write 21 | steps: 22 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 23 | with: 24 | persist-credentials: false 25 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/excessive-permissions/workflow-default-perms.yml: -------------------------------------------------------------------------------- 1 | # two findings in pedantic mode: one for the entire workflow for having 2 | # implicit permissions (pedantic), and one for the 'single' job for having 3 | # implicit permissions 4 | 5 | on: push 6 | 7 | jobs: 8 | single: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 12 | with: 13 | persist-credentials: false 14 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/excessive-permissions/workflow-empty-perms.yml: -------------------------------------------------------------------------------- 1 | on: push 2 | 3 | # No findings because the workflow clears all permissions, and the jobs 4 | # inherit the cleared permissions. 5 | permissions: {} 6 | 7 | jobs: 8 | job1: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 12 | with: 13 | persist-credentials: false 14 | 15 | job2: 16 | runs-on: ubuntu-latest 17 | steps: 18 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 19 | with: 20 | persist-credentials: false 21 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/excessive-permissions/workflow-read-all.yml: -------------------------------------------------------------------------------- 1 | on: push 2 | 3 | permissions: read-all 4 | 5 | jobs: 6 | job1: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 10 | with: 11 | persist-credentials: false 12 | 13 | job2: 14 | runs-on: ubuntu-latest 15 | steps: 16 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 17 | with: 18 | persist-credentials: false 19 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/excessive-permissions/workflow-write-all.yml: -------------------------------------------------------------------------------- 1 | on: push 2 | 3 | permissions: write-all 4 | 5 | jobs: 6 | job1: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 10 | with: 11 | persist-credentials: false 12 | 13 | job2: 14 | runs-on: ubuntu-latest 15 | steps: 16 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 17 | with: 18 | persist-credentials: false 19 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/excessive-permissions/workflow-write-explicit.yml: -------------------------------------------------------------------------------- 1 | on: push 2 | 3 | # Each of these is flagged as too broad. 4 | permissions: 5 | contents: write 6 | id-token: write 7 | nonexistent: write 8 | 9 | jobs: 10 | job1: 11 | runs-on: ubuntu-latest 12 | # not flagged because it's within the job scope 13 | permissions: 14 | deployments: write 15 | steps: 16 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 17 | with: 18 | persist-credentials: false 19 | 20 | job2: 21 | runs-on: ubuntu-latest 22 | steps: 23 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 24 | with: 25 | persist-credentials: false 26 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/forbidden-uses/configs/allow-all.yml: -------------------------------------------------------------------------------- 1 | rules: 2 | unpinned-uses: 3 | config: 4 | policies: 5 | # just to make unrelated findings go away 6 | "*": ref-pin 7 | 8 | forbidden-uses: 9 | config: 10 | allow: 11 | - "*" 12 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/forbidden-uses/configs/allow-some-refs.yml: -------------------------------------------------------------------------------- 1 | rules: 2 | unpinned-uses: 3 | config: 4 | policies: 5 | # just to make unrelated findings go away 6 | "*": ref-pin 7 | 8 | forbidden-uses: 9 | config: 10 | allow: 11 | - actions/setup-python@v4 12 | - actions/checkout@v3 # workflow actually uses v4 13 | - pypa/gh-action-pypi-publish@release/v1 14 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/forbidden-uses/configs/allow-some.yml: -------------------------------------------------------------------------------- 1 | rules: 2 | unpinned-uses: 3 | config: 4 | policies: 5 | # just to make unrelated findings go away 6 | "*": ref-pin 7 | 8 | forbidden-uses: 9 | config: 10 | allow: 11 | - "actions/checkout" 12 | - "pypa/gh-action-pypi-publish" 13 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/forbidden-uses/configs/deny-all.yml: -------------------------------------------------------------------------------- 1 | rules: 2 | unpinned-uses: 3 | config: 4 | policies: 5 | # just to make unrelated findings go away 6 | "*": ref-pin 7 | 8 | forbidden-uses: 9 | config: 10 | deny: 11 | - "*" 12 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/forbidden-uses/configs/deny-some-refs.yml: -------------------------------------------------------------------------------- 1 | rules: 2 | unpinned-uses: 3 | config: 4 | policies: 5 | # just to make unrelated findings go away 6 | "*": ref-pin 7 | 8 | forbidden-uses: 9 | config: 10 | deny: 11 | - actions/setup-python@v4 12 | - actions/checkout@v3 # workflow actually uses v4 13 | - pypa/gh-action-pypi-publish@release/v1 14 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/forbidden-uses/configs/deny-some.yml: -------------------------------------------------------------------------------- 1 | rules: 2 | unpinned-uses: 3 | config: 4 | policies: 5 | # just to make unrelated findings go away 6 | "*": ref-pin 7 | 8 | forbidden-uses: 9 | config: 10 | deny: 11 | - "actions/checkout" 12 | - "pypa/gh-action-pypi-publish" 13 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/forbidden-uses/forbidden-uses-menagerie.yml: -------------------------------------------------------------------------------- 1 | name: forbidden-uses-menagerie 2 | 3 | on: [push] 4 | 5 | permissions: {} 6 | 7 | jobs: 8 | menagerie: 9 | runs-on: ubuntu-latest 10 | 11 | steps: 12 | - uses: actions/setup-python@v4 13 | - uses: pypa/gh-action-pypi-publish@release/v1 14 | - uses: actions/checkout@v4 15 | with: 16 | persist-credentials: false 17 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/github-env/action.yml: -------------------------------------------------------------------------------- 1 | # demo of a composite action being flagged by github-env 2 | 3 | name: github-env-composite-action 4 | description: github-env-composite-action 5 | 6 | runs: 7 | using: composite 8 | steps: 9 | - name: true-positive-1 10 | run: | 11 | echo "foo=$(bar)" >> $GITHUB_ENV 12 | shell: bash 13 | 14 | - name: true-positive-2 15 | run: | 16 | echo "foo=$env:BAR" >> $env:GITHUB_ENV 17 | shell: pwsh 18 | 19 | - name: true-positive-3 20 | run: | 21 | echo LIBRARY=%LIBRARY% >> %GITHUB_ENV% 22 | shell: cmd 23 | 24 | - name: true-negative-4 25 | # No finding because foo=bar is wholly static. 26 | run: | 27 | echo foo=bar >> $GITHUB_ENV 28 | shell: bash 29 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/github-env/github-path.yml: -------------------------------------------------------------------------------- 1 | on: 2 | pull_request_target: # zizmor: ignore[dangerous-triggers] 3 | 4 | permissions: {} 5 | 6 | jobs: 7 | vulnerable: 8 | runs-on: ubuntu-latest 9 | 10 | steps: 11 | - name: Passes the title around 12 | env: 13 | TITLE: ${{ github.event.pull_request.title }} 14 | run: | 15 | message=$(echo "$TITLE" | grep -oP '[{\[][^}\]]+[}\]]' | sed 's/{\|}\|\[\|\]//g') 16 | echo "$message" >> $GITHUB_PATH 17 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/github-env/issue-397-repro.yml: -------------------------------------------------------------------------------- 1 | on: 2 | pull_request_target: # zizmor: ignore[dangerous-triggers] 3 | 4 | permissions: {} 5 | 6 | jobs: 7 | issue-397-repro: 8 | runs-on: ubuntu-latest 9 | 10 | steps: 11 | - name: Passes the title around 12 | env: 13 | TITLE: ${{ github.event.pull_request.title }} 14 | run: | 15 | message=$(echo "$TITLE" | grep -oP '[{\[][^}\]]+[}\]]' | sed 's/{\|}\|\[\|\]//g') 16 | echo "$message" >> $GITHUB_PATH 17 | # should be handled as bash 18 | shell: /bin/bash 19 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/github_env.yml: -------------------------------------------------------------------------------- 1 | on: 2 | pull_request_target: # zizmor: ignore[dangerous-triggers] 3 | 4 | permissions: {} 5 | 6 | jobs: 7 | vulnerable: 8 | runs-on: ubuntu-latest 9 | 10 | steps: 11 | - name: Passes the title around 12 | env: 13 | TITLE: ${{ github.event.pull_request.title }} 14 | run: | 15 | message=$(echo "$TITLE" | grep -oP '[{\[][^}\]]+[}\]]' | sed 's/{\|}\|\[\|\]//g') 16 | echo "message=$message" >> $GITHUB_ENV 17 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/hardcoded-credentials.yml: -------------------------------------------------------------------------------- 1 | # Adapted from 2 | # https://github.com/woodruffw/gha-hazmat/blob/main/.github/workflows/hardcoded-credentials.yml 3 | 4 | on: 5 | push: 6 | branches: 7 | - master 8 | workflow_dispatch: 9 | 10 | permissions: {} 11 | 12 | jobs: 13 | test: 14 | runs-on: ubuntu-latest 15 | container: 16 | image: fake.example.com/example 17 | credentials: 18 | username: user 19 | password: hackme 20 | steps: 21 | - run: echo 'vulnerable!' 22 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/inlined-ignores.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches: 4 | - master 5 | workflow_dispatch: 6 | 7 | permissions: {} 8 | 9 | jobs: 10 | artipacked-ignored: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # zizmor: ignore[artipacked] 14 | 15 | insecure-commands-ignored: 16 | runs-on: ubuntu-latest 17 | env: 18 | ACTIONS_ALLOW_UNSECURE_COMMANDS: yes # zizmor: ignore[insecure-commands] 19 | steps: 20 | - run: echo "I shall pass!" 21 | 22 | hardcoded-credentials-ignored: 23 | runs-on: ubuntu-latest 24 | container: 25 | image: fake.example.com/example # zizmor: ignore[unpinned-images] 26 | credentials: 27 | username: user 28 | password: hackme # zizmor: ignore[hardcoded-container-credentials] 29 | steps: 30 | - run: echo 'This is a honeypot actually!' 31 | 32 | unpinned-uses-ignored: 33 | runs-on: ubuntu-latest 34 | steps: 35 | - uses: github/codeql-action/upload-sarif # zizmor: ignore[unpinned-uses] 36 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/insecure-commands.yml: -------------------------------------------------------------------------------- 1 | on: pull_request 2 | 3 | name: insecure-commands 4 | 5 | permissions: {} 6 | 7 | jobs: 8 | some-dangerous-job: 9 | runs-on: ubuntu-latest 10 | env: 11 | ACTIONS_ALLOW_UNSECURE_COMMANDS: true 12 | steps: 13 | - run: echo "don't do this" 14 | 15 | env-via-matrix: 16 | runs-on: ubuntu-latest 17 | strategy: 18 | matrix: 19 | env: 20 | - ACTIONS_ALLOW_UNSECURE_COMMANDS: true 21 | 22 | steps: 23 | - run: echo "don't do this" 24 | env: ${{ matrix.env }} 25 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/insecure-commands/action.yml: -------------------------------------------------------------------------------- 1 | # demo of a composite action being flagged by insecure-commands 2 | 3 | name: insecure-commands-composite-action 4 | description: insecure-commands-composite-action 5 | 6 | inputs: 7 | insecure-commands: 8 | default: "yes" 9 | description: "do something insecure" 10 | 11 | runs: 12 | using: composite 13 | steps: 14 | - name: true-positive-1 15 | run: | 16 | echo "hello!" 17 | shell: bash 18 | env: 19 | ACTIONS_ALLOW_UNSECURE_COMMANDS: true 20 | 21 | - name: true-positive-2 22 | run: | 23 | echo "hello!" 24 | shell: bash 25 | env: 26 | ACTIONS_ALLOW_UNSECURE_COMMANDS: true 27 | 28 | - name: true-positive-3 29 | run: | 30 | echo "hello!" 31 | shell: bash 32 | env: ${{ mystery }} 33 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/insecure-commands/issue-839-repro.yml: -------------------------------------------------------------------------------- 1 | on: pull_request 2 | 3 | name: issue-839-repro 4 | 5 | permissions: {} 6 | 7 | jobs: 8 | some-dangerous-job: 9 | runs-on: ubuntu-latest 10 | env: 11 | ACTIONS_ALLOW_UNSECURE_COMMANDS: "true" 12 | steps: 13 | - run: echo "don't do this" 14 | 15 | env-via-matrix: 16 | runs-on: ubuntu-latest 17 | strategy: 18 | matrix: 19 | env: 20 | - ACTIONS_ALLOW_UNSECURE_COMMANDS: " true" 21 | 22 | steps: 23 | - run: echo "don't do this" 24 | env: ${{ matrix.env }} 25 | 26 | this-is-ok-1: 27 | runs-on: ubuntu-latest 28 | steps: 29 | - run: echo "this is ok" 30 | env: 31 | ACTIONS_ALLOW_UNSECURE_COMMANDS: false 32 | 33 | this-is-ok-2: 34 | runs-on: ubuntu-latest 35 | steps: 36 | - run: echo "this is ok" 37 | env: 38 | ACTIONS_ALLOW_UNSECURE_COMMANDS: "false" 39 | 40 | this-is-ok-3: 41 | runs-on: ubuntu-latest 42 | steps: 43 | - run: echo "this is ok" 44 | env: 45 | ACTIONS_ALLOW_UNSECURE_COMMANDS: yes # does not evaluate to true 46 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/invalid/bad-yaml-1.yml: -------------------------------------------------------------------------------- 1 | lol 2 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/invalid/bad-yaml-2.yml: -------------------------------------------------------------------------------- 1 | inconsistent: 2 | foo: bar 3 | baz: qux 4 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/invalid/blank.yml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/invalid/comment-only.yml: -------------------------------------------------------------------------------- 1 | # foo 2 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/invalid/empty-action/action.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zizmorcore/zizmor/a4a657f9bec0aced315811dc9983f703ee0d4e1b/crates/zizmor/tests/integration/test-data/invalid/empty-action/action.yml -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/invalid/empty.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zizmorcore/zizmor/a4a657f9bec0aced315811dc9983f703ee0d4e1b/crates/zizmor/tests/integration/test-data/invalid/empty.yml -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/invalid/invalid-action-1/action.yml: -------------------------------------------------------------------------------- 1 | name: "Action" 2 | inputs: 3 | some-input: 4 | description: "Input description" 5 | default: "default" 6 | outputs: 7 | some-output: 8 | description: "Output description" 9 | runs: 10 | # using: docker 11 | image: Dockerfile 12 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/invalid/invalid-action-2/action.yml: -------------------------------------------------------------------------------- 1 | inconsistent: 2 | foo: bar 3 | baz: qux 4 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/invalid/invalid-workflow-2.yml: -------------------------------------------------------------------------------- 1 | name: Invalid 2 | 3 | boom: 4 | 5 | on: 6 | workflow_call: 7 | inputs: 8 | input: 9 | description: Input 10 | 11 | permissions: {} 12 | 13 | jobs: 14 | valid: 15 | runs-on: ubuntu-latest 16 | steps: 17 | - run: echo 'invalid' 18 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/invalid/invalid-workflow.yml: -------------------------------------------------------------------------------- 1 | name: "invalid-workflow" 2 | 3 | on: 4 | repository_dispatch: 5 | 6 | permissions: 7 | contents: read 8 | 9 | jobs: 10 | invalid: 11 | name: "invalid" 12 | 13 | steps: 14 | - run: echo hello 15 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/issue-612-repro/action.yml: -------------------------------------------------------------------------------- 1 | # Repro case for #612. 2 | # Ensures that we don't unintuitively ignore ignore comments 3 | # when they occur on a line that's conceptually part of the finding's 4 | # span but is not included in the visible span rendering. 5 | # 6 | # This should emit no findings, only ignored findings. 7 | 8 | name: "Automerge dependabot and pre-commit.ci PRs" 9 | description: "Action merging dependabot and pre-commit.ci PRs." 10 | 11 | inputs: 12 | approver: 13 | description: "Approver GitHub ID." 14 | required: true 15 | approver-token: 16 | description: "Approver GitHub token." 17 | required: true 18 | 19 | runs: 20 | using: "composite" 21 | steps: 22 | - name: Verify allowed PRs (dependabot and pre-commit.ci) 23 | id: verify-allowed-prs # zizmor: ignore[template-injection] this works fine 24 | shell: bash 25 | run: | 26 | # Check if the author is either dependabot or pre-commit.ci. 27 | if [[ ${{ github.event.pull_request.user.login }} == 'dependabot[bot]' ]] || [[ ${{ github.event.pull_request.user.login }} == 'pre-commit-ci[bot]' ]]; then 28 | true 29 | else 30 | exit 1 31 | fi 32 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/obfuscation.yml: -------------------------------------------------------------------------------- 1 | on: pull_request 2 | 3 | name: obfuscation 4 | 5 | permissions: {} 6 | 7 | jobs: 8 | obfuscated-uses: 9 | runs-on: ubuntu-latest 10 | steps: 11 | # trailing slash 12 | - uses: actions/checkout/@v4 13 | 14 | # many trailing slashes 15 | - uses: actions/checkout////@v4 16 | 17 | # pointless use of . 18 | - uses: github/codeql-action/./init@v2 19 | - uses: actions/checkout/.@v4 20 | 21 | # pointless use of .. 22 | - uses: actions/cache/save/../save@v4 23 | 24 | obfuscated-exprs: 25 | runs-on: ubuntu-latest 26 | steps: 27 | # trivially reducible expressions 28 | - run: | 29 | echo ${{ '' }} 30 | echo ${{ 'a' }} 31 | echo ${{ true }} 32 | echo ${{ true && false }} 33 | echo ${{ true || false }} 34 | echo ${{ 1 > 2 || true }} 35 | echo ${{ 1 != 2}} 36 | 37 | # trivially reducible functions 38 | - run: | 39 | echo ${{ format('{0}', 'abc') }} 40 | echo ${{ format('{0} {1}', 'abc', 'def') }} 41 | echo ${{ format('{0} {1}', 'abc', format('{0}', 'def')) }} 42 | echo ${{ startsWith('abc', 'a') }} 43 | echo ${{ ENDSWITH('abc', 'c') }} 44 | 45 | # reducible subexpressions 46 | - run: | # zizmor: ignore[template-injection] not this test 47 | # inner format(...) is reducible 48 | echo ${{ format('{0}, {1}', github.event.number, format('{0}', 'abc')) }} 49 | # inner || is reducible 50 | echo ${{ format('{0}, {1}', github.event.number, format('{0} {1}', github.event.number, true || false)) }} 51 | # inner [...] is reducible 52 | echo ${{ foobar[format('{0}', 'event')]}} 53 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/overprovisioned-secrets.yml: -------------------------------------------------------------------------------- 1 | on: push 2 | 3 | permissions: {} 4 | 5 | jobs: 6 | test: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - run: echo "${stuff} ${otherstuff} ${morestuff}" 10 | env: 11 | # NOT OK: injects the entire secrets context into the runner 12 | stuff: ${{ format('{0}', toJSON(secrets)) }} 13 | # OK: selectively injects a single secret 14 | otherstuff: ${{ secrets.otherstuff }} 15 | # OK: weird, but still selectively injects only a single secret 16 | morestuff: ${{ toJSON(secrets.morestuff) }} 17 | 18 | - run: | 19 | some-random-command <<< "${secrets_json}" 20 | env: 21 | secrets_json: ${{ toJSON(secrets) }} 22 | 23 | - run: | 24 | some-random-command <<< "${secrets_json}" 25 | env: 26 | # tests that we handle ignore comments within raw spans correctly 27 | secrets_json: ${{ toJSON(secrets) }} # zizmor: ignore[overprovisioned-secrets] 28 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/ref-confusion.yml: -------------------------------------------------------------------------------- 1 | name: example 2 | on: [push] 3 | 4 | permissions: {} 5 | 6 | jobs: 7 | commit: 8 | runs-on: ubuntu-latest 9 | steps: 10 | # NOT OK: `confusable` is both a tag and a branch 11 | - uses: woodruffw/gha-hazmat/ref-confusion@confusable 12 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/ref-confusion/issue-518-repro.yml: -------------------------------------------------------------------------------- 1 | name: ISSUE-518-REPRO 2 | on: [push] 3 | 4 | permissions: {} 5 | 6 | jobs: 7 | issue-518-repro: 8 | runs-on: ubuntu-latest 9 | 10 | steps: 11 | - name: Install Task 12 | uses: arduino/setup-task@v2 13 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/secrets-inherit.yml: -------------------------------------------------------------------------------- 1 | on: push 2 | 3 | permissions: {} 4 | 5 | jobs: 6 | call-workflow-vulnerable-1: 7 | uses: octo-org/example-repo/.github/workflows/called-workflow.yml@main 8 | # NOT OK: unconditionally inherits 9 | secrets: inherit 10 | 11 | call-workflow-not-vulnerable-2: 12 | uses: octo-org/example-repo/.github/workflows/called-workflow.yml@main 13 | # OK: explicitly forwards intended secrets 14 | secrets: 15 | special-secret: ${{ secrets.special-secret }} 16 | 17 | call-workflow-not-vulnerable-3: 18 | uses: octo-org/example-repo/.github/workflows/called-workflow.yml@main 19 | # OK: no secrets forwarded 20 | 21 | call-workflow-not-vulnerable-4: 22 | uses: octo-org/example-repo/.github/workflows/called-workflow.yml@main 23 | # OK: no secrets forwarded 24 | secrets: {} 25 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/self-hosted.yml: -------------------------------------------------------------------------------- 1 | # Adapted from 2 | # https://github.com/woodruffw/gha-hazmat/blob/main/.github/workflows/self-hosted.yml 3 | on: 4 | push: 5 | 6 | permissions: {} 7 | 8 | jobs: 9 | whops: 10 | runs-on: [self-hosted, my-ubuntu-box] 11 | 12 | steps: 13 | - run: echo "hello from a self-hosted runner" 14 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/self-hosted/issue-283-repro.yml: -------------------------------------------------------------------------------- 1 | name: Workflow 2 | 3 | on: 4 | workflow_call: 5 | inputs: 6 | os: 7 | type: string 8 | 9 | permissions: {} 10 | 11 | jobs: 12 | deploy: 13 | runs-on: ${{inputs.os}} 14 | steps: 15 | - run: echo "Hello world" 16 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/self-hosted/self-hosted-matrix-dimension.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | 4 | permissions: {} 5 | 6 | jobs: 7 | whops: 8 | runs-on: ${{ matrix.os }} 9 | 10 | strategy: 11 | matrix: 12 | os: [self-hosted, ubuntu-latest] 13 | steps: 14 | - run: echo \"hello from a self-hosted runner\" 15 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/self-hosted/self-hosted-matrix-exclusion.yml: -------------------------------------------------------------------------------- 1 | # Adapted from 2 | # https://github.com/woodruffw/gha-hazmat/blob/main/.github/workflows/self-hosted.yml 3 | on: 4 | push: 5 | 6 | permissions: {} 7 | 8 | jobs: 9 | ok: 10 | runs-on: ${{ matrix.os }} 11 | 12 | strategy: 13 | matrix: 14 | os: [self-hosted, macOS-latest, ubuntu-latest] 15 | exclude: 16 | - os: self-hosted # Wont trigger a finding 17 | steps: 18 | - run: echo \"hello from a Github runner\" 19 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/self-hosted/self-hosted-matrix-inclusion.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | 4 | permissions: {} 5 | 6 | jobs: 7 | whops: 8 | runs-on: ${{ matrix.os }} 9 | 10 | strategy: 11 | matrix: 12 | os: [macOS-latest, ubuntu-latest] 13 | include: 14 | - os: self-hosted 15 | steps: 16 | - run: echo \"hello from a self-hosted runner\" 17 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/self-hosted/self-hosted-runner-group.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | 4 | permissions: {} 5 | 6 | jobs: 7 | whops: 8 | runs-on: 9 | group: ubuntu-runners 10 | 11 | steps: 12 | - run: echo \"hello from a self-hosted runner\" 13 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/self-hosted/self-hosted-runner-label.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | 4 | permissions: {} 5 | 6 | jobs: 7 | whops: 8 | runs-on: [self-hosted, linux, arm64] 9 | 10 | steps: 11 | - run: echo \"hello from a self-hosted runner\" 12 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/several-vulnerabilities.yml: -------------------------------------------------------------------------------- 1 | name: several vulnerabilities 2 | on: 3 | pull_request_target: 4 | 5 | permissions: write-all 6 | 7 | jobs: 8 | hackme: 9 | name: hackme 10 | runs-on: ubuntu-latest 11 | permissions: write-all 12 | 13 | steps: 14 | - name: hackme 15 | run: | 16 | echo "${{ github.event.pull_request.title }}" 17 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/stale-action-refs.yml: -------------------------------------------------------------------------------- 1 | on: pull_request 2 | 3 | name: stale-actions-refs 4 | permissions: {} 5 | 6 | jobs: 7 | non-stale: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/checkout@main 11 | with: 12 | persist-credentials: false 13 | - uses: actions/checkout@v4 14 | with: 15 | persist-credentials: false 16 | - uses: actions/checkout@v4.2.2 17 | with: 18 | persist-credentials: false 19 | # v4.2.2 commit 20 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 21 | with: 22 | persist-credentials: false 23 | 24 | stale: 25 | runs-on: ubuntu-latest 26 | steps: 27 | # non-tagged commit 28 | - uses: actions/checkout@009b9ae9e446ad8d9b8c809870b0fbcc5e03573e 29 | with: 30 | persist-credentials: false 31 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/template-injection.yml: -------------------------------------------------------------------------------- 1 | # Adapted from 2 | # https://github.com/woodruffw/gha-hazmat/blob/main/.github/workflows/template-injection.yml 3 | 4 | name: example 5 | on: 6 | issues: 7 | 8 | permissions: {} 9 | 10 | jobs: 11 | inject-me: 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # tag=v7.0.1 16 | with: 17 | script: | 18 | return "doing a thing: ${{ github.event.issue.title }}" 19 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/template-injection/codeql-sinks.yml: -------------------------------------------------------------------------------- 1 | # ensures that we flag template injections derived from CodeQL's sinks 2 | 3 | name: pwsh-script 4 | 5 | on: pull_request 6 | 7 | permissions: {} 8 | 9 | jobs: 10 | some-job: 11 | runs-on: ubuntu-latest 12 | 13 | steps: 14 | - uses: mikefarah/yq@b534aa9ee5d38001fba3cd8fe254a037e4847b37 # v4.45.4 15 | with: 16 | cmd: ${{ github.event.pull_request.title }} 17 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/template-injection/dataflow.yml: -------------------------------------------------------------------------------- 1 | name: template-injection-dataflow 2 | 3 | on: pull_request 4 | 5 | permissions: {} 6 | 7 | jobs: 8 | test: 9 | runs-on: ubuntu-latest 10 | 11 | steps: 12 | # OK: dangerous context but without dataflow 13 | - name: ok 14 | run: | 15 | echo "issue is foo: ${{ github.event.pull_request.title == 'foo' }}" 16 | echo "issue contains foo: ${{ contains(github.event.pull_request.title, 'foo') }}" 17 | 18 | # NOT OK: function call propagates dataflow 19 | - name: notok 20 | run: | 21 | echo "${{ toJSON(github.event.pull_request.title) }}" 22 | echo "${{ format('{0}', github.event.pull_request.title) }}" 23 | echo "${{ join(github.event.pull_request.labels.*.name) }}" 24 | 25 | # NOT OK: control flow propagates dataflow 26 | - name: notok-2 27 | run: | 28 | echo "${{ github.event.pull_request.title || github.event.issue.title }}" 29 | echo "${{ false || github.event.issue.title }}" 30 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/template-injection/false-positive-menagerie.yml: -------------------------------------------------------------------------------- 1 | name: false-positive-menagerie 2 | 3 | on: pull_request 4 | 5 | permissions: {} 6 | 7 | jobs: 8 | false-positive-menagerie: 9 | runs-on: ubuntu-latest 10 | 11 | steps: 12 | - name: false-positive-menagerie 13 | run: | 14 | # PR#402 15 | echo "${{ github.action_path }}" 16 | # PR#412 17 | echo "${{ github.server_url }}" 18 | # PR#445 19 | echo "${{ github.event.pull_request.base.sha }}" 20 | # PR#636 21 | echo "${{ github.event.pull_request.head.sha }}" 22 | # PR#661 23 | echo "${{ github.job }}" 24 | # PR#675 25 | echo "${{ github.event.pull_request.head.repo.fork }}" 26 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/template-injection/issue-339-repro.yml: -------------------------------------------------------------------------------- 1 | # minimized from https://github.com/zizmorcore/zizmor/issues/339 2 | 3 | name: "Publish" 4 | 5 | on: 6 | repository_dispatch: 7 | 8 | permissions: 9 | contents: read 10 | 11 | jobs: 12 | find-run: 13 | name: "Find latest kit.yml run" 14 | runs-on: "ubuntu-latest" 15 | outputs: 16 | run-id: ${{ steps.run-id.outputs.run-id }} 17 | 18 | steps: 19 | - name: "Find latest kit.yml run" 20 | id: runs 21 | uses: octokit/request-action@dad4362715b7fb2ddedf9772c8670824af564f0d # v2.4.0 22 | with: 23 | route: GET /repos/nedbat/coveragepy/actions/workflows/kit.yml/runs 24 | env: 25 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 26 | 27 | - name: "Record run id" 28 | id: run-id 29 | run: | 30 | echo "run-id=${{ fromJson(steps.runs.outputs.data).workflow_runs[0].id }}" >> "$GITHUB_OUTPUT" 31 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/template-injection/issue-418-repro.yml: -------------------------------------------------------------------------------- 1 | # reproduction case for https://github.com/zizmorcore/zizmor/issues/418 2 | 3 | name: Test 4 | 5 | on: 6 | issue_comment: 7 | types: [created] 8 | 9 | permissions: {} 10 | 11 | jobs: 12 | stop: 13 | runs-on: ubuntu-latest 14 | env: 15 | COMMENT_ID: "1234" 16 | steps: 17 | - uses: actions/github-script@v7 18 | with: 19 | script: console.log("${{ env.COMMENT_ID }}") 20 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/template-injection/issue-749-repro.yml: -------------------------------------------------------------------------------- 1 | # see https://github.com/zizmorcore/zizmor/issues/749 2 | 3 | name: issue-749-repro 4 | 5 | on: push 6 | 7 | permissions: {} 8 | 9 | jobs: 10 | inject-me: 11 | runs-on: ubuntu-latest 12 | 13 | steps: 14 | - uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # tag=v7.0.1 15 | with: 16 | # checks that we don't flag known-safe contexts as a finding 17 | # just because they're expressed through indices rather than 18 | # the normal dotted notation 19 | script: | 20 | return "doing a thing: ${{ github['event']['issue']['number'] }}" 21 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/template-injection/patterns.yml: -------------------------------------------------------------------------------- 1 | # patterns.yml: tests that we normalize contexts correctly for the FST 2 | # lookup inside template-injection 3 | 4 | name: patterns 5 | 6 | on: workflow_run # zizmor: ignore[dangerous-triggers] 7 | 8 | permissions: {} 9 | 10 | jobs: 11 | inject-me: 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | # these are safe and are correctly ignored by default by zizmor, 16 | # since they're all instantiations of the same fixed-cap pattern present 17 | # in the FST. 18 | - name: safe 19 | run: | 20 | echo "${{ github.event.workflow_run.pull_requests.*.base.repo.id }}" 21 | echo "${{ github.event.workflow_run.pull_requests[0].base.repo.id }}" 22 | echo "${{ github.event.workflow_run.pull_requests[1].base.repo.id }}" 23 | 24 | # these are unsafe and should be flagged by default by zizmor, 25 | # since they're all instantiations of the same arbitrary-cap pattern 26 | # present in the FST. 27 | - name: unsafe 28 | run: | 29 | echo "${{ github.event.changes.new_discussion.labels.*.name }}" 30 | echo "${{ github.event.changes.new_discussion.labels[0].name }}" 31 | echo "${{ github.event.changes.new_discussion.labels[1].name }}" 32 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/template-injection/pr-317-repro.yml: -------------------------------------------------------------------------------- 1 | # reproduction case for https://github.com/zizmorcore/zizmor/pull/317 2 | 3 | name: PR-317-REPRO 4 | on: 5 | pull_request: 6 | 7 | permissions: {} 8 | 9 | jobs: 10 | PR-317-REPRO: 11 | name: PR-317-REPRO 12 | runs-on: ubuntu-latest 13 | 14 | strategy: 15 | matrix: 16 | include: 17 | - foo: 123 18 | bar: abc 19 | 20 | - foo: 456 21 | # BUG: this should be detected as a matrix expansion 22 | # candidate containing an expression, but was not 23 | # before #317. 24 | bar: prefix-${{ github.repository_owner }} 25 | 26 | steps: 27 | - run: | 28 | echo ${{ matrix.bar }} 29 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/template-injection/pr-425-backstop/action.yml: -------------------------------------------------------------------------------- 1 | name: pr-425-backstop 2 | description: Functional test for changes in PR#425 3 | 4 | inputs: 5 | expandme: 6 | required: true 7 | description: expand me 8 | 9 | runs: 10 | using: composite 11 | steps: 12 | - name: case1 13 | run: | 14 | hello ${{ inputs.expandme }} 15 | shell: bash 16 | 17 | - name: case2 18 | uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea 19 | with: 20 | script: return "${{ inputs.expandme }}" 21 | 22 | - name: case3 23 | uses: azure/cli@089eac9d8cc39f5d003e94f8b65efc51076c9cbd 24 | with: 25 | inlineScript: | 26 | echo "hello ${{ inputs.expandme }}" 27 | 28 | - name: case4 29 | uses: azure/powershell 30 | with: 31 | inlineScript: Get-AzVM -ResourceGroupName "${{ inputs.expandme }}" 32 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/template-injection/pwsh-script.yml: -------------------------------------------------------------------------------- 1 | name: pwsh-script 2 | 3 | on: pull_request 4 | 5 | permissions: {} 6 | 7 | jobs: 8 | some-job: 9 | runs-on: ubuntu-latest 10 | 11 | steps: 12 | - uses: Amadevus/pwsh-script@97a8b211a5922816aa8a69ced41fa32f23477186 # v2.0.3 13 | with: 14 | script: | 15 | Write-ActionDebug "Running for pull request ${{ github.event.pull_request.title }}" 16 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/template-injection/static-env.yml: -------------------------------------------------------------------------------- 1 | name: static-env 2 | on: 3 | pull_request: 4 | 5 | env: 6 | foo: foo 7 | bar: ${{ github.event.issue.title }} 8 | baz: baz 9 | quux: ${{ github.event.issue.title }} 10 | 11 | permissions: {} 12 | 13 | jobs: 14 | static-env-1: 15 | name: static-env 16 | runs-on: ubuntu-latest 17 | 18 | env: 19 | foo: ${{ github.event.issue.title }} 20 | bar: bar 21 | 22 | steps: 23 | # OK: foo is static (step-level) 24 | - name: step-level-static 25 | run: | 26 | echo ${{ env.foo }} 27 | env: 28 | foo: foo 29 | 30 | # OK: bar is static (job-level) 31 | - name: job-level-static 32 | run: | 33 | echo ${{ env.bar }} 34 | 35 | # OK: baz is static (workflow-level) 36 | - name: workflow-level-static 37 | run: | 38 | echo ${{ env.baz }} 39 | 40 | # NOT OK: bar is not static (step-level) 41 | - name: step-level-non-static 42 | run: | 43 | echo ${{ env.bar }} 44 | env: 45 | bar: ${{ github.event.issue.title }} 46 | 47 | # NOT OK: foo is not static (job-level) 48 | - name: job-level-non-static 49 | run: | 50 | echo ${{ env.foo }} 51 | 52 | # NOT OK: quux is not static (workflow-level) 53 | - name: workflow-level-non-static 54 | run: | 55 | echo ${{ env.quux }} 56 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/template-injection/template-injection-dynamic-matrix.yml: -------------------------------------------------------------------------------- 1 | # Adapted from 2 | # https://github.com/woodruffw/gha-hazmat/blob/main/.github/workflows/template-injection.yml 3 | name: paw-me 4 | on: 5 | issues: 6 | 7 | permissions: {} 8 | 9 | jobs: 10 | not-ok: 11 | runs-on: ubuntu-latest 12 | 13 | strategy: 14 | matrix: 15 | frob: ["nothing", "special"] 16 | dynamic: ${{ github.event.client_payload.mystery_meat }} 17 | 18 | steps: 19 | - name: Please dont 20 | run: | 21 | echo "doing a thing: ${{ matrix.dynamic }}" 22 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/template-injection/template-injection-static-matrix.yml: -------------------------------------------------------------------------------- 1 | # Adapted from 2 | # https://github.com/woodruffw/gha-hazmat/blob/main/.github/workflows/template-injection.yml 3 | name: safe 4 | on: 5 | issues: 6 | 7 | permissions: {} 8 | 9 | jobs: 10 | ok-ish: 11 | runs-on: ubuntu-latest 12 | 13 | strategy: 14 | matrix: 15 | frob: ["nothing", "special"] 16 | 17 | steps: 18 | - name: Nothing to fear 19 | run: | 20 | echo "issue created: ${{ matrix.frob }}" 21 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/unpinned-uses.yml: -------------------------------------------------------------------------------- 1 | name: example 2 | on: [push] 3 | 4 | permissions: {} 5 | 6 | jobs: 7 | unpinned-0: 8 | runs-on: ubuntu-latest 9 | steps: 10 | # NOT OK: unpinned 11 | - uses: actions/checkout 12 | with: 13 | persist-credentials: false 14 | 15 | # PEDANTIC: pinned but unhashed 16 | - uses: actions/checkout@v3 17 | with: 18 | persist-credentials: false 19 | 20 | # NOT OK: unpinned 21 | - uses: github/codeql-action/upload-sarif 22 | 23 | # NOT OK: unpinned 24 | - uses: docker://ubuntu 25 | with: 26 | entrypoint: /bin/echo 27 | args: hello! 28 | 29 | # NOT OK: unpinned 30 | - uses: docker://ghcr.io/pypa/gh-action-pypi-publish 31 | with: 32 | entrypoint: /bin/echo 33 | args: hello! 34 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/unpinned-uses/action.yml: -------------------------------------------------------------------------------- 1 | name: unpinned-uses-composite-action 2 | description: unpinned-uses-composite-action 3 | 4 | runs: 5 | using: composite 6 | steps: 7 | - name: true-positive-1 8 | uses: asdf-vm/actions/setup@v3 9 | 10 | - name: true-positive-2 11 | uses: asdf-vm/actions/setup@main 12 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/unpinned-uses/configs/composite-2.yml: -------------------------------------------------------------------------------- 1 | rules: 2 | unpinned-uses: 3 | config: 4 | policies: 5 | # Ensures that we handle overlapping patterns correctly, 6 | # including with subpaths: github/codeql-action/* is shadowed by 7 | # github/codeql-action/init and github/codeql-action/upload-sarif, 8 | # which have stronger policies. 9 | actions/*: ref-pin 10 | pypa/*: ref-pin 11 | github/codeql-action/*: ref-pin 12 | github/codeql-action/init: hash-pin 13 | github/codeql-action/upload-sarif: hash-pin 14 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/unpinned-uses/configs/composite.yml: -------------------------------------------------------------------------------- 1 | rules: 2 | unpinned-uses: 3 | config: 4 | policies: 5 | # Ensures that we handle overlapping patterns correctly, 6 | # favoring more specific ones: `actions/*` is shadowed by 7 | # `actions/setup-python`, which has a stronger policy. 8 | "actions/*": any 9 | "actions/setup-python": hash-pin 10 | "pypa/gh-action-pypi-publish": ref-pin 11 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/unpinned-uses/configs/empty.yml: -------------------------------------------------------------------------------- 1 | rules: 2 | unpinned-uses: 3 | config: 4 | # If the user explicitly configures an empty policy set, 5 | # we apply the default policy, which is to require hash-pinning 6 | # for all actions. 7 | policies: {} 8 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/unpinned-uses/configs/hash-pin-everything.yml: -------------------------------------------------------------------------------- 1 | rules: 2 | unpinned-uses: 3 | config: 4 | policies: 5 | "*": hash-pin 6 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/unpinned-uses/configs/invalid-policy-syntax-1.yml: -------------------------------------------------------------------------------- 1 | rules: 2 | unpinned-uses: 3 | config: 4 | policies: 5 | # Invalid: lol should be one of *, `lol/...` or `lol/*` 6 | "lol": "any" 7 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/unpinned-uses/configs/invalid-policy-syntax-2.yml: -------------------------------------------------------------------------------- 1 | rules: 2 | unpinned-uses: 3 | config: 4 | policies: 5 | # Invalid: foo/ should be foo/* 6 | "foo/": "any" 7 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/unpinned-uses/configs/invalid-policy-syntax-3.yml: -------------------------------------------------------------------------------- 1 | rules: 2 | unpinned-uses: 3 | config: 4 | policies: 5 | # Invalid: * not allowed in owner position 6 | "*/foo": "any" 7 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/unpinned-uses/configs/invalid-policy-syntax-4.yml: -------------------------------------------------------------------------------- 1 | rules: 2 | unpinned-uses: 3 | config: 4 | policies: 5 | # Invalid: * must be alone in repo position 6 | "foo/b*r": "any" 7 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/unpinned-uses/configs/invalid-policy-syntax-5.yml: -------------------------------------------------------------------------------- 1 | rules: 2 | unpinned-uses: 3 | config: 4 | policies: 5 | # Valid use pattern, but invalid policy 6 | "foo/*": "does not exist" 7 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/unpinned-uses/configs/invalid-policy-syntax-6.yml: -------------------------------------------------------------------------------- 1 | rules: 2 | unpinned-uses: 3 | config: 4 | policies: 5 | # valid pattern, but not allowed in this context 6 | # because it makes no sense 7 | "foo/bar@v1": "hash-pin" 8 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/unpinned-uses/configs/invalid-wrong-policy-object.yml: -------------------------------------------------------------------------------- 1 | rules: 2 | unpinned-uses: 3 | config: 4 | # Invalid: policies should be a mapping, not a list. 5 | policies: [] 6 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/unpinned-uses/configs/ref-pin-everything.yml: -------------------------------------------------------------------------------- 1 | rules: 2 | unpinned-uses: 3 | config: 4 | policies: 5 | "*": ref-pin 6 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/unpinned-uses/issue-433-repro.yml: -------------------------------------------------------------------------------- 1 | # repro case for https://github.com/zizmorcore/zizmor/issues/433 2 | 3 | name: issue-433-repro 4 | 5 | on: push 6 | 7 | permissions: {} 8 | 9 | jobs: 10 | issue-433-repro: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: no-finding-1 14 | # workflow is local, so tagging is superfluous 15 | uses: ./.github/workflows/reusable.yml 16 | 17 | - name: no-finding-2 18 | # no pedantic finding for tag-pinned local workflows 19 | uses: ./.github/workflows/reusable.yml@tag 20 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/unpinned-uses/issue-659-repro.yml: -------------------------------------------------------------------------------- 1 | # minimized from https://raw.githubusercontent.com/docker/actions-toolkit/59501e62b/.github/workflows/test.yml 2 | name: issue-659-repro 3 | 4 | on: 5 | workflow_dispatch: 6 | 7 | jobs: 8 | test-itg: 9 | runs-on: ${{ matrix.os }} 10 | strategy: 11 | fail-fast: false 12 | matrix: 13 | include: ${{ fromJson(needs.prepare-itg.outputs.includes) }} 14 | steps: 15 | - # FIXME: Needs to setup node twice on Windows due to a bug with runner 16 | name: Setup Node 17 | uses: actions/setup-node@v4 18 | with: 19 | node-version: ${{ env.NODE_VERSION }} 20 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/unpinned-uses/menagerie-of-uses.yml: -------------------------------------------------------------------------------- 1 | name: menagerie-of-uses 2 | on: [push] 3 | 4 | permissions: {} 5 | 6 | jobs: 7 | menagerie: 8 | runs-on: ubuntu-latest 9 | 10 | steps: 11 | - uses: actions/setup-python@v4 12 | 13 | - uses: actions/checkout 14 | with: 15 | persist-credentials: false 16 | 17 | - uses: actions/checkout@v3 18 | with: 19 | persist-credentials: false 20 | 21 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 22 | with: 23 | persist-credentials: false 24 | 25 | - uses: pypa/gh-action-pypi-publish@release/v1 26 | 27 | - uses: github/codeql-action/init@v3 28 | 29 | - uses: github/codeql-action/upload-sarif@v3 30 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/unredacted-secrets.yml: -------------------------------------------------------------------------------- 1 | # unredacted-secrets.yml 2 | 3 | on: push 4 | 5 | permissions: {} 6 | 7 | jobs: 8 | test: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - run: echo "${stuff} ${otherstuff}" 12 | env: 13 | # NOT OK: potentially leaves 'password' unredacted in the runner's logs 14 | stuff: ${{ fromJSON(secrets.password) }} 15 | 16 | # NOT OK: potentially leaves 'field' within 'otherstuff' unredacted in the runner's logs 17 | otherstuff: ${{ fromJson(secrets.otherstuff).field }} 18 | 19 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/unsound-contains.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | pull_request: 4 | workflow_dispatch: 5 | inputs: 6 | some_value: 7 | required: true 8 | 9 | permissions: {} 10 | 11 | jobs: 12 | hackme: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - name: vulnerable-1 16 | run: echo hello 17 | if: ${{ contains('refs/heads/main refs/heads/develop', github.ref) }} 18 | 19 | - name: vulnerable-2 20 | run: echo hello 21 | if: ${{ contains('main,develop', env.GITHUB_REF_NAME) }} 22 | 23 | - name: vulnerable-3 24 | run: echo hello 25 | if: contains('main,prod', github.ref_name) || contains('longusername anotherlongusername', github.actor) == true 26 | 27 | - name: probably-not-vulnerable-but-still-bad 28 | run: echo hello 29 | if: contains('runner1,runner2', runner.name) 30 | 31 | - name: not-vulnerable 32 | run: echo hello 33 | if: contains(some.context.*.foo, github.ref_name) 34 | -------------------------------------------------------------------------------- /crates/zizmor/tests/integration/test-data/use-trusted-publishing.yml: -------------------------------------------------------------------------------- 1 | # Adapted from 2 | # https://github.com/woodruffw/gha-hazmat/blob/main/.github/workflows/pypi-manual-credential.yml 3 | 4 | on: [push] 5 | 6 | jobs: 7 | publish: 8 | runs-on: ubuntu-latest 9 | permissions: 10 | id-token: write 11 | steps: 12 | - name: vulnerable-2 13 | uses: pypa/gh-action-pypi-publish@release/v1 # zizmor: ignore[unpinned-uses] 14 | with: 15 | password: ${{ secrets.PYPI_TOKEN }} 16 | -------------------------------------------------------------------------------- /docs/assets/favicon48x48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zizmorcore/zizmor/a4a657f9bec0aced315811dc9983f703ee0d4e1b/docs/assets/favicon48x48.png -------------------------------------------------------------------------------- /docs/assets/rainbow.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/assets/zizmor-demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zizmorcore/zizmor/a4a657f9bec0aced315811dc9983f703ee0d4e1b/docs/assets/zizmor-demo.gif -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | # Welcome to `zizmor`'s documentation! 2 | 3 | [![CI](https://github.com/zizmorcore/zizmor/actions/workflows/ci.yml/badge.svg)](https://github.com/zizmorcore/zizmor/actions/workflows/ci.yml) 4 | [![Crates.io](https://img.shields.io/crates/v/zizmor)](https://crates.io/crates/zizmor) 5 | [![Packaging status](https://repology.org/badge/tiny-repos/zizmor.svg)](https://repology.org/project/zizmor/versions) 6 | [![GitHub Sponsors](https://img.shields.io/github/sponsors/woodruffw?style=flat&logo=githubsponsors&labelColor=white&color=white)](https://github.com/sponsors/woodruffw) 7 | [![Discord](https://img.shields.io/badge/Discord-%235865F2.svg?logo=discord&logoColor=white)](https://discord.com/invite/PGU3zGZuGG) 8 | 9 | :rainbow: Hello, and welcome to `zizmor`'s documentation! :rainbow: 10 | 11 | `zizmor` is a static analysis tool for GitHub Actions. It can find 12 | many common security issues in typical GitHub Actions CI/CD setups. 13 | 14 | Go right to our [Installation Steps](./installation.md), and then to 15 | [Quickstart](./quickstart.md) or [Usage Recipes](./usage.md) to 16 | learn more about how to use `zizmor` locally or in your CI/CD. 17 | 18 |
19 | ![](./assets/zizmor-demo.gif) 20 |
21 | 22 | ## Sponsors 💖 23 | 24 | `zizmor`'s development is supported by these amazing sponsors! 25 | 26 |
27 | --8<-- "sponsors.html" 28 |
29 | -------------------------------------------------------------------------------- /docs/snippets/render-trophies.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # render-trophies: take trophies.txt and produce a pretty 4 | # mkdocs-material card grid list from it 5 | 6 | from collections import defaultdict 7 | from pathlib import Path 8 | 9 | _TROPHIES = Path(__file__).parent / "trophies.txt" 10 | 11 | _TEMPLATE = """ 12 | - ![](https://github.com/{org}.png?size=40){{ width=\"40\" loading=lazy align=left }} {org} 13 | 14 | --- 15 | 16 | ??? example "Examples" 17 | {trophies} 18 | """ 19 | 20 | by_org = defaultdict(list) 21 | 22 | for trophy in _TROPHIES.open().readlines(): 23 | trophy = trophy.strip() 24 | if not trophy or trophy.startswith("#"): 25 | continue 26 | 27 | org, rest = trophy.split("/") 28 | if "#" in rest: 29 | repo, _ = rest.split("#") 30 | else: 31 | repo, _ = rest.split("@") 32 | 33 | by_org[org].append(trophy) 34 | 35 | 36 | for org, trophies in sorted(by_org.items(), key=lambda t: t[0].lower()): 37 | # NOTE: We request 40x40 from GitHub, but sometimes it gives us a bigger one. 38 | # Consequently, we also style with `width` to keep things consistent. 39 | trophies = [f" - {trophy}" for trophy in trophies] 40 | print(_TEMPLATE.format(org=org, trophies="\n".join(trophies))) 41 | -------------------------------------------------------------------------------- /docs/snippets/sponsors.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 13 | 14 | 15 |
Logo-level sponsors
7 | 8 | 9 |
10 | Astral 11 |
12 |
16 |
17 | 18 | 19 | 20 | 21 | 26 | 27 | 28 |
Name-level sponsors
22 | 23 | Tenki Cloud 24 | 25 |
29 | 30 | -------------------------------------------------------------------------------- /docs/snippets/sponsors.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "Astral", 4 | "url": "https://astral.sh/", 5 | "img": "https://avatars.githubusercontent.com/u/115962839?s=100&v=4" 6 | }, 7 | { 8 | "name": "Tenki Cloud", 9 | "url": "http://tenki.cloud/" 10 | } 11 | ] 12 | -------------------------------------------------------------------------------- /docs/trophy-case.md: -------------------------------------------------------------------------------- 1 | # Trophy case 🏆 2 | 3 | `zizmor`'s objective is to detect CI/CD security issues that could compromise 4 | the software we all rely on. 5 | 6 | This page documents key examples where `zizmor` helped make big projects more 7 | secure! 8 | 9 | !!! tip "Give yourself a trophy!" 10 | 11 | Do you contribute to or maintain a big (>100 star) project that had its GitHub 12 | Actions security improved by `zizmor`? 13 | [Add it to our list](./development.md#updating-the-trophy-case)! 14 | 15 |
16 | --8<-- "trophies.md" 17 |
18 | 19 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["maturin>=1.0,<2.0"] 3 | build-backend = "maturin" 4 | 5 | # NOTE: This section is a stub; needed to prevent 6 | # `uv run --only-group docs` from failing. 7 | [project] 8 | name = "zizmor" 9 | dynamic = ["version"] 10 | # Arbitrarily set to the oldest non-EOL Python. 11 | requires-python = ">=3.9" 12 | 13 | [tool.maturin] 14 | bindings = "bin" 15 | manifest-path = "crates/zizmor/Cargo.toml" 16 | 17 | [dependency-groups] 18 | docs = ["mkdocs ~= 1.6", "mkdocs-material[imaging] ~= 9.5"] 19 | codegen = ["prance[osv]", "requests", "pyyaml"] 20 | -------------------------------------------------------------------------------- /support/archive-release.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Turns a target-specific release build into an appropriately 4 | # named archive for distribution via a GitHub release. 5 | # 6 | # Expects to be run from the root of the repository. 7 | 8 | set -eo pipefail 9 | 10 | if [[ -z "${TARGET}" ]]; then 11 | >&2 echo "Error: TARGET environment variable not set" 12 | exit 1 13 | fi 14 | 15 | TARGET_DIR="./target" 16 | RELEASE_DIR="${TARGET_DIR}/${TARGET}/release" 17 | 18 | if [[ ! -d "${RELEASE_DIR}" ]]; then 19 | >&2 echo "Error: missing target release directory?" 20 | exit 1 21 | fi 22 | 23 | ARCHIVE_DIR="${TARGET_DIR}/archive/zizmor-${TARGET}" 24 | mkdir -p "${ARCHIVE_DIR}" 25 | cp "${RELEASE_DIR}/zizmor" "${ARCHIVE_DIR}/zizmor" 26 | 27 | if [[ "${TARGET}" == *"windows"* ]]; then 28 | ARCHIVE_FILE="${TARGET_DIR}/archive/zizmor-${TARGET}.zip" 29 | 7z a "${ARCHIVE_FILE}" "${ARCHIVE_DIR}"/* 30 | else 31 | ARCHIVE_FILE="${TARGET_DIR}/archive/zizmor-${TARGET}.tar.gz" 32 | tar -C "${ARCHIVE_DIR}" -czf "${ARCHIVE_FILE}" . 33 | fi 34 | 35 | if [[ -z "${GITHUB_OUTPUT}" ]]; then 36 | echo "${ARCHIVE_FILE}" 37 | else 38 | echo "filename=${ARCHIVE_FILE}" >> "${GITHUB_OUTPUT}" 39 | fi 40 | -------------------------------------------------------------------------------- /support/known-safe-contexts.txt: -------------------------------------------------------------------------------- 1 | # known-safe-contexts.txt 2 | # one per line, comment lines begin with # 3 | 4 | # The action path is always safe. 5 | github.action_path 6 | 7 | # The GitHub event name (i.e. trigger) is itself safe. 8 | github.event_name 9 | 10 | # hexadecimal SHA refs 11 | github.event.after 12 | github.event.before 13 | github.event.merge_group.base_sha 14 | github.event.pull_request.base.sha 15 | github.event.pull_request.head.sha 16 | 17 | # Corresponds to the job ID which is workflow-controlled 18 | # but can only be [A-Za-z0-9-_]. 19 | # See: https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions#jobsjob_id 20 | github.job 21 | 22 | # Information about the GitHub repository 23 | github.repository 24 | github.repository_id 25 | github.repositoryurl 26 | 27 | # Information about the GitHub repository owner (account/org or ID) 28 | github.repository_owner 29 | github.repository_owner_id 30 | 31 | # Unique numbers assigned by GitHub for workflow runs 32 | github.run_attempt 33 | github.run_id 34 | github.run_number 35 | 36 | # Typically something like `https://github.com`; you have bigger problems if 37 | # this is attacker-controlled. 38 | github.server_url 39 | 40 | # Always a 40-char SHA-1 reference. 41 | github.sha 42 | 43 | # Like `secrets.*`: not safe to expose but safe to interpolate. 44 | github.token 45 | 46 | # GitHub Actions-controlled local directory. 47 | github.workspace 48 | 49 | # runner contexts 50 | # GitHub Actions-controller runner architecture. 51 | runner.arch 52 | # Debug logging is (1) or is not (0) enabled on GitHub Actions runner. 53 | runner.debug 54 | # GitHub Actions runner operating system. 55 | runner.os 56 | # GitHub Actions temporary directory value controlled by the runner itself. 57 | runner.temp 58 | # GitHub Actions cached tool directory value controlled by the runner itself. 59 | runner.tool_cache 60 | --------------------------------------------------------------------------------