diff --git a/.github/dependabot.yml b/.github/dependabot.yml index f04f54a9..1ff7a9a4 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -17,7 +17,7 @@ updates: patterns: - "*" cooldown: - default-days: 2 + default-days: 10 semver-major-days: 7 semver-minor-days: 3 semver-patch-days: 2 @@ -38,6 +38,6 @@ updates: patterns: - "*" cooldown: - default-days: 2 + default-days: 10 commit-message: prefix: "ci" diff --git a/.github/workflows/ai-labeler.yml b/.github/workflows/ai-labeler.yml index 3085c539..bee8b7d6 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 trusted 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 b285a859..c09e5961 100644 --- a/.github/workflows/dependabot-auto-merge.yml +++ b/.github/workflows/dependabot-auto-merge.yml @@ -2,18 +2,19 @@ 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 is intentional: actor validates current trigger, user.login validates PR origin; on:pull_request (not pull_request_target) so actor is set by GitHub based on who pushed 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 8e711197..943082fe 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 955c4d8b..9df17352 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 trusted actions/labeler action, 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 4383346e..42ae50d7 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -9,12 +9,7 @@ concurrency: group: release-${{ github.ref }} cancel-in-progress: false -permissions: - contents: write - id-token: write - security-events: write - pull-requests: read - models: read +permissions: {} jobs: security: @@ -33,24 +28,25 @@ jobs: env: BASECAMP_NO_KEYRING: "1" 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 the cache used by tag-push workflows 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 - name: Cache BATS id: cache-bats - uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5 + uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3 # zizmor: ignore[cache-poisoning] -- cache is branch-isolated; fork PRs cannot write to the cache used by tag-push workflows with: path: /usr/local/libexec/bats-core key: bats-1.11.0 @@ -112,13 +108,14 @@ jobs: models: read attestations: write steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 0 + persist-credentials: false - name: Generate token for Homebrew tap id: sdk-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 }} @@ -127,7 +124,7 @@ jobs: permission-contents: write - 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 the cache used by tag-push workflows with: go-version-file: 'go.mod' @@ -140,7 +137,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: Build changelog context run: | @@ -226,7 +223,7 @@ jobs: MACOS_NOTARY_ISSUER_ID: ${{ secrets.MACOS_NOTARY_ISSUER_ID }} - name: Install GoReleaser - uses: goreleaser/goreleaser-action@ec59f474b9834571250b370d4735c50f8e2d1e29 # v7 + uses: goreleaser/goreleaser-action@ec59f474b9834571250b370d4735c50f8e2d1e29 # v7.0.0 with: distribution: goreleaser version: 'v2.14.1' @@ -278,15 +275,17 @@ jobs: permissions: contents: read steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false - name: Install Nix - uses: cachix/install-nix-action@1ca7d21a94afc7c957383a2d217460d980de4934 # v31 + uses: cachix/install-nix-action@1ca7d21a94afc7c957383a2d217460d980de4934 # v31.10.1 - name: Build and verify run: | STORE_PATH=$(nix build --no-link --print-out-paths) - $STORE_PATH/bin/basecamp --version + "$STORE_PATH/bin/basecamp" --version sync-skills: name: Sync skills @@ -303,11 +302,13 @@ jobs: contents: read issues: write steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false - name: Generate token for skills repo id: skills-token - uses: actions/create-github-app-token@f8d387b68d61c58ab83c6c016672934102569859 # v2 + uses: actions/create-github-app-token@f8d387b68d61c58ab83c6c016672934102569859 # v3.0.0 with: app-id: ${{ vars.RELEASE_CLIENT_ID }} private-key: ${{ secrets.RELEASE_APP_PRIVATE_KEY }} diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index fc5a0dc4..151b868b 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -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 e2435d46..00068565 100644 --- a/.github/workflows/security.yml +++ b/.github/workflows/security.yml @@ -11,19 +11,19 @@ on: workflow_call: # Allow release.yml to invoke the full security suite 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 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 0 + persist-credentials: false - name: Install gitleaks run: | @@ -36,9 +36,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 + 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 @@ -52,7 +57,7 @@ jobs: output: 'trivy-results.sarif' - 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: @@ -61,12 +66,17 @@ 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 + 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' @@ -76,7 +86,7 @@ jobs: gosec -tags dev -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: @@ -89,23 +99,32 @@ jobs: runs-on: ubuntu-latest if: github.event_name == 'pull_request' continue-on-error: true # Requires GitHub Advanced Security (not available on all plans) + permissions: + contents: read 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 codeql: name: CodeQL Analysis runs-on: ubuntu-latest + permissions: + contents: read + security-events: write 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' - 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 @@ -117,14 +136,14 @@ jobs: run: go build -tags dev ./... - 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 e9736ae4..4cd94cef 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 a trusted 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 f50dd992..cee346bb 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -7,20 +7,23 @@ on: branches: [main] workflow_dispatch: -permissions: - contents: read +permissions: {} jobs: test: name: Tests runs-on: ubuntu-latest + permissions: + contents: read env: BASECAMP_NO_KEYRING: "1" 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' @@ -52,28 +55,55 @@ 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 - name: Set up Go - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6 + uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0 with: go-version-file: 'go.mod' - name: Run golangci-lint - uses: golangci/golangci-lint-action@1e7e51e771db61008b38414a730f564565cf7c20 # v9 + uses: golangci/golangci-lint-action@1e7e51e771db61008b38414a730f564565cf7c20 # v9.2.0 with: version: v2.11.1 args: --build-tags dev + 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: 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-file: 'go.mod' @@ -87,13 +117,17 @@ jobs: race-check: name: Race Detection runs-on: ubuntu-latest + permissions: + contents: read env: BASECAMP_NO_KEYRING: "1" 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' @@ -103,19 +137,23 @@ jobs: integration: name: Integration Tests runs-on: ubuntu-latest + permissions: + contents: read env: BASECAMP_NO_KEYRING: "1" 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' - 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 @@ -132,15 +170,18 @@ jobs: cli-surface: name: CLI Surface Check runs-on: ubuntu-latest + permissions: + contents: read env: BASECAMP_NO_KEYRING: "1" 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 with: go-version-file: 'go.mod' @@ -167,9 +208,13 @@ jobs: skill-eval: name: Skill Evals runs-on: ubuntu-latest + permissions: + contents: read if: github.event_name == 'pull_request' steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false - name: Check for skill or eval changes id: filter @@ -182,14 +227,14 @@ jobs: - name: Set up Ruby if: steps.filter.outputs.skill == 'true' - uses: ruby/setup-ruby@13e7a03dc3ac6c3798f4570bfead2aed4d96abfb # v1 + uses: ruby/setup-ruby@13e7a03dc3ac6c3798f4570bfead2aed4d96abfb # v1.244.0 with: ruby-version: '3.3' - name: Run skill evals if: steps.filter.outputs.skill == 'true' env: - ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} + ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} # zizmor: ignore[secrets-outside-env] -- fork PRs don't receive secrets so untrusted code never sees the key; adding an environment would block PR-triggered runs run: | if [ -z "$ANTHROPIC_API_KEY" ]; then echo "::warning::ANTHROPIC_API_KEY not configured, skipping skill evals" @@ -200,14 +245,17 @@ 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: BASECAMP_NO_KEYRING: "1" 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 @@ -224,7 +272,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' @@ -234,7 +282,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 }} @@ -248,10 +296,10 @@ jobs: - name: Compare benchmarks if: steps.filter.outputs.bench == 'true' && hashFiles('benchmarks-baseline.txt') != '' run: | - echo "## Benchmark Comparison" >> $GITHUB_STEP_SUMMARY - echo '```' >> $GITHUB_STEP_SUMMARY - benchstat benchmarks-baseline.txt benchmarks.txt >> $GITHUB_STEP_SUMMARY 2>&1 || true - echo '```' >> $GITHUB_STEP_SUMMARY + echo "## Benchmark Comparison" >> "$GITHUB_STEP_SUMMARY" + echo '```' >> "$GITHUB_STEP_SUMMARY" + benchstat benchmarks-baseline.txt benchmarks.txt >> "$GITHUB_STEP_SUMMARY" 2>&1 || true + echo '```' >> "$GITHUB_STEP_SUMMARY" - name: Check for significant regression if: steps.filter.outputs.bench == 'true' && hashFiles('benchmarks-baseline.txt') != '' @@ -268,7 +316,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 e85edd7d..ce8416c8 100644 --- a/Makefile +++ b/Makefile @@ -329,7 +329,15 @@ check-smoke-coverage: build # Run all checks (local CI gate) .PHONY: check -check: fmt-check vet lint test test-e2e check-naming check-surface check-skill-drift check-bare-groups check-smoke-coverage provenance-check tidy-check +check: fmt-check vet lint lint-actions test test-e2e check-naming check-surface check-skill-drift check-bare-groups check-smoke-coverage provenance-check tidy-check + +# Lint GitHub Actions workflows (requires actionlint + zizmor) +.PHONY: lint-actions +lint-actions: + @command -v actionlint >/dev/null || (echo "Install actionlint: make tools (or: go install github.com/rhysd/actionlint/cmd/actionlint@latest)" && exit 1) + @command -v zizmor >/dev/null || (echo "Install zizmor: https://docs.zizmor.sh/installation/" && exit 1) + actionlint + zizmor . # Full pre-flight for release: check + replace-check + vuln + race + surface compat .PHONY: release-check @@ -458,6 +466,14 @@ tools: $(GOCMD) install golang.org/x/perf/cmd/benchstat@latest $(GOCMD) install github.com/zricethezav/gitleaks/v8@latest @command -v jq >/dev/null 2>&1 || echo "NOTE: jq is also required (install via your package manager)" + @command -v actionlint >/dev/null 2>&1 || { echo "Installing actionlint..."; $(GOCMD) install github.com/rhysd/actionlint/cmd/actionlint@latest; } + @command -v zizmor >/dev/null 2>&1 || { \ + echo "Installing zizmor..."; \ + if command -v brew >/dev/null 2>&1; then brew install zizmor; \ + elif command -v pacman >/dev/null 2>&1; then sudo pacman -S --noconfirm zizmor; \ + else echo "Could not auto-install zizmor: https://docs.zizmor.sh/installation/" && exit 1; \ + fi; \ + } # Run skill evals (requires ANTHROPIC_API_KEY and Ruby) @@ -516,6 +532,7 @@ help: @echo " fmt Format code" @echo " fmt-check Check code formatting" @echo " lint Run golangci-lint" + @echo " lint-actions Lint GitHub Actions workflows (actionlint + zizmor)" @echo " tidy-check Verify go.mod/go.sum are tidy" @echo " check Run all checks (local CI gate)" @echo " check-surface Generate CLI surface snapshot (validates --help --agent output)" diff --git a/bin/setup b/bin/setup index c399912f..1b78d1b5 100755 --- a/bin/setup +++ b/bin/setup @@ -10,7 +10,7 @@ fi # Install Go via mise (reads .mise.toml) mise install -# Install dev tools (golangci-lint, govulncheck, etc.) +# Install dev tools (golangci-lint, govulncheck, actionlint, zizmor, etc.) make tools # Build and install the binary