feat(ci): automate Go toolchain version updates via govulncheck failures#3267
feat(ci): automate Go toolchain version updates via govulncheck failures#3267dmihalcik-virtru wants to merge 4 commits intomainfrom
Conversation
Adds a workflow that detects govulncheck failures on main and release/** branches and automatically opens a PR bumping the Go toolchain to the latest supported patch (or latest minor if the current one is EOL). - `.github/scripts/bump-go-version.sh`: standalone script that updates the `toolchain` directive in `go.work` and all `go.mod` files, and syncs the hardcoded Go version in `checks.yaml` and `sonarcloud.yml`. Supports `--dry-run` (prints unified diff, no file changes), `--target` (skip API lookup), and `--api-url` (mock for tests). - `.github/scripts/bump-go-version.bats`: 9 BATS unit tests covering patch bumps, minor-version bumps, EOL detection, dry-run mode, and already-at-latest no-op behaviour. - `.github/scripts/fixtures/go-versions.json`: mock go.dev API response for offline test runs. - `.github/workflows/go-version-update.yaml`: automation workflow (workflow_dispatch + weekly schedule) that calls the script and creates/updates a PR as `opentdf-automation[bot]` with the `autobump` label. - `.github/workflows/checks.yaml`: adds `trigger-go-version-update` job (dispatches the update workflow when govulncheck artifacts are found on push to main/release/**) and `script-tests` job (runs the BATS tests; added to the `ci` gate). - `.policy.yml`: extends the `autobump` rule's branch pattern to also match `chore/bump-go-toolchain(-...)?` so bot PRs auto-merge on CI pass. - `AGENTS.md`: documents that Go toolchain bumps should go through this automation rather than being done by hand in feature PRs. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Signed-off-by: Dave Mihalcik <dmihalcik@virtru.com>
📝 WalkthroughWalkthroughAdds an automated Go toolchain bump flow: a new Bash script to update Changes
Sequence DiagramsequenceDiagram
participant Scheduler as "GitHub Actions (scheduler/dispatch)"
participant Workflow as "go-version-update.yaml"
participant API as "go.dev download API"
participant Script as "bump-go-version.sh"
participant Repo as "Repository files (go.work, go.mod, workflows)"
participant PR as "Pull Request"
Scheduler->>Workflow: trigger (cron or workflow_dispatch)
Workflow->>API: GET release JSON
API-->>Workflow: release list
Workflow->>Repo: read current toolchain from go.work
Workflow->>Script: run (--target or resolved version)
Script->>Repo: update go.work toolchain and optional go directive
Script->>Repo: run go mod edit on module go.mod files
Script->>Repo: update CI workflow YAMLs
Script-->>Workflow: report diffs/changes
Workflow->>Repo: commit changes on bump branch
Workflow->>PR: create or update PR with changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Summary of ChangesHello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request implements an automated lifecycle management system for the Go toolchain version across the monorepo. By integrating with govulncheck, the system proactively identifies when the project's Go version falls behind or becomes EOL, triggering an automated process to update the necessary configuration files. This reduces manual maintenance overhead and ensures the project remains on supported, secure toolchain versions. Highlights
🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console. Ignored Files
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here. The toolchain drifts as time goes by, We watch the govulncheck go dry. A script awakes to set it right, And keeps our builds both clean and bright. Footnotes
|
There was a problem hiding this comment.
Pull request overview
Adds CI automation to detect govulncheck failures on protected branches and automatically open/update a PR that bumps the repo’s pinned Go toolchain version consistently across workspace/modules and CI workflows.
Changes:
- Introduces a
go-version-updateworkflow (scheduled + dispatchable) that bumps Go toolchain versions and opens/updates anautobumpPR. - Adds a repo-wide
bump-go-version.shscript (with BATS unit tests + fixtures) to updatego.work, allgo.modfiles, and relevant workflow pins. - Extends CI (
checks.yaml) to trigger the updater on govulncheck failure artifacts and to run script unit tests; updates policy/docs to reflect the new process.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
AGENTS.md |
Documents the new Go toolchain bump process and discourages manual edits in feature PRs. |
.policy.yml |
Expands autobump branch pattern to include the new go-toolchain bump branches for auto-merge. |
.github/workflows/go-version-update.yaml |
New workflow to compute latest Go version and create/update an automation PR. |
.github/workflows/checks.yaml |
Adds a dispatcher job for go-version-update on govulncheck failures and a BATS script test job wired into the CI gate. |
.github/scripts/fixtures/go-versions.json |
Provides a mock go.dev API response for offline/unit testing. |
.github/scripts/bump-go-version.sh |
New script to bump toolchain/go directives across workspace/modules and sync workflow hardcoded versions. |
.github/scripts/bump-go-version.bats |
Adds unit tests covering patch/minor bumps, EOL detection, dry-run behavior, and no-op exits. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
.github/scripts/bump-go-version.sh
Outdated
| while [[ $# -gt 0 ]]; do | ||
| case "$1" in | ||
| --dry-run) DRY_RUN=true ;; | ||
| --target) TARGET_VERSION="$2"; shift ;; | ||
| --repo-root) REPO_ROOT="$2"; shift ;; | ||
| --api-url) API_URL="$2"; shift ;; |
There was a problem hiding this comment.
Option parsing assumes a value exists for flags like --target/--repo-root/--api-url (e.g., TARGET_VERSION="$2") while set -u is enabled. Calling the script with a missing value will crash with an unbound-variable error rather than producing a clear usage message. Add an explicit check that $# -ge 2 (or that $2 is set) for these options and fail with a helpful error + usage output.
| while [[ $# -gt 0 ]]; do | |
| case "$1" in | |
| --dry-run) DRY_RUN=true ;; | |
| --target) TARGET_VERSION="$2"; shift ;; | |
| --repo-root) REPO_ROOT="$2"; shift ;; | |
| --api-url) API_URL="$2"; shift ;; | |
| missing_option_value() { | |
| echo "[ERROR] Missing value for option: $1" >&2 | |
| usage | |
| exit 1 | |
| } | |
| while [[ $# -gt 0 ]]; do | |
| case "$1" in | |
| --dry-run) DRY_RUN=true ;; | |
| --target) | |
| [[ $# -ge 2 ]] || missing_option_value "$1" | |
| TARGET_VERSION="$2" | |
| shift | |
| ;; | |
| --repo-root) | |
| [[ $# -ge 2 ]] || missing_option_value "$1" | |
| REPO_ROOT="$2" | |
| shift | |
| ;; | |
| --api-url) | |
| [[ $# -ge 2 ]] || missing_option_value "$1" | |
| API_URL="$2" | |
| shift | |
| ;; |
.github/scripts/bump-go-version.sh
Outdated
| # Extract all distinct minor versions from stable releases, sorted ascending. | ||
| ALL_MINORS="$( | ||
| echo "$VERSIONS_JSON" \ | ||
| | jq -r '[ | ||
| .[].version | ||
| | ltrimstr("go") | ||
| | split(".") | ||
| | .[0:2] | ||
| | join(".") | ||
| ] | unique | sort_by(split(".") | map(tonumber)) | .[]' | ||
| )" | ||
|
|
||
| LATEST_MINOR="$(echo "$ALL_MINORS" | tail -1)" | ||
| PREV_MINOR="$(echo "$ALL_MINORS" | tail -2 | head -1)" | ||
|
|
||
| NEEDS_MINOR_BUMP=false | ||
| if [[ "$CURRENT_MINOR" != "$LATEST_MINOR" && "$CURRENT_MINOR" != "$PREV_MINOR" ]]; then | ||
| log "Go ${CURRENT_MINOR} is no longer in the two most-recent supported minors" \ | ||
| "(${PREV_MINOR}, ${LATEST_MINOR}); upgrading minor version." | ||
| TARGET_MINOR="$LATEST_MINOR" | ||
| NEEDS_MINOR_BUMP=true | ||
| else | ||
| TARGET_MINOR="$CURRENT_MINOR" | ||
| fi | ||
|
|
||
| # Latest patch release for the target minor. | ||
| LATEST_PATCH="$( | ||
| echo "$VERSIONS_JSON" \ | ||
| | jq -r --arg prefix "go${TARGET_MINOR}." \ | ||
| '[.[].version | select(startswith($prefix))] | first | ltrimstr("go")' | ||
| )" |
There was a problem hiding this comment.
The go.dev download JSON includes entries where stable is false (betas/RCs). This jq query doesn’t filter on .stable == true, so the script can accidentally select a prerelease as the "latest" patch/minor. Filter to stable releases and ensure the patch selection picks the highest patch for the target minor (don’t rely on API ordering + first).
.github/scripts/bump-go-version.sh
Outdated
| diff -u "$orig" "$modified" \ | ||
| --label "a/${rel}" \ | ||
| --label "b/${rel}" \ |
There was a problem hiding this comment.
diff --label is a GNU diff option and will fail on macOS/BSD diff, which makes --dry-run non-portable. Use BSD-compatible flags (e.g., diff -u -L a/... -L b/...) or omit labels so the dry-run works on both Linux and macOS as the script intends.
| diff -u "$orig" "$modified" \ | |
| --label "a/${rel}" \ | |
| --label "b/${rel}" \ | |
| diff -u \ | |
| -L "a/${rel}" \ | |
| -L "b/${rel}" \ | |
| "$orig" "$modified" \ |
| VERSIONS_JSON=$(curl -sf "https://go.dev/dl/?mode=json") | ||
|
|
||
| # Current toolchain from go.work (e.g. "1.25.8") | ||
| CURRENT=$(grep "^toolchain " go.work | sed 's/toolchain go//') | ||
| CURRENT_MINOR=$(echo "$CURRENT" | cut -d. -f1,2) | ||
|
|
||
| # All distinct minor versions in stable releases, sorted ascending. | ||
| ALL_MINORS=$( | ||
| echo "$VERSIONS_JSON" \ | ||
| | jq -r '[ | ||
| .[].version | ||
| | ltrimstr("go") | ||
| | split(".") | ||
| | .[0:2] | ||
| | join(".") | ||
| ] | unique | sort_by(split(".") | map(tonumber)) | .[]' | ||
| ) | ||
|
|
||
| LATEST_MINOR=$(echo "$ALL_MINORS" | tail -1) | ||
| PREV_MINOR=$(echo "$ALL_MINORS" | tail -2 | head -1) | ||
|
|
||
| TARGET_MINOR="$CURRENT_MINOR" | ||
| if [[ "$CURRENT_MINOR" != "$LATEST_MINOR" && "$CURRENT_MINOR" != "$PREV_MINOR" ]]; then | ||
| echo "Go ${CURRENT_MINOR} is EOL; upgrading to ${LATEST_MINOR}" | ||
| TARGET_MINOR="$LATEST_MINOR" | ||
| fi | ||
|
|
||
| LATEST_PATCH=$( | ||
| echo "$VERSIONS_JSON" \ | ||
| | jq -r --arg prefix "go${TARGET_MINOR}." \ | ||
| '[.[].version | select(startswith($prefix))] | first | ltrimstr("go")' | ||
| ) |
There was a problem hiding this comment.
The go.dev JSON feed contains non-stable releases (betas/RCs). The jq queries here don’t filter on stable == true, so this workflow can bump to a prerelease toolchain and open an automation PR that breaks CI. Filter to stable releases and make the patch selection compute the max patch for TARGET_MINOR rather than relying on API ordering + first.
Benchmark results, click to expandBenchmark authorization.GetDecisions Results:
Benchmark authorization.v2.GetMultiResourceDecision Results:
Benchmark Statistics
Bulk Benchmark Results
TDF3 Benchmark Results:
|
There was a problem hiding this comment.
Code Review
This pull request introduces an automated script (bump-go-version.sh) and its corresponding unit tests (bump-go-version.bats) to manage Go toolchain versions across the monorepo. The script updates go.work, go.mod files, and GitHub Actions workflows, supporting both patch and minor version bumps, including EOL minor version upgrades. Documentation (AGENTS.md) and policy (.policy.yml) are updated to reflect this automation. Feedback suggests improving the script's robustness by dynamically discovering Go modules instead of using a hardcoded list, adding timeouts to the curl command for API calls to prevent hanging, and making the jq filter for selecting the latest patch version more resilient to potential API response sorting changes.
| MODULE_DIRS=( | ||
| examples | ||
| sdk | ||
| service | ||
| lib/fixtures | ||
| lib/flattening | ||
| lib/identifier | ||
| lib/ocrypto | ||
| protocol/go | ||
| tests-bdd | ||
| test/integration | ||
| ) |
There was a problem hiding this comment.
The list of module directories is hardcoded, which creates a maintenance burden. Any new module added to the repository in the future will be skipped by this automation unless this script is manually updated. Consider dynamically discovering all subdirectories that contain a go.mod file to ensure the toolchain remains consistent across the entire monorepo.
.github/scripts/bump-go-version.sh
Outdated
| fi | ||
| else | ||
| log "Fetching Go release list from ${API_URL}" | ||
| VERSIONS_JSON="$(curl -sf "$API_URL")" |
There was a problem hiding this comment.
The curl command is missing a timeout. In a CI/CD environment, network issues or an unresponsive API could cause the workflow to hang indefinitely. It is recommended to add --connect-timeout and --max-time to ensure the script fails gracefully.
| VERSIONS_JSON="$(curl -sf "$API_URL")" | |
| VERSIONS_JSON="$(curl -sf --connect-timeout 5 --max-time 10 "$API_URL")" |
.github/scripts/bump-go-version.sh
Outdated
| LATEST_PATCH="$( | ||
| echo "$VERSIONS_JSON" \ | ||
| | jq -r --arg prefix "go${TARGET_MINOR}." \ | ||
| '[.[].version | select(startswith($prefix))] | first | ltrimstr("go")' |
There was a problem hiding this comment.
The jq filter uses first to select the latest patch version, which assumes the API response is always sorted in descending order. While this is currently true for the Go release API, explicitly sorting the versions numerically (e.g., ensuring 1.25.10 is recognized as newer than 1.25.9) makes the script more robust against potential changes in the API's response format.
| '[.[].version | select(startswith($prefix))] | first | ltrimstr("go")' | |
| '[.[].version | select(startswith($prefix))] | sort_by(ltrimstr("go") | split(".") | map(tonumber)) | last | ltrimstr("go")' |
There was a problem hiding this comment.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
.policy.yml (1)
98-107:⚠️ Potential issue | 🟠 MajorAdd
opentdf-automation[bot]tohas_contributor_in.The new workflow commits as
opentdf-automation[bot](lines 131–132 of.github/workflows/go-version-update.yaml), but theautobumprule'shas_contributor_inonly allowsgithub-actions[bot]. Since this condition evaluates commit authors/committers, the PRs created by this workflow won't satisfy theautobumprule without updating it.Suggested fix
has_contributor_in: users: - "github-actions[bot]" + - "opentdf-automation[bot]"🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.policy.yml around lines 98 - 107, The autobump rule's has_contributor_in list only allows "github-actions[bot]" but the workflow commits are authored/committed by "opentdf-automation[bot]"; update the rule by adding "opentdf-automation[bot]" to the has_contributor_in users array so the autobump condition matches those workflow-created PRs (modify the has_contributor_in block alongside has_author_in within the autobump rule to include the new bot).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In @.github/scripts/bump-go-version.sh:
- Around line 165-169: The current early-exit check using CURRENT ==
LATEST_PATCH is unsafe because apply_changes_to() also updates workflow files;
change the no-op logic to detect whether any managed files (e.g., go.work plus
.github/workflows/checks.yaml and .github/workflows/sonarcloud.yml that
apply_changes_to() touches) would be modified rather than only comparing CURRENT
and LATEST_PATCH, so replace the CURRENT/LATEST_PATCH equality check with a
dry-run or diff step that simulates apply_changes_to() and only exits when no
files would change; update the bump-go-version.sh logic accordingly (referencing
the CURRENT, LATEST_PATCH variables and apply_changes_to() call) and add a Bats
regression test that simulates "drift-only" (go.work already at LATEST_PATCH but
workflow pins differ) to ensure the script does not early-exit.
In @.github/workflows/checks.yaml:
- Around line 661-664: Disable setup-go's module caching in the script-tests job
by adding the cache setting to the actions/setup-go step: locate the
actions/setup-go usage (uses:
actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5) in the script-tests
job and add with: cache: false so the step does not restore/save Go module cache
during those Bats tests.
- Around line 624-629: The trigger-go-version-update job is skipped when the
prior go job fails, hiding the previously uploaded govulncheck-failure-*
artifact; update the trigger-go-version-update job (job name:
trigger-go-version-update) to include an unconditional job-level guard by adding
if: always() (while preserving the existing event/ref checks) so this job runs
even when the go job fails and the artifact was produced.
In @.github/workflows/go-version-update.yaml:
- Around line 44-48: The run block in the "Determine base branch" step (id:
base) is interpolating ${{ inputs.base_branch }} directly into the shell which
is unsafe; instead, pass the input through env: (e.g., BASE_BRANCH: ${{
inputs.base_branch || 'main' }}), read it in the run script from the
environment, validate it using git check-ref-format --branch "$BASE_BRANCH" and
then echo the validated value to GITHUB_OUTPUT, and apply the same env
indirection pattern wherever you read dynamic values from
steps.versions.outputs.* and steps.base.outputs.branch in later run steps so
those values are not directly expanded into shell commands.
---
Outside diff comments:
In @.policy.yml:
- Around line 98-107: The autobump rule's has_contributor_in list only allows
"github-actions[bot]" but the workflow commits are authored/committed by
"opentdf-automation[bot]"; update the rule by adding "opentdf-automation[bot]"
to the has_contributor_in users array so the autobump condition matches those
workflow-created PRs (modify the has_contributor_in block alongside
has_author_in within the autobump rule to include the new bot).
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 81f2dfaa-302f-4ae5-b5d8-f4d3a6a05e46
📒 Files selected for processing (7)
.github/scripts/bump-go-version.bats.github/scripts/bump-go-version.sh.github/scripts/fixtures/go-versions.json.github/workflows/checks.yaml.github/workflows/go-version-update.yaml.policy.ymlAGENTS.md
| # ── Early exit if already current ───────────────────────────────────────────── | ||
|
|
||
| if [[ "$CURRENT" == "$LATEST_PATCH" ]]; then | ||
| log "Already at Go ${LATEST_PATCH}; nothing to do." | ||
| exit 2 |
There was a problem hiding this comment.
CURRENT == LATEST_PATCH is not a safe no-op check.
apply_changes_to() also rewrites .github/workflows/checks.yaml and .github/workflows/sonarcloud.yml, so a repo can still need updates even when go.work is already on the latest toolchain. With this check, drift in those CI pins is treated as “already current”; the mirrored up_to_date logic in .github/workflows/go-version-update.yaml then skips the script entirely. Base the no-op path on whether any managed file would actually change, and add a Bats regression case for the drift-only scenario.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In @.github/scripts/bump-go-version.sh around lines 165 - 169, The current
early-exit check using CURRENT == LATEST_PATCH is unsafe because
apply_changes_to() also updates workflow files; change the no-op logic to detect
whether any managed files (e.g., go.work plus .github/workflows/checks.yaml and
.github/workflows/sonarcloud.yml that apply_changes_to() touches) would be
modified rather than only comparing CURRENT and LATEST_PATCH, so replace the
CURRENT/LATEST_PATCH equality check with a dry-run or diff step that simulates
apply_changes_to() and only exits when no files would change; update the
bump-go-version.sh logic accordingly (referencing the CURRENT, LATEST_PATCH
variables and apply_changes_to() call) and add a Bats regression test that
simulates "drift-only" (go.work already at LATEST_PATCH but workflow pins
differ) to ensure the script does not early-exit.
| trigger-go-version-update: | ||
| if: | | ||
| !cancelled() && | ||
| github.event_name == 'push' && | ||
| (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/heads/release/')) | ||
| needs: go |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
In GitHub Actions, if a job has needs: another-joband anif:condition withoutalways(), is it skipped when another-job fails?
💡 Result:
Yes. By default, if a job listed in needs: fails, any jobs that need it are skipped unless you use a conditional that explicitly allows continuing. [1]
Also, an if: condition that doesn’t include a status-check function is treated as if it were prefixed with success(), so it won’t run after a failed dependency unless you add something like always() / failure() / etc. [2]
Example to run anyway:
if: ${{ always() && <your condition> }}Sources: [1] (docs.github.com) [2] (docs.github.com)
Citations:
- 1: https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions?text=For+more+information%2C+see+%22GitHub%27s+products.%22&utm_source=openai
- 2: https://docs.github.com/en/actions/learn-github-actions/expressions
🏁 Script executed:
cat -n .github/workflows/checks.yaml | sed -n '620,680p'Repository: opentdf/platform
Length of output: 2491
🏁 Script executed:
grep -n "govulncheck-failure" .github/workflows/checks.yamlRepository: opentdf/platform
Length of output: 581
🏁 Script executed:
cat -n .github/workflows/checks.yaml | sed -n '50,150p'Repository: opentdf/platform
Length of output: 4859
Use always() on the dispatch job to prevent skipping when unrelated lint/test failures occur.
The govulncheck-failure-* artifact is uploaded at line 85-88 (when govulncheck fails), but golangci-lint and subsequent tests run after (lines 90-117). If any of these later steps fail, the go job fails. Since trigger-go-version-update has needs: go without always(), the job is skipped whenever go fails—even though the govulncheck artifact was successfully uploaded. This suppresses the automation when it should run.
Suggested fix
trigger-go-version-update:
if: |
+ always() &&
!cancelled() &&
github.event_name == 'push' &&
(github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/heads/release/'))📝 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.
| trigger-go-version-update: | |
| if: | | |
| !cancelled() && | |
| github.event_name == 'push' && | |
| (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/heads/release/')) | |
| needs: go | |
| trigger-go-version-update: | |
| if: | | |
| always() && | |
| !cancelled() && | |
| github.event_name == 'push' && | |
| (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/heads/release/')) | |
| needs: go |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In @.github/workflows/checks.yaml around lines 624 - 629, The
trigger-go-version-update job is skipped when the prior go job fails, hiding the
previously uploaded govulncheck-failure-* artifact; update the
trigger-go-version-update job (job name: trigger-go-version-update) to include
an unconditional job-level guard by adding if: always() (while preserving the
existing event/ref checks) so this job runs even when the go job fails and the
artifact was produced.
- Script: guard option flags against missing values (--target, --repo-root,
--api-url) with a clear error message rather than crashing on unbound var
- Script/workflow: filter .stable == true in all jq queries to exclude betas
and release candidates from version selection
- Script/workflow: sort by version numerically and take last entry instead of
relying on API response ordering (guard against go1.25.10 > go1.25.9)
- Script: add --connect-timeout 5 --max-time 30 to curl to prevent hangs
- Script: replace GNU-only diff --label with portable -L flags
- Workflow: move all ${{ }} template expansions in run: blocks to env: vars
to prevent code injection (zizmor finding)
- Fixture: add go1.26rc1 (stable: false) entry; add BATS test verifying
prereleases are excluded from version selection
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Dave Mihalcik <dmihalcik@virtru.com>
Benchmark results, click to expandBenchmark authorization.GetDecisions Results:
Benchmark authorization.v2.GetMultiResourceDecision Results:
Benchmark Statistics
Bulk Benchmark Results
TDF3 Benchmark Results:
|
There was a problem hiding this comment.
Actionable comments posted: 2
♻️ Duplicate comments (2)
.github/scripts/bump-go-version.sh (1)
179-184:⚠️ Potential issue | 🟠 MajorEarly exit skips YAML drift fixes when toolchain is already current.
The check
CURRENT == LATEST_PATCHexits early without callingapply_changes_to(). However, the CI workflow YAMLs (.github/workflows/checks.yamland.github/workflows/sonarcloud.yml) might still have outdated versions that need updating. This creates a scenario where the toolchain is current but YAMLs remain stale.Consider checking whether any managed file would change before declaring "nothing to do":
Suggested approach
-if [[ "$CURRENT" == "$LATEST_PATCH" ]]; then - log "Already at Go ${LATEST_PATCH}; nothing to do." - exit 2 -fi +# Check if any files would actually change (handles YAML-only drift) +TMPDIR_CHECK="$(mktemp -d)" +trap 'rm -rf "$TMPDIR_CHECK"' EXIT +while IFS= read -r rel; do + local_file="${REPO_ROOT}/${rel}" + if [[ -f "$local_file" ]]; then + mkdir -p "${TMPDIR_CHECK}/$(dirname "$rel")" + cp "$local_file" "${TMPDIR_CHECK}/${rel}" + fi +done < <(target_files) + +apply_changes_to "$TMPDIR_CHECK" + +HAS_CHANGES=false +while IFS= read -r rel; do + if [[ -f "${REPO_ROOT}/${rel}" && -f "${TMPDIR_CHECK}/${rel}" ]]; then + if ! diff -q "${REPO_ROOT}/${rel}" "${TMPDIR_CHECK}/${rel}" > /dev/null 2>&1; then + HAS_CHANGES=true + break + fi + fi +done < <(target_files) + +if [[ "$HAS_CHANGES" == "false" ]]; then + log "All files already at target; nothing to do." + exit 2 +fiThis requires moving
target_files()andapply_changes_to()above this check.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.github/scripts/bump-go-version.sh around lines 179 - 184, The early-exit compares CURRENT and LATEST_PATCH and returns before running target_files() / apply_changes_to(), so YAML workflow files may remain stale; move the calls to target_files() and apply_changes_to() above the CURRENT == LATEST_PATCH check and replace the unconditional exit with a conditional: run target_files() to collect managed files, run a dry-run or diff via apply_changes_to() (or have apply_changes_to() return whether it would modify any file), and only log "nothing to do" and exit when both the toolchain is current (CURRENT == LATEST_PATCH) AND apply_changes_to() reports no file changes; keep references to CURRENT, LATEST_PATCH, target_files(), and apply_changes_to() to locate the logic..github/workflows/checks.yaml (1)
624-629:⚠️ Potential issue | 🟠 MajorAdd
always()to ensure dispatch runs even when unrelated lint/test failures occur.The
trigger-go-version-updatejob depends ongovianeeds: go. If govulncheck fails and uploads an artifact (lines 84-88), but a later step ingo(likegolangci-lintor tests) also fails, the entiregojob fails. Withoutalways()in theif:condition, this job is skipped—even though the govulncheck artifact was successfully uploaded.Suggested fix
trigger-go-version-update: if: | + always() && !cancelled() && github.event_name == 'push' && (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/heads/release/'))🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.github/workflows/checks.yaml around lines 624 - 629, The trigger-go-version-update job is currently skipped when its dependency job (needs: go) fails even if govulncheck uploaded artifacts; update the job's if expression to include always() so the job still runs regardless of failures in its predecessors. Specifically modify the if condition for the trigger-go-version-update job (which currently checks !cancelled(), github.event_name and github.ref) to add always() at the start of the expression so the job runs even when the go job fails after govulncheck; keep the existing checks for event and ref intact.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In @.github/scripts/bump-go-version.bats:
- Around line 179-189: Add a new Bats test that exercises the YAML-only drift
case: call build_repo with the repo toolchain set to the requested target (e.g.,
"1.25.9") but leave the workflow YAMLs at an older version, then run the SCRIPT
with --target "1.25.9" and assert the script exits success and updates the YAMLs
(grep for go-version-input and go-version equal to the target). Ensure the new
test mirrors existing tests (use the same local root setup and build_repo
helper) but does not rely on a toolchain bump so it will catch the early-exit
behavior in bump-go-version.sh (the branch that currently returns a no-op when
toolchain is current) and verifies YAML-only updates are performed.
In @.github/workflows/go-version-update.yaml:
- Around line 37-42: Add an environment protection by specifying environment:
automation at the job level that contains the "Obtain app token" step (the step
with id "app-token" that uses actions/create-github-app-token and reads
secrets.APP_ID and secrets.AUTOMATION_KEY); create the "automation" environment
in repo settings with the desired protection rules, then add environment:
automation to the job so the step runs under that protected environment.
---
Duplicate comments:
In @.github/scripts/bump-go-version.sh:
- Around line 179-184: The early-exit compares CURRENT and LATEST_PATCH and
returns before running target_files() / apply_changes_to(), so YAML workflow
files may remain stale; move the calls to target_files() and apply_changes_to()
above the CURRENT == LATEST_PATCH check and replace the unconditional exit with
a conditional: run target_files() to collect managed files, run a dry-run or
diff via apply_changes_to() (or have apply_changes_to() return whether it would
modify any file), and only log "nothing to do" and exit when both the toolchain
is current (CURRENT == LATEST_PATCH) AND apply_changes_to() reports no file
changes; keep references to CURRENT, LATEST_PATCH, target_files(), and
apply_changes_to() to locate the logic.
In @.github/workflows/checks.yaml:
- Around line 624-629: The trigger-go-version-update job is currently skipped
when its dependency job (needs: go) fails even if govulncheck uploaded
artifacts; update the job's if expression to include always() so the job still
runs regardless of failures in its predecessors. Specifically modify the if
condition for the trigger-go-version-update job (which currently checks
!cancelled(), github.event_name and github.ref) to add always() at the start of
the expression so the job runs even when the go job fails after govulncheck;
keep the existing checks for event and ref intact.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 1845c76d-f65b-4e17-803a-417921d57f64
📒 Files selected for processing (5)
.github/scripts/bump-go-version.bats.github/scripts/bump-go-version.sh.github/scripts/fixtures/go-versions.json.github/workflows/checks.yaml.github/workflows/go-version-update.yaml
.github/scripts/bump-go-version.bats
Outdated
| @test "CI YAML files are updated unconditionally even if they lag the toolchain" { | ||
| local root="${BATS_TEST_TMPDIR}/repo" | ||
| # Repo toolchain is 1.25.8 but YAML files still reference 1.25.7 | ||
| build_repo "$root" "1.25.8" "1.25.0" | ||
|
|
||
| run "$SCRIPT" --repo-root "$root" --target "1.25.9" | ||
| [ "$status" -eq 0 ] | ||
|
|
||
| grep -q 'go-version-input: "1.25.9"' "${root}/.github/workflows/checks.yaml" | ||
| grep -q 'go-version: "1.25.9"' "${root}/.github/workflows/sonarcloud.yml" | ||
| } |
There was a problem hiding this comment.
Test does not cover pure YAML-drift scenario.
This test verifies YAML files are updated when the toolchain also needs bumping (1.25.8 → 1.25.9). However, it doesn't cover the case where go.work is already at the target (e.g., 1.25.9) but the YAML files still reference an older version (e.g., 1.25.7). The script's early exit at line 181-184 of bump-go-version.sh would skip updates in that scenario.
Consider adding a test like:
`@test` "YAML-only drift is updated even when toolchain is current" {
local root="${BATS_TEST_TMPDIR}/repo"
# Toolchain at 1.25.9 but YAMLs still at 1.25.7 (via build_repo default)
build_repo "$root" "1.25.9" "1.25.0"
run "$SCRIPT" --repo-root "$root" --target "1.25.9"
# Current behavior: exits 2 (no-op) - is this intended?
# If YAML drift should be fixed, expect exit 0 and updated YAMLs
}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In @.github/scripts/bump-go-version.bats around lines 179 - 189, Add a new Bats
test that exercises the YAML-only drift case: call build_repo with the repo
toolchain set to the requested target (e.g., "1.25.9") but leave the workflow
YAMLs at an older version, then run the SCRIPT with --target "1.25.9" and assert
the script exits success and updates the YAMLs (grep for go-version-input and
go-version equal to the target). Ensure the new test mirrors existing tests (use
the same local root setup and build_repo helper) but does not rely on a
toolchain bump so it will catch the early-exit behavior in bump-go-version.sh
(the branch that currently returns a no-op when toolchain is current) and
verifies YAML-only updates are performed.
| - name: Obtain app token | ||
| id: app-token | ||
| uses: actions/create-github-app-token@df432ceedc7162793a195dd1713ff69aefc7379e # v2.0.6 | ||
| with: | ||
| app-id: ${{ secrets.APP_ID }} | ||
| private-key: ${{ secrets.AUTOMATION_KEY }} |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
Consider adding an environment for secret protection.
The workflow accesses secrets.APP_ID and secrets.AUTOMATION_KEY without a dedicated environment. While functionally correct, using an environment (e.g., environment: automation) would enable environment protection rules, required reviewers, or deployment gates for additional security.
Suggested change
update:
name: bump Go toolchain
runs-on: ubuntu-22.04
+ environment: automation
permissions:
contents: write
pull-requests: writeThis requires creating the automation environment in repository settings with appropriate protection rules.
📝 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.
| - name: Obtain app token | |
| id: app-token | |
| uses: actions/create-github-app-token@df432ceedc7162793a195dd1713ff69aefc7379e # v2.0.6 | |
| with: | |
| app-id: ${{ secrets.APP_ID }} | |
| private-key: ${{ secrets.AUTOMATION_KEY }} | |
| update: | |
| name: bump Go toolchain | |
| runs-on: ubuntu-22.04 | |
| environment: automation | |
| permissions: | |
| contents: write | |
| pull-requests: write |
🧰 Tools
🪛 GitHub Check: zizmor
[warning] 41-41:
secrets referenced without a dedicated environment
[warning] 42-42:
secrets referenced without a dedicated environment
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In @.github/workflows/go-version-update.yaml around lines 37 - 42, Add an
environment protection by specifying environment: automation at the job level
that contains the "Obtain app token" step (the step with id "app-token" that
uses actions/create-github-app-token and reads secrets.APP_ID and
secrets.AUTOMATION_KEY); create the "automation" environment in repo settings
with the desired protection rules, then add environment: automation to the job
so the step runs under that protected environment.
…ce of truth Remove the `toolchain` directive from all go.mod files. The Go spec makes this directive local-only (it never affects downstream consumers), and in a workspace the go.work toolchain takes precedence. Experimentally verified that `go mod tidy` does not re-add it. Replace all hardcoded Go version strings in CI workflows with `go-version-file: go.work`: - checks.yaml govulncheck: `go-version-input: ""` + `go-version-file: go.work` - sonarcloud.yml: `go-version-file: go.work` Update work-init.sh to preserve the toolchain directive when regenerating go.work for release branches, so govulncheck continues to read the correct version. Simplify bump-go-version.sh: patch bumps now update only go.work (1 file instead of 13). Minor bumps additionally update go directives in go.mod files. No YAML edits needed in either case. Before: patch bump touched go.work + 10 go.mod + 2 YAML = 13 files After: patch bump touches go.work = 1 file Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: Dave Mihalcik <dmihalcik@virtru.com>
Benchmark results, click to expandBenchmark authorization.GetDecisions Results:
Benchmark authorization.v2.GetMultiResourceDecision Results:
Benchmark Statistics
Bulk Benchmark Results
TDF3 Benchmark Results:
|
|
|
This seems far too complicated. I've instead proposed #3285 to simplify the amount of work that needs to happen to update the golang target, which maybe will make workflow simpler or, better yet, unnecessary |
Adds a workflow that detects govulncheck failures on main and release/**
branches and automatically opens a PR bumping the Go toolchain to the
latest supported patch (or latest minor if the current one is EOL).
.github/scripts/bump-go-version.sh: standalone script that updatesthe
toolchaindirective ingo.workand allgo.modfiles, andsyncs the hardcoded Go version in
checks.yamlandsonarcloud.yml.Supports
--dry-run(prints unified diff, no file changes),--target(skip API lookup), and
--api-url(mock for tests)..github/scripts/bump-go-version.bats: 9 BATS unit tests coveringpatch bumps, minor-version bumps, EOL detection, dry-run mode, and
already-at-latest no-op behaviour.
.github/scripts/fixtures/go-versions.json: mock go.dev API responsefor offline test runs.
.github/workflows/go-version-update.yaml: automation workflow(workflow_dispatch + weekly schedule) that calls the script and
creates/updates a PR as
opentdf-automation[bot]with theautobumplabel.
.github/workflows/checks.yaml: addstrigger-go-version-updatejob(dispatches the update workflow when govulncheck artifacts are found on
push to main/release/**) and
script-testsjob (runs the BATS tests;added to the
cigate)..policy.yml: extends theautobumprule's branch pattern to alsomatch
chore/bump-go-toolchain(-...)?so bot PRs auto-merge on CI pass.AGENTS.md: documents that Go toolchain bumps should go through thisautomation rather than being done by hand in feature PRs.
Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com
Signed-off-by: Dave Mihalcik dmihalcik@virtru.com
Proposed Changes
Checklist
Testing Instructions
Summary by CodeRabbit
New Features
Documentation
Tests
Chores