diff --git a/cmd/rekor-cli/app/pflags.go b/cmd/rekor-cli/app/pflags.go index 2b4fcec8f82af9efedb4d41126123a13f454985c..13864dd3e976c2a795242864b31aea82573896d5 100644 --- a/cmd/rekor-cli/app/pflags.go +++ b/cmd/rekor-cli/app/pflags.go @@ -27,6 +27,7 @@ import ( "os" "path/filepath" "strconv" + "strings" "github.com/go-openapi/strfmt" "github.com/go-openapi/swag" @@ -47,7 +48,7 @@ func addSearchPFlags(cmd *cobra.Command) error { cmd.Flags().Var(&fileOrURLFlag{}, "artifact", "path or URL to artifact file") - cmd.Flags().Var(&uuidFlag{}, "sha", "the SHA256 sum of the artifact") + cmd.Flags().Var(&shaFlag{}, "sha", "the SHA256 sum of the artifact") cmd.Flags().Var(&emailFlag{}, "email", "email associated with the public key's subject") return nil @@ -468,6 +469,36 @@ func (f *pkiFormatFlag) Set(s string) error { return fmt.Errorf("value specified is invalid: [%s] supported values are: [pgp, minisign, x509, ssh]", s) } +type shaFlag struct { + hash string +} + +func (s *shaFlag) String() string { + return s.hash +} + +func (s *shaFlag) Set(v string) error { + if v == "" { + return errors.New("flag must be specified") + } + strToCheck := v + if strings.HasPrefix(v, "sha256:") { + strToCheck = strings.Replace(v, "sha256:", "", 1) + } + if _, err := hex.DecodeString(strToCheck); (err != nil) || (len(strToCheck) != 64) { + if err == nil { + err = errors.New("invalid length for value") + } + return fmt.Errorf("value specified is invalid: %w", err) + } + s.hash = v + return nil +} + +func (s *shaFlag) Type() string { + return "sha" +} + type uuidFlag struct { hash string } diff --git a/cmd/rekor-cli/app/search.go b/cmd/rekor-cli/app/search.go index 41837d5409749f6431234f34ac5943b0159fef9f..d96d454900c93f691ca90c75d838b62ebe2d92a5 100644 --- a/cmd/rekor-cli/app/search.go +++ b/cmd/rekor-cli/app/search.go @@ -116,7 +116,7 @@ var searchCmd = &cobra.Command{ } hashVal := strings.ToLower(hex.EncodeToString(hasher.Sum(nil))) - params.Query.Hash = hashVal + params.Query.Hash = "sha256:" + hashVal } publicKeyStr := viper.GetString("public-key") diff --git a/openapi.yaml b/openapi.yaml index 71be9ad46439110aa1e08b1b66f4d59232f47f6d..b531661d3076f18699cd4b016392ca9510d2e9a4 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -338,7 +338,7 @@ definitions: - "format" hash: type: string - pattern: '^[0-9a-fA-F]{64}$' + pattern: '^(sha256:)?[0-9a-fA-F]{64}$' SearchLogQuery: type: object diff --git a/pkg/api/entries.go b/pkg/api/entries.go index 203b6fdc84e77dca9eb9bae5f5fb7ade5d7c2c7c..257b20b45ee1155c27c09549d82cef1047e00bba 100644 --- a/pkg/api/entries.go +++ b/pkg/api/entries.go @@ -296,12 +296,14 @@ func SearchLogQueryHandler(params entries.SearchLogQueryParams) middleware.Respo } for _, leafResp := range searchByHashResults { - logEntry, err := logEntryFromLeaf(tc, leafResp.Leaf, leafResp.SignedLogRoot, leafResp.Proof) - if err != nil { - return handleRekorAPIError(params, code, err, err.Error()) - } + if leafResp != nil { + logEntry, err := logEntryFromLeaf(tc, leafResp.Leaf, leafResp.SignedLogRoot, leafResp.Proof) + if err != nil { + return handleRekorAPIError(params, code, err, err.Error()) + } - resultPayload = append(resultPayload, logEntry) + resultPayload = append(resultPayload, logEntry) + } } } diff --git a/pkg/generated/models/search_index.go b/pkg/generated/models/search_index.go index 9163f78f9926b75752ff021d26da096ef8fbd211..37645b7e2b67f41d6e693840e29625b31395a05f 100644 --- a/pkg/generated/models/search_index.go +++ b/pkg/generated/models/search_index.go @@ -41,7 +41,7 @@ type SearchIndex struct { Email strfmt.Email `json:"email,omitempty"` // hash - // Pattern: ^[0-9a-fA-F]{64}$ + // Pattern: ^(sha256:)?[0-9a-fA-F]{64}$ Hash string `json:"hash,omitempty"` // public key @@ -87,7 +87,7 @@ func (m *SearchIndex) validateHash(formats strfmt.Registry) error { return nil } - if err := validate.Pattern("hash", "body", m.Hash, `^[0-9a-fA-F]{64}$`); err != nil { + if err := validate.Pattern("hash", "body", m.Hash, `^(sha256:)?[0-9a-fA-F]{64}$`); err != nil { return err } diff --git a/pkg/generated/restapi/embedded_spec.go b/pkg/generated/restapi/embedded_spec.go index 44da32e4de5db373b02a8e95685b92cb6864fa0d..1cd7cb5b1d224d9256458d75b73f38c3330f7c24 100644 --- a/pkg/generated/restapi/embedded_spec.go +++ b/pkg/generated/restapi/embedded_spec.go @@ -497,7 +497,7 @@ func init() { }, "hash": { "type": "string", - "pattern": "^[0-9a-fA-F]{64}$" + "pattern": "^(sha256:)?[0-9a-fA-F]{64}$" }, "publicKey": { "type": "object", @@ -1602,7 +1602,7 @@ func init() { }, "hash": { "type": "string", - "pattern": "^[0-9a-fA-F]{64}$" + "pattern": "^(sha256:)?[0-9a-fA-F]{64}$" }, "publicKey": { "type": "object", diff --git a/pkg/types/jar/v0.0.1/entry.go b/pkg/types/jar/v0.0.1/entry.go index 2ea6fade90957e2c6696dae7fd21aa307ee06599..37df37f78e51d14c1212df773d289e6aeb477be7 100644 --- a/pkg/types/jar/v0.0.1/entry.go +++ b/pkg/types/jar/v0.0.1/entry.go @@ -93,7 +93,8 @@ func (v V001Entry) IndexKeys() []string { } if v.JARModel.Archive.Hash != nil { - result = append(result, strings.ToLower(swag.StringValue(v.JARModel.Archive.Hash.Value))) + hashKey := strings.ToLower(fmt.Sprintf("%s:%s", *v.JARModel.Archive.Hash.Algorithm, *v.JARModel.Archive.Hash.Value)) + result = append(result, hashKey) } return result diff --git a/pkg/types/rekord/v0.0.1/entry.go b/pkg/types/rekord/v0.0.1/entry.go index 3e5f55d2dd27cc0f179f8135ae4ac122698aa427..a7f63446fe416ccd828136aee9261877c230fe06 100644 --- a/pkg/types/rekord/v0.0.1/entry.go +++ b/pkg/types/rekord/v0.0.1/entry.go @@ -88,7 +88,8 @@ func (v V001Entry) IndexKeys() []string { result = append(result, v.keyObj.EmailAddresses()...) if v.RekordObj.Data.Hash != nil { - result = append(result, strings.ToLower(swag.StringValue(v.RekordObj.Data.Hash.Value))) + hashKey := strings.ToLower(fmt.Sprintf("%s:%s", *v.RekordObj.Data.Hash.Algorithm, *v.RekordObj.Data.Hash.Value)) + result = append(result, hashKey) } return result diff --git a/pkg/types/rpm/v0.0.1/entry.go b/pkg/types/rpm/v0.0.1/entry.go index b8ebbcb7bc0c5312ae0ab306202dc935a4c3ac06..10c9bdb3255f6a322070728fc0b81732e7b36245 100644 --- a/pkg/types/rpm/v0.0.1/entry.go +++ b/pkg/types/rpm/v0.0.1/entry.go @@ -92,7 +92,8 @@ func (v V001Entry) IndexKeys() []string { result = append(result, v.keyObj.EmailAddresses()...) if v.RPMModel.Package.Hash != nil { - result = append(result, strings.ToLower(swag.StringValue(v.RPMModel.Package.Hash.Value))) + hashKey := strings.ToLower(fmt.Sprintf("%s:%s", *v.RPMModel.Package.Hash.Algorithm, *v.RPMModel.Package.Hash.Value)) + result = append(result, hashKey) } return result diff --git a/tests/e2e-test.sh b/tests/e2e-test.sh index 2e8938a35c48c04fd7312789f909e05d0f73fb03..b9f890cb744a414e4f888ccd5ba395fd998496ee 100755 --- a/tests/e2e-test.sh +++ b/tests/e2e-test.sh @@ -45,3 +45,9 @@ TMPDIR="$(mktemp -d -t rekor_test.XXXXXX)" touch $TMPDIR.rekor.yaml trap "rm -rf $TMPDIR" EXIT TMPDIR=$TMPDIR go test -tags=e2e ./tests/ +if docker-compose logs --no-color | grep -q "panic: runtime error:" ; then + # if we're here, we found a panic + echo "Failing due to panics detected in logs" + docker-compose logs --no-color + exit 1 +fi diff --git a/tests/e2e_test.go b/tests/e2e_test.go index 1dfb80dced0b42748d155e1f2f2b6de10d5e76a0..a554bea5eaa74b20f50d2424aed3bec256ece68a 100644 --- a/tests/e2e_test.go +++ b/tests/e2e_test.go @@ -21,7 +21,9 @@ import ( "context" "crypto" "crypto/ecdsa" + "crypto/sha256" "crypto/x509" + "encoding/hex" "encoding/json" "encoding/pem" "fmt" @@ -187,6 +189,17 @@ func TestGet(t *testing.T) { out = runCli(t, "search", "--public-key", pubPath) outputContains(t, out, uuid) + + hash := sha256.New() + artifactBytes, err := ioutil.ReadFile(artifactPath) + if err != nil { + t.Error(err) + } + hash.Write(artifactBytes) + sha := hash.Sum(nil) + + out = runCli(t, "search", "--sha", fmt.Sprintf("sha256:%s", hex.EncodeToString(sha))) + outputContains(t, out, uuid) } func TestMinisign(t *testing.T) {