diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 496138a..ee91615 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -18,16 +18,16 @@ updates: patterns: - "*" cooldown: - default-days: 2 semver-major-days: 7 semver-minor-days: 3 semver-patch-days: 2 + default-days: 7 commit-message: prefix: "deps" # GitHub Actions - package-ecosystem: github-actions - directory: / + directory: "/" schedule: interval: weekly day: monday @@ -39,6 +39,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 f51819b..1e8fbd9 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 08fb61a..cb262db 100644 --- a/.github/workflows/dependabot-auto-merge.yml +++ b/.github/workflows/dependabot-auto-merge.yml @@ -2,17 +2,18 @@ name: Dependabot auto-merge on: pull_request -permissions: - contents: write - pull-requests: write +permissions: {} jobs: auto-merge: name: Auto-merge runs-on: ubuntu-latest - if: github.actor == 'dependabot[bot]' + permissions: + contents: write + pull-requests: write + 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: - - uses: dependabot/fetch-metadata@21025c705c08248db411dc16f3619e6b5f9ea21a # v2 + - uses: dependabot/fetch-metadata@21025c705c08248db411dc16f3619e6b5f9ea21a # v2.5.0 id: metadata with: github-token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/direct-push-alert.yml b/.github/workflows/direct-push-alert.yml index 8e71119..943082f 100644 --- a/.github/workflows/direct-push-alert.yml +++ b/.github/workflows/direct-push-alert.yml @@ -4,9 +4,7 @@ on: push: branches: [main] -permissions: - contents: read - issues: write +permissions: {} jobs: alert: diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml index 955c4d8..6f9c1aa 100644 --- a/.github/workflows/labeler.yml +++ b/.github/workflows/labeler.yml @@ -1,16 +1,17 @@ name: Label PRs on: - pull_request_target: + pull_request_target: # zizmor: ignore[dangerous-triggers] -- required for write access to PRs from forks; workflow only runs actions/labeler, no PR code is checked out or executed types: [opened, synchronize, reopened] -permissions: - contents: read - pull-requests: write +permissions: {} jobs: label: runs-on: ubuntu-latest + permissions: + contents: read + pull-requests: write steps: - uses: actions/labeler@634933edcd8ababfe52f92936142cc22ac488b1b # v6.0.1 with: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ba16a45..fd52716 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -9,16 +9,16 @@ concurrency: group: release-${{ github.ref }} cancel-in-progress: false -permissions: - contents: write - security-events: write - pull-requests: read - models: read +permissions: {} jobs: security: name: Security uses: ./.github/workflows/security.yml + permissions: + contents: read + security-events: write + pull-requests: read test: name: Test gate @@ -26,16 +26,17 @@ jobs: permissions: contents: read steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 0 + persist-credentials: false - - 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 - name: Install golangci-lint - uses: golangci/golangci-lint-action@1e7e51e771db61008b38414a730f564565cf7c20 # v9 + uses: golangci/golangci-lint-action@1e7e51e771db61008b38414a730f564565cf7c20 # v9.2.0 with: version: v2.9.0 install-only: true @@ -84,9 +85,10 @@ jobs: contents: write models: read steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 0 + persist-credentials: false - name: Verify tag is on main env: @@ -202,7 +204,9 @@ jobs: env: HAS_SKILLS_KEY: ${{ secrets.SKILLS_APP_PRIVATE_KEY && 'true' || '' }} steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false - name: Check prerequisites id: check @@ -220,7 +224,7 @@ jobs: - name: Generate token if: steps.check.outputs.ready == 'true' id: skills-token - uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2 + uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2.2.1 with: app-id: ${{ vars.SKILLS_APP_ID }} private-key: ${{ secrets.SKILLS_APP_PRIVATE_KEY }} diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index fc5a0dc..f44e488 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -7,7 +7,7 @@ on: - cron: '30 1 * * 6' workflow_dispatch: -permissions: read-all +permissions: {} jobs: analysis: @@ -17,7 +17,7 @@ jobs: id-token: write contents: read steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false @@ -33,7 +33,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 35c65bd..025e65b 100644 --- a/.github/workflows/security.yml +++ b/.github/workflows/security.yml @@ -10,10 +10,7 @@ on: workflow_call: workflow_dispatch: -permissions: - contents: read - security-events: write - pull-requests: read +permissions: {} jobs: secrets: @@ -22,9 +19,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: | @@ -41,7 +39,9 @@ jobs: contents: read security-events: write steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false - name: Run Trivy vulnerability scanner (filesystem) uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1 # 0.35.0 @@ -56,7 +56,7 @@ jobs: version: 'v0.69.3' - name: Upload Trivy scan results to GitHub Security tab - uses: github/codeql-action/upload-sarif@0d579ffd059c29b07949a3cce3983f0780820c98 # v4 + uses: github/codeql-action/upload-sarif@0d579ffd059c29b07949a3cce3983f0780820c98 # v4.32.6 if: always() continue-on-error: true # Requires GitHub Advanced Security with: @@ -69,9 +69,11 @@ jobs: contents: read security-events: write steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false - - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6 + - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0 with: go-version-file: go.mod @@ -82,7 +84,7 @@ jobs: run: gosec -no-fail -fmt sarif -out gosec-results.sarif ./... - name: Upload gosec scan results to GitHub Security tab - uses: github/codeql-action/upload-sarif@0d579ffd059c29b07949a3cce3983f0780820c98 # v4 + uses: github/codeql-action/upload-sarif@0d579ffd059c29b07949a3cce3983f0780820c98 # v4.32.6 if: always() continue-on-error: true # Requires GitHub Advanced Security with: @@ -96,9 +98,11 @@ jobs: contents: read pull-requests: read steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false - - uses: actions/dependency-review-action@2031cfc080254a8a887f58cffee85186f0e49e48 # v4 + - uses: actions/dependency-review-action@2031cfc080254a8a887f58cffee85186f0e49e48 # v4.9.0 continue-on-error: true # Requires GitHub Advanced Security codeql: @@ -108,14 +112,16 @@ jobs: contents: read security-events: write steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false - - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6 + - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0 with: go-version-file: go.mod - name: Initialize CodeQL - uses: github/codeql-action/init@0d579ffd059c29b07949a3cce3983f0780820c98 # v4 + uses: github/codeql-action/init@0d579ffd059c29b07949a3cce3983f0780820c98 # v4.32.6 with: languages: go build-mode: manual @@ -127,14 +133,14 @@ jobs: run: go build ./... - name: Perform CodeQL analysis - uses: github/codeql-action/analyze@0d579ffd059c29b07949a3cce3983f0780820c98 # v4 + uses: github/codeql-action/analyze@0d579ffd059c29b07949a3cce3983f0780820c98 # v4.32.6 with: category: codeql-go upload: never output: sarif-results - name: Upload SARIF to GitHub Security tab - uses: github/codeql-action/upload-sarif@0d579ffd059c29b07949a3cce3983f0780820c98 # v4 + uses: github/codeql-action/upload-sarif@0d579ffd059c29b07949a3cce3983f0780820c98 # v4.32.6 continue-on-error: true # Requires GitHub Advanced Security with: sarif_file: sarif-results diff --git a/.github/workflows/sensitive-change-gate.yml b/.github/workflows/sensitive-change-gate.yml index 2ca5d7e..0af3330 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 workflow, 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 6f9fd54..cbe95f6 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -7,17 +7,20 @@ on: branches: [main] workflow_dispatch: -permissions: - contents: read +permissions: {} jobs: test: name: 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 - - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6 + - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0 with: go-version-file: go.mod @@ -38,24 +41,50 @@ jobs: lint: name: 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 - - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6 + - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0 with: go-version-file: go.mod - - uses: golangci/golangci-lint-action@1e7e51e771db61008b38414a730f564565cf7c20 # v9 + - uses: golangci/golangci-lint-action@1e7e51e771db61008b38414a730f564565cf7c20 # v9.2.0 with: version: v2.9.0 + 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 + security: name: Govulncheck runs-on: ubuntu-latest + permissions: + contents: read steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false - - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6 + - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0 with: go-version-file: go.mod @@ -68,10 +97,14 @@ jobs: test-race: name: Test (race detector) runs-on: ubuntu-latest + permissions: + contents: read steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false - - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6 + - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0 with: go-version-file: go.mod @@ -81,15 +114,18 @@ jobs: benchmarks: name: Benchmarks runs-on: ubuntu-latest + permissions: + contents: read if: github.event_name == 'push' && github.ref == 'refs/heads/main' steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 2 + persist-credentials: false - name: Check for benchmark-relevant changes id: filter - uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3 + uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2 with: filters: | bench: @@ -99,7 +135,7 @@ jobs: - name: Set up Go if: steps.filter.outputs.bench == 'true' - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6 + uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0 with: go-version-file: go.mod @@ -111,7 +147,7 @@ jobs: - name: Download previous benchmark baseline if: steps.filter.outputs.bench == 'true' - uses: actions/cache/restore@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5 + uses: actions/cache/restore@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3 with: path: benchmarks-baseline.txt key: benchmarks-baseline-${{ github.sha }} @@ -145,7 +181,7 @@ jobs: - name: Cache benchmark baseline if: steps.filter.outputs.bench == 'true' - uses: actions/cache/save@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5 + uses: actions/cache/save@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3 with: path: benchmarks-baseline.txt key: benchmarks-baseline-${{ github.sha }} diff --git a/Makefile b/Makefile index 12f1d28..008dcad 100644 --- a/Makefile +++ b/Makefile @@ -73,8 +73,13 @@ secrets: # Run all security checks security: lint vuln secrets +# Lint GitHub Actions workflows +lint-actions: + actionlint + zizmor . + # Full suite: everything CI runs. -check-all: fmt-check vet lint test-race bench tidy-check +check-all: fmt-check vet lint lint-actions test-race bench tidy-check # Full pre-flight for release release-check: check-all replace-check vuln secrets diff --git a/seed/.github/dependabot.yml b/seed/.github/dependabot.yml index f04f54a..f1ae092 100644 --- a/seed/.github/dependabot.yml +++ b/seed/.github/dependabot.yml @@ -17,7 +17,7 @@ updates: patterns: - "*" cooldown: - default-days: 2 + default-days: 7 semver-major-days: 7 semver-minor-days: 3 semver-patch-days: 2 @@ -38,6 +38,6 @@ updates: patterns: - "*" cooldown: - default-days: 2 + default-days: 7 commit-message: prefix: "ci" diff --git a/seed/.github/workflows/ai-labeler.yml b/seed/.github/workflows/ai-labeler.yml index c4813f4..e460f65 100644 --- a/seed/.github/workflows/ai-labeler.yml +++ b/seed/.github/workflows/ai-labeler.yml @@ -1,24 +1,27 @@ name: Classify PR on: - pull_request_target: + pull_request_target: # zizmor: ignore[dangerous-triggers] -- required for write access to PRs from forks; workflow only runs trusted actions and gh CLI commands, 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: runs-on: ubuntu-latest + permissions: + contents: read + issues: write + models: read + pull-requests: write steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false - name: Build prompt env: @@ -100,8 +103,15 @@ jobs: breaking: runs-on: ubuntu-latest + permissions: + contents: read + issues: write + models: read + pull-requests: write steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false - name: Build prompt id: cmd-diff diff --git a/seed/.github/workflows/dependabot-auto-merge.yml b/seed/.github/workflows/dependabot-auto-merge.yml index b285a85..35cc334 100644 --- a/seed/.github/workflows/dependabot-auto-merge.yml +++ b/seed/.github/workflows/dependabot-auto-merge.yml @@ -2,14 +2,15 @@ name: Dependabot Auto-Merge on: pull_request -permissions: - contents: write - pull-requests: write +permissions: {} jobs: auto-merge: runs-on: ubuntu-latest - if: github.actor == 'dependabot[bot]' + permissions: + contents: write + pull-requests: write + 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 diff --git a/seed/.github/workflows/labeler.yml b/seed/.github/workflows/labeler.yml index 955c4d8..6f9c1aa 100644 --- a/seed/.github/workflows/labeler.yml +++ b/seed/.github/workflows/labeler.yml @@ -1,16 +1,17 @@ name: Label PRs on: - pull_request_target: + pull_request_target: # zizmor: ignore[dangerous-triggers] -- required for write access to PRs from forks; workflow only runs actions/labeler, no PR code is checked out or executed types: [opened, synchronize, reopened] -permissions: - contents: read - pull-requests: write +permissions: {} jobs: label: runs-on: ubuntu-latest + permissions: + contents: read + pull-requests: write steps: - uses: actions/labeler@634933edcd8ababfe52f92936142cc22ac488b1b # v6.0.1 with: diff --git a/seed/.github/workflows/release.yml b/seed/.github/workflows/release.yml index 614b491..014e7a4 100644 --- a/seed/.github/workflows/release.yml +++ b/seed/.github/workflows/release.yml @@ -9,18 +9,16 @@ concurrency: group: release-${{ github.ref }} cancel-in-progress: false -permissions: - contents: write - id-token: write - attestations: write - security-events: write - pull-requests: read - models: read +permissions: {} jobs: security: name: Security scan uses: ./.github/workflows/security.yml + permissions: + contents: read + security-events: write + pull-requests: read secrets: RELEASE_APP_PRIVATE_KEY: ${{ secrets.RELEASE_APP_PRIVATE_KEY }} @@ -36,20 +34,21 @@ jobs: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: fetch-depth: 0 + persist-credentials: false # Configure vars.RELEASE_CLIENT_ID and secrets.RELEASE_APP_PRIVATE_KEY to enable private module access - name: Generate token for private module access if: vars.RELEASE_CLIENT_ID != '' id: app-token - uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2 + uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2.2.1 with: app-id: ${{ vars.RELEASE_CLIENT_ID }} - private-key: ${{ secrets.RELEASE_APP_PRIVATE_KEY }} + private-key: ${{ secrets.RELEASE_APP_PRIVATE_KEY }} # zizmor: ignore[secrets-outside-env] -- private module token needed in pre-release tests; environment protection would block test gate before release approval owner: basecamp # repositories: ,homebrew-tap - name: Set up Go - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6 + uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6 # zizmor: ignore[cache-poisoning] -- cache is branch-isolated; fork PRs cannot write to this cache with: go-version-file: 'go.mod' @@ -67,7 +66,7 @@ jobs: - name: Cache BATS id: cache-bats - uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5 + uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3 # zizmor: ignore[cache-poisoning] -- static cache key (bats-1.11.0) is not attacker-controllable with: path: /usr/local/libexec/bats-core key: bats-1.11.0 @@ -138,12 +137,13 @@ jobs: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: fetch-depth: 0 + persist-credentials: false # Configure vars.RELEASE_CLIENT_ID and secrets.RELEASE_APP_PRIVATE_KEY for private modules + Homebrew tap - name: Generate token for private module and tap access if: vars.RELEASE_CLIENT_ID != '' id: sdk-token - uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2 + uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2.2.1 with: app-id: ${{ vars.RELEASE_CLIENT_ID }} private-key: ${{ secrets.RELEASE_APP_PRIVATE_KEY }} @@ -151,7 +151,7 @@ jobs: # repositories: ,homebrew-tap - name: Set up Go - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6 + uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6 # zizmor: ignore[cache-poisoning] -- cache is branch-isolated; fork PRs cannot write to this cache with: go-version-file: 'go.mod' @@ -197,7 +197,7 @@ jobs: uses: sigstore/cosign-installer@faadad0cce49287aee09b3a48701e75088a2c6ad # v4.0.0 - name: Install Syft - uses: anchore/sbom-action/download-syft@17ae1740179002c89186b61233e0f892c3118b11 # v0 + uses: anchore/sbom-action/download-syft@17ae1740179002c89186b61233e0f892c3118b11 # v0.23.0 # Configure vars.ENABLE_AI_CHANGELOG=true plus models:read permission to enable AI changelog - name: Build changelog context @@ -351,6 +351,8 @@ jobs: contents: read steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false - name: Check for skill files id: check-skills @@ -365,7 +367,7 @@ jobs: - name: Generate token for skills repo if: steps.check-skills.outputs.found == 'true' id: skills-token - uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2 + uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2.2.1 with: app-id: ${{ vars.SKILLS_APP_ID }} private-key: ${{ secrets.SKILLS_APP_PRIVATE_KEY }} diff --git a/seed/.github/workflows/scorecard.yml b/seed/.github/workflows/scorecard.yml index 6f0223e..95f9ea6 100644 --- a/seed/.github/workflows/scorecard.yml +++ b/seed/.github/workflows/scorecard.yml @@ -7,7 +7,7 @@ on: - cron: '30 1 * * 6' workflow_dispatch: -permissions: read-all +permissions: {} jobs: analysis: @@ -33,7 +33,7 @@ jobs: path: results.sarif retention-days: 5 - - uses: github/codeql-action/upload-sarif@c793b717bc78562f491db7b0e93a3a178b099162 # v4 + - uses: github/codeql-action/upload-sarif@c793b717bc78562f491db7b0e93a3a178b099162 # v4.32.5 continue-on-error: true with: sarif_file: results.sarif diff --git a/seed/.github/workflows/security.yml b/seed/.github/workflows/security.yml index a5dc882..ce41ad6 100644 --- a/seed/.github/workflows/security.yml +++ b/seed/.github/workflows/security.yml @@ -14,19 +14,19 @@ on: required: false workflow_dispatch: -permissions: - contents: read - security-events: write - pull-requests: read +permissions: {} jobs: secrets: name: Secret Scanning runs-on: ubuntu-latest + permissions: + contents: read steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: fetch-depth: 0 + persist-credentials: false - name: Install gitleaks run: | @@ -39,9 +39,14 @@ jobs: trivy: name: Trivy Security Scan runs-on: ubuntu-latest + permissions: + contents: read + security-events: write steps: - name: Checkout code uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false - name: Run Trivy vulnerability scanner (filesystem) uses: aquasecurity/trivy-action@e368e328979b113139d6f9068e03accaed98a518 # 0.34.1 @@ -56,7 +61,7 @@ jobs: version: 'v0.69.3' - name: Upload Trivy scan results to GitHub Security tab - uses: github/codeql-action/upload-sarif@89a39a4e59826350b863aa6b6252a07ad50cf83e # v4 + uses: github/codeql-action/upload-sarif@89a39a4e59826350b863aa6b6252a07ad50cf83e # v4.32.4 if: always() continue-on-error: true # Requires GitHub Advanced Security with: @@ -65,18 +70,23 @@ jobs: gosec: name: Go Security Checker runs-on: ubuntu-latest + permissions: + contents: read + security-events: write steps: - name: Checkout code uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false # Configure vars.RELEASE_CLIENT_ID and secrets.RELEASE_APP_PRIVATE_KEY to enable private module access - name: Generate token for private module access if: vars.RELEASE_CLIENT_ID != '' id: app-token - uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2 + uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2.2.1 with: app-id: ${{ vars.RELEASE_CLIENT_ID }} - private-key: ${{ secrets.RELEASE_APP_PRIVATE_KEY }} + private-key: ${{ secrets.RELEASE_APP_PRIVATE_KEY }} # zizmor: ignore[secrets-outside-env] -- private module token needed in CI security scans; environment protection would block PR-triggered runs owner: basecamp - name: Set up Go @@ -96,7 +106,7 @@ jobs: gosec -no-fail -fmt sarif -out gosec-results.sarif ./... - name: Upload gosec scan results to GitHub Security tab - uses: github/codeql-action/upload-sarif@89a39a4e59826350b863aa6b6252a07ad50cf83e # v4 + uses: github/codeql-action/upload-sarif@89a39a4e59826350b863aa6b6252a07ad50cf83e # v4.32.4 if: always() continue-on-error: true # Requires GitHub Advanced Security with: @@ -107,26 +117,36 @@ jobs: dependency-review: name: Dependency Review runs-on: ubuntu-latest + permissions: + contents: read + pull-requests: read if: github.event_name == 'pull_request' continue-on-error: true # Requires GitHub Advanced Security (not available on all plans) steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 - - uses: actions/dependency-review-action@05fe4576374b728f0c523d6a13d64c25081e0803 # v4 + with: + persist-credentials: false + - uses: actions/dependency-review-action@05fe4576374b728f0c523d6a13d64c25081e0803 # v4.8.3 codeql: name: CodeQL Analysis runs-on: ubuntu-latest + permissions: + contents: read + security-events: write steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false # Configure vars.RELEASE_CLIENT_ID and secrets.RELEASE_APP_PRIVATE_KEY to enable private module access - name: Generate token for private module access if: vars.RELEASE_CLIENT_ID != '' id: app-token - uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2 + uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2.2.1 with: app-id: ${{ vars.RELEASE_CLIENT_ID }} - private-key: ${{ secrets.RELEASE_APP_PRIVATE_KEY }} + private-key: ${{ secrets.RELEASE_APP_PRIVATE_KEY }} # zizmor: ignore[secrets-outside-env] -- private module token needed in CI security scans; environment protection would block PR-triggered runs owner: basecamp - name: Set up Go @@ -141,7 +161,7 @@ jobs: run: git config --global url."https://x-access-token:${TOKEN}@github.com/".insteadOf "https://github.com/" - name: Initialize CodeQL - uses: github/codeql-action/init@89a39a4e59826350b863aa6b6252a07ad50cf83e # v4 + uses: github/codeql-action/init@89a39a4e59826350b863aa6b6252a07ad50cf83e # v4.32.4 with: languages: go build-mode: manual @@ -153,14 +173,14 @@ jobs: run: go build ./... - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@89a39a4e59826350b863aa6b6252a07ad50cf83e # v4 + uses: github/codeql-action/analyze@89a39a4e59826350b863aa6b6252a07ad50cf83e # v4.32.4 with: category: codeql-go upload: never output: sarif-results - name: Upload SARIF to GitHub Security tab - uses: github/codeql-action/upload-sarif@89a39a4e59826350b863aa6b6252a07ad50cf83e # v4 + uses: github/codeql-action/upload-sarif@89a39a4e59826350b863aa6b6252a07ad50cf83e # v4.32.4 continue-on-error: true # Requires GitHub Advanced Security with: sarif_file: sarif-results diff --git a/seed/.github/workflows/test.yml b/seed/.github/workflows/test.yml index 3c88e8b..c3b8f5a 100644 --- a/seed/.github/workflows/test.yml +++ b/seed/.github/workflows/test.yml @@ -7,27 +7,30 @@ on: branches: [main] workflow_dispatch: -permissions: - contents: read +permissions: {} jobs: test: name: Tests runs-on: ubuntu-latest + permissions: + contents: read env: APPNAME_NO_KEYRING: "1" # Uncomment for private module access: GOPRIVATE: github.com/basecamp/ steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false # Configure vars.RELEASE_CLIENT_ID and secrets.RELEASE_APP_PRIVATE_KEY to enable private module access - name: Generate token for private module access if: vars.RELEASE_CLIENT_ID != '' id: app-token - uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2 + uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2.2.1 with: app-id: ${{ vars.RELEASE_CLIENT_ID }} - private-key: ${{ secrets.RELEASE_APP_PRIVATE_KEY }} + private-key: ${{ secrets.RELEASE_APP_PRIVATE_KEY }} # zizmor: ignore[secrets-outside-env] -- private module token needed in CI; environment protection would block PR-triggered runs owner: basecamp # repositories: @@ -60,17 +63,21 @@ jobs: lint: name: Lint runs-on: ubuntu-latest + permissions: + contents: read steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false # Uncomment for private module access: GOPRIVATE: github.com/basecamp/ - name: Generate token for private module access if: vars.RELEASE_CLIENT_ID != '' id: app-token - uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2 + uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2.2.1 with: app-id: ${{ vars.RELEASE_CLIENT_ID }} - private-key: ${{ secrets.RELEASE_APP_PRIVATE_KEY }} + private-key: ${{ secrets.RELEASE_APP_PRIVATE_KEY }} # zizmor: ignore[secrets-outside-env] -- private module token needed in CI; environment protection would block PR-triggered runs owner: basecamp - name: Set up Go @@ -92,16 +99,20 @@ jobs: security: name: Security runs-on: ubuntu-latest + permissions: + contents: read steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false - name: Generate token for private module access if: vars.RELEASE_CLIENT_ID != '' id: app-token - uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2 + uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2.2.1 with: app-id: ${{ vars.RELEASE_CLIENT_ID }} - private-key: ${{ secrets.RELEASE_APP_PRIVATE_KEY }} + private-key: ${{ secrets.RELEASE_APP_PRIVATE_KEY }} # zizmor: ignore[secrets-outside-env] -- private module token needed in CI; environment protection would block PR-triggered runs owner: basecamp - name: Set up Go @@ -125,19 +136,23 @@ jobs: race-check: name: Race Detection runs-on: ubuntu-latest + permissions: + contents: read env: APPNAME_NO_KEYRING: "1" # Uncomment for private module access: GOPRIVATE: github.com/basecamp/ steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false - name: Generate token for private module access if: vars.RELEASE_CLIENT_ID != '' id: app-token - uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2 + uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2.2.1 with: app-id: ${{ vars.RELEASE_CLIENT_ID }} - private-key: ${{ secrets.RELEASE_APP_PRIVATE_KEY }} + private-key: ${{ secrets.RELEASE_APP_PRIVATE_KEY }} # zizmor: ignore[secrets-outside-env] -- private module token needed in CI; environment protection would block PR-triggered runs owner: basecamp - name: Set up Go @@ -157,19 +172,23 @@ jobs: integration: name: Integration Tests runs-on: ubuntu-latest + permissions: + contents: read env: APPNAME_NO_KEYRING: "1" # Uncomment for private module access: GOPRIVATE: github.com/basecamp/ steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false - name: Generate token for private module access if: vars.RELEASE_CLIENT_ID != '' id: app-token - uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2 + uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2.2.1 with: app-id: ${{ vars.RELEASE_CLIENT_ID }} - private-key: ${{ secrets.RELEASE_APP_PRIVATE_KEY }} + private-key: ${{ secrets.RELEASE_APP_PRIVATE_KEY }} # zizmor: ignore[secrets-outside-env] -- private module token needed in CI; environment protection would block PR-triggered runs owner: basecamp - name: Set up Go @@ -185,7 +204,7 @@ jobs: - name: Cache BATS id: cache-bats - uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5 + uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3 with: path: /usr/local/libexec/bats-core key: bats-1.11.0 @@ -202,6 +221,8 @@ jobs: cli-surface: name: CLI Surface Check runs-on: ubuntu-latest + permissions: + contents: read env: APPNAME_NO_KEYRING: "1" # Uncomment for private module access: GOPRIVATE: github.com/basecamp/ @@ -209,14 +230,15 @@ jobs: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: fetch-depth: 0 + persist-credentials: false - name: Generate token for private module access if: vars.RELEASE_CLIENT_ID != '' id: app-token - uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2 + uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2.2.1 with: app-id: ${{ vars.RELEASE_CLIENT_ID }} - private-key: ${{ secrets.RELEASE_APP_PRIVATE_KEY }} + private-key: ${{ secrets.RELEASE_APP_PRIVATE_KEY }} # zizmor: ignore[secrets-outside-env] -- private module token needed in CI; environment protection would block PR-triggered runs owner: basecamp - name: Set up Go @@ -255,6 +277,8 @@ jobs: benchmarks: name: Benchmarks runs-on: ubuntu-latest + permissions: + contents: read if: github.event_name == 'push' && github.ref == 'refs/heads/main' continue-on-error: true env: @@ -264,14 +288,15 @@ jobs: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: fetch-depth: 2 + persist-credentials: false - name: Generate token for private module access if: vars.RELEASE_CLIENT_ID != '' id: app-token - uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2 + uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2.2.1 with: app-id: ${{ vars.RELEASE_CLIENT_ID }} - private-key: ${{ secrets.RELEASE_APP_PRIVATE_KEY }} + private-key: ${{ secrets.RELEASE_APP_PRIVATE_KEY }} # zizmor: ignore[secrets-outside-env] -- private module token needed in CI; environment protection would block PR-triggered runs owner: basecamp - name: Check for benchmark-relevant changes @@ -302,7 +327,7 @@ jobs: - name: Download previous benchmark baseline if: steps.filter.outputs.bench == 'true' - uses: actions/cache/restore@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5 + uses: actions/cache/restore@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3 with: path: benchmarks-baseline.txt key: benchmarks-baseline-${{ github.sha }} @@ -336,7 +361,7 @@ jobs: - name: Cache benchmark baseline if: steps.filter.outputs.bench == 'true' - uses: actions/cache/save@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5 + uses: actions/cache/save@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3 with: path: benchmarks-baseline.txt key: benchmarks-baseline-${{ github.sha }}