1
2
3
4
5 package modfetch
6
7 import (
8 "archive/zip"
9 "bytes"
10 "context"
11 "crypto/sha256"
12 "encoding/base64"
13 "errors"
14 "fmt"
15 "io"
16 "io/fs"
17 "os"
18 "path/filepath"
19 "sort"
20 "strings"
21 "sync"
22
23 "cmd/go/internal/base"
24 "cmd/go/internal/cfg"
25 "cmd/go/internal/fsys"
26 "cmd/go/internal/gover"
27 "cmd/go/internal/lockedfile"
28 "cmd/go/internal/par"
29 "cmd/go/internal/robustio"
30 "cmd/go/internal/str"
31 "cmd/go/internal/trace"
32
33 "golang.org/x/mod/module"
34 "golang.org/x/mod/sumdb/dirhash"
35 modzip "golang.org/x/mod/zip"
36 )
37
38 var downloadCache par.ErrCache[module.Version, string]
39
40 var ErrToolchain = errors.New("internal error: invalid operation on toolchain module")
41
42
43
44
45 func Download(ctx context.Context, mod module.Version) (dir string, err error) {
46 if gover.IsToolchain(mod.Path) {
47 return "", ErrToolchain
48 }
49 if err := checkCacheDir(ctx); err != nil {
50 base.Fatal(err)
51 }
52
53
54 return downloadCache.Do(mod, func() (string, error) {
55 dir, err := download(ctx, mod)
56 if err != nil {
57 return "", err
58 }
59 checkMod(ctx, mod)
60
61
62 if data, err := os.ReadFile(filepath.Join(dir, "go.mod")); err == nil {
63 goVersion := gover.GoModLookup(data, "go")
64 if gover.Compare(goVersion, gover.Local()) > 0 {
65 return "", &gover.TooNewError{What: mod.String(), GoVersion: goVersion}
66 }
67 } else if !errors.Is(err, fs.ErrNotExist) {
68 return "", err
69 }
70
71 return dir, nil
72 })
73 }
74
75 func download(ctx context.Context, mod module.Version) (dir string, err error) {
76 ctx, span := trace.StartSpan(ctx, "modfetch.download "+mod.String())
77 defer span.Done()
78
79 dir, err = DownloadDir(ctx, mod)
80 if err == nil {
81
82 return dir, nil
83 } else if dir == "" || !errors.Is(err, fs.ErrNotExist) {
84 return "", err
85 }
86
87
88
89
90 zipfile, err := DownloadZip(ctx, mod)
91 if err != nil {
92 return "", err
93 }
94
95 unlock, err := lockVersion(ctx, mod)
96 if err != nil {
97 return "", err
98 }
99 defer unlock()
100
101 ctx, span = trace.StartSpan(ctx, "unzip "+zipfile)
102 defer span.Done()
103
104
105 _, dirErr := DownloadDir(ctx, mod)
106 if dirErr == nil {
107 return dir, nil
108 }
109 _, dirExists := dirErr.(*DownloadDirPartialError)
110
111
112
113
114
115
116 parentDir := filepath.Dir(dir)
117 tmpPrefix := filepath.Base(dir) + ".tmp-"
118 if old, err := filepath.Glob(filepath.Join(str.QuoteGlob(parentDir), str.QuoteGlob(tmpPrefix)+"*")); err == nil {
119 for _, path := range old {
120 RemoveAll(path)
121 }
122 }
123 if dirExists {
124 if err := RemoveAll(dir); err != nil {
125 return "", err
126 }
127 }
128
129 partialPath, err := CachePath(ctx, mod, "partial")
130 if err != nil {
131 return "", err
132 }
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148 if err := os.MkdirAll(parentDir, 0777); err != nil {
149 return "", err
150 }
151 if err := os.WriteFile(partialPath, nil, 0666); err != nil {
152 return "", err
153 }
154 if err := modzip.Unzip(dir, mod, zipfile); err != nil {
155 fmt.Fprintf(os.Stderr, "-> %s\n", err)
156 if rmErr := RemoveAll(dir); rmErr == nil {
157 os.Remove(partialPath)
158 }
159 return "", err
160 }
161 if err := os.Remove(partialPath); err != nil {
162 return "", err
163 }
164
165 if !cfg.ModCacheRW {
166 makeDirsReadOnly(dir)
167 }
168 return dir, nil
169 }
170
171 var downloadZipCache par.ErrCache[module.Version, string]
172
173
174
175 func DownloadZip(ctx context.Context, mod module.Version) (zipfile string, err error) {
176
177 return downloadZipCache.Do(mod, func() (string, error) {
178 zipfile, err := CachePath(ctx, mod, "zip")
179 if err != nil {
180 return "", err
181 }
182 ziphashfile := zipfile + "hash"
183
184
185 if _, err := os.Stat(zipfile); err == nil {
186 if _, err := os.Stat(ziphashfile); err == nil {
187 return zipfile, nil
188 }
189 }
190
191
192 if cfg.CmdName != "mod download" {
193 vers := mod.Version
194 if mod.Path == "golang.org/toolchain" {
195
196 _, vers, _ = strings.Cut(vers, "-")
197 if i := strings.LastIndex(vers, "."); i >= 0 {
198 goos, goarch, _ := strings.Cut(vers[i+1:], "-")
199 vers = vers[:i] + " (" + goos + "/" + goarch + ")"
200 }
201 fmt.Fprintf(os.Stderr, "go: downloading %s\n", vers)
202 } else {
203 fmt.Fprintf(os.Stderr, "go: downloading %s %s\n", mod.Path, vers)
204 }
205 }
206 unlock, err := lockVersion(ctx, mod)
207 if err != nil {
208 return "", err
209 }
210 defer unlock()
211
212 if err := downloadZip(ctx, mod, zipfile); err != nil {
213 return "", err
214 }
215 return zipfile, nil
216 })
217 }
218
219 func downloadZip(ctx context.Context, mod module.Version, zipfile string) (err error) {
220 ctx, span := trace.StartSpan(ctx, "modfetch.downloadZip "+zipfile)
221 defer span.Done()
222
223
224
225 ziphashfile := zipfile + "hash"
226 var zipExists, ziphashExists bool
227 if _, err := os.Stat(zipfile); err == nil {
228 zipExists = true
229 }
230 if _, err := os.Stat(ziphashfile); err == nil {
231 ziphashExists = true
232 }
233 if zipExists && ziphashExists {
234 return nil
235 }
236
237
238 if err := os.MkdirAll(filepath.Dir(zipfile), 0777); err != nil {
239 return err
240 }
241
242
243
244
245 tmpPattern := filepath.Base(zipfile) + "*.tmp"
246 if old, err := filepath.Glob(filepath.Join(str.QuoteGlob(filepath.Dir(zipfile)), tmpPattern)); err == nil {
247 for _, path := range old {
248 os.Remove(path)
249 }
250 }
251
252
253
254 if zipExists {
255 return hashZip(mod, zipfile, ziphashfile)
256 }
257
258
259
260
261
262
263 f, err := tempFile(ctx, filepath.Dir(zipfile), filepath.Base(zipfile), 0666)
264 if err != nil {
265 return err
266 }
267 defer func() {
268 if err != nil {
269 f.Close()
270 os.Remove(f.Name())
271 }
272 }()
273
274 var unrecoverableErr error
275 err = TryProxies(func(proxy string) error {
276 if unrecoverableErr != nil {
277 return unrecoverableErr
278 }
279 repo := Lookup(ctx, proxy, mod.Path)
280 err := repo.Zip(ctx, f, mod.Version)
281 if err != nil {
282
283
284
285
286 if _, err := f.Seek(0, io.SeekStart); err != nil {
287 unrecoverableErr = err
288 return err
289 }
290 if err := f.Truncate(0); err != nil {
291 unrecoverableErr = err
292 return err
293 }
294 }
295 return err
296 })
297 if err != nil {
298 return err
299 }
300
301
302
303
304 fi, err := f.Stat()
305 if err != nil {
306 return err
307 }
308 z, err := zip.NewReader(f, fi.Size())
309 if err != nil {
310 return err
311 }
312 prefix := mod.Path + "@" + mod.Version + "/"
313 for _, f := range z.File {
314 if !strings.HasPrefix(f.Name, prefix) {
315 return fmt.Errorf("zip for %s has unexpected file %s", prefix[:len(prefix)-1], f.Name)
316 }
317 }
318
319 if err := f.Close(); err != nil {
320 return err
321 }
322
323
324 if err := hashZip(mod, f.Name(), ziphashfile); err != nil {
325 return err
326 }
327 if err := os.Rename(f.Name(), zipfile); err != nil {
328 return err
329 }
330
331
332
333 return nil
334 }
335
336
337
338
339
340
341 func hashZip(mod module.Version, zipfile, ziphashfile string) (err error) {
342 hash, err := dirhash.HashZip(zipfile, dirhash.DefaultHash)
343 if err != nil {
344 return err
345 }
346 if err := checkModSum(mod, hash); err != nil {
347 return err
348 }
349 hf, err := lockedfile.Create(ziphashfile)
350 if err != nil {
351 return err
352 }
353 defer func() {
354 if closeErr := hf.Close(); err == nil && closeErr != nil {
355 err = closeErr
356 }
357 }()
358 if err := hf.Truncate(int64(len(hash))); err != nil {
359 return err
360 }
361 if _, err := hf.WriteAt([]byte(hash), 0); err != nil {
362 return err
363 }
364 return nil
365 }
366
367
368
369 func makeDirsReadOnly(dir string) {
370 type pathMode struct {
371 path string
372 mode fs.FileMode
373 }
374 var dirs []pathMode
375 filepath.WalkDir(dir, func(path string, d fs.DirEntry, err error) error {
376 if err == nil && d.IsDir() {
377 info, err := d.Info()
378 if err == nil && info.Mode()&0222 != 0 {
379 dirs = append(dirs, pathMode{path, info.Mode()})
380 }
381 }
382 return nil
383 })
384
385
386 for i := len(dirs) - 1; i >= 0; i-- {
387 os.Chmod(dirs[i].path, dirs[i].mode&^0222)
388 }
389 }
390
391
392
393 func RemoveAll(dir string) error {
394
395 filepath.WalkDir(dir, func(path string, info fs.DirEntry, err error) error {
396 if err != nil {
397 return nil
398 }
399 if info.IsDir() {
400 os.Chmod(path, 0777)
401 }
402 return nil
403 })
404 return robustio.RemoveAll(dir)
405 }
406
407 var GoSumFile string
408 var WorkspaceGoSumFiles []string
409
410 type modSum struct {
411 mod module.Version
412 sum string
413 }
414
415 var goSum struct {
416 mu sync.Mutex
417 m map[module.Version][]string
418 w map[string]map[module.Version][]string
419 status map[modSum]modSumStatus
420 overwrite bool
421 enabled bool
422 }
423
424 type modSumStatus struct {
425 used, dirty bool
426 }
427
428
429
430 func Reset() {
431 GoSumFile = ""
432 WorkspaceGoSumFiles = nil
433
434
435
436
437 lookupCache = par.Cache[lookupCacheKey, Repo]{}
438 downloadCache = par.ErrCache[module.Version, string]{}
439
440
441 goSum.mu.Lock()
442 goSum.m = nil
443 goSum.w = nil
444 goSum.status = nil
445 goSum.overwrite = false
446 goSum.enabled = false
447 goSum.mu.Unlock()
448 }
449
450
451
452
453
454 func initGoSum() (bool, error) {
455 if GoSumFile == "" {
456 return false, nil
457 }
458 if goSum.m != nil {
459 return true, nil
460 }
461
462 goSum.m = make(map[module.Version][]string)
463 goSum.status = make(map[modSum]modSumStatus)
464 goSum.w = make(map[string]map[module.Version][]string)
465
466 for _, f := range WorkspaceGoSumFiles {
467 goSum.w[f] = make(map[module.Version][]string)
468 _, err := readGoSumFile(goSum.w[f], f)
469 if err != nil {
470 return false, err
471 }
472 }
473
474 enabled, err := readGoSumFile(goSum.m, GoSumFile)
475 goSum.enabled = enabled
476 return enabled, err
477 }
478
479 func readGoSumFile(dst map[module.Version][]string, file string) (bool, error) {
480 var (
481 data []byte
482 err error
483 )
484 if actualSumFile, ok := fsys.OverlayPath(file); ok {
485
486
487
488 data, err = os.ReadFile(actualSumFile)
489 } else {
490 data, err = lockedfile.Read(file)
491 }
492 if err != nil && !os.IsNotExist(err) {
493 return false, err
494 }
495 readGoSum(dst, file, data)
496
497 return true, nil
498 }
499
500
501
502
503 const emptyGoModHash = "h1:G7mAYYxgmS0lVkHyy2hEOLQCFB0DlQFTMLWggykrydY="
504
505
506
507 func readGoSum(dst map[module.Version][]string, file string, data []byte) {
508 lineno := 0
509 for len(data) > 0 {
510 var line []byte
511 lineno++
512 i := bytes.IndexByte(data, '\n')
513 if i < 0 {
514 line, data = data, nil
515 } else {
516 line, data = data[:i], data[i+1:]
517 }
518 f := strings.Fields(string(line))
519 if len(f) == 0 {
520
521 continue
522 }
523 if len(f) != 3 {
524 if cfg.CmdName == "mod tidy" {
525
526 continue
527 } else {
528 base.Fatalf("malformed go.sum:\n%s:%d: wrong number of fields %v\n", file, lineno, len(f))
529 }
530 }
531 if f[2] == emptyGoModHash {
532
533 continue
534 }
535 mod := module.Version{Path: f[0], Version: f[1]}
536 dst[mod] = append(dst[mod], f[2])
537 }
538 }
539
540
541
542
543
544 func HaveSum(mod module.Version) bool {
545 goSum.mu.Lock()
546 defer goSum.mu.Unlock()
547 inited, err := initGoSum()
548 if err != nil || !inited {
549 return false
550 }
551 for _, goSums := range goSum.w {
552 for _, h := range goSums[mod] {
553 if !strings.HasPrefix(h, "h1:") {
554 continue
555 }
556 if !goSum.status[modSum{mod, h}].dirty {
557 return true
558 }
559 }
560 }
561 for _, h := range goSum.m[mod] {
562 if !strings.HasPrefix(h, "h1:") {
563 continue
564 }
565 if !goSum.status[modSum{mod, h}].dirty {
566 return true
567 }
568 }
569 return false
570 }
571
572
573
574
575
576
577
578 func RecordedSum(mod module.Version) (sum string, ok bool) {
579 goSum.mu.Lock()
580 defer goSum.mu.Unlock()
581 inited, err := initGoSum()
582 foundSum := ""
583 if err != nil || !inited {
584 return "", false
585 }
586 for _, goSums := range goSum.w {
587 for _, h := range goSums[mod] {
588 if !strings.HasPrefix(h, "h1:") {
589 continue
590 }
591 if !goSum.status[modSum{mod, h}].dirty {
592 if foundSum != "" && foundSum != h {
593 return "", false
594 }
595 foundSum = h
596 }
597 }
598 }
599 for _, h := range goSum.m[mod] {
600 if !strings.HasPrefix(h, "h1:") {
601 continue
602 }
603 if !goSum.status[modSum{mod, h}].dirty {
604 if foundSum != "" && foundSum != h {
605 return "", false
606 }
607 foundSum = h
608 }
609 }
610 return foundSum, true
611 }
612
613
614 func checkMod(ctx context.Context, mod module.Version) {
615
616 ziphash, err := CachePath(ctx, mod, "ziphash")
617 if err != nil {
618 base.Fatalf("verifying %v", module.VersionError(mod, err))
619 }
620 data, err := lockedfile.Read(ziphash)
621 if err != nil {
622 base.Fatalf("verifying %v", module.VersionError(mod, err))
623 }
624 data = bytes.TrimSpace(data)
625 if !isValidSum(data) {
626
627 zip, err := CachePath(ctx, mod, "zip")
628 if err != nil {
629 base.Fatalf("verifying %v", module.VersionError(mod, err))
630 }
631 err = hashZip(mod, zip, ziphash)
632 if err != nil {
633 base.Fatalf("verifying %v", module.VersionError(mod, err))
634 }
635 return
636 }
637 h := string(data)
638 if !strings.HasPrefix(h, "h1:") {
639 base.Fatalf("verifying %v", module.VersionError(mod, fmt.Errorf("unexpected ziphash: %q", h)))
640 }
641
642 if err := checkModSum(mod, h); err != nil {
643 base.Fatalf("%s", err)
644 }
645 }
646
647
648 func goModSum(data []byte) (string, error) {
649 return dirhash.Hash1([]string{"go.mod"}, func(string) (io.ReadCloser, error) {
650 return io.NopCloser(bytes.NewReader(data)), nil
651 })
652 }
653
654
655
656 func checkGoMod(path, version string, data []byte) error {
657 h, err := goModSum(data)
658 if err != nil {
659 return &module.ModuleError{Path: path, Version: version, Err: fmt.Errorf("verifying go.mod: %v", err)}
660 }
661
662 return checkModSum(module.Version{Path: path, Version: version + "/go.mod"}, h)
663 }
664
665
666
667
668
669 func checkModSum(mod module.Version, h string) error {
670
671
672
673
674
675
676 goSum.mu.Lock()
677 inited, err := initGoSum()
678 if err != nil {
679 goSum.mu.Unlock()
680 return err
681 }
682 done := inited && haveModSumLocked(mod, h)
683 if inited {
684 st := goSum.status[modSum{mod, h}]
685 st.used = true
686 goSum.status[modSum{mod, h}] = st
687 }
688 goSum.mu.Unlock()
689
690 if done {
691 return nil
692 }
693
694
695
696 if useSumDB(mod) {
697
698 if err := checkSumDB(mod, h); err != nil {
699 return err
700 }
701 }
702
703
704 if inited {
705 goSum.mu.Lock()
706 addModSumLocked(mod, h)
707 st := goSum.status[modSum{mod, h}]
708 st.dirty = true
709 goSum.status[modSum{mod, h}] = st
710 goSum.mu.Unlock()
711 }
712 return nil
713 }
714
715
716
717
718 func haveModSumLocked(mod module.Version, h string) bool {
719 sumFileName := "go.sum"
720 if strings.HasSuffix(GoSumFile, "go.work.sum") {
721 sumFileName = "go.work.sum"
722 }
723 for _, vh := range goSum.m[mod] {
724 if h == vh {
725 return true
726 }
727 if strings.HasPrefix(vh, "h1:") {
728 base.Fatalf("verifying %s@%s: checksum mismatch\n\tdownloaded: %v\n\t%s: %v"+goSumMismatch, mod.Path, mod.Version, h, sumFileName, vh)
729 }
730 }
731
732 foundMatch := false
733
734
735 for goSumFile, goSums := range goSum.w {
736 for _, vh := range goSums[mod] {
737 if h == vh {
738 foundMatch = true
739 } else if strings.HasPrefix(vh, "h1:") {
740 base.Fatalf("verifying %s@%s: checksum mismatch\n\tdownloaded: %v\n\t%s: %v"+goSumMismatch, mod.Path, mod.Version, h, goSumFile, vh)
741 }
742 }
743 }
744 return foundMatch
745 }
746
747
748
749 func addModSumLocked(mod module.Version, h string) {
750 if haveModSumLocked(mod, h) {
751 return
752 }
753 if len(goSum.m[mod]) > 0 {
754 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)
755 }
756 goSum.m[mod] = append(goSum.m[mod], h)
757 }
758
759
760
761 func checkSumDB(mod module.Version, h string) error {
762 modWithoutSuffix := mod
763 noun := "module"
764 if before, found := strings.CutSuffix(mod.Version, "/go.mod"); found {
765 noun = "go.mod"
766 modWithoutSuffix.Version = before
767 }
768
769 db, lines, err := lookupSumDB(mod)
770 if err != nil {
771 return module.VersionError(modWithoutSuffix, fmt.Errorf("verifying %s: %v", noun, err))
772 }
773
774 have := mod.Path + " " + mod.Version + " " + h
775 prefix := mod.Path + " " + mod.Version + " h1:"
776 for _, line := range lines {
777 if line == have {
778 return nil
779 }
780 if strings.HasPrefix(line, prefix) {
781 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:"):]))
782 }
783 }
784 return nil
785 }
786
787
788
789 func Sum(ctx context.Context, mod module.Version) string {
790 if cfg.GOMODCACHE == "" {
791
792 return ""
793 }
794
795 ziphash, err := CachePath(ctx, mod, "ziphash")
796 if err != nil {
797 return ""
798 }
799 data, err := lockedfile.Read(ziphash)
800 if err != nil {
801 return ""
802 }
803 data = bytes.TrimSpace(data)
804 if !isValidSum(data) {
805 return ""
806 }
807 return string(data)
808 }
809
810
811
812
813
814
815 func isValidSum(data []byte) bool {
816 if bytes.IndexByte(data, '\000') >= 0 {
817 return false
818 }
819
820 if len(data) != len("h1:")+base64.StdEncoding.EncodedLen(sha256.Size) {
821 return false
822 }
823
824 return true
825 }
826
827 var ErrGoSumDirty = errors.New("updates to go.sum needed, disabled by -mod=readonly")
828
829
830
831
832
833
834
835 func WriteGoSum(ctx context.Context, keep map[module.Version]bool, readonly bool) error {
836 goSum.mu.Lock()
837 defer goSum.mu.Unlock()
838
839
840 if !goSum.enabled {
841 return nil
842 }
843
844
845
846
847 dirty := false
848 Outer:
849 for m, hs := range goSum.m {
850 for _, h := range hs {
851 st := goSum.status[modSum{m, h}]
852 if st.dirty && (!st.used || keep[m]) {
853 dirty = true
854 break Outer
855 }
856 }
857 }
858 if !dirty {
859 return nil
860 }
861 if readonly {
862 return ErrGoSumDirty
863 }
864 if _, ok := fsys.OverlayPath(GoSumFile); ok {
865 base.Fatalf("go: updates to go.sum needed, but go.sum is part of the overlay specified with -overlay")
866 }
867
868
869
870 if unlock, err := SideLock(ctx); err == nil {
871 defer unlock()
872 }
873
874 err := lockedfile.Transform(GoSumFile, func(data []byte) ([]byte, error) {
875 tidyGoSum := tidyGoSum(data, keep)
876 return tidyGoSum, nil
877 })
878
879 if err != nil {
880 return fmt.Errorf("updating go.sum: %w", err)
881 }
882
883 goSum.status = make(map[modSum]modSumStatus)
884 goSum.overwrite = false
885 return nil
886 }
887
888
889
890 func TidyGoSum(keep map[module.Version]bool) (before, after []byte) {
891 goSum.mu.Lock()
892 defer goSum.mu.Unlock()
893 before, err := lockedfile.Read(GoSumFile)
894 if err != nil && !errors.Is(err, fs.ErrNotExist) {
895 base.Fatalf("reading go.sum: %v", err)
896 }
897 after = tidyGoSum(before, keep)
898 return before, after
899 }
900
901
902
903 func tidyGoSum(data []byte, keep map[module.Version]bool) []byte {
904 if !goSum.overwrite {
905
906
907
908
909 goSum.m = make(map[module.Version][]string, len(goSum.m))
910 readGoSum(goSum.m, GoSumFile, data)
911 for ms, st := range goSum.status {
912 if st.used && !sumInWorkspaceModulesLocked(ms.mod) {
913 addModSumLocked(ms.mod, ms.sum)
914 }
915 }
916 }
917
918 var mods []module.Version
919 for m := range goSum.m {
920 mods = append(mods, m)
921 }
922 module.Sort(mods)
923
924 var buf bytes.Buffer
925 for _, m := range mods {
926 list := goSum.m[m]
927 sort.Strings(list)
928 str.Uniq(&list)
929 for _, h := range list {
930 st := goSum.status[modSum{m, h}]
931 if (!st.dirty || (st.used && keep[m])) && !sumInWorkspaceModulesLocked(m) {
932 fmt.Fprintf(&buf, "%s %s %s\n", m.Path, m.Version, h)
933 }
934 }
935 }
936 return buf.Bytes()
937 }
938
939 func sumInWorkspaceModulesLocked(m module.Version) bool {
940 for _, goSums := range goSum.w {
941 if _, ok := goSums[m]; ok {
942 return true
943 }
944 }
945 return false
946 }
947
948
949
950
951
952
953
954 func TrimGoSum(keep map[module.Version]bool) {
955 goSum.mu.Lock()
956 defer goSum.mu.Unlock()
957 inited, err := initGoSum()
958 if err != nil {
959 base.Fatalf("%s", err)
960 }
961 if !inited {
962 return
963 }
964
965 for m, hs := range goSum.m {
966 if !keep[m] {
967 for _, h := range hs {
968 goSum.status[modSum{m, h}] = modSumStatus{used: false, dirty: true}
969 }
970 goSum.overwrite = true
971 }
972 }
973 }
974
975 const goSumMismatch = `
976
977 SECURITY ERROR
978 This download does NOT match an earlier download recorded in go.sum.
979 The bits may have been replaced on the origin server, or an attacker may
980 have intercepted the download attempt.
981
982 For more information, see 'go help module-auth'.
983 `
984
985 const sumdbMismatch = `
986
987 SECURITY ERROR
988 This download does NOT match the one reported by the checksum server.
989 The bits may have been replaced on the origin server, or an attacker may
990 have intercepted the download attempt.
991
992 For more information, see 'go help module-auth'.
993 `
994
995 const hashVersionMismatch = `
996
997 SECURITY WARNING
998 This download is listed in go.sum, but using an unknown hash algorithm.
999 The download cannot be verified.
1000
1001 For more information, see 'go help module-auth'.
1002
1003 `
1004
1005 var HelpModuleAuth = &base.Command{
1006 UsageLine: "module-auth",
1007 Short: "module authentication using go.sum",
1008 Long: `
1009 When the go command downloads a module zip file or go.mod file into the
1010 module cache, it computes a cryptographic hash and compares it with a known
1011 value to verify the file hasn't changed since it was first downloaded. Known
1012 hashes are stored in a file in the module root directory named go.sum. Hashes
1013 may also be downloaded from the checksum database depending on the values of
1014 GOSUMDB, GOPRIVATE, and GONOSUMDB.
1015
1016 For details, see https://golang.org/ref/mod#authenticating.
1017 `,
1018 }
1019
1020 var HelpPrivate = &base.Command{
1021 UsageLine: "private",
1022 Short: "configuration for downloading non-public code",
1023 Long: `
1024 The go command defaults to downloading modules from the public Go module
1025 mirror at proxy.golang.org. It also defaults to validating downloaded modules,
1026 regardless of source, against the public Go checksum database at sum.golang.org.
1027 These defaults work well for publicly available source code.
1028
1029 The GOPRIVATE environment variable controls which modules the go command
1030 considers to be private (not available publicly) and should therefore not use
1031 the proxy or checksum database. The variable is a comma-separated list of
1032 glob patterns (in the syntax of Go's path.Match) of module path prefixes.
1033 For example,
1034
1035 GOPRIVATE=*.corp.example.com,rsc.io/private
1036
1037 causes the go command to treat as private any module with a path prefix
1038 matching either pattern, including git.corp.example.com/xyzzy, rsc.io/private,
1039 and rsc.io/private/quux.
1040
1041 For fine-grained control over module download and validation, the GONOPROXY
1042 and GONOSUMDB environment variables accept the same kind of glob list
1043 and override GOPRIVATE for the specific decision of whether to use the proxy
1044 and checksum database, respectively.
1045
1046 For example, if a company ran a module proxy serving private modules,
1047 users would configure go using:
1048
1049 GOPRIVATE=*.corp.example.com
1050 GOPROXY=proxy.example.com
1051 GONOPROXY=none
1052
1053 The GOPRIVATE variable is also used to define the "public" and "private"
1054 patterns for the GOVCS variable; see 'go help vcs'. For that usage,
1055 GOPRIVATE applies even in GOPATH mode. In that case, it matches import paths
1056 instead of module paths.
1057
1058 The 'go env -w' command (see 'go help env') can be used to set these variables
1059 for future go command invocations.
1060
1061 For more details, see https://golang.org/ref/mod#private-modules.
1062 `,
1063 }
1064
View as plain text