Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fail if the current Go version is newer than what built garble #508

Merged
merged 1 commit into from
Mar 22, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,13 @@ jobs:

# Static checks from this point forward. Only run on one Go version and on
# Linux, since it's the fastest platform, and the tools behave the same.
- if: matrix.os == 'ubuntu-latest' && matrix.go-version == '1.17.x'
- if: matrix.os == 'ubuntu-latest' && matrix.go-version == '1.18.x'
run: diff <(echo -n) <(gofmt -d .)
- if: matrix.os == 'ubuntu-latest' && matrix.go-version == '1.17.x'
- if: matrix.os == 'ubuntu-latest' && matrix.go-version == '1.18.x'
run: go vet ./...
# TODO: bump to Go 1.18 once staticcheck supports it
- if: matrix.os == 'ubuntu-latest' && matrix.go-version == '1.17.x'
uses: dominikh/staticcheck-action@v1.1.0
uses: dominikh/staticcheck-action@v1
with:
version: "2021.1.2"
install-go: false
Expand All @@ -61,7 +62,7 @@ jobs:
steps:
- uses: actions/setup-go@v3
with:
go-version: 1.17.x
go-version: 1.18.x
- uses: actions/checkout@v3
- name: Test
run: go test -timeout=15m ./...
Expand Down
43 changes: 34 additions & 9 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -256,27 +256,52 @@ type errJustExit int

func (e errJustExit) Error() string { return fmt.Sprintf("exit: %d", e) }

var goVersionSemver string
// toolchainVersionSemver is a semver-compatible version of the Go toolchain currently
// being used, as reported by "go env GOVERSION".
// Note that the version of Go that built the garble binary might be newer.
var toolchainVersionSemver string

func goVersionOK() bool {
const (
minGoVersionSemver = "v1.17.0"
suggestedGoVersion = "1.17.x"
)

rxVersion := regexp.MustCompile(`go\d+\.\d+(\.\d)?`)
version := rxVersion.FindString(cache.GoEnv.GOVERSION)
if version == "" {
// rxVersion looks for a version like "go1.2" or "go1.2.3"
rxVersion := regexp.MustCompile(`go\d+\.\d+(\.\d+)?`)

toolchainVersionFull := cache.GoEnv.GOVERSION
toolchainVersion := rxVersion.FindString(cache.GoEnv.GOVERSION)
if toolchainVersion == "" {
// Go 1.15.x and older do not have GOVERSION yet.
// We could go the extra mile and fetch it via 'go version',
// We could go the extra mile and fetch it via 'go toolchainVersion',
// but we'd have to error anyway.
fmt.Fprintf(os.Stderr, "Go version is too old; please upgrade to Go %s or a newer devel version\n", suggestedGoVersion)
return false
}

goVersionSemver = "v" + strings.TrimPrefix(version, "go")
if semver.Compare(goVersionSemver, minGoVersionSemver) < 0 {
fmt.Fprintf(os.Stderr, "Go version %q is too old; please upgrade to Go %s\n", version, suggestedGoVersion)
toolchainVersionSemver = "v" + strings.TrimPrefix(toolchainVersion, "go")
if semver.Compare(toolchainVersionSemver, minGoVersionSemver) < 0 {
fmt.Fprintf(os.Stderr, "Go version %q is too old; please upgrade to Go %s\n", toolchainVersionFull, suggestedGoVersion)
return false
}

// Ensure that the version of Go that built the garble binary is equal or
// newer than toolchainVersionSemver.
builtVersionFull := os.Getenv("GARBLE_TEST_GOVERSION")
if builtVersionFull == "" {
builtVersionFull = runtime.Version()
}
builtVersion := rxVersion.FindString(builtVersionFull)
if builtVersion == "" {
// If garble built itself, we don't know what Go version was used.
// Fall back to not performing the check against the toolchain version.
return true
}
builtVersionSemver := "v" + strings.TrimPrefix(builtVersion, "go")
if semver.Compare(builtVersionSemver, toolchainVersionSemver) < 0 {
fmt.Fprintf(os.Stderr, "garble was built with %q and is being used with %q; please rebuild garble with the newer version\n",
builtVersionFull, toolchainVersionFull)
return false
}

Expand Down Expand Up @@ -473,7 +498,7 @@ This command wraps "go %s". Below is its help:
command,
"-trimpath",
}
if semver.Compare(goVersionSemver, "v1.18.0") >= 0 {
if semver.Compare(toolchainVersionSemver, "v1.18.0") >= 0 {
// TODO: remove the conditional once we drop support for 1.17
goArgs = append(goArgs, "-buildvcs=false")
}
Expand Down
62 changes: 49 additions & 13 deletions testdata/scripts/goversion.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,39 +5,75 @@ go build -o .bin/go$exe ./fakego
env PATH=${WORK}/.bin${:}${PATH}

# An empty go version.
env GOVERSION=''
env TOOLCHAIN_GOVERSION=''
! garble build
stderr 'Go version is too old; please upgrade to Go 1.17.x or a newer devel version'
stderr 'Go version is too old; please upgrade to Go 1\.17\.x or a newer devel version'

# We should error on a devel version that's too old.
# Note that they lacked the "goN.M-" prefix.
env GOVERSION='devel +afb5fca Sun Aug 07 00:00:00 2020 +0000'
env TOOLCHAIN_GOVERSION='devel +afb5fca Sun Aug 07 00:00:00 2020 +0000'
! garble build
stderr 'Go version is too old; please upgrade to Go 1.17.x or a newer devel version'
stderr 'Go version is too old; please upgrade to Go 1\.17\.x or a newer devel version'

# Another form of old version; with an old "goN.M-" prefix.
env GOVERSION='devel go1.15-afb5fca Sun Aug 07 00:00:00 2020 +0000'
env TOOLCHAIN_GOVERSION='devel go1.15-afb5fca Sun Aug 07 00:00:00 2020 +0000'
! garble build
stderr 'Go version "go1.15" is too old; please upgrade to Go 1.17.x'
stderr 'Go version "devel go1\.15-.*2020.*" is too old; please upgrade to Go 1\.17\.x'

# A current devel version should be fine
env GOVERSION='devel go1.18-ad97d204f0 Sun Sep 12 16:46:58 2021 +0000'
# A current devel version should be fine.
# Note that we don't look at devel version timestamps.
env GARBLE_TEST_GOVERSION='go1.18'
env TOOLCHAIN_GOVERSION='devel go1.18-ad97d204f0 Sun Sep 12 16:46:58 2021 +0000'
! garble build
stderr 'mocking the real build'

# We should error on a stable version that's too old.
env GOVERSION='go1.14'
env TOOLCHAIN_GOVERSION='go1.14'
! garble build
stderr 'Go version "go1.14" is too old; please upgrade to Go 1.17.x'
stderr 'Go version "go1\.14" is too old; please upgrade to Go 1\.17\.x'
! stderr 'or a newer devel version'

# We should accept a future stable version.
env GOVERSION='go1.18.2'
# Note that we need to bump the version of Go that supposedly built it, too.
env GARBLE_TEST_GOVERSION='go1.28.2'
env TOOLCHAIN_GOVERSION='go1.28.2'
! garble build
stderr 'mocking the real build'

# We should accept custom devel strings.
env GOVERSION='devel go1.18-somecustomversion'
env TOOLCHAIN_GOVERSION='devel go1.18-somecustomversion'
! garble build
stderr 'mocking the real build'

# The current toolchain may be older than the one that built garble.
env GARBLE_TEST_GOVERSION='go1.18'
env TOOLCHAIN_GOVERSION='go1.17.3'
! garble build
stderr 'mocking the real build'

# The current toolchain may be equal to the one that built garble.
env GARBLE_TEST_GOVERSION='devel go1.19-6673d5d701 Sun Mar 20 16:05:03 2022 +0000'
env TOOLCHAIN_GOVERSION='devel go1.19-6673d5d701 Sun Mar 20 16:05:03 2022 +0000'
! garble build
stderr 'mocking the real build'

# The current toolchain must not be newer than the one that built garble.
env GARBLE_TEST_GOVERSION='go1.17'
env TOOLCHAIN_GOVERSION='go1.18.1'
! garble build
stderr 'garble was built with "go1\.17" and is being used with "go1\.18\.1"; please rebuild garble with the newer version'

# We'll error even if the difference is a minor (bugfix) level.
# In practice it probably wouldn't matter, but in theory it could still lead to tricky bugs.
env GARBLE_TEST_GOVERSION='go1.18.11'
env TOOLCHAIN_GOVERSION='go1.18.14'
! garble build
stderr 'garble was built with "go1\.18\.11" and is being used with "go1\.18\.14"; please rebuild garble with the newer version'

# If garble builds itself and is then used, it won't know what version built it.
# As a fallback, we drop the comparison against the toolchain's version.
env GARBLE_TEST_GOVERSION='bogus version'
env TOOLCHAIN_GOVERSION='go1.17.3'
! garble build
stderr 'mocking the real build'

Expand All @@ -64,7 +100,7 @@ func main() {
enc, _ := json.Marshal(struct{
GOVERSION string
} {
GOVERSION: os.Getenv("GOVERSION"),
GOVERSION: os.Getenv("TOOLCHAIN_GOVERSION"),
})
fmt.Printf("%s\n", enc)
return
Expand Down