From 76b70ebeb44b0b21e39e2b9546839bac612c253c Mon Sep 17 00:00:00 2001 From: Ettore Di Giacinto Date: Fri, 9 Jul 2021 11:52:23 +0200 Subject: [PATCH] Add dirhash to package signatures While this breaks current hashing, it ties also the spec content to the hash, in this way if we change something in the spec folder, it breaks the hashing for the package. Signed-off-by: Ettore Di Giacinto --- go.mod | 1 + go.sum | 2 + pkg/compiler/types/spec/spec.go | 7 +- vendor/golang.org/x/mod/semver/semver.go | 3 + vendor/golang.org/x/mod/sumdb/dirhash/hash.go | 132 ++++++++++++++++++ vendor/modules.txt | 4 +- 6 files changed, 147 insertions(+), 2 deletions(-) create mode 100644 vendor/golang.org/x/mod/sumdb/dirhash/hash.go diff --git a/go.mod b/go.mod index a7e9633e..7e75895b 100644 --- a/go.mod +++ b/go.mod @@ -56,6 +56,7 @@ require ( go.uber.org/atomic v1.5.1 // indirect go.uber.org/multierr v1.4.0 go.uber.org/zap v1.13.0 + golang.org/x/mod v0.4.2 google.golang.org/grpc v1.29.1 gopkg.in/yaml.v2 v2.3.0 gotest.tools/v3 v3.0.2 // indirect diff --git a/go.sum b/go.sum index 3735524d..f40de25a 100644 --- a/go.sum +++ b/go.sum @@ -1493,6 +1493,8 @@ golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzB golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= diff --git a/pkg/compiler/types/spec/spec.go b/pkg/compiler/types/spec/spec.go index d8221bc4..8c7768ea 100644 --- a/pkg/compiler/types/spec/spec.go +++ b/pkg/compiler/types/spec/spec.go @@ -26,6 +26,7 @@ import ( pkg "github.com/mudler/luet/pkg/package" "github.com/mudler/luet/pkg/solver" "github.com/otiai10/copy" + dirhash "golang.org/x/mod/sumdb/dirhash" yaml "gopkg.in/yaml.v2" ) @@ -269,7 +270,11 @@ func (cs *LuetCompilationSpec) Hash() (string, error) { // build a signature, we want to be part of the hash only the fields that are relevant for build purposes signature := cs.signature() h, err := hashstructure.Hash(signature, hashstructure.FormatV2, nil) - return fmt.Sprint(h), err + sum, err := dirhash.HashDir(cs.Package.Path, "", dirhash.DefaultHash) + if err != nil { + return "", err + } + return fmt.Sprint(h, sum), err } func (cs *LuetCompilationSpec) CopyRetrieves(dest string) error { diff --git a/vendor/golang.org/x/mod/semver/semver.go b/vendor/golang.org/x/mod/semver/semver.go index 2988e3cf..4338f351 100644 --- a/vendor/golang.org/x/mod/semver/semver.go +++ b/vendor/golang.org/x/mod/semver/semver.go @@ -138,6 +138,9 @@ func Compare(v, w string) int { // Max canonicalizes its arguments and then returns the version string // that compares greater. +// +// Deprecated: use Compare instead. In most cases, returning a canonicalized +// version is not expected or desired. func Max(v, w string) string { v = Canonical(v) w = Canonical(w) diff --git a/vendor/golang.org/x/mod/sumdb/dirhash/hash.go b/vendor/golang.org/x/mod/sumdb/dirhash/hash.go new file mode 100644 index 00000000..ef5df6f5 --- /dev/null +++ b/vendor/golang.org/x/mod/sumdb/dirhash/hash.go @@ -0,0 +1,132 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package dirhash defines hashes over directory trees. +// These hashes are recorded in go.sum files and in the Go checksum database, +// to allow verifying that a newly-downloaded module has the expected content. +package dirhash + +import ( + "archive/zip" + "crypto/sha256" + "encoding/base64" + "errors" + "fmt" + "io" + "os" + "path/filepath" + "sort" + "strings" +) + +// DefaultHash is the default hash function used in new go.sum entries. +var DefaultHash Hash = Hash1 + +// A Hash is a directory hash function. +// It accepts a list of files along with a function that opens the content of each file. +// It opens, reads, hashes, and closes each file and returns the overall directory hash. +type Hash func(files []string, open func(string) (io.ReadCloser, error)) (string, error) + +// Hash1 is the "h1:" directory hash function, using SHA-256. +// +// Hash1 is "h1:" followed by the base64-encoded SHA-256 hash of a summary +// prepared as if by the Unix command: +// +// find . -type f | sort | sha256sum +// +// More precisely, the hashed summary contains a single line for each file in the list, +// ordered by sort.Strings applied to the file names, where each line consists of +// the hexadecimal SHA-256 hash of the file content, +// two spaces (U+0020), the file name, and a newline (U+000A). +// +// File names with newlines (U+000A) are disallowed. +func Hash1(files []string, open func(string) (io.ReadCloser, error)) (string, error) { + h := sha256.New() + files = append([]string(nil), files...) + sort.Strings(files) + for _, file := range files { + if strings.Contains(file, "\n") { + return "", errors.New("dirhash: filenames with newlines are not supported") + } + r, err := open(file) + if err != nil { + return "", err + } + hf := sha256.New() + _, err = io.Copy(hf, r) + r.Close() + if err != nil { + return "", err + } + fmt.Fprintf(h, "%x %s\n", hf.Sum(nil), file) + } + return "h1:" + base64.StdEncoding.EncodeToString(h.Sum(nil)), nil +} + +// HashDir returns the hash of the local file system directory dir, +// replacing the directory name itself with prefix in the file names +// used in the hash function. +func HashDir(dir, prefix string, hash Hash) (string, error) { + files, err := DirFiles(dir, prefix) + if err != nil { + return "", err + } + osOpen := func(name string) (io.ReadCloser, error) { + return os.Open(filepath.Join(dir, strings.TrimPrefix(name, prefix))) + } + return hash(files, osOpen) +} + +// DirFiles returns the list of files in the tree rooted at dir, +// replacing the directory name dir with prefix in each name. +// The resulting names always use forward slashes. +func DirFiles(dir, prefix string) ([]string, error) { + var files []string + dir = filepath.Clean(dir) + err := filepath.Walk(dir, func(file string, info os.FileInfo, err error) error { + if err != nil { + return err + } + if info.IsDir() { + return nil + } + rel := file + if dir != "." { + rel = file[len(dir)+1:] + } + f := filepath.Join(prefix, rel) + files = append(files, filepath.ToSlash(f)) + return nil + }) + if err != nil { + return nil, err + } + return files, nil +} + +// HashZip returns the hash of the file content in the named zip file. +// Only the file names and their contents are included in the hash: +// the exact zip file format encoding, compression method, +// per-file modification times, and other metadata are ignored. +func HashZip(zipfile string, hash Hash) (string, error) { + z, err := zip.OpenReader(zipfile) + if err != nil { + return "", err + } + defer z.Close() + var files []string + zfiles := make(map[string]*zip.File) + for _, file := range z.File { + files = append(files, file.Name) + zfiles[file.Name] = file + } + zipOpen := func(name string) (io.ReadCloser, error) { + f := zfiles[name] + if f == nil { + return nil, fmt.Errorf("file %q not found in zip", name) // should never happen + } + return f.Open() + } + return hash(files, zipOpen) +} diff --git a/vendor/modules.txt b/vendor/modules.txt index e69ac397..cb69c7b2 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -690,8 +690,10 @@ golang.org/x/crypto/ssh/terminal # golang.org/x/lint v0.0.0-20200302205851-738671d3881b golang.org/x/lint golang.org/x/lint/golint -# golang.org/x/mod v0.3.0 +# golang.org/x/mod v0.4.2 +## explicit golang.org/x/mod/semver +golang.org/x/mod/sumdb/dirhash # golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0 golang.org/x/net/context golang.org/x/net/context/ctxhttp