cmd/go/internal/modfetch: do not use mangled version strings to construct module.VersionErrors

Better still would be to avoid passing around module.Version instances
with invalid Version strings in the first place, so that any time we
see a module.Version we know that it is actually a version of a module
(and not a structurally-similar datum with something else tacked on to
one of the fields). But that's a bigger cleanup for which I don't
currently have enough bandwidth.

Fixes #41060

Change-Id: I32fba5619105cbf67dd03691064c82b8ebb3ce18
Reviewed-on: https://go-review.googlesource.com/c/go/+/250951
Run-TryBot: Bryan C. Mills <bcmills@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Jay Conrod <jayconrod@google.com>
Reviewed-by: Michael Matloob <matloob@golang.org>
diff --git a/src/cmd/go/internal/modfetch/fetch.go b/src/cmd/go/internal/modfetch/fetch.go
index e29eb0a..01d8f00 100644
--- a/src/cmd/go/internal/modfetch/fetch.go
+++ b/src/cmd/go/internal/modfetch/fetch.go
@@ -503,6 +503,9 @@
 }
 
 // checkModSum checks that the recorded checksum for mod is h.
+//
+// mod.Version may have the additional suffix "/go.mod" to request the checksum
+// for the module's go.mod file only.
 func checkModSum(mod module.Version, h string) error {
 	// We lock goSum when manipulating it,
 	// but we arrange to release the lock when calling checkSumDB,
@@ -579,9 +582,16 @@
 // checkSumDB checks the mod, h pair against the Go checksum database.
 // It calls base.Fatalf if the hash is to be rejected.
 func checkSumDB(mod module.Version, h string) error {
+	modWithoutSuffix := mod
+	noun := "module"
+	if strings.HasSuffix(mod.Version, "/go.mod") {
+		noun = "go.mod"
+		modWithoutSuffix.Version = strings.TrimSuffix(mod.Version, "/go.mod")
+	}
+
 	db, lines, err := lookupSumDB(mod)
 	if err != nil {
-		return module.VersionError(mod, fmt.Errorf("verifying module: %v", err))
+		return module.VersionError(modWithoutSuffix, fmt.Errorf("verifying %s: %v", noun, err))
 	}
 
 	have := mod.Path + " " + mod.Version + " " + h
@@ -591,7 +601,7 @@
 			return nil
 		}
 		if strings.HasPrefix(line, prefix) {
-			return module.VersionError(mod, fmt.Errorf("verifying module: checksum mismatch\n\tdownloaded: %v\n\t%s: %v"+sumdbMismatch, h, db, line[len(prefix)-len("h1:"):]))
+			return module.VersionError(modWithoutSuffix, fmt.Errorf("verifying %s: checksum mismatch\n\tdownloaded: %v\n\t%s: %v"+sumdbMismatch, noun, h, db, line[len(prefix)-len("h1:"):]))
 		}
 	}
 	return nil
diff --git a/src/cmd/go/testdata/script/mod_download_json.txt b/src/cmd/go/testdata/script/mod_download_json.txt
index 2629168..9555adf 100644
--- a/src/cmd/go/testdata/script/mod_download_json.txt
+++ b/src/cmd/go/testdata/script/mod_download_json.txt
@@ -3,7 +3,7 @@
 
 # download -json with version should print JSON on sumdb failure
 ! go mod download -json 'rsc.io/quote@<=v1.5.0'
-stdout '"Error": ".*verifying module'
+stdout '"Error": ".*verifying (module|go.mod)'
 
 -- go.mod --
 module m
diff --git a/src/cmd/go/testdata/script/mod_sumdb.txt b/src/cmd/go/testdata/script/mod_sumdb.txt
index caf97e9..68bbd9c 100644
--- a/src/cmd/go/testdata/script/mod_sumdb.txt
+++ b/src/cmd/go/testdata/script/mod_sumdb.txt
@@ -15,6 +15,12 @@
 stderr 'SECURITY ERROR\nThis download does NOT match the one reported by the checksum server.'
 ! go get -d rsc.io/sampler
 ! go get -d golang.org/x/text
+
+go mod edit -require rsc.io/quote@v1.5.2
+! go list all
+stderr 'go: rsc.io/quote@v1.5.2: verifying go.mod: checksum mismatch'
+stderr 'SECURITY ERROR\n'
+
 rm go.sum
 
 # switching to truthful sumdb detects timeline inconsistency