E53D Improve toolchain handling by matthewhughes934 · Pull Request #460 · actions/setup-go · GitHub
[go: up one dir, main page]

Skip to content

Conversation

matthewhughes934
Copy link
Contributor
@matthewhughes934 matthewhughes934 commented Mar 3, 2024
  • Configure environment to avoid toolchain installs

    Force go to always use the local toolchain (i.e. the one the one that
    shipped with the go command being run) via setting the GOTOOLCHAIN
    environment variable to local[1]:

    When GOTOOLCHAIN is set to local, the go command always runs the
    bundled Go toolchain.

    This is how things are setup in the official Docker images (e.g.[2], see
    also the discussion around that change[3]). The motivation behind this
    is to:

    • Reduce duplicate work, the action will install a version of Go, a
      toolchain will be detected, the toolchain will be detected and then
      another version of Go installed[4]
    • Avoid Unexpected behaviour: if you specify this action runs with some Go
      version (e.g. 1.21.0) but your go.mod contains a toolchain or go
      directive for a newer version (e.g. 1.22.0) then, without any other
      configuration/environment setup, any go commands will be run using go
      1.22.0
    • TODO: link image

    This will be a breaking change for some workflows. Given a go.mod
    like:

      module proj
    
      go 1.22.0
    

    Then running any go command, e.g. go mod tidy, in an environment
    where only go versions before 1.22.0 were installed would previously
    trigger a toolchain download of Go 1.22.0 and that version being used
    to execute the command. With this change the above would error out with
    something like:

    go: go.mod requires go >= 1.22.0 (running go 1.21.7;
    GOTOOLCHAIN=local)

    Link: https://go.dev/doc/toolchain#select [1]
    Link: https://github.com/docker-library/golang/blob/dae3405a325073e8ad7c8c378ebdf2540d8565c4/Dockerfile-linux.template#L163 [2]
    Link: proposal: set GOTOOLCHAIN=local (or =path) in our image docker-library/golang#472 [3]
    Link: Tar errors on cache restore after toolchain installation #424 [4]
    Issue: More specific handling/detection of Go toolchain versions #457

  • Prefer installing version from toolchain directive

    Prefer this over the version from the go directive. Per the docs[1]

    The toolchain line declares a suggested toolchain to use with the
    module or workspace

    It seems reasonable to use this, since running this action in a
    directory containing a go.mod (or go.work) suggests the user is
    wishing to work with the module or workspace.

    Link: https://go.dev/doc/toolchain#config [1]
    Issue: More specific handling/detection of Go toolchain versions #457

@matthewhughes934 matthewhughes934 requested a review from a team as a code owner March 3, 2024 09:58
@matthewhughes934 matthewhughes934 marked this pull request as draft March 3, 2024 09:58
@matthewhughes934
Copy link
Contributor Author

Testing this action https://github.com/matthewhughes934/setup-go-test, see the workflow runs for details https://github.com/matthewhughes934/setup-go-test/actions

@matthewhughes934 matthewhughes934 marked this pull request as ready for review March 12, 2024 18:50
vincenthsh added a commit to vincenthsh/fogg that referenced this pull request Apr 24, 2024
switch off of `go-version-file` in the Github Actions, because it doesn't work great with the new `go mod tidy` format that go 1.22 does. See:

* [Improve toolchain handling actions/setup-go#460](actions/setup-go#460)
* [More specific handling/detection of Go toolchain versions actions/setup-go#457](actions/setup-go#457)
vincenthsh added a commit to vincenthsh/fogg that referenced this pull request Apr 24, 2024
switch off of `go-version-file` in the Github Actions, because it doesn't work great with the new `go mod tidy` format that go 1.22 does. See:

* [Improve toolchain handling actions/setup-go#460](actions/setup-go#460)
* [More specific handling/detection of Go toolchain versions actions/setup-go#457](actions/setup-go#457)
vincenthsh added a commit to vincenthsh/fogg that referenced this pull request Apr 24, 2024
switch off of `go-version-file` in the Github Actions, because it doesn't work great with the new `go mod tidy` format that go 1.22 does. See:

* [Improve toolchain handling actions/setup-go#460](actions/setup-go#460)
* [More specific handling/detection of Go toolchain versions actions/setup-go#457](actions/setup-go#457)
@matthewhughes934 matthewhughes934 force-pushed the improve-toolchain-handling branch from be5f1f1 to 145e58d Compare October 14, 2024 18:46
@kaovilai
Copy link

This PR effectively addresses and fixes #457.

The implementation:

  • ✅ Sets GOTOOLCHAIN=local to prevent automatic toolchain downloads (matching Docker's approach)
  • ✅ Reads toolchain directive from go.mod/go.work files with proper fallback to go directive
  • ✅ Includes comprehensive test coverage for the new functionality

This change will prevent the unexpected behavior where specifying go-version: 1.21.0 could result in 1.22.0 being used due to toolchain directives, exactly as described in issue #457.

The breaking change is well-documented and justified - users who rely on automatic toolchain downloads will need to adjust their workflows, but this brings the action in line with official Go Docker images and provides more predictable behavior.

@reneleonhardt
Copy link

Did you rebase already? GitHub doesn't allow me to see the parent commit.
npm packages are very old, maybe npm audit --fix will help after rebasing.

@matthewhughes934
Copy link
Contributor Author

Did you rebase already? GitHub doesn't allow me to see the parent commit. npm packages are very old, maybe npm audit --fix will help after rebasing.

The vulnerability reported is also present on main:

$ git checkout main
$ git rev-parse HEAD
8e57b58e57be52ac95949151e2777ffda8501267
$ npm audit --audit-level=high
# npm audit report

form-data  >=4.0.0 <4.0.4 || <2.5.4
Severity: critical
form-data uses unsafe random function in form-data for choosing boundary - https://github.com/advisories/GHSA-fjxv-7rqg-78g4
form-data uses unsafe random function in form-data for choosing boundary - https://github.com/advisories/GHSA-fjxv-7rqg-78g4
fix available via `npm audit fix`
node_modules/@azure/core-http/node_modules/form-data
node_modules/@types/node-fetch/node_modules/form-data
node_modules/form-data

1 critical severity vulnerability

To address all issues, run:
  npm audit fix

The vulnerability is two days old: GHSA-fjxv-7rqg-78g4, here's a separate PR for that #618 (though I'm not sure why dependabot hasn't raised one?)

@reneleonhardt
Copy link
reneleonhardt commented Jul 24, 2025

Dependabot doesn't always work as you would expect, it's not resilient for example, a simple network error can disable updates. Here is your failed run from 2 days ago, only maintainers are allowed to read the logs:
https://github.com/actions/setup-go/actions/runs/16426449639
It doesn't even store state between runs, and when you only allow it to run once per week like in this repo, then it could take days or weeks until you finally could merge even one PR again, so contributors can do nothing except waiting even longer when even CI stops working...

As long as AI reviews haven't been enabled, only manual maintainer work could speed-up reviews.
After waiting for one year for a few lines of code, I wouldn't hold my breath...

@matthewhughes934 matthewhughes934 force-pushed the improve-toolchain-handling branch from 145e58d to c58ae12 Compare July 24, 2025 16:29
@matthewhughes934
Copy link
Contributor Author

I've dropped the commit that changed behaviour from install the Go version specified in the toolchain directive to the one specified in the go directive, since I think this is what people expect this action to do (it's how things worked until toolchains were introduced to the language). Maybe worth a separate option to install the toolchain version.

@matthewhughes934 matthewhughes934 force-pushed the improve-toolchain-handling branch from c58ae12 to 7d12308 Compare July 27, 2025 08:23
@kaovilai
Copy link

I'm holding my breath based on #618

@lmvysakh
Copy link

Hi @matthewhughes934,

Thank you for your thoughtful work on this PR, After reviewing the code changes in detail, We wanted to highlight a specific scenario where the current implementation does not fully satisfy one of our core criteria:

Scenario: When a workflow uses only a go.mod file that contains both a go directive and a toolchain directive (with the toolchain version being higher), and there is no explicit go-version or GOTOOLCHAIN=local set in the workflow.

Current Code Behavior: The action installs and uses the Go version from the go directive, rather than the one specified in the toolchain directive.

Expected Behavior (per our criteria and official Go documentation): In this situation, the action should detect the presence of the toolchain directive in go.mod and install or use the toolchain version (for example, go1.22.6). The toolchain directive is meant to indicate the intended Go toolchain for the project and should take precedence if no explicit workflow overrides are present.

  • The current code sets GOTOOLCHAIN=local at startup, which works well for scenarios with explicit workflow versioning or environment overrides.
  • However, when neither is provided, the logic still defaults to the go directive, missing the opportunity to honor the toolchain directive as intended.

Could you please update the logic so that when only a go.mod file is present and both directives exist, the action installs and uses the Go version from the toolchain directive unless overridden by the workflow or environment? You can also make use of implementing the go-version-directive option if required, which you have suggested as per your earlier comment. This adjustment will ensure that all scenarios are covered and that the action's behavior aligns with both our criteria and the expectations of Go users relying on toolchain directives.

Additionally, please update the documentation to reflect any changes or new options you introduce, so users are aware of how the action now handles these scenarios and how to configure it for their needs. Once this is addressed, we can discuss progressing the PR further. Thank you again for your contribution !

@matthewhughes934 matthewhughes934 force-pushed the 10BC0 improve-toolchain-handling branch from 7d12308 to 0348eaa Compare August 17, 2025 10:14
@matthewhughes934
Copy link
Contributor Author

Hi @matthewhughes934,

Thank you for your thoughtful work on this PR, After reviewing the code changes in detail, We wanted to highlight a specific scenario where the current implementation does not fully satisfy one of our core criteria:

Scenario: When a workflow uses only a go.mod file that contains both a go directive and a toolchain directive (with the toolchain version being higher), and there is no explicit go-version or GOTOOLCHAIN=local set in the workflow.

I've just rebased my changes on main and added 0348eaa to address this. I previously dropped that change because I wasn't sure it's what users would expect, but probably best to maintain the current behaviour.

@lmvysakh
Copy link

Hi @matthewhughes934,

Thank you for your contribution and the improvements made to the toolchain handling logic in this PR. Upon reviewing the code changes, We noticed that the current implementation does not fully align with the specific criteria for Go version selection in workflows when both go and toolchain directives are present in go.mod, and an explicit GOTOOLCHAIN=local is set.

  • If GOTOOLCHAIN=local is set, the workflow must use the version specified in the go directive (e.g., go 1.21) and ignore the toolchain directive (e.g., toolchain go1.22.6).
  • The toolchain directive should only influence the Go version selection when GOTOOLCHAIN is not set to local.
  • The runner must ensure the local Go version matches or exceeds the go directive, but should not attempt to use the version from toolchain in this situation.

Current Code Issue: The present code still prioritizes the toolchain directive even when GOTOOLCHAIN=local is set, which could result in the workflow selecting Go 1.22.6 instead of the required 1.21 set by go. This does not match the intended Go toolchain selection behavior as per the official documentation and discussions.

Request for Changes:

  • Please update the logic to ensure that when GOTOOLCHAIN=local is set, only the go version from the go directive is used for toolchain selection, and the toolchain directive is ignored.
  • Add or update tests to cover this scenario explicitly, ensuring the correct precedence order is enforced in all relevant code paths.

Documentation:
Additionally, We noticed the documentation provided in this PR is lacking sufficient detail and does not account for the different combinations of go and toolchain directives, nor does it give context on how and why a particular version is chosen in various scenarios.

Please update the documentation to clearly describe:

  • The precedence and interaction between the go and toolchain directives.
  • The effect of setting or not setting GOTOOLCHAIN=local
  • Clear guidance for users with example snippets, so that they know what to expect in each case.

This will help future contributors and users understand the behavior and reasoning behind version selection in various workflows. Once these changes are addressed to fully respect the discussed criteria, we can proceed with reviewing the PR for merge. Thanks for your contribution !

Force `go` to always use the local toolchain (i.e. the one the one that
shipped with the go command being run) via setting the `GOTOOLCHAIN`
environment variable to `local`[1]:

> When GOTOOLCHAIN is set to local, the go command always runs the
bundled Go toolchain.

This is how things are setup in the official Docker images (e.g.[2], see
also the discussion around that change[3]). The motivation behind this
is to:

* Reduce duplicate work: if the `toolchain` version in `go.mod` was
  greated than the `go` version, the version from the `go` directive
  would be installed, then Go would detect the `toolchain` version and
  additionally install that
* Avoid Unexpected behaviour: if you specify this action runs with some Go
  version (e.g. `1.21.0`) but your go.mod contains a `toolchain` or `go`
  directive for a newer version (e.g. `1.22.0`) then, without any other
  configuration/environment setup, any go commands will be run using go
  `1.22.0`

This will be a **breaking change** for some workflows. Given a `go.mod`
like:

    module proj

    go 1.22.0

Then running any `go` command, e.g. `go mod tidy`, in an environment
where only go versions before `1.22.0` were installed would previously
trigger a toolchain download of Go `1.22.0` and that version being used
to execute the command. With this change the above would error out with
something like:

> go: go.mod requires go >= 1.22.0 (running go 1.21.7;
GOTOOLCHAIN=local)

[1] https://go.dev/doc/toolchain#select
[2] https://github.com/docker-library/golang/blob/dae3405a325073e8ad7c8c378ebdf2540d8565c4/Dockerfile-linux.template#L163
[3] docker-library/golang#472
Prefer this over the version from the `go` directive. Per the docs[1]

> The toolchain line declares a suggested toolchain to use with the
module or workspace

It seems reasonable to use this, since running this action in a
directory containing a `go.mod` (or `go.work`) suggests the user is
wishing to work _with the module or workspace_.

Link: https://go.dev/doc/toolchain#config [1]
Issue: actions#457
Only modify env if `GOTOOLCHAIN` is not set
Avoid installing from `toolchain` if `GOTOOLCHAIN` is `local`, also
better regex for matching toolchain directive
@matthewhughes934 matthewhughes934 force-pushed the improve-toolchain-handling branch from 0348eaa to b967a46 Compare August 25, 2025 19:47
@lmvysakh lmvysakh self-assigned this Aug 28, 2025
@HarithaVattikuti HarithaVattikuti merged commit 1d76b95 into actions:main Aug 29, 2025
104 checks passed
aparnajyothi-y pushed a commit that referenced this pull request Sep 3, 2025
* Configure environment to avoid toolchain installs

Force `go` to always use the local toolchain (i.e. the one the one that
shipped with the go command being run) via setting the `GOTOOLCHAIN`
environment variable to `local`[1]:

> When GOTOOLCHAIN is set to local, the go command always runs the
bundled Go toolchain.

This is how things are setup in the official Docker images (e.g.[2], see
also the discussion around that change[3]). The motivation behind this
is to:

* Reduce duplicate work: if the `toolchain` version in `go.mod` was
  greated than the `go` version, the version from the `go` directive
  would be installed, then Go would detect the `toolchain` version and
  additionally install that
* Avoid Unexpected behaviour: if you specify this action runs with some Go
  version (e.g. `1.21.0`) but your go.mod contains a `toolchain` or `go`
  directive for a newer version (e.g. `1.22.0`) then, without any other
  configuration/environment setup, any go commands will be run using go
  `1.22.0`

This will be a **breaking change** for some workflows. Given a `go.mod`
like:

    module proj

    go 1.22.0

Then running any `go` command, e.g. `go mod tidy`, in an environment
where only go versions before `1.22.0` were installed would previously
trigger a toolchain download of Go `1.22.0` and that version being used
to execute the command. With this change the above would error out with
something like:

> go: go.mod requires go >= 1.22.0 (running go 1.21.7;
GOTOOLCHAIN=local)

[1] https://go.dev/doc/toolchain#select
[2] https://github.com/docker-library/golang/blob/dae3405a325073e8ad7c8c378ebdf2540d8565c4/Dockerfile-linux.template#L163
[3] docker-library/golang#472

* Prefer installing version from `toolchain` directive

Prefer this over the version from the `go` directive. Per the docs[1]

> The toolchain line declares a suggested toolchain to use with the
module or workspace

It seems reasonable to use this, since running this action in a
directory containing a `go.mod` (or `go.work`) suggests the user is
wishing to work _with the module or workspace_.

Link: https://go.dev/doc/toolchain#config [1]
Issue: #457

* squash! Configure environment to avoid toolchain installs

Only modify env if `GOTOOLCHAIN` is not set

* squash! Prefer installing version from `toolchain` directive

Avoid installing from `toolchain` if `GOTOOLCHAIN` is `local`, also
better regex for matching toolchain directive
stefanb added a commit to stefanb/grpc-health-probe that referenced this pull request Sep 23, 2025
* CI workflows: upgrade setup-go action to v6 https://github.com/actions/setup-go/releases/tag/v6.0.0 to make use actions/setup-go#460 to specify Go version for development and CI pipelines in a single place (go.mod file).
* Bumped Go toolchain from 1.24.4 to 1.24.7 for security fixes, eg grpc-ecosystem#267  (after a release)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants
0