Should go.sum file be checked in to the git repository? - go

I have a program with source code hosted on GitHub that uses Go Modules introduced in go 1.11.
go.mod file describes my dependencies, but go.sum file seems to be a lockfile. Should I be adding go.sum to my repository or should I gitignore it?

https://github.com/golang/go/wiki/Modules#releasing-modules-all-versions:
Ensure your go.sum file is committed along with your go.mod file.

(Building on a previous answer.)
Yes, commit go.sum.
Ensure your go.sum file is committed along with your go.mod file. See FAQ below for more details and rationale.
From the FAQ:
Should I commit my 'go.sum' file as well as my 'go.mod' file?
Typically your module's go.sum file should be committed along with
your go.mod file.
go.sum contains the expected cryptographic checksums of the content of specific module versions.
If someone clones your repository and downloads your dependencies using the go command, they will receive an error if there is any
mismatch between their downloaded copies of your dependencies and the
corresponding entries in your go.sum.
In addition, go mod verify checks that the on-disk cached copies of module downloads still match the entries in go.sum.
Note that go.sum is not a lock file as used in some alternative dependency management systems. (go.mod provides enough information
for reproducible builds).
See very brief rationale here from
Filippo Valsorda on why you should check in your go.sum. See the
"Module downloading and
verification"
section of the tip documentation for more details. See possible future
extensions being discussed for example in
#24117 and
#25530.

Related

go.sum are different when using go mod vendor/download

I have a problem with the usage of commands go mod vendor and go mod download in a go module.
When I'm using go mod vendor, the generated go.sum has extra-lines. E.g, when I'm using go mod download, the go.sum contains:
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
However if I remove the go.sum and run go mod vendor, I have 2 lines:
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
This is problematic because if I commit the go.sum after running go mod vendor, any further go mod download (which may be used by someone else or in CI) will not work because of mismatching hashes which lead to a security issue.
Is there something I'm doing wrong in the usage of go mod vendor and go mod download? Why would they produce different hashes in the go.sum?
Here is the kind of error which instantly happens:
verifying xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx#v0.1.0: checksum mismatch
downloaded: h1:tIKKCv/bUyBNvVsB6YLo0Ds9ZFdGJ0FKkFun22nwvCI=
go.sum: h1:qta5K5jjJg+TnsD76tcFK7Bjf402WP9MIbPsJGU11Ms=
SECURITY ERROR
This download does NOT match an earlier download recorded in go.sum.
The bits may have been replaced on the origin server, or an attacker may
have intercepted the download attempt.
(Note: I replaced the name of the package by xxx because it carries my company name)
The problem was actually that the git repository was using git-lfs, but git-lfs was not available on either client or server side, which lead to incoherent hashes when calculated with and without git-lfs.
The fact that go mod download did not add go.sum entries for the downloaded modules was arguably a bug, and it will be fixed in the upcoming Go 1.16 release (see https://golang.org/issue/41341).

How can I use a local repository in the vendor in Google Cloud Functions with Go

I'm trying to deploy a Google Cloud Function written in Go.
By doing some research I found out that vendor files are prefered over go.mod so I'm vendoring everything I use (which includes some local dependencies) and ignoring the go.mod/sum files in the .gcloudignore file.
The problem is that after trying to deploy, I get the following error:
go: nimbus#v0.0.0-00010101000000-000000000000: parsing /nimbus/go.mod: open /nimbus/go.mod: no such file or directory; Error ID: 03a1e2f7
nimbus is my local dependency and it has the following structure:
My Function repository has the following structrure:
and my go.mod file is:
module my_function
go 1.13
require nimbus v0.0.0-00010101000000-000000000000
replace nimbus => ../../../nimbus
I've tried this solution https://stackoverflow.com/questions/5441096 already. But it did not fix my issue.
I've tried everything to solve this issue, but nothing seems to work.
If you have a go.mod file and a vendor directory, the vendor directory will be ignored when you deploy your function.
https://cloud.google.com/functions/docs/writing/specifying-dependencies-go
I have used modules when deploying GCP functions in Go. Haven't had any problems. But I can't speak to the preference of using vendor/ instead. It should work, just without the go.mod file.
Turns out the problem was very complicated and I hope Google finds a solution for it asp.
By deploying my function using Cloud Build, It would read from my repository on Google Source, but, by reading from there it would bypass the .gcloudignore file and deploy both the go.mod/sum files and the vendor directory with my local code.
As said in https://stackoverflow.com/a/62050872/10316247:
If you have a go.mod file and a vendor directory, the vendor directory will be ignored when you deploy your function.
So the error would occur because of my go.mod not being able to find local repository.
My solution was to rename my go.mod/sum files so it would not be considered:
When you use golang 1.16 and specify golang 1.16 in the go.mod folder it will instead default to using the vendor files with the --mod=vendor flag set, which will solve this issue.
You'll just need to ensure your module name is formatted correctly (something like example.com/module).

Getting all dependencies of a Go project

For my project I am trying to get all the dependencies and sub dependencies of my project. I need to specific version of each of these dependencies. Not only do I need the dependencies of my project, but the dependencies of the dependencies and so on until the root.
For my project, go list -m all works for everything except indirect dependencies that have not opted into using go.mod files. Right now my workflow is taking an initial batch of repositories, downloading them from git then using “GO111MODULE=on go build ./…”. and “GO111MODULE=on go list -m -json all” to get the list of dependencies. I do not check for go.mod as all of the repositories I am scanning are using go.mod files.
For the list of dependencies that come out of this initial list I have some questions, for files without go.mod files, I used this as a reference: “https://blog.golang.org/using-go-modules”
-Path = Received from go list -m all, it can be GitHub, gopkg, or whatever is used to dl the go package.
Without go.mod
-“GO111MODULE=on go mod init <PATH from parent go.mod>”
-“GO111MODULE=on go build ./…”
-“GO111MODULE=on go mod tidy”
-“GO111MODULE=on go list -m -json all”
-From there I get a list of the dependencies of this module.
With go.mod
-“GO111MODULE=on go build ./…”
-“GO111MODULE=on go mod tidy”
-“GO111MODULE=on go list -m -json all”
Should I be running go build on each dependency that has a go.mod file? For ones without a go.mod file, I understand this should be done, as how else will we populate the go.mod file with the dependencies. But for files with a go.mod file, will I be pulling extra stuff that is not necessarily being used by my project with go build, like test files and other files that might not be used when I am simply importing that project? I understand that its better to get more unused dependencies rather than missing some, but it is getting a bit overwhelming with how massive the amount of dependencies is.
I can try to analyze go.sum file (when you execute go list -u, go.sum was created)
The go command uses the go.sum file to ensure that future downloads of these modules retrieve the same bits as the first download, to ensure the modules your project depends on do not change unexpectedly, whether for malicious, accidental, or other reasons. Both go.mod and go.sum should be checked into version control. (Using Go Modules - Adding a dependency)
go.sum file lists down the checksum (and version tag) of direct and indirect dependency required by the module.
% cat go.sum
...
github.com/bmizerany/perks v0.0.0-20141205001514-d9a9656a3a4b/go.mod h1:ac9efd0D1fsDb3EJvhqgXRbFx7bs2wqZ10HQPeU8U/Q=
github.com/c2h5oh/datasize v0.0.0-20171227191756-4eba002a5eae/go.mod h1:S/7n9copUssQ56c7aAgHqftWO4LTf4xY6CGWt8Bc+3M=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
...
The phrase “all the dependencies” is unfortunately ambiguous.
go list -m lists all modules whose selected versions are determined by your go.mod file. That is one possible definition of "all the dependencies", but it is a much broader set of modules than I think most people intend when they talk about the “dependencies” of a module.
In practice, go list -test all (without the -m flag) is the broadest set of dependencies I would generally care about: it includes all of the packages listed in import statements within your module (i.e. everything you need in order to run go test ./... within your module), plus all of the packages transitively needed to run go test on those packages.
(In particular, go list -test all is also the set of packages that will be resolved when you run go mod tidy.)

How to use modules replace functionality in cloud functions

I have a google cloud function that is a subdirectory in a repository. It uses the "Directory with source code" option in the settings menu. I keep getting this error on deploy:
Deployment failure:
Build failed: go: parsing /utils/pubsub/go.mod: open /utils/pubsub/go.mod: no such file or directory
go: error loading module requirements
I'm assuming that GCF does not upload the entire directory to the instance, but instead only the folder? This breaks the replace functionality of Go modules. Is there something I am doing wrong?
Link to the repo: https://github.com/FreekingDean/jeffbotgo/tree/5d735cc/slackevent
I work at Google and on this product.
Only the directory where you run gcloud is uploaded. There is no staging step beyond zipping the current directory and uploading it.
Notably, modules are preferred by the builder over vendor. If there is a go.mod, modules will be used. When you upload your function, it only includes the directory with your function at the root, not any directories one level up. So, when there is a go.mod and you have a replace directive pointing one level up, it will not work.
The solution for now with this layout is to vendor and not upload the go.mod/go.sum files. When using gcloud, you can create a .gcloudignore file to do this for you. See https://cloud.google.com/functions/docs/concepts/go-runtime#specifying_dependencies for more detail. Alternatively, modify your project to include any necessary helper packages in subdirectories.
I had the same issue today.
When reading thru the documentation for the 8th time i came across a warning box bellow the "Vendor directory" headline.
Warning: If your project has both a go.mod file and a vendor directory
at the root of your project, the vendor directory will be ignored
during deployment. You must use a .gcloudignore file to ignore the
go.mod file in order to ensure that your vendor directory is used
during deployment.
So basically once i added a .gcloudignore file with go.mod (will add go.sum as well) everything worked. So i guess if you have a go.mod file the cloud function will try to fetch dependencies instead of using the ones uploaded in the vendor folder.
I'm just guessing here tough.

Modifying an imported library in Go

My Problem
Elastic Beats is an open source project for log shippers written in Go. It features several log outputs, including console, Elasticsearch and Redis. I would like to add an output of my own - to AWS Kinesis.
I have cloned the repo to ~/github/beats, and tried building it:
$ cd filebeat; go build main.go
However, it failed due to a missing library which is a part of the project:
main.go:6:2: cannot find package "github.com/elastic/beats/filebeat/cmd" in any of:
/usr/local/go/src/github.com/elastic/beats/filebeat/cmd (from $GOROOT)
/Users/adam/go/src/github.com/elastic/beats/filebeat/cmd (from $GOPATH)
A directory of the project is dependent on a package from the same repo, but instead of looking one directory up the hierarchy it looks in the GOPATH.
So, go get github.com/elastic/beats/filebeat/cmd fetched the code, and now go build main.go works. Changing the code in my GOPATH is reflected in these builds.
This leaves me with an structural inconvenience. Some of my code is at a working directory, and some of it is at my GOPATH and included by the code in my working directory.
I would like to have all my code in a single directory for various reasons, not the least being keeping everything under version control.
What Have I Tried
Mostly searching for the problem. I am quite new to Go, so I might have missed the correct terminology.
My Question
What is the right way to edit the code of an imported library in Go?
One of the recommended ways to work with other's packages is:
Get the sources of the original package:
go get github.com/elastic/beats
As a result you will clone project's git repository to the folder
$GOPATH/src/github.com/elastic/beats
Make some fixes, compile code, fix, compile... When you make go install package will be compiled and installed to your system. When you need merge updates from original repository you can git pull them.
Everything is OK. What's next? How to share your work with others?
Fork project on github, suppose it will be github.com/username/beats
Add this fork as another remote mycopy (or any other name you like) to your local repository
git remote add mycopy git://github.com/username/beats.git
When all is done you can push updated sources to your repo on github
git push mycopy
and then open a pull-request to original sources. This way you can share your work with others. And keep your changes in sync with mainstream.
Previous answers to this question are obsolete when developing projects that using Go Modules.
For projects that using Go Modules, one may use the following command to replace an imported library(eg. example.com/imported/module) with a local module(eg. ./local/module):
go mod edit -replace=example.com/imported/module=./local/module
Or by adding the following line into the go.mod file:
replace example.com/imported/module => ./local/module
Reference Docs: https://golang.org/doc/modules/managing-dependencies#unpublished
A project working copy should be checked out into $GOPATH/src/package/import/path - for example, this project should be checked out into /Users/adam/go/src/github.com/elastic/beats. With the project in the correct location, the go tooling will be able to operate on it normally; otherwise, it will not be able to resolve imports correctly. See go help gopath for more info.

Resources