github.com/gernest/nezuko@v0.1.2/internal/modcmd/verify.go (about)

     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 modcmd
     6  
     7  import (
     8  	"bytes"
     9  	"fmt"
    10  	"io/ioutil"
    11  	"os"
    12  
    13  	"github.com/gernest/nezuko/internal/base"
    14  	"github.com/gernest/nezuko/internal/dirhash"
    15  	"github.com/gernest/nezuko/internal/modfetch"
    16  	"github.com/gernest/nezuko/internal/modload"
    17  	"github.com/gernest/nezuko/internal/module"
    18  )
    19  
    20  var cmdVerify = &base.Command{
    21  	UsageLine: "z mod verify",
    22  	Short:     "verify dependencies have expected content",
    23  	Long: `
    24  Verify checks that the dependencies of the current module,
    25  which are stored in a local downloaded source cache, have not been
    26  modified since being downloaded. If all the modules are unmodified,
    27  verify prints "all modules verified." Otherwise it reports which
    28  modules have been changed and causes 'z mod' to exit with a
    29  non-zero status.
    30  	`,
    31  	Run: runVerify,
    32  }
    33  
    34  func runVerify(cmd *base.Command, args []string) {
    35  	if len(args) != 0 {
    36  		// NOTE(rsc): Could take a module pattern.
    37  		base.Fatalf("z mod verify: verify takes no arguments")
    38  	}
    39  	ok := true
    40  	for _, mod := range modload.LoadBuildList()[1:] {
    41  		ok = verifyMod(mod) && ok
    42  	}
    43  	if ok {
    44  		fmt.Printf("all modules verified\n")
    45  	}
    46  }
    47  
    48  func verifyMod(mod module.Version) bool {
    49  	ok := true
    50  	zip, zipErr := modfetch.CachePath(mod, "zip")
    51  	if zipErr == nil {
    52  		_, zipErr = os.Stat(zip)
    53  	}
    54  	dir, dirErr := modfetch.DownloadDir(mod)
    55  	if dirErr == nil {
    56  		_, dirErr = os.Stat(dir)
    57  	}
    58  	data, err := ioutil.ReadFile(zip + "hash")
    59  	if err != nil {
    60  		if zipErr != nil && os.IsNotExist(zipErr) && dirErr != nil && os.IsNotExist(dirErr) {
    61  			// Nothing downloaded yet. Nothing to verify.
    62  			return true
    63  		}
    64  		base.Errorf("%s %s: missing ziphash: %v", mod.Path, mod.Version, err)
    65  		return false
    66  	}
    67  	h := string(bytes.TrimSpace(data))
    68  
    69  	if zipErr != nil && os.IsNotExist(zipErr) {
    70  		// ok
    71  	} else {
    72  		hZ, err := dirhash.HashZip(zip, dirhash.DefaultHash)
    73  		if err != nil {
    74  			base.Errorf("%s %s: %v", mod.Path, mod.Version, err)
    75  			return false
    76  		} else if hZ != h {
    77  			base.Errorf("%s %s: zip has been modified (%v)", mod.Path, mod.Version, zip)
    78  			ok = false
    79  		}
    80  	}
    81  	if dirErr != nil && os.IsNotExist(dirErr) {
    82  		// ok
    83  	} else {
    84  		hD, err := dirhash.HashDir(dir, mod.Path+"@"+mod.Version, dirhash.DefaultHash)
    85  		if err != nil {
    86  
    87  			base.Errorf("%s %s: %v", mod.Path, mod.Version, err)
    88  			return false
    89  		}
    90  		if hD != h {
    91  			base.Errorf("%s %s: dir has been modified (%v)", mod.Path, mod.Version, dir)
    92  			ok = false
    93  		}
    94  	}
    95  	return ok
    96  }