From: Reinhard Tartler <siretart@tauware.de>
Subject: build against ttlcache v3
Origin: https://github.com/sigstore/sigstore/pull/1099

Index: golang-github-sigstore-sigstore/pkg/signature/kms/aws/client.go
===================================================================
--- golang-github-sigstore-sigstore.orig/pkg/signature/kms/aws/client.go
+++ golang-github-sigstore-sigstore/pkg/signature/kms/aws/client.go
@@ -34,7 +34,7 @@ import (
 	"github.com/aws/aws-sdk-go-v2/config"
 	"github.com/aws/aws-sdk-go-v2/service/kms"
 	"github.com/aws/aws-sdk-go-v2/service/kms/types"
-	"github.com/jellydator/ttlcache/v2"
+	"github.com/jellydator/ttlcache/v3"
 	"github.com/sigstore/sigstore/pkg/signature"
 	sigkms "github.com/sigstore/sigstore/pkg/signature/kms"
 )
@@ -56,7 +56,7 @@ type awsClient struct {
 	endpoint string
 	keyID    string
 	alias    string
-	keyCache *ttlcache.Cache
+	keyCache *ttlcache.Cache[string, cmk]
 }
 
 var (
@@ -124,9 +124,10 @@ func newAWSClient(ctx context.Context, k
 		return nil, err
 	}
 
-	a.keyCache = ttlcache.NewCache()
-	a.keyCache.SetLoaderFunction(a.keyCacheLoaderFunction)
-	a.keyCache.SkipTTLExtensionOnHit(true)
+	a.keyCache = ttlcache.New[string, cmk](
+		ttlcache.WithDisableTouchOnHit[string, cmk](),
+	)
+
 	return a, nil
 }
 
@@ -200,18 +201,6 @@ func (c *cmk) Verifier() (signature.Veri
 	}
 }
 
-func (a *awsClient) keyCacheLoaderFunction(key string) (cmk interface{}, ttl time.Duration, err error) {
-	return a.keyCacheLoaderFunctionWithContext(context.Background())(key)
-}
-
-func (a *awsClient) keyCacheLoaderFunctionWithContext(ctx context.Context) ttlcache.LoaderFunction {
-	return func(key string) (cmk interface{}, ttl time.Duration, err error) {
-		cmk, err = a.fetchCMK(ctx)
-		ttl = time.Second * 300
-		return
-	}
-}
-
 func (a *awsClient) fetchCMK(ctx context.Context) (*cmk, error) {
 	var err error
 	cmk := &cmk{}
@@ -235,15 +224,24 @@ func (a *awsClient) getHashFunc(ctx cont
 }
 
 func (a *awsClient) getCMK(ctx context.Context) (*cmk, error) {
-	c, err := a.keyCache.GetByLoader(cacheKey, a.keyCacheLoaderFunctionWithContext(ctx))
-	if err != nil {
-		return nil, err
-	}
-	cmk, ok := c.(*cmk)
-	if !ok {
-		return nil, fmt.Errorf("could not parse cache value as cmk")
+	var lerr error
+	loader := ttlcache.LoaderFunc[string, cmk](
+		func(c *ttlcache.Cache[string, cmk], key string) *ttlcache.Item[string, cmk] {
+			var k *cmk
+			k, lerr = a.fetchCMK(ctx)
+			if lerr == nil {
+				return c.Set(cacheKey, *k, time.Second*300)
+			}
+			return nil
+		},
+	)
+
+	item := a.keyCache.Get(cacheKey, ttlcache.WithLoader[string, cmk](loader))
+	if lerr == nil {
+		cmk := item.Value()
+		return &cmk, nil
 	}
-	return cmk, nil
+	return nil, lerr
 }
 
 func (a *awsClient) createKey(ctx context.Context, algorithm string) (crypto.PublicKey, error) {
@@ -252,8 +250,9 @@ func (a *awsClient) createKey(ctx contex
 	}
 
 	// look for existing key first
-	out, err := a.public(ctx)
+	cmk, err := a.getCMK(ctx)
 	if err == nil {
+		out := cmk.PublicKey
 		return out, nil
 	}
 
@@ -282,7 +281,8 @@ func (a *awsClient) createKey(ctx contex
 		return nil, fmt.Errorf("creating alias %q: %w", a.alias, err)
 	}
 
-	return a.public(ctx)
+	cmk, err = a.getCMK(ctx)
+	return cmk.PublicKey, err
 }
 
 func (a *awsClient) verify(ctx context.Context, sig, message io.Reader, opts ...signature.VerifyOption) error {
@@ -316,18 +316,6 @@ func (a *awsClient) verifyRemotely(ctx c
 	return nil
 }
 
-func (a *awsClient) public(ctx context.Context) (crypto.PublicKey, error) {
-	key, err := a.keyCache.GetByLoader(cacheKey, a.keyCacheLoaderFunctionWithContext(ctx))
-	if err != nil {
-		return nil, err
-	}
-	cmk, ok := key.(*cmk)
-	if !ok {
-		return nil, fmt.Errorf("could not parse key as cmk")
-	}
-	return cmk.PublicKey, nil
-}
-
 func (a *awsClient) sign(ctx context.Context, digest []byte, _ crypto.Hash) ([]byte, error) {
 	cmk, err := a.getCMK(ctx)
 	if err != nil {
Index: golang-github-sigstore-sigstore/pkg/signature/kms/aws/signer.go
===================================================================
--- golang-github-sigstore-sigstore.orig/pkg/signature/kms/aws/signer.go
+++ golang-github-sigstore-sigstore/pkg/signature/kms/aws/signer.go
@@ -117,7 +117,8 @@ func (a *SignerVerifier) PublicKey(opts
 		opt.ApplyContext(&ctx)
 	}
 
-	return a.client.public(ctx)
+	cmk, err := a.client.getCMK(ctx)
+	return cmk, err
 }
 
 // VerifySignature verifies the signature for the given message. Unless provided
Index: golang-github-sigstore-sigstore/pkg/signature/kms/azure/client.go
===================================================================
--- golang-github-sigstore-sigstore.orig/pkg/signature/kms/azure/client.go
+++ golang-github-sigstore-sigstore/pkg/signature/kms/azure/client.go
@@ -28,7 +28,7 @@ import (
 	"strings"
 	"time"
 
-	"github.com/jellydator/ttlcache/v2"
+	"github.com/jellydator/ttlcache/v3"
 	jose "gopkg.in/square/go-jose.v2"
 
 	kvauth "github.com/Azure/azure-sdk-for-go/services/keyvault/auth"
@@ -47,7 +47,7 @@ func init() {
 
 type azureVaultClient struct {
 	client    *keyvault.BaseClient
-	keyCache  *ttlcache.Cache
+	keyCache  *ttlcache.Cache[string, crypto.PublicKey]
 	vaultURL  string
 	vaultName string
 	keyName   string
@@ -104,12 +104,11 @@ func newAzureKMS(_ context.Context, keyR
 		vaultURL:  vaultURL,
 		vaultName: vaultName,
 		keyName:   keyName,
-		keyCache:  ttlcache.NewCache(),
+		keyCache: ttlcache.New[string, crypto.PublicKey](
+			ttlcache.WithDisableTouchOnHit[string, crypto.PublicKey](),
+		),
 	}
 
-	azClient.keyCache.SetLoaderFunction(azClient.keyCacheLoaderFunction)
-	azClient.keyCache.SkipTTLExtensionOnHit(true)
-
 	return azClient, nil
 }
 
@@ -194,20 +193,6 @@ func getKeysClient() (keyvault.BaseClien
 	return keyClient, nil
 }
 
-func (a *azureVaultClient) keyCacheLoaderFunction(key string) (data interface{}, ttl time.Duration, err error) {
-	ttl = time.Second * 300
-	var pubKey crypto.PublicKey
-
-	pubKey, err = a.fetchPublicKey(context.Background())
-	if err != nil {
-		data = nil
-		return
-	}
-
-	data = pubKey
-	return data, ttl, err
-}
-
 func (a *azureVaultClient) fetchPublicKey(ctx context.Context) (crypto.PublicKey, error) {
 	key, err := a.getKey(ctx)
 	if err != nil {
@@ -244,14 +229,30 @@ func (a *azureVaultClient) getKey(ctx co
 	return key, err
 }
 
-func (a *azureVaultClient) public() (crypto.PublicKey, error) {
-	return a.keyCache.Get(cacheKey)
+func (a *azureVaultClient) public(ctx context.Context) (crypto.PublicKey, error) {
+	var lerr error
+	loader := ttlcache.LoaderFunc[string, crypto.PublicKey](
+		func(c *ttlcache.Cache[string, crypto.PublicKey], key string) *ttlcache.Item[string, crypto.PublicKey] {
+			ttl := 300 * time.Second
+			var pubKey crypto.PublicKey
+			pubKey, lerr = a.fetchPublicKey(ctx)
+			if lerr == nil {
+				return c.Set(cacheKey, pubKey, ttl)
+			}
+			return nil
+		},
+	)
+	item := a.keyCache.Get(cacheKey, ttlcache.WithLoader[string, crypto.PublicKey](loader))
+	if lerr != nil {
+		return nil, lerr
+	}
+	return item.Value(), nil
 }
 
 func (a *azureVaultClient) createKey(ctx context.Context) (crypto.PublicKey, error) {
 	_, err := a.getKey(ctx)
 	if err == nil {
-		return a.public()
+		return a.public(ctx)
 	}
 
 	_, err = a.client.CreateKey(
@@ -276,7 +277,7 @@ func (a *azureVaultClient) createKey(ctx
 		return nil, err
 	}
 
-	return a.public()
+	return a.public(ctx)
 }
 
 func (a *azureVaultClient) sign(ctx context.Context, hash []byte) ([]byte, error) {
Index: golang-github-sigstore-sigstore/pkg/signature/kms/azure/signer.go
===================================================================
--- golang-github-sigstore-sigstore.orig/pkg/signature/kms/azure/signer.go
+++ golang-github-sigstore-sigstore/pkg/signature/kms/azure/signer.go
@@ -176,7 +176,7 @@ func (a *SignerVerifier) VerifySignature
 // PublicKey returns the public key that can be used to verify signatures created by
 // this signer. All options provided in arguments to this method are ignored.
 func (a *SignerVerifier) PublicKey(_ ...signature.PublicKeyOption) (crypto.PublicKey, error) {
-	return a.client.public()
+	return a.client.public(context.Background())
 }
 
 // CreateKey attempts to create a new key in Vault with the specified algorithm.
Index: golang-github-sigstore-sigstore/pkg/signature/kms/gcp/client.go
===================================================================
--- golang-github-sigstore-sigstore.orig/pkg/signature/kms/gcp/client.go
+++ golang-github-sigstore-sigstore/pkg/signature/kms/gcp/client.go
@@ -33,7 +33,7 @@ import (
 	kmspb "google.golang.org/genproto/googleapis/cloud/kms/v1"
 	"google.golang.org/protobuf/types/known/wrapperspb"
 
-	"github.com/jellydator/ttlcache/v2"
+	"github.com/jellydator/ttlcache/v3"
 	"github.com/sigstore/sigstore/pkg/cryptoutils"
 	"github.com/sigstore/sigstore/pkg/signature"
 	sigkms "github.com/sigstore/sigstore/pkg/signature/kms"
@@ -81,7 +81,7 @@ type gcpClient struct {
 	keyRing    string
 	keyName    string
 	version    string
-	kvCache    *ttlcache.Cache
+	kvCache    *ttlcache.Cache[string, cryptoKeyVersion]
 	kmsClient  *gcpkms.KeyManagementClient
 }
 
@@ -97,7 +97,7 @@ func newGCPClient(ctx context.Context, r
 	g := &gcpClient{
 		defaultCtx: ctx,
 		refString:  refStr,
-		kvCache:    ttlcache.NewCache(),
+		kvCache:    nil,
 	}
 	var err error
 	g.projectID, g.locationID, g.keyRing, g.keyName, g.version, err = parseReference(refStr)
@@ -110,13 +110,32 @@ func newGCPClient(ctx context.Context, r
 		return nil, fmt.Errorf("new gcp kms client: %w", err)
 	}
 
-	g.kvCache.SetLoaderFunction(g.kvCacheLoaderFunction)
-	g.kvCache.SkipTTLExtensionOnHit(true)
+	loader := ttlcache.LoaderFunc[string, cryptoKeyVersion](
+		func(c *ttlcache.Cache[string, cryptoKeyVersion], key string) *ttlcache.Item[string, cryptoKeyVersion] {
+			var ttl time.Duration
+
+			// if we're given an explicit version, cache this value forever
+			if g.version != "" {
+				ttl = time.Second * 0
+			} else {
+				ttl = time.Second * 300
+			}
+			data, err := g.keyVersionName(context.Background())
+			if err == nil {
+				item := c.Set(key, *data, ttl)
+				return item
+			}
+			return nil
+		},
+	)
+
+	g.kvCache = ttlcache.New[string, cryptoKeyVersion](
+		ttlcache.WithLoader[string, cryptoKeyVersion](loader),
+		ttlcache.WithDisableTouchOnHit[string, cryptoKeyVersion](),
+	)
+
 	// prime the cache
-	_, err = g.kvCache.Get(cacheKey)
-	if err != nil {
-		return nil, fmt.Errorf("initializing key version from GCP KMS: %w", err)
-	}
+	g.kvCache.Get(cacheKey)
 	return g, nil
 }
 
@@ -156,18 +175,6 @@ type cryptoKeyVersion struct {
 // use a consistent key for cache lookups
 const cacheKey = "crypto_key_version"
 
-func (g *gcpClient) kvCacheLoaderFunction(key string) (data interface{}, ttl time.Duration, err error) {
-	// if we're given an explicit version, cache this value forever
-	if g.version != "" {
-		ttl = time.Second * 0
-	} else {
-		ttl = time.Second * 300
-	}
-	data, err = g.keyVersionName(context.Background())
-
-	return
-}
-
 // keyVersionName returns the first key version found for a key in KMS
 func (g *gcpClient) keyVersionName(ctx context.Context) (*cryptoKeyVersion, error) {
 	parent := fmt.Sprintf("projects/%s/locations/%s/keyRings/%s/cryptoKeys/%s", g.projectID, g.locationID, g.keyRing, g.keyName)
@@ -274,17 +281,13 @@ func (g *gcpClient) getHashFunc() (crypt
 // call to GCP if the existing entry in the cache has expired.
 func (g *gcpClient) getCKV() (*cryptoKeyVersion, error) {
 	// we get once and use consistently to ensure the cache value doesn't change underneath us
-	kmsVersionInt, err := g.kvCache.Get(cacheKey)
-	if err != nil {
-		return nil, err
-	}
 
-	kv, ok := kmsVersionInt.(*cryptoKeyVersion)
-	if !ok {
-		return nil, fmt.Errorf("could not parse kms version cache value as CryptoKeyVersion")
+	item := g.kvCache.Get(cacheKey)
+	if item != nil {
+		v := item.Value()
+		return &v, nil
 	}
-
-	return kv, nil
+	return nil, fmt.Errorf("could not retrieve CryptoKeyVersion from gcp")
 }
 
 func (g *gcpClient) sign(ctx context.Context, digest []byte, alg crypto.Hash, crc uint32) ([]byte, error) {
@@ -353,7 +356,7 @@ func (g *gcpClient) verify(sig, message
 	if err := crv.Verifier.VerifySignature(sig, message, opts...); err != nil {
 		// key could have been rotated, clear cache and try again if we're not pinned to a version
 		if g.version == "" {
-			_ = g.kvCache.Remove(cacheKey)
+			g.kvCache.Delete(cacheKey)
 			crv, err = g.getCKV()
 			if err != nil {
 				return fmt.Errorf("transient error getting info from KMS: %w", err)
Index: golang-github-sigstore-sigstore/pkg/signature/kms/hashivault/client.go
===================================================================
--- golang-github-sigstore-sigstore.orig/pkg/signature/kms/hashivault/client.go
+++ golang-github-sigstore-sigstore/pkg/signature/kms/hashivault/client.go
@@ -30,7 +30,7 @@ import (
 	"time"
 
 	vault "github.com/hashicorp/vault/api"
-	"github.com/jellydator/ttlcache/v2"
+	"github.com/jellydator/ttlcache/v3"
 	"github.com/mitchellh/go-homedir"
 	"github.com/sigstore/sigstore/pkg/cryptoutils"
 	"github.com/sigstore/sigstore/pkg/signature"
@@ -47,7 +47,7 @@ type hashivaultClient struct {
 	client                  *vault.Client
 	keyPath                 string
 	transitSecretEnginePath string
-	keyCache                *ttlcache.Cache
+	keyCache                *ttlcache.Cache[string, crypto.PublicKey]
 	keyVersion              uint64
 }
 
@@ -140,11 +140,11 @@ func newHashivaultClient(address, token,
 		client:                  client,
 		keyPath:                 keyPath,
 		transitSecretEnginePath: transitSecretEnginePath,
-		keyCache:                ttlcache.NewCache(),
-		keyVersion:              keyVersion,
+		keyCache: ttlcache.New[string, crypto.PublicKey](
+			ttlcache.WithDisableTouchOnHit[string, crypto.PublicKey](),
+		),
+		keyVersion: keyVersion,
 	}
-	hvClient.keyCache.SetLoaderFunction(hvClient.keyCacheLoaderFunction)
-	hvClient.keyCache.SkipTTLExtensionOnHit(true)
 
 	return hvClient, nil
 }
@@ -179,18 +179,6 @@ func oidcLogin(_ context.Context, addres
 	return resp.TokenID()
 }
 
-func (h *hashivaultClient) keyCacheLoaderFunction(key string) (data interface{}, ttl time.Duration, err error) {
-	ttl = time.Second * 300
-	var pubKey crypto.PublicKey
-	pubKey, err = h.fetchPublicKey(context.Background())
-	if err != nil {
-		data = nil
-		return
-	}
-	data = pubKey
-	return data, ttl, err
-}
-
 func (h *hashivaultClient) fetchPublicKey(_ context.Context) (crypto.PublicKey, error) {
 	client := h.client.Logical()
 
@@ -245,7 +233,21 @@ func (h *hashivaultClient) fetchPublicKe
 }
 
 func (h *hashivaultClient) public() (crypto.PublicKey, error) {
-	return h.keyCache.Get(cacheKey)
+	var lerr error
+	loader := ttlcache.LoaderFunc[string, crypto.PublicKey](
+		func(c *ttlcache.Cache[string, crypto.PublicKey], key string) *ttlcache.Item[string, crypto.PublicKey] {
+			var pubkey crypto.PublicKey
+			pubkey, lerr = h.fetchPublicKey(context.Background())
+			if lerr == nil {
+				item := c.Set(key, pubkey, 300*time.Second)
+				return item
+			}
+			return nil
+		},
+	)
+
+	item := h.keyCache.Get(cacheKey, ttlcache.WithLoader[string, crypto.PublicKey](loader))
+	return item.Value(), lerr
 }
 
 func (h hashivaultClient) sign(digest []byte, alg crypto.Hash, opts ...signature.SignOption) ([]byte, error) {
