...

Source file src/pkg/cmd/go/internal/modfetch/fetch.go

     1	// Copyright 2018 The Go Authors. All rights reserved.
     2	// Use of this source code is governed by a BSD-style
     3	// license that can be found in the LICENSE file.
     4	
     5	package modfetch
     6	
     7	import (
     8		"archive/zip"
     9		"bytes"
    10		"fmt"
    11		"io"
    12		"io/ioutil"
    13		"os"
    14		"path/filepath"
    15		"sort"
    16		"strings"
    17		"sync"
    18	
    19		"cmd/go/internal/base"
    20		"cmd/go/internal/cfg"
    21		"cmd/go/internal/dirhash"
    22		"cmd/go/internal/module"
    23		"cmd/go/internal/par"
    24		"cmd/go/internal/renameio"
    25	)
    26	
    27	var downloadCache par.Cache
    28	
    29	// Download downloads the specific module version to the
    30	// local download cache and returns the name of the directory
    31	// corresponding to the root of the module's file tree.
    32	func Download(mod module.Version) (dir string, err error) {
    33		if PkgMod == "" {
    34			// Do not download to current directory.
    35			return "", fmt.Errorf("missing modfetch.PkgMod")
    36		}
    37	
    38		// The par.Cache here avoids duplicate work.
    39		type cached struct {
    40			dir string
    41			err error
    42		}
    43		c := downloadCache.Do(mod, func() interface{} {
    44			dir, err := DownloadDir(mod)
    45			if err != nil {
    46				return cached{"", err}
    47			}
    48			if err := download(mod, dir); err != nil {
    49				return cached{"", err}
    50			}
    51			checkMod(mod)
    52			return cached{dir, nil}
    53		}).(cached)
    54		return c.dir, c.err
    55	}
    56	
    57	func download(mod module.Version, dir string) (err error) {
    58		// If the directory exists, the module has already been extracted.
    59		fi, err := os.Stat(dir)
    60		if err == nil && fi.IsDir() {
    61			return nil
    62		}
    63	
    64		// To avoid cluttering the cache with extraneous files,
    65		// DownloadZip uses the same lockfile as Download.
    66		// Invoke DownloadZip before locking the file.
    67		zipfile, err := DownloadZip(mod)
    68		if err != nil {
    69			return err
    70		}
    71	
    72		if cfg.CmdName != "mod download" {
    73			fmt.Fprintf(os.Stderr, "go: extracting %s %s\n", mod.Path, mod.Version)
    74		}
    75	
    76		unlock, err := lockVersion(mod)
    77		if err != nil {
    78			return err
    79		}
    80		defer unlock()
    81	
    82		// Check whether the directory was populated while we were waiting on the lock.
    83		fi, err = os.Stat(dir)
    84		if err == nil && fi.IsDir() {
    85			return nil
    86		}
    87	
    88		// Clean up any remaining temporary directories from previous runs.
    89		// This is only safe to do because the lock file ensures that their writers
    90		// are no longer active.
    91		parentDir := filepath.Dir(dir)
    92		tmpPrefix := filepath.Base(dir) + ".tmp-"
    93		if old, err := filepath.Glob(filepath.Join(parentDir, tmpPrefix+"*")); err == nil {
    94			for _, path := range old {
    95				RemoveAll(path) // best effort
    96			}
    97		}
    98	
    99		// Extract the zip file to a temporary directory, then rename it to the
   100		// final path. That way, we can use the existence of the source directory to
   101		// signal that it has been extracted successfully, and if someone deletes
   102		// the entire directory (e.g. as an attempt to prune out file corruption)
   103		// the module cache will still be left in a recoverable state.
   104		if err := os.MkdirAll(parentDir, 0777); err != nil {
   105			return err
   106		}
   107		tmpDir, err := ioutil.TempDir(parentDir, tmpPrefix)
   108		if err != nil {
   109			return err
   110		}
   111		defer func() {
   112			if err != nil {
   113				RemoveAll(tmpDir)
   114			}
   115		}()
   116	
   117		modpath := mod.Path + "@" + mod.Version
   118		if err := Unzip(tmpDir, zipfile, modpath, 0); err != nil {
   119			fmt.Fprintf(os.Stderr, "-> %s\n", err)
   120			return err
   121		}
   122	
   123		if err := os.Rename(tmpDir, dir); err != nil {
   124			return err
   125		}
   126	
   127		// Make dir read-only only *after* renaming it.
   128		// os.Rename was observed to fail for read-only directories on macOS.
   129		makeDirsReadOnly(dir)
   130		return nil
   131	}
   132	
   133	var downloadZipCache par.Cache
   134	
   135	// DownloadZip downloads the specific module version to the
   136	// local zip cache and returns the name of the zip file.
   137	func DownloadZip(mod module.Version) (zipfile string, err error) {
   138		// The par.Cache here avoids duplicate work.
   139		type cached struct {
   140			zipfile string
   141			err     error
   142		}
   143		c := downloadZipCache.Do(mod, func() interface{} {
   144			zipfile, err := CachePath(mod, "zip")
   145			if err != nil {
   146				return cached{"", err}
   147			}
   148	
   149			// Skip locking if the zipfile already exists.
   150			if _, err := os.Stat(zipfile); err == nil {
   151				return cached{zipfile, nil}
   152			}
   153	
   154			// The zip file does not exist. Acquire the lock and create it.
   155			if cfg.CmdName != "mod download" {
   156				fmt.Fprintf(os.Stderr, "go: downloading %s %s\n", mod.Path, mod.Version)
   157			}
   158			unlock, err := lockVersion(mod)
   159			if err != nil {
   160				return cached{"", err}
   161			}
   162			defer unlock()
   163	
   164			// Double-check that the zipfile was not created while we were waiting for
   165			// the lock.
   166			if _, err := os.Stat(zipfile); err == nil {
   167				return cached{zipfile, nil}
   168			}
   169			if err := os.MkdirAll(filepath.Dir(zipfile), 0777); err != nil {
   170				return cached{"", err}
   171			}
   172			if err := downloadZip(mod, zipfile); err != nil {
   173				return cached{"", err}
   174			}
   175			return cached{zipfile, nil}
   176		}).(cached)
   177		return c.zipfile, c.err
   178	}
   179	
   180	func downloadZip(mod module.Version, zipfile string) (err error) {
   181		// Clean up any remaining tempfiles from previous runs.
   182		// This is only safe to do because the lock file ensures that their
   183		// writers are no longer active.
   184		for _, base := range []string{zipfile, zipfile + "hash"} {
   185			if old, err := filepath.Glob(renameio.Pattern(base)); err == nil {
   186				for _, path := range old {
   187					os.Remove(path) // best effort
   188				}
   189			}
   190		}
   191	
   192		// From here to the os.Rename call below is functionally almost equivalent to
   193		// renameio.WriteToFile, with one key difference: we want to validate the
   194		// contents of the file (by hashing it) before we commit it. Because the file
   195		// is zip-compressed, we need an actual file — or at least an io.ReaderAt — to
   196		// validate it: we can't just tee the stream as we write it.
   197		f, err := ioutil.TempFile(filepath.Dir(zipfile), filepath.Base(renameio.Pattern(zipfile)))
   198		if err != nil {
   199			return err
   200		}
   201		defer func() {
   202			if err != nil {
   203				f.Close()
   204				os.Remove(f.Name())
   205			}
   206		}()
   207	
   208		err = TryProxies(func(proxy string) error {
   209			repo, err := Lookup(proxy, mod.Path)
   210			if err != nil {
   211				return err
   212			}
   213			return repo.Zip(f, mod.Version)
   214		})
   215		if err != nil {
   216			return err
   217		}
   218	
   219		// Double-check that the paths within the zip file are well-formed.
   220		//
   221		// TODO(bcmills): There is a similar check within the Unzip function. Can we eliminate one?
   222		fi, err := f.Stat()
   223		if err != nil {
   224			return err
   225		}
   226		z, err := zip.NewReader(f, fi.Size())
   227		if err != nil {
   228			return err
   229		}
   230		prefix := mod.Path + "@" + mod.Version + "/"
   231		for _, f := range z.File {
   232			if !strings.HasPrefix(f.Name, prefix) {
   233				return fmt.Errorf("zip for %s has unexpected file %s", prefix[:len(prefix)-1], f.Name)
   234			}
   235		}
   236	
   237		// Sync the file before renaming it: otherwise, after a crash the reader may
   238		// observe a 0-length file instead of the actual contents.
   239		// See https://golang.org/issue/22397#issuecomment-380831736.
   240		if err := f.Sync(); err != nil {
   241			return err
   242		}
   243		if err := f.Close(); err != nil {
   244			return err
   245		}
   246	
   247		// Hash the zip file and check the sum before renaming to the final location.
   248		hash, err := dirhash.HashZip(f.Name(), dirhash.DefaultHash)
   249		if err != nil {
   250			return err
   251		}
   252		checkModSum(mod, hash)
   253	
   254		if err := renameio.WriteFile(zipfile+"hash", []byte(hash), 0666); err != nil {
   255			return err
   256		}
   257		if err := os.Rename(f.Name(), zipfile); err != nil {
   258			return err
   259		}
   260	
   261		// TODO(bcmills): Should we make the .zip and .ziphash files read-only to discourage tampering?
   262	
   263		return nil
   264	}
   265	
   266	var GoSumFile string // path to go.sum; set by package modload
   267	
   268	type modSum struct {
   269		mod module.Version
   270		sum string
   271	}
   272	
   273	var goSum struct {
   274		mu        sync.Mutex
   275		m         map[module.Version][]string // content of go.sum file (+ go.modverify if present)
   276		checked   map[modSum]bool             // sums actually checked during execution
   277		dirty     bool                        // whether we added any new sums to m
   278		overwrite bool                        // if true, overwrite go.sum without incorporating its contents
   279		enabled   bool                        // whether to use go.sum at all
   280		modverify string                      // path to go.modverify, to be deleted
   281	}
   282	
   283	// initGoSum initializes the go.sum data.
   284	// It reports whether use of go.sum is now enabled.
   285	// The goSum lock must be held.
   286	func initGoSum() bool {
   287		if GoSumFile == "" {
   288			return false
   289		}
   290		if goSum.m != nil {
   291			return true
   292		}
   293	
   294		goSum.m = make(map[module.Version][]string)
   295		goSum.checked = make(map[modSum]bool)
   296		data, err := renameio.ReadFile(GoSumFile)
   297		if err != nil && !os.IsNotExist(err) {
   298			base.Fatalf("go: %v", err)
   299		}
   300		goSum.enabled = true
   301		readGoSum(goSum.m, GoSumFile, data)
   302	
   303		// Add old go.modverify file.
   304		// We'll delete go.modverify in WriteGoSum.
   305		alt := strings.TrimSuffix(GoSumFile, ".sum") + ".modverify"
   306		if data, err := renameio.ReadFile(alt); err == nil {
   307			migrate := make(map[module.Version][]string)
   308			readGoSum(migrate, alt, data)
   309			for mod, sums := range migrate {
   310				for _, sum := range sums {
   311					addModSumLocked(mod, sum)
   312				}
   313			}
   314			goSum.modverify = alt
   315		}
   316		return true
   317	}
   318	
   319	// emptyGoModHash is the hash of a 1-file tree containing a 0-length go.mod.
   320	// A bug caused us to write these into go.sum files for non-modules.
   321	// We detect and remove them.
   322	const emptyGoModHash = "h1:G7mAYYxgmS0lVkHyy2hEOLQCFB0DlQFTMLWggykrydY="
   323	
   324	// readGoSum parses data, which is the content of file,
   325	// and adds it to goSum.m. The goSum lock must be held.
   326	func readGoSum(dst map[module.Version][]string, file string, data []byte) {
   327		lineno := 0
   328		for len(data) > 0 {
   329			var line []byte
   330			lineno++
   331			i := bytes.IndexByte(data, '\n')
   332			if i < 0 {
   333				line, data = data, nil
   334			} else {
   335				line, data = data[:i], data[i+1:]
   336			}
   337			f := strings.Fields(string(line))
   338			if len(f) == 0 {
   339				// blank line; skip it
   340				continue
   341			}
   342			if len(f) != 3 {
   343				base.Fatalf("go: malformed go.sum:\n%s:%d: wrong number of fields %v", file, lineno, len(f))
   344			}
   345			if f[2] == emptyGoModHash {
   346				// Old bug; drop it.
   347				continue
   348			}
   349			mod := module.Version{Path: f[0], Version: f[1]}
   350			dst[mod] = append(dst[mod], f[2])
   351		}
   352	}
   353	
   354	// checkMod checks the given module's checksum.
   355	func checkMod(mod module.Version) {
   356		if PkgMod == "" {
   357			// Do not use current directory.
   358			return
   359		}
   360	
   361		// Do the file I/O before acquiring the go.sum lock.
   362		ziphash, err := CachePath(mod, "ziphash")
   363		if err != nil {
   364			base.Fatalf("verifying %s@%s: %v", mod.Path, mod.Version, err)
   365		}
   366		data, err := renameio.ReadFile(ziphash)
   367		if err != nil {
   368			if os.IsNotExist(err) {
   369				// This can happen if someone does rm -rf GOPATH/src/cache/download. So it goes.
   370				return
   371			}
   372			base.Fatalf("verifying %s@%s: %v", mod.Path, mod.Version, err)
   373		}
   374		h := strings.TrimSpace(string(data))
   375		if !strings.HasPrefix(h, "h1:") {
   376			base.Fatalf("verifying %s@%s: unexpected ziphash: %q", mod.Path, mod.Version, h)
   377		}
   378	
   379		checkModSum(mod, h)
   380	}
   381	
   382	// goModSum returns the checksum for the go.mod contents.
   383	func goModSum(data []byte) (string, error) {
   384		return dirhash.Hash1([]string{"go.mod"}, func(string) (io.ReadCloser, error) {
   385			return ioutil.NopCloser(bytes.NewReader(data)), nil
   386		})
   387	}
   388	
   389	// checkGoMod checks the given module's go.mod checksum;
   390	// data is the go.mod content.
   391	func checkGoMod(path, version string, data []byte) {
   392		h, err := goModSum(data)
   393		if err != nil {
   394			base.Fatalf("verifying %s %s go.mod: %v", path, version, err)
   395		}
   396	
   397		checkModSum(module.Version{Path: path, Version: version + "/go.mod"}, h)
   398	}
   399	
   400	// checkModSum checks that the recorded checksum for mod is h.
   401	func checkModSum(mod module.Version, h string) {
   402		// We lock goSum when manipulating it,
   403		// but we arrange to release the lock when calling checkSumDB,
   404		// so that parallel calls to checkModHash can execute parallel calls
   405		// to checkSumDB.
   406	
   407		// Check whether mod+h is listed in go.sum already. If so, we're done.
   408		goSum.mu.Lock()
   409		inited := initGoSum()
   410		done := inited && haveModSumLocked(mod, h)
   411		goSum.mu.Unlock()
   412	
   413		if done {
   414			return
   415		}
   416	
   417		// Not listed, so we want to add them.
   418		// Consult checksum database if appropriate.
   419		if useSumDB(mod) {
   420			// Calls base.Fatalf if mismatch detected.
   421			checkSumDB(mod, h)
   422		}
   423	
   424		// Add mod+h to go.sum, if it hasn't appeared already.
   425		if inited {
   426			goSum.mu.Lock()
   427			addModSumLocked(mod, h)
   428			goSum.mu.Unlock()
   429		}
   430	}
   431	
   432	// haveModSumLocked reports whether the pair mod,h is already listed in go.sum.
   433	// If it finds a conflicting pair instead, it calls base.Fatalf.
   434	// goSum.mu must be locked.
   435	func haveModSumLocked(mod module.Version, h string) bool {
   436		goSum.checked[modSum{mod, h}] = true
   437		for _, vh := range goSum.m[mod] {
   438			if h == vh {
   439				return true
   440			}
   441			if strings.HasPrefix(vh, "h1:") {
   442				base.Fatalf("verifying %s@%s: checksum mismatch\n\tdownloaded: %v\n\tgo.sum:     %v"+goSumMismatch, mod.Path, mod.Version, h, vh)
   443			}
   444		}
   445		return false
   446	}
   447	
   448	// addModSumLocked adds the pair mod,h to go.sum.
   449	// goSum.mu must be locked.
   450	func addModSumLocked(mod module.Version, h string) {
   451		if haveModSumLocked(mod, h) {
   452			return
   453		}
   454		if len(goSum.m[mod]) > 0 {
   455			fmt.Fprintf(os.Stderr, "warning: verifying %s@%s: unknown hashes in go.sum: %v; adding %v"+hashVersionMismatch, mod.Path, mod.Version, strings.Join(goSum.m[mod], ", "), h)
   456		}
   457		goSum.m[mod] = append(goSum.m[mod], h)
   458		goSum.dirty = true
   459	}
   460	
   461	// checkSumDB checks the mod, h pair against the Go checksum database.
   462	// It calls base.Fatalf if the hash is to be rejected.
   463	func checkSumDB(mod module.Version, h string) {
   464		db, lines, err := lookupSumDB(mod)
   465		if err != nil {
   466			base.Fatalf("verifying %s@%s: %v", mod.Path, mod.Version, err)
   467		}
   468	
   469		have := mod.Path + " " + mod.Version + " " + h
   470		prefix := mod.Path + " " + mod.Version + " h1:"
   471		for _, line := range lines {
   472			if line == have {
   473				return
   474			}
   475			if strings.HasPrefix(line, prefix) {
   476				base.Fatalf("verifying %s@%s: checksum mismatch\n\tdownloaded: %v\n\t%s: %v"+sumdbMismatch, mod.Path, mod.Version, h, db, line[len(prefix)-len("h1:"):])
   477			}
   478		}
   479	}
   480	
   481	// Sum returns the checksum for the downloaded copy of the given module,
   482	// if present in the download cache.
   483	func Sum(mod module.Version) string {
   484		if PkgMod == "" {
   485			// Do not use current directory.
   486			return ""
   487		}
   488	
   489		ziphash, err := CachePath(mod, "ziphash")
   490		if err != nil {
   491			return ""
   492		}
   493		data, err := renameio.ReadFile(ziphash)
   494		if err != nil {
   495			return ""
   496		}
   497		return strings.TrimSpace(string(data))
   498	}
   499	
   500	// WriteGoSum writes the go.sum file if it needs to be updated.
   501	func WriteGoSum() {
   502		goSum.mu.Lock()
   503		defer goSum.mu.Unlock()
   504	
   505		if !goSum.enabled {
   506			// If we haven't read the go.sum file yet, don't bother writing it: at best,
   507			// we could rename the go.modverify file if it isn't empty, but we haven't
   508			// needed to touch it so far — how important could it be?
   509			return
   510		}
   511		if !goSum.dirty {
   512			// Don't bother opening the go.sum file if we don't have anything to add.
   513			return
   514		}
   515		if cfg.BuildMod == "readonly" {
   516			base.Fatalf("go: updates to go.sum needed, disabled by -mod=readonly")
   517		}
   518	
   519		// We want to avoid races between creating the lockfile and deleting it, but
   520		// we also don't want to leave a permanent lockfile in the user's repository.
   521		//
   522		// On top of that, if we crash while writing go.sum, we don't want to lose the
   523		// sums that were already present in the file, so it's important that we write
   524		// the file by renaming rather than truncating — which means that we can't
   525		// lock the go.sum file itself.
   526		//
   527		// Instead, we'll lock a distinguished file in the cache directory: that will
   528		// only race if the user runs `go clean -modcache` concurrently with a command
   529		// that updates go.sum, and that's already racy to begin with.
   530		//
   531		// We'll end up slightly over-synchronizing go.sum writes if the user runs a
   532		// bunch of go commands that update sums in separate modules simultaneously,
   533		// but that's unlikely to matter in practice.
   534	
   535		unlock := SideLock()
   536		defer unlock()
   537	
   538		if !goSum.overwrite {
   539			// Re-read the go.sum file to incorporate any sums added by other processes
   540			// in the meantime.
   541			data, err := renameio.ReadFile(GoSumFile)
   542			if err != nil && !os.IsNotExist(err) {
   543				base.Fatalf("go: re-reading go.sum: %v", err)
   544			}
   545	
   546			// Add only the sums that we actually checked: the user may have edited or
   547			// truncated the file to remove erroneous hashes, and we shouldn't restore
   548			// them without good reason.
   549			goSum.m = make(map[module.Version][]string, len(goSum.m))
   550			readGoSum(goSum.m, GoSumFile, data)
   551			for ms := range goSum.checked {
   552				addModSumLocked(ms.mod, ms.sum)
   553				goSum.dirty = true
   554			}
   555		}
   556	
   557		var mods []module.Version
   558		for m := range goSum.m {
   559			mods = append(mods, m)
   560		}
   561		module.Sort(mods)
   562		var buf bytes.Buffer
   563		for _, m := range mods {
   564			list := goSum.m[m]
   565			sort.Strings(list)
   566			for _, h := range list {
   567				fmt.Fprintf(&buf, "%s %s %s\n", m.Path, m.Version, h)
   568			}
   569		}
   570	
   571		if err := renameio.WriteFile(GoSumFile, buf.Bytes(), 0666); err != nil {
   572			base.Fatalf("go: writing go.sum: %v", err)
   573		}
   574	
   575		goSum.checked = make(map[modSum]bool)
   576		goSum.dirty = false
   577		goSum.overwrite = false
   578	
   579		if goSum.modverify != "" {
   580			os.Remove(goSum.modverify) // best effort
   581		}
   582	}
   583	
   584	// TrimGoSum trims go.sum to contain only the modules for which keep[m] is true.
   585	func TrimGoSum(keep map[module.Version]bool) {
   586		goSum.mu.Lock()
   587		defer goSum.mu.Unlock()
   588		if !initGoSum() {
   589			return
   590		}
   591	
   592		for m := range goSum.m {
   593			// If we're keeping x@v we also keep x@v/go.mod.
   594			// Map x@v/go.mod back to x@v for the keep lookup.
   595			noGoMod := module.Version{Path: m.Path, Version: strings.TrimSuffix(m.Version, "/go.mod")}
   596			if !keep[m] && !keep[noGoMod] {
   597				delete(goSum.m, m)
   598				goSum.dirty = true
   599				goSum.overwrite = true
   600			}
   601		}
   602	}
   603	
   604	const goSumMismatch = `
   605	
   606	SECURITY ERROR
   607	This download does NOT match an earlier download recorded in go.sum.
   608	The bits may have been replaced on the origin server, or an attacker may
   609	have intercepted the download attempt.
   610	
   611	For more information, see 'go help module-auth'.
   612	`
   613	
   614	const sumdbMismatch = `
   615	
   616	SECURITY ERROR
   617	This download does NOT match the one reported by the checksum server.
   618	The bits may have been replaced on the origin server, or an attacker may
   619	have intercepted the download attempt.
   620	
   621	For more information, see 'go help module-auth'.
   622	`
   623	
   624	const hashVersionMismatch = `
   625	
   626	SECURITY WARNING
   627	This download is listed in go.sum, but using an unknown hash algorithm.
   628	The download cannot be verified.
   629	
   630	For more information, see 'go help module-auth'.
   631	
   632	`
   633	
   634	var HelpModuleAuth = &base.Command{
   635		UsageLine: "module-auth",
   636		Short:     "module authentication using go.sum",
   637		Long: `
   638	The go command tries to authenticate every downloaded module,
   639	checking that the bits downloaded for a specific module version today
   640	match bits downloaded yesterday. This ensures repeatable builds
   641	and detects introduction of unexpected changes, malicious or not.
   642	
   643	In each module's root, alongside go.mod, the go command maintains
   644	a file named go.sum containing the cryptographic checksums of the
   645	module's dependencies.
   646	
   647	The form of each line in go.sum is three fields:
   648	
   649		<module> <version>[/go.mod] <hash>
   650	
   651	Each known module version results in two lines in the go.sum file.
   652	The first line gives the hash of the module version's file tree.
   653	The second line appends "/go.mod" to the version and gives the hash
   654	of only the module version's (possibly synthesized) go.mod file.
   655	The go.mod-only hash allows downloading and authenticating a
   656	module version's go.mod file, which is needed to compute the
   657	dependency graph, without also downloading all the module's source code.
   658	
   659	The hash begins with an algorithm prefix of the form "h<N>:".
   660	The only defined algorithm prefix is "h1:", which uses SHA-256.
   661	
   662	Module authentication failures
   663	
   664	The go command maintains a cache of downloaded packages and computes
   665	and records the cryptographic checksum of each package at download time.
   666	In normal operation, the go command checks the main module's go.sum file
   667	against these precomputed checksums instead of recomputing them on
   668	each command invocation. The 'go mod verify' command checks that
   669	the cached copies of module downloads still match both their recorded
   670	checksums and the entries in go.sum.
   671	
   672	In day-to-day development, the checksum of a given module version
   673	should never change. Each time a dependency is used by a given main
   674	module, the go command checks its local cached copy, freshly
   675	downloaded or not, against the main module's go.sum. If the checksums
   676	don't match, the go command reports the mismatch as a security error
   677	and refuses to run the build. When this happens, proceed with caution:
   678	code changing unexpectedly means today's build will not match
   679	yesterday's, and the unexpected change may not be beneficial.
   680	
   681	If the go command reports a mismatch in go.sum, the downloaded code
   682	for the reported module version does not match the one used in a
   683	previous build of the main module. It is important at that point
   684	to find out what the right checksum should be, to decide whether
   685	go.sum is wrong or the downloaded code is wrong. Usually go.sum is right:
   686	you want to use the same code you used yesterday.
   687	
   688	If a downloaded module is not yet included in go.sum and it is a publicly
   689	available module, the go command consults the Go checksum database to fetch
   690	the expected go.sum lines. If the downloaded code does not match those
   691	lines, the go command reports the mismatch and exits. Note that the
   692	database is not consulted for module versions already listed in go.sum.
   693	
   694	If a go.sum mismatch is reported, it is always worth investigating why
   695	the code downloaded today differs from what was downloaded yesterday.
   696	
   697	The GOSUMDB environment variable identifies the name of checksum database
   698	to use and optionally its public key and URL, as in:
   699	
   700		GOSUMDB="sum.golang.org"
   701		GOSUMDB="sum.golang.org+<publickey>"
   702		GOSUMDB="sum.golang.org+<publickey> https://sum.golang.org"
   703	
   704	The go command knows the public key of sum.golang.org, and also that the name
   705	sum.golang.google.cn (available inside mainland China) connects to the
   706	sum.golang.org checksum database; use of any other database requires giving
   707	the public key explicitly.
   708	The URL defaults to "https://" followed by the database name.
   709	
   710	GOSUMDB defaults to "sum.golang.org", the Go checksum database run by Google.
   711	See https://sum.golang.org/privacy for the service's privacy policy.
   712	
   713	If GOSUMDB is set to "off", or if "go get" is invoked with the -insecure flag,
   714	the checksum database is not consulted, and all unrecognized modules are
   715	accepted, at the cost of giving up the security guarantee of verified repeatable
   716	downloads for all modules. A better way to bypass the checksum database
   717	for specific modules is to use the GOPRIVATE or GONOSUMDB environment
   718	variables. See 'go help module-private' for details.
   719	
   720	The 'go env -w' command (see 'go help env') can be used to set these variables
   721	for future go command invocations.
   722	`,
   723	}
   724	
   725	var HelpModulePrivate = &base.Command{
   726		UsageLine: "module-private",
   727		Short:     "module configuration for non-public modules",
   728		Long: `
   729	The go command defaults to downloading modules from the public Go module
   730	mirror at proxy.golang.org. It also defaults to validating downloaded modules,
   731	regardless of source, against the public Go checksum database at sum.golang.org.
   732	These defaults work well for publicly available source code.
   733	
   734	The GOPRIVATE environment variable controls which modules the go command
   735	considers to be private (not available publicly) and should therefore not use the
   736	proxy or checksum database. The variable is a comma-separated list of
   737	glob patterns (in the syntax of Go's path.Match) of module path prefixes.
   738	For example,
   739	
   740		GOPRIVATE=*.corp.example.com,rsc.io/private
   741	
   742	causes the go command to treat as private any module with a path prefix
   743	matching either pattern, including git.corp.example.com/xyzzy, rsc.io/private,
   744	and rsc.io/private/quux.
   745	
   746	The GOPRIVATE environment variable may be used by other tools as well to
   747	identify non-public modules. For example, an editor could use GOPRIVATE
   748	to decide whether to hyperlink a package import to a godoc.org page.
   749	
   750	For fine-grained control over module download and validation, the GONOPROXY
   751	and GONOSUMDB environment variables accept the same kind of glob list
   752	and override GOPRIVATE for the specific decision of whether to use the proxy
   753	and checksum database, respectively.
   754	
   755	For example, if a company ran a module proxy serving private modules,
   756	users would configure go using:
   757	
   758		GOPRIVATE=*.corp.example.com
   759		GOPROXY=proxy.example.com
   760		GONOPROXY=none
   761	
   762	This would tell the go command and other tools that modules beginning with
   763	a corp.example.com subdomain are private but that the company proxy should
   764	be used for downloading both public and private modules, because
   765	GONOPROXY has been set to a pattern that won't match any modules,
   766	overriding GOPRIVATE.
   767	
   768	The 'go env -w' command (see 'go help env') can be used to set these variables
   769	for future go command invocations.
   770	`,
   771	}
   772	

View as plain text