zizmor 1.2.0__tar.gz → 1.2.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of zizmor might be problematic. Click here for more details.
- {zizmor-1.2.0 → zizmor-1.2.2}/.github/workflows/ci.yml +14 -2
- {zizmor-1.2.0 → zizmor-1.2.2}/.github/workflows/site.yml +1 -1
- {zizmor-1.2.0 → zizmor-1.2.2}/.github/workflows/zizmor.yml +3 -1
- {zizmor-1.2.0 → zizmor-1.2.2}/Cargo.lock +3 -3
- {zizmor-1.2.0 → zizmor-1.2.2}/Cargo.toml +2 -2
- {zizmor-1.2.0 → zizmor-1.2.2}/Makefile +4 -4
- {zizmor-1.2.0 → zizmor-1.2.2}/PKG-INFO +3 -1
- {zizmor-1.2.0 → zizmor-1.2.2}/docs/release-notes.md +21 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/docs/usage.md +1 -1
- zizmor-1.2.2/pyproject.toml +17 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/src/audit/bot_conditions.rs +2 -3
- {zizmor-1.2.0 → zizmor-1.2.2}/src/audit/excessive_permissions.rs +39 -22
- {zizmor-1.2.0 → zizmor-1.2.2}/src/github_api.rs +11 -1
- {zizmor-1.2.0 → zizmor-1.2.2}/src/main.rs +28 -15
- {zizmor-1.2.0 → zizmor-1.2.2}/src/models.rs +28 -15
- {zizmor-1.2.0 → zizmor-1.2.2}/src/registry.rs +53 -18
- {zizmor-1.2.0 → zizmor-1.2.2}/src/render.rs +5 -1
- {zizmor-1.2.0 → zizmor-1.2.2}/src/sarif.rs +2 -1
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/snapshot.rs +19 -0
- zizmor-1.2.2/tests/snapshots/snapshot__excessive_permissions-10.snap +21 -0
- zizmor-1.2.2/tests/snapshots/snapshot__excessive_permissions-11.snap +19 -0
- zizmor-1.2.2/tests/snapshots/snapshot__excessive_permissions-12.snap +47 -0
- zizmor-1.2.2/tests/test-data/excessive-permissions/issue-472-repro.yml +23 -0
- zizmor-1.2.2/tests/test-data/excessive-permissions/reusable-workflow-call.yml +9 -0
- zizmor-1.2.2/tests/test-data/excessive-permissions/reusable-workflow-other-triggers.yml +21 -0
- zizmor-1.2.2/uv.lock +869 -0
- zizmor-1.2.0/pyproject.toml +0 -6
- zizmor-1.2.0/site-requirements.txt +0 -2
- {zizmor-1.2.0 → zizmor-1.2.2}/.github/ISSUE_TEMPLATE/bug-report.yml +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/.github/ISSUE_TEMPLATE/feature-request.yml +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/.github/dependabot.yml +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/.github/workflows/pypi.yml +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/.github/workflows/release.yml +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/.gitignore +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/CONTRIBUTING.md +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/LICENSE +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/README.md +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/docs/assets/favicon48x48.png +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/docs/assets/rainbow.svg +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/docs/assets/zizmor-demo.gif +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/docs/audits.md +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/docs/configuration.md +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/docs/development.md +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/docs/index.md +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/docs/installation.md +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/docs/magiclink.css +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/docs/quickstart.md +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/docs/snippets/help.txt +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/docs/snippets/render-sponsors.py +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/docs/snippets/render-trophies.py +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/docs/snippets/sponsors.html +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/docs/snippets/sponsors.json +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/docs/snippets/trophies.md +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/docs/snippets/trophies.txt +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/docs/trophy-case.md +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/mkdocs.yml +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/src/audit/artipacked.rs +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/src/audit/cache_poisoning.rs +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/src/audit/dangerous_triggers.rs +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/src/audit/github_env.rs +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/src/audit/hardcoded_container_credentials.rs +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/src/audit/impostor_commit.rs +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/src/audit/insecure_commands.rs +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/src/audit/known_vulnerable_actions.rs +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/src/audit/mod.rs +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/src/audit/ref_confusion.rs +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/src/audit/secrets_inherit.rs +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/src/audit/self_hosted_runner.rs +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/src/audit/template_injection.rs +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/src/audit/unpinned_uses.rs +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/src/audit/use_trusted_publishing.rs +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/src/config.rs +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/src/expr/expr.pest +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/src/expr/mod.rs +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/src/finding/locate.rs +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/src/finding/mod.rs +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/src/models/coordinate.rs +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/src/models/uses.rs +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/src/state.rs +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/src/utils.rs +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/acceptance.rs +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/common.rs +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/snapshots/snapshot__artipacked-2.snap +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/snapshots/snapshot__artipacked-3.snap +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/snapshots/snapshot__artipacked-4.snap +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/snapshots/snapshot__artipacked.snap +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/snapshots/snapshot__bot_conditions.snap +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/snapshots/snapshot__cache_poisoning-10.snap +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/snapshots/snapshot__cache_poisoning-11.snap +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/snapshots/snapshot__cache_poisoning-12.snap +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/snapshots/snapshot__cache_poisoning-13.snap +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/snapshots/snapshot__cache_poisoning-14.snap +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/snapshots/snapshot__cache_poisoning-2.snap +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/snapshots/snapshot__cache_poisoning-3.snap +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/snapshots/snapshot__cache_poisoning-4.snap +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/snapshots/snapshot__cache_poisoning-5.snap +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/snapshots/snapshot__cache_poisoning-6.snap +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/snapshots/snapshot__cache_poisoning-7.snap +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/snapshots/snapshot__cache_poisoning-8.snap +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/snapshots/snapshot__cache_poisoning-9.snap +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/snapshots/snapshot__cache_poisoning.snap +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/snapshots/snapshot__cant_retrieve.snap +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/snapshots/snapshot__conflicting_online_options-2.snap +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/snapshots/snapshot__conflicting_online_options-3.snap +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/snapshots/snapshot__conflicting_online_options.snap +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/snapshots/snapshot__excessive_permissions-2.snap +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/snapshots/snapshot__excessive_permissions-3.snap +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/snapshots/snapshot__excessive_permissions-4.snap +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/snapshots/snapshot__excessive_permissions-5.snap +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/snapshots/snapshot__excessive_permissions-6.snap +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/snapshots/snapshot__excessive_permissions-7.snap +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/snapshots/snapshot__excessive_permissions-8.snap +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/snapshots/snapshot__excessive_permissions-9.snap +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/snapshots/snapshot__excessive_permissions.snap +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/snapshots/snapshot__github_env-2.snap +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/snapshots/snapshot__github_env-3.snap +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/snapshots/snapshot__github_env.snap +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/snapshots/snapshot__insecure_commands-2.snap +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/snapshots/snapshot__insecure_commands-3.snap +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/snapshots/snapshot__insecure_commands.snap +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/snapshots/snapshot__secrets_inherit.snap +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/snapshots/snapshot__self_hosted-2.snap +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/snapshots/snapshot__self_hosted-3.snap +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/snapshots/snapshot__self_hosted-4.snap +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/snapshots/snapshot__self_hosted-5.snap +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/snapshots/snapshot__self_hosted-6.snap +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/snapshots/snapshot__self_hosted-7.snap +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/snapshots/snapshot__self_hosted-8.snap +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/snapshots/snapshot__self_hosted.snap +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/snapshots/snapshot__template_injection-2.snap +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/snapshots/snapshot__template_injection-3.snap +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/snapshots/snapshot__template_injection-4.snap +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/snapshots/snapshot__template_injection-5.snap +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/snapshots/snapshot__template_injection-6.snap +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/snapshots/snapshot__template_injection-7.snap +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/snapshots/snapshot__template_injection-8.snap +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/snapshots/snapshot__template_injection.snap +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/snapshots/snapshot__unpinned_uses-2.snap +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/snapshots/snapshot__unpinned_uses-3.snap +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/snapshots/snapshot__unpinned_uses-4.snap +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/snapshots/snapshot__unpinned_uses.snap +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/test-data/artipacked/issue-447-repro.yml +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/test-data/artipacked.yml +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/test-data/bot-conditions.yml +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/test-data/cache-poisoning/caching-disabled-by-default.yml +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/test-data/cache-poisoning/caching-enabled-by-default.yml +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/test-data/cache-poisoning/caching-not-configurable.yml +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/test-data/cache-poisoning/caching-opt-in-boolean-toggle.yml +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/test-data/cache-poisoning/caching-opt-in-boolish-toggle.yml +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/test-data/cache-poisoning/caching-opt-in-expression.yml +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/test-data/cache-poisoning/caching-opt-in-multi-value-toggle.yml +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/test-data/cache-poisoning/caching-opt-out.yml +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/test-data/cache-poisoning/issue-343-repro.yml +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/test-data/cache-poisoning/issue-378-repro.yml +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/test-data/cache-poisoning/no-cache-aware-steps.yml +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/test-data/cache-poisoning/publisher-step.yml +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/test-data/cache-poisoning/workflow-release-branch-trigger.yml +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/test-data/cache-poisoning/workflow-tag-trigger.yml +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/test-data/cache-poisoning.yml +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/test-data/excessive-permissions/issue-336-repro.yml +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/test-data/excessive-permissions/jobs-broaden-permissions.yml +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/test-data/excessive-permissions/workflow-default-perms-all-jobs-explicit.yml +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/test-data/excessive-permissions/workflow-default-perms.yml +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/test-data/excessive-permissions/workflow-empty-perms.yml +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/test-data/excessive-permissions/workflow-read-all.yml +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/test-data/excessive-permissions/workflow-write-all.yml +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/test-data/excessive-permissions/workflow-write-explicit.yml +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/test-data/excessive-permissions.yml +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/test-data/github-env/action.yml +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/test-data/github-env/github-path.yml +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/test-data/github-env/issue-397-repro.yml +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/test-data/github_env.yml +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/test-data/hardcoded-credentials.yml +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/test-data/inlined-ignores.yml +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/test-data/insecure-commands/action.yml +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/test-data/insecure-commands.yml +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/test-data/secrets-inherit.yml +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/test-data/self-hosted/issue-283-repro.yml +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/test-data/self-hosted/self-hosted-matrix-dimension.yml +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/test-data/self-hosted/self-hosted-matrix-exclusion.yml +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/test-data/self-hosted/self-hosted-matrix-inclusion.yml +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/test-data/self-hosted/self-hosted-runner-group.yml +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/test-data/self-hosted/self-hosted-runner-label.yml +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/test-data/self-hosted.yml +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/test-data/template-injection/issue-22-repro.yml +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/test-data/template-injection/issue-339-repro.yml +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/test-data/template-injection/issue-418-repro.yml +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/test-data/template-injection/pr-317-repro.yml +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/test-data/template-injection/pr-425-backstop/action.yml +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/test-data/template-injection/static-env.yml +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/test-data/template-injection/template-injection-dynamic-matrix.yml +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/test-data/template-injection/template-injection-static-matrix.yml +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/test-data/template-injection.yml +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/test-data/unpinned-uses/action.yml +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/test-data/unpinned-uses/issue-433-repro.yml +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/test-data/unpinned-uses.yml +0 -0
- {zizmor-1.2.0 → zizmor-1.2.2}/tests/test-data/use-trusted-publishing.yml +0 -0
|
@@ -33,7 +33,7 @@ jobs:
|
|
|
33
33
|
|
|
34
34
|
- uses: Swatinem/rust-cache@f0deed1e0edfc6a9be95417288c0e1099b1eeec3 # v2
|
|
35
35
|
|
|
36
|
-
- uses: astral-sh/setup-uv@
|
|
36
|
+
- uses: astral-sh/setup-uv@b5f58b2abc5763ade55e4e9d0fe52cd1ff7979ca # v5.2.1
|
|
37
37
|
|
|
38
38
|
- name: Test
|
|
39
39
|
run: cargo test
|
|
@@ -43,9 +43,21 @@ jobs:
|
|
|
43
43
|
make snippets
|
|
44
44
|
git diff --exit-code
|
|
45
45
|
|
|
46
|
+
test-site:
|
|
47
|
+
runs-on: ubuntu-latest
|
|
48
|
+
steps:
|
|
49
|
+
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
|
50
|
+
with:
|
|
51
|
+
persist-credentials: false
|
|
52
|
+
|
|
53
|
+
- uses: astral-sh/setup-uv@b5f58b2abc5763ade55e4e9d0fe52cd1ff7979ca # v5.2.1
|
|
54
|
+
|
|
55
|
+
- name: Test site
|
|
56
|
+
run: make site
|
|
57
|
+
|
|
46
58
|
all-tests-pass:
|
|
47
59
|
if: always()
|
|
48
|
-
needs: [lint, test]
|
|
60
|
+
needs: [lint, test, test-site]
|
|
49
61
|
runs-on: ubuntu-latest
|
|
50
62
|
|
|
51
63
|
steps:
|
|
@@ -30,7 +30,7 @@ jobs:
|
|
|
30
30
|
persist-credentials: false
|
|
31
31
|
|
|
32
32
|
- name: Install the latest version of uv
|
|
33
|
-
uses: astral-sh/setup-uv@
|
|
33
|
+
uses: astral-sh/setup-uv@b5f58b2abc5763ade55e4e9d0fe52cd1ff7979ca # v5.2.1
|
|
34
34
|
|
|
35
35
|
- name: build site
|
|
36
36
|
run: make site
|
|
@@ -6,6 +6,8 @@ on:
|
|
|
6
6
|
pull_request:
|
|
7
7
|
branches: ["*"]
|
|
8
8
|
|
|
9
|
+
permissions: {}
|
|
10
|
+
|
|
9
11
|
jobs:
|
|
10
12
|
zizmor:
|
|
11
13
|
name: zizmor latest via Cargo
|
|
@@ -19,7 +21,7 @@ jobs:
|
|
|
19
21
|
with:
|
|
20
22
|
persist-credentials: false
|
|
21
23
|
- name: Install the latest version of uv
|
|
22
|
-
uses: astral-sh/setup-uv@
|
|
24
|
+
uses: astral-sh/setup-uv@b5f58b2abc5763ade55e4e9d0fe52cd1ff7979ca # v5.2.1
|
|
23
25
|
- name: Run zizmor 🌈
|
|
24
26
|
run: uvx zizmor --format sarif . > results.sarif
|
|
25
27
|
env:
|
|
@@ -616,9 +616,9 @@ checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
|
|
|
616
616
|
|
|
617
617
|
[[package]]
|
|
618
618
|
name = "github-actions-models"
|
|
619
|
-
version = "0.
|
|
619
|
+
version = "0.22.0"
|
|
620
620
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
621
|
-
checksum = "
|
|
621
|
+
checksum = "ea4c30fa8bf11e002d3ca72233e7a7bac33ffce4dc50877d63a8f5a161e0cd84"
|
|
622
622
|
dependencies = [
|
|
623
623
|
"indexmap",
|
|
624
624
|
"serde",
|
|
@@ -3108,7 +3108,7 @@ dependencies = [
|
|
|
3108
3108
|
|
|
3109
3109
|
[[package]]
|
|
3110
3110
|
name = "zizmor"
|
|
3111
|
-
version = "1.2.
|
|
3111
|
+
version = "1.2.2"
|
|
3112
3112
|
dependencies = [
|
|
3113
3113
|
"annotate-snippets",
|
|
3114
3114
|
"anstream",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
name = "zizmor"
|
|
3
3
|
description = "Static analysis for GitHub Actions"
|
|
4
|
-
version = "1.2.
|
|
4
|
+
version = "1.2.2"
|
|
5
5
|
edition = "2021"
|
|
6
6
|
repository = "https://github.com/woodruffw/zizmor"
|
|
7
7
|
homepage = "https://github.com/woodruffw/zizmor"
|
|
@@ -23,7 +23,7 @@ clap-verbosity-flag = { version = "3.0.2", features = [
|
|
|
23
23
|
], default-features = false }
|
|
24
24
|
etcetera = "0.8.0"
|
|
25
25
|
flate2 = "1.0.35"
|
|
26
|
-
github-actions-models = "0.
|
|
26
|
+
github-actions-models = "0.22.0"
|
|
27
27
|
http-cache-reqwest = "0.15.0"
|
|
28
28
|
human-panic = "2.0.1"
|
|
29
29
|
indexmap = "2.7.0"
|
|
@@ -3,12 +3,12 @@ all:
|
|
|
3
3
|
@echo "Run my targets individually!"
|
|
4
4
|
|
|
5
5
|
.PHONY: site
|
|
6
|
-
site:
|
|
7
|
-
|
|
6
|
+
site:
|
|
7
|
+
uv run --only-group docs mkdocs build
|
|
8
8
|
|
|
9
9
|
.PHONY: site-live
|
|
10
|
-
site-live:
|
|
11
|
-
|
|
10
|
+
site-live:
|
|
11
|
+
uv run --only-group docs mkdocs serve
|
|
12
12
|
|
|
13
13
|
.PHONY: snippets
|
|
14
14
|
snippets: trophies sponsors
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: zizmor
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.2
|
|
4
|
+
License-File: LICENSE
|
|
4
5
|
Summary: Static analysis for GitHub Actions
|
|
5
6
|
Keywords: cli,github-actions,static-analysis,security
|
|
6
7
|
Home-Page: https://github.com/woodruffw/zizmor
|
|
7
8
|
Author: William Woodruff <william@yossarian.net>
|
|
8
9
|
Author-email: William Woodruff <william@yossarian.net>
|
|
9
10
|
License: MIT
|
|
11
|
+
Requires-Python: >=3.9
|
|
10
12
|
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
|
|
11
13
|
Project-URL: Source Code, https://github.com/woodruffw/zizmor
|
|
12
14
|
|
|
@@ -11,6 +11,27 @@ of `zizmor`.
|
|
|
11
11
|
|
|
12
12
|
Nothing to see here (yet!)
|
|
13
13
|
|
|
14
|
+
## v1.2.2
|
|
15
|
+
|
|
16
|
+
### Bug Fixes 🐛
|
|
17
|
+
|
|
18
|
+
* The [excessive-permissions] audit is now more precise about both
|
|
19
|
+
reusable workflows and reusable workflow calls (#473)
|
|
20
|
+
|
|
21
|
+
### Improvements 🌱
|
|
22
|
+
|
|
23
|
+
* Fetch failures when running `zizmor org/repo` are now more informative (#475)
|
|
24
|
+
|
|
25
|
+
## v1.2.1
|
|
26
|
+
|
|
27
|
+
This is a small corrective release for some SARIF behavior that
|
|
28
|
+
changed with v1.2.0.
|
|
29
|
+
|
|
30
|
+
### Bug Fixes 🐛
|
|
31
|
+
|
|
32
|
+
* SARIF outputs now use relative paths again, but more correctly
|
|
33
|
+
than before [v1.2.0](#v120) (#469)
|
|
34
|
+
|
|
14
35
|
## v1.2.0
|
|
15
36
|
|
|
16
37
|
This release comes with one new audit ([bot-conditions]), plus a handful
|
|
@@ -0,0 +1,17 @@
|
|
|
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
|
+
|
|
16
|
+
[dependency-groups]
|
|
17
|
+
docs = ["mkdocs ~= 1.6", "mkdocs-material[imaging] ~= 9.5"]
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
use github_actions_models::common::{expr::ExplicitExpr, If};
|
|
2
2
|
|
|
3
|
+
use super::{audit_meta, Audit};
|
|
3
4
|
use crate::{
|
|
4
5
|
expr::{self, Expr},
|
|
5
6
|
finding::{Confidence, Severity},
|
|
6
7
|
models::JobExt,
|
|
7
8
|
};
|
|
8
9
|
|
|
9
|
-
use super::{audit_meta, Audit};
|
|
10
|
-
|
|
11
10
|
pub(crate) struct BotConditions;
|
|
12
11
|
|
|
13
12
|
audit_meta!(BotConditions, "bot-conditions", "spoofable bot actor check");
|
|
@@ -152,7 +151,7 @@ impl BotConditions {
|
|
|
152
151
|
// We have a bot condition but it doesn't dominate the expression.
|
|
153
152
|
(true, false) => Some(Confidence::Medium),
|
|
154
153
|
// No bot condition.
|
|
155
|
-
(
|
|
154
|
+
(..) => None,
|
|
156
155
|
}
|
|
157
156
|
}
|
|
158
157
|
}
|
|
@@ -57,12 +57,9 @@ impl Audit for ExcessivePermissions {
|
|
|
57
57
|
|
|
58
58
|
let all_jobs_have_permissions = workflow
|
|
59
59
|
.jobs()
|
|
60
|
-
.
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
Some(&job.permissions)
|
|
60
|
+
.map(|job| match job {
|
|
61
|
+
Job::NormalJob(job) => &job.permissions,
|
|
62
|
+
Job::ReusableWorkflowCallJob(job) => &job.permissions,
|
|
66
63
|
})
|
|
67
64
|
.all(|perm| !matches!(perm, Permissions::Base(BasePermission::Default)));
|
|
68
65
|
|
|
@@ -71,17 +68,21 @@ impl Audit for ExcessivePermissions {
|
|
|
71
68
|
Permissions::Base(BasePermission::Default)
|
|
72
69
|
);
|
|
73
70
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
//
|
|
78
|
-
//
|
|
79
|
-
//
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
71
|
+
let workflow_is_reusable_only =
|
|
72
|
+
workflow.has_workflow_call() && workflow.has_single_trigger();
|
|
73
|
+
|
|
74
|
+
// Top-level permissions are a pedantic finding under the following
|
|
75
|
+
// conditions:
|
|
76
|
+
//
|
|
77
|
+
// 1. The workflow has only one job.
|
|
78
|
+
// 2. All jobs in the workflow have their own explicit permissions.
|
|
79
|
+
// 3. The workflow is reusable and has only one trigger.
|
|
80
|
+
let workflow_finding_persona =
|
|
81
|
+
if workflow.jobs.len() == 1 || all_jobs_have_permissions || workflow_is_reusable_only {
|
|
82
|
+
Persona::Pedantic
|
|
83
|
+
} else {
|
|
84
|
+
Persona::Regular
|
|
85
|
+
};
|
|
85
86
|
|
|
86
87
|
// Handle top-level permissions.
|
|
87
88
|
let location = workflow.location().primary();
|
|
@@ -93,20 +94,35 @@ impl Audit for ExcessivePermissions {
|
|
|
93
94
|
Self::finding()
|
|
94
95
|
.severity(severity)
|
|
95
96
|
.confidence(confidence)
|
|
96
|
-
.persona(
|
|
97
|
+
.persona(workflow_finding_persona)
|
|
97
98
|
.add_location(perm_location)
|
|
98
99
|
.build(workflow)?,
|
|
99
100
|
);
|
|
100
101
|
}
|
|
101
102
|
|
|
102
103
|
for job in workflow.jobs() {
|
|
103
|
-
let
|
|
104
|
-
|
|
104
|
+
let (permissions, job_location, job_finding_persona) = match job {
|
|
105
|
+
Job::NormalJob(job) => {
|
|
106
|
+
// For normal jobs: if the workflow is reusable-only, we
|
|
107
|
+
// emit pedantic findings.
|
|
108
|
+
let persona = if workflow_is_reusable_only {
|
|
109
|
+
Persona::Pedantic
|
|
110
|
+
} else {
|
|
111
|
+
Persona::Regular
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
(&job.permissions, job.location(), persona)
|
|
115
|
+
}
|
|
116
|
+
Job::ReusableWorkflowCallJob(job) => {
|
|
117
|
+
// For reusable jobs: the caller is always responsible for
|
|
118
|
+
// permissions, so we emit regular findings even if
|
|
119
|
+
// the workflow is reusable-only.
|
|
120
|
+
(&job.permissions, job.location(), Persona::Regular)
|
|
121
|
+
}
|
|
105
122
|
};
|
|
106
123
|
|
|
107
|
-
let job_location = job.location();
|
|
108
124
|
if let Some((severity, confidence, perm_location)) = self.check_job_permissions(
|
|
109
|
-
|
|
125
|
+
permissions,
|
|
110
126
|
explicit_parent_permissions,
|
|
111
127
|
job_location.clone(),
|
|
112
128
|
) {
|
|
@@ -114,6 +130,7 @@ impl Audit for ExcessivePermissions {
|
|
|
114
130
|
Self::finding()
|
|
115
131
|
.severity(severity)
|
|
116
132
|
.confidence(confidence)
|
|
133
|
+
.persona(job_finding_persona)
|
|
117
134
|
.add_location(job_location)
|
|
118
135
|
.add_location(perm_location.primary())
|
|
119
136
|
.build(workflow)?,
|
|
@@ -12,6 +12,7 @@ use github_actions_models::common::RepositoryUses;
|
|
|
12
12
|
use http_cache_reqwest::{
|
|
13
13
|
CACacheManager, Cache, CacheMode, CacheOptions, HttpCache, HttpCacheOptions,
|
|
14
14
|
};
|
|
15
|
+
use owo_colors::OwoColorize;
|
|
15
16
|
use reqwest::{
|
|
16
17
|
header::{HeaderMap, ACCEPT, AUTHORIZATION, USER_AGENT},
|
|
17
18
|
StatusCode,
|
|
@@ -399,7 +400,16 @@ impl Client {
|
|
|
399
400
|
// TODO: Could probably make this slightly faster by
|
|
400
401
|
// streaming asynchronously into the decompression,
|
|
401
402
|
// probably with the async-compression crate.
|
|
402
|
-
let
|
|
403
|
+
let resp = self.http.get(&url).send().await?;
|
|
404
|
+
|
|
405
|
+
if !resp.status().is_success() {
|
|
406
|
+
return Err(anyhow!(
|
|
407
|
+
"failed to fetch {url}: {status}",
|
|
408
|
+
status = resp.status().red()
|
|
409
|
+
));
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
let contents = resp.bytes().await?;
|
|
403
413
|
let tar = GzDecoder::new(contents.deref());
|
|
404
414
|
|
|
405
415
|
let mut archive = Archive::new(tar);
|
|
@@ -160,17 +160,18 @@ fn tip(err: impl AsRef<str>, tip: impl AsRef<str>) -> String {
|
|
|
160
160
|
|
|
161
161
|
#[instrument(skip(mode, registry))]
|
|
162
162
|
fn collect_from_repo_dir(
|
|
163
|
-
|
|
163
|
+
top_dir: &Utf8Path,
|
|
164
|
+
current_dir: &Utf8Path,
|
|
164
165
|
mode: &CollectionMode,
|
|
165
166
|
registry: &mut InputRegistry,
|
|
166
167
|
) -> Result<()> {
|
|
167
168
|
// The workflow directory might not exist if we're collecting from
|
|
168
169
|
// a repository that only contains actions.
|
|
169
170
|
if mode.workflows() {
|
|
170
|
-
let workflow_dir = if
|
|
171
|
-
|
|
171
|
+
let workflow_dir = if current_dir.ends_with(".github/workflows") {
|
|
172
|
+
current_dir.into()
|
|
172
173
|
} else {
|
|
173
|
-
|
|
174
|
+
current_dir.join(".github/workflows")
|
|
174
175
|
};
|
|
175
176
|
|
|
176
177
|
if workflow_dir.is_dir() {
|
|
@@ -180,7 +181,7 @@ fn collect_from_repo_dir(
|
|
|
180
181
|
match input_path.extension() {
|
|
181
182
|
Some(ext) if ext == "yml" || ext == "yaml" => {
|
|
182
183
|
registry
|
|
183
|
-
.register_by_path(input_path)
|
|
184
|
+
.register_by_path(input_path, Some(top_dir))
|
|
184
185
|
.with_context(|| format!("failed to register input: {input_path}"))?;
|
|
185
186
|
}
|
|
186
187
|
_ => continue,
|
|
@@ -192,18 +193,18 @@ fn collect_from_repo_dir(
|
|
|
192
193
|
}
|
|
193
194
|
|
|
194
195
|
if mode.actions() {
|
|
195
|
-
for entry in
|
|
196
|
+
for entry in current_dir.read_dir_utf8()? {
|
|
196
197
|
let entry = entry?;
|
|
197
198
|
let entry_path = entry.path();
|
|
198
199
|
|
|
199
200
|
if entry_path.is_file()
|
|
200
201
|
&& matches!(entry_path.file_name(), Some("action.yml" | "action.yaml"))
|
|
201
202
|
{
|
|
202
|
-
let action = Action::from_file(entry_path)?;
|
|
203
|
+
let action = Action::from_file(entry_path, Some(top_dir))?;
|
|
203
204
|
registry.register_input(action.into())?;
|
|
204
205
|
} else if entry_path.is_dir() && !entry_path.ends_with(".github/workflows") {
|
|
205
206
|
// Recurse and limit the collection mode to only actions.
|
|
206
|
-
collect_from_repo_dir(entry_path, &CollectionMode::ActionsOnly, registry)?;
|
|
207
|
+
collect_from_repo_dir(top_dir, entry_path, &CollectionMode::ActionsOnly, registry)?;
|
|
207
208
|
}
|
|
208
209
|
}
|
|
209
210
|
}
|
|
@@ -257,7 +258,16 @@ fn collect_from_repo_slug(
|
|
|
257
258
|
registry.register_input(workflow.into())?;
|
|
258
259
|
}
|
|
259
260
|
} else {
|
|
260
|
-
let inputs = client.fetch_audit_inputs(&slug)
|
|
261
|
+
let inputs = client.fetch_audit_inputs(&slug).with_context(|| {
|
|
262
|
+
tip(
|
|
263
|
+
format!(
|
|
264
|
+
"couldn't collect inputs from https://github.com/{owner}/{repo}",
|
|
265
|
+
owner = slug.owner,
|
|
266
|
+
repo = slug.repo
|
|
267
|
+
),
|
|
268
|
+
"confirm the repository exists and that you have access to it",
|
|
269
|
+
)
|
|
270
|
+
})?;
|
|
261
271
|
|
|
262
272
|
tracing::info!(
|
|
263
273
|
"collected {len} inputs from {owner}/{repo}",
|
|
@@ -266,7 +276,7 @@ fn collect_from_repo_slug(
|
|
|
266
276
|
repo = slug.repo
|
|
267
277
|
);
|
|
268
278
|
|
|
269
|
-
for input in
|
|
279
|
+
for input in inputs {
|
|
270
280
|
registry.register_input(input)?;
|
|
271
281
|
}
|
|
272
282
|
}
|
|
@@ -285,13 +295,13 @@ fn collect_inputs(
|
|
|
285
295
|
for input in inputs {
|
|
286
296
|
let input_path = Utf8Path::new(input);
|
|
287
297
|
if input_path.is_file() {
|
|
298
|
+
// When collecting individual files, we don't know which part
|
|
299
|
+
// of the input path is the prefix.
|
|
288
300
|
registry
|
|
289
|
-
.register_by_path(input_path)
|
|
301
|
+
.register_by_path(input_path, None)
|
|
290
302
|
.with_context(|| format!("failed to register input: {input_path}"))?;
|
|
291
303
|
} else if input_path.is_dir() {
|
|
292
|
-
|
|
293
|
-
let absolute = input_path.canonicalize_utf8()?;
|
|
294
|
-
collect_from_repo_dir(&absolute, mode, &mut registry)?;
|
|
304
|
+
collect_from_repo_dir(input_path, input_path, mode, &mut registry)?;
|
|
295
305
|
} else {
|
|
296
306
|
// If this input isn't a file or directory, it's probably an
|
|
297
307
|
// `owner/repo(@ref)?` slug.
|
|
@@ -387,7 +397,10 @@ fn run() -> Result<ExitCode> {
|
|
|
387
397
|
})?);
|
|
388
398
|
Span::current().pb_inc(1);
|
|
389
399
|
}
|
|
390
|
-
tracing::info!(
|
|
400
|
+
tracing::info!(
|
|
401
|
+
"🌈 completed {input}",
|
|
402
|
+
input = input.key().best_effort_relative_path()
|
|
403
|
+
);
|
|
391
404
|
}
|
|
392
405
|
}
|
|
393
406
|
|
|
@@ -101,7 +101,7 @@ impl Workflow {
|
|
|
101
101
|
InputKey::Local(_) => None,
|
|
102
102
|
InputKey::Remote(_) => {
|
|
103
103
|
// NOTE: InputKey's Display produces a URL, hence `key.to_string()`.
|
|
104
|
-
Some(Link::new(key.
|
|
104
|
+
Some(Link::new(key.best_effort_relative_path(), &key.to_string()).to_string())
|
|
105
105
|
}
|
|
106
106
|
};
|
|
107
107
|
|
|
@@ -114,11 +114,9 @@ impl Workflow {
|
|
|
114
114
|
}
|
|
115
115
|
|
|
116
116
|
/// Load a workflow from the given file on disk.
|
|
117
|
-
pub(crate) fn from_file<P: AsRef<Utf8Path>>(
|
|
118
|
-
let contents = std::fs::read_to_string(
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
Self::from_string(contents, InputKey::local(path)?)
|
|
117
|
+
pub(crate) fn from_file<P: AsRef<Utf8Path>>(path: P, prefix: Option<P>) -> Result<Self> {
|
|
118
|
+
let contents = std::fs::read_to_string(path.as_ref())?;
|
|
119
|
+
Self::from_string(contents, InputKey::local(path, prefix)?)
|
|
122
120
|
}
|
|
123
121
|
|
|
124
122
|
/// This workflow's [`SymbolicLocation`].
|
|
@@ -137,7 +135,7 @@ impl Workflow {
|
|
|
137
135
|
Jobs::new(self)
|
|
138
136
|
}
|
|
139
137
|
|
|
140
|
-
/// Whether this workflow
|
|
138
|
+
/// Whether this workflow is triggered by pull_request_target.
|
|
141
139
|
pub(crate) fn has_pull_request_target(&self) -> bool {
|
|
142
140
|
match &self.on {
|
|
143
141
|
Trigger::BareEvent(event) => *event == BareEvent::PullRequestTarget,
|
|
@@ -146,7 +144,7 @@ impl Workflow {
|
|
|
146
144
|
}
|
|
147
145
|
}
|
|
148
146
|
|
|
149
|
-
/// Whether this workflow
|
|
147
|
+
/// Whether this workflow is triggered by workflow_run.
|
|
150
148
|
pub(crate) fn has_workflow_run(&self) -> bool {
|
|
151
149
|
match &self.on {
|
|
152
150
|
Trigger::BareEvent(event) => *event == BareEvent::WorkflowRun,
|
|
@@ -154,6 +152,24 @@ impl Workflow {
|
|
|
154
152
|
Trigger::Events(events) => !matches!(events.workflow_run, OptionalBody::Missing),
|
|
155
153
|
}
|
|
156
154
|
}
|
|
155
|
+
|
|
156
|
+
/// Whether this workflow is triggered by workflow_call.
|
|
157
|
+
pub(crate) fn has_workflow_call(&self) -> bool {
|
|
158
|
+
match &self.on {
|
|
159
|
+
Trigger::BareEvent(event) => *event == BareEvent::WorkflowCall,
|
|
160
|
+
Trigger::BareEvents(events) => events.contains(&BareEvent::WorkflowCall),
|
|
161
|
+
Trigger::Events(events) => !matches!(events.workflow_call, OptionalBody::Missing),
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/// Whether this workflow is triggered by exactly one event.
|
|
166
|
+
pub(crate) fn has_single_trigger(&self) -> bool {
|
|
167
|
+
match &self.on {
|
|
168
|
+
Trigger::BareEvent(_) => true,
|
|
169
|
+
Trigger::BareEvents(events) => events.len() == 1,
|
|
170
|
+
Trigger::Events(events) => events.count() == 1,
|
|
171
|
+
}
|
|
172
|
+
}
|
|
157
173
|
}
|
|
158
174
|
|
|
159
175
|
/// Common behavior across both normal and reusable jobs.
|
|
@@ -716,13 +732,10 @@ impl Debug for Action {
|
|
|
716
732
|
|
|
717
733
|
impl Action {
|
|
718
734
|
/// Load an action from the given file on disk.
|
|
719
|
-
pub(crate) fn from_file<P: AsRef<Utf8Path>>(
|
|
735
|
+
pub(crate) fn from_file<P: AsRef<Utf8Path>>(path: P, prefix: Option<P>) -> Result<Self> {
|
|
720
736
|
let contents =
|
|
721
|
-
std::fs::read_to_string(
|
|
722
|
-
|
|
723
|
-
let path = p.as_ref().canonicalize_utf8()?;
|
|
724
|
-
|
|
725
|
-
Self::from_string(contents, InputKey::local(path)?)
|
|
737
|
+
std::fs::read_to_string(path.as_ref()).with_context(|| "couldn't read action file")?;
|
|
738
|
+
Self::from_string(contents, InputKey::local(path, prefix)?)
|
|
726
739
|
}
|
|
727
740
|
|
|
728
741
|
/// Load a workflow from a buffer, with an assigned name.
|
|
@@ -736,7 +749,7 @@ impl Action {
|
|
|
736
749
|
InputKey::Local(_) => None,
|
|
737
750
|
InputKey::Remote(_) => {
|
|
738
751
|
// NOTE: InputKey's Display produces a URL, hence `key.to_string()`.
|
|
739
|
-
Some(Link::new(key.
|
|
752
|
+
Some(Link::new(key.best_effort_relative_path(), &key.to_string()).to_string())
|
|
740
753
|
}
|
|
741
754
|
};
|
|
742
755
|
|