Repository: sigstore/fulcio
Pull request #1976 (2025-03-18 18:04:27)

Bump golang-lru to latest version, bump Go toolchain
Now with generics!

Also fix lint errors.

<!--
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 sufficient 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

-->


codecov[bot]: ## [Codecov](https://app.codecov.io/gh/sigstore/fulcio/pull/1976?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=sigstore) Report
All modified and coverable lines are covered by tests :white_check_mark:
> Project coverage is 43.55%. Comparing base [(`cf238ac`)](https://app.codecov.io/gh/sigstore/fulcio/commit/cf238accd68ef13e1e3425a5d87db2f352de173c?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=sigstore) to head [(`d21376e`)](https://app.codecov.io/gh/sigstore/fulcio/commit/d21376e312e9c8f05e48472030228d225255cbdc?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=sigstore).
> Report is 319 commits behind head on main.

<details><summary>Additional details and impacted files</summary>


```diff
@@             Coverage Diff             @@
##             main    #1976       +/-   ##
===========================================
- Coverage   57.93%   43.55%   -14.39%     
===========================================
  Files          50       73       +23     
  Lines        3119     5722     +2603     
===========================================
+ Hits         1807     2492      +685     
- Misses       1154     2999     +1845     
- Partials      158      231       +73     
```

</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/sigstore/fulcio/pull/1976?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=sigstore).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=sigstore).

<details><summary>🚀 New features to boost your workflow: </summary>

- ❄ [Test Analytics](https://docs.codecov.com/docs/test-analytics): Detect flaky tests, report on failures, and find test suite problems.
</details>
haydentherapper: @bobcallaway fixed, it was a mismatch between my local Go toolchain and CI

Patch:
diff --git a/go.mod b/go.mod
index 015b345..47498bb 100644
--- a/go.mod
+++ b/go.mod
@@ -2,7 +2,7 @@ module github.com/sigstore/fulcio
 
 go 1.23.3
 
-toolchain go1.23.4
+toolchain go1.24.1
 
 require (
 	chainguard.dev/go-grpc-kit v0.17.7
@@ -19,7 +19,7 @@ require (
 	github.com/grpc-ecosystem/go-grpc-middleware v1.4.0
 	github.com/grpc-ecosystem/go-grpc-prometheus v1.2.1-0.20210315223345-82c243799c99
 	github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.0
-	github.com/hashicorp/golang-lru v1.0.2
+	github.com/hashicorp/golang-lru/v2 v2.0.7
 	github.com/magiconair/properties v1.8.9
 	github.com/prometheus/client_golang v1.20.5
 	github.com/prometheus/client_model v0.6.1
diff --git a/go.sum b/go.sum
index 3a41a74..007c97d 100644
--- a/go.sum
+++ b/go.sum
@@ -196,8 +196,8 @@ github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9
 github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4=
 github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc=
 github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A=
-github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c=
-github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
+github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
+github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
 github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
 github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
 github.com/hashicorp/vault/api v1.15.0 h1:O24FYQCWwhwKnF7CuSqP30S51rTV7vz1iACXE/pj5DA=
diff --git a/hack/tools/go.mod b/hack/tools/go.mod
index 19573a1..1308b87 100644
--- a/hack/tools/go.mod
+++ b/hack/tools/go.mod
@@ -1,7 +1,7 @@
 module github.com/sigstore/fulcio/hack/tools
 
 go 1.22.0
-toolchain go1.23.7
+toolchain go1.24.1
 
 require (
 	github.com/googleapis/api-linter v1.68.0
diff --git a/pkg/config/config.go b/pkg/config/config.go
index 04b9346..3eda753 100644
--- a/pkg/config/config.go
+++ b/pkg/config/config.go
@@ -32,7 +32,7 @@ import (
 	"time"
 
 	"github.com/coreos/go-oidc/v3/oidc"
-	lru "github.com/hashicorp/golang-lru"
+	lru "github.com/hashicorp/golang-lru/v2"
 	"github.com/sigstore/fulcio/pkg/certificate"
 	fulciogrpc "github.com/sigstore/fulcio/pkg/generated/protobuf"
 	"github.com/sigstore/fulcio/pkg/log"
@@ -72,7 +72,7 @@ type FulcioConfig struct {
 	// verifiers is a fixed mapping from our OIDCIssuers to their OIDC verifiers.
 	verifiers map[string][]*verifierWithConfig
 	// lru is an LRU cache of recently used verifiers for our meta issuers.
-	lru *lru.TwoQueueCache
+	lru *lru.TwoQueueCache[string, []*verifierWithConfig]
 }
 
 type IssuerMetadata struct {
@@ -193,9 +193,8 @@ func (fc *FulcioConfig) GetVerifier(issuerURL string, opts ...InsecureOIDCConfig
 	}
 
 	// Look in the LRU cache for a verifier
-	untyped, ok := fc.lru.Get(issuerURL)
+	v, ok = fc.lru.Get(issuerURL)
 	if ok {
-		v := untyped.([]*verifierWithConfig)
 		for _, c := range v {
 			if reflect.DeepEqual(c.Config, cfg) {
 				return c.IDTokenVerifier, true
@@ -238,7 +237,7 @@ func (fc *FulcioConfig) GetVerifier(issuerURL string, opts ...InsecureOIDCConfig
 	}
 
 	vwf := &verifierWithConfig{provider.Verifier(cfg), cfg}
-	if untyped == nil {
+	if v == nil {
 		v = []*verifierWithConfig{vwf}
 	} else {
 		v = append(v, vwf)
@@ -327,7 +326,7 @@ func (fc *FulcioConfig) prepare() error {
 		}
 	}
 
-	cache, err := lru.New2Q(100 /* size */)
+	cache, err := lru.New2Q[string, []*verifierWithConfig](100 /* size */)
 	if err != nil {
 		return fmt.Errorf("lru: %w", err)
 	}
diff --git a/pkg/server/error.go b/pkg/server/error.go
index 14b2821..36f6709 100644
--- a/pkg/server/error.go
+++ b/pkg/server/error.go
@@ -31,9 +31,9 @@ const (
 	failedToMarshalSCT     = "Error marshaling signed certificate timestamp"
 	failedToMarshalCert    = "Error marshaling code signing certificate"
 	insecurePublicKey      = "The public key supplied in the request is insecure"
-	//nolint
-	invalidCredentials = "There was an error processing the credentials for this request"
-	// nolint
+	// nolint:gosec // false positive G101
+	invalidCredentials = "There was an error processing the credentials for this request" //lint:ignore U1000 Used in past
+	// nolint:gosec // false positive G101
 	invalidIdentityToken                    = "There was an error processing the identity token"
 	genericCAError                          = "error communicating with CA backend"
 	retrieveTrustBundleCAError              = "error retrieving trust bundle from CA backend"
diff --git a/pkg/server/grpc_server.go b/pkg/server/grpc_server.go
index 3976d0e..fe304f5 100644
--- a/pkg/server/grpc_server.go
+++ b/pkg/server/grpc_server.go
@@ -163,7 +163,7 @@ func (g *grpcaCAServer) CreateSigningCertificate(ctx context.Context, request *f
 		return nil, handleFulcioGRPCError(ctx, codes.InvalidArgument, err, err.Error())
 	}
 	if !isPermitted {
-		err = fmt.Errorf("Signing algorithm not permitted: %T, %s", publicKey, hashFunc)
+		err = fmt.Errorf("signing algorithm not permitted: %T, %s", publicKey, hashFunc)
 		return nil, handleFulcioGRPCError(ctx, codes.InvalidArgument, err, err.Error())
 	}
 
@@ -179,7 +179,7 @@ func (g *grpcaCAServer) CreateSigningCertificate(ctx context.Context, request *f
 			if _, ok := err.(certauth.ValidationError); ok {
 				return nil, handleFulcioGRPCError(ctx, codes.InvalidArgument, err, err.Error())
 			}
-			err = fmt.Errorf("Error creating certificate: %w", err)
+			err = fmt.Errorf("error creating certificate: %w", err)
 			// otherwise return a 500 error to reflect that it is a transient server issue that the client can't resolve
 			return nil, handleFulcioGRPCError(ctx, codes.Internal, err, genericCAError)
 		}
@@ -230,7 +230,7 @@ func (g *grpcaCAServer) CreateSigningCertificate(ctx context.Context, request *f
 			if _, ok := err.(certauth.ValidationError); ok {
 				return nil, handleFulcioGRPCError(ctx, codes.InvalidArgument, err, err.Error())
 			}
-			err = fmt.Errorf("Error creating a pre-certificate and chain: %w", err)
+			err = fmt.Errorf("error creating a pre-certificate and chain: %w", err)
 			// otherwise return a 500 error to reflect that it is a transient server issue that the client can't resolve
 			return nil, handleFulcioGRPCError(ctx, codes.Internal, err, genericCAError)
 		}
@@ -241,7 +241,7 @@ func (g *grpcaCAServer) CreateSigningCertificate(ctx context.Context, request *f
 		}
 		csc, err = sctCa.IssueFinalCertificate(ctx, precert, sct)
 		if err != nil {
-			err = fmt.Errorf("Error issuing final certificate using the pre-certificate with CA backend: %w", err)
+			err = fmt.Errorf("error issuing final certificate using the pre-certificate with CA backend: %w", err)
 			return nil, handleFulcioGRPCError(ctx, codes.Internal, err, genericCAError)
 		}
 


Test patch:
diff --git a/pkg/config/config_test.go b/pkg/config/config_test.go
index 7728216..067a4cf 100644
--- a/pkg/config/config_test.go
+++ b/pkg/config/config_test.go
@@ -36,7 +36,7 @@ import (
 	"time"
 
 	"github.com/coreos/go-oidc/v3/oidc"
-	lru "github.com/hashicorp/golang-lru"
+	lru "github.com/hashicorp/golang-lru/v2"
 	"github.com/sigstore/fulcio/pkg/generated/protobuf"
 )
 
@@ -649,7 +649,7 @@ func TestToIssuers(t *testing.T) {
 }
 
 func TestVerifierCache(t *testing.T) {
-	cache, err := lru.New2Q(100 /* size */)
+	cache, err := lru.New2Q[string, []*verifierWithConfig](100 /* size */)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -815,7 +815,7 @@ func TestVerifierCacheWithCustomCA(t *testing.T) {
 	server.StartTLS()
 	defer server.Close()
 
-	cache, err := lru.New2Q(100)
+	cache, err := lru.New2Q[string, []*verifierWithConfig](100)
 	if err != nil {
 		t.Fatal(err)
 	}
diff --git a/pkg/server/grpc_server_test.go b/pkg/server/grpc_server_test.go
index 8159486..7e9abe1 100644
--- a/pkg/server/grpc_server_test.go
+++ b/pkg/server/grpc_server_test.go
@@ -2555,7 +2555,7 @@ func TestAPIWithInvalidCSRPublicKey(t *testing.T) {
 			CertificateSigningRequest: pemCSR,
 		},
 	})
-	if err == nil || !strings.Contains(err.Error(), "Signing algorithm not permitted") {
+	if err == nil || !strings.Contains(err.Error(), "signing algorithm not permitted") {
 		t.Fatalf("expected signing algorithm not permitted, got %v", err)
 	}
 	if status.Code(err) != codes.InvalidArgument {
diff --git a/test/prometheus/main.go b/test/prometheus/main.go
index 22864cc..edaa47e 100644
--- a/test/prometheus/main.go
+++ b/test/prometheus/main.go
@@ -73,7 +73,7 @@ func main() {
 // Make sure latency is a Histogram, and it has a POST with a 201.
 func checkLatency(latency *dto.MetricFamily) error {
 	if *latency.Type != *dto.MetricType_HISTOGRAM.Enum() {
-		return fmt.Errorf("Wrong type, wanted %+v, got: %+v", dto.MetricType_HISTOGRAM.Enum(), latency.Type)
+		return fmt.Errorf("wrong type, wanted %+v, got: %+v", dto.MetricType_HISTOGRAM.Enum(), latency.Type)
 	}
 
 	for _, metric := range latency.Metric {
@@ -89,24 +89,24 @@ func checkLatency(latency *dto.MetricFamily) error {
 		}
 		if code == "201" && method == "post" {
 			if *metric.Histogram.SampleCount != 1 {
-				return fmt.Errorf("Unexpected samplecount, wanted 1, got %d", *metric.Histogram.SampleCount)
+				return fmt.Errorf("unexpected samplecount, wanted 1, got %d", *metric.Histogram.SampleCount)
 			}
 			return nil
 		}
 	}
 
-	return fmt.Errorf("Got multiple entries, or none for metric, wanted one, got: %+v", latency.Metric)
+	return fmt.Errorf("got multiple entries, or none for metric, wanted one, got: %+v", latency.Metric)
 }
 
 func checkCertCount(certCount *dto.MetricFamily) error {
 	if *certCount.Type != *dto.MetricType_COUNTER.Enum() {
-		return fmt.Errorf("Wrong type, wanted %+v, got: %+v", dto.MetricType_COUNTER.Enum(), certCount.Type)
+		return fmt.Errorf("wrong type, wanted %+v, got: %+v", dto.MetricType_COUNTER.Enum(), certCount.Type)
 	}
 	if len(certCount.Metric) != 1 {
-		return fmt.Errorf("Got multiple entries, or none for metric, wanted one, got: %+v", certCount.Metric)
+		return fmt.Errorf("got multiple entries, or none for metric, wanted one, got: %+v", certCount.Metric)
 	}
 	if *certCount.Metric[0].Counter.Value < 1 {
-		return fmt.Errorf("Got incorrect cert count, wanted one, got: %f", *certCount.Metric[0].Counter.Value)
+		return fmt.Errorf("got incorrect cert count, wanted one, got: %f", *certCount.Metric[0].Counter.Value)
 	}
 	return nil
 }