diff --git a/.github/dependabot.yml b/.github/dependabot.yml index f30bd60..3ee2faa 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -14,7 +14,7 @@ updates: patterns: - "*" cooldown: - default-days: 2 + default-days: 7 semver-major-days: 7 semver-minor-days: 3 semver-patch-days: 2 @@ -35,6 +35,6 @@ updates: patterns: - "*" cooldown: - default-days: 2 + default-days: 7 commit-message: prefix: "ci" diff --git a/.github/workflows/ai-labeler.yml b/.github/workflows/ai-labeler.yml index 5459d49..16e24d0 100644 --- a/.github/workflows/ai-labeler.yml +++ b/.github/workflows/ai-labeler.yml @@ -1,18 +1,14 @@ name: Classify PR on: - pull_request_target: + pull_request_target: # zizmor: ignore[dangerous-triggers] -- required for write access to PRs from forks; workflow only calls reusable workflows, no PR code is checked out or executed types: [opened, synchronize, reopened] concurrency: group: classify-pr-${{ github.event.pull_request.number }} cancel-in-progress: true -permissions: - contents: read - issues: write - models: read - pull-requests: write +permissions: {} jobs: classify: diff --git a/.github/workflows/dependabot-auto-merge.yml b/.github/workflows/dependabot-auto-merge.yml index 310e2a1..626fafb 100644 --- a/.github/workflows/dependabot-auto-merge.yml +++ b/.github/workflows/dependabot-auto-merge.yml @@ -10,11 +10,11 @@ jobs: permissions: contents: write pull-requests: write - if: github.actor == 'dependabot[bot]' + if: github.actor == 'dependabot[bot]' && github.event.pull_request.user.login == 'dependabot[bot]' # zizmor: ignore[bot-conditions] -- dual check: actor validates current trigger, user.login validates PR origin steps: - name: Fetch Dependabot metadata id: metadata - uses: dependabot/fetch-metadata@21025c705c08248db411dc16f3619e6b5f9ea21a # v2 + uses: dependabot/fetch-metadata@21025c705c08248db411dc16f3619e6b5f9ea21a # v2.5.0 with: github-token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/direct-push-alert.yml b/.github/workflows/direct-push-alert.yml index 2989bb6..77b472e 100644 --- a/.github/workflows/direct-push-alert.yml +++ b/.github/workflows/direct-push-alert.yml @@ -4,9 +4,7 @@ on: push: branches: [master] -permissions: - contents: read - issues: write +permissions: {} jobs: alert: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 59e101e..d3ad0a7 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -35,12 +35,13 @@ jobs: attestations: write pull-requests: read steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 0 + persist-credentials: false - name: Set up Go - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6 + uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0 # zizmor: ignore[cache-poisoning] -- cache is branch-isolated; fork PRs cannot write to this cache with: go-version-file: go.mod @@ -78,7 +79,7 @@ jobs: - name: Generate GitHub App token id: app-token - uses: actions/create-github-app-token@f8d387b68d61c58ab83c6c016672934102569859 # v3 + uses: actions/create-github-app-token@f8d387b68d61c58ab83c6c016672934102569859 # v3.0.0 with: app-id: ${{ vars.RELEASE_CLIENT_ID }} private-key: ${{ secrets.RELEASE_APP_PRIVATE_KEY }} @@ -89,7 +90,7 @@ jobs: uses: sigstore/cosign-installer@ba7bc0a3fef59531c69a25acd34668d6d3fe6f22 # v4.1.0 - name: Install Syft - uses: anchore/sbom-action/download-syft@57aae528053a48a3f6235f2d9461b05fbcb7366d # v0 + uses: anchore/sbom-action/download-syft@57aae528053a48a3f6235f2d9461b05fbcb7366d # v0.23.1 - name: Generate shell completions run: | @@ -101,7 +102,7 @@ jobs: rm fizzy-tmp - name: Run GoReleaser - uses: goreleaser/goreleaser-action@ec59f474b9834571250b370d4735c50f8e2d1e29 # v7 + uses: goreleaser/goreleaser-action@ec59f474b9834571250b370d4735c50f8e2d1e29 # v7.0.0 with: version: 'v2.14.1' args: release --clean @@ -127,7 +128,9 @@ jobs: contents: read if: startsWith(github.ref, 'refs/tags/v') steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false - name: Check AUR secret id: check diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index 0364711..1aad8a6 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -7,17 +7,18 @@ on: - cron: '30 1 * * 6' workflow_dispatch: -permissions: read-all +permissions: {} jobs: analysis: runs-on: ubuntu-latest permissions: + actions: read security-events: write id-token: write contents: read steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false @@ -33,7 +34,7 @@ jobs: path: results.sarif retention-days: 5 - - uses: github/codeql-action/upload-sarif@0d579ffd059c29b07949a3cce3983f0780820c98 # v4 + - uses: github/codeql-action/upload-sarif@0d579ffd059c29b07949a3cce3983f0780820c98 # v4.32.6 continue-on-error: true with: sarif_file: results.sarif diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml index 035d48d..5fe2c52 100644 --- a/.github/workflows/security.yml +++ b/.github/workflows/security.yml @@ -18,9 +18,10 @@ jobs: permissions: contents: read steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 0 + persist-credentials: false - name: Install gitleaks run: | curl -sSfL https://github.com/gitleaks/gitleaks/releases/download/v8.21.2/gitleaks_8.21.2_linux_x64.tar.gz | tar -xz @@ -36,13 +37,15 @@ jobs: security-events: write if: github.event_name != 'pull_request' steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false - uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1 # 0.35.0 with: scan-type: fs format: sarif output: trivy-results.sarif - - uses: github/codeql-action/upload-sarif@0d579ffd059c29b07949a3cce3983f0780820c98 # v4 + - uses: github/codeql-action/upload-sarif@0d579ffd059c29b07949a3cce3983f0780820c98 # v4.32.6 with: sarif_file: trivy-results.sarif category: trivy @@ -55,11 +58,13 @@ jobs: security-events: write if: github.event_name != 'pull_request' steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false - uses: securego/gosec@bb17e422fc34bf4c0a2e5cab9d07dc45a68c040c # v2.24.7 with: args: -no-fail -exclude=G304,G401,G501 -exclude-dir=e2e -fmt sarif -out gosec-results.sarif ./... - - uses: github/codeql-action/upload-sarif@0d579ffd059c29b07949a3cce3983f0780820c98 # v4 + - uses: github/codeql-action/upload-sarif@0d579ffd059c29b07949a3cce3983f0780820c98 # v4.32.6 with: sarif_file: gosec-results.sarif category: gosec @@ -71,5 +76,7 @@ jobs: contents: read if: github.event_name == 'pull_request' steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 - - uses: actions/dependency-review-action@2031cfc080254a8a887f58cffee85186f0e49e48 # v4 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + - uses: actions/dependency-review-action@2031cfc080254a8a887f58cffee85186f0e49e48 # v4.9.0 diff --git a/.github/workflows/sensitive-change-gate.yml b/.github/workflows/sensitive-change-gate.yml index cbdf855..d2023eb 100644 --- a/.github/workflows/sensitive-change-gate.yml +++ b/.github/workflows/sensitive-change-gate.yml @@ -1,12 +1,10 @@ name: Sensitive Change Gate on: - pull_request_target: + pull_request_target: # zizmor: ignore[dangerous-triggers] -- required for write access to PRs from forks; workflow only calls reusable workflows, no PR code is checked out or executed types: [opened, synchronize, reopened] -permissions: - contents: read - pull-requests: write +permissions: {} jobs: gate: diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 80e9101..4ed9378 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -7,17 +7,20 @@ on: branches: [master] workflow_call: -permissions: - contents: read +permissions: {} jobs: test: runs-on: ubuntu-latest + permissions: + contents: read steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false - name: Set up Go - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6 + uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0 with: go-version-file: go.mod @@ -38,11 +41,15 @@ jobs: lint: runs-on: ubuntu-latest + permissions: + contents: read steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false - name: Set up Go - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6 + uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0 with: go-version-file: go.mod @@ -53,17 +60,21 @@ jobs: run: go vet ./... - name: golangci-lint - uses: golangci/golangci-lint-action@1e7e51e771db61008b38414a730f564565cf7c20 # v9 + uses: golangci/golangci-lint-action@1e7e51e771db61008b38414a730f564565cf7c20 # v9.2.0 with: version: v2.10 security: runs-on: ubuntu-latest + permissions: + contents: read steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false - name: Set up Go - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6 + uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0 with: go-version: 'stable' @@ -72,13 +83,35 @@ jobs: go install golang.org/x/vuln/cmd/govulncheck@v1.1.4 govulncheck ./... + lint-actions: + name: GitHub Actions audit + runs-on: ubuntu-latest + permissions: + contents: read + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + + - name: Run actionlint + uses: rhysd/actionlint@393031adb9afb225ee52ae2ccd7a5af5525e03e8 # v1.7.11 + + - name: Run zizmor + uses: zizmorcore/zizmor-action@71321a20a9ded102f6e9ce5718a2fcec2c4f70d8 # v0.5.2 + with: + advanced-security: false + race-check: runs-on: ubuntu-latest + permissions: + contents: read steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false - name: Set up Go - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6 + uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0 with: go-version-file: go.mod diff --git a/Makefile b/Makefile index cd8c167..c32e428 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ .PHONY: test test-unit test-e2e test-go test-file test-run build clean tidy help \ check-toolchain fmt fmt-check vet lint tidy-check race-test vuln secrets \ replace-check security check release-check release tools \ - surface-snapshot surface-check sync-skill + surface-snapshot surface-check sync-skill lint-actions BINARY := $(CURDIR)/bin/fizzy VERSION ?= $(shell git describe --tags --always --dirty 2>/dev/null || echo dev) @@ -37,6 +37,7 @@ help: @echo " make secrets Run gitleaks secret scan" @echo " make replace-check Guard against replace directives in go.mod" @echo "" + @echo " make lint-actions Lint GitHub Actions workflows" @echo " make security lint + vuln + secrets" @echo " make check fmt-check + vet + lint + test-unit + tidy-check" @echo " make release-check check + replace-check + vuln + race-test" @@ -166,11 +167,28 @@ release-check: check replace-check vuln release: @scripts/release.sh +# Lint GitHub Actions workflows +lint-actions: + actionlint + zizmor . + # Install dev tools tools: go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest go install golang.org/x/vuln/cmd/govulncheck@latest @echo "For gitleaks, install via: brew install gitleaks (or see https://github.com/gitleaks/gitleaks)" + @for tool in actionlint shellcheck zizmor; do \ + if ! command -v "$$tool" > /dev/null 2>&1; then \ + if command -v brew > /dev/null 2>&1; then \ + brew install "$$tool"; \ + elif command -v pacman > /dev/null 2>&1; then \ + sudo pacman -S --noconfirm "$$tool"; \ + else \ + echo "Error: install $$tool manually" >&2; \ + exit 1; \ + fi; \ + fi; \ + done # Regenerate SURFACE.txt surface-snapshot: