feat: Sequencing workflows so that faster workflows run before slower ones#4670
feat: Sequencing workflows so that faster workflows run before slower ones#4670
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
📝 WalkthroughWalkthroughConverted multiple GitHub Actions workflows from push-triggered to reusable (workflow_call). Added a new CI workflow that triggers on push and orchestrates the reusable workflows with dependencies across linting, checks, builds, and integration tests, including an OIDC variant. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant Dev as Developer
participant GH as GitHub Actions (CI)
participant L as lint.yml
participant P as precommit.yml
participant C as codespell.yml
participant M as markdownlint.yml
participant LC as license-check.yml
participant BT as base-test.yml
participant B as build.yml
participant BNP as build-no-proxy.yml
participant IT as integration-test.yml
participant OIDC as oidc-integration-test.yml
Dev->>GH: push
GH->>L: uses (workflow_call)
GH->>P: uses (workflow_call)
GH->>C: uses (workflow_call)
GH->>M: uses (workflow_call)
GH->>LC: uses (workflow_call)
par After checks complete
GH->>BT: uses (needs: L,P,C,M,LC)
GH->>B: uses (needs: L,P,C,M,LC)
GH->>BNP: uses (needs: L,P,C,M,LC)
end
GH->>IT: uses (needs: BT,B,BNP)
GH->>OIDC: uses (needs: BT,B,BNP) with id-token: write
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~15 minutes Possibly related PRs
Suggested reviewers
Tip 🔌 Remote MCP (Model Context Protocol) integration is now available!Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats. ✨ Finishing Touches🧪 Generate unit tests
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
Status, Documentation and Community
|
There was a problem hiding this comment.
Actionable comments posted: 9
🔭 Outside diff range comments (11)
.github/workflows/lint.yml (2)
11-21: Pin all third-party actions to immutable commit SHAsTo eliminate floating tags and reduce supply-chain risk, replace every
@vXreference with the corresponding full commit SHA.In
.github/workflows/lint.yml:
- Line 11: uses: actions/checkout@v4
- Line 14: uses: jdx/mise-action@v2
- Lines 31, 37, 43: uses: actions/cache@v4
Suggested diff pattern:
- uses: actions/checkout@v4 + uses: actions/checkout@<commit-SHA_for_v4> - uses: jdx/mise-action@v2 + uses: jdx/mise-action@<commit-SHA_for_v2> - uses: actions/cache@v4 + uses: actions/cache@<commit-SHA_for_v4>You can look up the latest SHAs on each repo’s “Releases” or “Tags” page:
• https://github.com/actions/checkout/tags/v4
• https://github.com/actions/cache/tags/v4
• https://github.com/jdx/mise-action/tags/v2
22-46: Add a workflow input for the golangci-lint cache path and correct the output nameThe reusable workflow currently hard-codes the golangci-lint cache path and misspells the output key. To fix:
- Under
on.workflow_call, declare an optional input for the cache path with a sensible default.- In the
go-cache-pathsstep, rename “golanci-lint-cache” to “golangci-lint-cache” and emit the value from the new input.- Update the cache step to reference the corrected output name.
Suggested diff:
.github/workflows/lint.yml on: - workflow_call: + workflow_call: + inputs: + golangci_lint_cache_path: + description: Path to golangci-lint cache directory + required: false + default: /home/runner/.cache/golangci-lint jobs: lint: runs-on: ubuntu-latest steps: @@ - id: go-cache-paths run: | - # TODO: Make this less brittle. - echo "golanci-lint-cache=/home/runner/.cache/golangci-lint" >> "$GITHUB_OUTPUT" + # Cache path for golangci-lint (configurable via workflow input) + echo "golangci-lint-cache=${{ inputs.golangci_lint_cache_path }}" >> "$GITHUB_OUTPUT" @@ - name: golangci-lint Cache uses: actions/cache@v4 with: - path: ${{ steps.go-cache-paths.outputs.golanci-lint-cache }} + path: ${{ steps.go-cache-paths.outputs.golangci-lint-cache }} key: ${{ runner.os }}-golangci-lint-${{ hashFiles('**/go.sum') }}-linux-amd64
- Defines
golangci_lint_cache_pathunderworkflow_call.inputs- Fixes the typo from
golanci-lint-cache→golangci-lint-cache- Makes the cache path configurable to avoid brittle, hard-coded Linux home paths
.github/workflows/markdownlint.yml (2)
14-19: Broaden default globs and allow override via input.Currently only
docs/**/*.mdis linted; top-level README and other Markdown outside docs are skipped.- name: Run markdownlint uses: DavidAnson/markdownlint-cli2-action@v20 with: - globs: | - docs/**/*.md + globs: ${{ inputs.globs || '**/*.md' }}
11-15: Pin Actions to Immutable SHAs
To prevent unexpected breakages from tag updates, please replace the mutable tags with full commit SHAs in .github/workflows/markdownlint.yml (around lines 11–15):• Replace
uses: actions/checkout@v4 uses: DavidAnson/markdownlint-cli2-action@v20with something like
- uses: actions/checkout@v4 + uses: actions/checkout@<checkout-commit-sha> - uses: DavidAnson/markdownlint-cli2-action@v20 + uses: DavidAnson/markdownlint-cli2-action@<markdownlint-commit-sha>I can follow up with a PR that pins these to the exact SHAs.
.github/workflows/build.yml (1)
28-66: Pin Actions to Specific SHAs and Add Job TimeoutTo prevent accidental breakage from upstream updates and avoid indefinite hangs, pin each action to its full commit SHA and set a timeout for the build job.
• Pin the following actions:
– actions/checkout@v4 → 08eba0b27e820071cde6df949e0beb9ba4906955
– jdx/mise-action@v2 → c37c93293d6b742fc901e1406b8f764f6fb19dac
– actions/cache@v4 → 0400d5f644dc74513175e3cd8d07132dd4860809
– actions/upload-artifact@v4 → ea165f8d65b6e75b540449e92b4886f43607fa02• Add a 15-minute timeout to the build job.
Suggested patch (in .github/workflows/build.yml):
jobs: build: + timeout-minutes: 15 strategy: matrix: os: [linux, windows] arch: [amd64, arm64] steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 - name: Use mise to install dependencies - uses: jdx/mise-action@v2 + uses: jdx/mise-action@c37c93293d6b742fc901e1406b8f764f6fb19dac with: version: 2025.4.4 experimental: true - id: go-cache-paths run: | echo "go-build=$(go env GOCACHE)" >> "$GITHUB_OUTPUT" - name: Go Build Cache - uses: actions/cache@v4 + uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 with: path: ${{ steps.go-cache-paths.outputs.go-build }} key: ${{ runner.os }}-go-build-${{ hashFiles('**/go.sum') }}-${{ matrix.os }}-${{ matrix.arch }} - name: Upload Build Artifact - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 with: name: terragrunt_${{ matrix.os }}_${{ matrix.arch }}.github/workflows/integration-test.yml (3)
218-228: Avoid potential secret leakage; keep xtrace off or sanitize.You
sourcean env file that may contain secrets, then enableset -x(xtrace). While yourgo testcommand doesn’t expand secrets directly, xtrace sometimes leaks values if used in future changes or commands. Safer to avoid xtrace or to redact.- # print command arguments - set -x + # print command arguments minimally; avoid xtrace to prevent accidental secret leakage + set -o nounset -o errexit -o pipefailAlternatively, use a wrapper that filters sensitive env on print.
163-189: Restrict permissions on the generated.env.secretsfileVerified that
generate-secrets.shonly writes secrets into$ENV_FILEand the only stdout message is the benign status echo. However, it never tightens filesystem permissions, so the file may be world-readable by default.Please update .github/scripts/setup/generate-secrets.sh to set restrictive permissions (e.g. 0600) after writing the secrets:
echo "Created environment file with secrets for $NAME" +chmod 0600 "$ENV_FILE"This ensures no unintended users can read the secrets file.
151-171: Pin Actions to Commit SHAs and Add a Job TimeoutTo prevent unexpected breaking changes and ensure this long‐running job can’t hang indefinitely:
• Replace version tags with full commit SHAs for each referenced action in
.github/workflows/integration-test.yml
– Line 153:actions/checkout@v4→actions/checkout@<SHA>
– Line 165:jdx/mise-action@v2→jdx/mise-action@<SHA>
– Line 240:actions/upload-artifact@v4→actions/upload-artifact@<SHA>
– Line 246:mikepenz/action-junit-report@v5→mikepenz/action-junit-report@<SHA>• Add a sane
timeout-minutesat the job level (same indentation asruns-on) to guard against runaway integration tests. For example:jobs: integration-test: runs-on: ubuntu-latest timeout-minutes: 60 steps: …Let me know if you’d like me to stage a PR with the exact SHAs and timeout value.
.github/workflows/build-no-proxy.yml (1)
51-64: Ensure output directory exists; build currently risks failing with “no such file or directory”.go build -o doesn’t create parent directories. If bin/ doesn’t exist, the build will fail.
Apply:
- name: Build Terragrunt without Go proxy env: GOPROXY: direct GOOS: ${{ matrix.os }} GOARCH: ${{ matrix.arch }} run: | OUTPUT="bin/terragrunt-${GOOS}-${GOARCH}" if [ "${GOOS}" = "windows" ]; then OUTPUT="${OUTPUT}.exe" fi + mkdir -p "$(dirname "${OUTPUT}")" go build -o "${OUTPUT}" \ -ldflags "-X github.com/gruntwork-io/go-commons/version.Version=${GITHUB_REF_NAME} -extldflags '-static'" \ ..github/workflows/oidc-integration-test.yml (2)
38-44: Fix potential hang: docker builder prune missing --force.docker builder prune -a prompts for confirmation without -f, which can hang the job.
Apply:
sudo rm -rf /usr/share/dotnet /usr/local/lib/android /opt/ghc /opt/hostedtoolcache/CodeQL sudo docker image prune --all --force - sudo docker builder prune -a + sudo docker builder prune -a --force df -h
101-111: Make artifacts/report robust when tests are skipped.When SKIP=true, result.xml isn’t created. Uploading artifacts and generating the report may warn/fail. Make uploads conditional and ignore missing files; keep the summary display.
Apply:
- name: Upload Report (${{ matrix.integration.name }}) + if: always() uses: actions/upload-artifact@v4 with: name: test-report-${{ matrix.integration.name }} path: result.xml + if-no-files-found: ignore - name: Display Test Results (${{ matrix.integration.name }}) uses: mikepenz/action-junit-report@v5 if: always() with: report_paths: result.xml detailed_summary: 'true' include_time_in_summary: 'true' group_suite: 'true'Also applies to: 122-127, 128-136
🧹 Nitpick comments (11)
.github/workflows/lint.yml (1)
31-41: Improve cache key specificity across architectures.Keys end with a hard-coded
linux-amd64. Prefer${{ runner.arch }}to prevent cache mismatches and improve hit rates if GitHub changes runner arch.- key: ${{ runner.os }}-go-build-${{ hashFiles('**/go.sum') }}-linux-amd64 + key: ${{ runner.os }}-go-build-${{ hashFiles('**/go.sum') }}-${{ runner.arch }} @@ - key: ${{ runner.os }}-go-mod-${{ hashFiles('**/go.sum') }}-linux-amd64 + key: ${{ runner.os }}-go-mod-${{ hashFiles('**/go.sum') }}-${{ runner.arch }} @@ - key: ${{ runner.os }}-golangci-lint-${{ hashFiles('**/go.sum') }}-linux-amd64 + key: ${{ runner.os }}-golangci-lint-${{ hashFiles('**/go.sum') }}-${{ runner.arch }}.github/workflows/base-test.yml (2)
36-46: Cache key uses hard-coded arch; switch to runner.arch.On macOS, GitHub-hosted runners can be arm64. Using
-amd64reduces cache hit quality and can cause subtle issues.- key: ${{ runner.os }}-go-build-${{ hashFiles('**/go.sum') }}-${{ matrix.os }}-amd64 + key: ${{ runner.os }}-go-build-${{ hashFiles('**/go.sum') }}-${{ matrix.os }}-${{ runner.arch }} @@ - key: ${{ runner.os }}-go-mod-${{ hashFiles('**/go.sum') }}-${{ matrix.os }}-amd64 + key: ${{ runner.os }}-go-mod-${{ hashFiles('**/go.sum') }}-${{ matrix.os }}-${{ runner.arch }}
6-16: Consider adding job-level timeout for extra safety.You already set
-timeout 45mforgo test; also addtimeout-minutes: 60at the job level to prevent stuck runners..github/workflows/build.yml (2)
40-49: Improve cache keys to consider runner architecture.Avoid generic keys that could mismatch across runner architectures.
- key: ${{ runner.os }}-go-build-${{ hashFiles('**/go.sum') }}-${{ matrix.os }}-${{ matrix.arch }} + key: ${{ runner.os }}-go-build-${{ hashFiles('**/go.sum') }}-${{ matrix.os }}-${{ matrix.arch }}-${{ runner.arch }}
69-145: Mac signing job: pin actions, cache gon by checksum, and consider artifact retention.
- Pin
actions/checkout@v4,actions/download-artifact@v4,actions/upload-artifact@v4to SHAs.- Cache
gonusing its download URL checksum to avoid stale tool whenGON_VERSIONchanges without cache key update.- Optionally set
retention-dayson upload-artifact.Example changes (non-diff snippet):
- uses: actions/cache@v4 with: path: gon key: gon-${{ env.GON_VERSION }}-${{ hashFiles('.github/workflows/build.yml') }} - uses: actions/upload-artifact@v4 with: name: signed-files path: bin/* retention-days: 7.github/workflows/integration-test.yml (1)
207-217: Cache key uses hard-coded arch; prefer runner.arch.- key: ${{ runner.os }}-go-build-${{ hashFiles('**/go.sum') }}-${{ matrix.integration.os }}-amd64 + key: ${{ runner.os }}-go-build-${{ hashFiles('**/go.sum') }}-${{ matrix.integration.os }}-${{ runner.arch }}.github/workflows/precommit.yml (2)
36-43: Drop unnecessary pre-commit install to speed up CI.Installing git hooks in CI is redundant; running the hooks directly is sufficient.
Apply:
- name: Run pre-commit hooks env: GOPROXY: direct GOOS: linux GOARCH: amd64 run: | - pre-commit install pre-commit run --all-files
26-35: Optional: cache Go modules for faster hooks.If any hooks do go builds/tests, also caching GOMODCACHE (module download cache) can reduce runtime.
Example:
- id: go-cache-paths run: | echo "go-build=$(go env GOCACHE)" >> "$GITHUB_OUTPUT" + echo "go-mod=$(go env GOMODCACHE)" >> "$GITHUB_OUTPUT" - name: Go Build Cache uses: actions/cache@v4 with: - path: ${{ steps.go-cache-paths.outputs.go-build }} - key: ${{ runner.os }}-go-build-${{ hashFiles('**/go.sum') }}-linux-amd64 + path: | + ${{ steps.go-cache-paths.outputs.go-build }} + ${{ steps.go-cache-paths.outputs.go-mod }} + key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}-linux-amd64.github/workflows/codespell.yml (1)
15-21: Verify codespell compatibility with Python 3.13, or pin to a known-supported version.You’re pinning codespell==2.4.0 and using Python 3.13.3 via mise. Confirm that this codespell version supports Python 3.13. If not, either:
- Use Python 3.12.x, or
- Bump codespell to a version that supports 3.13, or
- Install with pipx.
I can check upstream compatibility if needed. Would you like me to run a quick web check?
Optional change (pin Python 3.12):
with: version: 2025.4.4 experimental: true mise_toml: | [tools] - python = "3.13.3" + python = "3.12.5"Also applies to: 23-31, 35-36
.github/workflows/build-no-proxy.yml (2)
51-56: Optional: consider CGO_ENABLED=0 for more reliable cross-compiles.Static and cross-compiles (darwin/windows/linux 386) can fail if CGO is inadvertently enabled. Setting CGO_ENABLED=0 improves portability.
- name: Build Terragrunt without Go proxy env: GOPROXY: direct GOOS: ${{ matrix.os }} GOARCH: ${{ matrix.arch }} + CGO_ENABLED: 0
41-49: Optional: also cache GOMODCACHE for faster dependency resolution.You’re caching only GOCACHE. Caching the module download cache can significantly speed up builds.
- id: go-cache-paths run: | echo "go-build=$(go env GOCACHE)" >> "$GITHUB_OUTPUT" + echo "go-mod=$(go env GOMODCACHE)" >> "$GITHUB_OUTPUT" - name: Go Build Cache uses: actions/cache@v4 with: - path: ${{ steps.go-cache-paths.outputs.go-build }} - key: ${{ runner.os }}-go-build-${{ hashFiles('**/go.sum') }}-${{ matrix.os }}-${{ matrix.arch }} + path: | + ${{ steps.go-cache-paths.outputs.go-build }} + ${{ steps.go-cache-paths.outputs.go-mod }} + key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}-${{ matrix.os }}-${{ matrix.arch }}
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these settings in your CodeRabbit configuration.
📒 Files selected for processing (11)
.github/workflows/base-test.yml(1 hunks).github/workflows/build-no-proxy.yml(1 hunks).github/workflows/build.yml(1 hunks).github/workflows/ci.yml(1 hunks).github/workflows/codespell.yml(1 hunks).github/workflows/integration-test.yml(1 hunks).github/workflows/license-check.yml(1 hunks).github/workflows/lint.yml(1 hunks).github/workflows/markdownlint.yml(1 hunks).github/workflows/oidc-integration-test.yml(1 hunks).github/workflows/precommit.yml(1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (11)
- GitHub Check: build / Sign Binaries
- GitHub Check: build_no_proxy / Build (windows/386)
- GitHub Check: build_no_proxy / Build (linux/386)
- GitHub Check: build_no_proxy / Build (darwin/arm64)
- GitHub Check: build_no_proxy / Build (windows/amd64)
- GitHub Check: build_no_proxy / Build (linux/arm64)
- GitHub Check: build_no_proxy / Build (linux/amd64)
- GitHub Check: build_no_proxy / Build (darwin/amd64)
- GitHub Check: base_tests / Test (ubuntu)
- GitHub Check: base_tests / Test (macos)
- GitHub Check: build-and-test
🔇 Additional comments (11)
.github/workflows/base-test.yml (1)
48-57: go-junit-report is already provisioned by the mise step
- The workflow’s “Use mise to install dependencies” step (lines 21–25 in
.github/workflows/base-test.yml) readsmise.cicd.toml.- In
mise.cicd.toml, you havego-junit-report = "2.1.0"configured, so go-junit-report will be installed before running tests.- No extra installation step is needed.
.github/workflows/precommit.yml (1)
3-5: Reusable workflow conversion looks good; ensure the orchestrator sequences and inherits secrets.Switching to workflow_call is correct for central orchestration. Please confirm the new CI orchestrator:
- Calls this workflow with needs to sequence fast jobs ahead of slow ones.
- Uses secrets: inherit so the GITHUB_TOKEN is available to mise and pre-commit.
I can auto-verify ci.yml usage if you share it.
.github/workflows/codespell.yml (1)
3-5: Reusable workflow conversion is correct; verify orchestrator invocation.Ensure the new CI invokes this via uses and includes secrets: inherit so GITHUB_TOKEN is available to mise.
.github/workflows/build-no-proxy.yml (1)
3-5: Confirm sequencing in the parent CI workflow.This job is a slow, multi-matrix build. Validate that the orchestrating workflow runs it only after faster checks (lint, pre-commit, codespell) pass via needs to achieve the PR objective.
.github/workflows/oidc-integration-test.yml (2)
7-9: Reusable workflow conversion is fine; ensure caller passes permissions and secrets.OIDC requires id-token: write and relevant cloud secrets. Verify the calling CI workflow:
- Grants permissions: id-token: write for the job that uses this reusable workflow.
- Uses secrets: inherit (or passes explicit secrets).
I can scan ci.yml automatically if you’d like.
46-54: Request: verify go-junit-report availability and PATH.The pipeline pipes go test output into go-junit-report, but there’s no explicit install here. Presumably mise sets it up. Please confirm mise.toml (or previous setup) ensures go-junit-report is installed and in PATH.
Also applies to: 90-100, 101-111
.github/workflows/license-check.yml (2)
3-5: Reusable workflow conversion LGTM; confirm orchestrator passes secrets.This job requires GITHUB_TOKEN for make license-check. Ensure the caller uses secrets: inherit.
25-33: Nice use of pipefail to preserve failure status.The make | tee pattern won’t mask failures due to set -o pipefail. Good attention to CI correctness.
.github/workflows/ci.yml (3)
7-26: Nice sequencing: fast checks gate slower stagesThe use of needs to gate base tests and builds on quick checks achieves the PR goal of sequencing and prevents wasteful long runs on failing quick checks.
Also applies to: 27-44
53-60: OIDC permission placement looks correct for local reusablesSetting id-token: write at the caller job level is the right way to enable OIDC in a locally reused workflow. No change needed.
1-63: Heads-up: Required status check contexts have changed
Moving all jobs under the single “CI” workflow will rename your status checks from, for example,
• “lint” → “CI / lint”
• “build” → “CI / build”
• “integration_tests” → “CI / integration_tests”If you have branch protection rules that enforce required status checks on
main(or any protected branch), you will need to update those contexts or merges will be blocked.Action items:
- In your repo’s Settings → Branches → Branch protection, edit the rule for your protected branch.
- Under Require status checks to pass before merging, remove the old names and add the new contexts (e.g., “CI / lint”, “CI / build”, “CI / integration_tests”, etc.).
- Save your changes and confirm that all new checks are passing.
| on: | ||
| push: | ||
| workflow_call: | ||
|
|
There was a problem hiding this comment.
🛠️ Refactor suggestion
Reusable workflow conversion looks good; declare inputs and permissions.
Define inputs (e.g., OS matrix override, test timeout) and least-privilege permissions. This formalizes the contract and improves security.
on:
- workflow_call:
+ workflow_call:
+ inputs:
+ os:
+ description: 'Space-separated OS list (e.g., "ubuntu macos")'
+ required: false
+ type: string
+ timeout_minutes:
+ description: 'go test timeout in minutes'
+ required: false
+ type: number
+ secrets: {}Then add (outside selected range):
permissions:
contents: read🤖 Prompt for AI Agents
In .github/workflows/base-test.yml around lines 3 to 5, the reusable workflow is
missing declared inputs and least-privilege permissions; add a workflow_call
inputs block (for example inputs like os_matrix_override, test_timeout,
node_version or others your consumers need) directly under workflow_call to
formalize the contract, and add a top-level permissions block (e.g.,
permissions: contents: read) at the file root to enforce least-privilege access;
ensure input names, types and defaults are reasonable and documented in the file
so callers can override them.
| on: | ||
| push: | ||
| workflow_call: | ||
|
|
There was a problem hiding this comment.
🛠️ Refactor suggestion
Reusable conversion approved; expose inputs for matrix control and set permissions.
Allow the orchestrator to pass a subset of OS/arch to shorten slow builds when not needed.
on:
- workflow_call:
+ workflow_call:
+ inputs:
+ matrix_include:
+ description: 'YAML/JSON list for matrix.include (os/arch pairs)'
+ required: false
+ type: string
+ secrets: {}Then, adapt the matrix to read from input when provided (outside the selected range):
strategy:
matrix:
include: ${{ inputs.matrix_include && fromJSON(inputs.matrix_include) || matrix.include }}Also add:
permissions:
contents: read🤖 Prompt for AI Agents
In .github/workflows/build.yml around lines 3 to 5, the reusable workflow does
not expose inputs for controlling the OS/arch matrix nor set repository
permissions; add inputs for matrix control (e.g., matrix_include as a string)
under workflow_call so the orchestrator can pass a JSON subset, then update the
job strategy matrix to prefer the input when present (use the conditional:
include: ${{ inputs.matrix_include && fromJSON(inputs.matrix_include) ||
matrix.include }}), and add permissions: contents: read at the top-level of the
workflow so the reusable workflow has read access to repository contents.
| on: | ||
| push: | ||
|
|
||
| jobs: |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Add pull_request + workflow_dispatch triggers, default least-privilege permissions, and cancel-in-progress concurrency
This centralizes CI while ensuring PRs run, manual runs are possible, and redundant in-flight runs are canceled on new pushes to the same ref. Also sets minimal default GITHUB_TOKEN permissions.
Apply:
name: CI
-on:
- push:
+on:
+ push:
+ pull_request:
+ workflow_dispatch:
+
+permissions:
+ contents: read
+
+concurrency:
+ group: ci-${{ github.workflow }}-${{ github.ref }}
+ cancel-in-progress: true🤖 Prompt for AI Agents
In .github/workflows/ci.yml around lines 3-6, the workflow only triggers on push
and lacks least-privilege default permissions and concurrency control; update
the top-level YAML to include on: push, pull_request, and workflow_dispatch
triggers, add a minimal default permissions block (for example permissions:
contents: read, packages: read — adjust if your jobs need more), and add a
concurrency block (group: ${{ github.workflow }}-${{ github.ref }},
cancel-in-progress: true) so manual runs are possible, PRs trigger CI, runs use
least privilege, and in-flight runs for the same ref are cancelled.
| lint: | ||
| uses: ./.github/workflows/lint.yml | ||
| secrets: inherit | ||
|
|
||
| precommit: | ||
| uses: ./.github/workflows/precommit.yml | ||
| secrets: inherit | ||
|
|
||
| codespell: | ||
| uses: ./.github/workflows/codespell.yml | ||
| secrets: inherit | ||
|
|
||
| markdownlint: | ||
| uses: ./.github/workflows/markdownlint.yml | ||
| secrets: inherit | ||
|
|
||
| license_check: | ||
| uses: ./.github/workflows/license-check.yml | ||
| secrets: inherit | ||
|
|
There was a problem hiding this comment.
💡 Verification agent
🧩 Analysis chain
Verify all referenced reusable workflows are switched to workflow_call and inputs/secrets match
Given the conversion, ensure each callee has on: workflow_call and that any required inputs match (none provided here). This avoids silent dispatch failures.
Also applies to: 27-44, 45-60
🏁 Script executed:
#!/bin/bash
set -euo pipefail
files=(
".github/workflows/lint.yml"
".github/workflows/precommit.yml"
".github/workflows/codespell.yml"
".github/workflows/markdownlint.yml"
".github/workflows/license-check.yml"
".github/workflows/base-test.yml"
".github/workflows/build.yml"
".github/workflows/build-no-proxy.yml"
".github/workflows/integration-test.yml"
".github/workflows/oidc-integration-test.yml"
)
echo "Checking reusable workflow configuration..."
for f in "${files[@]}"; do
if [[ ! -f "$f" ]]; then
echo "MISSING: $f"
continue
fi
echo "---- $f"
rg -n "^\s*on:\s*workflow_call" "$f" || echo "WARNING: $f is not configured with on: workflow_call"
echo "Declared inputs (if any):"
rg -n "^\s*inputs:" -n "$f" -A 50 | sed '/^\s*outputs:/,$d' || true
echo
done
echo "If any workflow declares required inputs, add a with: { ... } block to the corresponding job in ci.yml."Length of output: 6429
Add on: workflow_call to all referenced reusable workflows
All of the workflows invoked from ci.yml currently lack a workflow_call trigger. To ensure they can be dispatched without silent failures, each of the following files must begin with:
on:
workflow_call:
# define inputs here if the workflow requires any• .github/workflows/lint.yml
• .github/workflows/precommit.yml
• .github/workflows/codespell.yml
• .github/workflows/markdownlint.yml
• .github/workflows/license-check.yml
• .github/workflows/base-test.yml
• .github/workflows/build.yml
• .github/workflows/build-no-proxy.yml
• .github/workflows/integration-test.yml
• .github/workflows/oidc-integration-test.yml
Since none of these declare required inputs, no with: blocks are currently needed in ci.yml. If you later add inputs to any reusable workflow, remember to pass them in the corresponding job’s with: section.
| integration_tests: | ||
| needs: [base_tests, build, build_no_proxy] | ||
| uses: ./.github/workflows/integration-test.yml | ||
| permissions: | ||
| contents: read | ||
| checks: write | ||
| secrets: inherit | ||
|
|
There was a problem hiding this comment.
💡 Verification agent
❓ Verification inconclusive
Guard integration tests on forked PRs and set a timeout
Secrets are not available to workflows on pull_request from forks. Guard to skip instead of fail, and add a sensible timeout to avoid hung runs.
integration_tests:
needs: [base_tests, build, build_no_proxy]
+ if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false }}
uses: ./.github/workflows/integration-test.yml
permissions:
contents: read
checks: write
+ timeout-minutes: 90
secrets: inheritIf your integration tests are expected to run on forked PRs (without secrets), reply and I can propose a paths-filter + conditional to only run a non-secret subset. Otherwise, verify the skip behavior matches expectations.
Guard integration tests on forked PRs and add a timeout
Integration tests rely on inherited secrets, which are not available for workflows triggered by pull_request from forked repos—causing failures. Skip the job for forked PRs and set a sensible timeout to prevent hung runs:
• File: .github/workflows/ci.yml (lines 45–52)
• Replace with:
integration_tests:
needs: [base_tests, build, build_no_proxy]
+ if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false }}
uses: ./.github/workflows/integration-test.yml
permissions:
contents: read
checks: write
+ timeout-minutes: 90
secrets: inheritIf you still need to run a subset of integration tests on forked PRs (without secrets), let me know and I can suggest a conditional paths filter. Otherwise, please apply this guard to avoid broken or hung CI runs.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| integration_tests: | |
| needs: [base_tests, build, build_no_proxy] | |
| uses: ./.github/workflows/integration-test.yml | |
| permissions: | |
| contents: read | |
| checks: write | |
| secrets: inherit | |
| integration_tests: | |
| needs: [base_tests, build, build_no_proxy] | |
| if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false }} | |
| uses: ./.github/workflows/integration-test.yml | |
| permissions: | |
| contents: read | |
| checks: write | |
| timeout-minutes: 90 | |
| secrets: inherit |
🤖 Prompt for AI Agents
In .github/workflows/ci.yml around lines 45 to 52, the integration_tests job
must be skipped for pull requests from forked repos and have a timeout to avoid
hanging; add an if condition to only run when the event is not a pull_request or
the pull_request head repo matches the current repository (use: if:
github.event.pull_request == null ||
github.event.pull_request.head.repo.full_name == github.repository) and add a
timeout-minutes value (e.g., timeout-minutes: 60) under the job definition so
the workflow exits after a sensible period.
| oidc_integration_tests: | ||
| needs: [base_tests, build, build_no_proxy] | ||
| uses: ./.github/workflows/oidc-integration-test.yml | ||
| permissions: | ||
| id-token: write | ||
| contents: read | ||
| checks: write | ||
| secrets: inherit |
There was a problem hiding this comment.
💡 Verification agent
🧩 Analysis chain
Guard OIDC integration tests on forked PRs and set a timeout
Same motivation as the non-OIDC integration suite. Keeps forks green without exposing secrets and avoids hangs.
oidc_integration_tests:
needs: [base_tests, build, build_no_proxy]
+ if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false }}
uses: ./.github/workflows/oidc-integration-test.yml
permissions:
id-token: write
contents: read
checks: write
+ timeout-minutes: 90
secrets: inherit🏁 Script executed:
#!/bin/bash
set -e
echo "Searching in ci.yml for non-OIDC integration_tests job"
rg -n "integration_tests:" .github/workflows/ci.yml || true
echo
echo "Searching for timeout-minutes usage across all workflow files"
rg -n "timeout-minutes" .github/workflows || trueLength of output: 422
🏁 Script executed:
#!/bin/bash
set -e
echo "Showing lines around the non-OIDC integration_tests job for context"
rg -n -C5 "integration_tests:" .github/workflows/ci.ymlLength of output: 812
Guard OIDC integration tests on forked PRs and set a timeout
Same motivation as the non-OIDC integration suite: keeps forks green without exposing secrets and prevents hung jobs.
• File: .github/workflows/ci.yml
Job: oidc_integration_tests (lines 53–60)
Suggested diff:
oidc_integration_tests:
needs: [base_tests, build, build_no_proxy]
+ if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false }}
uses: ./.github/workflows/oidc-integration-test.yml
permissions:
id-token: write
contents: read
checks: write
+ timeout-minutes: 90
secrets: inheritThis will skip OIDC tests on forked PRs and fail any run exceeding 90 minutes.
🤖 Prompt for AI Agents
In .github/workflows/ci.yml around lines 53 to 60, the oidc_integration_tests
job must be skipped for forked PRs and bounded to 90 minutes; update the job to
include an if guard that only runs when not a pull_request from a fork (for
example: github.event_name != 'pull_request' ||
github.event.pull_request.head.repo.full_name == github.repository) and add
timeout-minutes: 90 to the job definition so any run longer than 90 minutes will
fail.
| on: | ||
| push: | ||
| workflow_call: | ||
|
|
There was a problem hiding this comment.
🛠️ Refactor suggestion
Reusable conversion looks good; explicitly declare required secrets and inputs.
This workflow consumes many secrets via the setup and test steps. Make the requirements explicit to prevent accidental silent failures at call time and to document contract.
on:
- workflow_call:
+ workflow_call:
+ inputs:
+ include_matrix:
+ description: 'Subset of integrations to run (JSON/YAML list of matrix entries)'
+ required: false
+ type: string
+ secrets:
+ GHA_DEPLOY_KEY:
+ required: false
+ AWS_ACCESS_KEY_ID:
+ required: false
+ AWS_SECRET_ACCESS_KEY:
+ required: false
+ AWS_TEST_OIDC_ROLE_ARN:
+ required: false
+ GCLOUD_SERVICE_KEY:
+ required: false
+ GOOGLE_CLOUD_PROJECT:
+ required: false
+ GOOGLE_COMPUTE_ZONE:
+ required: false
+ GOOGLE_IDENTITY_EMAIL:
+ required: false
+ GOOGLE_PROJECT_ID:
+ required: false
+ GCLOUD_SERVICE_KEY_IMPERSONATOR:
+ required: false
+ AWS_TEST_S3_ASSUME_ROLE:
+ required: falseAdd least-privilege permissions (outside selected range). If any test uses OIDC, add id-token: write for that job only:
permissions:
contents: read
# id-token: write # enable only if OIDC tests are run in this workflow🤖 Prompt for AI Agents
In .github/workflows/integration-test.yml around lines 3 to 5, the reusable
workflow does not explicitly declare the required inputs/secrets or
least-privilege permissions, which can lead to silent failures when called;
update the workflow metadata to add an inputs and secrets section enumerating
every secret and required input the steps use (with descriptions and required:
true where applicable) and add a permissions block granting only needed scopes
(for example contents: read) and document/comment that id-token: write should be
added only for the job that uses OIDC; ensure the inputs/secrets names match
callers and update README/docs if needed.
| on: | ||
| push: | ||
| workflow_call: | ||
|
|
There was a problem hiding this comment.
💡 Verification agent
🧩 Analysis chain
Good conversion to a reusable workflow; consider formalizing inputs/secrets and least-privilege permissions.
Switching to workflow_call is correct. To make this reusable workflow more robust and self-documenting, define explicit inputs/secrets and set minimal permissions. This clarifies the contract for callers and tightens security.
Apply this diff to expand workflow_call with optional inputs (example) and declare no required secrets for now:
on:
- workflow_call:
+ workflow_call:
+ inputs:
+ go_version:
+ description: 'Go toolchain version (mise will resolve)'
+ required: false
+ type: string
+ golangci_lint_cache_path:
+ description: 'Path to golangci-lint cache on runner'
+ required: false
+ type: string
+ secrets: {}Then set least-privilege permissions at the workflow level (outside the selected range; add near the top-level keys):
permissions:
contents: readIf you want, I can propagate the same pattern to all reusable workflows in this PR and wire inputs from the new orchestrator.
🏁 Script executed:
#!/bin/bash
# Inspect the presence and context of workflow_call, inputs, secrets, and permissions in lint.yml
echo "---- snippet around workflow_call ----"
rg -n "workflow_call" -A5 -B5 .github/workflows/lint.yml || true
echo -e "\n---- top of lint.yml (first 20 lines) ----"
sed -n '1,20p' .github/workflows/lint.ymlLength of output: 764
Formalize reusable workflow inputs/secrets and enforce least-privilege permissions
This workflow currently exposes workflow_call without any declared inputs, secrets, or explicit permissions. Defining them makes the contract clearer for callers and tightens security.
• File: .github/workflows/lint.yml
• Location: around lines 3–5 (the on: workflow_call: block)
• Also add a top-level permissions section (immediately under name:)
Suggested changes:
name: Lint
+
+permissions:
+ contents: read
on:
workflow_call:
+ inputs:
+ go_version:
+ description: 'Go toolchain version (mise will resolve)'
+ required: false
+ type: string
+ golangci_lint_cache_path:
+ description: 'Path to golangci-lint cache on runner'
+ required: false
+ type: string
+ secrets: {}
jobs:
lint:
runs-on: ubuntu-latest📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| on: | |
| push: | |
| workflow_call: | |
| name: Lint | |
| permissions: | |
| contents: read | |
| on: | |
| workflow_call: | |
| inputs: | |
| go_version: | |
| description: 'Go toolchain version (mise will resolve)' | |
| required: false | |
| type: string | |
| golangci_lint_cache_path: | |
| description: 'Path to golangci-lint cache on runner' | |
| required: false | |
| type: string | |
| secrets: {} | |
| jobs: | |
| lint: | |
| runs-on: ubuntu-latest |
🤖 Prompt for AI Agents
.github/workflows/lint.yml around lines 3 to 5: the workflow_call trigger is
declared with no explicit inputs, secrets or permissions; update the on:
workflow_call block to declare named inputs and any required secrets (with types
and required: true/false) that callers must provide, and add a top-level
permissions section immediately under the name: key that grants only the minimal
rights needed (for example set contents: read, actions: read, pull-requests:
write or as appropriate), ensuring each permission is the least-privilege
option; also document default values and required flags for inputs so callers
have a clear contract.
| on: | ||
| push: | ||
| workflow_call: | ||
|
|
There was a problem hiding this comment.
🛠️ Refactor suggestion
Reusable workflow conversion is fine; add inputs and restrict permissions.
Let callers customize globs and keep permissions minimal.
on:
- workflow_call:
+ workflow_call:
+ inputs:
+ globs:
+ description: 'Markdown file globs to lint (newline separated)'
+ required: false
+ type: string
+ secrets: {}Add (outside selected range):
permissions:
contents: read🤖 Prompt for AI Agents
In .github/workflows/markdownlint.yml around lines 3 to 5, the reusable workflow
currently only declares workflow_call; update it to accept configurable glob
inputs and restrict permissions: add a workflow_call.inputs block exposing at
least a globs input (string or array) with a sensible default so callers can
customize file globs, and add a top-level permissions block (outside the shown
lines) setting contents: read to minimize token scope. Ensure inputs are
documented in the workflow and referenced where the lint job reads file
patterns.
Description
Sequences workflows so that we're not running slow workflows if we have to push again anyways.
TODOs
Read the Gruntwork contribution guidelines.
Release Notes (draft)
Added / Removed / Updated [X].
Migration Guide
Summary by CodeRabbit