Repository navigation
Fix Checkov reusable workflow permission mismatch (#45) #17
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Test reusable workflows | |
| # CI for the reusable workflows in this repo. On every PR that touches a workflow | |
| # YAML or one of its fixtures (including Dependabot SHA bumps), invoke that | |
| # workflow against tests/fixtures/<name>/ and assert it still works. On push to | |
| # main and on manual dispatch, run the full matrix as a regression sweep. | |
| on: | |
| pull_request: | |
| paths: | |
| - '.github/workflows/**' | |
| - 'tests/fixtures/**' | |
| - '.nvmrc' | |
| push: | |
| branches: [main] | |
| workflow_dispatch: | |
| permissions: | |
| contents: read | |
| concurrency: | |
| group: test-workflows-${{ github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| detect: | |
| name: Detect changed workflows | |
| runs-on: ubuntu-latest | |
| outputs: | |
| slither: ${{ steps.f.outputs.slither }} | |
| checkov: ${{ steps.f.outputs.checkov }} | |
| infracost: ${{ steps.f.outputs.infracost }} | |
| action_lint: ${{ steps.f.outputs.action_lint }} | |
| scan_workflows: ${{ steps.f.outputs.scan_workflows }} | |
| validate_pr_label: ${{ steps.f.outputs.validate_pr_label }} | |
| semantic_versioning: ${{ steps.f.outputs.semantic_versioning }} | |
| doc_update: ${{ steps.f.outputs.doc_update }} | |
| full_run: ${{ steps.full.outputs.full_run }} | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| with: | |
| persist-credentials: false | |
| - id: f | |
| uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1 | |
| with: | |
| filters: | | |
| slither: | |
| - '.github/workflows/slither.yaml' | |
| - 'tests/fixtures/slither/**' | |
| - '.nvmrc' | |
| checkov: | |
| - '.github/workflows/checkov.yaml' | |
| - 'tests/fixtures/checkov/**' | |
| infracost: | |
| - '.github/workflows/infracost.yaml' | |
| - 'tests/fixtures/infracost/**' | |
| action_lint: | |
| - '.github/workflows/action-lint.yaml' | |
| scan_workflows: | |
| - '.github/workflows/scan-workflows.yaml' | |
| validate_pr_label: | |
| - '.github/workflows/validate-pr-label.yaml' | |
| semantic_versioning: | |
| - '.github/workflows/semantic-versioning.yaml' | |
| doc_update: | |
| - '.github/workflows/doc-update.yaml' | |
| - id: full | |
| env: | |
| EVENT_NAME: ${{ github.event_name }} | |
| run: | | |
| if [ "$EVENT_NAME" = "push" ] || [ "$EVENT_NAME" = "workflow_dispatch" ]; then | |
| echo "full_run=true" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "full_run=false" >> "$GITHUB_OUTPUT" | |
| fi | |
| test-action-lint: | |
| name: action-lint | |
| needs: detect | |
| if: needs.detect.outputs.full_run == 'true' || needs.detect.outputs.action_lint == 'true' | |
| uses: ./.github/workflows/action-lint.yaml | |
| permissions: | |
| contents: read | |
| test-scan-workflows: | |
| name: scan-workflows | |
| needs: detect | |
| if: needs.detect.outputs.full_run == 'true' || needs.detect.outputs.scan_workflows == 'true' | |
| uses: ./.github/workflows/scan-workflows.yaml | |
| permissions: | |
| contents: read | |
| actions: read | |
| checks: write | |
| issues: write | |
| pull-requests: write | |
| secrets: | |
| ZIZMOR_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| test-slither: | |
| name: slither | |
| needs: detect | |
| if: needs.detect.outputs.full_run == 'true' || needs.detect.outputs.slither == 'true' | |
| uses: ./.github/workflows/slither.yaml | |
| permissions: | |
| contents: read | |
| security-events: write | |
| pull-requests: write | |
| issues: write | |
| actions: write | |
| with: | |
| target: tests/fixtures/slither/contracts | |
| skip-change-detection: true | |
| compile-command: skip | |
| cache: yarn | |
| fail-on: none | |
| test-checkov: | |
| name: checkov | |
| needs: detect | |
| if: needs.detect.outputs.full_run == 'true' || needs.detect.outputs.checkov == 'true' | |
| uses: ./.github/workflows/checkov.yaml | |
| permissions: | |
| contents: read | |
| actions: write | |
| with: | |
| # Confine the scan to the checkov fixture - skip the infracost fixture | |
| # (intentionally minimal/unhardened) and any other tf in the tree. | |
| skip_path: 'tests/fixtures/infracost' | |
| soft_fail: true | |
| test-validate-pr-label: | |
| name: validate-pr-label | |
| needs: detect | |
| if: github.event_name == 'pull_request' && (needs.detect.outputs.full_run == 'true' || needs.detect.outputs.validate_pr_label == 'true') | |
| uses: ./.github/workflows/validate-pr-label.yaml | |
| permissions: | |
| contents: read | |
| pull-requests: write | |
| with: | |
| DEFAULT_LABEL: 'increment:patch' | |
| test-semantic-versioning: | |
| name: semantic-versioning | |
| needs: detect | |
| if: github.event_name == 'pull_request' && (needs.detect.outputs.full_run == 'true' || needs.detect.outputs.semantic_versioning == 'true') | |
| uses: ./.github/workflows/semantic-versioning.yaml | |
| permissions: | |
| contents: read | |
| with: | |
| dry_run: true | |
| test-doc-update: | |
| name: doc-update | |
| needs: detect | |
| if: needs.detect.outputs.full_run == 'true' || needs.detect.outputs.doc_update == 'true' | |
| uses: ./.github/workflows/doc-update.yaml | |
| permissions: | |
| # Match the called workflow's declared job-level permissions. dry_run gates | |
| # the actual write paths (commit, push, gh pr create) so no mutation occurs. | |
| contents: write | |
| pull-requests: write | |
| with: | |
| dry_run: true | |
| simulated_tag: 'v.99.0.0' | |
| test-infracost: | |
| name: infracost | |
| needs: detect | |
| if: github.event_name == 'pull_request' && (needs.detect.outputs.full_run == 'true' || needs.detect.outputs.infracost == 'true') | |
| uses: ./.github/workflows/infracost.yaml | |
| permissions: | |
| contents: read | |
| pull-requests: write | |
| with: | |
| run-on-tf-changes-only: false | |
| root_path: tests/fixtures/infracost | |
| secrets: | |
| INFRACOST_API_KEY: ${{ secrets.INFRACOST_API_KEY }} | |
| # Negative test: doc-update must reject a malformed tag. Atomic - validates | |
| # the workflow's own regex check at doc-update.yaml step "Get the new release | |
| # tag and SHA". No external tool dependency. | |
| # | |
| # NOTE: GitHub Actions does NOT allow `continue-on-error` on reusable-workflow | |
| # calls (`uses:` jobs accept only name/uses/with/secrets/needs/if/concurrency/ | |
| # permissions/strategy). This job will appear RED in the UI when the negative | |
| # case correctly fails - that is expected. The `assert-doc-update-bad-tag-failed` | |
| # job below is the one wired into `required`; it goes green when this one | |
| # fails as designed, and goes red if doc-update incorrectly accepts the bad tag. | |
| test-doc-update-bad-tag: | |
| name: doc-update (bad tag - expected to fail red) | |
| needs: detect | |
| # PR-only: this job is designed to fail. Running it on push/main or | |
| # workflow_dispatch would leave a permanent red on the default branch | |
| # workflow runs and on the badge. PRs touching doc-update.yaml still | |
| # exercise it (selective via paths-filter). | |
| if: github.event_name == 'pull_request' && needs.detect.outputs.doc_update == 'true' | |
| uses: ./.github/workflows/doc-update.yaml | |
| permissions: | |
| contents: write | |
| pull-requests: write | |
| with: | |
| dry_run: true | |
| simulated_tag: 'notvalid' | |
| assert-doc-update-bad-tag-failed: | |
| name: assert doc-update rejects malformed tag | |
| needs: test-doc-update-bad-tag | |
| if: always() && needs.test-doc-update-bad-tag.result != 'skipped' | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| steps: | |
| - name: Verify the negative case actually failed | |
| env: | |
| RESULT: ${{ needs.test-doc-update-bad-tag.result }} | |
| run: | | |
| if [ "$RESULT" != "failure" ]; then | |
| echo "::error::Expected doc-update to reject simulated_tag=notvalid (got: $RESULT). Tag-format validation regressed." | |
| exit 1 | |
| fi | |
| echo "OK - doc-update correctly rejected the malformed tag." | |
| required: | |
| name: Test harness summary | |
| needs: | |
| - detect | |
| - test-action-lint | |
| - test-scan-workflows | |
| - test-slither | |
| - test-checkov | |
| - test-validate-pr-label | |
| - test-semantic-versioning | |
| - test-doc-update | |
| - test-infracost | |
| - assert-doc-update-bad-tag-failed | |
| if: always() | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Aggregate test results | |
| env: | |
| RESULTS: ${{ join(needs.*.result, ',') }} | |
| run: | | |
| echo "Job results: $RESULTS" | |
| # Fail only on hard failures or cancellations. "skipped" is expected for | |
| # workflows whose YAML/fixtures didn't change in this PR. | |
| if printf '%s' "$RESULTS" | tr ',' '\n' | grep -qE '^(failure|cancelled)$'; then | |
| echo "::error::At least one test job failed." | |
| exit 1 | |
| fi | |
| echo "All test jobs passed (or were skipped)." |