From 78dc391c1785729af17d7e74d2536709711cc24c Mon Sep 17 00:00:00 2001 From: Stefan Majer Date: Mon, 11 May 2026 06:57:16 +0200 Subject: [PATCH 1/9] token-store --- go.mod | 1 + go.sum | 13 ++++++++ pkg/service/services.go | 2 +- pkg/test/repository.go | 2 +- pkg/token/token-store.go | 57 +++++++++++++++++------------------ pkg/token/token-store_test.go | 32 ++++++++++++++------ 6 files changed, 65 insertions(+), 42 deletions(-) diff --git a/go.mod b/go.mod index 37dcb340..c9710716 100644 --- a/go.mod +++ b/go.mod @@ -41,6 +41,7 @@ require ( github.com/testcontainers/testcontainers-go/modules/valkey v0.42.0 github.com/urfave/cli/v2 v2.27.7 github.com/valkey-io/valkey-go v1.0.74 + github.com/valkey-io/valkey-go/valkeycompat v1.0.74 go.opentelemetry.io/otel/exporters/prometheus v0.65.0 go.opentelemetry.io/otel/sdk/metric v1.43.0 go4.org/netipx v0.0.0-20231129151722-fdeea329fbba diff --git a/go.sum b/go.sum index 9ac00526..549adc9f 100644 --- a/go.sum +++ b/go.sum @@ -233,6 +233,8 @@ github.com/go-openapi/validate v0.25.2/go.mod h1:Pgl1LpPPGFnZ+ys4/hTlDiRYQdI1ocK github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= +github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/go-viper/mapstructure/v2 v2.5.0 h1:vM5IJoUAy3d7zRSVtIwQgBj7BiWtMPfmPEgAXnvj1Ro= github.com/go-viper/mapstructure/v2 v2.5.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/go4org/plan9netshell v0.0.0-20250324183649-788daa080737 h1:cf60tHxREO3g1nroKr2osU3JWZsJzkfi7rEg+oAB0Lo= @@ -267,6 +269,8 @@ github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/nftables v0.2.1-0.20240414091927-5e242ec57806 h1:wG8RYIyctLhdFk6Vl1yPGtSRtwGpVkWyZww1OCil2MI= github.com/google/nftables v0.2.1-0.20240414091927-5e242ec57806/go.mod h1:Beg6V6zZ3oEn0JuiUQ4wqwuyqqzasOltcoXPtgLbFp4= +github.com/google/pprof v0.0.0-20260202012954-cb029daf43ef h1:xpF9fUHpoIrrjX24DURVKiwHcFpw19ndIs+FwTSMbno= +github.com/google/pprof v0.0.0-20260202012954-cb029daf43ef/go.mod h1:MxpfABSjhmINe3F1It9d+8exIHFvUqtLIRCdOGNXqiI= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -495,7 +499,10 @@ github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLA github.com/oklog/ulid/v2 v2.1.1 h1:suPZ4ARWLOJLegGFiZZ1dFAkqzhMjL3J1TzI+5wHz8s= github.com/oklog/ulid/v2 v2.1.1/go.mod h1:rcEKHmBBKfef9DhnvX7y1HZBYxjXb0cP5ExxNsTT1QQ= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.0 h1:Iw5WCbBcaAAd0fpRb1c9r5YCylv4XDoCSigm1zLevwU= github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg= +github.com/onsi/ginkgo/v2 v2.27.3 h1:ICsZJ8JoYafeXFFlFAG75a7CxMsJHwgKwtO+82SE9L8= +github.com/onsi/ginkgo/v2 v2.27.3/go.mod h1:ArE1D/XhNXBXCBkKOLkbsb2c81dQHCRcF5zwn/ykDRo= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= github.com/onsi/gomega v1.38.3 h1:eTX+W6dobAYfFeGC2PV6RwXRu/MyT+cQguijutvkpSM= @@ -623,6 +630,10 @@ github.com/urfave/cli/v2 v2.27.7 h1:bH59vdhbjLv3LAvIu6gd0usJHgoTTPhCFib8qqOwXYU= github.com/urfave/cli/v2 v2.27.7/go.mod h1:CyNAG/xg+iAOg0N4MPGZqVmv2rCoP267496AOXUZjA4= github.com/valkey-io/valkey-go v1.0.74 h1:NqtBHzjybz+is+c71hsyZP7hoE5lwCHQX026me0Vb08= github.com/valkey-io/valkey-go v1.0.74/go.mod h1:VGhZ6fs68Qrn2+OhH+6waZH27bjpgQOiLyUQyXuYK5k= +github.com/valkey-io/valkey-go/mock v1.0.74 h1:qN/Ui8EI2q0DeTKMfdk8be92ns6ozBihu532r8PUP2Q= +github.com/valkey-io/valkey-go/mock v1.0.74/go.mod h1:068Cb5LsnrPzxYOT31pPUbQ5TVy1CGBQeMTLdJculEo= +github.com/valkey-io/valkey-go/valkeycompat v1.0.74 h1:hw/Tx5G0nSrftsl2SBb24aMfJI0CGIcYR7my1XTbfog= +github.com/valkey-io/valkey-go/valkeycompat v1.0.74/go.mod h1:cEg0T8zAQRqGJgWgrfImWdDPzzyifW8u9uW7Nm4DMx0= github.com/valyala/fastjson v1.6.10 h1:/yjJg8jaVQdYR3arGxPE2X5z89xrlhS0eGXdv+ADTh4= github.com/valyala/fastjson v1.6.10/go.mod h1:e6FubmQouUNP73jtMLmcbxS6ydWIpOfhz34TSfO3JaE= github.com/vishvananda/netns v0.0.5 h1:DfiHV+j8bA32MFM7bfEunvT8IAqQ/NzSJHtcmW5zdEY= @@ -681,6 +692,8 @@ go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y= +go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= diff --git a/pkg/service/services.go b/pkg/service/services.go index d4e3182f..6b1ae60c 100644 --- a/pkg/service/services.go +++ b/pkg/service/services.go @@ -85,7 +85,7 @@ type RedisConfig struct { func New(ctx context.Context, log *slog.Logger, c Config) (*http.ServeMux, error) { var ( - tokenStore = tokencommon.NewRedisStore(c.RedisConfig.TokenClient) + tokenStore = tokencommon.NewRedisStore(c.RedisConfig.QueueClient) // FIXME TokenClient must be valkey-go certStore = certs.NewRedisStore(&certs.Config{ RedisClient: c.RedisConfig.TokenClient, }) diff --git a/pkg/test/repository.go b/pkg/test/repository.go index 29ae38f8..a4090b66 100644 --- a/pkg/test/repository.go +++ b/pkg/test/repository.go @@ -184,7 +184,7 @@ func StartRepositoryWithCleanup(t testing.TB, log *slog.Logger, testOpts ...test projectInviteStore := invite.NewProjectRedisStore(rc) tenantInviteStore := invite.NewTenantRedisStore(rc) - tokenStore := tokencommon.NewRedisStore(rc) + tokenStore := tokencommon.NewRedisStore(vc) certStore := certs.NewRedisStore(&certs.Config{RedisClient: rc}) auditingBackend, err := auditingmemory.NewMemory(auditing.Config{ diff --git a/pkg/token/token-store.go b/pkg/token/token-store.go index d6be5ac3..703e462b 100644 --- a/pkg/token/token-store.go +++ b/pkg/token/token-store.go @@ -6,10 +6,10 @@ import ( "errors" "fmt" "log/slog" - "time" apiv2 "github.com/metal-stack/api/go/metalstack/api/v2" - "github.com/redis/go-redis/v9" + "github.com/valkey-io/valkey-go" + "github.com/valkey-io/valkey-go/valkeycompat" ) const ( @@ -18,7 +18,7 @@ const ( ) var ( - ErrTokenNotFound = redis.Nil + ErrTokenNotFound = valkey.Nil ) type TokenStore interface { @@ -31,7 +31,7 @@ type TokenStore interface { } type redisStore struct { - client *redis.Client + client valkey.Client } func key(userid, tokenid string) string { @@ -42,7 +42,7 @@ func match(userid string) string { return prefix + userid + separator + "*" } -func NewRedisStore(client *redis.Client) TokenStore { +func NewRedisStore(client valkey.Client) TokenStore { return &redisStore{ client: client, } @@ -54,7 +54,7 @@ func (r *redisStore) Set(ctx context.Context, token *apiv2.Token) error { return fmt.Errorf("unable to encode token: %w", err) } - _, err = r.client.Set(ctx, key(token.User, token.Uuid), string(encoded), time.Until(token.Expires.AsTime())).Result() + err = r.client.Do(ctx, r.client.B().Set().Key(key(token.User, token.Uuid)).Value(string(encoded)).ExatTimestamp(token.Expires.AsTime().UnixMilli()).Build()).Error() if err != nil { return err } @@ -63,7 +63,7 @@ func (r *redisStore) Set(ctx context.Context, token *apiv2.Token) error { } func (r *redisStore) Get(ctx context.Context, userid, tokenid string) (*apiv2.Token, error) { - encoded, err := r.client.Get(ctx, key(userid, tokenid)).Result() + encoded, err := r.client.Do(ctx, r.client.B().Get().Key(key(userid, tokenid)).Build()).ToString() if err != nil { return nil, err } @@ -79,61 +79,58 @@ func (r *redisStore) Get(ctx context.Context, userid, tokenid string) (*apiv2.To func (r *redisStore) List(ctx context.Context, userid string) ([]*apiv2.Token, error) { var ( - res []*apiv2.Token - iter = r.client.Scan(ctx, 0, match(userid), 0).Iterator() + res []*apiv2.Token ) + entry, err := r.client.Do(ctx, r.client.B().Scan().Cursor(0).Match(match(userid)).Build()).AsScanEntry() + if err != nil { + return nil, fmt.Errorf("error scanning user token with:%q error:%w", match(userid), err) + } - for iter.Next(ctx) { - encoded, err := r.client.Get(ctx, iter.Val()).Result() + for _, element := range entry.Elements { + encoded, err := r.client.Do(ctx, r.client.B().Get().Key(element).Build()).AsBytes() if err != nil { - return nil, err + return nil, fmt.Errorf("unable to get content by key:%q error:%w", encoded, err) } var t token err = json.Unmarshal([]byte(encoded), &t) if err != nil { - return nil, err + return nil, fmt.Errorf("unable to decode scan result:%q error:%w", encoded, err) } - res = append(res, toExternal(&t)) } - if err := iter.Err(); err != nil { - return nil, err - } - return res, nil } func (r *redisStore) AdminList(ctx context.Context) ([]*apiv2.Token, error) { var ( - res []*apiv2.Token - iter = r.client.Scan(ctx, 0, prefix+"*", 0).Iterator() + compat = valkeycompat.NewAdapter(r.client) + res []*apiv2.Token ) + elements, _, err := compat.Scan(ctx, 0, prefix+"*", 0).Result() + if err != nil { + return nil, err + } - for iter.Next(ctx) { - encoded, err := r.client.Get(ctx, iter.Val()).Result() + for _, element := range elements { + encoded, err := r.client.Do(ctx, r.client.B().Get().Key(element).Build()).AsBytes() if err != nil { - return nil, err + return nil, fmt.Errorf("unable to get content by key:%q error:%w", encoded, err) } var t token err = json.Unmarshal([]byte(encoded), &t) if err != nil { - return nil, err + return nil, fmt.Errorf("unable to decode scan result:%q error:%w", encoded, err) } - res = append(res, toExternal(&t)) } - if err := iter.Err(); err != nil { - return nil, err - } return res, nil } func (r *redisStore) Revoke(ctx context.Context, userid, tokenid string) error { - _, err := r.client.Del(ctx, key(userid, tokenid)).Result() - return err + return r.client.Do(ctx, r.client.B().Del().Key(key(userid, tokenid)).Build()).Error() } func (r *redisStore) Migrate(ctx context.Context, log *slog.Logger) error { diff --git a/pkg/token/token-store_test.go b/pkg/token/token-store_test.go index 31339e74..3831bdcc 100644 --- a/pkg/token/token-store_test.go +++ b/pkg/token/token-store_test.go @@ -7,9 +7,9 @@ import ( "github.com/alicebob/miniredis/v2" apiv2 "github.com/metal-stack/api/go/metalstack/api/v2" - "github.com/redis/go-redis/v9" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/valkey-io/valkey-go" "google.golang.org/protobuf/types/known/timestamppb" ) @@ -17,15 +17,21 @@ func TestRedisStore(t *testing.T) { t.Parallel() ctx := t.Context() s := miniredis.RunT(t) - c := redis.NewClient(&redis.Options{Addr: s.Addr()}) - + c, err := valkey.NewClient(valkey.ClientOption{ + InitAddress: []string{s.Addr()}, + // This is required because otherwise we get: + // unknown subcommand 'TRACKING'. Try CLIENT HELP.: [CLIENT TRACKING ON OPTIN] + // ClientOption.DisableCache must be true for valkey not supporting client-side caching or not supporting RESP3 + DisableCache: true, + }) + require.NoError(t, err) store := NewRedisStore(c) - johnDoeToken := &apiv2.Token{User: "john@doe.com", Uuid: "abc"} - willSmithToken := &apiv2.Token{User: "will@smith.com", Uuid: "def"} - frankZappaToken := &apiv2.Token{User: "frank@zappa.com", Uuid: "cde"} + johnDoeToken := &apiv2.Token{User: "john@doe.com", Uuid: "abc", Expires: timestamppb.New(time.Now().Add(time.Hour))} + willSmithToken := &apiv2.Token{User: "will@smith.com", Uuid: "def", Expires: timestamppb.New(time.Now().Add(time.Hour))} + frankZappaToken := &apiv2.Token{User: "frank@zappa.com", Uuid: "cde", Expires: timestamppb.New(time.Now().Add(time.Hour))} - err := store.Set(ctx, johnDoeToken) + err = store.Set(ctx, johnDoeToken) require.NoError(t, err) err = store.Set(ctx, willSmithToken) @@ -59,8 +65,14 @@ func TestRedisStoreSetAndGet(t *testing.T) { t.Parallel() ctx := t.Context() s := miniredis.RunT(t) - c := redis.NewClient(&redis.Options{Addr: s.Addr()}) - + c, err := valkey.NewClient(valkey.ClientOption{ + InitAddress: []string{s.Addr()}, + // This is required because otherwise we get: + // unknown subcommand 'TRACKING'. Try CLIENT HELP.: [CLIENT TRACKING ON OPTIN] + // ClientOption.DisableCache must be true for valkey not supporting client-side caching or not supporting RESP3 + DisableCache: true, + }) + require.NoError(t, err) store := NewRedisStore(c) now := time.Now() @@ -91,7 +103,7 @@ func TestRedisStoreSetAndGet(t *testing.T) { MachineRoles: map[string]apiv2.MachineRole{}, } - err := store.Set(ctx, inTok) + err = store.Set(ctx, inTok) require.NoError(t, err) require.NoError(t, store.Migrate(ctx, slog.Default())) From 161cbaf02ca175fd876a2fe6701a8d357a614201 Mon Sep 17 00:00:00 2001 From: Stefan Majer Date: Mon, 11 May 2026 08:25:05 +0200 Subject: [PATCH 2/9] only asynq left --- cmd/server/serve-cmd.go | 6 +- cmd/server/token-cmd.go | 6 +- go.mod | 1 - go.sum | 13 ---- pkg/auth/authenticator-interceptor_test.go | 25 +++++-- pkg/auth/jwt-token-cert-rotation_test.go | 13 +++- pkg/certs/certs-store.go | 43 ++++++------ pkg/certs/certs-store_test.go | 27 +++++--- pkg/e2e/apiserver.go | 6 +- pkg/invite/invite-store.go | 74 +++++++++++---------- pkg/invite/invite-store_test.go | 35 +++++++--- pkg/rate-limiter/rate-limit-interceptor.go | 9 ++- pkg/rate-limiter/rate-limiter.go | 33 ++++----- pkg/rate-limiter/rate-limiter_test.go | 13 +++- pkg/service/api/token/token-service_test.go | 61 ++++++++++++++--- pkg/service/services.go | 10 +-- pkg/test/repository.go | 6 +- pkg/token/token-store.go | 10 ++- 18 files changed, 231 insertions(+), 160 deletions(-) diff --git a/cmd/server/serve-cmd.go b/cmd/server/serve-cmd.go index 945c769f..25569f4f 100644 --- a/cmd/server/serve-cmd.go +++ b/cmd/server/serve-cmd.go @@ -266,15 +266,15 @@ const ( func createRedisClients(cli *cli.Context, logger *slog.Logger) (*service.RedisConfig, error) { - token, _, err := createRedisClient(cli, logger, redisDatabaseTokens) + _, token, err := createRedisClient(cli, logger, redisDatabaseTokens) if err != nil { return nil, err } - rate, _, err := createRedisClient(cli, logger, redisDatabaseRateLimiting) + _, rate, err := createRedisClient(cli, logger, redisDatabaseRateLimiting) if err != nil { return nil, err } - invite, _, err := createRedisClient(cli, logger, redisDatabaseInvites) + _, invite, err := createRedisClient(cli, logger, redisDatabaseInvites) if err != nil { return nil, err } diff --git a/cmd/server/token-cmd.go b/cmd/server/token-cmd.go index 45d5abf4..ca63f39b 100644 --- a/cmd/server/token-cmd.go +++ b/cmd/server/token-cmd.go @@ -74,14 +74,14 @@ func newTokenCmd() *cli.Command { return fmt.Errorf("unable to create logger %w", err) } - tokenRedisClient, _, err := createRedisClient(ctx, log, redisDatabaseTokens) + _, tokenValkeyClient, err := createRedisClient(ctx, log, redisDatabaseTokens) if err != nil { return err } - tokenStore := tokencommon.NewRedisStore(tokenRedisClient) + tokenStore := tokencommon.NewRedisStore(tokenValkeyClient) certStore := certs.NewRedisStore(&certs.Config{ - RedisClient: tokenRedisClient, + ValkeyClient: tokenValkeyClient, }) tokenService := token.New(token.Config{ diff --git a/go.mod b/go.mod index c9710716..37dcb340 100644 --- a/go.mod +++ b/go.mod @@ -41,7 +41,6 @@ require ( github.com/testcontainers/testcontainers-go/modules/valkey v0.42.0 github.com/urfave/cli/v2 v2.27.7 github.com/valkey-io/valkey-go v1.0.74 - github.com/valkey-io/valkey-go/valkeycompat v1.0.74 go.opentelemetry.io/otel/exporters/prometheus v0.65.0 go.opentelemetry.io/otel/sdk/metric v1.43.0 go4.org/netipx v0.0.0-20231129151722-fdeea329fbba diff --git a/go.sum b/go.sum index 549adc9f..9ac00526 100644 --- a/go.sum +++ b/go.sum @@ -233,8 +233,6 @@ github.com/go-openapi/validate v0.25.2/go.mod h1:Pgl1LpPPGFnZ+ys4/hTlDiRYQdI1ocK github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= -github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/go-viper/mapstructure/v2 v2.5.0 h1:vM5IJoUAy3d7zRSVtIwQgBj7BiWtMPfmPEgAXnvj1Ro= github.com/go-viper/mapstructure/v2 v2.5.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/go4org/plan9netshell v0.0.0-20250324183649-788daa080737 h1:cf60tHxREO3g1nroKr2osU3JWZsJzkfi7rEg+oAB0Lo= @@ -269,8 +267,6 @@ github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/nftables v0.2.1-0.20240414091927-5e242ec57806 h1:wG8RYIyctLhdFk6Vl1yPGtSRtwGpVkWyZww1OCil2MI= github.com/google/nftables v0.2.1-0.20240414091927-5e242ec57806/go.mod h1:Beg6V6zZ3oEn0JuiUQ4wqwuyqqzasOltcoXPtgLbFp4= -github.com/google/pprof v0.0.0-20260202012954-cb029daf43ef h1:xpF9fUHpoIrrjX24DURVKiwHcFpw19ndIs+FwTSMbno= -github.com/google/pprof v0.0.0-20260202012954-cb029daf43ef/go.mod h1:MxpfABSjhmINe3F1It9d+8exIHFvUqtLIRCdOGNXqiI= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -499,10 +495,7 @@ github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLA github.com/oklog/ulid/v2 v2.1.1 h1:suPZ4ARWLOJLegGFiZZ1dFAkqzhMjL3J1TzI+5wHz8s= github.com/oklog/ulid/v2 v2.1.1/go.mod h1:rcEKHmBBKfef9DhnvX7y1HZBYxjXb0cP5ExxNsTT1QQ= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.12.0 h1:Iw5WCbBcaAAd0fpRb1c9r5YCylv4XDoCSigm1zLevwU= github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg= -github.com/onsi/ginkgo/v2 v2.27.3 h1:ICsZJ8JoYafeXFFlFAG75a7CxMsJHwgKwtO+82SE9L8= -github.com/onsi/ginkgo/v2 v2.27.3/go.mod h1:ArE1D/XhNXBXCBkKOLkbsb2c81dQHCRcF5zwn/ykDRo= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= github.com/onsi/gomega v1.38.3 h1:eTX+W6dobAYfFeGC2PV6RwXRu/MyT+cQguijutvkpSM= @@ -630,10 +623,6 @@ github.com/urfave/cli/v2 v2.27.7 h1:bH59vdhbjLv3LAvIu6gd0usJHgoTTPhCFib8qqOwXYU= github.com/urfave/cli/v2 v2.27.7/go.mod h1:CyNAG/xg+iAOg0N4MPGZqVmv2rCoP267496AOXUZjA4= github.com/valkey-io/valkey-go v1.0.74 h1:NqtBHzjybz+is+c71hsyZP7hoE5lwCHQX026me0Vb08= github.com/valkey-io/valkey-go v1.0.74/go.mod h1:VGhZ6fs68Qrn2+OhH+6waZH27bjpgQOiLyUQyXuYK5k= -github.com/valkey-io/valkey-go/mock v1.0.74 h1:qN/Ui8EI2q0DeTKMfdk8be92ns6ozBihu532r8PUP2Q= -github.com/valkey-io/valkey-go/mock v1.0.74/go.mod h1:068Cb5LsnrPzxYOT31pPUbQ5TVy1CGBQeMTLdJculEo= -github.com/valkey-io/valkey-go/valkeycompat v1.0.74 h1:hw/Tx5G0nSrftsl2SBb24aMfJI0CGIcYR7my1XTbfog= -github.com/valkey-io/valkey-go/valkeycompat v1.0.74/go.mod h1:cEg0T8zAQRqGJgWgrfImWdDPzzyifW8u9uW7Nm4DMx0= github.com/valyala/fastjson v1.6.10 h1:/yjJg8jaVQdYR3arGxPE2X5z89xrlhS0eGXdv+ADTh4= github.com/valyala/fastjson v1.6.10/go.mod h1:e6FubmQouUNP73jtMLmcbxS6ydWIpOfhz34TSfO3JaE= github.com/vishvananda/netns v0.0.5 h1:DfiHV+j8bA32MFM7bfEunvT8IAqQ/NzSJHtcmW5zdEY= @@ -692,8 +681,6 @@ go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= -go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y= -go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= diff --git a/pkg/auth/authenticator-interceptor_test.go b/pkg/auth/authenticator-interceptor_test.go index 1caa4669..057b73de 100644 --- a/pkg/auth/authenticator-interceptor_test.go +++ b/pkg/auth/authenticator-interceptor_test.go @@ -19,19 +19,26 @@ import ( "github.com/metal-stack/metal-apiserver/pkg/errorutil" "github.com/metal-stack/metal-apiserver/pkg/repository/api" "github.com/metal-stack/metal-apiserver/pkg/token" - "github.com/redis/go-redis/v9" "github.com/stretchr/testify/require" + "github.com/valkey-io/valkey-go" ) func prepare(t *testing.T) (certs.CertStore, *ecdsa.PrivateKey) { s := miniredis.RunT(t) - c := redis.NewClient(&redis.Options{Addr: s.Addr()}) + c, err := valkey.NewClient(valkey.ClientOption{ + InitAddress: []string{s.Addr()}, + // This is required because otherwise we get: + // unknown subcommand 'TRACKING'. Try CLIENT HELP.: [CLIENT TRACKING ON OPTIN] + // ClientOption.DisableCache must be true for valkey not supporting client-side caching or not supporting RESP3 + DisableCache: true, + }) + require.NoError(t, err) // creating an initial signing certificate store := certs.NewRedisStore(&certs.Config{ - RedisClient: c, + ValkeyClient: c, }) - _, err := store.LatestPrivate(t.Context()) + _, err = store.LatestPrivate(t.Context()) require.NoError(t, err) key, err := store.LatestPrivate(t.Context()) @@ -142,7 +149,15 @@ func Test_authorize_with_permissions(t *testing.T) { defer s.Close() ctx := t.Context() - tokenStore := token.NewRedisStore(redis.NewClient(&redis.Options{Addr: s.Addr()})) + c, err := valkey.NewClient(valkey.ClientOption{ + InitAddress: []string{s.Addr()}, + // This is required because otherwise we get: + // unknown subcommand 'TRACKING'. Try CLIENT HELP.: [CLIENT TRACKING ON OPTIN] + // ClientOption.DisableCache must be true for valkey not supporting client-side caching or not supporting RESP3 + DisableCache: true, + }) + require.NoError(t, err) + tokenStore := token.NewRedisStore(c) exp := time.Hour if tt.expiration != nil { diff --git a/pkg/auth/jwt-token-cert-rotation_test.go b/pkg/auth/jwt-token-cert-rotation_test.go index cb29d3ac..d3095b16 100644 --- a/pkg/auth/jwt-token-cert-rotation_test.go +++ b/pkg/auth/jwt-token-cert-rotation_test.go @@ -13,8 +13,8 @@ import ( "github.com/metal-stack/metal-apiserver/pkg/certs" tokenservice "github.com/metal-stack/metal-apiserver/pkg/service/api/token" "github.com/metal-stack/metal-apiserver/pkg/token" - "github.com/redis/go-redis/v9" "github.com/stretchr/testify/require" + "github.com/valkey-io/valkey-go" ) func Test_jwt_cert_rotation(t *testing.T) { @@ -33,11 +33,18 @@ func Test_jwt_cert_rotation(t *testing.T) { t.Logf("token lifetime: %s, certificate lifetime: %s, issue new signing certificate after: %s", token.DefaultExpiration, 2*token.MaxExpiration, 2*token.MaxExpiration-renewCertBeforeExpiration) s := miniredis.RunT(t) - c := redis.NewClient(&redis.Options{Addr: s.Addr()}) + c, err := valkey.NewClient(valkey.ClientOption{ + InitAddress: []string{s.Addr()}, + // This is required because otherwise we get: + // unknown subcommand 'TRACKING'. Try CLIENT HELP.: [CLIENT TRACKING ON OPTIN] + // ClientOption.DisableCache must be true for valkey not supporting client-side caching or not supporting RESP3 + DisableCache: true, + }) + require.NoError(t, err) log := slog.Default() certStore := certs.NewRedisStore(&certs.Config{ - RedisClient: c, + ValkeyClient: c, RenewCertBeforeExpiration: &renewCertBeforeExpiration, }) tokenStore := token.NewRedisStore(c) diff --git a/pkg/certs/certs-store.go b/pkg/certs/certs-store.go index 678b2011..effcb40d 100644 --- a/pkg/certs/certs-store.go +++ b/pkg/certs/certs-store.go @@ -18,7 +18,7 @@ import ( "github.com/google/uuid" "github.com/lestrrat-go/jwx/v3/jwk" "github.com/metal-stack/metal-apiserver/pkg/token" - "github.com/redis/go-redis/v9" + "github.com/valkey-io/valkey-go" ) const ( @@ -26,7 +26,7 @@ const ( ) type Config struct { - RedisClient *redis.Client + ValkeyClient valkey.Client RenewCertBeforeExpiration *time.Duration } @@ -36,7 +36,7 @@ type CertStore interface { } type redisStore struct { - client *redis.Client + client valkey.Client renewCertBeforeExpiration time.Duration } @@ -64,15 +64,15 @@ func NewRedisStore(c *Config) CertStore { renewCertBeforeExpiration = *c.RenewCertBeforeExpiration } return &redisStore{ - client: c.RedisClient, + client: c.ValkeyClient, renewCertBeforeExpiration: renewCertBeforeExpiration, } } func (r *redisStore) LatestPrivate(ctx context.Context) (*ecdsa.PrivateKey, error) { - res, err := r.client.Get(ctx, keyPrivateLatest()).Result() + res, err := r.client.Do(ctx, r.client.B().Get().Key(keyPrivateLatest()).Build()).AsBytes() if err != nil { - if !errors.Is(err, redis.Nil) { // this means not found + if !errors.Is(err, valkey.Nil) { // this means not found return nil, err } @@ -80,7 +80,7 @@ func (r *redisStore) LatestPrivate(ctx context.Context) (*ecdsa.PrivateKey, erro } var privateKey privateKey - err = json.Unmarshal([]byte(res), &privateKey) + err = json.Unmarshal(res, &privateKey) if err != nil { return nil, fmt.Errorf("unable to unmarshal private key: %w", err) } @@ -131,14 +131,13 @@ func (r *redisStore) setNewCert(ctx context.Context) (*ecdsa.PrivateKey, error) return nil, fmt.Errorf("unable to encode signing certificate: %w", err) } - pipe := r.client.TxPipeline() - - _ = pipe.Set(ctx, keyPrivateLatest(), string(encoded), expires) - _ = pipe.Set(ctx, keyPublic(), string(rawBytes), expires) - - _, err = pipe.Exec(ctx) - if err != nil { - return nil, fmt.Errorf("unable to store certificate: %w", err) + cmds := make(valkey.Commands, 0, 2) + cmds = append(cmds, r.client.B().Set().Key(keyPrivateLatest()).Value(string(encoded)).Ex(expires).Build()) + cmds = append(cmds, r.client.B().Set().Key(keyPublic()).Value(string(rawBytes)).Ex(expires).Build()) + for i, resp := range r.client.DoMulti(ctx, cmds...) { + if resp.Error() != nil { + return nil, fmt.Errorf("unable to store certificate with command:%s %w", cmds[i].Commands()[1], resp.Error()) + } } return privKey, nil @@ -146,12 +145,15 @@ func (r *redisStore) setNewCert(ctx context.Context) (*ecdsa.PrivateKey, error) func (r *redisStore) PublicKeys(ctx context.Context) (jwk.Set, string, error) { var ( - set = jwk.NewSet() - iter = r.client.Scan(ctx, 0, matchPublic(), 0).Iterator() + set = jwk.NewSet() ) + entry, err := r.client.Do(ctx, r.client.B().Scan().Cursor(0).Match(matchPublic()).Build()).AsScanEntry() + if err != nil { + return nil, "", err + } - for iter.Next(ctx) { - pemEncoded, err := r.client.Get(ctx, iter.Val()).Result() + for _, element := range entry.Elements { + pemEncoded, err := r.client.Do(ctx, r.client.B().Get().Key(element).Build()).AsBytes() if err != nil { return nil, "", err } @@ -176,9 +178,6 @@ func (r *redisStore) PublicKeys(ctx context.Context) (jwk.Set, string, error) { return nil, "", err } } - if err := iter.Err(); err != nil { - return nil, "", err - } res, err := json.MarshalIndent(set, "", " ") if err != nil { diff --git a/pkg/certs/certs-store_test.go b/pkg/certs/certs-store_test.go index bee3d242..6845361d 100644 --- a/pkg/certs/certs-store_test.go +++ b/pkg/certs/certs-store_test.go @@ -7,22 +7,31 @@ import ( "github.com/lestrrat-go/jwx/v3/jwk" "github.com/metal-stack/metal-apiserver/pkg/certs" "github.com/metal-stack/metal-apiserver/pkg/token" - "github.com/redis/go-redis/v9" "github.com/stretchr/testify/require" + "github.com/valkey-io/valkey-go" ) -func Test_redisStore(t *testing.T) { +func Test_certStore(t *testing.T) { t.Parallel() var ( - ctx = t.Context() - s = miniredis.RunT(t) - c = redis.NewClient(&redis.Options{Addr: s.Addr()}) - store = certs.NewRedisStore(&certs.Config{ - RenewCertBeforeExpiration: new(4 * token.MaxExpiration), - RedisClient: c, - }) + ctx = t.Context() + s = miniredis.RunT(t) ) + c, err := valkey.NewClient(valkey.ClientOption{ + InitAddress: []string{s.Addr()}, + // This is required because otherwise we get: + // unknown subcommand 'TRACKING'. Try CLIENT HELP.: [CLIENT TRACKING ON OPTIN] + // ClientOption.DisableCache must be true for valkey not supporting client-side caching or not supporting RESP3 + DisableCache: true, + }) + require.NoError(t, err) + + store := certs.NewRedisStore(&certs.Config{ + RenewCertBeforeExpiration: new(4 * token.MaxExpiration), + ValkeyClient: c, + }) + set, rawSet, err := store.PublicKeys(ctx) require.NoError(t, err) require.NotEmpty(t, rawSet) diff --git a/pkg/e2e/apiserver.go b/pkg/e2e/apiserver.go index e45e3188..cd670ef3 100644 --- a/pkg/e2e/apiserver.go +++ b/pkg/e2e/apiserver.go @@ -41,9 +41,9 @@ func StartApiserver(t testing.TB, log *slog.Logger, additionalTenants ...string) ServerHttpURL: "https://test.io", RedisConfig: &service.RedisConfig{ // Take the same redis db for all - TokenClient: testStore.GetRedisClient(), - RateLimitClient: testStore.GetRedisClient(), - InviteClient: testStore.GetRedisClient(), + TokenClient: testStore.GetValkeyClient(), + RateLimitClient: testStore.GetValkeyClient(), + InviteClient: testStore.GetValkeyClient(), AsyncClient: testStore.GetRedisClient(), QueueClient: testStore.GetValkeyClient(), ComponentClient: testStore.GetValkeyClient(), diff --git a/pkg/invite/invite-store.go b/pkg/invite/invite-store.go index 07ca452b..bb0550f1 100644 --- a/pkg/invite/invite-store.go +++ b/pkg/invite/invite-store.go @@ -8,10 +8,9 @@ import ( "math/big" "strconv" "strings" - "time" apiv2 "github.com/metal-stack/api/go/metalstack/api/v2" - "github.com/redis/go-redis/v9" + "github.com/valkey-io/valkey-go" "google.golang.org/protobuf/types/known/timestamppb" ) @@ -26,7 +25,7 @@ const ( ) var ( - ErrInviteNotFound = redis.Nil + ErrInviteNotFound = valkey.Nil ) type ProjectInviteStore interface { @@ -48,18 +47,18 @@ type invite interface { } type projectRedisStore struct { - client *redis.Client + client valkey.Client } type tenantRedisStore struct { - client *redis.Client + client valkey.Client } -func NewProjectRedisStore(client *redis.Client) ProjectInviteStore { +func NewProjectRedisStore(client valkey.Client) ProjectInviteStore { return &projectRedisStore{ client: client, } } -func NewTenantRedisStore(client *redis.Client) TenantInviteStore { +func NewTenantRedisStore(client valkey.Client) TenantInviteStore { return &tenantRedisStore{ client: client, } @@ -119,20 +118,20 @@ func (r *tenantRedisStore) SetInvite(ctx context.Context, invite *apiv2.TenantIn return set(ctx, r.client, invite, func() string { return tenantkey(invite) }) } -func get[E any](ctx context.Context, c *redis.Client, secret string) (E, error) { +func get[E any](ctx context.Context, c valkey.Client, secret string) (E, error) { var zero E if err := validateInviteSecret(secret); err != nil { return zero, err } - encoded, err := c.Get(ctx, secretkey(secret)).Result() + encoded, err := c.Do(ctx, c.B().Get().Key(secretkey(secret)).Build()).AsBytes() if err != nil { return zero, err } var e E - err = json.Unmarshal([]byte(encoded), &e) + err = json.Unmarshal(encoded, &e) if err != nil { return zero, err } @@ -140,22 +139,24 @@ func get[E any](ctx context.Context, c *redis.Client, secret string) (E, error) return e, nil } -func delete(ctx context.Context, c *redis.Client, i invite, keyFn func() string) error { +func delete(ctx context.Context, c valkey.Client, i invite, keyFn func() string) error { if err := validateInviteSecret(i.GetSecret()); err != nil { return err } - pipe := c.TxPipeline() - - _ = pipe.Del(ctx, secretkey(i.GetSecret())) - _ = pipe.Del(ctx, keyFn()) - - _, err := pipe.Exec(ctx) + cmds := make(valkey.Commands, 0, 2) + cmds = append(cmds, c.B().Del().Key(secretkey(i.GetSecret())).Build()) + cmds = append(cmds, c.B().Del().Key(keyFn()).Build()) + for i, resp := range c.DoMulti(ctx, cmds...) { + if resp.Error() != nil { + return fmt.Errorf("unable delete with command:%s %w", cmds[i].Commands()[1], resp.Error()) + } + } - return err + return nil } -func set(ctx context.Context, c *redis.Client, i invite, keyFn func() string) error { +func set(ctx context.Context, c valkey.Client, i invite, keyFn func() string) error { if i.GetExpiresAt() == nil { return fmt.Errorf("invite needs to have an expiration") } @@ -169,39 +170,40 @@ func set(ctx context.Context, c *redis.Client, i invite, keyFn func() string) er return fmt.Errorf("unable to encode invite: %w", err) } - pipe := c.TxPipeline() - - _ = pipe.Set(ctx, keyFn(), string(encoded), time.Until(i.GetExpiresAt().AsTime())) - _ = pipe.Set(ctx, secretkey(i.GetSecret()), string(encoded), time.Until(i.GetExpiresAt().AsTime())) - - _, err = pipe.Exec(ctx) - - return err + cmds := make(valkey.Commands, 0, 2) + cmds = append(cmds, c.B().Set().Key(keyFn()).Value(string(encoded)).Exat(i.GetExpiresAt().AsTime()).Build()) + cmds = append(cmds, c.B().Set().Key(secretkey(i.GetSecret())).Value(string(encoded)).Exat(i.GetExpiresAt().AsTime()).Build()) + for i, resp := range c.DoMulti(ctx, cmds...) { + if resp.Error() != nil { + return fmt.Errorf("unable delete with command:%s %w", cmds[i].Commands(), resp.Error()) + } + } + return nil } -func list[E any](ctx context.Context, c *redis.Client, match string) ([]E, error) { +func list[E any](ctx context.Context, c valkey.Client, match string) ([]E, error) { var ( - res []E - iter = c.Scan(ctx, 0, match, 0).Iterator() + res []E ) + entry, err := c.Do(ctx, c.B().Scan().Cursor(0).Match(match).Build()).AsScanEntry() + if err != nil { + return nil, err + } - for iter.Next(ctx) { - encoded, err := c.Get(ctx, iter.Val()).Result() + for _, element := range entry.Elements { + encoded, err := c.Do(ctx, c.B().Get().Key(element).Build()).AsBytes() if err != nil { return nil, err } var i E - err = json.Unmarshal([]byte(encoded), &i) + err = json.Unmarshal(encoded, &i) if err != nil { return nil, err } res = append(res, i) } - if err := iter.Err(); err != nil { - return nil, err - } return res, nil } diff --git a/pkg/invite/invite-store_test.go b/pkg/invite/invite-store_test.go index 6f7b0517..820b1e12 100644 --- a/pkg/invite/invite-store_test.go +++ b/pkg/invite/invite-store_test.go @@ -9,8 +9,8 @@ import ( "github.com/google/go-cmp/cmp" apiv2 "github.com/metal-stack/api/go/metalstack/api/v2" "github.com/metal-stack/metal-apiserver/pkg/errorutil" - "github.com/redis/go-redis/v9" "github.com/stretchr/testify/require" + "github.com/valkey-io/valkey-go" "google.golang.org/protobuf/types/known/timestamppb" ) @@ -53,10 +53,19 @@ func Test_ProjectInvite(t *testing.T) { secret, err := GenerateInviteSecret() require.NoError(t, err) + now := timestamppb.Now() + mr := miniredis.RunT(t) + c, err := valkey.NewClient(valkey.ClientOption{ + InitAddress: []string{mr.Addr()}, + // This is required because otherwise we get: + // unknown subcommand 'TRACKING'. Try CLIENT HELP.: [CLIENT TRACKING ON OPTIN] + // ClientOption.DisableCache must be true for valkey not supporting client-side caching or not supporting RESP3 + DisableCache: true, + }) + require.NoError(t, err) + var ( - now = timestamppb.Now() - mr = miniredis.RunT(t) - store = NewProjectRedisStore(redis.NewClient(&redis.Options{Addr: mr.Addr()})) + store = NewProjectRedisStore(c) ctx = t.Context() i = &apiv2.ProjectInvite{ @@ -96,13 +105,21 @@ func Test_TenantInvite(t *testing.T) { secret, err := GenerateInviteSecret() require.NoError(t, err) + now := timestamppb.Now() + mr := miniredis.RunT(t) + c, err := valkey.NewClient(valkey.ClientOption{ + InitAddress: []string{mr.Addr()}, + // This is required because otherwise we get: + // unknown subcommand 'TRACKING'. Try CLIENT HELP.: [CLIENT TRACKING ON OPTIN] + // ClientOption.DisableCache must be true for valkey not supporting client-side caching or not supporting RESP3 + DisableCache: true, + }) + require.NoError(t, err) + var ( - now = timestamppb.Now() - mr = miniredis.RunT(t) - store = NewTenantRedisStore(redis.NewClient(&redis.Options{Addr: mr.Addr()})) ctx = t.Context() - - i = &apiv2.TenantInvite{ + store = NewTenantRedisStore(c) + i = &apiv2.TenantInvite{ Secret: secret, TargetTenant: "target", Role: apiv2.TenantRole_TENANT_ROLE_EDITOR, diff --git a/pkg/rate-limiter/rate-limit-interceptor.go b/pkg/rate-limiter/rate-limit-interceptor.go index b431257d..e9878464 100644 --- a/pkg/rate-limiter/rate-limit-interceptor.go +++ b/pkg/rate-limiter/rate-limit-interceptor.go @@ -9,13 +9,12 @@ import ( "connectrpc.com/connect" "github.com/metal-stack/metal-apiserver/pkg/errorutil" "github.com/metal-stack/metal-apiserver/pkg/token" - - "github.com/redis/go-redis/v9" + "github.com/valkey-io/valkey-go" ) type Config struct { - Log *slog.Logger - RedisClient *redis.Client + Log *slog.Logger + ValkeyClient valkey.Client MaxRequestsPerMinuteToken int MaxRequestsPerMinuteUnauthenticated int @@ -30,7 +29,7 @@ type ratelimitInterceptor struct { func NewInterceptor(c *Config) *ratelimitInterceptor { return &ratelimitInterceptor{ - ratelimiter: New(c.RedisClient), + ratelimiter: New(c.ValkeyClient), maxRequestsPerMinuteToken: c.MaxRequestsPerMinuteToken, maxRequestsPerMinuteUnauthenticated: c.MaxRequestsPerMinuteUnauthenticated, log: c.Log, diff --git a/pkg/rate-limiter/rate-limiter.go b/pkg/rate-limiter/rate-limiter.go index 974f58dd..d51bbe31 100644 --- a/pkg/rate-limiter/rate-limiter.go +++ b/pkg/rate-limiter/rate-limiter.go @@ -7,7 +7,7 @@ import ( "strconv" "time" - "github.com/redis/go-redis/v9" + "github.com/valkey-io/valkey-go" apiv2 "github.com/metal-stack/api/go/metalstack/api/v2" "github.com/metal-stack/metal-apiserver/pkg/token" @@ -25,11 +25,11 @@ type ( } ratelimiter struct { - client *redis.Client + client valkey.Client } ) -func New(client *redis.Client) *ratelimiter { +func New(client valkey.Client) *ratelimiter { return &ratelimiter{ client: client, } @@ -51,31 +51,24 @@ func (r *ratelimiter) CheckLimitUnauthenticatedAccess(ctx context.Context, ip st } func (r *ratelimiter) limit(ctx context.Context, k string, maxRequestsPerMinute int) (bool, error) { - raw, err := r.client.Get(ctx, k).Result() - if err != nil && !errors.Is(err, redis.Nil) { + count, err := r.client.Do(ctx, r.client.B().Get().Key(k).Build()).AsInt64() + if err != nil && !errors.Is(err, valkey.Nil) { return false, err } if err == nil { - count, err := strconv.Atoi(raw) - if err != nil { - return false, fmt.Errorf("limit count is malformed: %w", err) - } - - if count > maxRequestsPerMinute { + if count > int64(maxRequestsPerMinute) { return false, &errRatelimitReached{limit: maxRequestsPerMinute} } } - // Redis Pipeline will create a new key prefix every minute - pipe := r.client.TxPipeline() - - _ = pipe.Incr(ctx, k) - _ = pipe.Expire(ctx, k, halfHour) // expiration must be less than 60 minutes - - _, err = pipe.Exec(ctx) - if err != nil { - return false, fmt.Errorf("unable to increment rate-limit count: %w", err) + cmds := make(valkey.Commands, 0, 2) + cmds = append(cmds, r.client.B().Incr().Key(k).Build()) + cmds = append(cmds, r.client.B().Expire().Key(k).Seconds(int64(halfHour.Seconds())).Build()) + for i, resp := range r.client.DoMulti(ctx, cmds...) { + if resp.Error() != nil { + return false, fmt.Errorf("unable to increment rate-limit count with command:%s %w", cmds[i].Commands()[1], resp.Error()) + } } return true, nil diff --git a/pkg/rate-limiter/rate-limiter_test.go b/pkg/rate-limiter/rate-limiter_test.go index 487e0281..4d065078 100644 --- a/pkg/rate-limiter/rate-limiter_test.go +++ b/pkg/rate-limiter/rate-limiter_test.go @@ -8,9 +8,9 @@ import ( "github.com/metal-stack/metal-apiserver/pkg/token" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/valkey-io/valkey-go" "github.com/alicebob/miniredis/v2" - "github.com/redis/go-redis/v9" apiv2 "github.com/metal-stack/api/go/metalstack/api/v2" ) @@ -18,14 +18,21 @@ import ( func Test_ratelimiter_CheckLimitTokenAccess(t *testing.T) { ctx := t.Context() s := miniredis.RunT(t) - c := redis.NewClient(&redis.Options{Addr: s.Addr()}) + c, err := valkey.NewClient(valkey.ClientOption{ + InitAddress: []string{s.Addr()}, + // This is required because otherwise we get: + // unknown subcommand 'TRACKING'. Try CLIENT HELP.: [CLIENT TRACKING ON OPTIN] + // ClientOption.DisableCache must be true for valkey not supporting client-side caching or not supporting RESP3 + DisableCache: true, + }) + require.NoError(t, err) limiter := ratelimiter{ client: c, } privateKey, err := certs.NewRedisStore(&certs.Config{ - RedisClient: c, + ValkeyClient: c, }).LatestPrivate(ctx) require.NoError(t, err) diff --git a/pkg/service/api/token/token-service_test.go b/pkg/service/api/token/token-service_test.go index 2da8bd56..8bc3fe5c 100644 --- a/pkg/service/api/token/token-service_test.go +++ b/pkg/service/api/token/token-service_test.go @@ -16,9 +16,9 @@ import ( "github.com/metal-stack/metal-apiserver/pkg/repository/api" "github.com/metal-stack/metal-apiserver/pkg/request" "github.com/metal-stack/metal-apiserver/pkg/token" - "github.com/redis/go-redis/v9" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/valkey-io/valkey-go" "google.golang.org/protobuf/types/known/durationpb" "google.golang.org/protobuf/types/known/timestamppb" ) @@ -32,11 +32,18 @@ func Test_tokenService_CreateConsoleTokenWithoutPermissionCheck(t *testing.T) { t.Parallel() ctx := t.Context() s := miniredis.RunT(t) - c := redis.NewClient(&redis.Options{Addr: s.Addr()}) + c, err := valkey.NewClient(valkey.ClientOption{ + InitAddress: []string{s.Addr()}, + // This is required because otherwise we get: + // unknown subcommand 'TRACKING'. Try CLIENT HELP.: [CLIENT TRACKING ON OPTIN] + // ClientOption.DisableCache must be true for valkey not supporting client-side caching or not supporting RESP3 + DisableCache: true, + }) + require.NoError(t, err) tokenStore := token.NewRedisStore(c) certStore := certs.NewRedisStore(&certs.Config{ - RedisClient: c, + ValkeyClient: c, }) service := New(Config{ @@ -471,11 +478,19 @@ func Test_Create(t *testing.T) { defer cancel() s := miniredis.RunT(t) - c := redis.NewClient(&redis.Options{Addr: s.Addr()}) + + c, err := valkey.NewClient(valkey.ClientOption{ + InitAddress: []string{s.Addr()}, + // This is required because otherwise we get: + // unknown subcommand 'TRACKING'. Try CLIENT HELP.: [CLIENT TRACKING ON OPTIN] + // ClientOption.DisableCache must be true for valkey not supporting client-side caching or not supporting RESP3 + DisableCache: true, + }) + require.NoError(t, err) tokenStore := token.NewRedisStore(c) certStore := certs.NewRedisStore(&certs.Config{ - RedisClient: c, + ValkeyClient: c, }) projectsAndTenantsGetter := func(ctx context.Context, userId string) (*api.ProjectsAndTenants, error) { @@ -596,11 +611,19 @@ func Test_CreateForUser(t *testing.T) { defer cancel() s := miniredis.RunT(t) - c := redis.NewClient(&redis.Options{Addr: s.Addr()}) + + c, err := valkey.NewClient(valkey.ClientOption{ + InitAddress: []string{s.Addr()}, + // This is required because otherwise we get: + // unknown subcommand 'TRACKING'. Try CLIENT HELP.: [CLIENT TRACKING ON OPTIN] + // ClientOption.DisableCache must be true for valkey not supporting client-side caching or not supporting RESP3 + DisableCache: true, + }) + require.NoError(t, err) tokenStore := token.NewRedisStore(c) certStore := certs.NewRedisStore(&certs.Config{ - RedisClient: c, + ValkeyClient: c, }) projectsAndTenantsGetter := func(ctx context.Context, userId string) (*api.ProjectsAndTenants, error) { @@ -1592,11 +1615,19 @@ func Test_Update(t *testing.T) { defer cancel() s := miniredis.RunT(t) - c := redis.NewClient(&redis.Options{Addr: s.Addr()}) + + c, err := valkey.NewClient(valkey.ClientOption{ + InitAddress: []string{s.Addr()}, + // This is required because otherwise we get: + // unknown subcommand 'TRACKING'. Try CLIENT HELP.: [CLIENT TRACKING ON OPTIN] + // ClientOption.DisableCache must be true for valkey not supporting client-side caching or not supporting RESP3 + DisableCache: true, + }) + require.NoError(t, err) tokenStore := token.NewRedisStore(c) certStore := certs.NewRedisStore(&certs.Config{ - RedisClient: c, + ValkeyClient: c, }) if tt.tokenToUpdate != nil { @@ -1732,11 +1763,19 @@ func Test_Refresh(t *testing.T) { defer cancel() s := miniredis.RunT(t) - c := redis.NewClient(&redis.Options{Addr: s.Addr()}) + + c, err := valkey.NewClient(valkey.ClientOption{ + InitAddress: []string{s.Addr()}, + // This is required because otherwise we get: + // unknown subcommand 'TRACKING'. Try CLIENT HELP.: [CLIENT TRACKING ON OPTIN] + // ClientOption.DisableCache must be true for valkey not supporting client-side caching or not supporting RESP3 + DisableCache: true, + }) + require.NoError(t, err) tokenStore := token.NewRedisStore(c) certStore := certs.NewRedisStore(&certs.Config{ - RedisClient: c, + ValkeyClient: c, }) if tt.existingToken != nil { diff --git a/pkg/service/services.go b/pkg/service/services.go index 6b1ae60c..a48d4bf7 100644 --- a/pkg/service/services.go +++ b/pkg/service/services.go @@ -75,9 +75,9 @@ type Config struct { } type RedisConfig struct { - TokenClient *redis.Client - RateLimitClient *redis.Client - InviteClient *redis.Client + TokenClient valkey.Client + RateLimitClient valkey.Client + InviteClient valkey.Client AsyncClient *redis.Client QueueClient valkey.Client ComponentClient valkey.Client @@ -87,7 +87,7 @@ func New(ctx context.Context, log *slog.Logger, c Config) (*http.ServeMux, error var ( tokenStore = tokencommon.NewRedisStore(c.RedisConfig.QueueClient) // FIXME TokenClient must be valkey-go certStore = certs.NewRedisStore(&certs.Config{ - RedisClient: c.RedisConfig.TokenClient, + ValkeyClient: c.RedisConfig.TokenClient, }) projectInviteStore = invite.NewProjectRedisStore(c.RedisConfig.InviteClient) tenantInviteStore = invite.NewTenantRedisStore(c.RedisConfig.InviteClient) @@ -130,7 +130,7 @@ func New(ctx context.Context, log *slog.Logger, c Config) (*http.ServeMux, error tenantInterceptor = tenant.NewInterceptor(log, c.MasterClient) ratelimitInterceptor = ratelimiter.NewInterceptor(&ratelimiter.Config{ Log: log, - RedisClient: c.RedisConfig.RateLimitClient, + ValkeyClient: c.RedisConfig.RateLimitClient, MaxRequestsPerMinuteToken: c.MaxRequestsPerMinuteToken, MaxRequestsPerMinuteUnauthenticated: c.MaxRequestsPerMinuteUnauthenticated, }) diff --git a/pkg/test/repository.go b/pkg/test/repository.go index a4090b66..1bbdb352 100644 --- a/pkg/test/repository.go +++ b/pkg/test/repository.go @@ -182,10 +182,10 @@ func StartRepositoryWithCleanup(t testing.TB, log *slog.Logger, testOpts ...test hc, headscaleControllerURL, headscaleCloser = StartHeadscale(t) } - projectInviteStore := invite.NewProjectRedisStore(rc) - tenantInviteStore := invite.NewTenantRedisStore(rc) + projectInviteStore := invite.NewProjectRedisStore(vc) + tenantInviteStore := invite.NewTenantRedisStore(vc) tokenStore := tokencommon.NewRedisStore(vc) - certStore := certs.NewRedisStore(&certs.Config{RedisClient: rc}) + certStore := certs.NewRedisStore(&certs.Config{ValkeyClient: vc}) auditingBackend, err := auditingmemory.NewMemory(auditing.Config{ Component: api.AuditingComponent, diff --git a/pkg/token/token-store.go b/pkg/token/token-store.go index 703e462b..3e7843d6 100644 --- a/pkg/token/token-store.go +++ b/pkg/token/token-store.go @@ -9,7 +9,6 @@ import ( apiv2 "github.com/metal-stack/api/go/metalstack/api/v2" "github.com/valkey-io/valkey-go" - "github.com/valkey-io/valkey-go/valkeycompat" ) const ( @@ -104,15 +103,14 @@ func (r *redisStore) List(ctx context.Context, userid string) ([]*apiv2.Token, e func (r *redisStore) AdminList(ctx context.Context) ([]*apiv2.Token, error) { var ( - compat = valkeycompat.NewAdapter(r.client) - res []*apiv2.Token + res []*apiv2.Token ) - elements, _, err := compat.Scan(ctx, 0, prefix+"*", 0).Result() + entry, err := r.client.Do(ctx, r.client.B().Scan().Cursor(0).Match(prefix+"*").Build()).AsScanEntry() if err != nil { - return nil, err + return nil, fmt.Errorf("error scanning all tokens error:%w", err) } - for _, element := range elements { + for _, element := range entry.Elements { encoded, err := r.client.Do(ctx, r.client.B().Get().Key(element).Build()).AsBytes() if err != nil { return nil, fmt.Errorf("unable to get content by key:%q error:%w", encoded, err) From 5b44d8e0c2baea61b8be11de4f1ab0b402466975 Mon Sep 17 00:00:00 2001 From: Stefan Majer Date: Thu, 14 May 2026 09:22:15 +0200 Subject: [PATCH 3/9] Test fixes --- cmd/server/token-cmd.go | 1 - pkg/db/generic/generic.go | 4 ++-- pkg/invite/invite-store.go | 11 +++++++---- pkg/invite/invite-store_test.go | 9 +++++---- pkg/service/api/tenant/tenant-service_test.go | 18 +++++++++--------- pkg/token/token-store.go | 8 +++++++- 6 files changed, 30 insertions(+), 21 deletions(-) diff --git a/cmd/server/token-cmd.go b/cmd/server/token-cmd.go index ca63f39b..eb2b6edb 100644 --- a/cmd/server/token-cmd.go +++ b/cmd/server/token-cmd.go @@ -136,7 +136,6 @@ func newTokenCmd() *cli.Command { var adminRole *apiv2.AdminRole if roleString := ctx.String(tokenAdminRoleFlag.Name); roleString != "" { - // FIXME new linter complains that role is never used role, ok := apiv2.AdminRole_value[roleString] if !ok { return fmt.Errorf("unknown role: %s", roleString) diff --git a/pkg/db/generic/generic.go b/pkg/db/generic/generic.go index acf73d59..691d4ecd 100644 --- a/pkg/db/generic/generic.go +++ b/pkg/db/generic/generic.go @@ -39,6 +39,7 @@ type ( } Datastore interface { + // Entities IP() Storage[*metal.IP] Machine() Storage[*metal.Machine] Size() Storage[*metal.Size] @@ -52,12 +53,11 @@ type ( SwitchStatus() Storage[*metal.SwitchStatus] Event() Storage[*metal.ProvisioningEventContainer] - // sizeimageConstraint Storage[*metal.SizeImageConstraint] - // Pools AsnPool() *integerPool VrfPool() *integerPool + // SharedMutex Lock(ctx context.Context, key string, opts ...lockOpt) error Unlock(ctx context.Context, key string, opts ...lockOpt) diff --git a/pkg/invite/invite-store.go b/pkg/invite/invite-store.go index bb0550f1..cbba71b3 100644 --- a/pkg/invite/invite-store.go +++ b/pkg/invite/invite-store.go @@ -125,15 +125,15 @@ func get[E any](ctx context.Context, c valkey.Client, secret string) (E, error) return zero, err } - encoded, err := c.Do(ctx, c.B().Get().Key(secretkey(secret)).Build()).AsBytes() + encoded, err := c.Do(ctx, c.B().Get().Key(secretkey(secret)).Build()).ToString() if err != nil { - return zero, err + return zero, fmt.Errorf("unable to get secret as bytes:%w", err) } var e E - err = json.Unmarshal(encoded, &e) + err = json.Unmarshal([]byte(encoded), &e) if err != nil { - return zero, err + return zero, fmt.Errorf("unable to unmarshal secret from bytes:%w", err) } return e, nil @@ -173,6 +173,9 @@ func set(ctx context.Context, c valkey.Client, i invite, keyFn func() string) er cmds := make(valkey.Commands, 0, 2) cmds = append(cmds, c.B().Set().Key(keyFn()).Value(string(encoded)).Exat(i.GetExpiresAt().AsTime()).Build()) cmds = append(cmds, c.B().Set().Key(secretkey(i.GetSecret())).Value(string(encoded)).Exat(i.GetExpiresAt().AsTime()).Build()) + for _, cmd := range cmds { + fmt.Printf("cmd:%s\n", cmd.Commands()) + } for i, resp := range c.DoMulti(ctx, cmds...) { if resp.Error() != nil { return fmt.Errorf("unable delete with command:%s %w", cmds[i].Commands(), resp.Error()) diff --git a/pkg/invite/invite-store_test.go b/pkg/invite/invite-store_test.go index 820b1e12..19f55c33 100644 --- a/pkg/invite/invite-store_test.go +++ b/pkg/invite/invite-store_test.go @@ -4,6 +4,7 @@ import ( "fmt" "strings" "testing" + "time" "github.com/alicebob/miniredis/v2" "github.com/google/go-cmp/cmp" @@ -53,7 +54,7 @@ func Test_ProjectInvite(t *testing.T) { secret, err := GenerateInviteSecret() require.NoError(t, err) - now := timestamppb.Now() + inOneHour := timestamppb.New(time.Now().Add(time.Hour)) mr := miniredis.RunT(t) c, err := valkey.NewClient(valkey.ClientOption{ InitAddress: []string{mr.Addr()}, @@ -76,7 +77,7 @@ func Test_ProjectInvite(t *testing.T) { ProjectName: "bar", Tenant: "tenant", TenantName: "tenant with name", - ExpiresAt: now, + ExpiresAt: inOneHour, JoinedAt: nil, } ) @@ -105,7 +106,7 @@ func Test_TenantInvite(t *testing.T) { secret, err := GenerateInviteSecret() require.NoError(t, err) - now := timestamppb.Now() + inOneHour := timestamppb.New(time.Now().Add(time.Hour)) mr := miniredis.RunT(t) c, err := valkey.NewClient(valkey.ClientOption{ InitAddress: []string{mr.Addr()}, @@ -127,7 +128,7 @@ func Test_TenantInvite(t *testing.T) { TargetTenantName: "target with name", Tenant: "tenant", TenantName: "tenant with name", - ExpiresAt: now, + ExpiresAt: inOneHour, JoinedAt: nil, } ) diff --git a/pkg/service/api/tenant/tenant-service_test.go b/pkg/service/api/tenant/tenant-service_test.go index 4ae423cd..e78290b1 100644 --- a/pkg/service/api/tenant/tenant-service_test.go +++ b/pkg/service/api/tenant/tenant-service_test.go @@ -1017,7 +1017,7 @@ func Test_tenantServiceServer_InviteGet(t *testing.T) { testStore, closer := test.StartRepositoryWithCleanup(t, log, test.WithPostgres(true)) defer closer() - now := timestamppb.Now() + inOneHour := timestamppb.New(time.Now().Add(time.Hour)) test.CreateTenantInvites(t, testStore, []*apiv2.TenantInvite{ { @@ -1028,7 +1028,7 @@ func Test_tenantServiceServer_InviteGet(t *testing.T) { TargetTenantName: "john.doe@github", Tenant: "john.doe@github", TenantName: "john.doe@github", - ExpiresAt: now, + ExpiresAt: inOneHour, JoinedAt: nil, }, }) @@ -1053,7 +1053,7 @@ func Test_tenantServiceServer_InviteGet(t *testing.T) { Tenant: "john.doe@github", TenantName: "john.doe@github", Secret: "abcdefghijklmnopqrstuvwxyz123456", - ExpiresAt: now, + ExpiresAt: inOneHour, JoinedAt: nil, }, }, @@ -1114,7 +1114,7 @@ func Test_tenantServiceServer_InvitesList(t *testing.T) { testStore, closer := test.StartRepositoryWithCleanup(t, log, test.WithPostgres(true)) defer closer() - now := timestamppb.Now() + inOneHour := timestamppb.New(time.Now().Add(time.Hour)) test.CreateTenantInvites(t, testStore, []*apiv2.TenantInvite{ { @@ -1125,7 +1125,7 @@ func Test_tenantServiceServer_InvitesList(t *testing.T) { TargetTenantName: "john.doe@github", Tenant: "john.doe@github", TenantName: "john.doe@github", - ExpiresAt: now, + ExpiresAt: inOneHour, JoinedAt: nil, }, { @@ -1136,7 +1136,7 @@ func Test_tenantServiceServer_InvitesList(t *testing.T) { TargetTenantName: "will.smith@github", Tenant: "john.doe@github", TenantName: "john.doe@github", - ExpiresAt: now, + ExpiresAt: inOneHour, JoinedAt: nil, }, }) @@ -1162,7 +1162,7 @@ func Test_tenantServiceServer_InvitesList(t *testing.T) { TargetTenantName: "john.doe@github", Tenant: "john.doe@github", TenantName: "john.doe@github", - ExpiresAt: now, + ExpiresAt: inOneHour, JoinedAt: nil, }, }, @@ -1217,7 +1217,7 @@ func Test_tenantServiceServer_InviteDelete(t *testing.T) { testStore, closer := test.StartRepositoryWithCleanup(t, log, test.WithPostgres(true)) defer closer() - now := timestamppb.Now() + inOneHour := timestamppb.New(time.Now().Add(time.Hour)) test.CreateTenantInvites(t, testStore, []*apiv2.TenantInvite{ { @@ -1228,7 +1228,7 @@ func Test_tenantServiceServer_InviteDelete(t *testing.T) { TargetTenantName: "john.doe@github", Tenant: "john.doe@github", TenantName: "john.doe@github", - ExpiresAt: now, + ExpiresAt: inOneHour, JoinedAt: nil, }, }) diff --git a/pkg/token/token-store.go b/pkg/token/token-store.go index 3e7843d6..f3dece77 100644 --- a/pkg/token/token-store.go +++ b/pkg/token/token-store.go @@ -6,9 +6,11 @@ import ( "errors" "fmt" "log/slog" + "time" apiv2 "github.com/metal-stack/api/go/metalstack/api/v2" "github.com/valkey-io/valkey-go" + "google.golang.org/protobuf/types/known/timestamppb" ) const ( @@ -52,8 +54,12 @@ func (r *redisStore) Set(ctx context.Context, token *apiv2.Token) error { if err != nil { return fmt.Errorf("unable to encode token: %w", err) } + if token.Expires == nil { + token.Expires = timestamppb.New(time.Now().Add(DefaultExpiration)) + } - err = r.client.Do(ctx, r.client.B().Set().Key(key(token.User, token.Uuid)).Value(string(encoded)).ExatTimestamp(token.Expires.AsTime().UnixMilli()).Build()).Error() + cmd := r.client.B().Set().Key(key(token.User, token.Uuid)).Value(string(encoded)).Exat(token.GetExpires().AsTime()).Build() + err = r.client.Do(ctx, cmd).Error() if err != nil { return err } From 4b09e913c82a2971beab80807ebc08fc2fd6ff99 Mon Sep 17 00:00:00 2001 From: Stefan Majer Date: Thu, 14 May 2026 09:46:11 +0200 Subject: [PATCH 4/9] Test fixes --- go.mod | 26 +++---- go.sum | 70 +++++++++---------- .../api/project/project-service_test.go | 18 ++--- pkg/token/token-store_test.go | 6 +- 4 files changed, 59 insertions(+), 61 deletions(-) diff --git a/go.mod b/go.mod index 37dcb340..0943da52 100644 --- a/go.mod +++ b/go.mod @@ -9,8 +9,8 @@ require ( connectrpc.com/grpcreflect v1.3.0 connectrpc.com/otelconnect v0.9.0 connectrpc.com/validate v0.6.0 - github.com/Masterminds/semver/v3 v3.4.0 - github.com/alicebob/miniredis/v2 v2.37.0 + github.com/Masterminds/semver/v3 v3.5.0 + github.com/alicebob/miniredis/v2 v2.38.0 github.com/avast/retry-go/v4 v4.7.0 github.com/dustin/go-humanize v1.0.1 github.com/golang-jwt/jwt/v5 v5.3.1 @@ -23,7 +23,7 @@ require ( github.com/jmoiron/sqlx v1.4.0 github.com/juanfont/headscale v0.28.0 github.com/klauspost/connect-compress/v2 v2.1.1 - github.com/lestrrat-go/jwx/v3 v3.1.0 + github.com/lestrrat-go/jwx/v3 v3.1.1 github.com/looplab/fsm v1.0.3 github.com/markbates/goth v1.82.0 github.com/metal-stack/api v0.0.62 @@ -32,7 +32,7 @@ require ( github.com/metal-stack/metal-lib v0.25.0 github.com/metal-stack/v v1.0.3 github.com/prometheus/client_golang v1.23.2 - github.com/redis/go-redis/v9 v9.18.0 + github.com/redis/go-redis/v9 v9.19.0 github.com/rs/cors v1.11.1 github.com/samber/lo v1.53.0 github.com/stretchr/testify v1.11.1 @@ -40,14 +40,14 @@ require ( github.com/testcontainers/testcontainers-go/modules/postgres v0.42.0 github.com/testcontainers/testcontainers-go/modules/valkey v0.42.0 github.com/urfave/cli/v2 v2.27.7 - github.com/valkey-io/valkey-go v1.0.74 + github.com/valkey-io/valkey-go v1.0.75 go.opentelemetry.io/otel/exporters/prometheus v0.65.0 go.opentelemetry.io/otel/sdk/metric v1.43.0 go4.org/netipx v0.0.0-20231129151722-fdeea329fbba - golang.org/x/crypto v0.50.0 + golang.org/x/crypto v0.51.0 golang.org/x/oauth2 v0.36.0 golang.org/x/sync v0.20.0 - google.golang.org/grpc v1.80.0 + google.golang.org/grpc v1.81.0 google.golang.org/protobuf v1.36.11 gopkg.in/rethinkdb/rethinkdb-go.v6 v6.2.2 tailscale.com v1.96.5 @@ -97,7 +97,6 @@ require ( github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/dblohm7/wingoes v0.0.0-20250822163801-6d8e6105c62d // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.1 // indirect - github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/distribution/reference v0.6.0 // indirect github.com/docker/go-connections v0.7.0 // indirect github.com/docker/go-units v0.5.0 // indirect @@ -195,6 +194,7 @@ require ( github.com/tailscale/wireguard-go v0.0.0-20250716170648-1d0488a3d7da // indirect github.com/tklauser/go-sysconf v0.3.16 // indirect github.com/tklauser/numcpus v0.11.0 // indirect + github.com/valyala/fastjson v1.6.10 // indirect github.com/x448/float16 v0.8.4 // indirect github.com/xdg-go/pbkdf2 v1.0.0 // indirect github.com/xdg-go/scram v1.2.0 // indirect @@ -218,11 +218,11 @@ require ( go.uber.org/zap v1.27.1 // indirect go.yaml.in/yaml/v2 v2.4.4 // indirect go4.org/mem v0.0.0-20240501181205-ae6ca9944745 // indirect - golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f // indirect - golang.org/x/net v0.53.0 // indirect - golang.org/x/sys v0.43.0 // indirect - golang.org/x/term v0.42.0 // indirect - golang.org/x/text v0.36.0 // indirect + golang.org/x/exp v0.0.0-20260508232706-74f9aab9d74a // indirect + golang.org/x/net v0.54.0 // indirect + golang.org/x/sys v0.44.0 // indirect + golang.org/x/term v0.43.0 // indirect + golang.org/x/text v0.37.0 // indirect golang.org/x/time v0.15.0 // indirect golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect golang.zx2c4.com/wireguard/windows v1.0.1 // indirect diff --git a/go.sum b/go.sum index 9ac00526..becd6c6f 100644 --- a/go.sum +++ b/go.sum @@ -31,8 +31,8 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03 github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg= github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= -github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0= -github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= +github.com/Masterminds/semver/v3 v3.5.0 h1:kQceYJfbupGfZOKZQg0kou0DgAKhzDg2NZPAwZ/2OOE= +github.com/Masterminds/semver/v3 v3.5.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= github.com/Masterminds/squirrel v1.5.4 h1:uUcX/aBc8O7Fg9kaISIUsHXdKuqehiXAMQTYX8afzqM= github.com/Masterminds/squirrel v1.5.4/go.mod h1:NNaOrjSoIDfDA40n7sr2tPNZRfjzjA400rg+riTZj10= github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= @@ -41,8 +41,8 @@ github.com/akutz/memconn v0.1.0 h1:NawI0TORU4hcOMsMr11g7vwlCdkYeLKXBcxWu2W/P8A= github.com/akutz/memconn v0.1.0/go.mod h1:Jo8rI7m0NieZyLI5e2CDlRdRqRRB4S7Xp77ukDjH+Fw= github.com/alexbrainman/sspi v0.0.0-20250919150558-7d374ff0d59e h1:4dAU9FXIyQktpoUAgOJK3OTFc/xug0PCXYCqU0FgDKI= github.com/alexbrainman/sspi v0.0.0-20250919150558-7d374ff0d59e/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4= -github.com/alicebob/miniredis/v2 v2.37.0 h1:RheObYW32G1aiJIj81XVt78ZHJpHonHLHW7OLIshq68= -github.com/alicebob/miniredis/v2 v2.37.0/go.mod h1:TcL7YfarKPGDAthEtl5NBeHZfeUQj6OXMm/+iu5cLMM= +github.com/alicebob/miniredis/v2 v2.38.0 h1:nZAzCR+Lj+Vxk4ZXzm2NuKq2O33RXj1XxJ2e2uP9jiw= +github.com/alicebob/miniredis/v2 v2.38.0/go.mod h1:TcL7YfarKPGDAthEtl5NBeHZfeUQj6OXMm/+iu5cLMM= github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8= github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4= github.com/antlr4-go/antlr/v4 v4.13.1 h1:SqQKkuVZ+zWkMMNkjy5FZe5mr5WURWnlpmOuzYWrPrQ= @@ -144,8 +144,6 @@ github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.1 h1:5RVFMOWjMyRy8cARdy79nAmgYw3h github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.1/go.mod h1:ZXNYxsqcloTdSy/rNShjYzMhyjf0LaoftYK0p+A3h40= github.com/dgryski/go-metro v0.0.0-20250106013310-edb8663e5e33 h1:ucRHb6/lvW/+mTEIGbvhcYU3S8+uSNkuMjx/qZFfhtM= github.com/dgryski/go-metro v0.0.0-20250106013310-edb8663e5e33/go.mod h1:c9O8+fpSOX1DM8cPNSkX/qsBWdkD4yd2dpciOWQjpBw= -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/digitalocean/go-smbios v0.0.0-20180907143718-390a4f403a8e h1:vUmf0yezR0y7jJ5pceLHthLaYf4bA5T14B6q39S4q2Q= github.com/digitalocean/go-smbios v0.0.0-20180907143718-390a4f403a8e/go.mod h1:YTIHhz/QFSYnu/EhlF2SpU2Uk+32abacUYA5ZPljz1A= github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= @@ -373,8 +371,8 @@ github.com/klauspost/compress v1.18.5 h1:/h1gH5Ce+VWNLSWqPzOVn6XBO+vJbCNGvjoaGBF github.com/klauspost/compress v1.18.5/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ= github.com/klauspost/connect-compress/v2 v2.1.1 h1:ycZNp4rWOZBodVE2Ls5AzK4aHkyK+GteEfzRZgKNs+c= github.com/klauspost/connect-compress/v2 v2.1.1/go.mod h1:9oilsPHJMzGKkjafSBk9J7iVo4mO+dw0G0KSdVpnlVE= -github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4= -github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE= +github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kortschak/wol v0.0.0-20200729010619-da482cc4850a h1:+RR6SqnTkDLWyICxS1xpjCi/3dhyV+TgZwA6Ww3KncQ= @@ -405,8 +403,8 @@ github.com/lestrrat-go/httpcc v1.0.1 h1:ydWCStUeJLkpYyjLDHihupbn2tYmZ7m22BGkcvZZ github.com/lestrrat-go/httpcc v1.0.1/go.mod h1:qiltp3Mt56+55GPVCbTdM9MlqhvzyuL6W/NMDA8vA5E= github.com/lestrrat-go/httprc/v3 v3.0.5 h1:S+Mb4L2I+bM6JGTibLmxExhyTOqnXjqx+zi9MoXw/TM= github.com/lestrrat-go/httprc/v3 v3.0.5/go.mod h1:mSMtkZW92Z98M5YoNNztbRGxbXHql7tSitCvaxvo9l0= -github.com/lestrrat-go/jwx/v3 v3.1.0 h1:AyyLtxc0QM75F75JroWgt1phwC7X+wOb3XKhH7XBZWw= -github.com/lestrrat-go/jwx/v3 v3.1.0/go.mod h1:uw/MN2M/Xiu4FhwcIwH11Zsh9JWx9SWzgALl7/uIEkU= +github.com/lestrrat-go/jwx/v3 v3.1.1 h1:yd9AdPmZ4INnQ7k42IrzXYpnEG803+SrQ6hdMvzHJzw= +github.com/lestrrat-go/jwx/v3 v3.1.1/go.mod h1:uw/MN2M/Xiu4FhwcIwH11Zsh9JWx9SWzgALl7/uIEkU= github.com/lestrrat-go/option/v2 v2.0.0 h1:XxrcaJESE1fokHy3FpaQ/cXW8ZsIdWcdFzzLOcID3Ss= github.com/lestrrat-go/option/v2 v2.0.0/go.mod h1:oSySsmzMoR0iRzCDCaUfsCzxQHUEuhOViQObyy7S6Vg= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= @@ -498,8 +496,8 @@ github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= -github.com/onsi/gomega v1.38.3 h1:eTX+W6dobAYfFeGC2PV6RwXRu/MyT+cQguijutvkpSM= -github.com/onsi/gomega v1.38.3/go.mod h1:ZCU1pkQcXDO5Sl9/VVEGlDyp+zm0m1cmeG5TOzLgdh4= +github.com/onsi/gomega v1.39.1 h1:1IJLAad4zjPn2PsnhH70V4DKRFlrCzGBNrNaru+Vf28= +github.com/onsi/gomega v1.39.1/go.mod h1:hL6yVALoTOxeWudERyfppUcZXjMwIMLnuSfruD2lcfg= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040= @@ -532,8 +530,8 @@ github.com/prometheus/otlptranslator v1.0.0 h1:s0LJW/iN9dkIH+EnhiD3BlkkP5QVIUVEo github.com/prometheus/otlptranslator v1.0.0/go.mod h1:vRYWnXvI6aWGpsdY/mOT/cbeVRBlPWtBNDb7kGR3uKM= github.com/prometheus/procfs v0.20.1 h1:XwbrGOIplXW/AU3YhIhLODXMJYyC1isLFfYCsTEycfc= github.com/prometheus/procfs v0.20.1/go.mod h1:o9EMBZGRyvDrSPH1RqdxhojkuXstoe4UlK79eF5TGGo= -github.com/redis/go-redis/v9 v9.18.0 h1:pMkxYPkEbMPwRdenAzUNyFNrDgHx9U+DrBabWNfSRQs= -github.com/redis/go-redis/v9 v9.18.0/go.mod h1:k3ufPphLU5YXwNTUcCRXGxUoF1fqxnhFQmscfkCoDA0= +github.com/redis/go-redis/v9 v9.19.0 h1:XPVaaPSnG6RhYf7p+rmSa9zZfeVAnWsH5h3lxthOm/k= +github.com/redis/go-redis/v9 v9.19.0/go.mod h1:v/M13XI1PVCDcm01VtPFOADfZtHf8YW3baQf57KlIkA= github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= github.com/rodaine/protogofakeit v0.1.1 h1:ZKouljuRM3A+TArppfBqnH8tGZHOwM/pjvtXe9DaXH8= @@ -621,8 +619,8 @@ github.com/u-root/uio v0.0.0-20240224005618-d2acac8f3701 h1:pyC9PaHYZFgEKFdlp3G8 github.com/u-root/uio v0.0.0-20240224005618-d2acac8f3701/go.mod h1:P3a5rG4X7tI17Nn3aOIAYr5HbIMukwXG0urG0WuL8OA= github.com/urfave/cli/v2 v2.27.7 h1:bH59vdhbjLv3LAvIu6gd0usJHgoTTPhCFib8qqOwXYU= github.com/urfave/cli/v2 v2.27.7/go.mod h1:CyNAG/xg+iAOg0N4MPGZqVmv2rCoP267496AOXUZjA4= -github.com/valkey-io/valkey-go v1.0.74 h1:NqtBHzjybz+is+c71hsyZP7hoE5lwCHQX026me0Vb08= -github.com/valkey-io/valkey-go v1.0.74/go.mod h1:VGhZ6fs68Qrn2+OhH+6waZH27bjpgQOiLyUQyXuYK5k= +github.com/valkey-io/valkey-go v1.0.75 h1:cfq9DODW2ntuUgyHJmFWb4/p+xpLpQB1t5SQyWM9uJ4= +github.com/valkey-io/valkey-go v1.0.75/go.mod h1:6X581PhgfeMkJmyfjIsa2eFdq6dy3Qkkg9zwjM1p42M= github.com/valyala/fastjson v1.6.10 h1:/yjJg8jaVQdYR3arGxPE2X5z89xrlhS0eGXdv+ADTh4= github.com/valyala/fastjson v1.6.10/go.mod h1:e6FubmQouUNP73jtMLmcbxS6ydWIpOfhz34TSfO3JaE= github.com/vishvananda/netns v0.0.5 h1:DfiHV+j8bA32MFM7bfEunvT8IAqQ/NzSJHtcmW5zdEY= @@ -646,8 +644,8 @@ github.com/yuin/gopher-lua v1.1.2 h1:yF/FjE3hD65tBbt0VXLE13HWS9h34fdzJmrWRXwobGA github.com/yuin/gopher-lua v1.1.2/go.mod h1:7aRmXIWl37SqRf0koeyylBEzJ+aPt8A+mmkQ4f1ntR8= github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= -github.com/zeebo/xxh3 v1.0.2 h1:xZmwmqxHZA8AI603jOQ0tMqmBr9lPeFwGg6d+xy9DC0= -github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA= +github.com/zeebo/xxh3 v1.1.0 h1:s7DLGDK45Dyfg7++yxI0khrfwq9661w9EN78eP/UZVs= +github.com/zeebo/xxh3 v1.1.0/go.mod h1:IisAie1LELR4xhVinxWS5+zf1lA4p0MW4T+w+W07F5s= github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= go.etcd.io/etcd/api/v3 v3.6.10 h1:jlwjtELjA8yi2VWpOFH+0w0lGr3K6mVDyn0RDB9aaAY= go.etcd.io/etcd/api/v3 v3.6.10/go.mod h1:pdV4VeFmvhdNjB4LWRkC8ReLyRBAxUOze3GarMhE2sk= @@ -713,10 +711,10 @@ golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/crypto v0.20.0/go.mod h1:Xwo95rrVNIoSMx9wa1JroENMToLWn3RNVrTBpLHgZPQ= -golang.org/x/crypto v0.50.0 h1:zO47/JPrL6vsNkINmLoo/PH1gcxpls50DNogFvB5ZGI= -golang.org/x/crypto v0.50.0/go.mod h1:3muZ7vA7PBCE6xgPX7nkzzjiUq87kRItoJQM1Yo8S+Q= -golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f h1:W3F4c+6OLc6H2lb//N1q4WpJkhzJCK5J6kUi1NTVXfM= -golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f/go.mod h1:J1xhfL/vlindoeF/aINzNzt2Bket5bjo9sdOYzOsU80= +golang.org/x/crypto v0.51.0 h1:IBPXwPfKxY7cWQZ38ZCIRPI50YLeevDLlLnyC5wRGTI= +golang.org/x/crypto v0.51.0/go.mod h1:8AdwkbraGNABw2kOX6YFPs3WM22XqI4EXEd8g+x7Oc8= +golang.org/x/exp v0.0.0-20260508232706-74f9aab9d74a h1:+3jdDGGB8NGb1Zktc737jlt3/A5f6UlwSzmvqUuufxw= +golang.org/x/exp v0.0.0-20260508232706-74f9aab9d74a/go.mod h1:d2fgXJLVs4dYDHUk5lwMIfzRzSrWCfGZb0ZqeLa/Vcw= golang.org/x/exp/typeparams v0.0.0-20240314144324-c7f7c6466f7f h1:phY1HzDcf18Aq9A8KkmRtY9WvOFIxN8wgfvy6Zm1DV8= golang.org/x/exp/typeparams v0.0.0-20240314144324-c7f7c6466f7f/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= golang.org/x/image v0.27.0 h1:C8gA4oWU/tKkdCfYT6T2u4faJu3MeNS5O8UPWlPF61w= @@ -728,8 +726,8 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.35.0 h1:Ww1D637e6Pg+Zb2KrWfHQUnH2dQRLBQyAtpr/haaJeM= -golang.org/x/mod v0.35.0/go.mod h1:+GwiRhIInF8wPm+4AoT6L0FA1QWAad3OMdTRx4tFYlU= +golang.org/x/mod v0.36.0 h1:JJjpVx6myfUsUdAzZuOSTTmRE0PfZeNWzzvKrP7amb4= +golang.org/x/mod v0.36.0/go.mod h1:moc6ELqsWcOw5Ef3xVprK5ul/MvtVvkIXLziUOICjUQ= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -742,8 +740,8 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= -golang.org/x/net v0.53.0 h1:d+qAbo5L0orcWAr0a9JweQpjXF19LMXJE8Ey7hwOdUA= -golang.org/x/net v0.53.0/go.mod h1:JvMuJH7rrdiCfbeHoo3fCQU24Lf5JJwT9W3sJFulfgs= +golang.org/x/net v0.54.0 h1:2zJIZAxAHV/OHCDTCOHAYehQzLfSXuf/5SoL/Dv6w/w= +golang.org/x/net v0.54.0/go.mod h1:Sj4oj8jK6XmHpBZU/zWHw3BV3abl4Kvi+Ut7cQcY+cQ= golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs= golang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -779,16 +777,16 @@ golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI= -golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/sys v0.44.0 h1:ildZl3J4uzeKP07r2F++Op7E9B29JRUy+a27EibtBTQ= +golang.org/x/sys v0.44.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= -golang.org/x/term v0.42.0 h1:UiKe+zDFmJobeJ5ggPwOshJIVt6/Ft0rcfrXZDLWAWY= -golang.org/x/term v0.42.0/go.mod h1:Dq/D+snpsbazcBG5+F9Q1n2rXV8Ma+71xEjTRufARgY= +golang.org/x/term v0.43.0 h1:S4RLU2sB31O/NCl+zFN9Aru9A/Cq2aqKpTZJ6B+DwT4= +golang.org/x/term v0.43.0/go.mod h1:lrhlHNdQJHO+1qVYiHfFKVuVioJIheAc3fBSMFYEIsk= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -799,8 +797,8 @@ golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.36.0 h1:JfKh3XmcRPqZPKevfXVpI1wXPTqbkE5f7JA92a55Yxg= -golang.org/x/text v0.36.0/go.mod h1:NIdBknypM8iqVmPiuco0Dh6P5Jcdk8lJL0CUebqK164= +golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc= +golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38= golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U= golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -816,8 +814,8 @@ golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.44.0 h1:UP4ajHPIcuMjT1GqzDWRlalUEoY+uzoZKnhOjbIPD2c= -golang.org/x/tools v0.44.0/go.mod h1:KA0AfVErSdxRZIsOVipbv3rQhVXTnlU6UhKxHd1seDI= +golang.org/x/tools v0.45.0 h1:18qN3FAooORvApf5XjCXgsuayZOEtXf6JK18I3+ONa8= +golang.org/x/tools v0.45.0/go.mod h1:LuUGqqaXcXMEFEruIVJVm5mgDD8vww/z/SR1gQ4uE/0= golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -834,8 +832,8 @@ google.golang.org/genproto/googleapis/api v0.0.0-20260420184626-e10c466a9529 h1: google.golang.org/genproto/googleapis/api v0.0.0-20260420184626-e10c466a9529/go.mod h1:a5OGAgyRr4lqco7AG9hQM9Fwh0N2ZV4grR0eXFEsXQg= google.golang.org/genproto/googleapis/rpc v0.0.0-20260420184626-e10c466a9529 h1:XF8+t6QQiS0o9ArVan/HW8Q7cycNPGsJf6GA2nXxYAg= google.golang.org/genproto/googleapis/rpc v0.0.0-20260420184626-e10c466a9529/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= -google.golang.org/grpc v1.80.0 h1:Xr6m2WmWZLETvUNvIUmeD5OAagMw3FiKmMlTdViWsHM= -google.golang.org/grpc v1.80.0/go.mod h1:ho/dLnxwi3EDJA4Zghp7k2Ec1+c2jqup0bFkw07bwF4= +google.golang.org/grpc v1.81.0 h1:W3G9N3KQf3BU+YuCtGKJk0CmxQNbAISICD/9AORxLIw= +google.golang.org/grpc v1.81.0/go.mod h1:xGH9GfzOyMTGIOXBJmXt+BX/V0kcdQbdcuwQ/zNw42I= google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= diff --git a/pkg/service/api/project/project-service_test.go b/pkg/service/api/project/project-service_test.go index c4dbb411..4dce6ee4 100644 --- a/pkg/service/api/project/project-service_test.go +++ b/pkg/service/api/project/project-service_test.go @@ -1115,7 +1115,7 @@ func Test_projectServiceServer_InviteGet(t *testing.T) { testStore, closer := test.StartRepositoryWithCleanup(t, log, test.WithPostgres(true)) defer closer() - now := timestamppb.Now() + inOneHour := timestamppb.New(time.Now().Add(time.Hour)) test.CreateProjectInvites(t, testStore, []*apiv2.ProjectInvite{ { @@ -1126,7 +1126,7 @@ func Test_projectServiceServer_InviteGet(t *testing.T) { TenantName: "john.doe@github", Project: p0, ProjectName: "john.doe@github", - ExpiresAt: now, + ExpiresAt: inOneHour, JoinedAt: nil, }, }) @@ -1151,7 +1151,7 @@ func Test_projectServiceServer_InviteGet(t *testing.T) { Project: p0, ProjectName: "john.doe@github", Secret: "abcdefghijklmnopqrstuvwxyz123456", - ExpiresAt: now, + ExpiresAt: inOneHour, JoinedAt: nil, }, }, @@ -1211,7 +1211,7 @@ func Test_projectServiceServer_InvitesList(t *testing.T) { testStore, closer := test.StartRepositoryWithCleanup(t, log, test.WithPostgres(true)) defer closer() - now := timestamppb.Now() + inOneHour := timestamppb.New(time.Now().Add(time.Hour)) test.CreateProjectInvites(t, testStore, []*apiv2.ProjectInvite{ { @@ -1222,7 +1222,7 @@ func Test_projectServiceServer_InvitesList(t *testing.T) { TenantName: "john.doe@github", Project: p0, ProjectName: "john.doe@github", - ExpiresAt: now, + ExpiresAt: inOneHour, JoinedAt: nil, }, { @@ -1233,7 +1233,7 @@ func Test_projectServiceServer_InvitesList(t *testing.T) { TenantName: "john.doe@github", Project: p1, ProjectName: "project-1", - ExpiresAt: now, + ExpiresAt: inOneHour, JoinedAt: nil, }, }) @@ -1259,7 +1259,7 @@ func Test_projectServiceServer_InvitesList(t *testing.T) { TenantName: "john.doe@github", Project: p1, ProjectName: "project-1", - ExpiresAt: now, + ExpiresAt: inOneHour, JoinedAt: nil, }, }, @@ -1313,7 +1313,7 @@ func Test_projectServiceServer_InviteDelete(t *testing.T) { testStore, closer := test.StartRepositoryWithCleanup(t, log, test.WithPostgres(true)) defer closer() - now := timestamppb.Now() + inOneHour := timestamppb.New(time.Now().Add(time.Hour)) test.CreateProjectInvites(t, testStore, []*apiv2.ProjectInvite{ { @@ -1324,7 +1324,7 @@ func Test_projectServiceServer_InviteDelete(t *testing.T) { TenantName: "john.doe@github", Project: p1, ProjectName: "john.doe@github", - ExpiresAt: now, + ExpiresAt: inOneHour, JoinedAt: nil, }, }) diff --git a/pkg/token/token-store_test.go b/pkg/token/token-store_test.go index 3831bdcc..44c3ea56 100644 --- a/pkg/token/token-store_test.go +++ b/pkg/token/token-store_test.go @@ -75,7 +75,7 @@ func TestRedisStoreSetAndGet(t *testing.T) { require.NoError(t, err) store := NewRedisStore(c) - now := time.Now() + inOneHour := time.Now().Add(time.Hour) inTok := &apiv2.Token{ Uuid: "bd21fe60-047c-45aa-812d-adc44e098a38", @@ -87,8 +87,8 @@ func TestRedisStoreSetAndGet(t *testing.T) { Methods: []string{"b", "c"}, }, }, - Expires: timestamppb.New(now), - IssuedAt: timestamppb.New(now), + Expires: timestamppb.New(inOneHour), + IssuedAt: timestamppb.New(inOneHour), TokenType: apiv2.TokenType_TOKEN_TYPE_API, ProjectRoles: map[string]apiv2.ProjectRole{ "8aa3f4c1-52a8-4656-86bc-4006ec016af6": apiv2.ProjectRole_PROJECT_ROLE_OWNER, From 3aac7799d9c2273b93263f1340120a942624627c Mon Sep 17 00:00:00 2001 From: Stefan Majer Date: Thu, 14 May 2026 15:52:48 +0200 Subject: [PATCH 5/9] Fix test --- pkg/auth/jwt-token-cert-rotation_test.go | 194 +++++++++++------------ 1 file changed, 95 insertions(+), 99 deletions(-) diff --git a/pkg/auth/jwt-token-cert-rotation_test.go b/pkg/auth/jwt-token-cert-rotation_test.go index d3095b16..fdbef57a 100644 --- a/pkg/auth/jwt-token-cert-rotation_test.go +++ b/pkg/auth/jwt-token-cert-rotation_test.go @@ -5,7 +5,6 @@ import ( "fmt" "log/slog" "testing" - "testing/synctest" "time" "github.com/alicebob/miniredis/v2" @@ -34,10 +33,7 @@ func Test_jwt_cert_rotation(t *testing.T) { s := miniredis.RunT(t) c, err := valkey.NewClient(valkey.ClientOption{ - InitAddress: []string{s.Addr()}, - // This is required because otherwise we get: - // unknown subcommand 'TRACKING'. Try CLIENT HELP.: [CLIENT TRACKING ON OPTIN] - // ClientOption.DisableCache must be true for valkey not supporting client-side caching or not supporting RESP3 + InitAddress: []string{s.Addr()}, DisableCache: true, }) require.NoError(t, err) @@ -73,111 +69,111 @@ func Test_jwt_cert_rotation(t *testing.T) { return s }() - synctest.Test(t, func(t *testing.T) { - - ctx := t.Context() - - var ( - token1 = "" - token2 = "" - token3 = "" - previousAt *time.Duration - ) - steps := []struct { - name string - at time.Duration - task func(t *testing.T) - }{ - { - name: "token 1", - at: 0 * time.Second, - task: func(t *testing.T) { - token1 = createNewConsoleToken(t, ctx, service) - expectCertStore(t, ctx, certStore, 1) - expectTokenWorks(t, ctx, auth, token1) - }, + // synctest.Test(t, func(t *testing.T) { + + ctx := t.Context() + + var ( + token1 = "" + token2 = "" + token3 = "" + previousAt *time.Duration + ) + steps := []struct { + name string + at time.Duration + task func(t *testing.T) + }{ + { + name: "token 1", + at: 0 * time.Second, + task: func(t *testing.T) { + token1 = createNewConsoleToken(t, ctx, service) + expectCertStore(t, ctx, certStore, 1) + expectTokenWorks(t, ctx, auth, token1) }, - { - name: "token2", - at: 2 * time.Second, - task: func(t *testing.T) { - token2 = createNewConsoleToken(t, ctx, service) - expectCertStore(t, ctx, certStore, 1) - expectTokenWorks(t, ctx, auth, token1) - expectTokenWorks(t, ctx, auth, token2) - }, + }, + { + name: "token2", + at: 2 * time.Second, + task: func(t *testing.T) { + token2 = createNewConsoleToken(t, ctx, service) + expectCertStore(t, ctx, certStore, 1) + expectTokenWorks(t, ctx, auth, token1) + expectTokenWorks(t, ctx, auth, token2) }, - { - name: "token3, next signing cert gets created", - at: 4 * time.Second, - task: func(t *testing.T) { - token3 = createNewConsoleToken(t, ctx, service) - expectCertStore(t, ctx, certStore, 2) - expectTokenWorks(t, ctx, auth, token1) - expectTokenWorks(t, ctx, auth, token2) - expectTokenWorks(t, ctx, auth, token3) - }, + }, + { + name: "token3, next signing cert gets created", + at: 4 * time.Second, + task: func(t *testing.T) { + token3 = createNewConsoleToken(t, ctx, service) + expectCertStore(t, ctx, certStore, 2) + expectTokenWorks(t, ctx, auth, token1) + expectTokenWorks(t, ctx, auth, token2) + expectTokenWorks(t, ctx, auth, token3) }, - { - name: "token1 expired, token 2 and 3 still work", - at: 6 * time.Second, - task: func(t *testing.T) { - token3 = createNewConsoleToken(t, ctx, service) - expectCertStore(t, ctx, certStore, 2) - expectTokenExpired(t, ctx, auth, token1) - expectTokenWorks(t, ctx, auth, token2) - expectTokenWorks(t, ctx, auth, token3) - }, + }, + { + name: "token1 expired, token 2 and 3 still work", + at: 6 * time.Second, + task: func(t *testing.T) { + token3 = createNewConsoleToken(t, ctx, service) + expectCertStore(t, ctx, certStore, 2) + expectTokenExpired(t, ctx, auth, token1) + expectTokenWorks(t, ctx, auth, token2) + expectTokenWorks(t, ctx, auth, token3) }, - { - name: "token1 and token2 expired, token 3 still works", - at: 8 * time.Second, - task: func(t *testing.T) { - expectCertStore(t, ctx, certStore, 2) - expectTokenExpired(t, ctx, auth, token1) - expectTokenExpired(t, ctx, auth, token2) - expectTokenWorks(t, ctx, auth, token3) - }, + }, + { + name: "token1 and token2 expired, token 3 still works", + at: 8 * time.Second, + task: func(t *testing.T) { + expectCertStore(t, ctx, certStore, 2) + expectTokenExpired(t, ctx, auth, token1) + expectTokenExpired(t, ctx, auth, token2) + expectTokenWorks(t, ctx, auth, token3) }, - { - name: "all tokens expired, first signing cert is gone", - at: 11 * time.Second, - task: func(t *testing.T) { - expectCertStore(t, ctx, certStore, 1) - expectTokenNoPublicKeyForSignatureFound(t, ctx, auth, token1) - expectTokenNoPublicKeyForSignatureFound(t, ctx, auth, token2) - expectTokenExpired(t, ctx, auth, token3) - }, + }, + { + name: "all tokens expired, first signing cert is gone", + at: 11 * time.Second, + task: func(t *testing.T) { + expectCertStore(t, ctx, certStore, 1) + expectTokenNoPublicKeyForSignatureFound(t, ctx, auth, token1) + expectTokenNoPublicKeyForSignatureFound(t, ctx, auth, token2) + expectTokenExpired(t, ctx, auth, token3) }, - { - name: "all tokens expired, all signing certs gone", - at: 15 * time.Second, - task: func(t *testing.T) { - expectCertStore(t, ctx, certStore, 0) - expectTokenNoPublicKeyForSignatureFound(t, ctx, auth, token1) - expectTokenNoPublicKeyForSignatureFound(t, ctx, auth, token2) - expectTokenNoPublicKeyForSignatureFound(t, ctx, auth, token3) - }, + }, + { + name: "all tokens expired, all signing certs gone", + at: 15 * time.Second, + task: func(t *testing.T) { + expectCertStore(t, ctx, certStore, 0) + expectTokenNoPublicKeyForSignatureFound(t, ctx, auth, token1) + expectTokenNoPublicKeyForSignatureFound(t, ctx, auth, token2) + expectTokenNoPublicKeyForSignatureFound(t, ctx, auth, token3) }, - } + }, + } - time.Sleep(1 * time.Second) + time.Sleep(1 * time.Second) - for _, step := range steps { - forwardText := "" - if previousAt != nil { - forward := step.at - *previousAt - forwardText = fmt.Sprintf(" (forwarding by %s)", forward) - time.Sleep(forward) - s.FastForward(forward) - } - previousAt = &step.at + for _, step := range steps { + forwardText := "" + if previousAt != nil { + forward := step.at - *previousAt + forwardText = fmt.Sprintf(" (forwarding by %s)", forward) + time.Sleep(forward) + s.FastForward(forward) + } + previousAt = &step.at - t.Logf("%s: running step at %q%s: %q", time.Now(), step.at, forwardText, step.name) + t.Logf("%s: running step at %q%s: %q", time.Now(), step.at, forwardText, step.name) - step.task(t) - } - }) + step.task(t) + } + // }) } func createNewConsoleToken(t *testing.T, ctx context.Context, service tokenservice.TokenService) string { From f055c12c7090d0f4643ea6857f7870f37590b537 Mon Sep 17 00:00:00 2001 From: Stefan Majer Date: Fri, 15 May 2026 08:10:30 +0200 Subject: [PATCH 6/9] Reuse test helper --- pkg/auth/authenticator-interceptor_test.go | 35 +++++---------------- pkg/certs/certs-store_test.go | 15 ++------- pkg/invite/invite-store_test.go | 10 ++---- pkg/rate-limiter/rate-limiter_test.go | 16 +++------- pkg/repository/machine.go | 2 +- pkg/service/api/token/token-service_test.go | 25 +++------------ pkg/test/valkey.go | 5 ++- pkg/token/token-store_test.go | 10 ++---- 8 files changed, 29 insertions(+), 89 deletions(-) diff --git a/pkg/auth/authenticator-interceptor_test.go b/pkg/auth/authenticator-interceptor_test.go index 057b73de..d5ac5573 100644 --- a/pkg/auth/authenticator-interceptor_test.go +++ b/pkg/auth/authenticator-interceptor_test.go @@ -10,7 +10,6 @@ import ( "testing" "time" - "github.com/alicebob/miniredis/v2" "github.com/golang-jwt/jwt/v5" "github.com/google/go-cmp/cmp" "github.com/google/uuid" @@ -18,33 +17,26 @@ import ( "github.com/metal-stack/metal-apiserver/pkg/certs" "github.com/metal-stack/metal-apiserver/pkg/errorutil" "github.com/metal-stack/metal-apiserver/pkg/repository/api" + "github.com/metal-stack/metal-apiserver/pkg/test" "github.com/metal-stack/metal-apiserver/pkg/token" "github.com/stretchr/testify/require" "github.com/valkey-io/valkey-go" ) -func prepare(t *testing.T) (certs.CertStore, *ecdsa.PrivateKey) { - s := miniredis.RunT(t) - c, err := valkey.NewClient(valkey.ClientOption{ - InitAddress: []string{s.Addr()}, - // This is required because otherwise we get: - // unknown subcommand 'TRACKING'. Try CLIENT HELP.: [CLIENT TRACKING ON OPTIN] - // ClientOption.DisableCache must be true for valkey not supporting client-side caching or not supporting RESP3 - DisableCache: true, - }) - require.NoError(t, err) +func prepare(t *testing.T) (valkey.Client, certs.CertStore, *ecdsa.PrivateKey) { + _, c, _ := test.StartValkey(t, test.WithMiniRedis(true)) // creating an initial signing certificate store := certs.NewRedisStore(&certs.Config{ ValkeyClient: c, }) - _, err = store.LatestPrivate(t.Context()) + _, err := store.LatestPrivate(t.Context()) require.NoError(t, err) key, err := store.LatestPrivate(t.Context()) require.NoError(t, err) - return store, key + return c, store, key } func Test_authorize_with_permissions(t *testing.T) { @@ -52,9 +44,11 @@ func Test_authorize_with_permissions(t *testing.T) { require.NoError(t, err) var ( expired = -time.Hour - certStore, key = prepare(t) + c, certStore, key = prepare(t) defaultIssuer = "https://api-server" maliciousSigningKey = pk + tokenStore = token.NewRedisStore(c) + ctx = t.Context() ) tests := []struct { @@ -145,19 +139,6 @@ func Test_authorize_with_permissions(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - s := miniredis.RunT(t) - defer s.Close() - - ctx := t.Context() - c, err := valkey.NewClient(valkey.ClientOption{ - InitAddress: []string{s.Addr()}, - // This is required because otherwise we get: - // unknown subcommand 'TRACKING'. Try CLIENT HELP.: [CLIENT TRACKING ON OPTIN] - // ClientOption.DisableCache must be true for valkey not supporting client-side caching or not supporting RESP3 - DisableCache: true, - }) - require.NoError(t, err) - tokenStore := token.NewRedisStore(c) exp := time.Hour if tt.expiration != nil { diff --git a/pkg/certs/certs-store_test.go b/pkg/certs/certs-store_test.go index 6845361d..3aa68780 100644 --- a/pkg/certs/certs-store_test.go +++ b/pkg/certs/certs-store_test.go @@ -3,29 +3,20 @@ package certs_test import ( "testing" - "github.com/alicebob/miniredis/v2" "github.com/lestrrat-go/jwx/v3/jwk" "github.com/metal-stack/metal-apiserver/pkg/certs" + "github.com/metal-stack/metal-apiserver/pkg/test" "github.com/metal-stack/metal-apiserver/pkg/token" "github.com/stretchr/testify/require" - "github.com/valkey-io/valkey-go" ) func Test_certStore(t *testing.T) { t.Parallel() var ( ctx = t.Context() - s = miniredis.RunT(t) ) - - c, err := valkey.NewClient(valkey.ClientOption{ - InitAddress: []string{s.Addr()}, - // This is required because otherwise we get: - // unknown subcommand 'TRACKING'. Try CLIENT HELP.: [CLIENT TRACKING ON OPTIN] - // ClientOption.DisableCache must be true for valkey not supporting client-side caching or not supporting RESP3 - DisableCache: true, - }) - require.NoError(t, err) + _, c, closer := test.StartValkey(t, test.WithMiniRedis(true)) + defer closer() store := certs.NewRedisStore(&certs.Config{ RenewCertBeforeExpiration: new(4 * token.MaxExpiration), diff --git a/pkg/invite/invite-store_test.go b/pkg/invite/invite-store_test.go index 19f55c33..214000b9 100644 --- a/pkg/invite/invite-store_test.go +++ b/pkg/invite/invite-store_test.go @@ -57,10 +57,7 @@ func Test_ProjectInvite(t *testing.T) { inOneHour := timestamppb.New(time.Now().Add(time.Hour)) mr := miniredis.RunT(t) c, err := valkey.NewClient(valkey.ClientOption{ - InitAddress: []string{mr.Addr()}, - // This is required because otherwise we get: - // unknown subcommand 'TRACKING'. Try CLIENT HELP.: [CLIENT TRACKING ON OPTIN] - // ClientOption.DisableCache must be true for valkey not supporting client-side caching or not supporting RESP3 + InitAddress: []string{mr.Addr()}, DisableCache: true, }) require.NoError(t, err) @@ -109,10 +106,7 @@ func Test_TenantInvite(t *testing.T) { inOneHour := timestamppb.New(time.Now().Add(time.Hour)) mr := miniredis.RunT(t) c, err := valkey.NewClient(valkey.ClientOption{ - InitAddress: []string{mr.Addr()}, - // This is required because otherwise we get: - // unknown subcommand 'TRACKING'. Try CLIENT HELP.: [CLIENT TRACKING ON OPTIN] - // ClientOption.DisableCache must be true for valkey not supporting client-side caching or not supporting RESP3 + InitAddress: []string{mr.Addr()}, DisableCache: true, }) require.NoError(t, err) diff --git a/pkg/rate-limiter/rate-limiter_test.go b/pkg/rate-limiter/rate-limiter_test.go index 4d065078..4ea42738 100644 --- a/pkg/rate-limiter/rate-limiter_test.go +++ b/pkg/rate-limiter/rate-limiter_test.go @@ -5,27 +5,19 @@ import ( "time" "github.com/metal-stack/metal-apiserver/pkg/certs" + "github.com/metal-stack/metal-apiserver/pkg/test" "github.com/metal-stack/metal-apiserver/pkg/token" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/valkey-io/valkey-go" - - "github.com/alicebob/miniredis/v2" apiv2 "github.com/metal-stack/api/go/metalstack/api/v2" ) func Test_ratelimiter_CheckLimitTokenAccess(t *testing.T) { ctx := t.Context() - s := miniredis.RunT(t) - c, err := valkey.NewClient(valkey.ClientOption{ - InitAddress: []string{s.Addr()}, - // This is required because otherwise we get: - // unknown subcommand 'TRACKING'. Try CLIENT HELP.: [CLIENT TRACKING ON OPTIN] - // ClientOption.DisableCache must be true for valkey not supporting client-side caching or not supporting RESP3 - DisableCache: true, - }) - require.NoError(t, err) + + _, c, closer := test.StartValkey(t, test.WithMiniRedis(true)) + defer closer() limiter := ratelimiter{ client: c, diff --git a/pkg/repository/machine.go b/pkg/repository/machine.go index a71fa044..faa5fe29 100644 --- a/pkg/repository/machine.go +++ b/pkg/repository/machine.go @@ -376,7 +376,7 @@ func (r *machineRepository) convertToProto(ctx context.Context, m *metal.Machine for _, gpu := range m.Hardware.MetalGPUs { gpus = append(gpus, &apiv2.MetalGPU{ - Vendor: gpu.Model, + Vendor: gpu.Vendor, Model: gpu.Model, }) } diff --git a/pkg/service/api/token/token-service_test.go b/pkg/service/api/token/token-service_test.go index 8bc3fe5c..f3081e0e 100644 --- a/pkg/service/api/token/token-service_test.go +++ b/pkg/service/api/token/token-service_test.go @@ -33,10 +33,7 @@ func Test_tokenService_CreateConsoleTokenWithoutPermissionCheck(t *testing.T) { ctx := t.Context() s := miniredis.RunT(t) c, err := valkey.NewClient(valkey.ClientOption{ - InitAddress: []string{s.Addr()}, - // This is required because otherwise we get: - // unknown subcommand 'TRACKING'. Try CLIENT HELP.: [CLIENT TRACKING ON OPTIN] - // ClientOption.DisableCache must be true for valkey not supporting client-side caching or not supporting RESP3 + InitAddress: []string{s.Addr()}, DisableCache: true, }) require.NoError(t, err) @@ -480,10 +477,7 @@ func Test_Create(t *testing.T) { s := miniredis.RunT(t) c, err := valkey.NewClient(valkey.ClientOption{ - InitAddress: []string{s.Addr()}, - // This is required because otherwise we get: - // unknown subcommand 'TRACKING'. Try CLIENT HELP.: [CLIENT TRACKING ON OPTIN] - // ClientOption.DisableCache must be true for valkey not supporting client-side caching or not supporting RESP3 + InitAddress: []string{s.Addr()}, DisableCache: true, }) require.NoError(t, err) @@ -613,10 +607,7 @@ func Test_CreateForUser(t *testing.T) { s := miniredis.RunT(t) c, err := valkey.NewClient(valkey.ClientOption{ - InitAddress: []string{s.Addr()}, - // This is required because otherwise we get: - // unknown subcommand 'TRACKING'. Try CLIENT HELP.: [CLIENT TRACKING ON OPTIN] - // ClientOption.DisableCache must be true for valkey not supporting client-side caching or not supporting RESP3 + InitAddress: []string{s.Addr()}, DisableCache: true, }) require.NoError(t, err) @@ -1617,10 +1608,7 @@ func Test_Update(t *testing.T) { s := miniredis.RunT(t) c, err := valkey.NewClient(valkey.ClientOption{ - InitAddress: []string{s.Addr()}, - // This is required because otherwise we get: - // unknown subcommand 'TRACKING'. Try CLIENT HELP.: [CLIENT TRACKING ON OPTIN] - // ClientOption.DisableCache must be true for valkey not supporting client-side caching or not supporting RESP3 + InitAddress: []string{s.Addr()}, DisableCache: true, }) require.NoError(t, err) @@ -1765,10 +1753,7 @@ func Test_Refresh(t *testing.T) { s := miniredis.RunT(t) c, err := valkey.NewClient(valkey.ClientOption{ - InitAddress: []string{s.Addr()}, - // This is required because otherwise we get: - // unknown subcommand 'TRACKING'. Try CLIENT HELP.: [CLIENT TRACKING ON OPTIN] - // ClientOption.DisableCache must be true for valkey not supporting client-side caching or not supporting RESP3 + InitAddress: []string{s.Addr()}, DisableCache: true, }) require.NoError(t, err) diff --git a/pkg/test/valkey.go b/pkg/test/valkey.go index 273ec8bb..fbdd7494 100644 --- a/pkg/test/valkey.go +++ b/pkg/test/valkey.go @@ -12,6 +12,7 @@ import ( "github.com/testcontainers/testcontainers-go" "github.com/testcontainers/testcontainers-go/modules/valkey" ) + type testOptMiniRedis struct { with bool } @@ -48,7 +49,9 @@ func StartValkey(t testing.TB, testOpts ...testOpt) (*redis.Client, valkeygo.Cli DisableCache: true, }) require.NoError(t, err) - return rc, vc, nil + return rc, vc, func() { + mr.Close() + } } valkeyContainer, err := valkey.Run(ctx, diff --git a/pkg/token/token-store_test.go b/pkg/token/token-store_test.go index 44c3ea56..fee52c5b 100644 --- a/pkg/token/token-store_test.go +++ b/pkg/token/token-store_test.go @@ -18,10 +18,7 @@ func TestRedisStore(t *testing.T) { ctx := t.Context() s := miniredis.RunT(t) c, err := valkey.NewClient(valkey.ClientOption{ - InitAddress: []string{s.Addr()}, - // This is required because otherwise we get: - // unknown subcommand 'TRACKING'. Try CLIENT HELP.: [CLIENT TRACKING ON OPTIN] - // ClientOption.DisableCache must be true for valkey not supporting client-side caching or not supporting RESP3 + InitAddress: []string{s.Addr()}, DisableCache: true, }) require.NoError(t, err) @@ -66,10 +63,7 @@ func TestRedisStoreSetAndGet(t *testing.T) { ctx := t.Context() s := miniredis.RunT(t) c, err := valkey.NewClient(valkey.ClientOption{ - InitAddress: []string{s.Addr()}, - // This is required because otherwise we get: - // unknown subcommand 'TRACKING'. Try CLIENT HELP.: [CLIENT TRACKING ON OPTIN] - // ClientOption.DisableCache must be true for valkey not supporting client-side caching or not supporting RESP3 + InitAddress: []string{s.Addr()}, DisableCache: true, }) require.NoError(t, err) From a4323697e36796c611d3f3a32cdd6985d4b854bb Mon Sep 17 00:00:00 2001 From: Stefan Majer Date: Fri, 15 May 2026 08:19:03 +0200 Subject: [PATCH 7/9] reduce byte slice casting --- pkg/invite/invite-store.go | 4 ++-- pkg/token/token-store.go | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/pkg/invite/invite-store.go b/pkg/invite/invite-store.go index cbba71b3..88a93985 100644 --- a/pkg/invite/invite-store.go +++ b/pkg/invite/invite-store.go @@ -125,13 +125,13 @@ func get[E any](ctx context.Context, c valkey.Client, secret string) (E, error) return zero, err } - encoded, err := c.Do(ctx, c.B().Get().Key(secretkey(secret)).Build()).ToString() + encoded, err := c.Do(ctx, c.B().Get().Key(secretkey(secret)).Build()).AsBytes() if err != nil { return zero, fmt.Errorf("unable to get secret as bytes:%w", err) } var e E - err = json.Unmarshal([]byte(encoded), &e) + err = json.Unmarshal(encoded, &e) if err != nil { return zero, fmt.Errorf("unable to unmarshal secret from bytes:%w", err) } diff --git a/pkg/token/token-store.go b/pkg/token/token-store.go index f3dece77..68e1c962 100644 --- a/pkg/token/token-store.go +++ b/pkg/token/token-store.go @@ -68,13 +68,13 @@ func (r *redisStore) Set(ctx context.Context, token *apiv2.Token) error { } func (r *redisStore) Get(ctx context.Context, userid, tokenid string) (*apiv2.Token, error) { - encoded, err := r.client.Do(ctx, r.client.B().Get().Key(key(userid, tokenid)).Build()).ToString() + encoded, err := r.client.Do(ctx, r.client.B().Get().Key(key(userid, tokenid)).Build()).AsBytes() if err != nil { return nil, err } var t token - err = json.Unmarshal([]byte(encoded), &t) + err = json.Unmarshal(encoded, &t) if err != nil { return nil, err } @@ -98,7 +98,7 @@ func (r *redisStore) List(ctx context.Context, userid string) ([]*apiv2.Token, e } var t token - err = json.Unmarshal([]byte(encoded), &t) + err = json.Unmarshal(encoded, &t) if err != nil { return nil, fmt.Errorf("unable to decode scan result:%q error:%w", encoded, err) } @@ -123,7 +123,7 @@ func (r *redisStore) AdminList(ctx context.Context) ([]*apiv2.Token, error) { } var t token - err = json.Unmarshal([]byte(encoded), &t) + err = json.Unmarshal(encoded, &t) if err != nil { return nil, fmt.Errorf("unable to decode scan result:%q error:%w", encoded, err) } From 3465503c0e8f208b5212f67822464ccb4653ad62 Mon Sep 17 00:00:00 2001 From: Stefan Majer Date: Fri, 15 May 2026 08:27:02 +0200 Subject: [PATCH 8/9] Add token benchmark --- pkg/token/token-store_benchmark_test.go | 64 +++++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 pkg/token/token-store_benchmark_test.go diff --git a/pkg/token/token-store_benchmark_test.go b/pkg/token/token-store_benchmark_test.go new file mode 100644 index 00000000..22a5b53a --- /dev/null +++ b/pkg/token/token-store_benchmark_test.go @@ -0,0 +1,64 @@ +package token_test + +import ( + "testing" + "time" + + "github.com/alicebob/miniredis/v2" + apiv2 "github.com/metal-stack/api/go/metalstack/api/v2" + "github.com/metal-stack/metal-apiserver/pkg/token" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/valkey-io/valkey-go" + "google.golang.org/protobuf/types/known/timestamppb" +) + +func BenchmarkTokenSetAndGet(b *testing.B) { + ctx := b.Context() + s := miniredis.RunT(b) + c, err := valkey.NewClient(valkey.ClientOption{ + InitAddress: []string{s.Addr()}, + DisableCache: true, + }) + require.NoError(b, err) + store := token.NewRedisStore(c) + + inOneHour := time.Now().Add(time.Hour) + + inTok := &apiv2.Token{ + Uuid: "bd21fe60-047c-45aa-812d-adc44e098a38", + User: "john@doe.com", + Description: "abc", + Permissions: []*apiv2.MethodPermission{ + { + Subject: "a", + Methods: []string{"b", "c"}, + }, + }, + Expires: timestamppb.New(inOneHour), + IssuedAt: timestamppb.New(inOneHour), + TokenType: apiv2.TokenType_TOKEN_TYPE_API, + ProjectRoles: map[string]apiv2.ProjectRole{ + "8aa3f4c1-52a8-4656-86bc-4006ec016af6": apiv2.ProjectRole_PROJECT_ROLE_OWNER, + }, + TenantRoles: map[string]apiv2.TenantRole{ + "foo@github": apiv2.TenantRole_TENANT_ROLE_OWNER, + "bar@github": apiv2.TenantRole_TENANT_ROLE_EDITOR, + "42@github": apiv2.TenantRole_TENANT_ROLE_VIEWER, + }, + AdminRole: new(apiv2.AdminRole_ADMIN_ROLE_VIEWER), + InfraRole: new(apiv2.InfraRole_INFRA_ROLE_EDITOR), + MachineRoles: map[string]apiv2.MachineRole{}, + } + + for b.Loop() { + err := store.Set(ctx, inTok) + require.NoError(b, err) + + outTok, err := store.Get(ctx, inTok.User, inTok.Uuid) + require.NoError(b, err) + require.NotNil(b, outTok) + + assert.Equal(b, inTok, outTok) + } +} From 0ef1712dcc64f986b26aad76d6949e8536ab4c80 Mon Sep 17 00:00:00 2001 From: Stefan Majer Date: Fri, 15 May 2026 09:24:02 +0200 Subject: [PATCH 9/9] Try to stabilize test --- go.mod | 53 ++++++------ go.sum | 104 +++++++++++------------ pkg/auth/jwt-token-cert-rotation_test.go | 2 +- 3 files changed, 80 insertions(+), 79 deletions(-) diff --git a/go.mod b/go.mod index 0943da52..a96ffc82 100644 --- a/go.mod +++ b/go.mod @@ -47,7 +47,7 @@ require ( golang.org/x/crypto v0.51.0 golang.org/x/oauth2 v0.36.0 golang.org/x/sync v0.20.0 - google.golang.org/grpc v1.81.0 + google.golang.org/grpc v1.81.1 google.golang.org/protobuf v1.36.11 gopkg.in/rethinkdb/rethinkdb-go.v6 v6.2.2 tailscale.com v1.96.5 @@ -57,7 +57,7 @@ replace github.com/markbates/goth => github.com/metal-stack/goth v0.1.0 require ( buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.11-20260415201107-50325440f8f2.1 // indirect - cel.dev/expr v0.25.1 // indirect + cel.dev/expr v0.25.2 // indirect dario.cat/mergo v1.0.2 // indirect filippo.io/edwards25519 v1.2.0 // indirect github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect @@ -66,20 +66,20 @@ require ( github.com/akutz/memconn v0.1.0 // indirect github.com/alexbrainman/sspi v0.0.0-20250919150558-7d374ff0d59e // indirect github.com/antlr4-go/antlr/v4 v4.13.1 // indirect - github.com/aws/aws-sdk-go-v2 v1.41.6 // indirect - github.com/aws/aws-sdk-go-v2/config v1.32.16 // indirect - github.com/aws/aws-sdk-go-v2/credentials v1.19.15 // indirect - github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.22 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.22 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.22 // indirect - github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.23 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.8 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.22 // indirect - github.com/aws/aws-sdk-go-v2/service/signin v1.0.10 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.30.16 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.20 // indirect - github.com/aws/aws-sdk-go-v2/service/sts v1.42.0 // indirect - github.com/aws/smithy-go v1.25.0 // indirect + github.com/aws/aws-sdk-go-v2 v1.41.7 // indirect + github.com/aws/aws-sdk-go-v2/config v1.32.17 // indirect + github.com/aws/aws-sdk-go-v2/credentials v1.19.16 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.23 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.23 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.23 // indirect + github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.24 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.9 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.23 // indirect + github.com/aws/aws-sdk-go-v2/service/signin v1.0.11 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.30.17 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.21 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.42.1 // indirect + github.com/aws/smithy-go v1.25.1 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect @@ -126,7 +126,7 @@ require ( github.com/golang/protobuf v1.5.4 // indirect github.com/golang/snappy v1.0.0 // indirect github.com/google/btree v1.1.3 // indirect - github.com/google/cel-go v0.28.0 // indirect + github.com/google/cel-go v0.28.1 // indirect github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.3 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0 // indirect github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed // indirect @@ -137,7 +137,7 @@ require ( github.com/jackc/pgx/v4 v4.18.3 // indirect github.com/jsimonetti/rtnetlink v1.4.2 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/klauspost/compress v1.18.5 // indirect + github.com/klauspost/compress v1.18.6 // indirect github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect github.com/lestrrat-go/blackmagic v1.0.4 // indirect @@ -152,7 +152,7 @@ require ( github.com/mdlayher/netlink v1.11.1 // indirect github.com/mdlayher/socket v0.6.0 // indirect github.com/metal-stack/security v0.9.6 // indirect - github.com/minio/minlz v1.1.0 // indirect + github.com/minio/minlz v1.1.1 // indirect github.com/mitchellh/go-ps v1.0.0 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect github.com/moby/go-archive v0.2.0 // indirect @@ -183,7 +183,7 @@ require ( github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/safchain/ethtool v0.7.0 // indirect github.com/segmentio/asm v1.2.1 // indirect - github.com/shirou/gopsutil/v4 v4.26.3 // indirect + github.com/shirou/gopsutil/v4 v4.26.4 // indirect github.com/sirupsen/logrus v1.9.4 // indirect github.com/spf13/cast v1.10.0 // indirect github.com/tailscale/certstore v0.1.1-0.20231202035212-d3fa0460f47e // indirect @@ -203,9 +203,9 @@ require ( github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect github.com/yuin/gopher-lua v1.1.2 // indirect github.com/yusufpapurcu/wmi v1.2.4 // indirect - go.etcd.io/etcd/api/v3 v3.6.10 // indirect - go.etcd.io/etcd/client/pkg/v3 v3.6.10 // indirect - go.etcd.io/etcd/client/v3 v3.6.10 // indirect + go.etcd.io/etcd/api/v3 v3.6.11 // indirect + go.etcd.io/etcd/client/pkg/v3 v3.6.11 // indirect + go.etcd.io/etcd/client/v3 v3.6.11 // indirect go.mongodb.org/mongo-driver v1.17.9 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.68.0 // indirect @@ -215,8 +215,9 @@ require ( go.opentelemetry.io/otel/trace v1.43.0 // indirect go.uber.org/atomic v1.11.0 // indirect go.uber.org/multierr v1.11.0 // indirect - go.uber.org/zap v1.27.1 // indirect + go.uber.org/zap v1.28.0 // indirect go.yaml.in/yaml/v2 v2.4.4 // indirect + go.yaml.in/yaml/v3 v3.0.4 // indirect go4.org/mem v0.0.0-20240501181205-ae6ca9944745 // indirect golang.org/x/exp v0.0.0-20260508232706-74f9aab9d74a // indirect golang.org/x/net v0.54.0 // indirect @@ -226,8 +227,8 @@ require ( golang.org/x/time v0.15.0 // indirect golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect golang.zx2c4.com/wireguard/windows v1.0.1 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20260420184626-e10c466a9529 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20260420184626-e10c466a9529 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20260511170946-3700d4141b60 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20260511170946-3700d4141b60 // indirect gopkg.in/cenkalti/backoff.v2 v2.2.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect gvisor.dev/gvisor v0.0.0-20260224225140-573d5e7127a8 // indirect diff --git a/go.sum b/go.sum index becd6c6f..0886a42f 100644 --- a/go.sum +++ b/go.sum @@ -4,8 +4,8 @@ buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.11-202604152011 buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.11-20260415201107-50325440f8f2.1/go.mod h1:tvtbpgaVXZX4g6Pn+AnzFycuRK3MOz5HJfEGeEllXYM= buf.build/go/protovalidate v1.2.0 h1:DQVrUWkmGTBij+kOYv/x2LLxwcLaGKMdzShj1/6/3H0= buf.build/go/protovalidate v1.2.0/go.mod h1:7rYiQEhqvAipoazpVNBBH2S2f8bjG4huMVy1V2Yofn4= -cel.dev/expr v0.25.1 h1:1KrZg61W6TWSxuNZ37Xy49ps13NUovb66QLprthtwi4= -cel.dev/expr v0.25.1/go.mod h1:hrXvqGP6G6gyx8UAHSHJ5RGk//1Oj5nXQ2NI02Nrsg4= +cel.dev/expr v0.25.2 h1:K6j46C81hXtZQfuX60cVWQFBJahKSE2gfRbNuvr5bFs= +cel.dev/expr v0.25.2/go.mod h1:hrXvqGP6G6gyx8UAHSHJ5RGk//1Oj5nXQ2NI02Nrsg4= connectrpc.com/connect v1.19.2 h1:McQ83FGdzL+t60peksi0gXC7MQ/iLKgLduAnThbM0mo= connectrpc.com/connect v1.19.2/go.mod h1:tN20fjdGlewnSFeZxLKb0xwIZ6ozc3OQs2hTXy4du9w= connectrpc.com/grpchealth v1.4.0 h1:MJC96JLelARPgZTiRF9KRfY/2N9OcoQvF2EWX07v2IE= @@ -49,36 +49,36 @@ github.com/antlr4-go/antlr/v4 v4.13.1 h1:SqQKkuVZ+zWkMMNkjy5FZe5mr5WURWnlpmOuzYW github.com/antlr4-go/antlr/v4 v4.13.1/go.mod h1:GKmUxMtwp6ZgGwZSva4eWPC5mS6vUAmOABFgjdkM7Nw= github.com/avast/retry-go/v4 v4.7.0 h1:yjDs35SlGvKwRNSykujfjdMxMhMQQM0TnIjJaHB+Zio= github.com/avast/retry-go/v4 v4.7.0/go.mod h1:ZMPDa3sY2bKgpLtap9JRUgk2yTAba7cgiFhqxY2Sg6Q= -github.com/aws/aws-sdk-go-v2 v1.41.6 h1:1AX0AthnBQzMx1vbmir3Y4WsnJgiydmnJjiLu+LvXOg= -github.com/aws/aws-sdk-go-v2 v1.41.6/go.mod h1:dy0UzBIfwSeot4grGvY1AqFWN5zgziMmWGzysDnHFcQ= -github.com/aws/aws-sdk-go-v2/config v1.32.16 h1:Q0iQ7quUgJP0F/SCRTieScnaMdXr9h/2+wze1u3cNeM= -github.com/aws/aws-sdk-go-v2/config v1.32.16/go.mod h1:duCCnJEFqpt2RC6no1iK6q+8HpwOAkiUua0pY507dQc= -github.com/aws/aws-sdk-go-v2/credentials v1.19.15 h1:fyvgWTszojq8hEnMi8PPBTvZdTtEVmAVyo+NFLHBhH4= -github.com/aws/aws-sdk-go-v2/credentials v1.19.15/go.mod h1:gJiYyMOjNg8OEdRWOf3CrFQxM2a98qmrtjx1zuiQfB8= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.22 h1:IOGsJ1xVWhsi+ZO7/NW8OuZZBtMJLZbk4P5HDjJO0jQ= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.22/go.mod h1:b+hYdbU+jGKfXE8kKM6g1+h+L/Go3vMvzlxBsiuGsxg= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.22 h1:GmLa5Kw1ESqtFpXsx5MmC84QWa/ZrLZvlJGa2y+4kcQ= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.22/go.mod h1:6sW9iWm9DK9YRpRGga/qzrzNLgKpT2cIxb7Vo2eNOp0= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.22 h1:dY4kWZiSaXIzxnKlj17nHnBcXXBfac6UlsAx2qL6XrU= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.22/go.mod h1:KIpEUx0JuRZLO7U6cbV204cWAEco2iC3l061IxlwLtI= -github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.23 h1:FPXsW9+gMuIeKmz7j6ENWcWtBGTe1kH8r9thNt5Uxx4= -github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.23/go.mod h1:7J8iGMdRKk6lw2C+cMIphgAnT8uTwBwNOsGkyOCm80U= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.8 h1:HtOTYcbVcGABLOVuPYaIihj6IlkqubBwFj10K5fxRek= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.8/go.mod h1:VsK9abqQeGlzPgUr+isNWzPlK2vKe9INMLWnY65f5Xs= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.22 h1:PUmZeJU6Y1Lbvt9WFuJ0ugUK2xn6hIWUBBbKuOWF30s= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.22/go.mod h1:nO6egFBoAaoXze24a2C0NjQCvdpk8OueRoYimvEB9jo= -github.com/aws/aws-sdk-go-v2/service/signin v1.0.10 h1:a1Fq/KXn75wSzoJaPQTgZO0wHGqE9mjFnylnqEPTchA= -github.com/aws/aws-sdk-go-v2/service/signin v1.0.10/go.mod h1:p6+MXNxW7IA6dMgHfTAzljuwSKD0NCm/4lbS4t6+7vI= +github.com/aws/aws-sdk-go-v2 v1.41.7 h1:DWpAJt66FmnnaRIOT/8ASTucrvuDPZASqhhLey6tLY8= +github.com/aws/aws-sdk-go-v2 v1.41.7/go.mod h1:4LAfZOPHNVNQEckOACQx60Y8pSRjIkNZQz1w92xpMJc= +github.com/aws/aws-sdk-go-v2/config v1.32.17 h1:FpL4/758/diKwqbytU0prpuiu60fgXKUWCpDJtApclU= +github.com/aws/aws-sdk-go-v2/config v1.32.17/go.mod h1:OXqUMzgXytfoF9JaKkhrOYsyh72t9G+MJH8mMRaexOE= +github.com/aws/aws-sdk-go-v2/credentials v1.19.16 h1:r3RJBuU7X9ibt8RHbMjWE6y60QbKBiII6wSrXnapxSU= +github.com/aws/aws-sdk-go-v2/credentials v1.19.16/go.mod h1:6cx7zqDENJDbBIIWX6P8s0h6hqHC8Avbjh9Dseo27ug= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.23 h1:UuSfcORqNSz/ey3VPRS8TcVH2Ikf0/sC+Hdj400QI6U= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.23/go.mod h1:+G/OSGiOFnSOkYloKj/9M35s74LgVAdJBSD5lsFfqKg= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.23 h1:GpT/TrnBYuE5gan2cZbTtvP+JlHsutdmlV2YfEyNde0= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.23/go.mod h1:xYWD6BS9ywC5bS3sz9Xh04whO/hzK2plt2Zkyrp4JuA= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.23 h1:bpd8vxhlQi2r1hiueOw02f/duEPTMK59Q4QMAoTTtTo= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.23/go.mod h1:15DfR2nw+CRHIk0tqNyifu3G1YdAOy68RftkhMDDwYk= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.24 h1:OQqn11BtaYv1WLUowvcA30MpzIu8Ti4pcLPIIyoKZrA= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.24/go.mod h1:X5ZJyfwVrWA96GzPmUCWFQaEARPR7gCrpq2E92PJwAE= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.9 h1:FLudkZLt5ci0ozzgkVo8BJGwvqNaZbTWb3UcucAateA= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.9/go.mod h1:w7wZ/s9qK7c8g4al+UyoF1Sp/Z45UwMGcqIzLWVQHWk= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.23 h1:pbrxO/kuIwgEsOPLkaHu0O+m4fNgLU8B3vxQ+72jTPw= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.23/go.mod h1:/CMNUqoj46HpS3MNRDEDIwcgEnrtZlKRaHNaHxIFpNA= +github.com/aws/aws-sdk-go-v2/service/signin v1.0.11 h1:TdJ+HdzOBhU8+iVAOGUTU63VXopcumCOF1paFulHWZc= +github.com/aws/aws-sdk-go-v2/service/signin v1.0.11/go.mod h1:R82ZRExE/nheo0N+T8zHPcLRTcH8MGsnR3BiVGX0TwI= github.com/aws/aws-sdk-go-v2/service/ssm v1.44.7 h1:a8HvP/+ew3tKwSXqL3BCSjiuicr+XTU2eFYeogV9GJE= github.com/aws/aws-sdk-go-v2/service/ssm v1.44.7/go.mod h1:Q7XIWsMo0JcMpI/6TGD6XXcXcV1DbTj6e9BKNntIMIM= -github.com/aws/aws-sdk-go-v2/service/sso v1.30.16 h1:x6bKbmDhsgSZwv6q19wY/u3rLk/3FGjJWyqKcIRufpE= -github.com/aws/aws-sdk-go-v2/service/sso v1.30.16/go.mod h1:CudnEVKRtLn0+3uMV0yEXZ+YZOKnAtUJ5DmDhilVnIw= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.20 h1:oK/njaL8GtyEihkWMD4k3VgHCT64RQKkZwh0DG5j8ak= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.20/go.mod h1:JHs8/y1f3zY7U5WcuzoJ/yAYGYtNIVPKLIbp61euvmg= -github.com/aws/aws-sdk-go-v2/service/sts v1.42.0 h1:ks8KBcZPh3PYISr5dAiXCM5/Thcuxk8l+PG4+A0exds= -github.com/aws/aws-sdk-go-v2/service/sts v1.42.0/go.mod h1:pFw33T0WLvXU3rw1WBkpMlkgIn54eCB5FYLhjDc9Foo= -github.com/aws/smithy-go v1.25.0 h1:Sz/XJ64rwuiKtB6j98nDIPyYrV1nVNJ4YU74gttcl5U= -github.com/aws/smithy-go v1.25.0/go.mod h1:YE2RhdIuDbA5E5bTdciG9KrW3+TiEONeUWCqxX9i1Fc= +github.com/aws/aws-sdk-go-v2/service/sso v1.30.17 h1:7byT8HUWrgoRp6sXjxtZwgOKfhss5fW6SkLBtqzgRoE= +github.com/aws/aws-sdk-go-v2/service/sso v1.30.17/go.mod h1:xNWknVi4Ezm1vg1QsB/5EWpAJURq22uqd38U8qKvOJc= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.21 h1:+1Kl1zx6bWi4X7cKi3VYh29h8BvsCoHQEQ6ST9X8w7w= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.21/go.mod h1:4vIRDq+CJB2xFAXZ+YgGUTiEft7oAQlhIs71xcSeuVg= +github.com/aws/aws-sdk-go-v2/service/sts v1.42.1 h1:F/M5Y9I3nwr2IEpshZgh1GeHpOItExNM9L1euNuh/fk= +github.com/aws/aws-sdk-go-v2/service/sts v1.42.1/go.mod h1:mTNxImtovCOEEuD65mKW7DCsL+2gjEH+RPEAexAzAio= +github.com/aws/smithy-go v1.25.1 h1:J8ERsGSU7d+aCmdQur5Txg6bVoYelvQJgtZehD12GkI= +github.com/aws/smithy-go v1.25.1/go.mod h1:YE2RhdIuDbA5E5bTdciG9KrW3+TiEONeUWCqxX9i1Fc= github.com/axiomhq/hyperloglog v0.2.6 h1:sRhvvF3RIXWQgAXaTphLp4yJiX4S0IN3MWTaAgZoRJw= github.com/axiomhq/hyperloglog v0.2.6/go.mod h1:YjX/dQqCR/7QYX0g8mu8UZAjpIenz1FKM71UEsjFoTo= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= @@ -254,8 +254,8 @@ github.com/golang/snappy v1.0.0 h1:Oy607GVXHs7RtbggtPBnr2RmDArIsAefDwvrdWvRhGs= github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg= github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= -github.com/google/cel-go v0.28.0 h1:KjSWstCpz/MN5t4a8gnGJNIYUsJRpdi/r97xWDphIQc= -github.com/google/cel-go v0.28.0/go.mod h1:X0bD6iVNR8pkROSOoHVdgTkzmRcosof7WQqCD6wcMc8= +github.com/google/cel-go v0.28.1 h1:YWIwi77J4xIsYUwAF/iIuS6haffzIHS8yWI8glSbLWM= +github.com/google/cel-go v0.28.1/go.mod h1:X0bD6iVNR8pkROSOoHVdgTkzmRcosof7WQqCD6wcMc8= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/go-tpm v0.9.4 h1:awZRf9FwOeTunQmHoDYSHJps3ie6f1UlhS1fOdPEt1I= @@ -367,8 +367,8 @@ github.com/kamstrup/intmap v0.5.2 h1:qnwBm1mh4XAnW9W9Ue9tZtTff8pS6+s6iKF6JRIV2Dk github.com/kamstrup/intmap v0.5.2/go.mod h1:gWUVWHKzWj8xpJVFf5GC0O26bWmv3GqdnIX/LMT6Aq4= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.18.5 h1:/h1gH5Ce+VWNLSWqPzOVn6XBO+vJbCNGvjoaGBFW2IE= -github.com/klauspost/compress v1.18.5/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ= +github.com/klauspost/compress v1.18.6 h1:2jupLlAwFm95+YDR+NwD2MEfFO9d4z4Prjl1XXDjuao= +github.com/klauspost/compress v1.18.6/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ= github.com/klauspost/connect-compress/v2 v2.1.1 h1:ycZNp4rWOZBodVE2Ls5AzK4aHkyK+GteEfzRZgKNs+c= github.com/klauspost/connect-compress/v2 v2.1.1/go.mod h1:9oilsPHJMzGKkjafSBk9J7iVo4mO+dw0G0KSdVpnlVE= github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE= @@ -455,8 +455,8 @@ github.com/metal-stack/v v1.0.3 h1:Sh2oBlnxrCUD+mVpzfC8HiqL045YWkxs0gpTvkjppqs= github.com/metal-stack/v v1.0.3/go.mod h1:YTahEu7/ishwpYKnp/VaW/7nf8+PInogkfGwLcGPdXg= github.com/miekg/dns v1.1.58 h1:ca2Hdkz+cDg/7eNF6V56jjzuZ4aCAE+DbVkILdQWG/4= github.com/miekg/dns v1.1.58/go.mod h1:Ypv+3b/KadlvW9vJfXOTf300O4UqaHFzFCuHz+rPkBY= -github.com/minio/minlz v1.1.0 h1:rUOGu3EP4EqJC5k3qCsIwEnZiJULKqtRyDdqbhlvMmQ= -github.com/minio/minlz v1.1.0/go.mod h1:qT0aEB35q79LLornSzeDH75LBf3aH1MV+jB5w9Wasec= +github.com/minio/minlz v1.1.1 h1:OGmft1V6AnI/Wme332U6bhG54nxEan+VFgkD7lat4KM= +github.com/minio/minlz v1.1.1/go.mod h1:qT0aEB35q79LLornSzeDH75LBf3aH1MV+jB5w9Wasec= github.com/mitchellh/go-ps v1.0.0 h1:i6ampVEEF4wQFF+bkYfwYgY+F/uYJDktmvLPf7qIgjc= github.com/mitchellh/go-ps v1.0.0/go.mod h1:J4lOc8z8yJs6vUwklHw2XEIiT4z4C40KtWVN3nvg8Pg= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= @@ -553,8 +553,8 @@ github.com/samber/lo v1.53.0/go.mod h1:4+MXEGsJzbKGaUEQFKBq2xtfuznW9oz/WrgyzMzRo github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/segmentio/asm v1.2.1 h1:DTNbBqs57ioxAD4PrArqftgypG4/qNpXoJx8TVXxPR0= github.com/segmentio/asm v1.2.1/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs= -github.com/shirou/gopsutil/v4 v4.26.3 h1:2ESdQt90yU3oXF/CdOlRCJxrP+Am1aBYubTMTfxJ1qc= -github.com/shirou/gopsutil/v4 v4.26.3/go.mod h1:LZ6ewCSkBqUpvSOf+LsTGnRinC6iaNUNMGBtDkJBaLQ= +github.com/shirou/gopsutil/v4 v4.26.4 h1:B4SXVbcwTyrocPHEmWBC4uCYr4Xcu3MK1TXqbprAOWY= +github.com/shirou/gopsutil/v4 v4.26.4/go.mod h1:LZ6ewCSkBqUpvSOf+LsTGnRinC6iaNUNMGBtDkJBaLQ= github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= @@ -647,12 +647,12 @@ github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQ github.com/zeebo/xxh3 v1.1.0 h1:s7DLGDK45Dyfg7++yxI0khrfwq9661w9EN78eP/UZVs= github.com/zeebo/xxh3 v1.1.0/go.mod h1:IisAie1LELR4xhVinxWS5+zf1lA4p0MW4T+w+W07F5s= github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= -go.etcd.io/etcd/api/v3 v3.6.10 h1:jlwjtELjA8yi2VWpOFH+0w0lGr3K6mVDyn0RDB9aaAY= -go.etcd.io/etcd/api/v3 v3.6.10/go.mod h1:pdV4VeFmvhdNjB4LWRkC8ReLyRBAxUOze3GarMhE2sk= -go.etcd.io/etcd/client/pkg/v3 v3.6.10 h1:tBT7podcPhuVbCVkAEzx8bC5I+aqxfLwBN8/As1arrA= -go.etcd.io/etcd/client/pkg/v3 v3.6.10/go.mod h1:WEy3PpwbbEBVRdh1NVJYsuUe/8eyI21PNJRazeD8z/Y= -go.etcd.io/etcd/client/v3 v3.6.10 h1:J598zJ+C/ZPvImypmq5waj84+bovePrlZERHklf34y0= -go.etcd.io/etcd/client/v3 v3.6.10/go.mod h1:iHhUDUcEwaKs1YFq3MgmI9U4zhTVasp/vgdVbFf1RS8= +go.etcd.io/etcd/api/v3 v3.6.11 h1:XFGTgrJ8nak3kB4NgMG8t7NT+lEeuuvKQAqUHKVgkWQ= +go.etcd.io/etcd/api/v3 v3.6.11/go.mod h1:HYfTh0jyh+uFgp6gMbxJteIDYY97yMuYz85Rnw6Gy9o= +go.etcd.io/etcd/client/pkg/v3 v3.6.11 h1:e41mp315Yn3QMGPmEzCyLsMINgJXTY/dX8kM++1csxU= +go.etcd.io/etcd/client/pkg/v3 v3.6.11/go.mod h1:DysuMe/inqRyC/1tjRR6hReH/VV9Lufs27YKSKBWWJg= +go.etcd.io/etcd/client/v3 v3.6.11 h1:LAByD96VmmeuairkvdAcE0RZnrmGz/q3ceeWePo9bwc= +go.etcd.io/etcd/client/v3 v3.6.11/go.mod h1:vOTDMCo+fGPEClJqcFEFSqZ+8e7WKV7AyqJjX//HR2w= go.mongodb.org/mongo-driver v1.17.9 h1:IexDdCuuNJ3BHrELgBlyaH9p60JXAvdzWR128q+U5tU= go.mongodb.org/mongo-driver v1.17.9/go.mod h1:LlOhpH5NUEfhxcAwG0UEkMqwYcc4JU18gtCdGudk/tQ= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= @@ -688,8 +688,8 @@ go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9E go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= -go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= -go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +go.uber.org/zap v1.28.0 h1:IZzaP1Fv73/T/pBMLk4VutPl36uNC+OSUh3JLG3FIjo= +go.uber.org/zap v1.28.0/go.mod h1:rDLpOi171uODNm/mxFcuYWxDsqWSAVkFdX4XojSKg/Q= go.yaml.in/yaml/v2 v2.4.4 h1:tuyd0P+2Ont/d6e2rl3be67goVK4R6deVxCUX5vyPaQ= go.yaml.in/yaml/v2 v2.4.4/go.mod h1:gMZqIpDtDqOfM0uNfy0SkpRhvUryYH0Z6wdMYcacYXQ= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= @@ -828,12 +828,12 @@ golang.zx2c4.com/wireguard/windows v1.0.1 h1:eOxiDVbywPC+ZQqvdCK7x+ZwWXKbYv50TtH golang.zx2c4.com/wireguard/windows v1.0.1/go.mod h1:+fbT3FFdX4zzYDLwJh5+HPEcNN/3HyNdzhNSVsQM+zs= gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4= gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E= -google.golang.org/genproto/googleapis/api v0.0.0-20260420184626-e10c466a9529 h1:zUWMZsvo/IJcD1t6MNCPO/azZTwz0TvwCBqr5aifoVY= -google.golang.org/genproto/googleapis/api v0.0.0-20260420184626-e10c466a9529/go.mod h1:a5OGAgyRr4lqco7AG9hQM9Fwh0N2ZV4grR0eXFEsXQg= -google.golang.org/genproto/googleapis/rpc v0.0.0-20260420184626-e10c466a9529 h1:XF8+t6QQiS0o9ArVan/HW8Q7cycNPGsJf6GA2nXxYAg= -google.golang.org/genproto/googleapis/rpc v0.0.0-20260420184626-e10c466a9529/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= -google.golang.org/grpc v1.81.0 h1:W3G9N3KQf3BU+YuCtGKJk0CmxQNbAISICD/9AORxLIw= -google.golang.org/grpc v1.81.0/go.mod h1:xGH9GfzOyMTGIOXBJmXt+BX/V0kcdQbdcuwQ/zNw42I= +google.golang.org/genproto/googleapis/api v0.0.0-20260511170946-3700d4141b60 h1:3WsB1FAbiRIf2tOxscWKs3pQBD9he1NsrnbhMuWfekc= +google.golang.org/genproto/googleapis/api v0.0.0-20260511170946-3700d4141b60/go.mod h1:7yoXV7RIh5gblj/xVYoogxAWvA9wUeVbpsK/M694l00= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260511170946-3700d4141b60 h1:seT2EwLWM78plQ7wcDfuWBc/4FAEAXDDiaSol4ku4qo= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260511170946-3700d4141b60/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= +google.golang.org/grpc v1.81.1 h1:VnnIIZ88UzOOKLukQi+ImGz8O1Wdp8nAGGnvOfEIWQQ= +google.golang.org/grpc v1.81.1/go.mod h1:xGH9GfzOyMTGIOXBJmXt+BX/V0kcdQbdcuwQ/zNw42I= google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= diff --git a/pkg/auth/jwt-token-cert-rotation_test.go b/pkg/auth/jwt-token-cert-rotation_test.go index fdbef57a..7a5fee4a 100644 --- a/pkg/auth/jwt-token-cert-rotation_test.go +++ b/pkg/auth/jwt-token-cert-rotation_test.go @@ -17,7 +17,7 @@ import ( ) func Test_jwt_cert_rotation(t *testing.T) { - t.Parallel() + // t.Parallel() oldMaxExpiration := token.MaxExpiration oldDefaultExpiration := token.DefaultExpiration