Repository: sigstore/rekor
Pull request #1778 (2023-10-19 11:15:53)

build(deps): Bump google/cloud-sdk from `4bcc272` to `1969fea`
Bumps google/cloud-sdk from `4bcc272` to `1969fea`.


[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=google/cloud-sdk&package-manager=docker&previous-version=451.0.0&new-version=451.0.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)


</details>

codecov[bot]: ## [Codecov](https://app.codecov.io/gh/sigstore/rekor/pull/1778?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=sigstore) Report
> Merging [#1778](https://app.codecov.io/gh/sigstore/rekor/pull/1778?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=sigstore) (86f25e6) into [main](https://app.codecov.io/gh/sigstore/rekor/commit/2143e33f8398d4694f27de71fee5597aa05c9b8f?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=sigstore) (2143e33) will **not change** coverage.
> The diff coverage is `n/a`.

```diff
@@           Coverage Diff           @@
##             main    #1778   +/-   ##
=======================================
  Coverage   47.70%   47.70%           
=======================================
  Files          78       78           
  Lines        8182     8182           
=======================================
  Hits         3903     3903           
  Misses       3902     3902           
  Partials      377      377           
```

| [Flag](https://app.codecov.io/gh/sigstore/rekor/pull/1778/flags?src=pr&el=flags&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=sigstore) | Coverage Δ | |
|---|---|---|
| [unittests](https://app.codecov.io/gh/sigstore/rekor/pull/1778/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=sigstore) | `47.70% <ø> (ø)` | |

Flags with carried forward coverage won't be shown. [Click here](https://docs.codecov.io/docs/carryforward-flags?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=sigstore#carryforward-flags-in-the-pull-request-comment) to find out more.

[see 1 file with indirect coverage changes](https://app.codecov.io/gh/sigstore/rekor/pull/1778/indirect-changes?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=sigstore)



Patch:
diff --git a/Dockerfile.pubsub-emulator b/Dockerfile.pubsub-emulator
index 6dc1fa6..5b7d7f4 100644
--- a/Dockerfile.pubsub-emulator
+++ b/Dockerfile.pubsub-emulator
@@ -1,3 +1,3 @@
 # gcloud sdk for pubsub emulator with netcat added for the startup health check
-FROM google/cloud-sdk:451.0.0@sha256:4bcc272a0cdbdd97b6bc8b8400e101f5fba388e304925bdfd3e79762cb2f656a
+FROM google/cloud-sdk:451.0.0@sha256:1969fea02784de69e3684deb5f800896cb6f56f206398bff19484d8cf884e7af
 RUN apt-get install -y netcat
diff --git a/go.mod b/go.mod
index db585a9..9dfcd12 100644
--- a/go.mod
+++ b/go.mod
@@ -132,7 +132,7 @@ require (
 	cloud.google.com/go v0.110.8 // indirect
 	cloud.google.com/go/compute v1.23.0 // indirect
 	cloud.google.com/go/iam v1.1.2 // indirect
-	cloud.google.com/go/kms v1.15.2 // indirect
+	cloud.google.com/go/kms v1.15.3 // indirect
 	cloud.google.com/go/storage v1.31.0 // indirect
 	github.com/beorn7/perks v1.0.1 // indirect
 	github.com/cavaliercoder/badio v0.0.0-20160213150051-ce5280129e9e // indirect
@@ -181,7 +181,7 @@ require (
 	github.com/x448/float16 v0.8.4 // indirect
 	go.mongodb.org/mongo-driver v1.11.3 // indirect
 	go.opencensus.io v0.24.0 // indirect
-	go.step.sm/crypto v0.36.0
+	go.step.sm/crypto v0.36.1
 	go.uber.org/multierr v1.11.0 // indirect
 	golang.org/x/oauth2 v0.13.0 // indirect
 	golang.org/x/sys v0.13.0 // indirect
diff --git a/go.sum b/go.sum
index cd25821..65f2106 100644
--- a/go.sum
+++ b/go.sum
@@ -33,8 +33,8 @@ cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7
 cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
 cloud.google.com/go/iam v1.1.2 h1:gacbrBdWcoVmGLozRuStX45YKvJtzIjJdAolzUs1sm4=
 cloud.google.com/go/iam v1.1.2/go.mod h1:A5avdyVL2tCppe4unb0951eI9jreack+RJ0/d+KUZOU=
-cloud.google.com/go/kms v1.15.2 h1:lh6qra6oC4AyWe5fUUUBe/S27k12OHAleOOOw6KakdE=
-cloud.google.com/go/kms v1.15.2/go.mod h1:3hopT4+7ooWRCjc2DxgnpESFxhIraaI2IpAVUEhbT/w=
+cloud.google.com/go/kms v1.15.3 h1:RYsbxTRmk91ydKCzekI2YjryO4c5Y2M80Zwcs9/D/cI=
+cloud.google.com/go/kms v1.15.3/go.mod h1:AJdXqHxS2GlPyduM99s9iGqi2nwbviBbhV/hdmt4iOQ=
 cloud.google.com/go/profiler v0.3.1 h1:b5got9Be9Ia0HVvyt7PavWxXEht15B9lWnigdvHtxOc=
 cloud.google.com/go/profiler v0.3.1/go.mod h1:GsG14VnmcMFQ9b+kq71wh3EKMZr3WRMgLzNiFRpW7tE=
 cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
@@ -78,8 +78,8 @@ github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj
 github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
 github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so=
 github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
-github.com/aws/aws-sdk-go v1.45.25 h1:c4fLlh5sLdK2DCRTY1z0hyuJZU4ygxX8m1FswL6/nF4=
-github.com/aws/aws-sdk-go v1.45.25/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
+github.com/aws/aws-sdk-go v1.45.26 h1:PJ2NJNY5N/yeobLYe1Y+xLdavBi67ZI8gvph6ftwVCg=
+github.com/aws/aws-sdk-go v1.45.26/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
 github.com/aws/aws-sdk-go-v2 v1.21.1/go.mod h1:ErQhvNuEMhJjweavOYhxVkn2RUx7kQXVATHrjKtxIpM=
 github.com/aws/aws-sdk-go-v2 v1.21.2 h1:+LXZ0sgo8quN9UOKXXzAWRT3FWd4NxeXWOZom9pE7GA=
 github.com/aws/aws-sdk-go-v2 v1.21.2/go.mod h1:ErQhvNuEMhJjweavOYhxVkn2RUx7kQXVATHrjKtxIpM=
@@ -653,8 +653,8 @@ go.opentelemetry.io/otel/sdk v1.14.0 h1:PDCppFRDq8A1jL9v6KMI6dYesaq+DFcDZvjsoGvx
 go.opentelemetry.io/otel/sdk v1.14.0/go.mod h1:bwIC5TjrNG6QDCHNWvW4HLHtUQ4I+VQDsnjhvyZCALM=
 go.opentelemetry.io/otel/trace v1.14.0 h1:wp2Mmvj41tDsyAJXiWDWpfNsOiIyd38fy85pyKcFq/M=
 go.opentelemetry.io/otel/trace v1.14.0/go.mod h1:8avnQLK+CG77yNLUae4ea2JDQ6iT+gozhnZjy/rw9G8=
-go.step.sm/crypto v0.36.0 h1:njrVQqjWVyCzHxqQUDprR7HXypZX8IxtOqe4IIHSjgU=
-go.step.sm/crypto v0.36.0/go.mod h1:XMRbgkhoigPLaPMjZeY1VFIYXVw03Wul0+5lENF6l7c=
+go.step.sm/crypto v0.36.1 h1:hrHIc0qVcOowJB/r1SgPGu10d59onUw3czYeMLJluBc=
+go.step.sm/crypto v0.36.1/go.mod h1:3b2wJhYMWzHpc8ke4CvTXOehx/FK5acd8rwXt+c8g68=
 go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A=
 go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4=
 go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
diff --git a/pkg/types/alpine/v0.0.1/entry.go b/pkg/types/alpine/v0.0.1/entry.go
index cd3f20b..d4998bb 100644
--- a/pkg/types/alpine/v0.0.1/entry.go
+++ b/pkg/types/alpine/v0.0.1/entry.go
@@ -362,6 +362,13 @@ func (v V001Entry) Verifiers() ([]pki.PublicKey, error) {
 	return []pki.PublicKey{key}, nil
 }
 
+func (v V001Entry) ArtifactHash() (string, error) {
+	if v.AlpineModel.Package == nil || v.AlpineModel.Package.Hash == nil || v.AlpineModel.Package.Hash.Value == nil || v.AlpineModel.Package.Hash.Algorithm == nil {
+		return "", errors.New("alpine v0.0.1 entry not initialized")
+	}
+	return strings.ToLower(fmt.Sprintf("%s:%s", *v.AlpineModel.Package.Hash.Algorithm, *v.AlpineModel.Package.Hash.Value)), nil
+}
+
 func (v V001Entry) Insertable() (bool, error) {
 	if v.AlpineModel.Package == nil {
 		return false, fmt.Errorf("missing package entry")
diff --git a/pkg/types/cose/v0.0.1/entry.go b/pkg/types/cose/v0.0.1/entry.go
index d5a74b4..930afb4 100644
--- a/pkg/types/cose/v0.0.1/entry.go
+++ b/pkg/types/cose/v0.0.1/entry.go
@@ -359,6 +359,13 @@ func (v V001Entry) Verifiers() ([]pki.PublicKey, error) {
 	return []pki.PublicKey{key}, nil
 }
 
+func (v V001Entry) ArtifactHash() (string, error) {
+	if v.CoseObj.Data == nil || v.CoseObj.Data.PayloadHash == nil || v.CoseObj.Data.PayloadHash.Value == nil || v.CoseObj.Data.PayloadHash.Algorithm == nil {
+		return "", errors.New("cose v0.0.1 entry not initialized")
+	}
+	return strings.ToLower(fmt.Sprintf("%s:%s", *v.CoseObj.Data.PayloadHash.Algorithm, *v.CoseObj.Data.PayloadHash.Value)), nil
+}
+
 func (v V001Entry) Insertable() (bool, error) {
 	if len(v.CoseObj.Message) == 0 {
 		return false, errors.New("missing COSE Sign1 message")
diff --git a/pkg/types/dsse/v0.0.1/entry.go b/pkg/types/dsse/v0.0.1/entry.go
index ba41742..fb62a22 100644
--- a/pkg/types/dsse/v0.0.1/entry.go
+++ b/pkg/types/dsse/v0.0.1/entry.go
@@ -419,6 +419,13 @@ func (v V001Entry) Verifiers() ([]pki.PublicKey, error) {
 	return keys, nil
 }
 
+func (v V001Entry) ArtifactHash() (string, error) {
+	if v.DSSEObj.PayloadHash == nil || v.DSSEObj.PayloadHash.Algorithm == nil || v.DSSEObj.PayloadHash.Value == nil {
+		return "", errors.New("dsse v0.0.1 entry not initialized")
+	}
+	return strings.ToLower(fmt.Sprintf("%s:%s", *v.DSSEObj.PayloadHash.Algorithm, *v.DSSEObj.PayloadHash.Value)), nil
+}
+
 func (v V001Entry) Insertable() (bool, error) {
 	if v.DSSEObj.ProposedContent == nil {
 		return false, errors.New("missing proposed content")
diff --git a/pkg/types/entries.go b/pkg/types/entries.go
index 3bbf47e..c256596 100644
--- a/pkg/types/entries.go
+++ b/pkg/types/entries.go
@@ -37,8 +37,9 @@ type EntryImpl interface {
 	Canonicalize(ctx context.Context) ([]byte, error) // marshal the canonical entry to be put into the tlog
 	Unmarshal(e models.ProposedEntry) error           // unmarshal the abstract entry into the specific struct for this versioned type
 	CreateFromArtifactProperties(context.Context, ArtifactProperties) (models.ProposedEntry, error)
-	Verifiers() ([]pki.PublicKey, error)
-	Insertable() (bool, error) // denotes whether the entry that was unmarshalled has the writeOnly fields required to validate and insert into the log
+	Verifiers() ([]pki.PublicKey, error) // list of keys or certificates that can verify an entry's signature
+	ArtifactHash() (string, error)       // hex-encoded artifact hash prefixed with hash name, e.g. sha256:abcdef
+	Insertable() (bool, error)           // denotes whether the entry that was unmarshalled has the writeOnly fields required to validate and insert into the log
 }
 
 // EntryWithAttestationImpl specifies the behavior of a versioned type that also stores attestations
diff --git a/pkg/types/hashedrekord/v0.0.1/entry.go b/pkg/types/hashedrekord/v0.0.1/entry.go
index 5fdef02..5f0cb13 100644
--- a/pkg/types/hashedrekord/v0.0.1/entry.go
+++ b/pkg/types/hashedrekord/v0.0.1/entry.go
@@ -257,6 +257,13 @@ func (v V001Entry) Verifiers() ([]pki.PublicKey, error) {
 	return []pki.PublicKey{key}, nil
 }
 
+func (v V001Entry) ArtifactHash() (string, error) {
+	if v.HashedRekordObj.Data == nil || v.HashedRekordObj.Data.Hash == nil || v.HashedRekordObj.Data.Hash.Value == nil || v.HashedRekordObj.Data.Hash.Algorithm == nil {
+		return "", errors.New("hashedrekord v0.0.1 entry not initialized")
+	}
+	return strings.ToLower(fmt.Sprintf("%s:%s", *v.HashedRekordObj.Data.Hash.Algorithm, *v.HashedRekordObj.Data.Hash.Value)), nil
+}
+
 func (v V001Entry) Insertable() (bool, error) {
 	if v.HashedRekordObj.Signature == nil {
 		return false, errors.New("missing signature property")
diff --git a/pkg/types/helm/v0.0.1/entry.go b/pkg/types/helm/v0.0.1/entry.go
index 9100a7d..80e4395 100644
--- a/pkg/types/helm/v0.0.1/entry.go
+++ b/pkg/types/helm/v0.0.1/entry.go
@@ -360,6 +360,13 @@ func (v V001Entry) Verifiers() ([]pki.PublicKey, error) {
 	return []pki.PublicKey{key}, nil
 }
 
+func (v V001Entry) ArtifactHash() (string, error) {
+	if v.HelmObj.Chart == nil || v.HelmObj.Chart.Hash == nil || v.HelmObj.Chart.Hash.Algorithm == nil || v.HelmObj.Chart.Hash.Value == nil {
+		return "", errors.New("helm v0.0.1 entry not initialized")
+	}
+	return strings.ToLower(fmt.Sprintf("%s:%s", *v.HelmObj.Chart.Hash.Algorithm, *v.HelmObj.Chart.Hash.Value)), nil
+}
+
 func (v V001Entry) Insertable() (bool, error) {
 	if v.HelmObj.PublicKey == nil {
 		return false, errors.New("missing public key property")
diff --git a/pkg/types/intoto/v0.0.1/entry.go b/pkg/types/intoto/v0.0.1/entry.go
index ceb7371..e44c767 100644
--- a/pkg/types/intoto/v0.0.1/entry.go
+++ b/pkg/types/intoto/v0.0.1/entry.go
@@ -364,6 +364,13 @@ func (v V001Entry) Verifiers() ([]pki.PublicKey, error) {
 	return []pki.PublicKey{key}, nil
 }
 
+func (v V001Entry) ArtifactHash() (string, error) {
+	if v.IntotoObj.Content == nil || v.IntotoObj.Content.PayloadHash == nil || v.IntotoObj.Content.PayloadHash.Algorithm == nil || v.IntotoObj.Content.PayloadHash.Value == nil {
+		return "", errors.New("hashedrekord v0.0.1 entry not initialized")
+	}
+	return strings.ToLower(fmt.Sprintf("%s:%s", *v.IntotoObj.Content.PayloadHash.Algorithm, *v.IntotoObj.Content.PayloadHash.Value)), nil
+}
+
 func (v V001Entry) Insertable() (bool, error) {
 	if v.IntotoObj.Content == nil {
 		return false, errors.New("missing content property")
diff --git a/pkg/types/intoto/v0.0.2/entry.go b/pkg/types/intoto/v0.0.2/entry.go
index 69a9b4c..0ae4a9d 100644
--- a/pkg/types/intoto/v0.0.2/entry.go
+++ b/pkg/types/intoto/v0.0.2/entry.go
@@ -478,6 +478,13 @@ func (v V002Entry) Verifiers() ([]pki.PublicKey, error) {
 	return keys, nil
 }
 
+func (v V002Entry) ArtifactHash() (string, error) {
+	if v.IntotoObj.Content == nil || v.IntotoObj.Content.PayloadHash == nil || v.IntotoObj.Content.PayloadHash.Algorithm == nil || v.IntotoObj.Content.PayloadHash.Value == nil {
+		return "", errors.New("intoto v0.0.2 entry not initialized")
+	}
+	return strings.ToLower(fmt.Sprintf("%s:%s", *v.IntotoObj.Content.PayloadHash.Algorithm, *v.IntotoObj.Content.PayloadHash.Value)), nil
+}
+
 func (v V002Entry) Insertable() (bool, error) {
 	if v.IntotoObj.Content == nil {
 		return false, errors.New("missing content property")
diff --git a/pkg/types/jar/v0.0.1/entry.go b/pkg/types/jar/v0.0.1/entry.go
index 01fc6ac..ec25ad5 100644
--- a/pkg/types/jar/v0.0.1/entry.go
+++ b/pkg/types/jar/v0.0.1/entry.go
@@ -349,6 +349,13 @@ func (v V001Entry) Verifiers() ([]pki.PublicKey, error) {
 	return []pki.PublicKey{key}, nil
 }
 
+func (v V001Entry) ArtifactHash() (string, error) {
+	if v.JARModel.Archive == nil || v.JARModel.Archive.Hash == nil || v.JARModel.Archive.Hash.Value == nil || v.JARModel.Archive.Hash.Algorithm == nil {
+		return "", errors.New("jar v0.0.1 entry not initialized")
+	}
+	return strings.ToLower(fmt.Sprintf("%s:%s", *v.JARModel.Archive.Hash.Algorithm, *v.JARModel.Archive.Hash.Value)), nil
+}
+
 func (v V001Entry) Insertable() (bool, error) {
 	if v.JARModel.Archive == nil {
 		return false, errors.New("missing archive property")
diff --git a/pkg/types/rekord/v0.0.1/entry.go b/pkg/types/rekord/v0.0.1/entry.go
index da0af23..619f19f 100644
--- a/pkg/types/rekord/v0.0.1/entry.go
+++ b/pkg/types/rekord/v0.0.1/entry.go
@@ -450,6 +450,13 @@ func (v V001Entry) Verifiers() ([]pki.PublicKey, error) {
 	return []pki.PublicKey{key}, nil
 }
 
+func (v V001Entry) ArtifactHash() (string, error) {
+	if v.RekordObj.Data == nil || v.RekordObj.Data.Hash == nil || v.RekordObj.Data.Hash.Value == nil || v.RekordObj.Data.Hash.Algorithm == nil {
+		return "", errors.New("rekord v0.0.1 entry not initialized")
+	}
+	return strings.ToLower(fmt.Sprintf("%s:%s", *v.RekordObj.Data.Hash.Algorithm, *v.RekordObj.Data.Hash.Value)), nil
+}
+
 func (v V001Entry) Insertable() (bool, error) {
 	if v.RekordObj.Signature == nil {
 		return false, errors.New("missing signature property")
diff --git a/pkg/types/rfc3161/v0.0.1/entry.go b/pkg/types/rfc3161/v0.0.1/entry.go
index 9a6c049..dfac12b 100644
--- a/pkg/types/rfc3161/v0.0.1/entry.go
+++ b/pkg/types/rfc3161/v0.0.1/entry.go
@@ -26,6 +26,7 @@ import (
 	"fmt"
 	"os"
 	"path/filepath"
+	"strings"
 
 	"github.com/sigstore/rekor/pkg/pki"
 	"github.com/sigstore/rekor/pkg/types/rfc3161"
@@ -211,6 +212,18 @@ func (v V001Entry) Verifiers() ([]pki.PublicKey, error) {
 	return nil, errors.New("Verifiers() does not support rfc3161 entry type")
 }
 
+func (v V001Entry) ArtifactHash() (string, error) {
+	if v.Rfc3161Obj.Tsr == nil || v.Rfc3161Obj.Tsr.Content == nil {
+		return "", errors.New("rfc3161 v0.0.1 entry not initialized")
+	}
+	tsrDecoded, err := base64.StdEncoding.DecodeString(v.Rfc3161Obj.Tsr.Content.String())
+	if err != nil {
+		return "", err
+	}
+	h := sha256.Sum256(tsrDecoded)
+	return strings.ToLower(fmt.Sprintf("sha256:%s", hex.EncodeToString(h[:]))), nil
+}
+
 func (v V001Entry) Insertable() (bool, error) {
 	if v.Rfc3161Obj.Tsr == nil {
 		return false, errors.New("missing tsr property")
diff --git a/pkg/types/rpm/v0.0.1/entry.go b/pkg/types/rpm/v0.0.1/entry.go
index fd3b91c..d83527e 100644
--- a/pkg/types/rpm/v0.0.1/entry.go
+++ b/pkg/types/rpm/v0.0.1/entry.go
@@ -382,6 +382,13 @@ func (v V001Entry) Verifiers() ([]pki.PublicKey, error) {
 	return []pki.PublicKey{key}, nil
 }
 
+func (v V001Entry) ArtifactHash() (string, error) {
+	if v.RPMModel.Package == nil || v.RPMModel.Package.Hash == nil || v.RPMModel.Package.Hash.Value == nil || v.RPMModel.Package.Hash.Algorithm == nil {
+		return "", errors.New("rpm v0.0.1 entry not initialized")
+	}
+	return strings.ToLower(fmt.Sprintf("%s:%s", *v.RPMModel.Package.Hash.Algorithm, *v.RPMModel.Package.Hash.Value)), nil
+}
+
 func (v V001Entry) Insertable() (bool, error) {
 	if v.RPMModel.PublicKey == nil {
 		return false, errors.New("missing publicKey property")
diff --git a/pkg/types/tuf/v0.0.1/entry.go b/pkg/types/tuf/v0.0.1/entry.go
index be24fd6..608162e 100644
--- a/pkg/types/tuf/v0.0.1/entry.go
+++ b/pkg/types/tuf/v0.0.1/entry.go
@@ -385,6 +385,26 @@ func (v V001Entry) Verifiers() ([]pki.PublicKey, error) {
 	return []pki.PublicKey{key}, nil
 }
 
+func (v V001Entry) ArtifactHash() (string, error) {
+	if v.TufObj.Metadata == nil || v.TufObj.Metadata.Content == nil {
+		return "", errors.New("tuf v0.0.1 entry not initialized")
+	}
+	sigBytes, err := v.parseMetadataContent()
+	if err != nil {
+		return "", err
+	}
+	sig, err := ptuf.NewSignature(bytes.NewReader(sigBytes))
+	if err != nil {
+		return "", err
+	}
+	metadata, err := sig.CanonicalValue()
+	if err != nil {
+		return "", err
+	}
+	metadataHash := sha256.Sum256(metadata)
+	return strings.ToLower(fmt.Sprintf("sha256:%s", hex.EncodeToString(metadataHash[:]))), nil
+}
+
 func (v V001Entry) Insertable() (bool, error) {
 	if v.TufObj.Metadata == nil {
 		return false, errors.New("missing metadata property")


Test patch:
diff --git a/pkg/types/alpine/v0.0.1/entry_test.go b/pkg/types/alpine/v0.0.1/entry_test.go
index 03fd600..3df4689 100644
--- a/pkg/types/alpine/v0.0.1/entry_test.go
+++ b/pkg/types/alpine/v0.0.1/entry_test.go
@@ -18,6 +18,8 @@ package alpine
 import (
 	"bytes"
 	"context"
+	"crypto/sha256"
+	"encoding/hex"
 	"os"
 	"reflect"
 	"testing"
@@ -177,6 +179,13 @@ func TestCrossFieldValidation(t *testing.T) {
 			if ok, err := ei.Insertable(); ok || err == nil {
 				t.Errorf("unexpected success calling Insertable on entry created from canonicalized content")
 			}
+			hash, err := ei.ArtifactHash()
+			expectedHash := sha256.Sum256(dataBytes)
+			if err != nil {
+				t.Errorf("unexpected failure with ArtifactHash: %v", err)
+			} else if hash != "sha256:"+hex.EncodeToString(expectedHash[:]) {
+				t.Errorf("unexpected match with ArtifactHash: %s", hash)
+			}
 		}
 
 		verifiers, err := v.Verifiers()
diff --git a/pkg/types/cose/v0.0.1/entry_test.go b/pkg/types/cose/v0.0.1/entry_test.go
index f6b7a41..7f60b3c 100644
--- a/pkg/types/cose/v0.0.1/entry_test.go
+++ b/pkg/types/cose/v0.0.1/entry_test.go
@@ -303,6 +303,13 @@ func TestV001Entry_Unmarshal(t *testing.T) {
 						if ok, err := ei.Insertable(); ok || err == nil {
 							t.Errorf("entry created from canonicalized entry should not also be insertable")
 						}
+						hash, err := ei.ArtifactHash()
+						expectedHash := sha256.Sum256([]byte("hello"))
+						if err != nil {
+							t.Errorf("unexpected failure with ArtifactHash: %v", err)
+						} else if hash != "sha256:"+hex.EncodeToString(expectedHash[:]) {
+							t.Errorf("unexpected match with ArtifactHash: %s", hash)
+						}
 					}
 				}
 
diff --git a/pkg/types/dsse/v0.0.1/entry_test.go b/pkg/types/dsse/v0.0.1/entry_test.go
index e59e46f..77cfe66 100644
--- a/pkg/types/dsse/v0.0.1/entry_test.go
+++ b/pkg/types/dsse/v0.0.1/entry_test.go
@@ -306,6 +306,14 @@ func TestV001Entry_Unmarshal(t *testing.T) {
 					t.Errorf("index keys from hydrated object do not match those generated from canonicalized (and re-hydrated) object: %v %v", got, canonicalIndexKeys)
 				}
 
+				hash, err := canonicalV001.ArtifactHash()
+				expectedHash := sha256.Sum256([]byte(validPayload))
+				if err != nil {
+					t.Errorf("unexpected failure with ArtifactHash: %v", err)
+				} else if hash != "sha256:"+hex.EncodeToString(expectedHash[:]) {
+					t.Errorf("unexpected match with ArtifactHash: %s", hash)
+				}
+
 				return nil
 			}
 			if err := uv(); (err != nil) != tt.wantErr {
diff --git a/pkg/types/hashedrekord/hashedrekord_test.go b/pkg/types/hashedrekord/hashedrekord_test.go
index aeb2975..e75ab22 100644
--- a/pkg/types/hashedrekord/hashedrekord_test.go
+++ b/pkg/types/hashedrekord/hashedrekord_test.go
@@ -47,6 +47,10 @@ func (u UnmarshalFailsTester) Verifiers() ([]pki.PublicKey, error) {
 	return nil, nil
 }
 
+func (u UnmarshalFailsTester) ArtifactHash() (string, error) {
+	return "", nil
+}
+
 func TestRekordType(t *testing.T) {
 	// empty to start
 	if VersionMap.Count() != 0 {
diff --git a/pkg/types/hashedrekord/v0.0.1/entry_test.go b/pkg/types/hashedrekord/v0.0.1/entry_test.go
index 6c9fb2f..343712d 100644
--- a/pkg/types/hashedrekord/v0.0.1/entry_test.go
+++ b/pkg/types/hashedrekord/v0.0.1/entry_test.go
@@ -289,6 +289,13 @@ func TestCrossFieldValidation(t *testing.T) {
 			if !ok || err != nil {
 				t.Errorf("unexpected failure in testing insertable on valid entry: %v", err)
 			}
+
+			hash, err := v.ArtifactHash()
+			if err != nil {
+				t.Errorf("unexpected failure with ArtifactHash: %v", err)
+			} else if hash != "sha256:"+dataSHA {
+				t.Errorf("unexpected match with ArtifactHash: %s", hash)
+			}
 		}
 
 		b, err := v.Canonicalize(context.TODO())
@@ -313,6 +320,12 @@ func TestCrossFieldValidation(t *testing.T) {
 			if !ok || err != nil {
 				t.Errorf("unexpected failure in testing insertable on entry created from canonicalized content: %v", err)
 			}
+			hash, err := ei.ArtifactHash()
+			if err != nil {
+				t.Errorf("unexpected failure with ArtifactHash: %v", err)
+			} else if hash != "sha256:"+dataSHA {
+				t.Errorf("unexpected match with ArtifactHash: %s", hash)
+			}
 		}
 
 		verifiers, err := v.Verifiers()
diff --git a/pkg/types/helm/v0.0.1/entry_test.go b/pkg/types/helm/v0.0.1/entry_test.go
index d9f79eb..510e1bd 100644
--- a/pkg/types/helm/v0.0.1/entry_test.go
+++ b/pkg/types/helm/v0.0.1/entry_test.go
@@ -209,6 +209,12 @@ func TestCrossFieldValidation(t *testing.T) {
 				if ok, err := ei.Insertable(); ok || err == nil {
 					t.Errorf("unexpected success calling Insertable on entry created from canonicalized content")
 				}
+				hash, err := ei.ArtifactHash()
+				if err != nil {
+					t.Errorf("unexpected failure with ArtifactHash: %v", err)
+				} else if hash != "sha256:6dec7ea21e655d5796c1e214cfb75b73428b2abfa2e66c8f7bc64ff4a7b3b29f" {
+					t.Errorf("unexpected match with ArtifactHash: %s", hash)
+				}
 			}
 
 			verifiers, err := v.Verifiers()
diff --git a/pkg/types/intoto/v0.0.1/entry_test.go b/pkg/types/intoto/v0.0.1/entry_test.go
index 23eb549..3fb6134 100644
--- a/pkg/types/intoto/v0.0.1/entry_test.go
+++ b/pkg/types/intoto/v0.0.1/entry_test.go
@@ -336,6 +336,14 @@ func TestV001Entry_Unmarshal(t *testing.T) {
 					t.Errorf("index keys from hydrated object do not match those generated from canonicalized (and re-hydrated) object: %v %v", got, canonicalIndexKeys)
 				}
 
+				hash, err := canonicalV001.ArtifactHash()
+				expectedHash := sha256.Sum256([]byte(validPayload))
+				if err != nil {
+					t.Errorf("unexpected failure with ArtifactHash: %v", err)
+				} else if hash != "sha256:"+hex.EncodeToString(expectedHash[:]) {
+					t.Errorf("unexpected match with ArtifactHash: %s", hash)
+				}
+
 				verifiers, err := v.Verifiers()
 				if !tt.wantVerifierErr {
 					if err != nil {
diff --git a/pkg/types/intoto/v0.0.2/entry_test.go b/pkg/types/intoto/v0.0.2/entry_test.go
index cde6970..f26518c 100644
--- a/pkg/types/intoto/v0.0.2/entry_test.go
+++ b/pkg/types/intoto/v0.0.2/entry_test.go
@@ -377,6 +377,14 @@ func TestV002Entry_Unmarshal(t *testing.T) {
 					t.Errorf("index keys from hydrated object do not match those generated from canonicalized (and re-hydrated) object: %v %v", got, canonicalIndexKeys)
 				}
 
+				hash, err := canonicalV002.ArtifactHash()
+				expectedHash := sha256.Sum256([]byte(validPayload))
+				if err != nil {
+					t.Errorf("unexpected failure with ArtifactHash: %v", err)
+				} else if hash != "sha256:"+hex.EncodeToString(expectedHash[:]) {
+					t.Errorf("unexpected match with ArtifactHash: %s", hash)
+				}
+
 				verifiers, err := v.Verifiers()
 				if !tt.wantVerifierErr {
 					if err != nil {
diff --git a/pkg/types/jar/v0.0.1/entry_test.go b/pkg/types/jar/v0.0.1/entry_test.go
index 9a096b3..ad857ab 100644
--- a/pkg/types/jar/v0.0.1/entry_test.go
+++ b/pkg/types/jar/v0.0.1/entry_test.go
@@ -140,6 +140,12 @@ Hr/+CxFvaJWmpYqNkLDGRU+9orzh5hI2RrcuaQ==
 			if ok, err := ei.Insertable(); ok || err == nil {
 				t.Errorf("unexpected err from calling Insertable on entry created from canonicalized content")
 			}
+			hash, err := ei.ArtifactHash()
+			if err != nil {
+				t.Errorf("unexpected failure with ArtifactHash: %v", err)
+			} else if hash != "sha256:4a9d0ab4e10597497ed6c4617c983c35fa9e964e75cdd6f9fae3a0da1929acc6" {
+				t.Errorf("unexpected match with ArtifactHash: %s", hash)
+			}
 		}
 
 		verifiers, err := v.Verifiers()
diff --git a/pkg/types/rekord/v0.0.1/entry_test.go b/pkg/types/rekord/v0.0.1/entry_test.go
index e236a50..7c2dee2 100644
--- a/pkg/types/rekord/v0.0.1/entry_test.go
+++ b/pkg/types/rekord/v0.0.1/entry_test.go
@@ -18,6 +18,8 @@ package rekord
 import (
 	"bytes"
 	"context"
+	"crypto/sha256"
+	"encoding/hex"
 	"os"
 	"reflect"
 	"testing"
@@ -256,6 +258,13 @@ func TestCrossFieldValidation(t *testing.T) {
 			if ok, err := ei.Insertable(); ok || err == nil {
 				t.Errorf("unexpected success calling Insertable on entry created from canonicalized content")
 			}
+			hash, err := ei.ArtifactHash()
+			expectedHash := sha256.Sum256(dataBytes)
+			if err != nil {
+				t.Errorf("unexpected failure with ArtifactHash: %v", err)
+			} else if hash != "sha256:"+hex.EncodeToString(expectedHash[:]) {
+				t.Errorf("unexpected match with ArtifactHash: %s", hash)
+			}
 		}
 
 		verifiers, err := v.Verifiers()
diff --git a/pkg/types/rfc3161/v0.0.1/entry_test.go b/pkg/types/rfc3161/v0.0.1/entry_test.go
index 6c54574..b115acc 100644
--- a/pkg/types/rfc3161/v0.0.1/entry_test.go
+++ b/pkg/types/rfc3161/v0.0.1/entry_test.go
@@ -197,6 +197,12 @@ func TestCrossFieldValidation(t *testing.T) {
 			if ok, err := ei.Insertable(); !ok || err != nil {
 				t.Errorf("unexpected error calling insertable on entry created from canonicalized content")
 			}
+			hash, err := ei.ArtifactHash()
+			if err != nil {
+				t.Errorf("unexpected failure with ArtifactHash: %v", err)
+			} else if hash != "sha256:6dbda791c778454d0baa96e1dec5fa2c50867fd22d119ebe75c60c513b254c91" {
+				t.Errorf("unexpected match with ArtifactHash: %s", hash)
+			}
 		}
 	}
 }
diff --git a/pkg/types/rpm/v0.0.1/entry_test.go b/pkg/types/rpm/v0.0.1/entry_test.go
index 9b1ec7b..539c21d 100644
--- a/pkg/types/rpm/v0.0.1/entry_test.go
+++ b/pkg/types/rpm/v0.0.1/entry_test.go
@@ -194,6 +194,12 @@ func TestCrossFieldValidation(t *testing.T) {
 			if ok, err := ei.Insertable(); ok || err == nil {
 				t.Errorf("unexpected success calling Insertable on entry created from canonicalized content")
 			}
+			hash, err := ei.ArtifactHash()
+			if err != nil {
+				t.Errorf("unexpected failure with ArtifactHash: %v", err)
+			} else if hash != "sha256:c8b0bc59708d74f53aab0089ac587d5c348d6ead143dab9f6d9c4b48c973bfd8" {
+				t.Errorf("unexpected match with ArtifactHash: %s", hash)
+			}
 		}
 
 		verifiers, err := v.Verifiers()
diff --git a/pkg/types/test_util.go b/pkg/types/test_util.go
index 529d71b..0fada89 100644
--- a/pkg/types/test_util.go
+++ b/pkg/types/test_util.go
@@ -31,6 +31,10 @@ func (u BaseUnmarshalTester) NewEntry() EntryImpl {
 	return &BaseUnmarshalTester{}
 }
 
+func (u BaseUnmarshalTester) ArtifactHash() (string, error) {
+	return "", nil
+}
+
 func (u BaseUnmarshalTester) Verifiers() ([]pki.PublicKey, error) {
 	return nil, nil
 }
diff --git a/pkg/types/tuf/v0.0.1/entry_test.go b/pkg/types/tuf/v0.0.1/entry_test.go
index 174bb8c..92ca46a 100644
--- a/pkg/types/tuf/v0.0.1/entry_test.go
+++ b/pkg/types/tuf/v0.0.1/entry_test.go
@@ -239,10 +239,17 @@ func TestCrossFieldValidation(t *testing.T) {
 				if err != nil {
 					t.Errorf("unexpected err from Unmarshalling canonicalized entry for '%v': %v", tc.caseDesc, err)
 				}
-				if _, err := types.UnmarshalEntry(pe); err != nil {
+				ei, err := types.UnmarshalEntry(pe)
+				if err != nil {
 					t.Errorf("unexpected err from type-specific unmarshalling for '%v': %v", tc.caseDesc, err)
 				}
 				// Insertable on canonicalized content is variable so we skip testing it here
+				hash, err := ei.ArtifactHash()
+				if err != nil {
+					t.Errorf("unexpected failure with ArtifactHash: %v", err)
+				} else if hash != "sha256:c170ae288c93f56031639bac1ad085fc47918346f733b3d76b07a8124ebd24f9" {
+					t.Errorf("unexpected match with ArtifactHash: %s", hash)
+				}
 			}
 
 			verifiers, err := v.Verifiers()