GoCenter: 1.12 and 1.13 Incorrect Pseudo-Versions Fix
Tags: go, devops
Published: 2020-01-13 18:08:45

# Problem Statement

GoCenter supports multiple module versions from 1.13 to all prior versions such as 1.12. Starting from Go 1.13, the Go client verifies the pseudo-version components against the version control metadata. According to the [release notes](https://golang.org/doc/go1.13), it verifies specifically:

- The version prefix must be of the form vX.0.0, or derived from a tag on an ancestor of the named revision, or derived from a tag that includes build metadata on the named revision itself.
- The date string must match the UTC timestamp of the revision.
- The short name of the revision must use the same number of characters as what the go command would generate. (For SHA-1 hashes as used by git, a 12-digit prefix.)

The Checksum Server also enforces those rules when serving checksum content.

Go versions before 1.13 do not enforce these rules about pseudo-version components. This means that, even though users were not supposed to generate pseudo-versions manually, they could have the same commit hash being used in multiple pseudo-versions without any issues.

GoCenter aims to be Go version agnostic (we support all Go module versions even prior to 1.13) while providing the same experience users were used to when resolving the dependencies from source. This causes it to also serve multiple pseudo-versions for the same commit hash if users request them. This is causing problems for Go 1.13 users when an incorrect pseudo-version is the latest available for a module in GoCenter. After resolving the module from the proxy, the Go client will try to fetch the checksum content from the Checksum Server, which enforces the pseudo-version component rules and refuses to serve the checksum content.

```
→ go get golang.org/x/crypto
go: finding golang.org/x/crypto latest
verifying golang.org/x/crypto@v0.0.0-20191227151644-53104e6ec876/go.mod: golang.org/x/crypto@v0.0.0-20191227151644-53104e6ec876/go.mod: reading https://gocenter.io/sumdb/sum.golang.org/lookup/golang.org/x/crypto@v0.0.0-20191227151644-53104e6ec876: 404 Not Found
```

# Proposed Solution

In order to be fully compatible with the other services in the ecosystem, we need to stop serving those incorrect pseudo-versions for Go 1.13 users while redirecting Go 1.12 users to the right pseudo-versions.

To achieve this, we need to change the metadata we serve on the .info request of the modules Download Protocol when an incorrect pseudo-version is requested to redirect the users to the right pseudo-versions.

```
→ curl https://gocenter.io/github.com/creack/pty/@v/v0.0.0-00000000000000-8ab47f72e854.info
{
"Name":"v1.1.10-0.20191209115840-8ab47f72e854",
"ShortName":"v1.1.10-0.20191209115840-8ab47f72e854",
"Version":"v1.1.10-0.20191209115840-8ab47f72e854",
"Time":"2020-01-09T06:29:04Z"
}%
```

# Provided User Experience

This redirection will be completely transparent for Go 1.12 users and they will get the right pseudo-version in their go.mod files:

```
→ go get -v github.com/creack/pty@v0.0.0-00000000000000-8ab47f72e854
go: finding github.com/creack/pty v0.0.0-00000000000000-8ab47f72e854
Fetching https://gocenter.io/github.com/creack/pty/@v/v0.0.0-00000000000000-8ab47f72e854.info
Fetching https://gocenter.io/github.com/creack/pty/@v/v1.1.10-0.20191209115840-8ab47f72e854.mod
go: downloading github.com/creack/pty v1.1.10-0.20191209115840-8ab47f72e854
Fetching https://gocenter.io/github.com/creack/pty/@v/v1.1.10-0.20191209115840-8ab47f72e854.zip
go: extracting github.com/creack/pty v1.1.10-0.20191209115840-8ab47f72e854

→ cat go.mod
module jfrog.com/eliom/module

go 1.12

require github.com/creack/pty v1.1.10-0.20191209115840-8ab47f72e854 // indirect
```

For Go 1.13 users, the Go client will fail the dependency resolution and display the right pseudo-version GoCenter wants to serve instead:

```
→ go get -v github.com/creack/pty@v0.0.0-00000000000000-8ab47f72e854
go: finding github.com v0.0.0-00000000000000-8ab47f72e854
go: finding github.com/creack v0.0.0-00000000000000-8ab47f72e854
go: finding github.com/creack/pty v0.0.0-00000000000000-8ab47f72e854
go get github.com/creack/pty@v0.0.0-00000000000000-8ab47f72e854: github.com/creack/pty@v0.0.0-00000000000000-8ab47f72e854: proxy returned info for version v1.1.10-0.20191209115840-8ab47f72e854 instead of requested version
```

Go 1.13 users will need to fix the go get command to point to the right pseudo-version or use the recommended go get approach for pseudo-versions by using only the commit hash as a version and delegating to the proxy to translate that to an actual pseudo-version:

```
→ go get -v github.com/creack/pty@8ab47f72e854
go: finding github.com 8ab47f72e854
go: finding github.com/creack/pty 8ab47f72e854
go: finding github.com/creack 8ab47f72e854
go: downloading github.com/creack/pty v1.1.10-0.20191209115840-8ab47f72e854
go: extracting github.com/creack/pty v1.1.10-0.20191209115840-8ab47f72e854
github.com/creack/pty

→ cat go.mod
module jfrog.com/eliom/module

go 1.13

require github.com/creack/pty v1.1.10-0.20191209115840-8ab47f72e854 // indirect
```

Additionally, if the user is not sure about the pseudo-versions declared in their go.mod files, they can rely on GoCenter to provide the actual pseudo-versions for their dependencies by removing all pseudo-version components except the commit hash and then running the go get command.

```
→ cat go.mod
module jfrog.com/eliom/module

go 1.13

require github.com/creack/pty 8ab47f72e854

→ go get -v
go: finding github.com/creack/pty 8ab47f72e854
go: downloading github.com/creack/pty v1.1.10-0.20191209115840-8ab47f72e854
go: extracting github.com/creack/pty v1.1.10-0.20191209115840-8ab47f72e854
jfrog.com/eliom/module

→ cat go.mod
module jfrog.com/eliom/module

go 1.13

require github.com/creack/pty v1.1.10-0.20191209115840-8ab47f72e854
```

GoCenter’s goal is to continue to support module versions prior to 1.13, and of course, we will continue to support module versions in 1.13 as well as 1.14 in the near future. To learn more about [GoCenter.io](https://search.gocenter.io/stats), checkout our [Wiki](https://github.com/jfrog/gocenter/wiki) and join us on [Slack](https://invite.slack.golangbridge.org/) at the channel #gocenter.