Repository: sigstore/rekor
Pull request #1454 (2023-04-27 23:46:04)

Refactor Trillian client with exported methods
This allows the Trillian client to be used in other parts of the codebase besides the api package. The changes included exporting the Response fields and all but one of the struct methods. Also removed ranges since these weren't used outside the api package.

<!--
Thanks for opening a pull request! Please do not just delete this text.  The three fields below are mandatory.

Please remember to:
- This PR requires an issue. If it is a new feature, the issue should proceed the PR and will have allowed sufficent time for discussions to take place. Please use
issue tags such as "Closes #XYZ" or "Resolves sigstore/repo-name#XYZ".
  [documentation](https://docs.github.com/en/github/managing-your-work-on-github/linking-a-pull-request-to-an-issue#linking-a-pull-request-to-an-issue-using-a-keyword)
- ensure your commits are signed-off, as sigstore uses the [DCO](https://en.wikipedia.org/wiki/Developer_Certificate_of_Origin) using `git commit -s`, or `git commit -s --amend` if you want to amend already existing commits
- lastly, ensure there are no merge commits!

Thank you :)
-->

#### Summary
<!--
 Explain the **motivation** for making this change. What existing problem does the pull request solve? How can reviewers test this PR?
-->

#### Release Note
<!--
Add a release note for each of the following conditions:

* Config changes (additions, deletions, updates)
* API additions—new endpoint, new response fields, or newly accepted request parameters
* Database changes (any)
* Websocket additions or changes
* Anything noteworthy to an administrator running private sigstore instances (err on the side of over-communicating)
* New features and improvements, including behavioural changes, UI changes and CLI changes
* Bug fixes and fixes of previous known issues
* Deprecation warnings, breaking changes, or compatibility notes

If no release notes are required write NONE. Use past-tense.

-->

#### Documentation
<!--

Does this change require an update to documentation? How will users implement your new feature?

Please reference a PR within https://docs.sigstore.dev

-->


haydentherapper: Context is starting work on creating a stable checkpoint, where a goroutine outside of the api package will periodically fetch the latest checkpoint.
codecov[bot]: ## [Codecov](https://codecov.io/gh/sigstore/rekor/pull/1454?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=sigstore) Report
> Merging [#1454](https://codecov.io/gh/sigstore/rekor/pull/1454?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=sigstore) (af6f1f5) into [main](https://codecov.io/gh/sigstore/rekor/commit/fb19879aba8a11fb024a4aa64879eb0040659494?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=sigstore) (fb19879) will **decrease** coverage by `21.08%`.
> The diff coverage is `0.00%`.

```diff
@@             Coverage Diff             @@
##             main    #1454       +/-   ##
===========================================
- Coverage   64.35%   43.28%   -21.08%     
===========================================
  Files          82       74        -8     
  Lines        7873     7414      -459     
===========================================
- Hits         5067     3209     -1858     
- Misses       2159     3869     +1710     
+ Partials      647      336      -311     
```

| Flag | Coverage Δ | |
|---|---|---|
| e2etests | `?` | |
| unittests | `43.28% <0.00%> (+0.05%)` | :arrow_up: |

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.

| [Impacted Files](https://codecov.io/gh/sigstore/rekor/pull/1454?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=sigstore) | Coverage Δ | |
|---|---|---|
| [pkg/api/api.go](https://codecov.io/gh/sigstore/rekor/pull/1454?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=sigstore#diff-cGtnL2FwaS9hcGkuZ28=) | `0.00% <0.00%> (-64.29%)` | :arrow_down: |
| [pkg/api/entries.go](https://codecov.io/gh/sigstore/rekor/pull/1454?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=sigstore#diff-cGtnL2FwaS9lbnRyaWVzLmdv) | `0.00% <0.00%> (-64.88%)` | :arrow_down: |
| [pkg/api/public\_key.go](https://codecov.io/gh/sigstore/rekor/pull/1454?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=sigstore#diff-cGtnL2FwaS9wdWJsaWNfa2V5Lmdv) | `0.00% <0.00%> (-37.50%)` | :arrow_down: |
| [pkg/api/tlog.go](https://codecov.io/gh/sigstore/rekor/pull/1454?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=sigstore#diff-cGtnL2FwaS90bG9nLmdv) | `0.00% <0.00%> (-39.03%)` | :arrow_down: |
| [pkg/util/trillian\_client.go](https://codecov.io/gh/sigstore/rekor/pull/1454?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=sigstore#diff-cGtnL3V0aWwvdHJpbGxpYW5fY2xpZW50Lmdv) | `0.00% <0.00%> (ø)` | |

... and [50 files with indirect coverage changes](https://codecov.io/gh/sigstore/rekor/pull/1454/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/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
index 8482e18..fb991d3 100644
--- a/.github/workflows/codeql-analysis.yml
+++ b/.github/workflows/codeql-analysis.yml
@@ -46,12 +46,12 @@ jobs:
 
     # Initializes the CodeQL tools for scanning.
     - name: Initialize CodeQL
-      uses: github/codeql-action/init@8662eabe0e9f338a07350b7fd050732745f93848 # v2.3.1
+      uses: github/codeql-action/init@f3feb00acb00f31a6f60280e6ace9ca31d91c76a # v2.3.2
       with:
         languages: ${{ matrix.language }}
 
     - name: Autobuild
-      uses: github/codeql-action/autobuild@8662eabe0e9f338a07350b7fd050732745f93848 # v2.3.1
+      uses: github/codeql-action/autobuild@f3feb00acb00f31a6f60280e6ace9ca31d91c76a # v2.3.2
 
     - name: Perform CodeQL Analysis
-      uses: github/codeql-action/analyze@8662eabe0e9f338a07350b7fd050732745f93848 # v2.3.1
+      uses: github/codeql-action/analyze@f3feb00acb00f31a6f60280e6ace9ca31d91c76a # v2.3.2
diff --git a/cmd/backfill-redis/main.go b/cmd/backfill-redis/main.go
index 58f3c17..5c0df33 100644
--- a/cmd/backfill-redis/main.go
+++ b/cmd/backfill-redis/main.go
@@ -36,7 +36,7 @@ import (
 	"os"
 
 	"github.com/go-openapi/runtime"
-	radix "github.com/mediocregopher/radix/v4"
+	"github.com/redis/go-redis/v9"
 	"sigs.k8s.io/release-utils/version"
 
 	"github.com/sigstore/rekor/pkg/client"
@@ -96,11 +96,11 @@ func main() {
 
 	log.Printf("running backfill redis Version: %s GitCommit: %s BuildDate: %s", versionInfo.GitVersion, versionInfo.GitCommit, versionInfo.BuildDate)
 
-	cfg := radix.PoolConfig{}
-	redisClient, err := cfg.New(context.Background(), "tcp", fmt.Sprintf("%s:%s", *redisHostname, *redisPort))
-	if err != nil {
-		log.Fatal(err)
-	}
+	redisClient := redis.NewClient(&redis.Options{
+		Addr:    fmt.Sprintf("%s:%s", *redisHostname, *redisPort),
+		Network: "tcp",
+		DB:      0, // default DB
+	})
 
 	rekorClient, err := client.GetRekorClient(*rekorAddress)
 	if err != nil {
@@ -171,11 +171,13 @@ func unmarshalEntryImpl(e string) (types.EntryImpl, string, string, error) {
 
 // removeFromIndex removes all occurrences of a value from a given key. This guards against
 // multiple invocations of backfilling creating duplicates.
-func removeFromIndex(ctx context.Context, redisClient radix.Client, key, value string) error {
-	return redisClient.Do(ctx, radix.Cmd(nil, "LREM", key, "0", value))
+func removeFromIndex(ctx context.Context, redisClient *redis.Client, key, value string) error {
+	_, err := redisClient.LRem(ctx, key, 0, value).Result()
+	return err
 }
 
 // addToIndex pushes a value onto a key of type list.
-func addToIndex(ctx context.Context, redisClient radix.Client, key, value string) error {
-	return redisClient.Do(ctx, radix.Cmd(nil, "LPUSH", key, value))
+func addToIndex(ctx context.Context, redisClient *redis.Client, key, value string) error {
+	_, err := redisClient.LPush(ctx, key, value).Result()
+	return err
 }
diff --git a/go.mod b/go.mod
index c266b98..225bba3 100644
--- a/go.mod
+++ b/go.mod
@@ -15,13 +15,12 @@ require (
 	github.com/go-openapi/strfmt v0.21.7
 	github.com/go-openapi/swag v0.22.3
 	github.com/go-openapi/validate v0.22.1
-	github.com/go-playground/validator/v10 v10.12.0
+	github.com/go-playground/validator/v10 v10.13.0
 	github.com/google/go-cmp v0.5.9
 	github.com/google/rpmpack v0.0.0-20210518075352-dc539ef4f2ea
 	github.com/google/trillian v1.5.1
 	github.com/in-toto/in-toto-golang v0.8.0
 	github.com/jedisct1/go-minisign v0.0.0-20211028175153-1c139d1cc84b
-	github.com/mediocregopher/radix/v4 v4.1.2
 	github.com/mitchellh/go-homedir v1.1.0
 	github.com/mitchellh/mapstructure v1.5.0
 	github.com/pkg/errors v0.9.1 // indirect
@@ -52,11 +51,12 @@ require (
 )
 
 require (
-	github.com/AdaLogics/go-fuzz-headers v0.0.0-20230106234847-43070de90fa1
+	github.com/AdamKorcz/go-fuzz-headers-1 v0.0.0-20230329111138-12e09aba5ebd
 	github.com/cyberphone/json-canonicalization v0.0.0-20220623050100-57a0ce2678a7
 	github.com/golang/mock v1.6.0
 	github.com/hashicorp/go-cleanhttp v0.5.2
 	github.com/hashicorp/go-retryablehttp v0.7.2
+	github.com/redis/go-redis/v9 v9.0.4
 	golang.org/x/exp v0.0.0-20230124195608-d38c7dcee874
 )
 
@@ -64,6 +64,7 @@ require (
 	cloud.google.com/go/compute/metadata v0.2.3 // indirect
 	filippo.io/edwards25519 v1.0.0 // indirect
 	github.com/cyphar/filepath-securejoin v0.2.3 // indirect
+	github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
 	github.com/go-logr/logr v1.2.3 // indirect
 	github.com/go-logr/stdr v1.2.2 // indirect
 	github.com/google/s2a-go v0.1.2 // indirect
@@ -105,7 +106,7 @@ require (
 	github.com/howeyc/gopass v0.0.0-20190910152052-7cb4b85ec19c // indirect
 	github.com/inconshreveable/mousetrap v1.1.0 // indirect
 	github.com/josharian/intern v1.0.0 // indirect
-	github.com/leodido/go-urn v1.2.2 // indirect
+	github.com/leodido/go-urn v1.2.3 // indirect
 	github.com/letsencrypt/boulder v0.0.0-20221109233200-85aa52084eaf // indirect
 	github.com/magiconair/properties v1.8.7 // indirect
 	github.com/mailru/easyjson v0.7.7 // indirect
@@ -123,7 +124,6 @@ require (
 	github.com/spf13/jwalterweatherman v1.1.0 // indirect
 	github.com/subosito/gotenv v1.4.2 // indirect
 	github.com/tidwall/pretty v1.2.0 // indirect
-	github.com/tilinna/clock v1.1.0 // indirect
 	github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 // indirect
 	github.com/ulikunitz/xz v0.5.10 // indirect
 	github.com/x448/float16 v0.8.4 // indirect
@@ -143,5 +143,3 @@ require (
 	gopkg.in/yaml.v2 v2.4.0
 	gopkg.in/yaml.v3 v3.0.1 // indirect
 )
-
-replace github.com/AdaLogics/go-fuzz-headers => github.com/AdamKorcz/go-fuzz-headers-1 v0.0.0-20230201144411-22e92b796899
diff --git a/go.sum b/go.sum
index 6e03ee7..63def60 100644
--- a/go.sum
+++ b/go.sum
@@ -421,8 +421,9 @@ contrib.go.opencensus.io/integrations/ocsql v0.1.7/go.mod h1:8DsSdjz3F+APR+0z0Wk
 dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
 filippo.io/edwards25519 v1.0.0 h1:0wAIcmJUqRdI8IJ/3eGi5/HwXZWPujYXXlkrQogz0Ek=
 filippo.io/edwards25519 v1.0.0/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns=
-github.com/AdamKorcz/go-fuzz-headers-1 v0.0.0-20230201144411-22e92b796899 h1:tkR1HRX5M+lhVP9WOioyxEYDyXeV0I2oBAOugCW87xY=
-github.com/AdamKorcz/go-fuzz-headers-1 v0.0.0-20230201144411-22e92b796899/go.mod h1:0vOOKsOMKPThRu9lQMAxcQ8D60f8U+wHXl07SyUw0+U=
+github.com/AdaLogics/go-fuzz-headers v0.0.0-20210715213245-6c3934b029d8/go.mod h1:CzsSbkDixRphAF5hS6wbMKq0eI6ccJRb7/A0M6JBnwg=
+github.com/AdamKorcz/go-fuzz-headers-1 v0.0.0-20230329111138-12e09aba5ebd h1:1tbEqR4NyQLgiod7vLXSswHteGetAVZrMGCqrJxLKRs=
+github.com/AdamKorcz/go-fuzz-headers-1 v0.0.0-20230329111138-12e09aba5ebd/go.mod h1:0vOOKsOMKPThRu9lQMAxcQ8D60f8U+wHXl07SyUw0+U=
 github.com/Azure/azure-amqp-common-go/v3 v3.2.3/go.mod h1:7rPmbSfszeovxGfc5fSAXE4ehlXQZHpMja2OtxC2Tas=
 github.com/Azure/azure-sdk-for-go v16.2.1+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
 github.com/Azure/azure-sdk-for-go v63.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
@@ -624,6 +625,8 @@ github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdn
 github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
 github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
 github.com/bshuster-repo/logrus-logstash-hook v0.4.1/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk=
+github.com/bsm/ginkgo/v2 v2.7.0 h1:ItPMPH90RbmZJt5GtkcNvIRuGEdwlBItdNVoyzaNQao=
+github.com/bsm/gomega v1.26.0 h1:LhQm+AFcgV2M0WyKroMASzAzCAJVpAxQXv4SaI9a69Y=
 github.com/buger/jsonparser v0.0.0-20180808090653-f4dd9f5a6b44/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=
 github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
 github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8=
@@ -831,6 +834,8 @@ github.com/denverdino/aliyungo v0.0.0-20190125010748-a747050bb1ba/go.mod h1:dV8l
 github.com/devigned/tab v0.1.1/go.mod h1:XG9mPq0dFghrYvoBF3xdRrJzSTX1b7IQrvaL9mzjeJY=
 github.com/dgrijalva/jwt-go v0.0.0-20170104182250-a601269ab70c/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
 github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
+github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
+github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
 github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
 github.com/dgryski/go-sip13 v0.0.0-20200911182023-62edffca9245/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
 github.com/digitalocean/godo v1.78.0/go.mod h1:GBmu8MkjZmNARE7IXRPmkbbnocNN8+uBm0xbEVw2LCs=
@@ -1017,8 +1022,8 @@ github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJn
 github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
 github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI=
 github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4=
-github.com/go-playground/validator/v10 v10.12.0 h1:E4gtWgxWxp8YSxExrQFv5BpCahla0PVF2oTTEYaWQGI=
-github.com/go-playground/validator/v10 v10.12.0/go.mod h1:hCAPuzYvKdP33pxWa+2+6AIKXEKqjIUyqsNCtbsSJrA=
+github.com/go-playground/validator/v10 v10.13.0 h1:cFRQdfaSMCOSfGCCLB20MHvuoHb/s5G8L5pu2ppK5AQ=
+github.com/go-playground/validator/v10 v10.13.0/go.mod h1:dwu7+CG8/CtBiJFZDz4e+5Upb6OLw04gtBYw0mcG/z4=
 github.com/go-resty/resty/v2 v2.1.1-0.20191201195748-d7b97669fe48/go.mod h1:dZGr0i9PLlaaTD4H/hoZIDjQ+r6xq8mgbRzHZf7f2J8=
 github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc=
 github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
@@ -1466,8 +1471,8 @@ github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
 github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k=
 github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
 github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
-github.com/leodido/go-urn v1.2.2 h1:7z68G0FCGvDk646jz1AelTYNYWrTNm0bEcFAo147wt4=
-github.com/leodido/go-urn v1.2.2/go.mod h1:kUaIbLZWttglzwNuG0pgsh5vuV6u2YcGBYz1hIPjtOQ=
+github.com/leodido/go-urn v1.2.3 h1:6BE2vPT0lqoz3fmOesHZiaiFh7889ssCo2GMvLCfiuA=
+github.com/leodido/go-urn v1.2.3/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4=
 github.com/letsencrypt/boulder v0.0.0-20221109233200-85aa52084eaf h1:ndns1qx/5dL43g16EQkPV/i8+b3l5bYQwLeoSBe7tS8=
 github.com/letsencrypt/boulder v0.0.0-20221109233200-85aa52084eaf/go.mod h1:aGkAgvWY/IUcVFfuly53REpfv5edu25oij+qHRFaraA=
 github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
@@ -1524,8 +1529,6 @@ github.com/matttproud/golang_protobuf_extensions v1.0.2/go.mod h1:BSXmuO+STAnVfr
 github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
 github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
 github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88Jz2VyhSmden33/aXg4oVIY=
-github.com/mediocregopher/radix/v4 v4.1.2 h1:Pj7XnNK5WuzzFy63g98pnccainAePK+aZNQRvxSvj2I=
-github.com/mediocregopher/radix/v4 v4.1.2/go.mod h1:ajchozX/6ELmydxWeWM6xCFHVpZ4+67LXHOTOVR0nCE=
 github.com/microsoft/ApplicationInsights-Go v0.4.4/go.mod h1:fKRUseBqkw6bDiXTs3ESTiU/4YTIHsQS4W3fP2ieF4U=
 github.com/microsoft/go-mssqldb v0.18.0/go.mod h1:ukJCBnnzLzpVF0qYRT+eg1e+eSwjeQ7IvenUv8QPook=
 github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
@@ -1763,6 +1766,8 @@ github.com/prometheus/prometheus v0.42.0/go.mod h1:Pfqb/MLnnR2KK+0vchiaH39jXxvLM
 github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
 github.com/rakyll/embedmd v0.0.0-20171029212350-c8060a0752a2/go.mod h1:7jOTMgqac46PZcF54q6l2hkLEG8op93fZu61KmxWDV4=
 github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
+github.com/redis/go-redis/v9 v9.0.4 h1:FC82T+CHJ/Q/PdyLW++GeCO+Ol59Y4T7R4jbgjvktgc=
+github.com/redis/go-redis/v9 v9.0.4/go.mod h1:WqMKv5vnQbRuZstUwxQI195wHy+t4PuXDOjzMvcuQHk=
 github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
 github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
 github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
@@ -1779,7 +1784,6 @@ github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OK
 github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
 github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
 github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
-github.com/rwtodd/Go.Sed v0.0.0-20210816025313-55464686f9ef/go.mod h1:8AEUvGVi2uQ5b24BIhcr0GCcpd/RNAFWaN2CJFrWIIQ=
 github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
 github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
 github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk=
@@ -1817,7 +1821,6 @@ github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6Mwd
 github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
 github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
 github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
-github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
 github.com/smallstep/assert v0.0.0-20200723003110-82e2b9b3b262 h1:unQFBIznI+VYD1/1fApl1A+9VcBk+9dcqGfnePY87LY=
 github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
 github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
@@ -1898,9 +1901,6 @@ github.com/theupdateframework/go-tuf v0.5.2/go.mod h1:SyMV5kg5n4uEclsyxXJZI2UxPF
 github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
 github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
 github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
-github.com/tilinna/clock v1.0.2/go.mod h1:ZsP7BcY7sEEz7ktc0IVy8Us6boDrK8VradlKRUGfOao=
-github.com/tilinna/clock v1.1.0 h1:6IQQQCo6KoBxVudv6gwtY8o4eDfhHo8ojA5dP0MfhSs=
-github.com/tilinna/clock v1.1.0/go.mod h1:ZsP7BcY7sEEz7ktc0IVy8Us6boDrK8VradlKRUGfOao=
 github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 h1:e/5i7d4oYZ+C1wj2THlRK+oAhjeS/TRQwMfkIuet3w0=
 github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399/go.mod h1:LdwHTNJT99C5fTAzDz0ud328OgXz+gierycbcIx2fRs=
 github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
@@ -2459,7 +2459,6 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc
 golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220624220833-87e55d714810/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220731174439-a90be440212d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
diff --git a/hack/tools/go.mod b/hack/tools/go.mod
index 73d3bae..eda997a 100644
--- a/hack/tools/go.mod
+++ b/hack/tools/go.mod
@@ -3,7 +3,7 @@ module github.com/sigstore/rekor/hack/tools
 go 1.20
 
 require (
-	github.com/AdaLogics/go-fuzz-headers v0.0.0-20220708163326-82d177caec6e
+	github.com/AdamKorcz/go-fuzz-headers-1 v0.0.0-20230329111138-12e09aba5ebd
 	github.com/go-swagger/go-swagger v0.30.4
 	github.com/google/trillian v1.5.1
 	github.com/wadey/gocovmerge v0.0.0-20160331181800-b5bfa59ec0ad
diff --git a/hack/tools/go.sum b/hack/tools/go.sum
index 02e81f9..84fc695 100644
--- a/hack/tools/go.sum
+++ b/hack/tools/go.sum
@@ -66,8 +66,8 @@ cloud.google.com/go/trace v1.4.0/go.mod h1:UG0v8UBqzusp+z63o7FK74SdFE+AXpCLdFb1r
 contrib.go.opencensus.io/exporter/stackdriver v0.13.12 h1:bjBKzIf7/TAkxd7L2utGaLM78bmUWlCval5K9UeElbY=
 contrib.go.opencensus.io/exporter/stackdriver v0.13.12/go.mod h1:mmxnWlrvrFdpiOHOhxBaVi1rkc0WOqhgfknj4Yg0SeQ=
 dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
-github.com/AdaLogics/go-fuzz-headers v0.0.0-20220708163326-82d177caec6e h1:Gvv863NmqhY4a/MygkMdO0EQHB/alMtAm3qPMOkljFc=
-github.com/AdaLogics/go-fuzz-headers v0.0.0-20220708163326-82d177caec6e/go.mod h1:i9fr2JpcEcY/IHEvzCM3qXUZYOQHgR89dt4es1CgMhc=
+github.com/AdamKorcz/go-fuzz-headers-1 v0.0.0-20230329111138-12e09aba5ebd h1:1tbEqR4NyQLgiod7vLXSswHteGetAVZrMGCqrJxLKRs=
+github.com/AdamKorcz/go-fuzz-headers-1 v0.0.0-20230329111138-12e09aba5ebd/go.mod h1:0vOOKsOMKPThRu9lQMAxcQ8D60f8U+wHXl07SyUw0+U=
 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
 github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
 github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=
@@ -446,7 +446,6 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxv
 github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
 github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
 github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
-github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
 github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
 github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
 github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
@@ -565,8 +564,7 @@ github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPx
 github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
 github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
 github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
-github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
-github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
+github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
 github.com/soheilhy/cmux v0.1.5 h1:jjzc5WVemNEDTLwv9tlmemhC73tI08BNOIGwBOo10Js=
 github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
 github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4=
@@ -1149,7 +1147,6 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8
 gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
-gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
 gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
 gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
 gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
diff --git a/hack/tools/tools.go b/hack/tools/tools.go
index 5aa62ec..aac0d23 100644
--- a/hack/tools/tools.go
+++ b/hack/tools/tools.go
@@ -20,7 +20,7 @@
 package tools
 
 import (
-	_ "github.com/AdaLogics/go-fuzz-headers"
+	_ "github.com/AdamKorcz/go-fuzz-headers-1"
 	_ "github.com/go-swagger/go-swagger/cmd/swagger"
 	_ "github.com/wadey/gocovmerge"
 
diff --git a/oid-info.md b/oid-info.md
new file mode 100644
index 0000000..1f2269c
--- /dev/null
+++ b/oid-info.md
@@ -0,0 +1,14 @@
+# Rekor OID Information
+
+## Description
+
+This document defines Rekor
+[OID values](https://github.com/sigstore/sigstore/blob/main/docs/oid-info.md).
+
+Rekor reserves the `1.3.6.1.4.1.57264.3` OID root for all of its values.
+
+## Directory
+
+| OID                   | Name                 | Tag Type     | Description                                                                                                                                                        |
+| --------------------- | -------------------- | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
+| 1.3.6.1.4.1.57264.3.1 | TransparencyLogEntry | `UTF8STRING` | Proto serialized [TransparencyLogEntry](https://github.com/sigstore/protobuf-specs/blob/4dbf10bc287d76f1bfa68c05a78f3f5add5f56fe/protos/sigstore_rekor.proto#L89). |
diff --git a/pkg/api/api.go b/pkg/api/api.go
index 84ca4ac..32dd155 100644
--- a/pkg/api/api.go
+++ b/pkg/api/api.go
@@ -24,7 +24,7 @@ import (
 	"time"
 
 	"github.com/google/trillian"
-	radix "github.com/mediocregopher/radix/v4"
+	"github.com/redis/go-redis/v9"
 	"github.com/spf13/viper"
 	"golang.org/x/exp/slices"
 	"google.golang.org/grpc"
@@ -34,6 +34,7 @@ import (
 	"github.com/sigstore/rekor/pkg/sharding"
 	"github.com/sigstore/rekor/pkg/signer"
 	"github.com/sigstore/rekor/pkg/storage"
+	"github.com/sigstore/rekor/pkg/util"
 	"github.com/sigstore/sigstore/pkg/cryptoutils"
 	"github.com/sigstore/sigstore/pkg/signature"
 	"github.com/sigstore/sigstore/pkg/signature/options"
@@ -82,7 +83,7 @@ func NewAPI(treeID uint) (*API, error) {
 	tid := int64(treeID)
 	if tid == 0 {
 		log.Logger.Info("No tree ID specified, attempting to create a new tree")
-		t, err := createAndInitTree(ctx, logAdminClient, logClient)
+		t, err := util.CreateAndInitTree(ctx, logAdminClient, logClient)
 		if err != nil {
 			return nil, fmt.Errorf("create and init tree: %w", err)
 		}
@@ -122,12 +123,11 @@ func NewAPI(treeID uint) (*API, error) {
 
 var (
 	api           *API
-	redisClient   radix.Client
 	storageClient storage.AttestationStorage
+	redisClient   *redis.Client
 )
 
 func ConfigureAPI(treeID uint) {
-	cfg := radix.PoolConfig{}
 	var err error
 
 	api, err = NewAPI(treeID)
@@ -135,10 +135,11 @@ func ConfigureAPI(treeID uint) {
 		log.Logger.Panic(err)
 	}
 	if viper.GetBool("enable_retrieve_api") || slices.Contains(viper.GetStringSlice("enabled_api_endpoints"), "searchIndex") {
-		redisClient, err = cfg.New(context.Background(), "tcp", fmt.Sprintf("%v:%v", viper.GetString("redis_server.address"), viper.GetUint64("redis_server.port")))
-		if err != nil {
-			log.Logger.Panic("failure connecting to redis instance: ", err)
-		}
+		redisClient = redis.NewClient(&redis.Options{
+			Addr:    fmt.Sprintf("%v:%v", viper.GetString("redis_server.address"), viper.GetUint64("redis_server.port")),
+			Network: "tcp",
+			DB:      0, // default DB
+		})
 	}
 
 	if viper.GetBool("enable_attestation_storage") {
diff --git a/pkg/api/entries.go b/pkg/api/entries.go
index 294304b..4abc5db 100644
--- a/pkg/api/entries.go
+++ b/pkg/api/entries.go
@@ -67,7 +67,7 @@ func signEntry(ctx context.Context, signer signature.Signer, entry models.LogEnt
 }
 
 // logEntryFromLeaf creates a signed LogEntry struct from trillian structs
-func logEntryFromLeaf(ctx context.Context, signer signature.Signer, tc TrillianClient, leaf *trillian.LogLeaf,
+func logEntryFromLeaf(ctx context.Context, signer signature.Signer, tc util.TrillianClient, leaf *trillian.LogLeaf,
 	signedLogRoot *trillian.SignedLogRoot, proof *trillian.Proof, tid int64, ranges sharding.LogRanges) (models.LogEntry, error) {
 
 	log.ContextLogger(ctx).Debugf("log entry from leaf %d", leaf.GetLeafIndex())
@@ -93,7 +93,7 @@ func logEntryFromLeaf(ctx context.Context, signer signature.Signer, tc TrillianC
 		return nil, fmt.Errorf("signing entry error: %w", err)
 	}
 
-	scBytes, err := util.CreateAndSignCheckpoint(ctx, viper.GetString("rekor_server.hostname"), tc.logID, root, api.signer)
+	scBytes, err := util.CreateAndSignCheckpoint(ctx, viper.GetString("rekor_server.hostname"), tid, root, api.signer)
 	if err != nil {
 		return nil, err
 	}
@@ -186,16 +186,16 @@ func createLogEntry(params entries.CreateLogEntryParams) (models.LogEntry, middl
 		return nil, handleRekorAPIError(params, http.StatusInternalServerError, err, failedToGenerateCanonicalEntry)
 	}
 
-	tc := NewTrillianClient(ctx)
+	tc := util.NewTrillianClient(ctx, api.logClient, api.logID)
 
-	resp := tc.addLeaf(leaf)
+	resp := tc.AddLeaf(leaf)
 	// this represents overall GRPC response state (not the results of insertion into the log)
-	if resp.status != codes.OK {
-		return nil, handleRekorAPIError(params, http.StatusInternalServerError, fmt.Errorf("grpc error: %w", resp.err), trillianUnexpectedResult)
+	if resp.Status != codes.OK {
+		return nil, handleRekorAPIError(params, http.StatusInternalServerError, fmt.Errorf("grpc error: %w", resp.Err), trillianUnexpectedResult)
 	}
 
 	// this represents the results of inserting the proposed leaf into the log; status is nil in success path
-	insertionStatus := resp.getAddResult.QueuedLeaf.Status
+	insertionStatus := resp.GetAddResult.QueuedLeaf.Status
 	if insertionStatus != nil {
 		switch insertionStatus.Code {
 		case int32(code.Code_OK):
@@ -212,10 +212,10 @@ func createLogEntry(params entries.CreateLogEntryParams) (models.LogEntry, middl
 	// We made it this far, that means the entry was successfully added.
 	metricNewEntries.Inc()
 
-	queuedLeaf := resp.getAddResult.QueuedLeaf.Leaf
+	queuedLeaf := resp.GetAddResult.QueuedLeaf.Leaf
 
 	uuid := hex.EncodeToString(queuedLeaf.GetMerkleLeafHash())
-	activeTree := fmt.Sprintf("%x", tc.logID)
+	activeTree := fmt.Sprintf("%x", api.logID)
 	entryIDstruct, err := sharding.CreateEntryIDFromParts(activeTree, uuid)
 	if err != nil {
 		err := fmt.Errorf("error creating EntryID from active treeID %v and uuid %v: %w", activeTree, uuid, err)
@@ -271,15 +271,15 @@ func createLogEntry(params entries.CreateLogEntryParams) (models.LogEntry, middl
 	}
 
 	root := &ttypes.LogRootV1{}
-	if err := root.UnmarshalBinary(resp.getLeafAndProofResult.SignedLogRoot.LogRoot); err != nil {
+	if err := root.UnmarshalBinary(resp.GetLeafAndProofResult.SignedLogRoot.LogRoot); err != nil {
 		return nil, handleRekorAPIError(params, http.StatusInternalServerError, fmt.Errorf("error unmarshalling log root: %v", err), sthGenerateError)
 	}
 	hashes := []string{}
-	for _, hash := range resp.getLeafAndProofResult.Proof.Hashes {
+	for _, hash := range resp.GetLeafAndProofResult.Proof.Hashes {
 		hashes = append(hashes, hex.EncodeToString(hash))
 	}
 
-	scBytes, err := util.CreateAndSignCheckpoint(ctx, viper.GetString("rekor_server.hostname"), tc.logID, root, api.signer)
+	scBytes, err := util.CreateAndSignCheckpoint(ctx, viper.GetString("rekor_server.hostname"), api.logID, root, api.signer)
 	if err != nil {
 		return nil, handleRekorAPIError(params, http.StatusInternalServerError, err, sthGenerateError)
 	}
@@ -405,22 +405,22 @@ func SearchLogQueryHandler(params entries.SearchLogQueryParams) middleware.Respo
 		for i, hash := range searchHashes {
 			var results map[int64]*trillian.GetEntryAndProofResponse
 			for _, shard := range api.logRanges.AllShards() {
-				tcs := NewTrillianClientFromTreeID(httpReqCtx, shard)
-				resp := tcs.getLeafAndProofByHash(hash)
-				switch resp.status {
+				tcs := util.NewTrillianClient(httpReqCtx, api.logClient, shard)
+				resp := tcs.GetLeafAndProofByHash(hash)
+				switch resp.Status {
 				case codes.OK:
-					leafResult := resp.getLeafAndProofResult
+					leafResult := resp.GetLeafAndProofResult
 					if leafResult != nil && leafResult.Leaf != nil {
 						if results == nil {
 							results = map[int64]*trillian.GetEntryAndProofResponse{}
 						}
-						results[shard] = resp.getLeafAndProofResult
+						results[shard] = resp.GetLeafAndProofResult
 					}
 				case codes.NotFound:
 					// do nothing here, do not throw 404 error
 					continue
 				default:
-					return handleRekorAPIError(params, http.StatusInternalServerError, fmt.Errorf("error getLeafAndProofByHash(%s): code: %v, msg %v", hex.EncodeToString(hash), resp.status, resp.err), trillianCommunicationError)
+					return handleRekorAPIError(params, http.StatusInternalServerError, fmt.Errorf("error getLeafAndProofByHash(%s): code: %v, msg %v", hex.EncodeToString(hash), resp.Status, resp.Err), trillianCommunicationError)
 				}
 			}
 			searchByHashResults[i] = results
@@ -431,7 +431,7 @@ func SearchLogQueryHandler(params entries.SearchLogQueryParams) middleware.Respo
 				if leafResp == nil {
 					continue
 				}
-				tcs := NewTrillianClientFromTreeID(httpReqCtx, shard)
+				tcs := util.NewTrillianClient(httpReqCtx, api.logClient, shard)
 				logEntry, err := logEntryFromLeaf(httpReqCtx, api.signer, tcs, leafResp.Leaf, leafResp.SignedLogRoot, leafResp.Proof, shard, api.logRanges)
 				if err != nil {
 					return handleRekorAPIError(params, http.StatusInternalServerError, err, err.Error())
@@ -461,19 +461,19 @@ func retrieveLogEntryByIndex(ctx context.Context, logIndex int) (models.LogEntry
 	log.ContextLogger(ctx).Infof("Retrieving log entry by index %d", logIndex)
 
 	tid, resolvedIndex := api.logRanges.ResolveVirtualIndex(logIndex)
-	tc := NewTrillianClientFromTreeID(ctx, tid)
+	tc := util.NewTrillianClient(ctx, api.logClient, tid)
 	log.ContextLogger(ctx).Debugf("Retrieving resolved index %v from TreeID %v", resolvedIndex, tid)
 
-	resp := tc.getLeafAndProofByIndex(resolvedIndex)
-	switch resp.status {
+	resp := tc.GetLeafAndProofByIndex(resolvedIndex)
+	switch resp.Status {
 	case codes.OK:
 	case codes.NotFound, codes.OutOfRange, codes.InvalidArgument:
 		return models.LogEntry{}, ErrNotFound
 	default:
-		return models.LogEntry{}, fmt.Errorf("grpc err: %w: %s", resp.err, trillianCommunicationError)
+		return models.LogEntry{}, fmt.Errorf("grpc err: %w: %s", resp.Err, trillianCommunicationError)
 	}
 
-	result := resp.getLeafAndProofResult
+	result := resp.GetLeafAndProofResult
 	leaf := result.Leaf
 	if leaf == nil {
 		return models.LogEntry{}, ErrNotFound
@@ -525,13 +525,13 @@ func retrieveUUIDFromTree(ctx context.Context, uuid string, tid int64) (models.L
 		return models.LogEntry{}, types.ValidationError(err)
 	}
 
-	tc := NewTrillianClientFromTreeID(ctx, tid)
+	tc := util.NewTrillianClient(ctx, api.logClient, tid)
 	log.ContextLogger(ctx).Debugf("Attempting to retrieve UUID %v from TreeID %v", uuid, tid)
 
-	resp := tc.getLeafAndProofByHash(hashValue)
-	switch resp.status {
+	resp := tc.GetLeafAndProofByHash(hashValue)
+	switch resp.Status {
 	case codes.OK:
-		result := resp.getLeafAndProofResult
+		result := resp.GetLeafAndProofResult
 		leaf := result.Leaf
 		if leaf == nil {
 			return models.LogEntry{}, ErrNotFound
@@ -546,7 +546,7 @@ func retrieveUUIDFromTree(ctx context.Context, uuid string, tid int64) (models.L
 	case codes.NotFound:
 		return models.LogEntry{}, ErrNotFound
 	default:
-		log.ContextLogger(ctx).Errorf("Unexpected response code while attempting to retrieve UUID %v from TreeID %v: %v", uuid, tid, resp.status)
+		log.ContextLogger(ctx).Errorf("Unexpected response code while attempting to retrieve UUID %v from TreeID %v: %v", uuid, tid, resp.Status)
 		return models.LogEntry{}, errors.New("unexpected error")
 	}
 }
diff --git a/pkg/api/index.go b/pkg/api/index.go
index afda3aa..7286425 100644
--- a/pkg/api/index.go
+++ b/pkg/api/index.go
@@ -25,7 +25,6 @@ import (
 
 	"github.com/go-openapi/runtime/middleware"
 	"github.com/go-openapi/swag"
-	radix "github.com/mediocregopher/radix/v4"
 
 	"github.com/sigstore/rekor/pkg/generated/models"
 	"github.com/sigstore/rekor/pkg/generated/restapi/operations/index"
@@ -46,8 +45,8 @@ func SearchIndexHandler(params index.SearchIndexParams) middleware.Responder {
 	if params.Query.Hash != "" {
 		// This must be a valid hash
 		sha := util.PrefixSHA(params.Query.Hash)
-		var resultUUIDs []string
-		if err := redisClient.Do(httpReqCtx, radix.Cmd(&resultUUIDs, "LRANGE", strings.ToLower(sha), "0", "-1")); err != nil {
+		resultUUIDs, err := redisClient.LRange(httpReqCtx, strings.ToLower(sha), 0, -1).Result()
+		if err != nil {
 			return handleRekorAPIError(params, http.StatusInternalServerError, fmt.Errorf("redis client: %w", err), redisUnexpectedResult)
 		}
 		result.Add(resultUUIDs)
@@ -73,15 +72,15 @@ func SearchIndexHandler(params index.SearchIndexParams) middleware.Responder {
 		}
 
 		keyHash := sha256.Sum256(canonicalKey)
-		var resultUUIDs []string
-		if err := redisClient.Do(httpReqCtx, radix.Cmd(&resultUUIDs, "LRANGE", strings.ToLower(hex.EncodeToString(keyHash[:])), "0", "-1")); err != nil {
+		resultUUIDs, err := redisClient.LRange(httpReqCtx, strings.ToLower(hex.EncodeToString(keyHash[:])), 0, -1).Result()
+		if err != nil {
 			return handleRekorAPIError(params, http.StatusInternalServerError, fmt.Errorf("redis client: %w", err), redisUnexpectedResult)
 		}
 		result.Add(resultUUIDs)
 	}
 	if params.Query.Email != "" {
-		var resultUUIDs []string
-		if err := redisClient.Do(httpReqCtx, radix.Cmd(&resultUUIDs, "LRANGE", strings.ToLower(params.Query.Email.String()), "0", "-1")); err != nil {
+		resultUUIDs, err := redisClient.LRange(httpReqCtx, strings.ToLower(params.Query.Email.String()), 0, -1).Result()
+		if err != nil {
 			return handleRekorAPIError(params, http.StatusInternalServerError, fmt.Errorf("redis client: %w", err), redisUnexpectedResult)
 		}
 		result.Add(resultUUIDs)
@@ -101,7 +100,8 @@ func SearchIndexNotImplementedHandler(params index.SearchIndexParams) middleware
 }
 
 func addToIndex(ctx context.Context, key, value string) error {
-	if err := redisClient.Do(ctx, radix.Cmd(nil, "LPUSH", key, value)); err != nil {
+	_, err := redisClient.LPush(ctx, key, value).Result()
+	if err != nil {
 		return fmt.Errorf("redis client: %w", err)
 	}
 	return nil
diff --git a/pkg/api/public_key.go b/pkg/api/public_key.go
index 22e0c04..e7e6b0f 100644
--- a/pkg/api/public_key.go
+++ b/pkg/api/public_key.go
@@ -26,10 +26,8 @@ import (
 )
 
 func GetPublicKeyHandler(params pubkey.GetPublicKeyParams) middleware.Responder {
-	ctx := params.HTTPRequest.Context()
 	treeID := swag.StringValue(params.TreeID)
-	tc := NewTrillianClient(ctx)
-	pk, err := tc.ranges.PublicKey(api.pubkey, treeID)
+	pk, err := api.logRanges.PublicKey(api.pubkey, treeID)
 	if err != nil {
 		return handleRekorAPIError(params, http.StatusBadRequest, err, "")
 	}
diff --git a/pkg/api/tlog.go b/pkg/api/tlog.go
index e6bbdcc..4419a95 100644
--- a/pkg/api/tlog.go
+++ b/pkg/api/tlog.go
@@ -36,12 +36,12 @@ import (
 
 // GetLogInfoHandler returns the current size of the tree and the STH
 func GetLogInfoHandler(params tlog.GetLogInfoParams) middleware.Responder {
-	tc := NewTrillianClient(params.HTTPRequest.Context())
+	tc := util.NewTrillianClient(params.HTTPRequest.Context(), api.logClient, api.logID)
 
 	// for each inactive shard, get the loginfo
 	var inactiveShards []*models.InactiveShardLogInfo
-	for _, shard := range tc.ranges.GetInactive() {
-		if shard.TreeID == tc.ranges.ActiveTreeID() {
+	for _, shard := range api.logRanges.GetInactive() {
+		if shard.TreeID == api.logRanges.ActiveTreeID() {
 			break
 		}
 		// Get details for this inactive shard
@@ -52,11 +52,11 @@ func GetLogInfoHandler(params tlog.GetLogInfoParams) middleware.Responder {
 		inactiveShards = append(inactiveShards, is)
 	}
 
-	resp := tc.getLatest(0)
-	if resp.status != codes.OK {
-		return handleRekorAPIError(params, http.StatusInternalServerError, fmt.Errorf("grpc error: %w", resp.err), trillianCommunicationError)
+	resp := tc.GetLatest(0)
+	if resp.Status != codes.OK {
+		return handleRekorAPIError(params, http.StatusInternalServerError, fmt.Errorf("grpc error: %w", resp.Err), trillianCommunicationError)
 	}
-	result := resp.getLatestResult
+	result := resp.GetLatestResult
 
 	root := &types.LogRootV1{}
 	if err := root.UnmarshalBinary(result.SignedLogRoot.LogRoot); err != nil {
@@ -67,7 +67,7 @@ func GetLogInfoHandler(params tlog.GetLogInfoParams) middleware.Responder {
 	treeSize := int64(root.TreeSize)
 
 	scBytes, err := util.CreateAndSignCheckpoint(params.HTTPRequest.Context(),
-		viper.GetString("rekor_server.hostname"), tc.ranges.ActiveTreeID(), root, api.signer)
+		viper.GetString("rekor_server.hostname"), api.logRanges.ActiveTreeID(), root, api.signer)
 	if err != nil {
 		return handleRekorAPIError(params, http.StatusInternalServerError, err, sthGenerateError)
 	}
@@ -76,7 +76,7 @@ func GetLogInfoHandler(params tlog.GetLogInfoParams) middleware.Responder {
 		RootHash:       &hashString,
 		TreeSize:       &treeSize,
 		SignedTreeHead: stringPointer(string(scBytes)),
-		TreeID:         stringPointer(fmt.Sprintf("%d", tc.logID)),
+		TreeID:         stringPointer(fmt.Sprintf("%d", api.logID)),
 		InactiveShards: inactiveShards,
 	}
 
@@ -92,21 +92,21 @@ func GetLogProofHandler(params tlog.GetLogProofParams) middleware.Responder {
 	if *params.FirstSize > params.LastSize {
 		return handleRekorAPIError(params, http.StatusBadRequest, nil, fmt.Sprintf(firstSizeLessThanLastSize, *params.FirstSize, params.LastSize))
 	}
-	tc := NewTrillianClient(params.HTTPRequest.Context())
+	tc := util.NewTrillianClient(params.HTTPRequest.Context(), api.logClient, api.logID)
 	if treeID := swag.StringValue(params.TreeID); treeID != "" {
 		id, err := strconv.Atoi(treeID)
 		if err != nil {
 			log.Logger.Infof("Unable to convert %s to string, skipping initializing client with Tree ID: %v", treeID, err)
 		} else {
-			tc = NewTrillianClientFromTreeID(params.HTTPRequest.Context(), int64(id))
+			tc = util.NewTrillianClient(params.HTTPRequest.Context(), api.logClient, int64(id))
 		}
 	}
 
-	resp := tc.getConsistencyProof(*params.FirstSize, params.LastSize)
-	if resp.status != codes.OK {
-		return handleRekorAPIError(params, http.StatusInternalServerError, fmt.Errorf("grpc error: %w", resp.err), trillianCommunicationError)
+	resp := tc.GetConsistencyProof(*params.FirstSize, params.LastSize)
+	if resp.Status != codes.OK {
+		return handleRekorAPIError(params, http.StatusInternalServerError, fmt.Errorf("grpc error: %w", resp.Err), trillianCommunicationError)
 	}
-	result := resp.getConsistencyProofResult
+	result := resp.GetConsistencyProofResult
 
 	var root types.LogRootV1
 	if err := root.UnmarshalBinary(result.SignedLogRoot.LogRoot); err != nil {
@@ -136,12 +136,12 @@ func GetLogProofHandler(params tlog.GetLogProofParams) middleware.Responder {
 }
 
 func inactiveShardLogInfo(ctx context.Context, tid int64) (*models.InactiveShardLogInfo, error) {
-	tc := NewTrillianClientFromTreeID(ctx, tid)
-	resp := tc.getLatest(0)
-	if resp.status != codes.OK {
-		return nil, fmt.Errorf("resp code is %d", resp.status)
+	tc := util.NewTrillianClient(ctx, api.logClient, tid)
+	resp := tc.GetLatest(0)
+	if resp.Status != codes.OK {
+		return nil, fmt.Errorf("resp code is %d", resp.Status)
 	}
-	result := resp.getLatestResult
+	result := resp.GetLatestResult
 
 	root := &types.LogRootV1{}
 	if err := root.UnmarshalBinary(result.SignedLogRoot.LogRoot); err != nil {
diff --git a/pkg/fuzz/alpine_utils.go b/pkg/fuzz/alpine_utils.go
index 3d429ca..1bb6113 100644
--- a/pkg/fuzz/alpine_utils.go
+++ b/pkg/fuzz/alpine_utils.go
@@ -23,7 +23,7 @@ import (
 	"os"
 	"strings"
 
-	fuzz "github.com/AdaLogics/go-fuzz-headers"
+	fuzz "github.com/AdamKorcz/go-fuzz-headers-1"
 	"github.com/sigstore/rekor/pkg/types"
 )
 
diff --git a/pkg/fuzz/fuzz_utils.go b/pkg/fuzz/fuzz_utils.go
index c4f6c07..15f274c 100644
--- a/pkg/fuzz/fuzz_utils.go
+++ b/pkg/fuzz/fuzz_utils.go
@@ -26,7 +26,7 @@ import (
 	"go.uber.org/zap"
 	"go.uber.org/zap/zapcore"
 
-	fuzz "github.com/AdaLogics/go-fuzz-headers"
+	fuzz "github.com/AdamKorcz/go-fuzz-headers-1"
 
 	"github.com/sigstore/rekor/pkg/log"
 	"github.com/sigstore/rekor/pkg/types"
diff --git a/pkg/api/trillian_client.go b/pkg/util/trillian_client.go
similarity index 62%
rename from pkg/api/trillian_client.go
rename to pkg/util/trillian_client.go
index f0043d9..e1d0d5d 100644
--- a/pkg/api/trillian_client.go
+++ b/pkg/util/trillian_client.go
@@ -13,7 +13,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package api
+package util
 
 import (
 	"context"
@@ -22,7 +22,6 @@ import (
 	"time"
 
 	"github.com/sigstore/rekor/pkg/log"
-	"github.com/sigstore/rekor/pkg/sharding"
 	"github.com/transparency-dev/merkle/proof"
 	"github.com/transparency-dev/merkle/rfc6962"
 
@@ -35,38 +34,38 @@ import (
 	"github.com/google/trillian/types"
 )
 
+// TrillianClient provides a wrapper around the Trillian client
 type TrillianClient struct {
 	client  trillian.TrillianLogClient
-	ranges  sharding.LogRanges
 	logID   int64
 	context context.Context
 }
 
-func NewTrillianClient(ctx context.Context) TrillianClient {
+// NewTrillianClient creates a TrillianClient with the given Trillian client and log/tree ID.
+func NewTrillianClient(ctx context.Context, logClient trillian.TrillianLogClient, logID int64) TrillianClient {
 	return TrillianClient{
-		client:  api.logClient,
-		ranges:  api.logRanges,
-		logID:   api.logID,
-		context: ctx,
-	}
-}
-
-func NewTrillianClientFromTreeID(ctx context.Context, tid int64) TrillianClient {
-	return TrillianClient{
-		client:  api.logClient,
-		logID:   tid,
+		client:  logClient,
+		logID:   logID,
 		context: ctx,
 	}
 }
 
+// Response includes a status code, an optional error message, and one of the results based on the API call
 type Response struct {
-	status                    codes.Code
-	err                       error
-	getAddResult              *trillian.QueueLeafResponse
-	getProofResult            *trillian.GetInclusionProofByHashResponse
-	getLeafAndProofResult     *trillian.GetEntryAndProofResponse
-	getLatestResult           *trillian.GetLatestSignedLogRootResponse
-	getConsistencyProofResult *trillian.GetConsistencyProofResponse
+	// Status is the status code of the response
+	Status codes.Code
+	// Error contains an error on request or client failure
+	Err error
+	// GetAddResult contains the response from queueing a leaf in Trillian
+	GetAddResult *trillian.QueueLeafResponse
+	// GetLeafAndProofResult contains the response for fetching an inclusion proof and leaf
+	GetLeafAndProofResult *trillian.GetEntryAndProofResponse
+	// GetLatestResult contains the response for the latest checkpoint
+	GetLatestResult *trillian.GetLatestSignedLogRootResponse
+	// GetConsistencyProofResult contains the response for a consistency proof between two log sizes
+	GetConsistencyProofResult *trillian.GetConsistencyProofResponse
+	// getProofResult contains the response for an inclusion proof fetched by leaf hash
+	getProofResult *trillian.GetInclusionProofByHashResponse
 }
 
 func unmarshalLogRoot(logRoot []byte) (types.LogRootV1, error) {
@@ -88,7 +87,7 @@ func (t *TrillianClient) root() (types.LogRootV1, error) {
 	return unmarshalLogRoot(resp.SignedLogRoot.LogRoot)
 }
 
-func (t *TrillianClient) addLeaf(byteValue []byte) *Response {
+func (t *TrillianClient) AddLeaf(byteValue []byte) *Response {
 	leaf := &trillian.LogLeaf{
 		LeafValue: byteValue,
 	}
@@ -101,18 +100,18 @@ func (t *TrillianClient) addLeaf(byteValue []byte) *Response {
 	// check for error
 	if err != nil || (resp.QueuedLeaf.Status != nil && resp.QueuedLeaf.Status.Code != int32(codes.OK)) {
 		return &Response{
-			status:       status.Code(err),
-			err:          err,
-			getAddResult: resp,
+			Status:       status.Code(err),
+			Err:          err,
+			GetAddResult: resp,
 		}
 	}
 
 	root, err := t.root()
 	if err != nil {
 		return &Response{
-			status:       status.Code(err),
-			err:          err,
-			getAddResult: resp,
+			Status:       status.Code(err),
+			Err:          err,
+			GetAddResult: resp,
 		}
 	}
 	v := client.NewLogVerifier(rfc6962.DefaultHasher)
@@ -123,8 +122,8 @@ func (t *TrillianClient) addLeaf(byteValue []byte) *Response {
 			select {
 			case <-ctx.Done():
 				return &Response{
-					status: codes.DeadlineExceeded,
-					err:    ctx.Err(),
+					Status: codes.DeadlineExceeded,
+					Err:    ctx.Err(),
 				}
 			case <-time.After(logClient.MinMergeDelay):
 			}
@@ -134,7 +133,7 @@ func (t *TrillianClient) addLeaf(byteValue []byte) *Response {
 			if root.TreeSize >= 1 {
 				proofResp := t.getProofByHash(resp.QueuedLeaf.Leaf.MerkleLeafHash)
 				// if this call succeeds or returns an error other than "not found", return
-				if proofResp.err == nil || (proofResp.err != nil && status.Code(proofResp.err) != codes.NotFound) {
+				if proofResp.Err == nil || (proofResp.Err != nil && status.Code(proofResp.Err) != codes.NotFound) {
 					return proofResp
 				}
 				// otherwise wait for a root update before trying again
@@ -142,19 +141,19 @@ func (t *TrillianClient) addLeaf(byteValue []byte) *Response {
 
 			if _, err := logClient.WaitForRootUpdate(ctx); err != nil {
 				return &Response{
-					status: codes.Unknown,
-					err:    err,
+					Status: codes.Unknown,
+					Err:    err,
 				}
 			}
 		}
 	}
 
 	proofResp := waitForInclusion(t.context, resp.QueuedLeaf.Leaf.MerkleLeafHash)
-	if proofResp.err != nil {
+	if proofResp.Err != nil {
 		return &Response{
-			status:       status.Code(proofResp.err),
-			err:          proofResp.err,
-			getAddResult: resp,
+			Status:       status.Code(proofResp.Err),
+			Err:          proofResp.Err,
+			GetAddResult: resp,
 		}
 	}
 
@@ -162,41 +161,41 @@ func (t *TrillianClient) addLeaf(byteValue []byte) *Response {
 	if len(proofs) != 1 {
 		err := fmt.Errorf("expected 1 proof from getProofByHash for %v, found %v", hex.EncodeToString(resp.QueuedLeaf.Leaf.MerkleLeafHash), len(proofs))
 		return &Response{
-			status:       status.Code(err),
-			err:          err,
-			getAddResult: resp,
+			Status:       status.Code(err),
+			Err:          err,
+			GetAddResult: resp,
 		}
 	}
 
 	leafIndex := proofs[0].LeafIndex
-	leafResp := t.getLeafAndProofByIndex(leafIndex)
-	if leafResp.err != nil {
+	leafResp := t.GetLeafAndProofByIndex(leafIndex)
+	if leafResp.Err != nil {
 		return &Response{
-			status:       status.Code(leafResp.err),
-			err:          leafResp.err,
-			getAddResult: resp,
+			Status:       status.Code(leafResp.Err),
+			Err:          leafResp.Err,
+			GetAddResult: resp,
 		}
 	}
 
 	// overwrite queued leaf that doesn't have index set
-	resp.QueuedLeaf.Leaf = leafResp.getLeafAndProofResult.Leaf
+	resp.QueuedLeaf.Leaf = leafResp.GetLeafAndProofResult.Leaf
 
 	return &Response{
-		status:       status.Code(err),
-		err:          err,
-		getAddResult: resp,
+		Status:       status.Code(err),
+		Err:          err,
+		GetAddResult: resp,
 		// include getLeafAndProofResult for inclusion proof
-		getLeafAndProofResult: leafResp.getLeafAndProofResult,
+		GetLeafAndProofResult: leafResp.GetLeafAndProofResult,
 	}
 }
 
-func (t *TrillianClient) getLeafAndProofByHash(hash []byte) *Response {
+func (t *TrillianClient) GetLeafAndProofByHash(hash []byte) *Response {
 	// get inclusion proof for hash, extract index, then fetch leaf using index
 	proofResp := t.getProofByHash(hash)
-	if proofResp.err != nil {
+	if proofResp.Err != nil {
 		return &Response{
-			status: status.Code(proofResp.err),
-			err:    proofResp.err,
+			Status: status.Code(proofResp.Err),
+			Err:    proofResp.Err,
 		}
 	}
 
@@ -204,31 +203,31 @@ func (t *TrillianClient) getLeafAndProofByHash(hash []byte) *Response {
 	if len(proofs) != 1 {
 		err := fmt.Errorf("expected 1 proof from getProofByHash for %v, found %v", hex.EncodeToString(hash), len(proofs))
 		return &Response{
-			status: status.Code(err),
-			err:    err,
+			Status: status.Code(err),
+			Err:    err,
 		}
 	}
 
-	return t.getLeafAndProofByIndex(proofs[0].LeafIndex)
+	return t.GetLeafAndProofByIndex(proofs[0].LeafIndex)
 }
 
-func (t *TrillianClient) getLeafAndProofByIndex(index int64) *Response {
+func (t *TrillianClient) GetLeafAndProofByIndex(index int64) *Response {
 	ctx, cancel := context.WithTimeout(t.context, 20*time.Second)
 	defer cancel()
 
-	rootResp := t.getLatest(0)
-	if rootResp.err != nil {
+	rootResp := t.GetLatest(0)
+	if rootResp.Err != nil {
 		return &Response{
-			status: status.Code(rootResp.err),
-			err:    rootResp.err,
+			Status: status.Code(rootResp.Err),
+			Err:    rootResp.Err,
 		}
 	}
 
-	root, err := unmarshalLogRoot(rootResp.getLatestResult.SignedLogRoot.LogRoot)
+	root, err := unmarshalLogRoot(rootResp.GetLatestResult.SignedLogRoot.LogRoot)
 	if err != nil {
 		return &Response{
-			status: status.Code(rootResp.err),
-			err:    rootResp.err,
+			Status: status.Code(rootResp.Err),
+			Err:    rootResp.Err,
 		}
 	}
 
@@ -242,24 +241,61 @@ func (t *TrillianClient) getLeafAndProofByIndex(index int64) *Response {
 	if resp != nil && resp.Proof != nil {
 		if err := proof.VerifyInclusion(rfc6962.DefaultHasher, uint64(index), root.TreeSize, resp.GetLeaf().MerkleLeafHash, resp.Proof.Hashes, root.RootHash); err != nil {
 			return &Response{
-				status: status.Code(err),
-				err:    err,
+				Status: status.Code(err),
+				Err:    err,
 			}
 		}
 		return &Response{
-			status: status.Code(err),
-			err:    err,
-			getLeafAndProofResult: &trillian.GetEntryAndProofResponse{
+			Status: status.Code(err),
+			Err:    err,
+			GetLeafAndProofResult: &trillian.GetEntryAndProofResponse{
 				Proof:         resp.Proof,
 				Leaf:          resp.Leaf,
-				SignedLogRoot: rootResp.getLatestResult.SignedLogRoot,
+				SignedLogRoot: rootResp.GetLatestResult.SignedLogRoot,
 			},
 		}
 	}
 
 	return &Response{
-		status: status.Code(err),
-		err:    err,
+		Status: status.Code(err),
+		Err:    err,
+	}
+}
+
+func (t *TrillianClient) GetLatest(leafSizeInt int64) *Response {
+
+	ctx, cancel := context.WithTimeout(t.context, 20*time.Second)
+	defer cancel()
+
+	resp, err := t.client.GetLatestSignedLogRoot(ctx,
+		&trillian.GetLatestSignedLogRootRequest{
+			LogId:         t.logID,
+			FirstTreeSize: leafSizeInt,
+		})
+
+	return &Response{
+		Status:          status.Code(err),
+		Err:             err,
+		GetLatestResult: resp,
+	}
+}
+
+func (t *TrillianClient) GetConsistencyProof(firstSize, lastSize int64) *Response {
+
+	ctx, cancel := context.WithTimeout(t.context, 20*time.Second)
+	defer cancel()
+
+	resp, err := t.client.GetConsistencyProof(ctx,
+		&trillian.GetConsistencyProofRequest{
+			LogId:          t.logID,
+			FirstTreeSize:  firstSize,
+			SecondTreeSize: lastSize,
+		})
+
+	return &Response{
+		Status:                    status.Code(err),
+		Err:                       err,
+		GetConsistencyProofResult: resp,
 	}
 }
 
@@ -267,26 +303,26 @@ func (t *TrillianClient) getProofByHash(hashValue []byte) *Response {
 	ctx, cancel := context.WithTimeout(t.context, 20*time.Second)
 	defer cancel()
 
-	rootResp := t.getLatest(0)
-	if rootResp.err != nil {
+	rootResp := t.GetLatest(0)
+	if rootResp.Err != nil {
 		return &Response{
-			status: status.Code(rootResp.err),
-			err:    rootResp.err,
+			Status: status.Code(rootResp.Err),
+			Err:    rootResp.Err,
 		}
 	}
-	root, err := unmarshalLogRoot(rootResp.getLatestResult.SignedLogRoot.LogRoot)
+	root, err := unmarshalLogRoot(rootResp.GetLatestResult.SignedLogRoot.LogRoot)
 	if err != nil {
 		return &Response{
-			status: status.Code(rootResp.err),
-			err:    rootResp.err,
+			Status: status.Code(rootResp.Err),
+			Err:    rootResp.Err,
 		}
 	}
 
 	// issue 1308: if the tree is empty, there's no way we can return a proof
 	if root.TreeSize == 0 {
 		return &Response{
-			status: codes.NotFound,
-			err:    status.Error(codes.NotFound, "tree is empty"),
+			Status: codes.NotFound,
+			Err:    status.Error(codes.NotFound, "tree is empty"),
 		}
 	}
 
@@ -302,66 +338,29 @@ func (t *TrillianClient) getProofByHash(hashValue []byte) *Response {
 		for _, proof := range resp.Proof {
 			if err := v.VerifyInclusionByHash(&root, hashValue, proof); err != nil {
 				return &Response{
-					status: status.Code(err),
-					err:    err,
+					Status: status.Code(err),
+					Err:    err,
 				}
 			}
 		}
 		// Return an inclusion proof response with the requested
 		return &Response{
-			status: status.Code(err),
-			err:    err,
+			Status: status.Code(err),
+			Err:    err,
 			getProofResult: &trillian.GetInclusionProofByHashResponse{
 				Proof:         resp.Proof,
-				SignedLogRoot: rootResp.getLatestResult.SignedLogRoot,
+				SignedLogRoot: rootResp.GetLatestResult.SignedLogRoot,
 			},
 		}
 	}
 
 	return &Response{
-		status: status.Code(err),
-		err:    err,
-	}
-}
-
-func (t *TrillianClient) getLatest(leafSizeInt int64) *Response {
-
-	ctx, cancel := context.WithTimeout(t.context, 20*time.Second)
-	defer cancel()
-
-	resp, err := t.client.GetLatestSignedLogRoot(ctx,
-		&trillian.GetLatestSignedLogRootRequest{
-			LogId:         t.logID,
-			FirstTreeSize: leafSizeInt,
-		})
-
-	return &Response{
-		status:          status.Code(err),
-		err:             err,
-		getLatestResult: resp,
-	}
-}
-
-func (t *TrillianClient) getConsistencyProof(firstSize, lastSize int64) *Response {
-
-	ctx, cancel := context.WithTimeout(t.context, 20*time.Second)
-	defer cancel()
-
-	resp, err := t.client.GetConsistencyProof(ctx,
-		&trillian.GetConsistencyProofRequest{
-			LogId:          t.logID,
-			FirstTreeSize:  firstSize,
-			SecondTreeSize: lastSize,
-		})
-
-	return &Response{
-		status:                    status.Code(err),
-		err:                       err,
-		getConsistencyProofResult: resp,
+		Status: status.Code(err),
+		Err:    err,
 	}
 }
 
-func createAndInitTree(ctx context.Context, adminClient trillian.TrillianAdminClient, logClient trillian.TrillianLogClient) (*trillian.Tree, error) {
+func CreateAndInitTree(ctx context.Context, adminClient trillian.TrillianAdminClient, logClient trillian.TrillianLogClient) (*trillian.Tree, error) {
 	t, err := adminClient.CreateTree(ctx, &trillian.CreateTreeRequest{
 		Tree: &trillian.Tree{
 			TreeType:        trillian.TreeType_LOG,
diff --git a/release/README.md b/release/README.md
index 76ff1fc..bfd4ae6 100644
--- a/release/README.md
+++ b/release/README.md
@@ -1,11 +1,12 @@
 # Release
 
-This directory contain the files and scripts to run a cosign release.
+This directory contain the files and scripts to run a Rekor release.
 
 # Cutting a Rekor Release
 
 1. Release notes: Create a PR to update and review release notes in CHANGELOG.md.
-  - Check merged pull requests since the last release and make sure enhancements, bug fixes, and authors are reflected in the notes.
+
+Check merged pull requests since the last release and make sure enhancements, bug fixes, and authors are reflected in the notes.
 
 You can get a list of pull requests since the last release by substituting in the date of the last release and running:
 
@@ -19,46 +20,41 @@ and a list of authors by running:
 git log --pretty="* %an" --after="YYYY-MM-DD" | sort -u
 ```
 
-2. Tag the repository
+2. Open a Pull Request to update CHANGELOG.md
+
+3. Tag the repository
+
+**WARNING**: Tags should not be updated to a new ref or deleted/recreated after creation. Go provides a [checksum database](https://sum.golang.org/)
+that persists an immutable mapping between version and ref, and updating the tag will break clients that have already downloaded the release.
 
 ```shell
-$ export RELEASE_TAG=<release version, eg "v1.1.0">
+$ export RELEASE_TAG=<release version, eg "v2.0.2">
 $ git tag -s ${RELEASE_TAG} -m "${RELEASE_TAG}"
-$ git push origin ${RELEASE_TAG}
+$ git push upstream ${RELEASE_TAG}
 ```
 
-3. Submit the cloudbuild Job using the following command:
+Note that `upstream` should be the upstream `sigstore/rekor` repository. You may have to change this if you've configured remotes.
 
-```shell
-$ gcloud builds submit --config <PATH_TO_CLOUDBUILD> \
-   --substitutions _GIT_TAG=<_GIT_TAG>,_TOOL_ORG=sigstore,_TOOL_REPO=rekor,_STORAGE_LOCATION=rekor-releases,_KEY_RING=<KEY_RING>,_KEY_NAME=<KEY_NAME>,_GITHUB_USER=<GITHUB_USER> \
-   --project <GCP_PROJECT>
-```
+4. Then go to the `Actions` tab and click on the [Cut Release workflow](https://github.com/sigstore/rekor/actions/workflows/cut-release.yml). Note you need
+to be in [this list](https://github.com/sigstore/sigstore/blob/main/.github/workflows/reusable-release.yml#L45) to trigger this workflow.
+
+Click to run a workflow and insert the following parameters ("Cosign" is correct, this refers to the artifact signing key):
 
-Where:
+  - `Release tag`: the tag that use pushed for the release
+  - `Key ring for cosign key`: the value is `release-cosign`
+  - `Key name for cosign key`: the value is `cosign`
 
-- `PATH_TO_CLOUDBUILD` is the path where the cloudbuild.yaml can be found.
-- `GCP_PROJECT` is the GCP project where we will run the job.
-- `_GIT_TAG` is the release version we are publishing, this will also create the GitHub Tag.
-- `_TOOL_ORG` is the GitHub Org we will use. Default `sigstore`.
-- `_TOOL_REPO` is the repository we will use to clone. Default `cosign`.
-- `_STORAGE_LOCATION` where to push the built artifacts. Default `cosign-releases`.
-- `_KEY_RING` key ring name of your cosign key.
-- `_KEY_NAME` key name of your  cosign key.
-- `_KEY_VERSION` version of the key storaged in KMS. Default `1`.
-- `_KEY_LOCATION` location in GCP where the key is storaged. Default `global`.
-- `_GITHUB_USER` GitHub user to authenticate for pushing to GHCR.
+That will trigger a CloudBuild job and will run the release using `goreleaser`, which will publish images to
+`gcr.io` and `ghcr.io`, and the binaries will be available in the GitHub release.
 
-4. When the job finish, whithout issues, you should be able to see in GitHub a draft release.
-You now can review the release, make any changes if needed and then publish to make it an official release.
+If you have permissions to access the project, you can follow the CloudBuild job in the `projectsigstore`(https://console.cloud.google.com/cloud-build/builds?project=projectsigstore) GCP Project.
 
-5. Send an annoucement email to `sigstore-dev@googlegroups.com` mailling list
+As the last step of the CloudBuild job, `goreleaser` will create a `draft release` in GitHub.
 
-6. Tweet about the new release with a fun new trigonometry pun!
+5. Navigate to the `Draft Release` in the Github repository. Click the `Publish Release` button to make the Release available.
 
-7. Honk!
+You might want/need to add any extra notes/breaking changes notices, upgrade paths.
 
-#### After the release:
+6. Post on the `#general` and `#rekor` Slack channels.
 
-* Add a pending new section in CHANGELOG.md to set up for the next release
-* Create a new GitHub Milestone
+7. If it's a significant release, send an announcement email to sigstore-dev@googlegroups.com mailing list.


Test patch:
diff --git a/pkg/types/alpine/fuzz_test.go b/pkg/types/alpine/fuzz_test.go
index 8417863..4f67b48 100644
--- a/pkg/types/alpine/fuzz_test.go
+++ b/pkg/types/alpine/fuzz_test.go
@@ -19,7 +19,7 @@ import (
 	"bytes"
 	"testing"
 
-	fuzz "github.com/AdaLogics/go-fuzz-headers"
+	fuzz "github.com/AdamKorcz/go-fuzz-headers-1"
 	utils "github.com/sigstore/rekor/pkg/fuzz"
 )
 
diff --git a/pkg/types/alpine/v0.0.1/fuzz_test.go b/pkg/types/alpine/v0.0.1/fuzz_test.go
index a1f3cf8..568e1d7 100644
--- a/pkg/types/alpine/v0.0.1/fuzz_test.go
+++ b/pkg/types/alpine/v0.0.1/fuzz_test.go
@@ -20,7 +20,7 @@ import (
 	"sync"
 	"testing"
 
-	fuzz "github.com/AdaLogics/go-fuzz-headers"
+	fuzz "github.com/AdamKorcz/go-fuzz-headers-1"
 
 	fuzzUtils "github.com/sigstore/rekor/pkg/fuzz"
 	"github.com/sigstore/rekor/pkg/types/alpine"
diff --git a/pkg/types/cose/v0.0.1/fuzz_test.go b/pkg/types/cose/v0.0.1/fuzz_test.go
index fb808b2..d7520d8 100644
--- a/pkg/types/cose/v0.0.1/fuzz_test.go
+++ b/pkg/types/cose/v0.0.1/fuzz_test.go
@@ -20,7 +20,7 @@ import (
 	"sync"
 	"testing"
 
-	fuzz "github.com/AdaLogics/go-fuzz-headers"
+	fuzz "github.com/AdamKorcz/go-fuzz-headers-1"
 
 	fuzzUtils "github.com/sigstore/rekor/pkg/fuzz"
 	"github.com/sigstore/rekor/pkg/types/cose"
diff --git a/pkg/types/hashedrekord/v0.0.1/fuzz_test.go b/pkg/types/hashedrekord/v0.0.1/fuzz_test.go
index ccfdd52..7adb281 100644
--- a/pkg/types/hashedrekord/v0.0.1/fuzz_test.go
+++ b/pkg/types/hashedrekord/v0.0.1/fuzz_test.go
@@ -20,7 +20,7 @@ import (
 	"sync"
 	"testing"
 
-	fuzz "github.com/AdaLogics/go-fuzz-headers"
+	fuzz "github.com/AdamKorcz/go-fuzz-headers-1"
 
 	fuzzUtils "github.com/sigstore/rekor/pkg/fuzz"
 	"github.com/sigstore/rekor/pkg/types/hashedrekord"
diff --git a/pkg/types/helm/v0.0.1/fuzz_test.go b/pkg/types/helm/v0.0.1/fuzz_test.go
index 49dbf45..5e091ee 100644
--- a/pkg/types/helm/v0.0.1/fuzz_test.go
+++ b/pkg/types/helm/v0.0.1/fuzz_test.go
@@ -21,7 +21,7 @@ import (
 	"sync"
 	"testing"
 
-	fuzz "github.com/AdaLogics/go-fuzz-headers"
+	fuzz "github.com/AdamKorcz/go-fuzz-headers-1"
 
 	fuzzUtils "github.com/sigstore/rekor/pkg/fuzz"
 	"github.com/sigstore/rekor/pkg/types/helm"
diff --git a/pkg/types/intoto/v0.0.1/fuzz_test.go b/pkg/types/intoto/v0.0.1/fuzz_test.go
index d462096..eecbfe0 100644
--- a/pkg/types/intoto/v0.0.1/fuzz_test.go
+++ b/pkg/types/intoto/v0.0.1/fuzz_test.go
@@ -20,7 +20,7 @@ import (
 	"sync"
 	"testing"
 
-	fuzz "github.com/AdaLogics/go-fuzz-headers"
+	fuzz "github.com/AdamKorcz/go-fuzz-headers-1"
 
 	fuzzUtils "github.com/sigstore/rekor/pkg/fuzz"
 	"github.com/sigstore/rekor/pkg/types/intoto"
diff --git a/pkg/types/intoto/v0.0.2/fuzz_test.go b/pkg/types/intoto/v0.0.2/fuzz_test.go
index e3cbdcf..7ef866a 100644
--- a/pkg/types/intoto/v0.0.2/fuzz_test.go
+++ b/pkg/types/intoto/v0.0.2/fuzz_test.go
@@ -20,7 +20,7 @@ import (
 	"sync"
 	"testing"
 
-	fuzz "github.com/AdaLogics/go-fuzz-headers"
+	fuzz "github.com/AdamKorcz/go-fuzz-headers-1"
 
 	fuzzUtils "github.com/sigstore/rekor/pkg/fuzz"
 	"github.com/sigstore/rekor/pkg/types/intoto"
diff --git a/pkg/types/jar/v0.0.1/fuzz_test.go b/pkg/types/jar/v0.0.1/fuzz_test.go
index 775cd24..d9b4108 100644
--- a/pkg/types/jar/v0.0.1/fuzz_test.go
+++ b/pkg/types/jar/v0.0.1/fuzz_test.go
@@ -22,7 +22,7 @@ import (
 	"sync"
 	"testing"
 
-	fuzz "github.com/AdaLogics/go-fuzz-headers"
+	fuzz "github.com/AdamKorcz/go-fuzz-headers-1"
 
 	jarutils "github.com/sassoftware/relic/lib/signjar"
 
diff --git a/pkg/types/rekord/v0.0.1/fuzz_test.go b/pkg/types/rekord/v0.0.1/fuzz_test.go
index c0d2b4c..d669f70 100644
--- a/pkg/types/rekord/v0.0.1/fuzz_test.go
+++ b/pkg/types/rekord/v0.0.1/fuzz_test.go
@@ -20,7 +20,7 @@ import (
 	"sync"
 	"testing"
 
-	fuzz "github.com/AdaLogics/go-fuzz-headers"
+	fuzz "github.com/AdamKorcz/go-fuzz-headers-1"
 
 	fuzzUtils "github.com/sigstore/rekor/pkg/fuzz"
 	"github.com/sigstore/rekor/pkg/types/rekord"
diff --git a/pkg/types/rfc3161/v0.0.1/fuzz_test.go b/pkg/types/rfc3161/v0.0.1/fuzz_test.go
index cd2070a..15e0f41 100644
--- a/pkg/types/rfc3161/v0.0.1/fuzz_test.go
+++ b/pkg/types/rfc3161/v0.0.1/fuzz_test.go
@@ -20,7 +20,7 @@ import (
 	"sync"
 	"testing"
 
-	fuzz "github.com/AdaLogics/go-fuzz-headers"
+	fuzz "github.com/AdamKorcz/go-fuzz-headers-1"
 
 	fuzzUtils "github.com/sigstore/rekor/pkg/fuzz"
 	"github.com/sigstore/rekor/pkg/types/rfc3161"
diff --git a/pkg/types/rpm/v0.0.1/fuzz_test.go b/pkg/types/rpm/v0.0.1/fuzz_test.go
index 5cab3f0..0f0de91 100644
--- a/pkg/types/rpm/v0.0.1/fuzz_test.go
+++ b/pkg/types/rpm/v0.0.1/fuzz_test.go
@@ -20,7 +20,7 @@ import (
 	"sync"
 	"testing"
 
-	fuzz "github.com/AdaLogics/go-fuzz-headers"
+	fuzz "github.com/AdamKorcz/go-fuzz-headers-1"
 
 	fuzzUtils "github.com/sigstore/rekor/pkg/fuzz"
 	"github.com/sigstore/rekor/pkg/types/rpm"
diff --git a/pkg/types/tuf/v0.0.1/fuzz_test.go b/pkg/types/tuf/v0.0.1/fuzz_test.go
index da81047..bd52cf3 100644
--- a/pkg/types/tuf/v0.0.1/fuzz_test.go
+++ b/pkg/types/tuf/v0.0.1/fuzz_test.go
@@ -20,7 +20,7 @@ import (
 	"sync"
 	"testing"
 
-	fuzz "github.com/AdaLogics/go-fuzz-headers"
+	fuzz "github.com/AdamKorcz/go-fuzz-headers-1"
 
 	fuzzUtils "github.com/sigstore/rekor/pkg/fuzz"
 	"github.com/sigstore/rekor/pkg/types/tuf"