Zanzana: Split up settings into client and server sections (#99066)
* Split up zanzana settings into client and server sections * Update workspace
This commit is contained in:
@@ -22,8 +22,6 @@ import (
|
||||
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||
authzextv1 "github.com/grafana/grafana/pkg/services/authz/proto/v1"
|
||||
"github.com/grafana/grafana/pkg/services/authz/zanzana"
|
||||
zclient "github.com/grafana/grafana/pkg/services/authz/zanzana/client"
|
||||
zserver "github.com/grafana/grafana/pkg/services/authz/zanzana/server"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
"github.com/grafana/grafana/pkg/services/grpcserver"
|
||||
"github.com/grafana/grafana/pkg/services/grpcserver/interceptors"
|
||||
@@ -36,17 +34,17 @@ const zanzanaAudience = "zanzana"
|
||||
// It will also start an embedded ZanzanaSever if mode is set to "embedded".
|
||||
func ProvideZanzana(cfg *setting.Cfg, db db.DB, features featuremgmt.FeatureToggles) (zanzana.Client, error) {
|
||||
if !features.IsEnabledGlobally(featuremgmt.FlagZanzana) {
|
||||
return zclient.NewNoop(), nil
|
||||
return zanzana.NewNoopClient(), nil
|
||||
}
|
||||
|
||||
logger := log.New("zanzana")
|
||||
|
||||
var client zanzana.Client
|
||||
switch cfg.Zanzana.Mode {
|
||||
switch cfg.ZanzanaClient.Mode {
|
||||
case setting.ZanzanaModeClient:
|
||||
tokenClient, err := authnlib.NewTokenExchangeClient(authnlib.TokenExchangeConfig{
|
||||
Token: cfg.Zanzana.Token,
|
||||
TokenExchangeURL: cfg.Zanzana.TokenExchangeURL,
|
||||
Token: cfg.ZanzanaClient.Token,
|
||||
TokenExchangeURL: cfg.ZanzanaClient.TokenExchangeURL,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to initialize token exchange client: %w", err)
|
||||
@@ -69,12 +67,12 @@ func ProvideZanzana(cfg *setting.Cfg, db db.DB, features featuremgmt.FeatureTogg
|
||||
grpc.WithPerRPCCredentials(tokenAuthCred),
|
||||
}
|
||||
|
||||
conn, err := grpc.NewClient(cfg.Zanzana.Addr, dialOptions...)
|
||||
conn, err := grpc.NewClient(cfg.ZanzanaClient.Addr, dialOptions...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create zanzana client to remote server: %w", err)
|
||||
}
|
||||
|
||||
client, err = zclient.NewClient(context.Background(), conn, cfg)
|
||||
client, err = zanzana.NewClient(conn)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to initialize zanzana client: %w", err)
|
||||
}
|
||||
@@ -84,12 +82,12 @@ func ProvideZanzana(cfg *setting.Cfg, db db.DB, features featuremgmt.FeatureTogg
|
||||
return nil, fmt.Errorf("failed to start zanzana: %w", err)
|
||||
}
|
||||
|
||||
openfga, err := zserver.NewOpenFGA(&cfg.Zanzana, store, logger)
|
||||
openfga, err := zanzana.NewOpenFGAServer(cfg.ZanzanaServer, store, logger)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to start zanzana: %w", err)
|
||||
}
|
||||
|
||||
srv, err := zserver.NewAuthzServer(cfg, openfga)
|
||||
srv, err := zanzana.NewServer(cfg.ZanzanaServer, openfga, logger)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to start zanzana: %w", err)
|
||||
}
|
||||
@@ -109,13 +107,13 @@ func ProvideZanzana(cfg *setting.Cfg, db db.DB, features featuremgmt.FeatureTogg
|
||||
authzv1.RegisterAuthzServiceServer(channel, srv)
|
||||
authzextv1.RegisterAuthzExtentionServiceServer(channel, srv)
|
||||
|
||||
client, err = zclient.NewClient(context.Background(), channel, cfg)
|
||||
client, err = zanzana.NewClient(channel)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to initialize zanzana client: %w", err)
|
||||
}
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported zanzana mode: %s", cfg.Zanzana.Mode)
|
||||
return nil, fmt.Errorf("unsupported zanzana mode: %s", cfg.ZanzanaClient.Mode)
|
||||
}
|
||||
|
||||
return client, nil
|
||||
@@ -156,12 +154,12 @@ func (z *Zanzana) start(ctx context.Context) error {
|
||||
return fmt.Errorf("failed to initilize zanana store: %w", err)
|
||||
}
|
||||
|
||||
openfga, err := zserver.NewOpenFGA(&z.cfg.Zanzana, store, z.logger)
|
||||
openfga, err := zanzana.NewOpenFGAServer(z.cfg.ZanzanaServer, store, z.logger)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to start zanzana: %w", err)
|
||||
}
|
||||
|
||||
srv, err := zserver.NewAuthzServer(z.cfg, openfga)
|
||||
srv, err := zanzana.NewServer(z.cfg.ZanzanaServer, openfga, z.logger)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to start zanzana: %w", err)
|
||||
}
|
||||
@@ -183,7 +181,7 @@ func (z *Zanzana) start(ctx context.Context) error {
|
||||
AllowedAudiences: []string{zanzanaAudience},
|
||||
},
|
||||
authnlib.NewKeyRetriever(authnlib.KeyRetrieverConfig{
|
||||
SigningKeysURL: z.cfg.Zanzana.SigningKeysURL,
|
||||
SigningKeysURL: z.cfg.ZanzanaServer.SigningKeysURL,
|
||||
}),
|
||||
),
|
||||
)
|
||||
@@ -218,14 +216,18 @@ func (z *Zanzana) start(ctx context.Context) error {
|
||||
}
|
||||
|
||||
func (z *Zanzana) running(ctx context.Context) error {
|
||||
if z.cfg.Env == setting.Dev && z.cfg.Zanzana.ListenHTTP {
|
||||
go func() {
|
||||
z.logger.Info("Starting OpenFGA HTTP server")
|
||||
err := zserver.StartOpenFGAHttpSever(z.cfg, z.handle, z.logger)
|
||||
if err != nil {
|
||||
z.logger.Error("failed to start OpenFGA HTTP server", "error", err)
|
||||
}
|
||||
}()
|
||||
if z.cfg.Env == setting.Dev && z.cfg.ZanzanaServer.OpenFGAHttpAddr != "" {
|
||||
srv, err := zanzana.NewOpenFGAHttpServer(z.cfg.ZanzanaServer, z.handle)
|
||||
if err != nil {
|
||||
z.logger.Error("failed to create OpenFGA HTTP server", "error", err)
|
||||
} else {
|
||||
go func() {
|
||||
z.logger.Info("Starting OpenFGA HTTP server")
|
||||
if err := srv.ListenAndServe(); err != nil {
|
||||
z.logger.Error("failed to start OpenFGA HTTP server", "error", err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
}
|
||||
|
||||
// Run is blocking so we can just run it here
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
|
||||
"github.com/grafana/authlib/authz"
|
||||
"google.golang.org/grpc"
|
||||
|
||||
authzextv1 "github.com/grafana/grafana/pkg/services/authz/proto/v1"
|
||||
"github.com/grafana/grafana/pkg/services/authz/zanzana/client"
|
||||
@@ -17,6 +18,10 @@ type Client interface {
|
||||
BatchCheck(ctx context.Context, req *authzextv1.BatchCheckRequest) (*authzextv1.BatchCheckResponse, error)
|
||||
}
|
||||
|
||||
func NewClient(cc grpc.ClientConnInterface) (*client.Client, error) {
|
||||
return client.New(cc)
|
||||
}
|
||||
|
||||
func NewNoopClient() *client.NoopClient {
|
||||
return client.NewNoop()
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/grafana/authlib/authz"
|
||||
authzv1 "github.com/grafana/authlib/authz/proto/v1"
|
||||
@@ -13,66 +12,28 @@ import (
|
||||
"github.com/grafana/grafana/pkg/apimachinery/utils"
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
authzextv1 "github.com/grafana/grafana/pkg/services/authz/proto/v1"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
)
|
||||
|
||||
var _ authz.AccessClient = (*Client)(nil)
|
||||
|
||||
var tracer = otel.Tracer("github.com/grafana/grafana/pkg/services/authz/zanzana/client")
|
||||
|
||||
type ClientOption func(c *Client)
|
||||
|
||||
func WithTenantID(tenantID string) ClientOption {
|
||||
return func(c *Client) {
|
||||
c.tenantID = tenantID
|
||||
}
|
||||
}
|
||||
|
||||
func WithLogger(logger log.Logger) ClientOption {
|
||||
return func(c *Client) {
|
||||
c.logger = logger
|
||||
}
|
||||
}
|
||||
|
||||
type Client struct {
|
||||
logger log.Logger
|
||||
authz authzv1.AuthzServiceClient
|
||||
authzext authzextv1.AuthzExtentionServiceClient
|
||||
tenantID string
|
||||
}
|
||||
|
||||
func NewClient(ctx context.Context, cc grpc.ClientConnInterface, cfg *setting.Cfg) (*Client, error) {
|
||||
stackID := cfg.StackID
|
||||
if stackID == "" {
|
||||
stackID = "default"
|
||||
}
|
||||
|
||||
return New(
|
||||
ctx,
|
||||
cc,
|
||||
WithTenantID(fmt.Sprintf("stacks-%s", stackID)),
|
||||
WithLogger(log.New("zanzana-client")),
|
||||
)
|
||||
}
|
||||
|
||||
func New(ctx context.Context, cc grpc.ClientConnInterface, opts ...ClientOption) (*Client, error) {
|
||||
func New(cc grpc.ClientConnInterface) (*Client, error) {
|
||||
c := &Client{
|
||||
authz: authzv1.NewAuthzServiceClient(cc),
|
||||
authzext: authzextv1.NewAuthzExtentionServiceClient(cc),
|
||||
}
|
||||
|
||||
for _, o := range opts {
|
||||
o(c)
|
||||
}
|
||||
|
||||
if c.logger == nil {
|
||||
c.logger = log.NewNopLogger()
|
||||
logger: log.New("zanzana-client"),
|
||||
}
|
||||
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// Check implements authz.AccessClient.
|
||||
func (c *Client) Check(ctx context.Context, id claims.AuthInfo, req authz.CheckRequest) (authz.CheckResponse, error) {
|
||||
ctx, span := tracer.Start(ctx, "authz.zanzana.client.Check")
|
||||
defer span.End()
|
||||
|
||||
@@ -1 +1,26 @@
|
||||
package zanzana
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
openfgav1 "github.com/openfga/api/proto/openfga/v1"
|
||||
openfgaserver "github.com/openfga/openfga/pkg/server"
|
||||
openfgastorage "github.com/openfga/openfga/pkg/storage"
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/services/authz/zanzana/server"
|
||||
"github.com/grafana/grafana/pkg/services/grpcserver"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
)
|
||||
|
||||
func NewServer(cfg setting.ZanzanaServerSettings, openfga openfgav1.OpenFGAServiceServer, logger log.Logger) (*server.Server, error) {
|
||||
return server.NewServer(cfg, openfga, logger)
|
||||
}
|
||||
|
||||
func NewOpenFGAServer(cfg setting.ZanzanaServerSettings, store openfgastorage.OpenFGADatastore, logger log.Logger) (*openfgaserver.Server, error) {
|
||||
return server.NewOpenFGAServer(cfg, store, logger)
|
||||
}
|
||||
|
||||
func NewOpenFGAHttpServer(cfg setting.ZanzanaServerSettings, srv grpcserver.Provider) (*http.Server, error) {
|
||||
return server.NewOpenFGAHttpServer(cfg, srv)
|
||||
}
|
||||
|
||||
@@ -14,7 +14,6 @@ import (
|
||||
|
||||
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
|
||||
"github.com/rs/cors"
|
||||
"go.uber.org/zap/zapcore"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials/insecure"
|
||||
healthv1pb "google.golang.org/grpc/health/grpc_health_v1"
|
||||
@@ -27,7 +26,7 @@ import (
|
||||
zlogger "github.com/grafana/grafana/pkg/services/authz/zanzana/logger"
|
||||
)
|
||||
|
||||
func NewOpenFGA(cfg *setting.ZanzanaSettings, store storage.OpenFGADatastore, logger log.Logger) (*server.Server, error) {
|
||||
func NewOpenFGAServer(cfg setting.ZanzanaServerSettings, store storage.OpenFGADatastore, logger log.Logger) (*server.Server, error) {
|
||||
opts := []server.OpenFGAServiceV1Option{
|
||||
server.WithDatastore(store),
|
||||
server.WithLogger(zlogger.New(logger)),
|
||||
@@ -48,8 +47,7 @@ func NewOpenFGA(cfg *setting.ZanzanaSettings, store storage.OpenFGADatastore, lo
|
||||
return srv, nil
|
||||
}
|
||||
|
||||
// StartOpenFGAHttpSever starts HTTP server which allows to use fga cli.
|
||||
func StartOpenFGAHttpSever(cfg *setting.Cfg, srv grpcserver.Provider, logger log.Logger) error {
|
||||
func NewOpenFGAHttpServer(cfg setting.ZanzanaServerSettings, srv grpcserver.Provider) (*http.Server, error) {
|
||||
dialOpts := []grpc.DialOption{
|
||||
grpc.WithTransportCredentials(insecure.NewCredentials()),
|
||||
}
|
||||
@@ -66,12 +64,12 @@ func StartOpenFGAHttpSever(cfg *setting.Cfg, srv grpcserver.Provider, logger log
|
||||
retries++
|
||||
}
|
||||
if addr == "" {
|
||||
return fmt.Errorf("failed to start HTTP server: GRPC server unavailable")
|
||||
return nil, fmt.Errorf("failed to create HTTP server: GRPC server unavailable")
|
||||
}
|
||||
|
||||
conn, err := grpc.NewClient(addr, dialOpts...)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to dial GRPC: %w", err)
|
||||
return nil, fmt.Errorf("unable to dial GRPC: %w", err)
|
||||
}
|
||||
|
||||
muxOpts := []runtime.ServeMuxOption{
|
||||
@@ -91,11 +89,11 @@ func StartOpenFGAHttpSever(cfg *setting.Cfg, srv grpcserver.Provider, logger log
|
||||
}
|
||||
mux := runtime.NewServeMux(muxOpts...)
|
||||
if err := openfgav1.RegisterOpenFGAServiceHandler(context.TODO(), mux, conn); err != nil {
|
||||
return fmt.Errorf("failed to register gateway handler: %w", err)
|
||||
return nil, fmt.Errorf("failed to register gateway handler: %w", err)
|
||||
}
|
||||
|
||||
httpServer := &http.Server{
|
||||
Addr: cfg.Zanzana.HttpAddr,
|
||||
return &http.Server{
|
||||
Addr: cfg.OpenFGAHttpAddr,
|
||||
Handler: cors.New(cors.Options{
|
||||
AllowedOrigins: []string{"*"},
|
||||
AllowCredentials: true,
|
||||
@@ -104,13 +102,5 @@ func StartOpenFGAHttpSever(cfg *setting.Cfg, srv grpcserver.Provider, logger log
|
||||
http.MethodHead, http.MethodPatch, http.MethodDelete, http.MethodPut},
|
||||
}).Handler(mux),
|
||||
ReadHeaderTimeout: 30 * time.Second,
|
||||
}
|
||||
go func() {
|
||||
err = httpServer.ListenAndServe()
|
||||
if err != nil {
|
||||
logger.Error("failed to start http server", zapcore.Field{Key: "err", Type: zapcore.ErrorType, Interface: err})
|
||||
}
|
||||
}()
|
||||
logger.Info(fmt.Sprintf("OpenFGA HTTP server listening on '%s'...", httpServer.Addr))
|
||||
return nil
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@ import (
|
||||
"github.com/fullstorydev/grpchan/inprocgrpc"
|
||||
authzv1 "github.com/grafana/authlib/authz/proto/v1"
|
||||
openfgav1 "github.com/openfga/api/proto/openfga/v1"
|
||||
"github.com/openfga/language/pkg/go/transformer"
|
||||
"go.opentelemetry.io/otel"
|
||||
|
||||
dashboardalpha1 "github.com/grafana/grafana/pkg/apis/dashboard/v2alpha1"
|
||||
@@ -34,9 +33,8 @@ type Server struct {
|
||||
openfga openfgav1.OpenFGAServiceServer
|
||||
openfgaClient openfgav1.OpenFGAServiceClient
|
||||
|
||||
cfg setting.ZanzanaSettings
|
||||
cfg setting.ZanzanaServerSettings
|
||||
logger log.Logger
|
||||
modules []transformer.ModuleFile
|
||||
stores map[string]storeInfo
|
||||
storesMU *sync.Mutex
|
||||
cache *localcache.CacheService
|
||||
@@ -47,25 +45,7 @@ type storeInfo struct {
|
||||
ModelID string
|
||||
}
|
||||
|
||||
type ServerOption func(s *Server)
|
||||
|
||||
func WithLogger(logger log.Logger) ServerOption {
|
||||
return func(s *Server) {
|
||||
s.logger = logger
|
||||
}
|
||||
}
|
||||
|
||||
func WithSchema(modules []transformer.ModuleFile) ServerOption {
|
||||
return func(s *Server) {
|
||||
s.modules = modules
|
||||
}
|
||||
}
|
||||
|
||||
func NewAuthzServer(cfg *setting.Cfg, openfga openfgav1.OpenFGAServiceServer) (*Server, error) {
|
||||
return NewAuthz(cfg, openfga)
|
||||
}
|
||||
|
||||
func NewAuthz(cfg *setting.Cfg, openfga openfgav1.OpenFGAServiceServer, opts ...ServerOption) (*Server, error) {
|
||||
func NewServer(cfg setting.ZanzanaServerSettings, openfga openfgav1.OpenFGAServiceServer, logger log.Logger) (*Server, error) {
|
||||
channel := &inprocgrpc.Channel{}
|
||||
openfgav1.RegisterOpenFGAServiceServer(channel, openfga)
|
||||
openFGAClient := openfgav1.NewOpenFGAServiceClient(channel)
|
||||
@@ -75,16 +55,9 @@ func NewAuthz(cfg *setting.Cfg, openfga openfgav1.OpenFGAServiceServer, opts ...
|
||||
openfgaClient: openFGAClient,
|
||||
storesMU: &sync.Mutex{},
|
||||
stores: make(map[string]storeInfo),
|
||||
cfg: cfg.Zanzana,
|
||||
cache: localcache.New(cfg.Zanzana.CheckQueryCacheTTL, cacheCleanInterval),
|
||||
}
|
||||
|
||||
for _, o := range opts {
|
||||
o(s)
|
||||
}
|
||||
|
||||
if s.logger == nil {
|
||||
s.logger = log.New("authz-server")
|
||||
cfg: cfg,
|
||||
cache: localcache.New(cfg.CheckQueryCacheTTL, cacheCleanInterval),
|
||||
logger: logger,
|
||||
}
|
||||
|
||||
return s, nil
|
||||
|
||||
@@ -71,10 +71,10 @@ func setup(t *testing.T, testDB db.DB, cfg *setting.Cfg) *Server {
|
||||
t.Helper()
|
||||
store, err := store.NewEmbeddedStore(cfg, testDB, log.NewNopLogger())
|
||||
require.NoError(t, err)
|
||||
openfga, err := NewOpenFGA(&cfg.Zanzana, store, log.NewNopLogger())
|
||||
openfga, err := NewOpenFGAServer(cfg.ZanzanaServer, store, log.NewNopLogger())
|
||||
require.NoError(t, err)
|
||||
|
||||
srv, err := NewAuthz(cfg, openfga)
|
||||
srv, err := NewServer(cfg.ZanzanaServer, openfga, log.NewNopLogger())
|
||||
require.NoError(t, err)
|
||||
|
||||
storeInf, err := srv.getStoreInfo(context.Background(), namespace)
|
||||
|
||||
@@ -473,7 +473,8 @@ type Cfg struct {
|
||||
|
||||
RBAC RBACSettings
|
||||
|
||||
Zanzana ZanzanaSettings
|
||||
ZanzanaClient ZanzanaClientSettings
|
||||
ZanzanaServer ZanzanaServerSettings
|
||||
|
||||
// GRPC Server.
|
||||
GRPCServer GRPCServerSettings
|
||||
|
||||
@@ -12,20 +12,24 @@ const (
|
||||
ZanzanaModeEmbedded ZanzanaMode = "embedded"
|
||||
)
|
||||
|
||||
type ZanzanaSettings struct {
|
||||
// Addr is only used when mode is set to client
|
||||
Addr string
|
||||
// Mode can either be embedded or client
|
||||
type ZanzanaClientSettings struct {
|
||||
// Mode can either be embedded or client.
|
||||
Mode ZanzanaMode
|
||||
// ListenHTTP enables OpenFGA http server which allows to use fga cli
|
||||
ListenHTTP bool
|
||||
// OpenFGA http server address which allows to connect with fga cli
|
||||
HttpAddr string
|
||||
// If enabled, authorization cheks will be only performed by zanzana.
|
||||
// This bypasses the performance comparison with the legacy system.
|
||||
ZanzanaOnlyEvaluation bool
|
||||
// Number of concurrent check requests running by Grafana.
|
||||
ConcurrentChecks int64
|
||||
// Addr is the address of the Zanzana server.
|
||||
// Only used when mode is set to client.
|
||||
Addr string
|
||||
// Token used to perform the exchange request.
|
||||
// Only used when mode is set to client.
|
||||
Token string
|
||||
// URL called to perform exchange request.
|
||||
// Only used when mode is set to client.
|
||||
TokenExchangeURL string
|
||||
}
|
||||
|
||||
type ZanzanaServerSettings struct {
|
||||
// OpenFGA http server address which allows to connect with fga cli.
|
||||
// Can only be used in dev mode.
|
||||
OpenFGAHttpAddr string
|
||||
// Enable cache for Check() requests
|
||||
CheckQueryCache bool
|
||||
// TTL for cached requests. Default is 10 seconds.
|
||||
@@ -37,42 +41,38 @@ type ZanzanaSettings struct {
|
||||
// Use streamed version of list objects.
|
||||
// Returns full list of objects, but takes more time.
|
||||
UseStreamedListObjects bool
|
||||
|
||||
// Token used to perform the exchange request.
|
||||
Token string
|
||||
// URL called to perform exchange request.
|
||||
TokenExchangeURL string
|
||||
// URL for signing keys
|
||||
// URL for fetching signing keys.
|
||||
SigningKeysURL string
|
||||
}
|
||||
|
||||
func (cfg *Cfg) readZanzanaSettings() {
|
||||
s := ZanzanaSettings{}
|
||||
|
||||
sec := cfg.Raw.Section("zanzana")
|
||||
s.Mode = ZanzanaMode(sec.Key("mode").MustString("embedded"))
|
||||
zc := ZanzanaClientSettings{}
|
||||
clientSec := cfg.Raw.Section("zanzana.client")
|
||||
|
||||
zc.Mode = ZanzanaMode(clientSec.Key("mode").MustString("embedded"))
|
||||
validModes := []ZanzanaMode{ZanzanaModeEmbedded, ZanzanaModeClient}
|
||||
|
||||
if !slices.Contains(validModes, s.Mode) {
|
||||
cfg.Logger.Warn("Invalid zanzana mode", "expected", validModes, "got", s.Mode)
|
||||
s.Mode = "embedded"
|
||||
if !slices.Contains(validModes, zc.Mode) {
|
||||
cfg.Logger.Warn("Invalid zanzana mode", "expected", validModes, "got", zc.Mode)
|
||||
zc.Mode = "embedded"
|
||||
}
|
||||
|
||||
s.Addr = sec.Key("address").MustString("")
|
||||
s.ListenHTTP = sec.Key("listen_http").MustBool(false)
|
||||
s.HttpAddr = sec.Key("http_addr").MustString("127.0.0.1:8080")
|
||||
s.ConcurrentChecks = sec.Key("concurrent_checks").MustInt64(10)
|
||||
s.ZanzanaOnlyEvaluation = sec.Key("zanzana_only_evaluation").MustBool(false)
|
||||
s.CheckQueryCache = sec.Key("check_query_cache").MustBool(true)
|
||||
s.CheckQueryCacheTTL = sec.Key("check_query_cache_ttl").MustDuration(10 * time.Second)
|
||||
s.ListObjectsDeadline = sec.Key("list_objects_deadline").MustDuration(3 * time.Second)
|
||||
s.ListObjectsMaxResults = uint32(sec.Key("list_objects_max_results").MustUint(1000))
|
||||
s.UseStreamedListObjects = sec.Key("use_streamed_list_objects").MustBool(false)
|
||||
zc.Token = clientSec.Key("token").MustString("")
|
||||
zc.TokenExchangeURL = clientSec.Key("token_exchange_url").MustString("")
|
||||
zc.Addr = clientSec.Key("address").MustString("")
|
||||
|
||||
s.Token = sec.Key("token").MustString("")
|
||||
s.TokenExchangeURL = sec.Key("token_exchange_url").MustString("")
|
||||
s.SigningKeysURL = sec.Key("signing_keys_url").MustString("")
|
||||
cfg.ZanzanaClient = zc
|
||||
|
||||
cfg.Zanzana = s
|
||||
zs := ZanzanaServerSettings{}
|
||||
serverSec := cfg.Raw.Section("zanzana.server")
|
||||
|
||||
zs.OpenFGAHttpAddr = serverSec.Key("http_addr").MustString("127.0.0.1:8080")
|
||||
zs.CheckQueryCache = serverSec.Key("check_query_cache").MustBool(true)
|
||||
zs.CheckQueryCacheTTL = serverSec.Key("check_query_cache_ttl").MustDuration(10 * time.Second)
|
||||
zs.ListObjectsDeadline = serverSec.Key("list_objects_deadline").MustDuration(3 * time.Second)
|
||||
zs.ListObjectsMaxResults = uint32(serverSec.Key("list_objects_max_results").MustUint(1000))
|
||||
zs.UseStreamedListObjects = serverSec.Key("use_streamed_list_objects").MustBool(false)
|
||||
zs.SigningKeysURL = serverSec.Key("signing_keys_url").MustString("")
|
||||
|
||||
cfg.ZanzanaServer = zs
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
cel.dev/expr v0.18.0 h1:CJ6drgk+Hf96lkLikr4rFf19WrU0BOWEihyZnI2TAzo=
|
||||
cel.dev/expr v0.18.0/go.mod h1:MrpN08Q+lEBs+bGYdLxxHkZoUSsCp0nSKTs0nTymJgw=
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.37.4/go.mod h1:NHPJ89PdicEuT9hdPXMROBD91xc5uRDxsMtSB16k7hw=
|
||||
@@ -77,6 +79,8 @@ github.com/alecthomas/units v0.0.0-20240927000941-0f3dac36c52b h1:mimo19zliBX/vS
|
||||
github.com/alecthomas/units v0.0.0-20240927000941-0f3dac36c52b/go.mod h1:fvzegU4vN3H1qMT+8wDmzjAcDONcgo2/SZ/TyfdUOFs=
|
||||
github.com/andybalholm/brotli v1.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7XdTA=
|
||||
github.com/andybalholm/brotli v1.1.1/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA=
|
||||
github.com/antlr4-go/antlr/v4 v4.13.1 h1:SqQKkuVZ+zWkMMNkjy5FZe5mr5WURWnlpmOuzYWrPrQ=
|
||||
github.com/antlr4-go/antlr/v4 v4.13.1/go.mod h1:GKmUxMtwp6ZgGwZSva4eWPC5mS6vUAmOABFgjdkM7Nw=
|
||||
github.com/apache/arrow-go/v18 v18.0.1-0.20241212180703-82be143d7c30 h1:hXVi7QKuCQ0E8Yujfu9b0f0RnzZ72efpWvPnZgnJPrE=
|
||||
github.com/apache/arrow-go/v18 v18.0.1-0.20241212180703-82be143d7c30/go.mod h1:RNuWDIiGjq5nndL2PyQrndUy9nMLwheA3uWaAV7fe4U=
|
||||
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
|
||||
@@ -347,6 +351,8 @@ github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEW
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
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.22.0 h1:b3FJZxpiv1vTMo2/5RDUqAHPxkT8mmMfJIrq1llbf7g=
|
||||
github.com/google/cel-go v0.22.0/go.mod h1:BuznPXXfQDpXKWQ9sPW3TzlAJN5zzFe+i9tIs0yC4s8=
|
||||
github.com/google/flatbuffers v24.3.25+incompatible h1:CX395cjN9Kke9mmalRoL3d81AtFUxJM+yDthflgJGkI=
|
||||
github.com/google/flatbuffers v24.3.25+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
|
||||
github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I=
|
||||
@@ -422,6 +428,8 @@ github.com/grafana/pyroscope-go/godeltaprof v0.1.8 h1:iwOtYXeeVSAeYefJNaxDytgjKt
|
||||
github.com/grafana/pyroscope-go/godeltaprof v0.1.8/go.mod h1:2+l7K7twW49Ct4wFluZD3tZ6e0SjanjcUUBPVD/UuGU=
|
||||
github.com/grafana/sqlds/v4 v4.1.3 h1:+Hy5Yz+tSbD5N3yuLM0VKTsWlVaCzM1S1m1QEBZL7fE=
|
||||
github.com/grafana/sqlds/v4 v4.1.3/go.mod h1:Lx8IR939lIrCBpCKthv7AXs7E7bmNWPgt0gene/idT8=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0/go.mod h1:g5qyo/la0ALbONm6Vbp88Yd8NsDy6rZz+RcrMPxvld8=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1 h1:qnpSQwGEnkcRpTqNOIR6bJbR0gAorgP9CSALpRcKoAA=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1/go.mod h1:lXGCsh6c22WGtjr+qGHj1otzZpV/1kwTMAqkwZsnWRU=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.2.0 h1:kQ0NI7W1B3HwiN5gAYtY+XFItDPbLBwYRxAqbFTyDes=
|
||||
@@ -459,6 +467,8 @@ github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iP
|
||||
github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
|
||||
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/hashicorp/memberlist v0.5.0 h1:EtYPN8DpAURiapus508I4n9CzHs2W+8NZGbmmR/prTM=
|
||||
github.com/hashicorp/memberlist v0.5.0/go.mod h1:yvyXLpo0QaGE59Y7hDTsTzDD25JYBZ4mHgHUZ8lrOI0=
|
||||
github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE=
|
||||
@@ -552,6 +562,8 @@ github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
|
||||
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/magefile/mage v1.15.0 h1:BvGheCMAsG3bWUDbZ8AyXXpCNwU9u5CB6sM+HNb9HYg=
|
||||
github.com/magefile/mage v1.15.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A=
|
||||
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
|
||||
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
|
||||
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
|
||||
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||
github.com/mattetti/filebuffer v1.0.1 h1:gG7pyfnSIZCxdoKq+cPa8T0hhYtD9NxCdI4D7PTjRLM=
|
||||
@@ -622,6 +634,8 @@ github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRW
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/nakagami/firebirdsql v0.0.0-20190310045651-3c02a58cfed8/go.mod h1:86wM1zFnC6/uDBfZGNwB65O+pR2OFi5q/YQaEUid1qA=
|
||||
github.com/natefinch/wrap v0.2.0 h1:IXzc/pw5KqxJv55gV0lSOcKHYuEZPGbQrOOXr/bamRk=
|
||||
github.com/natefinch/wrap v0.2.0/go.mod h1:6gMHlAl12DwYEfKP3TkuykYUfLSEAvHw67itm4/KAS8=
|
||||
github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4=
|
||||
github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
|
||||
github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA=
|
||||
@@ -639,8 +653,12 @@ github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQ
|
||||
github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
|
||||
github.com/openfga/api/proto v0.0.0-20240906203051-102620ef2a66 h1:pAYrdyIKxPsMs/nRcTEnS9za2io11g7Rt7ng7HK82hk=
|
||||
github.com/openfga/api/proto v0.0.0-20240906203051-102620ef2a66/go.mod h1:gil5LBD8tSdFQbUkCQdnXsoeU9kDJdJgbGdHkgJfcd0=
|
||||
github.com/openfga/language/pkg/go v0.2.0-beta.2.0.20240926131254-992b301a003f h1:ZMZ7ntMnaHIPZxvVQv/aqC4ctzLqH+9Fqn4uw35kQpk=
|
||||
github.com/openfga/language/pkg/go v0.2.0-beta.2.0.20240926131254-992b301a003f/go.mod h1:ll/hN6kS4EE6B/7J/PbZqac9Nuv7ZHpI+Jfh36JLrbs=
|
||||
github.com/openfga/openfga v1.6.2 h1:tHBAgiCPomCZb3IH0CFqOpTDVDA/Xb8kG87oX4JCbXc=
|
||||
github.com/openfga/openfga v1.6.2/go.mod h1:jzbEpheazf6MFjtanQt1rpxexSRzfa9057F7JlkMv2I=
|
||||
github.com/opentracing-contrib/go-stdlib v1.0.0 h1:TBS7YuVotp8myLon4Pv7BtCBzOTo1DeZCld0Z63mW2w=
|
||||
github.com/opentracing-contrib/go-stdlib v1.0.0/go.mod h1:qtI1ogk+2JhVPIXVc6q+NHziSmy2W5GbdQZFUHADCBU=
|
||||
github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs=
|
||||
github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc=
|
||||
github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
|
||||
@@ -649,6 +667,8 @@ github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0Mw
|
||||
github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
|
||||
github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M=
|
||||
github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc=
|
||||
github.com/perimeterx/marshmallow v1.1.5 h1:a2LALqQ1BlHM8PZblsDdidgv1mWi1DgC2UmX50IvK2s=
|
||||
github.com/perimeterx/marshmallow v1.1.5/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0Vchtcl8we9tYaXw=
|
||||
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
||||
@@ -710,6 +730,10 @@ github.com/rs/cors v1.11.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ=
|
||||
github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4=
|
||||
github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
|
||||
github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ=
|
||||
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I=
|
||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
||||
@@ -730,12 +754,20 @@ github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304 h1:Jpy1PX
|
||||
github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c h1:Ho+uVpkel/udgjbwB5Lktg9BtvJSh2DT0Hi6LPSyI2w=
|
||||
github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s=
|
||||
github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
|
||||
github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
|
||||
github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
|
||||
github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
|
||||
github.com/spf13/cast v1.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w=
|
||||
github.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
|
||||
github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
|
||||
github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI=
|
||||
github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg=
|
||||
github.com/stoewer/go-strcase v1.3.0 h1:g0eASXYtp+yvN9fK8sH94oCIk0fau9uV1/ZdJ0AVEzs=
|
||||
github.com/stoewer/go-strcase v1.3.0/go.mod h1:fAH5hQ5pehh+j3nZfvwdk2RgEgQjAoM8wodgtPmh1xo=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
@@ -755,6 +787,8 @@ github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXl
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
|
||||
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
|
||||
github.com/teris-io/shortid v0.0.0-20171029131806-771a37caa5cf h1:Z2X3Os7oRzpdJ75iPqWZc0HeJWFYNCvKsfpQwFpRNTA=
|
||||
github.com/teris-io/shortid v0.0.0-20171029131806-771a37caa5cf/go.mod h1:M8agBzgqHIhgj7wEn9/0hJUZcrvt9VY+Ln+S1I5Mha0=
|
||||
github.com/tidwall/pretty v0.0.0-20180105212114-65a9db5fad51/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
|
||||
@@ -835,6 +869,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.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU=
|
||||
go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=
|
||||
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
|
||||
|
||||
Reference in New Issue
Block a user