enterprise-portal: implement basic MSP IAM and RPCs (#63173)

Closes CORE-99, closes CORE-176

This PR is based off (and was also served as PoC of) [RFC 962: MSP IAM
framework](https://docs.google.com/document/d/1ItJlQnpR5AHbrfAholZqjH8-8dPF1iQcKh99gE6SSjs/edit).
It comes with two main parts:

1. The initial version of the MSP IAM SDK:
`lib/managedservicesplatform/iam`
- Embeds the [OpenFGA server
implementation](https://github.com/openfga/openfga/tree/main/pkg/server)
and exposes the a `ClientV1` for interacting with it.
- Automagically manages the both MSP IAM's and OpenFGA's database
migrations upon initializing the `ClientV1`.
![CleanShot 2024-06-18 at 15 09
24@2x](https://github.com/sourcegraph/sourcegraph/assets/2946214/387e0e28-a6c2-4664-b946-0ea4a1dd0804)
- Ensures the specified OpenFGA's store and automatization model DSL
exists.
- Utility types and helpers to avoid easy mistakes (i.e. make the
relation tuples a bit more strongly-typed).
- Decided to put all types and pre-defined values together to simulate a
"central registry" and acting as a forcing function for services to form
some sort of convention. Then when we migrate the OpenFGA server to a
separate standalone service, it will be less headache about
consolidating similar meaning types/relations but different string
literals.
1. The first use case of the MSP IAM:
`cmd/enterprise-portal/internal/subscriptionsservice`
	- Added/updated RPCs:
		- Listing enterprise subscriptions via permissions
		- Update enterprise subscriptions to assign instance domains
- Update enterprise subscriptions membership to assign roles (and
permissions)
- A database table for enterprise subscriptions, only storing the extra
instance domains as Enterprise Portal is not the
writeable-source-of-truth.

## Other minor changes

- Moved `internal/redislock` to `lib/redislock` to be used in MSP IAM
SDK.
- Call `createdb ...` as part of `enterprise-portal` install script in
`sg.config.yaml` (`msp_iam` database is a hard requirement of MSP IAM
framework).

## Test plan

Tested with gRPC UI:

- `UpdateEnterpriseSubscription` to assign an instance domain
- `UpdateEnterpriseSubscriptionMembership` to assign roles
- `ListEnterpriseSubscriptions`:
	- List by subscription ID
	- List by instance domain
	- List by view cody analytics permissions

---------

Co-authored-by: Robert Lin <robert@bobheadxi.dev>
This commit is contained in:
Joe Chen 2024-06-19 21:46:48 -04:00 committed by GitHub
parent 5630eef9e9
commit b717fd518a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
53 changed files with 5473 additions and 1062 deletions

View File

@ -6,6 +6,7 @@ go_library(
srcs = [
"adapters.go",
"v1.go",
"v1_store.go",
],
importpath = "github.com/sourcegraph/sourcegraph/cmd/enterprise-portal/internal/codyaccessservice",
tags = [TAG_INFRA_CORESERVICES],
@ -21,6 +22,7 @@ go_library(
"//lib/errors",
"@com_connectrpc_connect//:connect",
"@com_github_sourcegraph_log//:log",
"@com_github_sourcegraph_sourcegraph_accounts_sdk_go//:sourcegraph-accounts-sdk-go",
"@com_github_sourcegraph_sourcegraph_accounts_sdk_go//scopes",
"@org_golang_google_protobuf//types/known/durationpb",
],

View File

@ -30,16 +30,16 @@ type DotComDB interface {
func RegisterV1(
logger log.Logger,
mux *http.ServeMux,
samsClient samsm2m.TokenIntrospector,
store StoreV1,
dotcom DotComDB,
opts ...connect.HandlerOption,
) {
mux.Handle(
codyaccessv1connect.NewCodyAccessServiceHandler(
&handlerV1{
logger: logger.Scoped("codyaccess.v1"),
samsClient: samsClient,
dotcom: dotcom,
logger: logger.Scoped("codyaccess.v1"),
store: store,
dotcom: dotcom,
},
opts...,
),
@ -48,10 +48,10 @@ func RegisterV1(
type handlerV1 struct {
codyaccessv1connect.UnimplementedCodyAccessServiceHandler
logger log.Logger
samsClient samsm2m.TokenIntrospector
dotcom DotComDB
logger log.Logger
store StoreV1
dotcom DotComDB
}
var _ codyaccessv1connect.CodyAccessServiceHandler = (*handlerV1)(nil)
@ -62,7 +62,7 @@ func (s *handlerV1) GetCodyGatewayAccess(ctx context.Context, req *connect.Reque
// 🚨 SECURITY: Require approrpiate M2M scope.
requiredScope := samsm2m.EnterprisePortalScope("codyaccess", scopes.ActionRead)
clientAttrs, err := samsm2m.RequireScope(ctx, logger, s.samsClient, requiredScope, req)
clientAttrs, err := samsm2m.RequireScope(ctx, logger, s.store, requiredScope, req)
if err != nil {
return nil, err
}
@ -106,7 +106,7 @@ func (s *handlerV1) ListCodyGatewayAccesses(ctx context.Context, req *connect.Re
// 🚨 SECURITY: Require approrpiate M2M scope.
requiredScope := samsm2m.EnterprisePortalScope("codyaccess", scopes.ActionRead)
clientAttrs, err := samsm2m.RequireScope(ctx, logger, s.samsClient, requiredScope, req)
clientAttrs, err := samsm2m.RequireScope(ctx, logger, s.store, requiredScope, req)
if err != nil {
return nil, err
}

View File

@ -0,0 +1,38 @@
package codyaccessservice
import (
"context"
sams "github.com/sourcegraph/sourcegraph-accounts-sdk-go"
)
// StoreV1 is the data layer carrier for Cody access service v1. This interface
// is meant to abstract away and limit the exposure of the underlying data layer
// to the handler through a thin-wrapper.
type StoreV1 interface {
// IntrospectSAMSToken takes a SAMS access token and returns relevant metadata.
//
// 🚨SECURITY: SAMS will return a successful result if the token is valid, but
// is no longer active. It is critical that the caller not honor tokens where
// `.Active == false`.
IntrospectSAMSToken(ctx context.Context, token string) (*sams.IntrospectTokenResponse, error)
}
type storeV1 struct {
SAMSClient *sams.ClientV1
}
type StoreV1Options struct {
SAMSClient *sams.ClientV1
}
// NewStoreV1 returns a new StoreV1 using the given resource handles.
func NewStoreV1(opts StoreV1Options) StoreV1 {
return &storeV1{
SAMSClient: opts.SAMSClient,
}
}
func (s *storeV1) IntrospectSAMSToken(ctx context.Context, token string) (*sams.IntrospectTokenResponse, error) {
return s.SAMSClient.Tokens().IntrospectToken(ctx, token)
}

View File

@ -1,3 +1,4 @@
load("//dev:go_defs.bzl", "go_test")
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
@ -5,21 +6,22 @@ go_library(
srcs = [
"database.go",
"migrate.go",
"permissions.go",
"subscriptions.go",
],
importpath = "github.com/sourcegraph/sourcegraph/cmd/enterprise-portal/internal/database",
visibility = ["//cmd/enterprise-portal:__subpackages__"],
deps = [
"//internal/redislock",
"//lib/errors",
"//lib/managedservicesplatform/runtime",
"//lib/redislock",
"@com_github_jackc_pgx_v5//:pgx",
"@com_github_jackc_pgx_v5//pgxpool",
"@com_github_redis_go_redis_v9//:go-redis",
"@com_github_sourcegraph_log//:log",
"@io_gorm_driver_postgres//:postgres",
"@io_gorm_gorm//:gorm",
"@io_gorm_gorm//logger",
"@io_gorm_gorm//schema",
"@io_gorm_plugin_opentelemetry//tracing",
"@io_opentelemetry_go_otel//:otel",
"@io_opentelemetry_go_otel//attribute",
@ -27,3 +29,27 @@ go_library(
"@io_opentelemetry_go_otel_trace//:trace",
],
)
go_test(
name = "database_test",
srcs = [
"main_test.go",
"subscriptions_test.go",
],
embed = [":database"],
tags = [
# Test requires localhost database
"requires-network",
],
deps = [
"//internal/database/dbtest",
"@com_github_google_uuid//:uuid",
"@com_github_jackc_pgx_v5//:pgx",
"@com_github_jackc_pgx_v5//pgxpool",
"@com_github_stretchr_testify//assert",
"@com_github_stretchr_testify//require",
"@io_gorm_driver_postgres//:postgres",
"@io_gorm_gorm//:gorm",
"@io_gorm_gorm//schema",
],
)

View File

@ -2,11 +2,14 @@ package database
import (
"context"
"os"
"github.com/jackc/pgx/v5"
"github.com/jackc/pgx/v5/pgxpool"
"github.com/redis/go-redis/v9"
"github.com/sourcegraph/log"
"go.opentelemetry.io/otel"
"gorm.io/gorm/schema"
"github.com/sourcegraph/sourcegraph/lib/errors"
"github.com/sourcegraph/sourcegraph/lib/managedservicesplatform/runtime"
@ -19,13 +22,23 @@ type DB struct {
db *pgxpool.Pool
}
// ⚠️ WARNING: This list is meant to be read-only.
var allTables = []any{
&Subscription{},
&Permission{},
func (db *DB) Subscriptions() *SubscriptionsStore {
return newSubscriptionsStore(db.db)
}
const databaseName = "enterprise-portal"
// ⚠️ WARNING: This list is meant to be read-only.
var allTables = []schema.Tabler{
&Subscription{},
}
func databaseName(msp bool) string {
if msp {
return "enterprise_portal"
}
// Use whatever the current database is for local development.
return os.Getenv("PGDATABASE")
}
// NewHandle returns a new database handle with the given configuration. It may
// attempt to auto-migrate the database schema if the application version has
@ -36,9 +49,34 @@ func NewHandle(ctx context.Context, logger log.Logger, contract runtime.Contract
return nil, errors.Wrap(err, "maybe migrate")
}
pool, err := contract.PostgreSQL.GetConnectionPool(ctx, databaseName)
pool, err := contract.PostgreSQL.GetConnectionPool(ctx, databaseName(contract.MSP))
if err != nil {
return nil, errors.Wrap(err, "get connection pool")
}
return &DB{db: pool}, nil
}
// transaction executes the given function within a transaction. If the function
// returns an error, the transaction will be rolled back.
func transaction(ctx context.Context, db *pgxpool.Pool, fn func(tx pgx.Tx) error) (err error) {
tx, err := db.Begin(ctx)
if err != nil {
return errors.Wrap(err, "begin")
}
defer func() {
rollbackErr := tx.Rollback(ctx)
// Only return the rollback error if there is no other error.
if err == nil {
err = errors.Wrap(rollbackErr, "rollback")
}
}()
if err = fn(tx); err != nil {
return err
}
if err = tx.Commit(ctx); err != nil {
return errors.Wrap(err, "commit")
}
return nil
}

View File

@ -0,0 +1,111 @@
package database
import (
"context"
"database/sql"
"fmt"
"strings"
"testing"
"time"
"github.com/jackc/pgx/v5/pgxpool"
"github.com/stretchr/testify/require"
"gorm.io/driver/postgres"
"gorm.io/gorm"
"gorm.io/gorm/schema"
"github.com/sourcegraph/sourcegraph/internal/database/dbtest"
)
// newTestDB creates a new test database and initializes the given list of
// tables for the suite. The test database is dropped after testing is completed
// unless failed.
//
// Future: Move to a shared package when more than Enterprise Portal uses it.
func newTestDB(t testing.TB, system, suite string, tables ...schema.Tabler) *pgxpool.Pool {
if testing.Short() {
t.Skip("skipping DB test since -short specified")
}
dsn, err := dbtest.GetDSN()
require.NoError(t, err)
// Open a connection to control the test database lifecycle.
sqlDB, err := sql.Open("pgx", dsn.String())
require.NoError(t, err)
// Set up test suite database.
dbName := fmt.Sprintf("sourcegraph-test-%s-%s-%d", system, suite, time.Now().Unix())
_, err = sqlDB.Exec(fmt.Sprintf("DROP DATABASE IF EXISTS %q", dbName))
require.NoError(t, err)
_, err = sqlDB.Exec(fmt.Sprintf("CREATE DATABASE %q", dbName))
require.NoError(t, err)
// Swap out the database name to be the test suite database in the DSN.
dsn.Path = "/" + dbName
now := time.Now().UTC().Truncate(time.Second)
db, err := gorm.Open(
postgres.Open(dsn.String()),
&gorm.Config{
SkipDefaultTransaction: true,
NowFunc: func() time.Time {
return now
},
},
)
require.NoError(t, err)
for _, table := range tables {
err = db.AutoMigrate(table)
require.NoError(t, err)
}
// Close the connection used to auto-migrate the database.
migrateDB, err := db.DB()
require.NoError(t, err)
err = migrateDB.Close()
require.NoError(t, err)
// Open a new connection to the test suite database.
testDB, err := pgxpool.New(context.Background(), dsn.String())
require.NoError(t, err)
t.Cleanup(func() {
if t.Failed() {
t.Logf("Database %q left intact for inspection", dbName)
return
}
testDB.Close()
_, err = sqlDB.Exec(fmt.Sprintf(`DROP DATABASE %q`, dbName))
if err != nil {
t.Errorf("Failed to drop test suite database %q: %v", dbName, err)
}
err = sqlDB.Close()
if err != nil {
t.Errorf("Failed to close test database connection %q: %v", dbName, err)
}
})
return testDB
}
// clearTables removes all rows from the list of tables in the original order.
// It uses soft-deletion when available and skips deletion when the test suite
// failed.
//
// Future: Move to a shared package when more than Enterprise Portal uses it.
func clearTables(t *testing.T, db *pgxpool.Pool, tables ...schema.Tabler) error {
if t.Failed() {
return nil
}
tableNames := make([]string, 0, len(tables))
for _, t := range tables {
tableNames = append(tableNames, t.TableName())
}
_, err := db.Exec(context.Background(), "TRUNCATE TABLE "+strings.Join(tableNames, ", ")+" RESTART IDENTITY")
return err
}

View File

@ -16,21 +16,14 @@ import (
gormlogger "gorm.io/gorm/logger"
"gorm.io/plugin/opentelemetry/tracing"
"github.com/sourcegraph/sourcegraph/internal/redislock"
"github.com/sourcegraph/sourcegraph/lib/errors"
"github.com/sourcegraph/sourcegraph/lib/managedservicesplatform/runtime"
"github.com/sourcegraph/sourcegraph/lib/redislock"
)
// maybeMigrate runs the auto-migration for the database when needed based on
// the given version.
func maybeMigrate(ctx context.Context, logger log.Logger, contract runtime.Contract, redisClient *redis.Client, currentVersion string) (err error) {
// TODO(jchen): We need to figure otu a way to make local dev more seamless.
// Until then, only run migrations in MSP. See
// https://linear.app/sourcegraph/issue/CORE-176/enterprise-portal-do-not-require-a-separate-database-in-local-dev
if !contract.MSP {
return nil
}
ctx, span := databaseTracer.Start(
ctx,
"database.maybeMigrate",
@ -46,7 +39,8 @@ func maybeMigrate(ctx context.Context, logger log.Logger, contract runtime.Contr
span.End()
}()
sqlDB, err := contract.PostgreSQL.OpenDatabase(ctx, databaseName)
dbName := databaseName(contract.MSP)
sqlDB, err := contract.PostgreSQL.OpenDatabase(ctx, dbName)
if err != nil {
return errors.Wrap(err, "open database")
}
@ -79,18 +73,18 @@ func maybeMigrate(ctx context.Context, logger log.Logger, contract runtime.Contr
return redislock.OnlyOne(
logger,
redisClient,
fmt.Sprintf("%s:auto-migrate", databaseName),
fmt.Sprintf("%s:auto-migrate", dbName),
15*time.Second,
func() error {
versionKey := fmt.Sprintf("%s:db_version", databaseName)
span.AddEvent("lock.acquired")
versionKey := fmt.Sprintf("%s:db_version", dbName)
if shouldSkipMigration(
redisClient.Get(context.Background(), versionKey).Val(),
currentVersion,
) {
logger.Info("skipped auto-migration",
log.String("database", databaseName),
log.String("database", dbName),
log.String("currentVersion", currentVersion),
)
span.SetAttributes(attribute.Bool("skipped", true))

View File

@ -1,20 +0,0 @@
package database
import (
"time"
)
// Permission is a Zanzibar-inspired permission record.
type Permission struct {
// Namespace is the namespace of the permission, e.g. "cody_analytics".
Namespace string `gorm:"not null;index"`
// Subject is the subject of the permission, e.g. "User:<SAMS account ID>".
Subject string `gorm:"not null;index"`
// Object is the object of the permission, e.g. "Subscription:<subscription ID>".
Object string `gorm:"not null"`
// Relation is the relationship between the subject and the object, e.g.
// "customer_admin".
Relation string `gorm:"not null"`
// CommitTime is the time when the permission was committed.
CommitTime time.Time `gorm:"not null"`
}

View File

@ -1,10 +1,162 @@
package database
import (
"context"
"fmt"
"strings"
"github.com/jackc/pgx/v5"
"github.com/jackc/pgx/v5/pgxpool"
"github.com/sourcegraph/sourcegraph/lib/errors"
)
// Subscription is a product subscription record.
type Subscription struct {
// ID is the prefixed UUID-format identifier for the subscription.
ID string `gorm:"primaryKey"`
// InstanceDomain is the instance domain associated with the subscription, e.g.
// "acme.sourcegraphcloud.com".
InstanceDomain string `gorm:"index"`
InstanceDomain string `gorm:"unique"`
}
func (s *Subscription) TableName() string {
return "enterprise_portal_subscriptions"
}
// SubscriptionsStore is the storage layer for product subscriptions.
type SubscriptionsStore struct {
db *pgxpool.Pool
}
func newSubscriptionsStore(db *pgxpool.Pool) *SubscriptionsStore {
return &SubscriptionsStore{
db: db,
}
}
// ListEnterpriseSubscriptionsOptions is the set of options to filter subscriptions.
// Non-empty fields are treated as AND-concatenated.
type ListEnterpriseSubscriptionsOptions struct {
// IDs is a list of subscription IDs to filter by.
IDs []string
// InstanceDomains is a list of instance domains to filter by.
InstanceDomains []string
// OnlyArchived indicates whether to only list archived subscriptions.
OnlyArchived bool
// PageSize is the maximum number of subscriptions to return.
PageSize int
}
func (opts ListEnterpriseSubscriptionsOptions) toQueryConditions() (where, limit string, _ pgx.NamedArgs) {
whereConds := []string{"TRUE"}
namedArgs := pgx.NamedArgs{}
if len(opts.IDs) > 0 {
whereConds = append(whereConds, "id = ANY(@ids)")
namedArgs["ids"] = opts.IDs
}
if len(opts.InstanceDomains) > 0 {
whereConds = append(whereConds, "instance_domain = ANY(@instanceDomains)")
namedArgs["instanceDomains"] = opts.InstanceDomains
}
// Future: Uncomment the following block when the archived field is added to the table.
// if opts.OnlyArchived {
// whereConds = append(whereConds, "archived = TRUE")
// }
where = strings.Join(whereConds, " AND ")
if opts.PageSize > 0 {
limit = "LIMIT @pageSize"
namedArgs["pageSize"] = opts.PageSize
}
return where, limit, namedArgs
}
// List returns a list of subscriptions based on the given options.
func (s *SubscriptionsStore) List(ctx context.Context, opts ListEnterpriseSubscriptionsOptions) ([]*Subscription, error) {
where, limit, namedArgs := opts.toQueryConditions()
query := fmt.Sprintf(`
SELECT
id,
instance_domain
FROM enterprise_portal_subscriptions
WHERE %s
%s`,
where, limit,
)
rows, err := s.db.Query(ctx, query, namedArgs)
if err != nil {
return nil, errors.Wrap(err, "query rows")
}
defer rows.Close()
var subscriptions []*Subscription
for rows.Next() {
var subscription Subscription
if err = rows.Scan(&subscription.ID, &subscription.InstanceDomain); err != nil {
return nil, errors.Wrap(err, "scan row")
}
subscriptions = append(subscriptions, &subscription)
}
return subscriptions, rows.Err()
}
type UpsertSubscriptionOptions struct {
InstanceDomain string
// ForceUpdate indicates whether to force update all fields of the subscription
// record.
ForceUpdate bool
}
// toQuery returns the query based on the options. It returns an empty query if
// nothing to update.
func (opts UpsertSubscriptionOptions) toQuery(id string) (query string, _ pgx.NamedArgs) {
const queryFmt = `
INSERT INTO enterprise_portal_subscriptions (id, instance_domain)
VALUES (@id, @instanceDomain)
ON CONFLICT (id)
DO UPDATE SET
%s`
namedArgs := pgx.NamedArgs{
"id": id,
"instanceDomain": opts.InstanceDomain,
}
var sets []string
if opts.ForceUpdate || opts.InstanceDomain != "" {
sets = append(sets, "instance_domain = excluded.instance_domain")
}
if len(sets) == 0 {
return "", nil
}
query = fmt.Sprintf(
queryFmt,
strings.Join(sets, ", "),
)
return query, namedArgs
}
// Upsert upserts a subscription record based on the given options.
func (s *SubscriptionsStore) Upsert(ctx context.Context, subscriptionID string, opts UpsertSubscriptionOptions) (*Subscription, error) {
query, namedArgs := opts.toQuery(subscriptionID)
if query != "" {
_, err := s.db.Exec(ctx, query, namedArgs)
if err != nil {
return nil, errors.Wrap(err, "exec")
}
}
return s.Get(ctx, subscriptionID)
}
// Get returns a subscription record with the given subscription ID. It returns
// pgx.ErrNoRows if no such subscription exists.
func (s *SubscriptionsStore) Get(ctx context.Context, subscriptionID string) (*Subscription, error) {
var subscription Subscription
query := `SELECT id, instance_domain FROM enterprise_portal_subscriptions WHERE id = @id`
namedArgs := pgx.NamedArgs{"id": subscriptionID}
err := s.db.QueryRow(ctx, query, namedArgs).Scan(&subscription.ID, &subscription.InstanceDomain)
if err != nil {
return nil, err
}
return &subscription, nil
}

View File

@ -0,0 +1,157 @@
package database
import (
"context"
"testing"
"github.com/google/uuid"
"github.com/jackc/pgx/v5"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestSubscriptionsStore(t *testing.T) {
t.Parallel()
ctx := context.Background()
db := newSubscriptionsStore(newTestDB(t, "enterprise-portal", "SubscriptionsStore", allTables...))
for _, tc := range []struct {
name string
test func(t *testing.T, ctx context.Context, s *SubscriptionsStore)
}{
{"List", SubscriptionsStoreList},
{"Upsert", SubscriptionsStoreUpsert},
{"Get", SubscriptionsStoreGet},
} {
t.Run(tc.name, func(t *testing.T) {
t.Cleanup(func() {
err := clearTables(t, db.db, allTables...)
require.NoError(t, err)
})
tc.test(t, ctx, db)
})
if t.Failed() {
break
}
}
}
func SubscriptionsStoreList(t *testing.T, ctx context.Context, s *SubscriptionsStore) {
// Create test records.
s1, err := s.Upsert(
ctx,
uuid.New().String(),
UpsertSubscriptionOptions{InstanceDomain: "s1.sourcegraph.com"},
)
require.NoError(t, err)
s2, err := s.Upsert(
ctx,
uuid.New().String(),
UpsertSubscriptionOptions{InstanceDomain: "s2.sourcegraph.com"},
)
require.NoError(t, err)
_, err = s.Upsert(
ctx,
uuid.New().String(),
UpsertSubscriptionOptions{InstanceDomain: "s3.sourcegraph.com"},
)
require.NoError(t, err)
t.Run("list by IDs", func(t *testing.T) {
subscriptions, err := s.List(ctx, ListEnterpriseSubscriptionsOptions{IDs: []string{s1.ID, s2.ID}})
require.NoError(t, err)
require.Len(t, subscriptions, 2)
assert.Equal(t, s1.ID, subscriptions[0].ID)
assert.Equal(t, s2.ID, subscriptions[1].ID)
t.Run("no match", func(t *testing.T) {
subscriptions, err = s.List(ctx, ListEnterpriseSubscriptionsOptions{IDs: []string{"1234"}})
require.NoError(t, err)
require.Len(t, subscriptions, 0)
})
})
t.Run("list by instance domains", func(t *testing.T) {
subscriptions, err := s.List(ctx, ListEnterpriseSubscriptionsOptions{
InstanceDomains: []string{s1.InstanceDomain, s2.InstanceDomain}},
)
require.NoError(t, err)
require.Len(t, subscriptions, 2)
assert.Equal(t, s1.ID, subscriptions[0].ID)
assert.Equal(t, s2.ID, subscriptions[1].ID)
t.Run("no match", func(t *testing.T) {
subscriptions, err = s.List(ctx, ListEnterpriseSubscriptionsOptions{InstanceDomains: []string{"1234"}})
require.NoError(t, err)
require.Len(t, subscriptions, 0)
})
})
t.Run("list with page size", func(t *testing.T) {
subscriptions, err := s.List(
ctx,
ListEnterpriseSubscriptionsOptions{
IDs: []string{s1.ID, s2.ID}, // Two matching but only of them will be returned.
PageSize: 1,
},
)
require.NoError(t, err)
assert.Len(t, subscriptions, 1)
})
}
func SubscriptionsStoreUpsert(t *testing.T, ctx context.Context, s *SubscriptionsStore) {
// Create initial test record.
s1, err := s.Upsert(
ctx,
uuid.New().String(),
UpsertSubscriptionOptions{InstanceDomain: "s1.sourcegraph.com"},
)
require.NoError(t, err)
got, err := s.Get(ctx, s1.ID)
require.NoError(t, err)
assert.Equal(t, s1.ID, got.ID)
assert.Equal(t, s1.InstanceDomain, got.InstanceDomain)
t.Run("noop", func(t *testing.T) {
got, err = s.Upsert(ctx, s1.ID, UpsertSubscriptionOptions{})
require.NoError(t, err)
assert.Equal(t, s1.InstanceDomain, got.InstanceDomain)
})
t.Run("update", func(t *testing.T) {
got, err = s.Upsert(ctx, s1.ID, UpsertSubscriptionOptions{InstanceDomain: "s1-new.sourcegraph.com"})
require.NoError(t, err)
assert.Equal(t, "s1-new.sourcegraph.com", got.InstanceDomain)
})
t.Run("force update", func(t *testing.T) {
got, err = s.Upsert(ctx, s1.ID, UpsertSubscriptionOptions{ForceUpdate: true})
require.NoError(t, err)
assert.Empty(t, got.InstanceDomain)
})
}
func SubscriptionsStoreGet(t *testing.T, ctx context.Context, s *SubscriptionsStore) {
// Create initial test record.
s1, err := s.Upsert(
ctx,
uuid.New().String(),
UpsertSubscriptionOptions{InstanceDomain: "s1.sourcegraph.com"},
)
require.NoError(t, err)
t.Run("not found", func(t *testing.T) {
_, err := s.Get(ctx, uuid.New().String())
assert.Equal(t, pgx.ErrNoRows, err)
})
t.Run("found", func(t *testing.T) {
got, err := s.Get(ctx, s1.ID)
require.NoError(t, err)
assert.Equal(t, s1.ID, got.ID)
assert.Equal(t, s1.InstanceDomain, got.InstanceDomain)
})
}

View File

@ -413,6 +413,10 @@ func scanLicenseAttributes(row pgx.Row) (*LicenseAttributes, error) {
return &attrs, nil
}
// ListEnterpriseSubscriptionLicenses returns a list of enterprise subscription
// license attributes with the given filters. It silently ignores any
// non-matching filters. The caller should check the length of the returned
// slice to ensure all requested licenses were found.
func (r *Reader) ListEnterpriseSubscriptionLicenses(
ctx context.Context,
filters []*subscriptionsv1.ListEnterpriseSubscriptionLicensesFilter,
@ -453,3 +457,37 @@ func (r *Reader) ListEnterpriseSubscriptionLicenses(
}
return attrs, rows.Err()
}
type SubscriptionAttributes struct {
ID string
CreatedAt time.Time
ArchivedAt *time.Time
}
// ListEnterpriseSubscriptions returns a list of enterprise subscription
// attributes with the given IDs. It silently ignores any non-existent
// subscription IDs. The caller should check the length of the returned slice to
// ensure all requested subscriptions were found.
func (r *Reader) ListEnterpriseSubscriptions(ctx context.Context, subscriptionIDs ...string) ([]*SubscriptionAttributes, error) {
if len(subscriptionIDs) == 0 {
return []*SubscriptionAttributes{}, nil
}
query := `SELECT id, created_at, archived_at FROM product_subscriptions WHERE id = ANY(@ids)`
namedArgs := pgx.NamedArgs{"ids": subscriptionIDs}
rows, err := r.db.Query(ctx, query, namedArgs)
if err != nil {
return nil, errors.Wrap(err, "query subscription attributes")
}
defer rows.Close()
var attrs []*SubscriptionAttributes
for rows.Next() {
var attr SubscriptionAttributes
err = rows.Scan(&attr.ID, &attr.CreatedAt, &attr.ArchivedAt)
if err != nil {
return nil, errors.Wrap(err, "scan subscription attributes")
}
attrs = append(attrs, &attr)
}
return attrs, rows.Err()
}

View File

@ -27,10 +27,10 @@ func EnterprisePortalScope(permission scopes.Permission, action scopes.Action) s
return scopes.ToScope(scopes.ServiceEnterprisePortal, permission, action)
}
var tracer = otel.GetTracerProvider().Tracer("telemetry-gateway/samsm2m")
var tracer = otel.GetTracerProvider().Tracer("enterprise-portal/samsm2m")
type TokenIntrospector interface {
IntrospectToken(ctx context.Context, token string) (*sams.IntrospectTokenResponse, error)
IntrospectSAMSToken(ctx context.Context, token string) (*sams.IntrospectTokenResponse, error)
}
type Request interface {
@ -71,7 +71,7 @@ func RequireScope(ctx context.Context, logger log.Logger, tokens TokenIntrospect
// TODO: as part of go/sams-m2m we need to build out a SDK for SAMS M2M
// consumers that has a recommended short-caching mechanism. Avoid doing it
// for now until we have a concerted effort.
result, err := tokens.IntrospectToken(ctx, token)
result, err := tokens.IntrospectSAMSToken(ctx, token)
if err != nil {
return nil, connectutil.InternalError(ctx, logger, err, "unable to validate token")
}

View File

@ -12,6 +12,7 @@ import (
sams "github.com/sourcegraph/sourcegraph-accounts-sdk-go"
"github.com/sourcegraph/sourcegraph-accounts-sdk-go/scopes"
"github.com/sourcegraph/sourcegraph/lib/errors"
)
@ -20,7 +21,7 @@ type mockSAMSClient struct {
error error
}
func (m mockSAMSClient) IntrospectToken(context.Context, string) (*sams.IntrospectTokenResponse, error) {
func (m mockSAMSClient) IntrospectSAMSToken(context.Context, string) (*sams.IntrospectTokenResponse, error) {
return m.result, m.error
}

View File

@ -1,3 +1,5 @@
load("//dev:go_mockgen.bzl", "go_mockgen")
load("//dev:go_defs.bzl", "go_test")
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
@ -19,11 +21,50 @@ go_library(
"//lib/enterpriseportal/subscriptions/v1:subscriptions",
"//lib/enterpriseportal/subscriptions/v1/v1connect",
"//lib/errors",
"//lib/managedservicesplatform/iam",
"//lib/pointers",
"@com_connectrpc_connect//:connect",
"@com_github_sourcegraph_log//:log",
"@com_github_sourcegraph_sourcegraph_accounts_sdk_go//:sourcegraph-accounts-sdk-go",
"@com_github_sourcegraph_sourcegraph_accounts_sdk_go//clients/v1:clients",
"@com_github_sourcegraph_sourcegraph_accounts_sdk_go//scopes",
"@org_golang_google_protobuf//types/known/timestamppb",
"@org_golang_x_exp//maps",
],
)
go_test(
name = "subscriptionsservice_test",
srcs = [
"mocks_test.go",
"v1_test.go",
],
embed = [":subscriptionsservice"],
deps = [
"//cmd/enterprise-portal/internal/database",
"//cmd/enterprise-portal/internal/dotcomdb",
"//cmd/enterprise-portal/internal/samsm2m",
"//lib/enterpriseportal/subscriptions/v1:subscriptions",
"//lib/managedservicesplatform/iam",
"@com_connectrpc_connect//:connect",
"@com_github_derision_test_go_mockgen_v2//testutil/require",
"@com_github_sourcegraph_log//logtest",
"@com_github_sourcegraph_sourcegraph_accounts_sdk_go//:sourcegraph-accounts-sdk-go",
"@com_github_sourcegraph_sourcegraph_accounts_sdk_go//clients/v1:clients",
"@com_github_sourcegraph_sourcegraph_accounts_sdk_go//scopes",
"@com_github_stretchr_testify//assert",
"@com_github_stretchr_testify//require",
"@org_golang_google_protobuf//types/known/fieldmaskpb",
],
)
go_mockgen(
name = "generate_mocks",
out = "mocks_test.go",
manifests = [
"//:mockgen.yaml",
"//:mockgen.test.yaml",
"//:mockgen.temp.yaml",
],
deps = [":subscriptionsservice"],
)

View File

@ -3,8 +3,10 @@ package subscriptionsservice
import (
"google.golang.org/protobuf/types/known/timestamppb"
"github.com/sourcegraph/sourcegraph/cmd/enterprise-portal/internal/database"
"github.com/sourcegraph/sourcegraph/cmd/enterprise-portal/internal/dotcomdb"
subscriptionsv1 "github.com/sourcegraph/sourcegraph/lib/enterpriseportal/subscriptions/v1"
"github.com/sourcegraph/sourcegraph/lib/managedservicesplatform/iam"
"github.com/sourcegraph/sourcegraph/lib/pointers"
)
@ -43,3 +45,42 @@ func convertLicenseAttrsToProto(attrs *dotcomdb.LicenseAttributes) *subscription
},
}
}
func convertSubscriptionToProto(subscription *database.Subscription, attrs *dotcomdb.SubscriptionAttributes) *subscriptionsv1.EnterpriseSubscription {
conds := []*subscriptionsv1.EnterpriseSubscriptionCondition{
{
Status: subscriptionsv1.EnterpriseSubscriptionCondition_STATUS_CREATED,
LastTransitionTime: timestamppb.New(attrs.CreatedAt),
},
}
if attrs.ArchivedAt != nil {
conds = append(conds, &subscriptionsv1.EnterpriseSubscriptionCondition{
Status: subscriptionsv1.EnterpriseSubscriptionCondition_STATUS_ARCHIVED,
LastTransitionTime: timestamppb.New(*attrs.ArchivedAt),
})
}
return &subscriptionsv1.EnterpriseSubscription{
Id: subscriptionsv1.EnterpriseSubscriptionIDPrefix + attrs.ID,
Conditions: conds,
InstanceDomain: subscription.InstanceDomain,
}
}
func convertProtoToIAMTupleObjectType(typ subscriptionsv1.PermissionType) iam.TupleType {
switch typ {
case subscriptionsv1.PermissionType_PERMISSION_TYPE_SUBSCRIPTION_CODY_ANALYTICS:
return iam.TupleTypeSubscriptionCodyAnalytics
default:
panic("unexpected permission type")
}
}
func convertProtoToIAMTupleRelation(action subscriptionsv1.PermissionRelation) iam.TupleRelation {
switch action {
case subscriptionsv1.PermissionRelation_PERMISSION_RELATION_VIEW:
return iam.TupleRelationView
default:
panic("unexpected permission relation")
}
}

File diff suppressed because it is too large Load Diff

View File

@ -3,20 +3,24 @@ package subscriptionsservice
import (
"context"
"net/http"
"strings"
"connectrpc.com/connect"
"github.com/sourcegraph/log"
sams "github.com/sourcegraph/sourcegraph-accounts-sdk-go"
"github.com/sourcegraph/sourcegraph-accounts-sdk-go/scopes"
"golang.org/x/exp/maps"
"github.com/sourcegraph/sourcegraph-accounts-sdk-go/scopes"
"github.com/sourcegraph/sourcegraph/cmd/enterprise-portal/internal/connectutil"
"github.com/sourcegraph/sourcegraph/cmd/enterprise-portal/internal/dotcomdb"
"github.com/sourcegraph/sourcegraph/cmd/enterprise-portal/internal/samsm2m"
"github.com/sourcegraph/sourcegraph/internal/trace"
subscriptionsv1 "github.com/sourcegraph/sourcegraph/lib/enterpriseportal/subscriptions/v1"
subscriptionsv1connect "github.com/sourcegraph/sourcegraph/lib/enterpriseportal/subscriptions/v1/v1connect"
"github.com/sourcegraph/sourcegraph/lib/errors"
"github.com/sourcegraph/sourcegraph/lib/managedservicesplatform/iam"
"github.com/sourcegraph/sourcegraph/cmd/enterprise-portal/internal/connectutil"
"github.com/sourcegraph/sourcegraph/cmd/enterprise-portal/internal/database"
"github.com/sourcegraph/sourcegraph/cmd/enterprise-portal/internal/dotcomdb"
"github.com/sourcegraph/sourcegraph/cmd/enterprise-portal/internal/samsm2m"
"github.com/sourcegraph/sourcegraph/internal/trace"
)
const Name = subscriptionsv1connect.SubscriptionsServiceName
@ -24,16 +28,14 @@ const Name = subscriptionsv1connect.SubscriptionsServiceName
func RegisterV1(
logger log.Logger,
mux *http.ServeMux,
samsClient samsm2m.TokenIntrospector,
store StoreV1,
opts ...connect.HandlerOption,
) {
mux.Handle(
subscriptionsv1connect.NewSubscriptionsServiceHandler(
&handlerV1{
logger: logger.Scoped("subscriptions.v1"),
samsClient: samsClient,
store: store,
logger: logger.Scoped("subscriptions.v1"),
store: store,
},
opts...,
),
@ -43,19 +45,167 @@ func RegisterV1(
type handlerV1 struct {
subscriptionsv1connect.UnimplementedSubscriptionsServiceHandler
logger log.Logger
samsClient samsm2m.TokenIntrospector
store StoreV1
logger log.Logger
store StoreV1
}
var _ subscriptionsv1connect.SubscriptionsServiceHandler = (*handlerV1)(nil)
func (s *handlerV1) ListEnterpriseSubscriptions(ctx context.Context, req *connect.Request[subscriptionsv1.ListEnterpriseSubscriptionsRequest]) (*connect.Response[subscriptionsv1.ListEnterpriseSubscriptionsResponse], error) {
logger := trace.Logger(ctx, s.logger)
// 🚨 SECURITY: Require appropriate M2M scope.
requiredScope := samsm2m.EnterprisePortalScope("subscription", scopes.ActionRead)
clientAttrs, err := samsm2m.RequireScope(ctx, logger, s.store, requiredScope, req)
if err != nil {
return nil, err
}
logger = logger.With(clientAttrs...)
// Pagination is unimplemented (https://linear.app/sourcegraph/issue/CORE-134),
// but we do want to allow pageSize to act as a 'limit' parameter for querying
// product subscriptions.
if req.Msg.PageToken != "" {
return nil, connect.NewError(connect.CodeUnimplemented, errors.New("pagination not implemented"))
}
// Validate and process filters.
filters := req.Msg.GetFilters()
if len(filters) == 0 {
return nil, connect.NewError(connect.CodeInvalidArgument, errors.New("at least one filter is required"))
}
onlyArchived := false
subscriptionIDs := make([]string, 0, len(filters))
var iamListObjectOptions *iam.ListObjectsOptions
for _, filter := range filters {
switch f := filter.GetFilter().(type) {
case *subscriptionsv1.ListEnterpriseSubscriptionsFilter_SubscriptionId:
if f.SubscriptionId == "" {
return nil, connect.NewError(
connect.CodeInvalidArgument,
errors.New(`invalid filter: "subscription_id" provided but is empty`),
)
}
subscriptionIDs = append(
subscriptionIDs,
strings.TrimPrefix(f.SubscriptionId, subscriptionsv1.EnterpriseSubscriptionIDPrefix),
)
case *subscriptionsv1.ListEnterpriseSubscriptionsFilter_IsArchived:
onlyArchived = f.IsArchived
case *subscriptionsv1.ListEnterpriseSubscriptionsFilter_Permission:
if f.Permission == nil {
return nil, connect.NewError(
connect.CodeInvalidArgument,
errors.New(`invalid filter: "permission" provided but is empty`),
)
} else if f.Permission.Type == subscriptionsv1.PermissionType_PERMISSION_TYPE_UNSPECIFIED {
return nil, connect.NewError(
connect.CodeInvalidArgument,
errors.New(`invalid filter: "permission" provided but "type" is unspecified`),
)
} else if f.Permission.Relation == subscriptionsv1.PermissionRelation_PERMISSION_RELATION_UNSPECIFIED {
return nil, connect.NewError(
connect.CodeInvalidArgument,
errors.New(`invalid filter: "permission" provided but "relation" is unspecified`),
)
} else if f.Permission.SamsAccountId == "" {
return nil, connect.NewError(
connect.CodeInvalidArgument,
errors.New(`invalid filter: "permission" provided but "sams_account_id" is empty`),
)
}
if iamListObjectOptions != nil {
return nil, connect.NewError(
connect.CodeInvalidArgument,
errors.New(`invalid filter: "permission" can only be provided once`),
)
}
iamListObjectOptions = &iam.ListObjectsOptions{
Type: convertProtoToIAMTupleObjectType(f.Permission.Type),
Relation: convertProtoToIAMTupleRelation(f.Permission.Relation),
Subject: iam.ToTupleSubjectUser(f.Permission.SamsAccountId),
}
}
}
// When requested, overwrite subscription IDs with those that have the required
// permissions. This makes logical sense because even if a subscription ID is
// provided, because it may not be accessible by the subject (and thus be
// excluded from the response).
if iamListObjectOptions != nil {
// Object IDs are in the form of `subscription_cody_analytics:<subscriptionID>`.
objectIDs, err := s.store.IAMListObjects(ctx, *iamListObjectOptions)
if err != nil {
return nil, connectutil.InternalError(ctx, logger, err, "list subscriptions from IAM")
}
// 🚨 SECURITY: If permissions are used as filter, but we found no results, we
// should directly return an empty response to not mistaken as list all.
if len(objectIDs) == 0 {
return connect.NewResponse(&subscriptionsv1.ListEnterpriseSubscriptionsResponse{}), nil
}
subscriptionIDs = make([]string, 0, len(objectIDs))
for _, objectID := range objectIDs {
subscriptionIDs = append(subscriptionIDs, strings.TrimPrefix(objectID, "subscription_cody_analytics:"))
}
}
subscriptions, err := s.store.ListEnterpriseSubscriptions(
ctx,
database.ListEnterpriseSubscriptionsOptions{
IDs: subscriptionIDs,
OnlyArchived: onlyArchived,
PageSize: int(req.Msg.GetPageSize()),
},
)
if err != nil {
return nil, connectutil.InternalError(ctx, logger, err, "list subscriptions")
}
// List from dotcom DB and merge attributes.
dotcomSubscriptions, err := s.store.ListDotcomEnterpriseSubscriptions(ctx, subscriptionIDs...)
if err != nil {
return nil, connectutil.InternalError(ctx, logger, err, "list subscriptions from dotcom DB")
}
dotcomSubscriptionsSet := make(map[string]*dotcomdb.SubscriptionAttributes, len(dotcomSubscriptions))
for _, s := range dotcomSubscriptions {
dotcomSubscriptionsSet[s.ID] = s
}
respSubscriptions := make([]*subscriptionsv1.EnterpriseSubscription, 0, len(subscriptions))
for _, s := range subscriptions {
respSubscriptions = append(
respSubscriptions,
convertSubscriptionToProto(s, dotcomSubscriptionsSet[s.ID]),
)
}
accessedSubscriptions := map[string]struct{}{}
for _, s := range respSubscriptions {
accessedSubscriptions[s.GetId()] = struct{}{}
}
logger.Scoped("audit").Info("ListEnterpriseSubscriptions",
log.Strings("accessedSubscriptions", maps.Keys(accessedSubscriptions)),
)
return connect.NewResponse(
&subscriptionsv1.ListEnterpriseSubscriptionsResponse{
// Never a next page, pagination is not implemented yet:
// https://linear.app/sourcegraph/issue/CORE-134
NextPageToken: "",
Subscriptions: respSubscriptions,
},
), nil
}
func (s *handlerV1) ListEnterpriseSubscriptionLicenses(ctx context.Context, req *connect.Request[subscriptionsv1.ListEnterpriseSubscriptionLicensesRequest]) (*connect.Response[subscriptionsv1.ListEnterpriseSubscriptionLicensesResponse], error) {
logger := trace.Logger(ctx, s.logger)
// 🚨 SECURITY: Require appropriate M2M scope.
requiredScope := samsm2m.EnterprisePortalScope("subscription", scopes.ActionRead)
clientAttrs, err := samsm2m.RequireScope(ctx, logger, s.samsClient, requiredScope, req)
clientAttrs, err := samsm2m.RequireScope(ctx, logger, s.store, requiredScope, req)
if err != nil {
return nil, err
}
@ -86,19 +236,22 @@ func (s *handlerV1) ListEnterpriseSubscriptionLicenses(ctx context.Context, req
errors.New("filtering by license key substring is not implemented"))
case *subscriptionsv1.ListEnterpriseSubscriptionLicensesFilter_SubscriptionId:
if f.SubscriptionId == "" {
return nil, connect.NewError(connect.CodeInvalidArgument, errors.New("invalid query: access token"))
return nil, connect.NewError(
connect.CodeInvalidArgument,
errors.New(`invalid filter: "subscription_id"" provided but is empty`),
)
}
case *subscriptionsv1.ListEnterpriseSubscriptionLicensesFilter_IsArchived:
// Nothing to validate
}
}
licenses, err := s.store.ListEnterpriseSubscriptionLicenses(ctx, filters,
licenses, err := s.store.ListDotcomEnterpriseSubscriptionLicenses(ctx, filters,
// Provide page size to allow "active license" functionality, by only
// retrieving the most recently created result.
int(req.Msg.GetPageSize()))
if err != nil {
if err == dotcomdb.ErrCodyGatewayAccessNotFound {
if errors.Is(err, dotcomdb.ErrCodyGatewayAccessNotFound) {
return nil, connect.NewError(connect.CodeNotFound, err)
}
return nil, connectutil.InternalError(ctx, logger, err,
@ -124,3 +277,173 @@ func (s *handlerV1) ListEnterpriseSubscriptionLicenses(ctx context.Context, req
log.Strings("accessedLicenses", accessedLicenses))
return connect.NewResponse(&resp), nil
}
func (s *handlerV1) UpdateEnterpriseSubscription(ctx context.Context, req *connect.Request[subscriptionsv1.UpdateEnterpriseSubscriptionRequest]) (*connect.Response[subscriptionsv1.UpdateEnterpriseSubscriptionResponse], error) {
logger := trace.Logger(ctx, s.logger)
// 🚨 SECURITY: Require appropriate M2M scope.
requiredScope := samsm2m.EnterprisePortalScope("subscription", scopes.ActionWrite)
clientAttrs, err := samsm2m.RequireScope(ctx, logger, s.store, requiredScope, req)
if err != nil {
return nil, err
}
logger = logger.With(clientAttrs...)
subscriptionID := strings.TrimPrefix(req.Msg.GetSubscription().GetId(), subscriptionsv1.EnterpriseSubscriptionIDPrefix)
if subscriptionID == "" {
return nil, connect.NewError(connect.CodeInvalidArgument, errors.New("subscription.id is required"))
}
// Double check with the dotcom DB that the subscription ID is valid.
subscriptionAttrs, err := s.store.ListDotcomEnterpriseSubscriptions(ctx, subscriptionID)
if err != nil {
return nil, connectutil.InternalError(ctx, logger, err, "get dotcom enterprise subscription")
} else if len(subscriptionAttrs) != 1 {
return nil, connect.NewError(connect.CodeNotFound, errors.New("subscription not found"))
}
var opts database.UpsertSubscriptionOptions
fieldPaths := req.Msg.GetUpdateMask().GetPaths()
// Empty field paths means update all non-empty fields.
if len(fieldPaths) == 0 {
if v := req.Msg.GetSubscription().GetInstanceDomain(); v != "" {
opts.InstanceDomain = v
}
} else {
for _, p := range fieldPaths {
switch p {
case "instance_domain":
opts.InstanceDomain = req.Msg.GetSubscription().GetInstanceDomain()
case "*":
opts.ForceUpdate = true
opts.InstanceDomain = req.Msg.GetSubscription().GetInstanceDomain()
}
}
}
subscription, err := s.store.UpsertEnterpriseSubscription(ctx, subscriptionID, opts)
if err != nil {
return nil, connectutil.InternalError(ctx, logger, err, "upsert subscription")
}
respSubscription := convertSubscriptionToProto(subscription, subscriptionAttrs[0])
logger.Scoped("audit").Info("UpdateEnterpriseSubscription",
log.String("updatedSubscription", respSubscription.GetId()),
)
return connect.NewResponse(
&subscriptionsv1.UpdateEnterpriseSubscriptionResponse{
Subscription: respSubscription,
},
), nil
}
func (s *handlerV1) UpdateEnterpriseSubscriptionMembership(ctx context.Context, req *connect.Request[subscriptionsv1.UpdateEnterpriseSubscriptionMembershipRequest]) (*connect.Response[subscriptionsv1.UpdateEnterpriseSubscriptionMembershipResponse], error) {
logger := trace.Logger(ctx, s.logger)
// 🚨 SECURITY: Require appropriate M2M scope.
requiredScope := samsm2m.EnterprisePortalScope("permission.subscription", scopes.ActionWrite)
clientAttrs, err := samsm2m.RequireScope(ctx, logger, s.store, requiredScope, req)
if err != nil {
return nil, err
}
logger = logger.With(clientAttrs...)
samsAccountID := req.Msg.GetMembership().GetMemberSamsAccountId()
if samsAccountID == "" {
return nil, connect.NewError(connect.CodeInvalidArgument, errors.New("membership.member_sams_account_id is required"))
}
_, err = s.store.GetSAMSUserByID(ctx, samsAccountID)
if err != nil {
if errors.Is(err, sams.ErrNotFound) {
return nil, connect.NewError(connect.CodeNotFound, errors.New("SAMS user not found"))
}
return nil, connectutil.InternalError(ctx, logger, err, "get SAMS user by ID")
}
subscriptionID := strings.TrimPrefix(req.Msg.GetMembership().GetSubscriptionId(), subscriptionsv1.EnterpriseSubscriptionIDPrefix)
instanceDomain := req.Msg.GetMembership().GetInstanceDomain()
if subscriptionID == "" && instanceDomain == "" {
return nil, connect.NewError(
connect.CodeInvalidArgument,
errors.New("either membership.subscription_id or membership.instance_domain must be specified"),
)
}
if subscriptionID != "" {
// Double check with the dotcom DB that the subscription ID is valid.
subscriptionAttrs, err := s.store.ListDotcomEnterpriseSubscriptions(ctx, subscriptionID)
if err != nil {
return nil, connectutil.InternalError(ctx, logger, err, "get dotcom enterprise subscription")
} else if len(subscriptionAttrs) != 1 {
return nil, connect.NewError(connect.CodeNotFound, errors.New("subscription not found"))
}
} else if instanceDomain != "" {
subscriptions, err := s.store.ListEnterpriseSubscriptions(
ctx,
database.ListEnterpriseSubscriptionsOptions{
InstanceDomains: []string{instanceDomain},
PageSize: 1,
},
)
if err != nil {
return nil, connectutil.InternalError(ctx, logger, err, "list subscriptions")
} else if len(subscriptions) != 1 {
return nil, connect.NewError(connect.CodeNotFound, errors.New("subscription not found"))
}
subscriptionID = subscriptions[0].ID
}
roles := req.Msg.GetMembership().GetMemberRoles()
writes := make([]iam.TupleKey, 0, len(roles))
for _, role := range roles {
switch role {
case subscriptionsv1.Role_ROLE_SUBSCRIPTION_CODY_ANALYTICS_CUSTOMER_ADMIN:
// Subscription cody analytics customer admin can:
// - View cody analytics of the subscription
// Make sure the customer_admin role is created for the subscription.
tk := iam.TupleKey{
Object: iam.ToTupleObject(iam.TupleTypeSubscriptionCodyAnalytics, subscriptionID),
TupleRelation: iam.TupleRelationView,
Subject: iam.ToTupleSubjectCustomerAdmin(subscriptionID, iam.TupleRelationMember),
}
allowed, err := s.store.IAMCheck(ctx, iam.CheckOptions{TupleKey: tk})
if err != nil {
return nil, connectutil.InternalError(ctx, logger, err, "check relation tuple in IAM")
}
if !allowed {
writes = append(writes, tk)
}
// Add the user as a member of the customer_admin role of the subscription.
tk = iam.TupleKey{
Object: iam.ToTupleObject(iam.TupleTypeCustomerAdmin, subscriptionID),
TupleRelation: iam.TupleRelationMember,
Subject: iam.ToTupleSubjectUser(samsAccountID),
}
allowed, err = s.store.IAMCheck(ctx, iam.CheckOptions{TupleKey: tk})
if err != nil {
return nil, connectutil.InternalError(ctx, logger, err, "check relation tuple in IAM")
}
if !allowed {
writes = append(writes, tk)
}
default:
return nil, connect.NewError(connect.CodeInvalidArgument, errors.Errorf("invalid role: %s", role))
}
}
err = s.store.IAMWrite(
ctx,
iam.WriteOptions{
Writes: writes,
},
)
if err != nil {
return nil, connectutil.InternalError(ctx, logger, err, "write relation tuples to IAM")
}
return connect.NewResponse(&subscriptionsv1.UpdateEnterpriseSubscriptionMembershipResponse{}), nil
}

View File

@ -3,36 +3,114 @@ package subscriptionsservice
import (
"context"
sams "github.com/sourcegraph/sourcegraph-accounts-sdk-go"
clientsv1 "github.com/sourcegraph/sourcegraph-accounts-sdk-go/clients/v1"
"github.com/sourcegraph/sourcegraph/cmd/enterprise-portal/internal/database"
"github.com/sourcegraph/sourcegraph/cmd/enterprise-portal/internal/dotcomdb"
subscriptionsv1 "github.com/sourcegraph/sourcegraph/lib/enterpriseportal/subscriptions/v1"
"github.com/sourcegraph/sourcegraph/lib/managedservicesplatform/iam"
)
// StoreV1 is the data layer carrier for subscriptions service v1. This interface
// is meant to abstract away and limit the exposure of the underlying data layer
// to the handler through a thin-wrapper.
type StoreV1 interface {
ListEnterpriseSubscriptionLicenses(context.Context, []*subscriptionsv1.ListEnterpriseSubscriptionLicensesFilter, int) ([]*dotcomdb.LicenseAttributes, error)
// UpsertEnterpriseSubscription upserts a enterprise subscription record based
// on the given options.
UpsertEnterpriseSubscription(ctx context.Context, subscriptionID string, opts database.UpsertSubscriptionOptions) (*database.Subscription, error)
// ListEnterpriseSubscriptions returns a list of enterprise subscriptions based
// on the given options.
ListEnterpriseSubscriptions(ctx context.Context, opts database.ListEnterpriseSubscriptionsOptions) ([]*database.Subscription, error)
// ListDotcomEnterpriseSubscriptionLicenses returns a list of enterprise
// subscription license attributes with the given filters. It silently ignores
// any non-matching filters. The caller should check the length of the returned
// slice to ensure all requested licenses were found.
ListDotcomEnterpriseSubscriptionLicenses(context.Context, []*subscriptionsv1.ListEnterpriseSubscriptionLicensesFilter, int) ([]*dotcomdb.LicenseAttributes, error)
// ListDotcomEnterpriseSubscriptions returns a list of enterprise subscription
// attributes with the given IDs from dotcom DB. It silently ignores any
// non-existent subscription IDs. The caller should check the length of the
// returned slice to ensure all requested subscriptions were found.
ListDotcomEnterpriseSubscriptions(ctx context.Context, subscriptionIDs ...string) ([]*dotcomdb.SubscriptionAttributes, error)
// IntrospectSAMSToken takes a SAMS access token and returns relevant metadata.
//
// 🚨SECURITY: SAMS will return a successful result if the token is valid, but
// is no longer active. It is critical that the caller not honor tokens where
// `.Active == false`.
IntrospectSAMSToken(ctx context.Context, token string) (*sams.IntrospectTokenResponse, error)
// GetSAMSUserByID returns the SAMS user with the given ID. It returns
// sams.ErrNotFound if no such user exists.
//
// Required scope: profile
GetSAMSUserByID(ctx context.Context, id string) (*clientsv1.User, error)
// IAMListObjects returns a list of object IDs that satisfy the given options.
IAMListObjects(ctx context.Context, opts iam.ListObjectsOptions) ([]string, error)
// IAMWrite adds, updates, and/or deletes the IAM relation tuples.
IAMWrite(ctx context.Context, opts iam.WriteOptions) error
// IAMCheck checks whether a relationship exists (thus permission allowed) using
// the given tuple key as the check condition.
IAMCheck(ctx context.Context, opts iam.CheckOptions) (allowed bool, _ error)
}
type storeV1 struct {
db *database.DB
dotcomDB *dotcomdb.Reader
db *database.DB
dotcomDB *dotcomdb.Reader
SAMSClient *sams.ClientV1
IAMClient *iam.ClientV1
}
type NewStoreV1Options struct {
DB *database.DB
DotcomDB *dotcomdb.Reader
DB *database.DB
DotcomDB *dotcomdb.Reader
SAMSClient *sams.ClientV1
IAMClient *iam.ClientV1
}
// NewStoreV1 returns a new StoreV1 using the given client and database handles.
// NewStoreV1 returns a new StoreV1 using the given resource handles.
func NewStoreV1(opts NewStoreV1Options) StoreV1 {
return &storeV1{
db: opts.DB,
dotcomDB: opts.DotcomDB,
db: opts.DB,
dotcomDB: opts.DotcomDB,
SAMSClient: opts.SAMSClient,
IAMClient: opts.IAMClient,
}
}
func (s *storeV1) ListEnterpriseSubscriptionLicenses(ctx context.Context, filters []*subscriptionsv1.ListEnterpriseSubscriptionLicensesFilter, limit int) ([]*dotcomdb.LicenseAttributes, error) {
func (s *storeV1) UpsertEnterpriseSubscription(ctx context.Context, subscriptionID string, opts database.UpsertSubscriptionOptions) (*database.Subscription, error) {
return s.db.Subscriptions().Upsert(ctx, subscriptionID, opts)
}
func (s *storeV1) ListEnterpriseSubscriptions(ctx context.Context, opts database.ListEnterpriseSubscriptionsOptions) ([]*database.Subscription, error) {
return s.db.Subscriptions().List(ctx, opts)
}
func (s *storeV1) ListDotcomEnterpriseSubscriptionLicenses(ctx context.Context, filters []*subscriptionsv1.ListEnterpriseSubscriptionLicensesFilter, limit int) ([]*dotcomdb.LicenseAttributes, error) {
return s.dotcomDB.ListEnterpriseSubscriptionLicenses(ctx, filters, limit)
}
func (s *storeV1) ListDotcomEnterpriseSubscriptions(ctx context.Context, subscriptionIDs ...string) ([]*dotcomdb.SubscriptionAttributes, error) {
return s.dotcomDB.ListEnterpriseSubscriptions(ctx, subscriptionIDs...)
}
func (s *storeV1) IntrospectSAMSToken(ctx context.Context, token string) (*sams.IntrospectTokenResponse, error) {
return s.SAMSClient.Tokens().IntrospectToken(ctx, token)
}
func (s *storeV1) GetSAMSUserByID(ctx context.Context, id string) (*clientsv1.User, error) {
return s.SAMSClient.Users().GetUserByID(ctx, id)
}
func (s *storeV1) IAMListObjects(ctx context.Context, opts iam.ListObjectsOptions) ([]string, error) {
return s.IAMClient.ListObjects(ctx, opts)
}
func (s *storeV1) IAMWrite(ctx context.Context, opts iam.WriteOptions) error {
return s.IAMClient.Write(ctx, opts)
}
func (s *storeV1) IAMCheck(ctx context.Context, opts iam.CheckOptions) (allowed bool, _ error) {
return s.IAMClient.Check(ctx, opts)
}

View File

@ -0,0 +1,312 @@
package subscriptionsservice
import (
"context"
"testing"
"connectrpc.com/connect"
mockrequire "github.com/derision-test/go-mockgen/v2/testutil/require"
"github.com/sourcegraph/log/logtest"
sams "github.com/sourcegraph/sourcegraph-accounts-sdk-go"
"github.com/sourcegraph/sourcegraph-accounts-sdk-go/scopes"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"google.golang.org/protobuf/types/known/fieldmaskpb"
"github.com/sourcegraph/sourcegraph/cmd/enterprise-portal/internal/database"
"github.com/sourcegraph/sourcegraph/cmd/enterprise-portal/internal/dotcomdb"
"github.com/sourcegraph/sourcegraph/cmd/enterprise-portal/internal/samsm2m"
subscriptionsv1 "github.com/sourcegraph/sourcegraph/lib/enterpriseportal/subscriptions/v1"
"github.com/sourcegraph/sourcegraph/lib/managedservicesplatform/iam"
)
type testHandlerV1 struct {
*handlerV1
mockStore *MockStoreV1
}
func newTestHandlerV1() *testHandlerV1 {
mockStore := NewMockStoreV1()
mockStore.IntrospectSAMSTokenFunc.SetDefaultReturn(
&sams.IntrospectTokenResponse{
Active: true,
Scopes: scopes.Scopes{
samsm2m.EnterprisePortalScope("subscription", scopes.ActionRead),
samsm2m.EnterprisePortalScope("subscription", scopes.ActionWrite),
samsm2m.EnterprisePortalScope("permission.subscription", scopes.ActionWrite),
},
},
nil,
)
return &testHandlerV1{
handlerV1: &handlerV1{
logger: logtest.NoOp(nil),
store: mockStore,
},
mockStore: mockStore,
}
}
func TestHandlerV1_ListEnterpriseSubscriptions(t *testing.T) {
ctx := context.Background()
t.Run("more than one permission filter", func(t *testing.T) {
req := connect.NewRequest(&subscriptionsv1.ListEnterpriseSubscriptionsRequest{
Filters: []*subscriptionsv1.ListEnterpriseSubscriptionsFilter{
{Filter: &subscriptionsv1.ListEnterpriseSubscriptionsFilter_Permission{
Permission: &subscriptionsv1.Permission{
Type: subscriptionsv1.PermissionType_PERMISSION_TYPE_SUBSCRIPTION_CODY_ANALYTICS,
Relation: subscriptionsv1.PermissionRelation_PERMISSION_RELATION_VIEW,
SamsAccountId: "018d21f2-04a6-7aaf-9f6f-6fc58c4187b9",
},
}},
{Filter: &subscriptionsv1.ListEnterpriseSubscriptionsFilter_Permission{
Permission: &subscriptionsv1.Permission{
Type: subscriptionsv1.PermissionType_PERMISSION_TYPE_SUBSCRIPTION_CODY_ANALYTICS,
Relation: subscriptionsv1.PermissionRelation_PERMISSION_RELATION_VIEW,
SamsAccountId: "018d21f2-0b8d-756a-84f0-13b942a2bae5",
},
}},
},
})
req.Header().Add("Authorization", "Bearer foolmeifyoucan")
h := newTestHandlerV1()
_, err := h.ListEnterpriseSubscriptions(ctx, req)
require.EqualError(t, err, `invalid_argument: invalid filter: "permission" can only be provided once`)
})
t.Run("only subscription ID filter", func(t *testing.T) {
req := connect.NewRequest(&subscriptionsv1.ListEnterpriseSubscriptionsRequest{
Filters: []*subscriptionsv1.ListEnterpriseSubscriptionsFilter{
{Filter: &subscriptionsv1.ListEnterpriseSubscriptionsFilter_SubscriptionId{
SubscriptionId: "80ca12e2-54b4-448c-a61a-390b1a9c1224",
}},
},
})
req.Header().Add("Authorization", "Bearer foolmeifyoucan")
h := newTestHandlerV1()
h.mockStore.ListEnterpriseSubscriptionsFunc.SetDefaultHook(func(_ context.Context, opts database.ListEnterpriseSubscriptionsOptions) ([]*database.Subscription, error) {
require.Len(t, opts.IDs, 1)
assert.Equal(t, "80ca12e2-54b4-448c-a61a-390b1a9c1224", opts.IDs[0])
return []*database.Subscription{}, nil
})
_, err := h.ListEnterpriseSubscriptions(ctx, req)
require.NoError(t, err)
mockrequire.Called(t, h.mockStore.ListEnterpriseSubscriptionsFunc)
})
t.Run("only permission filter", func(t *testing.T) {
req := connect.NewRequest(&subscriptionsv1.ListEnterpriseSubscriptionsRequest{
Filters: []*subscriptionsv1.ListEnterpriseSubscriptionsFilter{
{Filter: &subscriptionsv1.ListEnterpriseSubscriptionsFilter_Permission{
Permission: &subscriptionsv1.Permission{
Type: subscriptionsv1.PermissionType_PERMISSION_TYPE_SUBSCRIPTION_CODY_ANALYTICS,
Relation: subscriptionsv1.PermissionRelation_PERMISSION_RELATION_VIEW,
SamsAccountId: "018d21f2-04a6-7aaf-9f6f-6fc58c4187b9",
},
}},
},
})
req.Header().Add("Authorization", "Bearer foolmeifyoucan")
h := newTestHandlerV1()
h.mockStore.IAMListObjectsFunc.SetDefaultReturn([]string{"subscription_cody_analytics:80ca12e2-54b4-448c-a61a-390b1a9c1224"}, nil)
h.mockStore.ListEnterpriseSubscriptionsFunc.SetDefaultHook(func(_ context.Context, opts database.ListEnterpriseSubscriptionsOptions) ([]*database.Subscription, error) {
require.Len(t, opts.IDs, 1)
assert.Equal(t, "80ca12e2-54b4-448c-a61a-390b1a9c1224", opts.IDs[0])
return []*database.Subscription{}, nil
})
_, err := h.ListEnterpriseSubscriptions(ctx, req)
require.NoError(t, err)
mockrequire.Called(t, h.mockStore.ListEnterpriseSubscriptionsFunc)
})
t.Run("both subscription ID and permission filter", func(t *testing.T) {
req := connect.NewRequest(&subscriptionsv1.ListEnterpriseSubscriptionsRequest{
Filters: []*subscriptionsv1.ListEnterpriseSubscriptionsFilter{
{Filter: &subscriptionsv1.ListEnterpriseSubscriptionsFilter_Permission{
Permission: &subscriptionsv1.Permission{
Type: subscriptionsv1.PermissionType_PERMISSION_TYPE_SUBSCRIPTION_CODY_ANALYTICS,
Relation: subscriptionsv1.PermissionRelation_PERMISSION_RELATION_VIEW,
SamsAccountId: "018d21f2-04a6-7aaf-9f6f-6fc58c4187b9",
},
}},
{Filter: &subscriptionsv1.ListEnterpriseSubscriptionsFilter_SubscriptionId{
SubscriptionId: "80ca12e2-54b4-448c-a61a-390b1a9c1224",
}},
},
})
req.Header().Add("Authorization", "Bearer foolmeifyoucan")
h := newTestHandlerV1()
h.mockStore.IAMListObjectsFunc.SetDefaultReturn([]string{"subscription_cody_analytics:a-different-subscription-id"}, nil)
h.mockStore.ListEnterpriseSubscriptionsFunc.SetDefaultHook(func(_ context.Context, opts database.ListEnterpriseSubscriptionsOptions) ([]*database.Subscription, error) {
require.Len(t, opts.IDs, 1)
assert.Equal(t, "a-different-subscription-id", opts.IDs[0])
return []*database.Subscription{}, nil
})
_, err := h.ListEnterpriseSubscriptions(ctx, req)
require.NoError(t, err)
mockrequire.Called(t, h.mockStore.ListEnterpriseSubscriptionsFunc)
})
t.Run("permission filter with no results", func(t *testing.T) {
req := connect.NewRequest(&subscriptionsv1.ListEnterpriseSubscriptionsRequest{
Filters: []*subscriptionsv1.ListEnterpriseSubscriptionsFilter{
{Filter: &subscriptionsv1.ListEnterpriseSubscriptionsFilter_Permission{
Permission: &subscriptionsv1.Permission{
Type: subscriptionsv1.PermissionType_PERMISSION_TYPE_SUBSCRIPTION_CODY_ANALYTICS,
Relation: subscriptionsv1.PermissionRelation_PERMISSION_RELATION_VIEW,
SamsAccountId: "018d21f2-04a6-7aaf-9f6f-6fc58c4187b9",
},
}},
{Filter: &subscriptionsv1.ListEnterpriseSubscriptionsFilter_SubscriptionId{
SubscriptionId: "80ca12e2-54b4-448c-a61a-390b1a9c1224",
}},
},
})
req.Header().Add("Authorization", "Bearer foolmeifyoucan")
h := newTestHandlerV1()
h.mockStore.IAMListObjectsFunc.SetDefaultReturn([]string{}, nil)
resp, err := h.ListEnterpriseSubscriptions(ctx, req)
require.NoError(t, err)
assert.Nil(t, resp.Msg.Subscriptions)
})
}
func TestHandlerV1_UpdateEnterpriseSubscription(t *testing.T) {
ctx := context.Background()
t.Run("no update_mask", func(t *testing.T) {
req := connect.NewRequest(&subscriptionsv1.UpdateEnterpriseSubscriptionRequest{
Subscription: &subscriptionsv1.EnterpriseSubscription{
Id: "80ca12e2-54b4-448c-a61a-390b1a9c1224",
InstanceDomain: "s1.sourcegraph.com",
},
UpdateMask: nil,
})
req.Header().Add("Authorization", "Bearer foolmeifyoucan")
h := newTestHandlerV1()
h.mockStore.ListDotcomEnterpriseSubscriptionsFunc.SetDefaultReturn([]*dotcomdb.SubscriptionAttributes{{ID: "80ca12e2-54b4-448c-a61a-390b1a9c1224"}}, nil)
h.mockStore.UpsertEnterpriseSubscriptionFunc.SetDefaultHook(func(_ context.Context, _ string, opts database.UpsertSubscriptionOptions) (*database.Subscription, error) {
assert.NotEmpty(t, opts.InstanceDomain)
assert.False(t, opts.ForceUpdate)
return &database.Subscription{}, nil
})
_, err := h.UpdateEnterpriseSubscription(ctx, req)
require.NoError(t, err)
mockrequire.Called(t, h.mockStore.UpsertEnterpriseSubscriptionFunc)
})
t.Run("specified update_mask", func(t *testing.T) {
req := connect.NewRequest(&subscriptionsv1.UpdateEnterpriseSubscriptionRequest{
Subscription: &subscriptionsv1.EnterpriseSubscription{
Id: "80ca12e2-54b4-448c-a61a-390b1a9c1224",
InstanceDomain: "s1.sourcegraph.com",
},
UpdateMask: &fieldmaskpb.FieldMask{Paths: []string{"instance_domain"}},
})
req.Header().Add("Authorization", "Bearer foolmeifyoucan")
h := newTestHandlerV1()
h.mockStore.ListDotcomEnterpriseSubscriptionsFunc.SetDefaultReturn([]*dotcomdb.SubscriptionAttributes{{ID: "80ca12e2-54b4-448c-a61a-390b1a9c1224"}}, nil)
h.mockStore.UpsertEnterpriseSubscriptionFunc.SetDefaultHook(func(_ context.Context, _ string, opts database.UpsertSubscriptionOptions) (*database.Subscription, error) {
assert.NotEmpty(t, opts.InstanceDomain)
assert.False(t, opts.ForceUpdate)
return &database.Subscription{}, nil
})
_, err := h.UpdateEnterpriseSubscription(ctx, req)
require.NoError(t, err)
mockrequire.Called(t, h.mockStore.UpsertEnterpriseSubscriptionFunc)
})
t.Run("* update_mask", func(t *testing.T) {
req := connect.NewRequest(&subscriptionsv1.UpdateEnterpriseSubscriptionRequest{
Subscription: &subscriptionsv1.EnterpriseSubscription{
Id: "80ca12e2-54b4-448c-a61a-390b1a9c1224",
InstanceDomain: "",
},
UpdateMask: &fieldmaskpb.FieldMask{Paths: []string{"*"}},
})
req.Header().Add("Authorization", "Bearer foolmeifyoucan")
h := newTestHandlerV1()
h.mockStore.ListDotcomEnterpriseSubscriptionsFunc.SetDefaultReturn([]*dotcomdb.SubscriptionAttributes{{ID: "80ca12e2-54b4-448c-a61a-390b1a9c1224"}}, nil)
h.mockStore.UpsertEnterpriseSubscriptionFunc.SetDefaultHook(func(_ context.Context, _ string, opts database.UpsertSubscriptionOptions) (*database.Subscription, error) {
assert.Empty(t, opts.InstanceDomain)
assert.True(t, opts.ForceUpdate)
return &database.Subscription{}, nil
})
_, err := h.UpdateEnterpriseSubscription(ctx, req)
require.NoError(t, err)
mockrequire.Called(t, h.mockStore.UpsertEnterpriseSubscriptionFunc)
})
t.Run("noop update", func(t *testing.T) {
req := connect.NewRequest(&subscriptionsv1.UpdateEnterpriseSubscriptionRequest{
Subscription: &subscriptionsv1.EnterpriseSubscription{
Id: "80ca12e2-54b4-448c-a61a-390b1a9c1224",
InstanceDomain: "",
},
})
req.Header().Add("Authorization", "Bearer foolmeifyoucan")
h := newTestHandlerV1()
h.mockStore.ListDotcomEnterpriseSubscriptionsFunc.SetDefaultReturn([]*dotcomdb.SubscriptionAttributes{{ID: "80ca12e2-54b4-448c-a61a-390b1a9c1224"}}, nil)
h.mockStore.UpsertEnterpriseSubscriptionFunc.SetDefaultHook(func(_ context.Context, _ string, opts database.UpsertSubscriptionOptions) (*database.Subscription, error) {
assert.Empty(t, opts.InstanceDomain)
assert.False(t, opts.ForceUpdate)
return &database.Subscription{}, nil
})
_, err := h.UpdateEnterpriseSubscription(ctx, req)
require.NoError(t, err)
mockrequire.Called(t, h.mockStore.UpsertEnterpriseSubscriptionFunc)
})
}
func TestHandlerV1_UpdateEnterpriseSubscriptionMembership(t *testing.T) {
ctx := context.Background()
t.Run("via subscription ID", func(t *testing.T) {
req := connect.NewRequest(&subscriptionsv1.UpdateEnterpriseSubscriptionMembershipRequest{
Membership: &subscriptionsv1.EnterpriseSubscriptionMembership{
SubscriptionId: "80ca12e2-54b4-448c-a61a-390b1a9c1224",
MemberSamsAccountId: "018d21f2-04a6-7aaf-9f6f-6fc58c4187b9",
MemberRoles: []subscriptionsv1.Role{subscriptionsv1.Role_ROLE_SUBSCRIPTION_CODY_ANALYTICS_CUSTOMER_ADMIN},
},
})
req.Header().Add("Authorization", "Bearer foolmeifyoucan")
h := newTestHandlerV1()
h.mockStore.ListDotcomEnterpriseSubscriptionsFunc.SetDefaultReturn([]*dotcomdb.SubscriptionAttributes{{ID: "80ca12e2-54b4-448c-a61a-390b1a9c1224"}}, nil)
h.mockStore.IAMWriteFunc.SetDefaultHook(func(_ context.Context, opts iam.WriteOptions) error {
assert.Len(t, opts.Writes, 2)
return nil
})
_, err := h.UpdateEnterpriseSubscriptionMembership(ctx, req)
require.NoError(t, err)
mockrequire.Called(t, h.mockStore.IAMWriteFunc)
})
t.Run("via instance domain", func(t *testing.T) {
req := connect.NewRequest(&subscriptionsv1.UpdateEnterpriseSubscriptionMembershipRequest{
Membership: &subscriptionsv1.EnterpriseSubscriptionMembership{
InstanceDomain: "s1.sourcegraph.com",
MemberSamsAccountId: "018d21f2-04a6-7aaf-9f6f-6fc58c4187b9",
MemberRoles: []subscriptionsv1.Role{subscriptionsv1.Role_ROLE_SUBSCRIPTION_CODY_ANALYTICS_CUSTOMER_ADMIN},
},
})
req.Header().Add("Authorization", "Bearer foolmeifyoucan")
h := newTestHandlerV1()
h.mockStore.ListEnterpriseSubscriptionsFunc.SetDefaultReturn([]*database.Subscription{{ID: "80ca12e2-54b4-448c-a61a-390b1a9c1224"}}, nil)
h.mockStore.IAMWriteFunc.SetDefaultHook(func(_ context.Context, opts iam.WriteOptions) error {
assert.Len(t, opts.Writes, 2)
return nil
})
_, err := h.UpdateEnterpriseSubscriptionMembership(ctx, req)
require.NoError(t, err)
mockrequire.Called(t, h.mockStore.IAMWriteFunc)
})
}

View File

@ -5,10 +5,12 @@ go_library(
srcs = [
"config.go",
"dotcomdb.go",
"iam.go",
"redis.go",
"service.go",
"state.go",
],
embedsrcs = ["iam_model.fga"],
importpath = "github.com/sourcegraph/sourcegraph/cmd/enterprise-portal/service",
tags = [TAG_INFRA_CORESERVICES],
visibility = ["//visibility:public"],
@ -24,6 +26,7 @@ go_library(
"//lib/background",
"//lib/errors",
"//lib/managedservicesplatform/cloudsql",
"//lib/managedservicesplatform/iam",
"//lib/managedservicesplatform/runtime",
"@com_connectrpc_connect//:connect",
"@com_connectrpc_grpcreflect//:grpcreflect",

View File

@ -0,0 +1,33 @@
package service
import (
"context"
_ "embed"
"github.com/redis/go-redis/v9"
"github.com/sourcegraph/log"
"github.com/sourcegraph/sourcegraph/lib/errors"
"github.com/sourcegraph/sourcegraph/lib/managedservicesplatform/iam"
"github.com/sourcegraph/sourcegraph/lib/managedservicesplatform/runtime"
)
//go:embed iam_model.fga
var iamModelDSL string
func newIAMClient(ctx context.Context, logger log.Logger, contract runtime.Contract, redisClient *redis.Client) (_ *iam.ClientV1, close func(), _ error) {
iamClient, closeIAMClient, err := iam.NewClientV1(
ctx,
logger,
contract,
redisClient,
iam.ClientV1Config{
StoreName: "enterprise-portal",
AuthorizationModelDSL: iamModelDSL,
},
)
if err != nil {
return nil, nil, errors.Wrap(err, "new client")
}
return iamClient, closeIAMClient, nil
}

View File

@ -0,0 +1,14 @@
// Playground for this model: https://play.fga.dev/stores/create/?id=01J0HFEZA72MWZ69SRRENC4Y33
model
schema 1.1
type customer_admin
relations
define member: [user]
type user
type subscription_cody_analytics
relations
define view: [user, customer_admin#member]

View File

@ -76,6 +76,11 @@ func (Service) Initialize(ctx context.Context, logger log.Logger, contract runti
return nil, errors.Wrap(err, "create Sourcegraph Accounts client")
}
iamClient, closeIAMClient, err := newIAMClient(ctx, logger, contract, redisClient)
if err != nil {
return nil, errors.Wrap(err, "initialize IAM client")
}
httpServer := http.NewServeMux()
// Register MSP endpoints
@ -93,16 +98,26 @@ func (Service) Initialize(ctx context.Context, logger log.Logger, contract runti
}
// Register connect endpoints
codyaccessservice.RegisterV1(logger, httpServer, samsClient.Tokens(), dotcomDB,
connect.WithInterceptors(otelConnctInterceptor))
codyaccessservice.RegisterV1(
logger,
httpServer,
codyaccessservice.NewStoreV1(
codyaccessservice.StoreV1Options{
SAMSClient: samsClient,
},
),
dotcomDB,
connect.WithInterceptors(otelConnctInterceptor),
)
subscriptionsservice.RegisterV1(
logger,
httpServer,
samsClient.Tokens(),
subscriptionsservice.NewStoreV1(
subscriptionsservice.NewStoreV1Options{
DB: dbHandle,
DotcomDB: dotcomDB,
DB: dbHandle,
DotcomDB: dotcomDB,
SAMSClient: samsClient,
IAMClient: iamClient,
},
),
connect.WithInterceptors(otelConnctInterceptor),
@ -152,7 +167,15 @@ func (Service) Initialize(ctx context.Context, logger log.Logger, contract runti
)
return background.LIFOStopRoutine{
background.CallbackRoutine{
StopFunc: func(ctx context.Context) error {
NameFunc: func() string { return "close IAM client" },
StopFunc: func(context.Context) error {
closeIAMClient()
return nil
},
},
background.CallbackRoutine{
NameFunc: func() string { return "close dotcom database connection pool" },
StopFunc: func(context.Context) error {
start := time.Now()
// NOTE: If we simply shut down, some in-fly requests may be dropped as the
// service exits, so we attempt to gracefully shutdown first.

579
deps.bzl

File diff suppressed because it is too large Load Diff

View File

@ -125,5 +125,6 @@ write_source_files(
"//dev/build-tracker:generate_mocks",
"//cmd/worker/internal/sourcegraphaccounts:generate_mocks",
"//cmd/cody-gateway/internal/actor/productsubscription/productsubscriptiontest:generate_mocks",
"//cmd/enterprise-portal/internal/subscriptionsservice:generate_mocks",
],
)

View File

@ -30,6 +30,8 @@ import (
)
func TestRockskipIntegration(t *testing.T) {
t.Skip("This test is having data race and needs to be fixed. See https://github.com/sourcegraph/sourcegraph/issues/63360")
gs, _ := gitserverintegration.NewTestGitserverWithRepos(t, map[api.RepoName]string{
"github.com/sourcegraph/rockskiptest": gitserverintegration.RepoWithCommands(t,
"echo '# Title' > README.md",

View File

@ -71,6 +71,8 @@ func lintLoggingLibraries() *linter {
"cmd/frontend/internal/app/otlpadapter",
// Legacy and special case handling of panics in background routines
"lib/background/goroutine.go",
// Need to make a logger shim for the OpenFGA server
"lib/managedservicesplatform/iam/openfga_server.go",
},
ErrorFunc: func(bannedImport string) error {
return errors.Newf(`banned usage of '%s': use "github.com/sourcegraph/log" instead`,

View File

@ -621,3 +621,10 @@
:why: Safe open font license
:versions: []
:when: 2024-06-12 01:39:30.854523000 Z
- - :license
- github.com/antlr4-go/antlr/v4
- BSD-3-Clause
- :who:
:why:
:versions: []
:when: 2024-06-18 18:25:40.220943000 Z

88
go.mod
View File

@ -43,6 +43,8 @@ replace (
github.com/gomodule/redigo => github.com/gomodule/redigo v1.8.9
// Pending: Renamed to github.com/google/gnostic. Transitive deps still use the old name (kubernetes/kubernetes).
github.com/googleapis/gnostic => github.com/googleapis/gnostic v0.5.5
// Pending: https://github.com/openfga/openfga/pull/1688
github.com/openfga/openfga => github.com/sourcegraph/openfga v0.0.0-20240614204729-de6b563022de
// Pending: https://github.com/shurcooL/httpgzip/pull/9
github.com/shurcooL/httpgzip => github.com/sourcegraph/httpgzip v0.0.0-20211015085752-0bad89b3b4df
)
@ -85,7 +87,7 @@ require (
github.com/aws/smithy-go v1.13.5
github.com/beevik/etree v1.3.0
github.com/buildkite/go-buildkite/v3 v3.0.1
github.com/cespare/xxhash/v2 v2.2.0
github.com/cespare/xxhash/v2 v2.3.0
github.com/coreos/go-oidc v2.2.1+incompatible
github.com/coreos/go-semver v0.3.1
github.com/crewjam/saml v0.4.14
@ -184,7 +186,7 @@ require (
github.com/stretchr/testify v1.9.0
github.com/temoto/robotstxt v1.1.2
github.com/throttled/throttled/v2 v2.12.0
github.com/tidwall/gjson v1.14.0
github.com/tidwall/gjson v1.17.1
github.com/tj/go-naturaldate v1.3.0
github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80
github.com/uber/gonduit v0.13.0
@ -202,28 +204,28 @@ require (
go.opentelemetry.io/collector/receiver v0.92.0
go.opentelemetry.io/collector/receiver/otlpreceiver v0.92.0
go.opentelemetry.io/contrib/detectors/gcp v1.24.0
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.50.0
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.51.0
go.opentelemetry.io/contrib/propagators/jaeger v1.24.0
go.opentelemetry.io/contrib/propagators/ot v1.24.0
go.opentelemetry.io/otel v1.24.0
go.opentelemetry.io/otel v1.26.0
go.opentelemetry.io/otel/bridge/opentracing v1.22.0 // indirect
go.opentelemetry.io/otel/exporters/jaeger v1.17.0
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.24.0
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.25.0
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.25.0
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.22.0
go.opentelemetry.io/otel/metric v1.24.0
go.opentelemetry.io/otel/sdk v1.24.0
go.opentelemetry.io/otel/metric v1.26.0
go.opentelemetry.io/otel/sdk v1.25.0
go.opentelemetry.io/otel/sdk/metric v1.24.0
go.opentelemetry.io/otel/trace v1.24.0
go.opentelemetry.io/proto/otlp v1.1.0
go.opentelemetry.io/otel/trace v1.26.0
go.opentelemetry.io/proto/otlp v1.2.0
go.uber.org/atomic v1.11.0
go.uber.org/automaxprocs v1.5.2
go.uber.org/ratelimit v0.2.0
go.uber.org/zap v1.26.0
go.uber.org/zap v1.27.0
golang.org/x/crypto v0.24.0
golang.org/x/net v0.26.0
golang.org/x/oauth2 v0.19.0
golang.org/x/oauth2 v0.20.0
golang.org/x/sync v0.7.0
golang.org/x/sys v0.21.0
golang.org/x/time v0.5.0
@ -266,18 +268,18 @@ require (
github.com/edsrzf/mmap-go v1.1.0
github.com/go-json-experiment/json v0.0.0-20231102232822-2e55bd4e08b0
github.com/go-redis/redis/v8 v8.11.5
github.com/go-redsync/redsync/v4 v4.8.1
github.com/go-redsync/redsync/v4 v4.13.0
github.com/google/go-containerregistry v0.16.1
github.com/google/go-github/v48 v48.2.0
github.com/google/go-github/v55 v55.0.0
github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.0-rc.0
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.0.0
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0
github.com/hashicorp/cronexpr v1.1.1
github.com/hashicorp/go-tfe v1.32.1
github.com/hashicorp/terraform-cdk-go/cdktf v0.20.7
github.com/invopop/jsonschema v0.12.0
github.com/jackc/pgerrcode v0.0.0-20220416144525-469b46aa5efa
github.com/jackc/pgx/v5 v5.5.4
github.com/jackc/pgx/v5 v5.5.5
github.com/jomei/notionapi v1.13.0
github.com/maxbrunsfeld/counterfeiter/v6 v6.8.1
github.com/mitchellh/hashstructure/v2 v2.0.2
@ -288,7 +290,7 @@ require (
github.com/pkoukk/tiktoken-go-loader v0.0.1
github.com/prometheus/statsd_exporter v0.22.7
github.com/redis/go-redis/extra/redisotel/v9 v9.0.5
github.com/redis/go-redis/v9 v9.0.5
github.com/redis/go-redis/v9 v9.5.3
github.com/robert-nix/ansihtml v1.0.1
github.com/sourcegraph/cloud-api v0.0.0-20240501113836-ecd1d4cba9dd
github.com/sourcegraph/log/logr v0.0.0-20240425170707-431bcb6c8668
@ -315,9 +317,9 @@ require (
go.opentelemetry.io/collector/config/configtls v0.92.0
go.opentelemetry.io/otel/exporters/prometheus v0.46.0
go.uber.org/goleak v1.3.0
google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237
gorm.io/driver/postgres v1.5.7
gorm.io/gorm v1.25.7-0.20240204074919-46816ad31dde
google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157
gorm.io/driver/postgres v1.5.9
gorm.io/gorm v1.25.10
gorm.io/plugin/opentelemetry v0.1.4
oss.terrastruct.com/d2 v0.6.5
pgregory.net/rapid v1.1.0
@ -326,20 +328,23 @@ require (
require (
cloud.google.com/go/cloudsqlconn v1.5.1 // indirect
cloud.google.com/go/compute/metadata v0.2.4-0.20230617002413-005d2dfb6b68 // indirect
cloud.google.com/go/compute/metadata v0.3.0 // indirect
cloud.google.com/go/longrunning v0.5.5 // indirect
cloud.google.com/go/trace v1.10.5 // indirect
dario.cat/mergo v1.0.0 // indirect
filippo.io/edwards25519 v1.1.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.2 // indirect
github.com/AzureAD/microsoft-authentication-library-for-go v1.1.1 // indirect
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.21.0 // indirect
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.45.0 // indirect
github.com/Masterminds/semver/v3 v3.2.1 // indirect
github.com/Masterminds/squirrel v1.5.4 // indirect
github.com/PuerkitoBio/goquery v1.8.1 // indirect
github.com/agnivade/levenshtein v1.1.1 // indirect
github.com/alexflint/go-arg v1.4.2 // indirect
github.com/alexflint/go-scalar v1.0.0 // indirect
github.com/andybalholm/cascadia v1.3.2 // indirect
github.com/antlr4-go/antlr/v4 v4.13.0 // indirect
github.com/apache/arrow/go/v14 v14.0.2 // indirect
github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.22 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.25 // indirect
@ -353,7 +358,6 @@ require (
github.com/buger/jsonparser v1.1.1 // indirect
github.com/cloudflare/circl v1.3.7 // indirect
github.com/cockroachdb/apd/v2 v2.0.1 // indirect
github.com/containerd/log v0.1.0 // indirect
github.com/containerd/stargz-snapshotter/estargz v0.14.3 // indirect
github.com/containerd/typeurl/v2 v2.1.1 // indirect
github.com/creack/pty v1.1.21 // indirect
@ -372,11 +376,13 @@ require (
github.com/go-chi/chi/v5 v5.0.10 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect
github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect
github.com/go-sql-driver/mysql v1.8.1 // indirect
github.com/goccy/go-json v0.10.2 // indirect
github.com/gofrs/uuid/v5 v5.0.0 // indirect
github.com/golang-jwt/jwt/v5 v5.2.1 // indirect
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/google/cel-go v0.20.1 // indirect
github.com/google/flatbuffers v23.5.26+incompatible // indirect
github.com/google/gnostic-models v0.6.8 // indirect
github.com/google/s2a-go v0.1.7 // indirect
@ -384,8 +390,8 @@ require (
github.com/gosimple/slug v1.12.0 // indirect
github.com/gosimple/unidecode v1.0.1 // indirect
github.com/grafana-tools/sdk v0.0.0-20220919052116-6562121319fc // indirect
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-hclog v1.2.0 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/hashicorp/go-slug v0.12.1 // indirect
github.com/hashicorp/golang-lru v0.5.4 // indirect
@ -396,27 +402,48 @@ require (
github.com/jackc/puddle/v2 v2.2.1 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/karlseguin/ccache/v3 v3.0.5 // indirect
github.com/knadh/koanf/v2 v2.0.1 // indirect
github.com/kylelemons/godebug v1.1.0 // indirect
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect
github.com/magiconair/properties v1.8.7 // indirect
github.com/matryer/is v1.2.0 // indirect
github.com/mazznoer/csscolorparser v0.1.3 // indirect
github.com/mfridman/interpolate v0.0.2 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/moby/docker-image-spec v1.3.1 // indirect
github.com/moby/sys/mountinfo v0.6.2 // indirect
github.com/morikuni/aec v1.0.0 // indirect
github.com/mpvl/unique v0.0.0-20150818121801-cbe035fff7de // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/opencontainers/image-spec v1.1.0-rc6 // indirect
github.com/natefinch/wrap v0.2.0 // indirect
github.com/oklog/ulid/v2 v2.1.0 // indirect
github.com/opencontainers/image-spec v1.1.0 // indirect
github.com/openfga/api/proto v0.0.0-20240529184453-5b0b4941f3e0 // indirect
github.com/openfga/language/pkg/go v0.0.0-20240409225820-a53ea2892d6d // indirect
github.com/openfga/openfga v1.5.4 // indirect
github.com/pelletier/go-toml/v2 v2.1.1 // indirect
github.com/pierrec/lz4/v4 v4.1.21 // indirect
github.com/pjbgf/sha1cd v0.3.0 // indirect
github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b // indirect
github.com/pressly/goose/v3 v3.20.0 // indirect
github.com/prometheus/prometheus v0.40.5 // indirect
github.com/redis/go-redis/extra/rediscmd/v9 v9.0.5 // indirect
github.com/rickb777/date v1.14.3 // indirect
github.com/rickb777/plural v1.2.2 // indirect
github.com/sagikazarmark/locafero v0.4.0 // indirect
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
github.com/sethvargo/go-retry v0.2.4 // indirect
github.com/shirou/gopsutil/v3 v3.23.12 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
github.com/skeema/knownhosts v1.2.1 // indirect
github.com/smartystreets/assertions v1.13.0 // indirect
github.com/spf13/afero v1.11.0 // indirect
github.com/spf13/cast v1.6.0 // indirect
github.com/spf13/viper v1.18.2 // indirect
github.com/stoewer/go-strcase v1.3.0 // indirect
github.com/subosito/gotenv v1.6.0 // indirect
github.com/tetratelabs/wazero v1.3.0 // indirect
github.com/vbatts/tar-split v0.11.5 // indirect
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
@ -435,6 +462,7 @@ require (
go.opentelemetry.io/collector/extension v0.92.0 // indirect
go.opentelemetry.io/collector/extension/auth v0.92.0 // indirect
go.opentelemetry.io/collector/featuregate v1.0.1 // indirect
go.uber.org/mock v0.4.0 // indirect
golang.org/x/image v0.14.0 // indirect
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 // indirect
golang.org/x/tools/go/vcs v0.1.0-deprecated // indirect
@ -442,6 +470,7 @@ require (
gonum.org/v1/plot v0.14.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240617180043-68d350f18fd4 // indirect
gopkg.in/go-jose/go-jose.v2 v2.6.1 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
k8s.io/apiextensions-apiserver v0.29.2 // indirect
k8s.io/component-base v0.29.2 // indirect
@ -451,7 +480,6 @@ require (
require (
bitbucket.org/creachadair/shell v0.0.7 // indirect
cloud.google.com/go v0.112.1 // indirect
cloud.google.com/go/compute v1.25.1 // indirect
cloud.google.com/go/iam v1.1.6 // indirect
cuelang.org/go v0.4.3
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect
@ -488,7 +516,7 @@ require (
github.com/bufbuild/buf v1.25.0 // indirect
github.com/c2h5oh/datasize v0.0.0-20220606134207-859f65c6625b
github.com/cenkalti/backoff v2.2.1+incompatible // indirect
github.com/cenkalti/backoff/v4 v4.2.1 // indirect
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
github.com/charmbracelet/glamour v0.5.0 // indirect
github.com/cockroachdb/errors v1.11.1
github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect
@ -500,7 +528,7 @@ require (
github.com/djherbis/buffer v1.2.0 // indirect
github.com/djherbis/nio/v3 v3.0.1 // indirect
github.com/dlclark/regexp2 v1.10.0 // indirect
github.com/docker/docker v25.0.5+incompatible // indirect
github.com/docker/docker v26.0.2+incompatible // indirect
github.com/docker/go-connections v0.5.0 // indirect
github.com/docker/go-units v0.5.0 // indirect
github.com/dustin/go-humanize v1.0.1
@ -511,7 +539,7 @@ require (
github.com/facebookgo/clock v0.0.0-20150410010913-600d898af40a // indirect
github.com/facebookgo/limitgroup v0.0.0-20150612190941-6abd8d71ec01 // indirect
github.com/facebookgo/muster v0.0.0-20150708232844-fd3d7953fd52 // indirect
github.com/frankban/quicktest v1.14.4
github.com/frankban/quicktest v1.14.6
github.com/fullstorydev/grpcui v1.3.1
github.com/go-enry/go-oniguruma v1.2.1 // indirect
github.com/go-errors/errors v1.5.1 // indirect
@ -542,9 +570,9 @@ require (
github.com/gopherjs/gopherwasm v1.1.0 // indirect
github.com/gorilla/css v1.0.0 // indirect
github.com/gorilla/websocket v1.5.0 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.1 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/go-retryablehttp v0.7.4 // indirect
github.com/hashicorp/go-retryablehttp v0.7.5 // indirect
github.com/hashicorp/go-version v1.6.0 // indirect
github.com/hexops/autogold/v2 v2.2.1
github.com/hexops/gotextdiff v1.0.3

251
go.sum
View File

@ -39,10 +39,8 @@ cloud.google.com/go/bigquery v1.59.1 h1:CpT+/njKuKT3CEmswm6IbhNu9u35zt5dO4yPDLW+
cloud.google.com/go/bigquery v1.59.1/go.mod h1:VP1UJYgevyTwsV7desjzNzDND5p6hZB+Z8gZJN1GQUc=
cloud.google.com/go/cloudsqlconn v1.5.1 h1:rMtPv66pkuk2K1ciCicjZY8Ma1DSyOYSoqwPUw/Timo=
cloud.google.com/go/cloudsqlconn v1.5.1/go.mod h1:DPWjhwD5Fhv43M0RP/+7J37xo4PByfNWCzMlKa9OBwE=
cloud.google.com/go/compute v1.25.1 h1:ZRpHJedLtTpKgr3RV1Fx23NuaAEN1Zfx9hw1u4aJdjU=
cloud.google.com/go/compute v1.25.1/go.mod h1:oopOIR53ly6viBYxaDhBfJwzUAxf1zE//uf3IB011ls=
cloud.google.com/go/compute/metadata v0.2.4-0.20230617002413-005d2dfb6b68 h1:aRVqY1p2IJaBGStWMsQMpkAa83cPkCDLl80eOj0Rbz4=
cloud.google.com/go/compute/metadata v0.2.4-0.20230617002413-005d2dfb6b68/go.mod h1:1a3eRNYX12fs5UABBIXS8HXVvQbX9hRB/RkEBPORpe8=
cloud.google.com/go/compute/metadata v0.3.0 h1:Tz+eQXMEqDIKRsmY3cHTL6FVaynIjX2QxYC4trgAKZc=
cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k=
cloud.google.com/go/datacatalog v1.19.3 h1:A0vKYCQdxQuV4Pi0LL9p39Vwvg4jH5yYveMv50gU5Tw=
cloud.google.com/go/datacatalog v1.19.3/go.mod h1:ra8V3UAsciBpJKQ+z9Whkxzxv7jmQg1hfODr3N3YPJ4=
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
@ -90,6 +88,8 @@ cuelang.org/go v0.4.3/go.mod h1:7805vR9H+VoBNdWFdI7jyDR3QLUPp4+naHfbcgp55HI=
dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
git.sr.ht/~sbinet/gg v0.5.0 h1:6V43j30HM623V329xA9Ntq+WJrMjDxRjuAB1LFWF5m8=
git.sr.ht/~sbinet/gg v0.5.0/go.mod h1:G2C0eRESqlKhS7ErsNey6HHrqU1PwsnCQlekFi9Q2Oo=
github.com/99designs/gqlgen v0.17.2/go.mod h1:K5fzLKwtph+FFgh9j7nFbRUdBKvTcGnsta51fsMTn3o=
@ -144,9 +144,13 @@ github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0
github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ=
github.com/Masterminds/sprig v2.22.0+incompatible h1:z4yfnGrZ7netVz+0EDJ0Wi+5VZCSYp4Z0m2dk6cEM60=
github.com/Masterminds/sprig v2.22.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o=
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.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
github.com/Microsoft/hcsshim v0.11.4 h1:68vKo2VN8DE9AdN4tnkWnmdhqdbpUFM8OF3Airm7fz8=
github.com/Microsoft/hcsshim v0.11.4/go.mod h1:smjE4dvqPX9Zldna+t5FG3rnoHhaB7QYxPRqGcpAD9w=
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I=
github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c=
@ -210,6 +214,8 @@ github.com/andybalholm/cascadia v1.3.2/go.mod h1:7gtRlve5FxPPgIgX36uWBX58OdBsSS6
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/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/antlr4-go/antlr/v4 v4.13.0 h1:lxCg3LAv+EUK6t1i0y1V6/SLeUi0eKEKdhQAlS8TVTI=
github.com/antlr4-go/antlr/v4 v4.13.0/go.mod h1:pfChB/xh/Unjila75QW7+VU4TSnWnnk9UTnmpPaOR2g=
github.com/apache/arrow/go/v14 v14.0.2 h1:N8OkaJEOfI3mEZt07BIkvo4sC6XDbL+48MBPWO5IONw=
github.com/apache/arrow/go/v14 v14.0.2/go.mod h1:u3fgh3EdgN/YQ8cVQRguVW3R+seMybFg8QBQ5LU+eBY=
github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0 h1:jfIu9sQUG6Ig+0+Ap1h4unLjW6YQJpKZVmUzxsD4E/Q=
@ -338,12 +344,12 @@ github.com/bradfitz/gomemcache v0.0.0-20170208213004-1952afaa557d/go.mod h1:PmM6
github.com/bradleyjkemp/cupaloy/v2 v2.6.0 h1:knToPYa2xtfg42U3I6punFEjaGFKWQRXJwj0JTv4mTs=
github.com/bradleyjkemp/cupaloy/v2 v2.6.0/go.mod h1:bm7JXdkRd4BHJk9HpwqAI8BoAY1lps46Enkdqw6aRX0=
github.com/bshuster-repo/logrus-logstash-hook v1.0.0/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk=
github.com/bsm/ginkgo/v2 v2.5.0/go.mod h1:AiKlXPm7ItEHNc/2+OkrNG4E0ITzojb9/xWzvQ9XZ9w=
github.com/bsm/ginkgo/v2 v2.7.0 h1:ItPMPH90RbmZJt5GtkcNvIRuGEdwlBItdNVoyzaNQao=
github.com/bsm/ginkgo/v2 v2.7.0/go.mod h1:AiKlXPm7ItEHNc/2+OkrNG4E0ITzojb9/xWzvQ9XZ9w=
github.com/bsm/gomega v1.20.0/go.mod h1:JifAceMQ4crZIWYUKrlGcmbN3bqHogVTADMD2ATsbwk=
github.com/bsm/gomega v1.26.0 h1:LhQm+AFcgV2M0WyKroMASzAzCAJVpAxQXv4SaI9a69Y=
github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=
github.com/bsm/gomega v1.26.0/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0=
github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0=
github.com/bufbuild/buf v1.25.0 h1:HFxKrR8wFcZwrBInN50K/oJX/WOtPVq24rHb/ArjfBA=
github.com/bufbuild/buf v1.25.0/go.mod h1:GCKZ5bAP6Ht4MF7KcfaGVgBEXGumwAz2hXjjLVxx8ZU=
github.com/bufbuild/connect-go v1.9.0 h1:JIgAeNuFpo+SUPfU19Yt5TcWlznsN5Bv10/gI/6Pjoc=
@ -367,14 +373,14 @@ github.com/campoy/embedmd v1.0.0/go.mod h1:oxyr9RCiSXg0M3VJ3ks0UGfp98BpSSGr0kpiX
github.com/cenkalti/backoff v1.1.1-0.20171020064038-309aa717adbf/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4=
github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM=
github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/charmbracelet/glamour v0.5.0 h1:wu15ykPdB7X6chxugG/NNfDUbyyrCLV9XBalj5wdu3g=
github.com/charmbracelet/glamour v0.5.0/go.mod h1:9ZRtG19AUIzcTm7FGLGbq3D5WKQ5UyZBbQsMQN0XIqc=
github.com/chromedp/cdproto v0.0.0-20210526005521-9e51b9051fd0/go.mod h1:At5TxYYdxkbQL0TSefRjhLE3Q0lgvqKKMSFUglJ7i1U=
@ -414,6 +420,8 @@ github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b h1:r6VH0faHjZe
github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs=
github.com/cockroachdb/redact v1.1.5 h1:u1PMllDkdFfPWaNGMyLD1+so+aq3uUItthCFqzwPJ30=
github.com/cockroachdb/redact v1.1.5/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg=
github.com/containerd/containerd v1.7.12 h1:+KQsnv4VnzyxWcfO9mlxxELaoztsDEjOuCMPAuPqgU0=
github.com/containerd/containerd v1.7.12/go.mod h1:/5OMpE1p0ylxtEUGY8kuCYkDRzJm9NO1TFMWjUpdevk=
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
github.com/containerd/stargz-snapshotter/estargz v0.14.3 h1:OqlDCK3ZVUO6C3B/5FSkDwbkEETK84kQgEeFwDC+62k=
@ -434,6 +442,8 @@ github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/cpuguy83/dockercfg v0.3.1 h1:/FpZ+JaygUR/lZP2NlFI2DVfrOEMAIKP5wWEJdoYe9E=
github.com/cpuguy83/dockercfg v0.3.1/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
@ -499,8 +509,8 @@ github.com/docker/cli v25.0.2+incompatible h1:6GEdvxwEA451/+Y3GtqIGn/MNjujQazUlx
github.com/docker/cli v25.0.2+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk=
github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/docker v25.0.5+incompatible h1:UmQydMduGkrD5nQde1mecF/YnSbTOaPeFIeP5C4W+DE=
github.com/docker/docker v25.0.5+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker v26.0.2+incompatible h1:yGVmKUFGgcxA6PXWAokO0sQL22BrQ67cgVjko8tGdXE=
github.com/docker/docker v26.0.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker-credential-helpers v0.8.1 h1:j/eKUktUltBtMzKqmfLB0PAgqYyMHOp5vfsD1807oKo=
github.com/docker/docker-credential-helpers v0.8.1/go.mod h1:P3ci7E3lwkZg6XiHdRKft1KckHiO9a2rNtyFbZ/ry9M=
github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
@ -573,8 +583,9 @@ github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps=
github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY=
github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/fsnotify/fsnotify v1.4.3-0.20170329110642-4da3e2cfbabc/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
@ -672,24 +683,22 @@ github.com/go-pdf/fpdf v0.9.0/go.mod h1:oO8N111TkmKb9D7VvWGLvLJlaZUQVPM+6V42pp3i
github.com/go-redis/redis v6.15.8+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
github.com/go-redis/redis v6.15.9+incompatible h1:K0pv1D7EQUjfyoMql+r/jZqCLizCGKFlFgcHWWmHQjg=
github.com/go-redis/redis v6.15.9+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
github.com/go-redis/redis/v7 v7.4.0 h1:7obg6wUoj05T0EpY0o8B59S9w5yeMWql7sw2kwNW1x4=
github.com/go-redis/redis/v7 v7.4.0/go.mod h1:JDNMw23GTyLNC4GZu9njt15ctBQVn7xjRfnwdHj/Dcg=
github.com/go-redis/redis/v7 v7.4.1 h1:PASvf36gyUpr2zdOUS/9Zqc80GbM+9BDyiJSJDDOrTI=
github.com/go-redis/redis/v7 v7.4.1/go.mod h1:JDNMw23GTyLNC4GZu9njt15ctBQVn7xjRfnwdHj/Dcg=
github.com/go-redis/redis/v8 v8.4.2/go.mod h1:A1tbYoHSa1fXwN+//ljcCYYJeLmVrwL9hbQN45Jdy0M=
github.com/go-redis/redis/v8 v8.11.4/go.mod h1:2Z2wHZXdQpCDXEGzqMockDpNyYvi2l4Pxt6RJr792+w=
github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI=
github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo=
github.com/go-redsync/redsync/v4 v4.8.1 h1:rq2RvdTI0obznMdxKUWGdmmulo7lS9yCzb8fgDKOlbM=
github.com/go-redsync/redsync/v4 v4.8.1/go.mod h1:LmUAsQuQxhzZAoGY7JS6+dNhNmZyonMZiiEDY9plotM=
github.com/go-redsync/redsync/v4 v4.13.0 h1:49X6GJfnbLGaIpBBREM/zA4uIMDXKAh1NDkvQ1EkZKA=
github.com/go-redsync/redsync/v4 v4.13.0/go.mod h1:HMW4Q224GZQz6x1Xc7040Yfgacukdzu7ifTDAKiyErQ=
github.com/go-sourcemap/sourcemap v2.1.3+incompatible h1:W1iEw64niKVGogNgBN3ePyLFfuisuzeidWPMPWmECqU=
github.com/go-sourcemap/sourcemap v2.1.3+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg=
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI=
github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
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.6.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw=
github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
github.com/go-test/deep v1.0.2-0.20181118220953-042da051cf31/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
@ -790,6 +799,8 @@ github.com/gomodule/redigo v1.8.9 h1:Sl3u+2BI/kk+VEatbj0scLdrFhjPmbxOc1myhDP41ws
github.com/gomodule/redigo v1.8.9/go.mod h1:7ArFNvsTjH8GMMzB4uy1snslv2BwmginuMs06a1uzZE=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/cel-go v0.20.1 h1:nDx9r8S3L4pE61eDdt8igGj8rf5kjYR3ILxWIpWNi84=
github.com/google/cel-go v0.20.1/go.mod h1:kWcIzTsPX0zmQ+H3TirHstLLf9ep5QTsZBN9u4dOYLg=
github.com/google/flatbuffers v23.5.26+incompatible h1:M9dgRyhJemaM4Sw8+66GHBu8ioaQmyPLg1b8VwK5WJg=
github.com/google/flatbuffers v23.5.26+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I=
@ -904,15 +915,17 @@ github.com/gregjones/httpcache v0.0.0-20170920190843-316c5e0ff04e/go.mod h1:Fecb
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 h1:+ngKgrYPPJrOjhax5N+uePQ0Fh1Z7PheYoUI/0nzkPA=
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
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.0-rc.0 h1:mdLirNAJBxnGgyB6pjZLcs6ue/6eZGBui6gXspfq4ks=
github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.0-rc.0/go.mod h1:kdXbOySqcQeTxiqglW7aahTmWZy3Pgi6SYL36yvKeyA=
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.0.0 h1:2cz5kSrxzMYHiWOBbKj8itQm+nRykkB8aMv4ThcHYHA=
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.0.0/go.mod h1:w9Y7gY31krpLmrVU5ZPG9H7l9fZuRu5/3R3S3FMtVQ4=
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0 h1:pRhl55Yx1eC7BZ1N+BBWwnKaMyD8uC+34TLdndZMAKk=
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0/go.mod h1:XKMd7iuf/RGPSMJ/U4HP0zS2Z9Fh8Ps9a+6X26m/tmI=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.1 h1:/c3QmbOGMGTOumP2iT/rCwB7b0QDGLKzqOmktBjT+Is=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.1/go.mod h1:5SN9VR2LTsRFsrEC6FHgRbTWrTHu6tqPeKxEQv15giM=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 h1:bkypFPDjIYGfCYD5mRBvpqxfYX1YCS1PXdKYWi8FsN0=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0/go.mod h1:P+Lt/0by1T8bfcF3z737NnSbmxQAppXMRziHUxPOC8k=
github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
github.com/hashicorp/consul/api v1.13.0/go.mod h1:ZlVrynguJKcYr54zGaDbaL3fOvKC9m72FhPvA8T35KQ=
github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
@ -930,8 +943,8 @@ github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd/go.mod h1:9bjs9
github.com/hashicorp/go-hclog v0.8.0/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
github.com/hashicorp/go-hclog v1.2.0 h1:La19f8d7WIlm4ogzNHB0JGqs5AUDAZ2UfCY4sJXcJdM=
github.com/hashicorp/go-hclog v1.2.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c=
github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
@ -941,8 +954,8 @@ github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9
github.com/hashicorp/go-plugin v1.0.1/go.mod h1:++UyYGoz3o5w9ZzAdZxtQKrWWP+iqPBn3cQptSMzBuY=
github.com/hashicorp/go-retryablehttp v0.5.1/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs=
github.com/hashicorp/go-retryablehttp v0.5.4/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs=
github.com/hashicorp/go-retryablehttp v0.7.4 h1:ZQgVdpTdAL7WpMIwLzCfbalOcSUdkDZnpUv3/+BxzFA=
github.com/hashicorp/go-retryablehttp v0.7.4/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8=
github.com/hashicorp/go-retryablehttp v0.7.5 h1:bJj+Pj19UZMIweq/iie+1u5YCdGrnxCT9yvm0e+Nd5M=
github.com/hashicorp/go-retryablehttp v0.7.5/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8=
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
github.com/hashicorp/go-rootcerts v1.0.1/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8=
github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8=
@ -1067,8 +1080,8 @@ github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQ
github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs=
github.com/jackc/pgx/v4 v4.18.2 h1:xVpYkNR5pk5bMCZGfClbO962UIqVABcAGt7ha1s/FeU=
github.com/jackc/pgx/v4 v4.18.2/go.mod h1:Ey4Oru5tH5sB6tV7hDmfWFahwF15Eb7DNXlRKx2CkVw=
github.com/jackc/pgx/v5 v5.5.4 h1:Xp2aQS8uXButQdnCMWNmvx6UysWQQC+u1EoizjguY+8=
github.com/jackc/pgx/v5 v5.5.4/go.mod h1:ez9gk+OAat140fv9ErkZDYFWmXLfV+++K0uAOiwgm1A=
github.com/jackc/pgx/v5 v5.5.5 h1:amBjrZVmksIdNjxGW/IiIMzxMKZFelXbUoPNb+8sjQw=
github.com/jackc/pgx/v5 v5.5.5/go.mod h1:ez9gk+OAat140fv9ErkZDYFWmXLfV+++K0uAOiwgm1A=
github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
@ -1125,6 +1138,8 @@ github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8
github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213/go.mod h1:vNUNkEQ1e29fT/6vq2aBdFsgNPmy8qMdSay1npru+Sw=
github.com/k3a/html2text v1.1.0 h1:ks4hKSTdiTRsLr0DM771mI5TvsoG6zH7m1Ulv7eJRHw=
github.com/k3a/html2text v1.1.0/go.mod h1:ieEXykM67iT8lTvEWBh6fhpH4B23kB9OMKPdIBmgUqA=
github.com/karlseguin/ccache/v3 v3.0.5 h1:hFX25+fxzNjsRlREYsoGNa2LoVEw5mPF8wkWq/UnevQ=
github.com/karlseguin/ccache/v3 v3.0.5/go.mod h1:qxC372+Qn+IBj8Pe3KvGjHPj0sWwEF7AeZVhsNPZ6uY=
github.com/karlseguin/expect v1.0.7/go.mod h1:lXdI8iGiQhmzpnnmU/EGA60vqKs8NbRNFnhhrJGoD5g=
github.com/karlseguin/typed v1.1.7/go.mod h1:329jL66F7EH9O3xIBv2GAIFnMHIxH55NCQ78LUbZoJM=
github.com/karlseguin/typed v1.1.8 h1:ND0eDpwiUFIrm/n1ehxUyh/XNGs9zkYrLxtGqENSalY=
@ -1175,6 +1190,10 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 h1:SOEGU9fKiNWd/HOJuq6+3iTQz8KNCLtVX6idSoTLdUw=
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0/go.mod h1:dXGbAdH5GtBTC4WfIxhKZfyBF/HBFgRZSWwZ9g/He9o=
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 h1:P6pPBnrTSX3DEVR4fDembhRWSsG5rVo6hYhAB/ADZrk=
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0/go.mod h1:vmVJ0l/dxyfGW6FmdpVm2joNMFikkuWg0EoCKLGUMNw=
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
@ -1184,12 +1203,15 @@ github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/logrusorgru/aurora/v3 v3.0.0/go.mod h1:vsR12bk5grlLvLXAYrBsb5Oc/N+LxAlxggSjiwMnCUc=
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4=
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
github.com/machinebox/graphql v0.2.2 h1:dWKpJligYKhYKO5A2gvNhkJdQMNZeChZYyBbrZkBZfo=
github.com/machinebox/graphql v0.2.2/go.mod h1:F+kbVMHuwrQ5tYgU9JXlnskM8nOaFxCAEolaQybkjWA=
github.com/magiconair/properties v1.7.4-0.20170902060319-8d7837e64d3c/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
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.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs=
@ -1237,11 +1259,13 @@ github.com/maxbrunsfeld/counterfeiter/v6 v6.8.1 h1:NicmruxkeqHjDv03SfSxqmaLuisdd
github.com/maxbrunsfeld/counterfeiter/v6 v6.8.1/go.mod h1:eyp4DdUJAKkr9tvxR3jWhw2mDK7CWABMG5r9uyaKC7I=
github.com/mazznoer/csscolorparser v0.1.3 h1:vug4zh6loQxAUxfU1DZEu70gTPufDPspamZlHAkKcxE=
github.com/mazznoer/csscolorparser v0.1.3/go.mod h1:Aj22+L/rYN/Y6bj3bYqO3N6g1dtdHtGfQ32xZ5PJQic=
github.com/mfridman/interpolate v0.0.2 h1:pnuTK7MQIxxFz1Gr+rjSIx9u7qVjf5VOoM/u6BbAxPY=
github.com/mfridman/interpolate v0.0.2/go.mod h1:p+7uk6oE07mpE/Ik1b8EckO0O4ZXiGAfshKBWLUM9Xg=
github.com/microcosm-cc/bluemonday v1.0.17/go.mod h1:Z0r70sCuXHig8YpBzCc5eGHAap2K7e/u082ZUpDRRqM=
github.com/microcosm-cc/bluemonday v1.0.26 h1:xbqSvqzQMeEHCqMi64VAs4d8uy6Mequs3rQ0k/Khz58=
github.com/microcosm-cc/bluemonday v1.0.26/go.mod h1:JyzOCs9gkyQyjs+6h10UEVSe02CGwkhd72Xdqh78TWs=
github.com/microsoft/go-mssqldb v1.6.0 h1:mM3gYdVwEPFrlg/Dvr2DNVEgYFG7L42l+dGc67NNNpc=
github.com/microsoft/go-mssqldb v1.6.0/go.mod h1:00mDtPbeQCRGC1HwOOR5K/gr30P1NcEG0vx6Kbv2aJU=
github.com/microsoft/go-mssqldb v1.7.0 h1:sgMPW0HA6Ihd37Yx0MzHyKD726C2kY/8KJsQtXHNaAs=
github.com/microsoft/go-mssqldb v1.7.0/go.mod h1:kOvZKUdrhhFQmxLZqbwUV0rHkNkZpthMITIb2Ko1IoA=
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI=
@ -1280,8 +1304,16 @@ github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zx
github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
github.com/moby/buildkit v0.12.5 h1:RNHH1l3HDhYyZafr5EgstEu8aGNCwyfvMtrQDtjH9T0=
github.com/moby/buildkit v0.12.5/go.mod h1:YGwjA2loqyiYfZeEo8FtI7z4x5XponAaIWsWcSjWwso=
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk=
github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc=
github.com/moby/sys/mountinfo v0.6.2 h1:BzJjoreD5BMFNmD9Rus6gdd1pLuecOFPt8wC+Vygl78=
github.com/moby/sys/mountinfo v0.6.2/go.mod h1:IJb6JQeOklcdMU9F5xQ8ZALD+CUr5VlGpwtX+VE0rpI=
github.com/moby/sys/sequential v0.5.0 h1:OPvI35Lzn9K04PBbCLW0g4LcFAJgHsvXsRyewg5lXtc=
github.com/moby/sys/sequential v0.5.0/go.mod h1:tH2cOOs5V9MlPiXcQzRC+eEyab644PWKGRYaaV5ZZlo=
github.com/moby/sys/user v0.1.0 h1:WmZ93f5Ux6het5iituh9x2zAG7NFY9Aqi49jjE1PaQg=
github.com/moby/sys/user v0.1.0/go.mod h1:fKJhFOnsCN6xZ5gSfbM6zaHGgDJMrqt9/reuj4T7MmU=
github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0=
github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
@ -1320,6 +1352,10 @@ github.com/mwitkow/go-proto-validators v0.3.2 h1:qRlmpTzm2pstMKKzTdvwPCF5QfBNURS
github.com/mwitkow/go-proto-validators v0.3.2/go.mod h1:ej0Qp0qMgHN/KtDyUt+Q1/tA7a5VarXUOUxD+oeD30w=
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus=
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
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/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/nightlyone/lockfile v1.0.0 h1:RHep2cFKK4PonZJDdEl4GmkabuhbsRMgk/k3uAmxBiA=
@ -1329,37 +1365,38 @@ github.com/npillmayer/nestext v0.1.3/go.mod h1:h2lrijH8jpicr25dFY+oAJLyzlya6jhnu
github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d h1:VhgPp6v9qf9Agr/56bj7Y/xa04UccTW04VP0Qed4vnQ=
github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d/go.mod h1:YUTz3bUH2ZwIWBy3CJBeOBEugqcmXREj14T+iG/4k4U=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
github.com/nxadm/tail v1.4.11 h1:8feyoE3OzPrcshW5/MJ4sGESc5cqmGkGCWlco4l0bqY=
github.com/nxadm/tail v1.4.11/go.mod h1:OTaG3NK980DZzxbRq6lEuzgU+mug70nY11sMd4JXXHc=
github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
github.com/oklog/ulid/v2 v2.1.0 h1:+9lhoxAP56we25tyYETBBY1YLA2SaoLvUFgrP2miPJU=
github.com/oklog/ulid/v2 v2.1.0/go.mod h1:rcEKHmBBKfef9DhnvX7y1HZBYxjXb0cP5ExxNsTT1QQ=
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
github.com/onsi/ginkgo v1.14.2/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
github.com/onsi/ginkgo/v2 v2.14.0 h1:vSmGj2Z5YPb9JwCWT6z6ihcUvDhuXLc3sJiqd3jMKAY=
github.com/onsi/ginkgo/v2 v2.14.0/go.mod h1:JkUdW7JkN0V6rFvsHcJ478egV3XH9NxpD27Hal/PhZw=
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc=
github.com/onsi/gomega v1.16.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
github.com/onsi/gomega v1.30.0 h1:hvMK7xYz4D3HapigLTeGdId/NcfQx1VHMJc60ew99+8=
github.com/onsi/gomega v1.30.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ=
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.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
github.com/opencontainers/image-spec v1.1.0-rc6 h1:XDqvyKsJEbRtATzkgItUqBA7QHk58yxX1Ov9HERHNqU=
github.com/opencontainers/image-spec v1.1.0-rc6/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM=
github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug=
github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM=
github.com/openfga/api/proto v0.0.0-20240529184453-5b0b4941f3e0 h1:tSJl/atdqsDACjRQQPCbXe2GfEvcOkhdrUNmDToAjTA=
github.com/openfga/api/proto v0.0.0-20240529184453-5b0b4941f3e0/go.mod h1:XnvYrdU//9i70Aou6n4H5DJ0bdRPB3IlmE/Vx6qhnm8=
github.com/openfga/language/pkg/go v0.0.0-20240409225820-a53ea2892d6d h1:n44DfITs+CLCYJIgsryJkG2ElwOZJ3huekPZKydPi7U=
github.com/openfga/language/pkg/go v0.0.0-20240409225820-a53ea2892d6d/go.mod h1:wkI4GcY3yNNuFMU2ncHPWqBaF7XylQTkJYfBi2pIpK8=
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
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=
@ -1369,11 +1406,14 @@ github.com/oschwald/maxminddb-golang v1.12.0 h1:9FnTOD0YOhP7DGxGsq4glzpGy5+w7pq5
github.com/oschwald/maxminddb-golang v1.12.0/go.mod h1:q0Nob5lTCqyQ8WT6FYgS1L7PXKVVbgiymefNwIjPzgY=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pborman/getopt v0.0.0-20170112200414-7148bc3a4c30/go.mod h1:85jBQOZwpVEaDAr341tbn15RS4fCAsIst0qp7i8ex1o=
github.com/pelletier/go-toml v1.0.1-0.20170904195809-1d6b12b7cb29/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pelletier/go-toml v1.6.0/go.mod h1:5N711Q9dKgbdkxHL+MEfF31hpT7l0S0s/t2kKREewys=
github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE=
github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
github.com/pelletier/go-toml/v2 v2.1.1 h1:LWAJwfNvjQZCFIDKWYQaM62NcYeYViCmWIwmOStowAI=
github.com/pelletier/go-toml/v2 v2.1.1/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
github.com/peterbourgon/ff v1.7.1 h1:xt1lxTG+Nr2+tFtysY7abFgPoH3Lug8CwYJMOmJRXhk=
github.com/peterbourgon/ff v1.7.1/go.mod h1:fYI5YA+3RDqQRExmFbHnBjEeWzh9TrS8rnRpEq7XIg0=
github.com/peterbourgon/ff/v3 v3.3.2 h1:2J07/5/36kd9HYVt42Zve0xCeQ+LLRIvoKrt6sAZXJ4=
@ -1414,6 +1454,8 @@ github.com/pquerna/cachecontrol v0.2.0 h1:vBXSNuE5MYP9IJ5kjsdo8uq+w41jSPgvba2DEn
github.com/pquerna/cachecontrol v0.2.0/go.mod h1:NrUG3Z7Rdu85UNR3vm7SOsl1nFIeSiQnrHV5K9mBcUI=
github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g=
github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U=
github.com/pressly/goose/v3 v3.20.0 h1:uPJdOxF/Ipj7ABVNOAMJXSxwFXZGwMGHNqjC8e61VA0=
github.com/pressly/goose/v3 v3.20.0/go.mod h1:BRfF2GcG4FTG12QfdBVy3q1yveaf4ckL9vWwEcIO3lA=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
@ -1468,9 +1510,13 @@ github.com/redis/go-redis/extra/rediscmd/v9 v9.0.5 h1:EaDatTxkdHG+U3Bk4EUr+DZ7fO
github.com/redis/go-redis/extra/rediscmd/v9 v9.0.5/go.mod h1:fyalQWdtzDBECAQFBJuQe5bzQ02jGd5Qcbgb97Flm7U=
github.com/redis/go-redis/extra/redisotel/v9 v9.0.5 h1:EfpWLLCyXw8PSM2/XNJLjI3Pb27yVE+gIAfeqp8LUCc=
github.com/redis/go-redis/extra/redisotel/v9 v9.0.5/go.mod h1:WZjPDy7VNzn77AAfnAfVjZNvfJTYfPetfZk5yoSTLaQ=
github.com/redis/go-redis/v9 v9.0.2/go.mod h1:/xDTe9EF1LM61hek62Poq2nzQSGj0xSrEtEHbBQevps=
github.com/redis/go-redis/v9 v9.0.5 h1:CuQcn5HIEeK7BgElubPP8CGtE0KakrnbBSTLjathl5o=
github.com/redis/go-redis/v9 v9.0.5/go.mod h1:WqMKv5vnQbRuZstUwxQI195wHy+t4PuXDOjzMvcuQHk=
github.com/redis/go-redis/v9 v9.5.3 h1:fOAp1/uJG+ZtcITgZOfYFmTKPE7n4Vclj1wZFgRciUU=
github.com/redis/go-redis/v9 v9.5.3/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M=
github.com/redis/rueidis v1.0.19 h1:s65oWtotzlIFN8eMPhyYwxlwLR1lUdhza2KtWprKYSo=
github.com/redis/rueidis v1.0.19/go.mod h1:8B+r5wdnjwK3lTFml5VtxjzGOQAC+5UmujoD12pDrEo=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/rhnvrm/simples3 v0.6.1/go.mod h1:Y+3vYm2V7Y4VijFoJHHTrja6OgPrJ2cBti8dPGkC3sA=
github.com/rickb777/date v1.14.3 h1:FS47C+yEMgIPE2ZUA67ekpU1CZXMSliHkeB/V+ZFUg4=
github.com/rickb777/date v1.14.3/go.mod h1:mes+vf4wqTD6l4zgZh4Z5TQkrLA57dpuzEGVeTk/XSc=
@ -1513,6 +1559,10 @@ github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFo
github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc=
github.com/sabhiram/go-gitignore v0.0.0-20210923224102-525f6e181f06 h1:OkMGxebDjyw0ULyrTYWeN0UNCCkmCWfjPnIA2W6oviI=
github.com/sabhiram/go-gitignore v0.0.0-20210923224102-525f6e181f06/go.mod h1:+ePHsJ1keEjQtpvf9HHw0f4ZeJ0TLRsxhunSI2hYJSs=
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/schollz/progressbar/v3 v3.13.1 h1:o8rySDYiQ59Mwzy2FELeHY5ZARXZTVJC7iHD6PEFUiE=
github.com/schollz/progressbar/v3 v3.13.1/go.mod h1:xvrbki8kfT1fzWzBT/UZd9L6GA+jdL7HAgq2RFnO6fQ=
@ -1528,13 +1578,17 @@ github.com/segmentio/ksuid v1.0.4/go.mod h1:/XUiZBD3kVx5SmUOl55voK5yeAbBNNIed+2O
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8=
github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I=
github.com/sethvargo/go-retry v0.2.4 h1:T+jHEQy/zKJf5s95UkguisicE0zuF9y7+/vgz08Ocec=
github.com/sethvargo/go-retry v0.2.4/go.mod h1:1afjQuvh7s4gflMObvjLPaWgluLLyhA1wmVZ6KLpICw=
github.com/shirou/gopsutil/v3 v3.23.12 h1:z90NtUkp3bMtmICZKpC4+WaknU1eXtp5vtbQ11DgpE4=
github.com/shirou/gopsutil/v3 v3.23.12/go.mod h1:1FrWgea594Jp7qmjHUUPlJDTPgcsb9mGnXDxavtikzM=
github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM=
github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ=
github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k=
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ=
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8=
github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk=
github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
@ -1608,6 +1662,8 @@ github.com/sourcegraph/mountinfo v0.0.0-20240201124957-b314c0befab1 h1:nBb4Cp27e
github.com/sourcegraph/mountinfo v0.0.0-20240201124957-b314c0befab1/go.mod h1:ghoEiutaNVERt2cu5q/bU3HOo29AHGSPrRZE1sOaA0w=
github.com/sourcegraph/notionreposync v0.0.0-20240517090426-98b2d4b017d7 h1:1uwYDdt1HGBwl+5a1/zyUehFX4/1969Uv34vKlmltcY=
github.com/sourcegraph/notionreposync v0.0.0-20240517090426-98b2d4b017d7/go.mod h1:p8BpoweXljSzz6OAlra0Q+CuzoFfCsm+/J1ZiNmQxrE=
github.com/sourcegraph/openfga v0.0.0-20240614204729-de6b563022de h1:0p4KNG4nvdNCHZjyoL9ju9PxttiwtPni5g5aJTldXv4=
github.com/sourcegraph/openfga v0.0.0-20240614204729-de6b563022de/go.mod h1:8bRAwVDc00rzddY2V19Vwug+h8FWfS1IlVWvblN7THE=
github.com/sourcegraph/run v0.12.0 h1:3A8w5e8HIYPfafHekvmdmmh42RHKGVhmiTZAPJclg7I=
github.com/sourcegraph/run v0.12.0/go.mod h1:PwaP936BTnAJC1cqR5rSbG5kOs/EWStTK3lqvMX5GUA=
github.com/sourcegraph/scip v0.4.0 h1:Tqf5ThVlPu8fV+WeTkJEbW34fPOfDUpbxQWU4iLvaQI=
@ -1622,9 +1678,13 @@ github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasO
github.com/spf13/afero v0.0.0-20170901052352-ee1bd8ee15a1/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
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.1.0/go.mod h1:r2rcYCSwa1IExKTDiTfzaxqT2FNHs8hODu4LnUfgKEg=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0=
github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk=
github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0=
@ -1640,7 +1700,11 @@ github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An
github.com/spf13/viper v1.0.0/go.mod h1:A8kyI5cUJhb8N+3pkfONlcEcZbueH6nhAm0Fq7SrnBM=
github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns=
github.com/spf13/viper v1.18.2 h1:LUXCnvUvSM6FXAsj6nnfc8Q2tp1dIgUfY9Kc8GsSOiQ=
github.com/spf13/viper v1.18.2/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMVB+yk=
github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8=
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.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
@ -1666,16 +1730,24 @@ github.com/strum355/go-mockgen/v2 v2.0.0-20240306201845-b2e8d553a343/go.mod h1:1
github.com/stvp/tempredis v0.0.0-20181119212430-b82af8480203 h1:QVqDTf3h2WHt08YuiTGPZLls0Wq99X9bWd0Q5ZSBesM=
github.com/stvp/tempredis v0.0.0-20181119212430-b82af8480203/go.mod h1:oqN97ltKNihBbwlX8dLpwxCl3+HnXKV/R0e+sRLd9C8=
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
github.com/tadvi/systray v0.0.0-20190226123456-11a2b8fa57af h1:6yITBqGTE2lEeTPG04SN9W+iWHCRyHqlVYILiSXziwk=
github.com/tadvi/systray v0.0.0-20190226123456-11a2b8fa57af/go.mod h1:4F09kP5F+am0jAwlQLddpoMDM+iewkxxt6nxUQ5nq5o=
github.com/temoto/robotstxt v1.1.2 h1:W2pOjSJ6SWvldyEuiFXNxz3xZ8aiWX5LbfDiOFd7Fxg=
github.com/temoto/robotstxt v1.1.2/go.mod h1:+1AmkuG3IYkh1kv0d2qEB9Le88ehNO0zwOr3ujewlOo=
github.com/testcontainers/testcontainers-go v0.30.0 h1:jmn/XS22q4YRrcMwWg0pAwlClzs/abopbsBzrepyc4E=
github.com/testcontainers/testcontainers-go v0.30.0/go.mod h1:K+kHNGiM5zjklKjgTtcrEetF3uhWbMUyqAQoyoh8Pf0=
github.com/testcontainers/testcontainers-go/modules/mysql v0.30.0 h1:wrePvxfU/2HFALKyBqpNs6VoPPvThzHy9aN+PCxse9g=
github.com/testcontainers/testcontainers-go/modules/mysql v0.30.0/go.mod h1:Srnlf7wwA7s6K4sKKhjAoBHJcKorRINR/i5dCA4ZyGk=
github.com/testcontainers/testcontainers-go/modules/postgres v0.30.0 h1:D3HFqpZS90iRGAN7M85DFiuhPfvYvFNnx8urQ6mPAvo=
github.com/testcontainers/testcontainers-go/modules/postgres v0.30.0/go.mod h1:e1sKxwUOkqzvaqdHl/oV9mUtFmkDPTfBGp0po2tnWQU=
github.com/tetratelabs/wazero v1.3.0 h1:nqw7zCldxE06B8zSZAY0ACrR9OH5QCcPwYmYlwtcwtE=
github.com/tetratelabs/wazero v1.3.0/go.mod h1:wYx2gNRg8/WihJfSDxA1TIL8H+GkfLYm+bIfbblu9VQ=
github.com/throttled/throttled/v2 v2.12.0 h1:IezKE1uHlYC/0Al05oZV6Ar+uN/znw3cy9J8banxhEY=
github.com/throttled/throttled/v2 v2.12.0/go.mod h1:+EAvrG2hZAQTx8oMpBu8fq6Xmm+d1P2luKK7fIY1Esc=
github.com/tidwall/gjson v1.14.0 h1:6aeJ0bzojgWLa82gDQHcx3S0Lr/O51I9bJ5nv6JFx5w=
github.com/tidwall/gjson v1.14.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/gjson v1.17.1 h1:wlYEnwqAHgzmhNUFfw7Xalt2JzQvsMx2Se4PcoFCT/U=
github.com/tidwall/gjson v1.17.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
@ -1685,7 +1757,9 @@ github.com/tj/assert v0.0.0-20190920132354-ee03d75cd160 h1:NSWpaDaurcAJY7PkL8Xt0
github.com/tj/assert v0.0.0-20190920132354-ee03d75cd160/go.mod h1:mZ9/Rh9oLWpLLDRpvE+3b7gP/C2YyLFYxNmcLnPTMe0=
github.com/tj/go-naturaldate v1.3.0 h1:OgJIPkR/Jk4bFMBLbxZ8w+QUxwjqSvzd9x+yXocY4RI=
github.com/tj/go-naturaldate v1.3.0/go.mod h1:rpUbjivDKiS1BlfMGc2qUKNZ/yxgthOfmytQs8d8hKk=
github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU=
github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI=
github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk=
github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY=
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80 h1:nrZ3ySNYwJbSpD6ce9duiP+QkD3JuLCcWkdaehUS/3Y=
@ -1840,42 +1914,42 @@ go.opentelemetry.io/contrib/config v0.1.1 h1:lIUTrMWkfDE0GvzBLhwv6ATDB1vntrnTsRv
go.opentelemetry.io/contrib/config v0.1.1/go.mod h1:rDrK4+PS6Cs+WIphU/GO5Sk4TGV36lEQqk/Z1vZkaLI=
go.opentelemetry.io/contrib/detectors/gcp v1.24.0 h1:1Szzq5d735VbnwbEmwPUJ/FIpY9CPM9KYfCRsSNjPgw=
go.opentelemetry.io/contrib/detectors/gcp v1.24.0/go.mod h1:KAZHUFgklT30k9ZaYrDyg6v/T5EfBq6Eqg03H6ywN6Q=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 h1:4Pp6oUg3+e/6M4C0A/3kJ2VYa++dsWVTtGgLVj5xtHg=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0/go.mod h1:Mjt1i1INqiaoZOMGR1RIUJN+i3ChKoFRqzrRQhlkbs0=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.50.0 h1:zvpPXY7RfYAGSdYQLjp6zxdJNSYD/+FFoCTQN9IPxBs=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.50.0/go.mod h1:BMn8NB1vsxTljvuorms2hyOs8IBuuBEq0pl7ltOfy30=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.51.0 h1:Xs2Ncz0gNihqu9iosIZ5SkBbWo5T8JhhLJFMQL1qmLI=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.51.0/go.mod h1:vy+2G/6NvVMpwGX/NyLqcC41fxepnuKHk16E6IZUcJc=
go.opentelemetry.io/contrib/propagators/jaeger v1.24.0 h1:CKtIfwSgDvJmaWsZROcHzONZgmQdMYn9mVYWypOWT5o=
go.opentelemetry.io/contrib/propagators/jaeger v1.24.0/go.mod h1:Q5JA/Cfdy/ta+5VeEhrMJRWGyS6UNRwFbl+yS3W1h5I=
go.opentelemetry.io/contrib/propagators/ot v1.24.0 h1:6lf4HoYefKDOTUSCatwkpzliUYihAvlN0omfpOn5IDs=
go.opentelemetry.io/contrib/propagators/ot v1.24.0/go.mod h1:A406hNQ7A0EWsOFzWI1p53YaYQXe12C9f6wGHUxfh0g=
go.opentelemetry.io/otel v0.14.0/go.mod h1:vH5xEuwy7Rts0GNtsCW3HYQoZDY+OmBJ6t1bFGGlxgw=
go.opentelemetry.io/otel v1.6.3/go.mod h1:7BgNga5fNlF/iZjG06hM3yofffp0ofKCDwSXx1GC4dI=
go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo=
go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo=
go.opentelemetry.io/otel v1.26.0 h1:LQwgL5s/1W7YiiRwxf03QGnWLb2HW4pLiAhaA5cZXBs=
go.opentelemetry.io/otel v1.26.0/go.mod h1:UmLkJHUAidDval2EICqBMbnAd0/m2vmpf/dAM+fvFs4=
go.opentelemetry.io/otel/bridge/opentracing v1.22.0 h1:ZujpdLoATPdsyzp8hE5xW3jCNVZE46eMm42eu1JuxKk=
go.opentelemetry.io/otel/bridge/opentracing v1.22.0/go.mod h1:tnna9idtdH9//GUou9KCMo9pmnU9G14zrosFeeaqFP0=
go.opentelemetry.io/otel/exporters/jaeger v1.17.0 h1:D7UpUy2Xc2wsi1Ras6V40q806WM07rqoCWzXu7Sqy+4=
go.opentelemetry.io/otel/exporters/jaeger v1.17.0/go.mod h1:nPCqOnEH9rNLKqH/+rrUjiMzHJdV1BlpKcTwRTyKkKI=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0 h1:t6wl9SPayj+c7lEIFgm4ooDBZVb01IhLB4InpomhRw8=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0/go.mod h1:iSDOcsnSA5INXzZtwaBPrKp/lWu/V14Dd+llD0oI2EA=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.24.0 h1:Mw5xcxMwlqoJd97vwPxA8isEaIoxsta9/Q51+TTJLGE=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.24.0/go.mod h1:CQNu9bj7o7mC6U7+CA/schKEYakYXWr79ucDHTMGhCM=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.25.0 h1:dT33yIHtmsqpixFsSQPwNeY5drM9wTcoL8h0FWF4oGM=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.25.0/go.mod h1:h95q0LBGh7hlAC08X2DhSeyIG02YQ0UyioTCVAqRPmc=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.25.0 h1:vOL89uRfOCCNIjkisd0r7SEdJF3ZJFyCNY34fdZs8eU=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.25.0/go.mod h1:8GlBGcDk8KKi7n+2S4BT/CPZQYH3erLu0/k64r1MYgo=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.22.0 h1:FyjCyI9jVEfqhUh2MoSkmolPjfh5fp2hnV0b0irxH4Q=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.22.0/go.mod h1:hYwym2nDEeZfG/motx0p7L7J1N1vyzIThemQsb4g2qY=
go.opentelemetry.io/otel/exporters/prometheus v0.46.0 h1:I8WIFXR351FoLJYuloU4EgXbtNX2URfU/85pUPheIEQ=
go.opentelemetry.io/otel/exporters/prometheus v0.46.0/go.mod h1:ztwVUHe5DTR/1v7PeuGRnU5Bbd4QKYwApWmuutKsJSs=
go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI=
go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco=
go.opentelemetry.io/otel/sdk v1.24.0 h1:YMPPDNymmQN3ZgczicBY3B6sf9n62Dlj9pWD3ucgoDw=
go.opentelemetry.io/otel/sdk v1.24.0/go.mod h1:KVrIYw6tEubO9E96HQpcmpTKDVn9gdv35HoYiQWGDFg=
go.opentelemetry.io/otel/metric v1.26.0 h1:7S39CLuY5Jgg9CrnA9HHiEjGMF/X2VHvoXGgSllRz30=
go.opentelemetry.io/otel/metric v1.26.0/go.mod h1:SY+rHOI4cEawI9a7N1A4nIg/nTQXe1ccCNWYOJUrpX4=
go.opentelemetry.io/otel/sdk v1.25.0 h1:PDryEJPC8YJZQSyLY5eqLeafHtG+X7FWnf3aXMtxbqo=
go.opentelemetry.io/otel/sdk v1.25.0/go.mod h1:oFgzCM2zdsxKzz6zwpTZYLLQsFwc+K0daArPdIhuxkw=
go.opentelemetry.io/otel/sdk/metric v1.24.0 h1:yyMQrPzF+k88/DbH7o4FMAs80puqd+9osbiBrJrz/w8=
go.opentelemetry.io/otel/sdk/metric v1.24.0/go.mod h1:I6Y5FjH6rvEnTTAYQz3Mmv2kl6Ek5IIrmwTLqMrrOE0=
go.opentelemetry.io/otel/trace v1.6.3/go.mod h1:GNJQusJlUgZl9/TQBPKU/Y/ty+0iVB5fjhKeJGZPGFs=
go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI=
go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU=
go.opentelemetry.io/otel/trace v1.26.0 h1:1ieeAUb4y0TE26jUFrCIXKpTuVK7uJGN9/Z/2LP5sQA=
go.opentelemetry.io/otel/trace v1.26.0/go.mod h1:4iDxvGDQuUkHve82hJJ8UqrwswHYsZuWCBllGV2U2y0=
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
go.opentelemetry.io/proto/otlp v1.1.0 h1:2Di21piLrCqJ3U3eXGCTPHE9R8Nh+0uglSnOyxikMeI=
go.opentelemetry.io/proto/otlp v1.1.0/go.mod h1:GpBHCBWiqvVLDqmHZsoMM3C5ySeKTC7ej/RNTae6MdY=
go.opentelemetry.io/proto/otlp v1.2.0 h1:pVeZGk7nXDC9O2hncA6nHldxEjm6LByfA2aN8IOkz94=
go.opentelemetry.io/proto/otlp v1.2.0/go.mod h1:gGpR8txAl5M03pDhMC79G6SdqNV26naRm/KDsgaHD8A=
go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5/go.mod h1:nmDLcffg48OtT/PSW0Hg7FvpRQsQh5OSqIylirxKC7o=
go.starlark.net v0.0.0-20210223155950-e043a3d3c984/go.mod h1:t3mmBBPzAVvK0L0n1drDmrQsJ8FoIx4INCqVMTr/Zo0=
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
@ -1887,8 +1961,11 @@ 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/automaxprocs v1.5.2 h1:2LxUOGiR3O6tw8ui5sZa2LAaHnsviZdVOUZw4fvbnME=
go.uber.org/automaxprocs v1.5.2/go.mod h1:eRbA25aqJrxAbsLO0xy5jVwPt7FQnRgjW+efnwa1WM0=
go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
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.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=
@ -1902,8 +1979,9 @@ 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.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo=
go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so=
go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI=
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
@ -2023,7 +2101,6 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8=
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
@ -2056,8 +2133,8 @@ golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ
golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.19.0 h1:9+E/EZBCbTLNrbN35fHv/a/d/mOBatymz1zbtQrXpIg=
golang.org/x/oauth2 v0.19.0/go.mod h1:vYi7skDa1x015PmRRYZ7+s1cWyPgrPiSYRe4rnsexc8=
golang.org/x/oauth2 v0.20.0 h1:4mQdhULixXKP1rwYBW0vAijoXnkTG0BLCDRzfe1idMo=
golang.org/x/oauth2 v0.20.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
golang.org/x/sync v0.0.0-20170517211232-f52d1811a629/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@ -2107,7 +2184,6 @@ golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20191002063906-3421d5a6bb1c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -2138,7 +2214,6 @@ golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201207223542-d4d67f95c62d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -2158,6 +2233,7 @@ golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220406163625-3f8b81556e12/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@ -2238,6 +2314,7 @@ golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtn
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
@ -2274,7 +2351,6 @@ golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82u
golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
@ -2362,6 +2438,7 @@ google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfG
google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
@ -2385,8 +2462,8 @@ google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaE
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 h1:9+tzLLstTlPTRyJTh+ah5wIMsBW5c4tQwGTN3thOW9Y=
google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9/go.mod h1:mqHbVIp48Muh7Ywss/AD6I5kNVKZMmAa/QEW58Gxp2s=
google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237 h1:RFiFrvy37/mpSpdySBDrUdipW/dHwsRwh3J3+A9VgT4=
google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237/go.mod h1:Z5Iiy3jtmioajWHDGFk7CeugTyHtPvMHA4UTmUkyalE=
google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157 h1:7whR9kGa5LUwFtpLm2ArCEejtnxlGeLbAyjFY8sGNFw=
google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157/go.mod h1:99sLkeliLXfdj2J75X3Ho+rrVCaJze0uwN7zDDkjPVU=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240617180043-68d350f18fd4 h1:Di6ANFilr+S60a4S61ZM00vLdw0IrQOSMS2/6mrnOU0=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240617180043-68d350f18fd4/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY=
google.golang.org/grpc v1.2.1-0.20170921194603-d4b75ebd4f9f/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
@ -2456,6 +2533,8 @@ gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:a
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
@ -2479,12 +2558,12 @@ gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gorm.io/driver/postgres v1.5.7 h1:8ptbNJTDbEmhdr62uReG5BGkdQyeasu/FZHxI0IMGnM=
gorm.io/driver/postgres v1.5.7/go.mod h1:3e019WlBaYI5o5LIdNV+LyxCMNtLOQETBXL2h4chKpA=
gorm.io/driver/postgres v1.5.9 h1:DkegyItji119OlcaLjqN11kHoUgZ/j13E0jkJZgD6A8=
gorm.io/driver/postgres v1.5.9/go.mod h1:DX3GReXH+3FPWGrrgffdvCk3DQ1dwDPdmbenSkweRGI=
gorm.io/driver/sqlite v1.5.0 h1:zKYbzRCpBrT1bNijRnxLDJWPjVfImGEn0lSnUY5gZ+c=
gorm.io/driver/sqlite v1.5.0/go.mod h1:kDMDfntV9u/vuMmz8APHtHF0b4nyBB7sfCieC6G8k8I=
gorm.io/gorm v1.25.7-0.20240204074919-46816ad31dde h1:9DShaph9qhkIYw7QF91I/ynrr4cOO2PZra2PFD7Mfeg=
gorm.io/gorm v1.25.7-0.20240204074919-46816ad31dde/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
gorm.io/gorm v1.25.10 h1:dQpO+33KalOA+aFYGlK+EfxcI5MbO7EP2yYygwh9h+s=
gorm.io/gorm v1.25.10/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
gorm.io/plugin/opentelemetry v0.1.4 h1:7p0ocWELjSSRI7NCKPW2mVe6h43YPini99sNJcbsTuc=
gorm.io/plugin/opentelemetry v0.1.4/go.mod h1:tndJHOdvPT0pyGhOb8E2209eXJCUxhC5UpKw7bGVWeI=
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
@ -2519,6 +2598,20 @@ k8s.io/utils v0.0.0-20230726121419-3b25d923346b h1:sgn3ZU783SCgtaSJjpcVVlRqd6GSn
k8s.io/utils v0.0.0-20230726121419-3b25d923346b/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
layeh.com/gopher-luar v1.0.10 h1:55b0mpBhN9XSshEd2Nz6WsbYXctyBT35azk4POQNSXo=
layeh.com/gopher-luar v1.0.10/go.mod h1:TPnIVCZ2RJBndm7ohXyaqfhzjlZ+OA2SZR/YwL8tECk=
modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6 h1:5D53IMaUuA5InSeMu9eJtlQXS2NxAhyWQvkKEgXZhHI=
modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6/go.mod h1:Qz0X07sNOR1jWYCrJMEnbW/X55x206Q7Vt4mz6/wHp4=
modernc.org/libc v1.41.0 h1:g9YAc6BkKlgORsUWj+JwqoB1wU3o4DE3bM3yvA3k+Gk=
modernc.org/libc v1.41.0/go.mod h1:w0eszPsiXoOnoMJgrXjglgLuDy/bt5RR4y3QzUUeodY=
modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4=
modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo=
modernc.org/memory v1.7.2 h1:Klh90S215mmH8c9gO98QxQFsY+W451E8AnzjoE2ee1E=
modernc.org/memory v1.7.2/go.mod h1:NO4NVCQy0N7ln+T9ngWqOQfi7ley4vpwvARR+Hjw95E=
modernc.org/sqlite v1.29.6 h1:0lOXGrycJPptfHDuohfYgNqoe4hu+gYuN/pKgY5XjS4=
modernc.org/sqlite v1.29.6/go.mod h1:S02dvcmm7TnTRvGhv8IGYyLnIt7AS2KPaB1F/71p75U=
modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA=
modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0=
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=
modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
mvdan.cc/gofumpt v0.4.0/go.mod h1:PljLOHDeZqgS8opHRKLzp2It2VBuSdteAgqUfzMTxlQ=
mvdan.cc/gofumpt v0.5.0 h1:0EQ+Z56k8tXjj/6TQD25BFNKQXpCvT0rnansIc7Ug5E=
mvdan.cc/gofumpt v0.5.0/go.mod h1:HBeVDtMKRZpXyxFciAirzdKklDlGu8aAy1wEbH5Y9js=

View File

@ -3,41 +3,27 @@ load("//dev:go_defs.bzl", "go_test")
go_library(
name = "redislock",
srcs = [
"mutex.go",
"redislock.go",
],
srcs = ["redislock.go"],
importpath = "github.com/sourcegraph/sourcegraph/internal/redislock",
visibility = ["//:__subpackages__"],
deps = [
"//internal/redispool",
"//lib/errors",
"@com_github_go_redsync_redsync_v4//:redsync",
"@com_github_go_redsync_redsync_v4//redis/goredis/v9:goredis",
"@com_github_gomodule_redigo//redis",
"@com_github_google_uuid//:uuid",
"@com_github_redis_go_redis_v9//:go-redis",
"@com_github_sourcegraph_log//:log",
],
)
go_test(
name = "redislock_test",
srcs = [
"mutex_test.go",
"redislock_test.go",
],
srcs = ["redislock_test.go"],
embed = [":redislock"],
tags = [
# Test requires localhost database
"requires-network",
],
deps = [
"//internal/rcache",
"//internal/redispool",
"@com_github_derision_test_go_mockgen_v2//testutil/require",
"@com_github_redis_go_redis_v9//:go-redis",
"@com_github_sourcegraph_log//logtest",
"@com_github_stretchr_testify//assert",
"@com_github_stretchr_testify//require",
],

File diff suppressed because it is too large Load Diff

View File

@ -48,8 +48,7 @@ service SubscriptionsService {
option idempotency_level = IDEMPOTENT;
}
// UpdateEnterpriseSubscription updates an existing Enterprise subscription.
// Only properties specified by the update_mask are applied.
// UpdateEnterpriseSubscription updates an existing enterprise subscription.
rpc UpdateEnterpriseSubscription(UpdateEnterpriseSubscriptionRequest) returns (UpdateEnterpriseSubscriptionResponse) {
option idempotency_level = IDEMPOTENT;
}
@ -69,9 +68,8 @@ service SubscriptionsService {
// optional idempotency in the future.
}
// UpdateSubscriptionMembership updates a subscription membership. It creates
// a new one if it does not exist and allow_missing is set to true.
rpc UpdateSubscriptionMembership(UpdateSubscriptionMembershipRequest) returns (UpdateSubscriptionMembershipResponse) {
// UpdateEnterpriseSubscriptionMembership updates an enterprise subscription membership.
rpc UpdateEnterpriseSubscriptionMembership(UpdateEnterpriseSubscriptionMembershipRequest) returns (UpdateEnterpriseSubscriptionMembershipResponse) {
option idempotency_level = IDEMPOTENT;
}
}
@ -216,6 +214,17 @@ enum EnterpriseSubscriptionLicenseType {
ENTERPRISE_SUBSCRIPTION_LICENSE_TYPE_KEY = 1;
}
message ListEnterpriseSubscriptionsFilter {
oneof filter {
// Return only product subscriptions has the given subscription ID.
string subscription_id = 1;
// Return only product subscriptions with the given archival status.
bool is_archived = 2;
// Return only product subscriptions that satisfies the given permission.
Permission permission = 3;
}
}
message ListEnterpriseSubscriptionsRequest {
// Clients use this field to specify the maximum number of results to be
// returned by the server. The server may further constrain the maximum number
@ -228,6 +237,10 @@ message ListEnterpriseSubscriptionsRequest {
//
// See pagination concepts from https://cloud.google.com/apis/design/design_patterns#list_pagination
string page_token = 2;
// Filters define the lookup strategy for this list request. Multiple filters
// are treated as AND-concatenated.
repeated ListEnterpriseSubscriptionsFilter filters = 3;
}
message ListEnterpriseSubscriptionsResponse {
@ -250,16 +263,6 @@ message ListEnterpriseSubscriptionLicensesFilter {
// Return only product subscriptions whose license key contains this
// substring.
string license_key_substring = 4;
// Return only product subscriptions whose license key contains the given member.
Member member = 5;
}
message Member {
// Return only product subscriptions contains the member with given SAMS
// account ID.
string sams_account_id = 1;
// Return only product subscriptions contains the member with the given permission.
string permission = 2;
}
}
@ -332,8 +335,7 @@ message UpdateEnterpriseSubscriptionRequest {
// The list of fields to update, fields are specified relative to the EnterpriseSubscription.
// Updatable fields are:
// - display_name
// - domain
// - instance_domain
google.protobuf.FieldMask update_mask = 2;
}
@ -376,20 +378,46 @@ message EnterpriseSubscriptionMembership {
string instance_domain = 2;
// The SAMS account ID of the member.
string member_sams_account_id = 3;
// The roles of the member, e.g. "cody_analytics::customer_admin".
repeated string member_roles = 4;
// The roles of the member.
repeated Role member_roles = 4;
}
message UpdateSubscriptionMembershipRequest {
message UpdateEnterpriseSubscriptionMembershipRequest {
// The membership to update.
// The following fields are used to identify the membership to update:
// The first non-empty field of the following fields is used to identify the product subscription to update:
// - subscription_id
// - instance_domain
// Multiple fields are treated as AND-concatenated.
EnterpriseSubscriptionMembership membership = 1;
// If set to true, and the membership is not found, a new membership will be created.
bool allow_missing = 2;
}
message UpdateSubscriptionMembershipResponse {}
message UpdateEnterpriseSubscriptionMembershipResponse {}
// Role represents a role that can be granted to a user.
enum Role {
ROLE_UNSPECIFIED = 0;
ROLE_SUBSCRIPTION_CODY_ANALYTICS_CUSTOMER_ADMIN = 1;
}
// Permission represents a permission that can be performed by a user.
message Permission {
// The type of the permission.
PermissionType type = 1;
// The relation between the user and the resource.
PermissionRelation relation = 2;
// The SAMS account ID of the user.
string sams_account_id = 3;
}
// PermissionType defines a class of objects with similar characteristics.
// https://openfga.dev/docs/concepts#what-is-a-type
enum PermissionType {
PERMISSION_TYPE_UNSPECIFIED = 0;
PERMISSION_TYPE_SUBSCRIPTION_CODY_ANALYTICS = 1;
}
// PermissionRelation represents the relation between the user and the resource.
enum PermissionRelation {
PERMISSION_RELATION_UNSPECIFIED = 0;
PERMISSION_RELATION_VIEW = 1;
}

View File

@ -19,15 +19,15 @@ import (
const _ = grpc.SupportPackageIsVersion7
const (
SubscriptionsService_GetEnterpriseSubscription_FullMethodName = "/enterpriseportal.subscriptions.v1.SubscriptionsService/GetEnterpriseSubscription"
SubscriptionsService_ListEnterpriseSubscriptions_FullMethodName = "/enterpriseportal.subscriptions.v1.SubscriptionsService/ListEnterpriseSubscriptions"
SubscriptionsService_ListEnterpriseSubscriptionLicenses_FullMethodName = "/enterpriseportal.subscriptions.v1.SubscriptionsService/ListEnterpriseSubscriptionLicenses"
SubscriptionsService_CreateEnterpriseSubscriptionLicense_FullMethodName = "/enterpriseportal.subscriptions.v1.SubscriptionsService/CreateEnterpriseSubscriptionLicense"
SubscriptionsService_RevokeEnterpriseSubscriptionLicense_FullMethodName = "/enterpriseportal.subscriptions.v1.SubscriptionsService/RevokeEnterpriseSubscriptionLicense"
SubscriptionsService_UpdateEnterpriseSubscription_FullMethodName = "/enterpriseportal.subscriptions.v1.SubscriptionsService/UpdateEnterpriseSubscription"
SubscriptionsService_ArchiveEnterpriseSubscription_FullMethodName = "/enterpriseportal.subscriptions.v1.SubscriptionsService/ArchiveEnterpriseSubscription"
SubscriptionsService_CreateEnterpriseSubscription_FullMethodName = "/enterpriseportal.subscriptions.v1.SubscriptionsService/CreateEnterpriseSubscription"
SubscriptionsService_UpdateSubscriptionMembership_FullMethodName = "/enterpriseportal.subscriptions.v1.SubscriptionsService/UpdateSubscriptionMembership"
SubscriptionsService_GetEnterpriseSubscription_FullMethodName = "/enterpriseportal.subscriptions.v1.SubscriptionsService/GetEnterpriseSubscription"
SubscriptionsService_ListEnterpriseSubscriptions_FullMethodName = "/enterpriseportal.subscriptions.v1.SubscriptionsService/ListEnterpriseSubscriptions"
SubscriptionsService_ListEnterpriseSubscriptionLicenses_FullMethodName = "/enterpriseportal.subscriptions.v1.SubscriptionsService/ListEnterpriseSubscriptionLicenses"
SubscriptionsService_CreateEnterpriseSubscriptionLicense_FullMethodName = "/enterpriseportal.subscriptions.v1.SubscriptionsService/CreateEnterpriseSubscriptionLicense"
SubscriptionsService_RevokeEnterpriseSubscriptionLicense_FullMethodName = "/enterpriseportal.subscriptions.v1.SubscriptionsService/RevokeEnterpriseSubscriptionLicense"
SubscriptionsService_UpdateEnterpriseSubscription_FullMethodName = "/enterpriseportal.subscriptions.v1.SubscriptionsService/UpdateEnterpriseSubscription"
SubscriptionsService_ArchiveEnterpriseSubscription_FullMethodName = "/enterpriseportal.subscriptions.v1.SubscriptionsService/ArchiveEnterpriseSubscription"
SubscriptionsService_CreateEnterpriseSubscription_FullMethodName = "/enterpriseportal.subscriptions.v1.SubscriptionsService/CreateEnterpriseSubscription"
SubscriptionsService_UpdateEnterpriseSubscriptionMembership_FullMethodName = "/enterpriseportal.subscriptions.v1.SubscriptionsService/UpdateEnterpriseSubscriptionMembership"
)
// SubscriptionsServiceClient is the client API for SubscriptionsService service.
@ -51,8 +51,7 @@ type SubscriptionsServiceClient interface {
// Enterprise subscription, permanently disabling its use for features
// managed by Sourcegraph. Revocation cannot be undone.
RevokeEnterpriseSubscriptionLicense(ctx context.Context, in *RevokeEnterpriseSubscriptionLicenseRequest, opts ...grpc.CallOption) (*RevokeEnterpriseSubscriptionLicenseResponse, error)
// UpdateEnterpriseSubscription updates an existing Enterprise subscription.
// Only properties specified by the update_mask are applied.
// UpdateEnterpriseSubscription updates an existing enterprise subscription.
UpdateEnterpriseSubscription(ctx context.Context, in *UpdateEnterpriseSubscriptionRequest, opts ...grpc.CallOption) (*UpdateEnterpriseSubscriptionResponse, error)
// ArchiveEnterpriseSubscriptionRequest archives an existing Enterprise
// subscription. This is a permanent operation, and cannot be undone.
@ -62,9 +61,8 @@ type SubscriptionsServiceClient interface {
ArchiveEnterpriseSubscription(ctx context.Context, in *ArchiveEnterpriseSubscriptionRequest, opts ...grpc.CallOption) (*ArchiveEnterpriseSubscriptionResponse, error)
// CreateEnterpriseSubscription creates an Enterprise subscription.
CreateEnterpriseSubscription(ctx context.Context, in *CreateEnterpriseSubscriptionRequest, opts ...grpc.CallOption) (*CreateEnterpriseSubscriptionResponse, error)
// UpdateSubscriptionMembership updates a subscription membership. It creates
// a new one if it does not exist and allow_missing is set to true.
UpdateSubscriptionMembership(ctx context.Context, in *UpdateSubscriptionMembershipRequest, opts ...grpc.CallOption) (*UpdateSubscriptionMembershipResponse, error)
// UpdateEnterpriseSubscriptionMembership updates an enterprise subscription membership.
UpdateEnterpriseSubscriptionMembership(ctx context.Context, in *UpdateEnterpriseSubscriptionMembershipRequest, opts ...grpc.CallOption) (*UpdateEnterpriseSubscriptionMembershipResponse, error)
}
type subscriptionsServiceClient struct {
@ -147,9 +145,9 @@ func (c *subscriptionsServiceClient) CreateEnterpriseSubscription(ctx context.Co
return out, nil
}
func (c *subscriptionsServiceClient) UpdateSubscriptionMembership(ctx context.Context, in *UpdateSubscriptionMembershipRequest, opts ...grpc.CallOption) (*UpdateSubscriptionMembershipResponse, error) {
out := new(UpdateSubscriptionMembershipResponse)
err := c.cc.Invoke(ctx, SubscriptionsService_UpdateSubscriptionMembership_FullMethodName, in, out, opts...)
func (c *subscriptionsServiceClient) UpdateEnterpriseSubscriptionMembership(ctx context.Context, in *UpdateEnterpriseSubscriptionMembershipRequest, opts ...grpc.CallOption) (*UpdateEnterpriseSubscriptionMembershipResponse, error) {
out := new(UpdateEnterpriseSubscriptionMembershipResponse)
err := c.cc.Invoke(ctx, SubscriptionsService_UpdateEnterpriseSubscriptionMembership_FullMethodName, in, out, opts...)
if err != nil {
return nil, err
}
@ -177,8 +175,7 @@ type SubscriptionsServiceServer interface {
// Enterprise subscription, permanently disabling its use for features
// managed by Sourcegraph. Revocation cannot be undone.
RevokeEnterpriseSubscriptionLicense(context.Context, *RevokeEnterpriseSubscriptionLicenseRequest) (*RevokeEnterpriseSubscriptionLicenseResponse, error)
// UpdateEnterpriseSubscription updates an existing Enterprise subscription.
// Only properties specified by the update_mask are applied.
// UpdateEnterpriseSubscription updates an existing enterprise subscription.
UpdateEnterpriseSubscription(context.Context, *UpdateEnterpriseSubscriptionRequest) (*UpdateEnterpriseSubscriptionResponse, error)
// ArchiveEnterpriseSubscriptionRequest archives an existing Enterprise
// subscription. This is a permanent operation, and cannot be undone.
@ -188,9 +185,8 @@ type SubscriptionsServiceServer interface {
ArchiveEnterpriseSubscription(context.Context, *ArchiveEnterpriseSubscriptionRequest) (*ArchiveEnterpriseSubscriptionResponse, error)
// CreateEnterpriseSubscription creates an Enterprise subscription.
CreateEnterpriseSubscription(context.Context, *CreateEnterpriseSubscriptionRequest) (*CreateEnterpriseSubscriptionResponse, error)
// UpdateSubscriptionMembership updates a subscription membership. It creates
// a new one if it does not exist and allow_missing is set to true.
UpdateSubscriptionMembership(context.Context, *UpdateSubscriptionMembershipRequest) (*UpdateSubscriptionMembershipResponse, error)
// UpdateEnterpriseSubscriptionMembership updates an enterprise subscription membership.
UpdateEnterpriseSubscriptionMembership(context.Context, *UpdateEnterpriseSubscriptionMembershipRequest) (*UpdateEnterpriseSubscriptionMembershipResponse, error)
mustEmbedUnimplementedSubscriptionsServiceServer()
}
@ -222,8 +218,8 @@ func (UnimplementedSubscriptionsServiceServer) ArchiveEnterpriseSubscription(con
func (UnimplementedSubscriptionsServiceServer) CreateEnterpriseSubscription(context.Context, *CreateEnterpriseSubscriptionRequest) (*CreateEnterpriseSubscriptionResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method CreateEnterpriseSubscription not implemented")
}
func (UnimplementedSubscriptionsServiceServer) UpdateSubscriptionMembership(context.Context, *UpdateSubscriptionMembershipRequest) (*UpdateSubscriptionMembershipResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method UpdateSubscriptionMembership not implemented")
func (UnimplementedSubscriptionsServiceServer) UpdateEnterpriseSubscriptionMembership(context.Context, *UpdateEnterpriseSubscriptionMembershipRequest) (*UpdateEnterpriseSubscriptionMembershipResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method UpdateEnterpriseSubscriptionMembership not implemented")
}
func (UnimplementedSubscriptionsServiceServer) mustEmbedUnimplementedSubscriptionsServiceServer() {}
@ -382,20 +378,20 @@ func _SubscriptionsService_CreateEnterpriseSubscription_Handler(srv interface{},
return interceptor(ctx, in, info, handler)
}
func _SubscriptionsService_UpdateSubscriptionMembership_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(UpdateSubscriptionMembershipRequest)
func _SubscriptionsService_UpdateEnterpriseSubscriptionMembership_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(UpdateEnterpriseSubscriptionMembershipRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(SubscriptionsServiceServer).UpdateSubscriptionMembership(ctx, in)
return srv.(SubscriptionsServiceServer).UpdateEnterpriseSubscriptionMembership(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: SubscriptionsService_UpdateSubscriptionMembership_FullMethodName,
FullMethod: SubscriptionsService_UpdateEnterpriseSubscriptionMembership_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(SubscriptionsServiceServer).UpdateSubscriptionMembership(ctx, req.(*UpdateSubscriptionMembershipRequest))
return srv.(SubscriptionsServiceServer).UpdateEnterpriseSubscriptionMembership(ctx, req.(*UpdateEnterpriseSubscriptionMembershipRequest))
}
return interceptor(ctx, in, info, handler)
}
@ -440,8 +436,8 @@ var SubscriptionsService_ServiceDesc = grpc.ServiceDesc{
Handler: _SubscriptionsService_CreateEnterpriseSubscription_Handler,
},
{
MethodName: "UpdateSubscriptionMembership",
Handler: _SubscriptionsService_UpdateSubscriptionMembership_Handler,
MethodName: "UpdateEnterpriseSubscriptionMembership",
Handler: _SubscriptionsService_UpdateEnterpriseSubscriptionMembership_Handler,
},
},
Streams: []grpc.StreamDesc{},

View File

@ -57,23 +57,23 @@ const (
// SubscriptionsServiceCreateEnterpriseSubscriptionProcedure is the fully-qualified name of the
// SubscriptionsService's CreateEnterpriseSubscription RPC.
SubscriptionsServiceCreateEnterpriseSubscriptionProcedure = "/enterpriseportal.subscriptions.v1.SubscriptionsService/CreateEnterpriseSubscription"
// SubscriptionsServiceUpdateSubscriptionMembershipProcedure is the fully-qualified name of the
// SubscriptionsService's UpdateSubscriptionMembership RPC.
SubscriptionsServiceUpdateSubscriptionMembershipProcedure = "/enterpriseportal.subscriptions.v1.SubscriptionsService/UpdateSubscriptionMembership"
// SubscriptionsServiceUpdateEnterpriseSubscriptionMembershipProcedure is the fully-qualified name
// of the SubscriptionsService's UpdateEnterpriseSubscriptionMembership RPC.
SubscriptionsServiceUpdateEnterpriseSubscriptionMembershipProcedure = "/enterpriseportal.subscriptions.v1.SubscriptionsService/UpdateEnterpriseSubscriptionMembership"
)
// These variables are the protoreflect.Descriptor objects for the RPCs defined in this package.
var (
subscriptionsServiceServiceDescriptor = v1.File_subscriptions_proto.Services().ByName("SubscriptionsService")
subscriptionsServiceGetEnterpriseSubscriptionMethodDescriptor = subscriptionsServiceServiceDescriptor.Methods().ByName("GetEnterpriseSubscription")
subscriptionsServiceListEnterpriseSubscriptionsMethodDescriptor = subscriptionsServiceServiceDescriptor.Methods().ByName("ListEnterpriseSubscriptions")
subscriptionsServiceListEnterpriseSubscriptionLicensesMethodDescriptor = subscriptionsServiceServiceDescriptor.Methods().ByName("ListEnterpriseSubscriptionLicenses")
subscriptionsServiceCreateEnterpriseSubscriptionLicenseMethodDescriptor = subscriptionsServiceServiceDescriptor.Methods().ByName("CreateEnterpriseSubscriptionLicense")
subscriptionsServiceRevokeEnterpriseSubscriptionLicenseMethodDescriptor = subscriptionsServiceServiceDescriptor.Methods().ByName("RevokeEnterpriseSubscriptionLicense")
subscriptionsServiceUpdateEnterpriseSubscriptionMethodDescriptor = subscriptionsServiceServiceDescriptor.Methods().ByName("UpdateEnterpriseSubscription")
subscriptionsServiceArchiveEnterpriseSubscriptionMethodDescriptor = subscriptionsServiceServiceDescriptor.Methods().ByName("ArchiveEnterpriseSubscription")
subscriptionsServiceCreateEnterpriseSubscriptionMethodDescriptor = subscriptionsServiceServiceDescriptor.Methods().ByName("CreateEnterpriseSubscription")
subscriptionsServiceUpdateSubscriptionMembershipMethodDescriptor = subscriptionsServiceServiceDescriptor.Methods().ByName("UpdateSubscriptionMembership")
subscriptionsServiceServiceDescriptor = v1.File_subscriptions_proto.Services().ByName("SubscriptionsService")
subscriptionsServiceGetEnterpriseSubscriptionMethodDescriptor = subscriptionsServiceServiceDescriptor.Methods().ByName("GetEnterpriseSubscription")
subscriptionsServiceListEnterpriseSubscriptionsMethodDescriptor = subscriptionsServiceServiceDescriptor.Methods().ByName("ListEnterpriseSubscriptions")
subscriptionsServiceListEnterpriseSubscriptionLicensesMethodDescriptor = subscriptionsServiceServiceDescriptor.Methods().ByName("ListEnterpriseSubscriptionLicenses")
subscriptionsServiceCreateEnterpriseSubscriptionLicenseMethodDescriptor = subscriptionsServiceServiceDescriptor.Methods().ByName("CreateEnterpriseSubscriptionLicense")
subscriptionsServiceRevokeEnterpriseSubscriptionLicenseMethodDescriptor = subscriptionsServiceServiceDescriptor.Methods().ByName("RevokeEnterpriseSubscriptionLicense")
subscriptionsServiceUpdateEnterpriseSubscriptionMethodDescriptor = subscriptionsServiceServiceDescriptor.Methods().ByName("UpdateEnterpriseSubscription")
subscriptionsServiceArchiveEnterpriseSubscriptionMethodDescriptor = subscriptionsServiceServiceDescriptor.Methods().ByName("ArchiveEnterpriseSubscription")
subscriptionsServiceCreateEnterpriseSubscriptionMethodDescriptor = subscriptionsServiceServiceDescriptor.Methods().ByName("CreateEnterpriseSubscription")
subscriptionsServiceUpdateEnterpriseSubscriptionMembershipMethodDescriptor = subscriptionsServiceServiceDescriptor.Methods().ByName("UpdateEnterpriseSubscriptionMembership")
)
// SubscriptionsServiceClient is a client for the
@ -96,8 +96,7 @@ type SubscriptionsServiceClient interface {
// Enterprise subscription, permanently disabling its use for features
// managed by Sourcegraph. Revocation cannot be undone.
RevokeEnterpriseSubscriptionLicense(context.Context, *connect.Request[v1.RevokeEnterpriseSubscriptionLicenseRequest]) (*connect.Response[v1.RevokeEnterpriseSubscriptionLicenseResponse], error)
// UpdateEnterpriseSubscription updates an existing Enterprise subscription.
// Only properties specified by the update_mask are applied.
// UpdateEnterpriseSubscription updates an existing enterprise subscription.
UpdateEnterpriseSubscription(context.Context, *connect.Request[v1.UpdateEnterpriseSubscriptionRequest]) (*connect.Response[v1.UpdateEnterpriseSubscriptionResponse], error)
// ArchiveEnterpriseSubscriptionRequest archives an existing Enterprise
// subscription. This is a permanent operation, and cannot be undone.
@ -107,9 +106,8 @@ type SubscriptionsServiceClient interface {
ArchiveEnterpriseSubscription(context.Context, *connect.Request[v1.ArchiveEnterpriseSubscriptionRequest]) (*connect.Response[v1.ArchiveEnterpriseSubscriptionResponse], error)
// CreateEnterpriseSubscription creates an Enterprise subscription.
CreateEnterpriseSubscription(context.Context, *connect.Request[v1.CreateEnterpriseSubscriptionRequest]) (*connect.Response[v1.CreateEnterpriseSubscriptionResponse], error)
// UpdateSubscriptionMembership updates a subscription membership. It creates
// a new one if it does not exist and allow_missing is set to true.
UpdateSubscriptionMembership(context.Context, *connect.Request[v1.UpdateSubscriptionMembershipRequest]) (*connect.Response[v1.UpdateSubscriptionMembershipResponse], error)
// UpdateEnterpriseSubscriptionMembership updates an enterprise subscription membership.
UpdateEnterpriseSubscriptionMembership(context.Context, *connect.Request[v1.UpdateEnterpriseSubscriptionMembershipRequest]) (*connect.Response[v1.UpdateEnterpriseSubscriptionMembershipResponse], error)
}
// NewSubscriptionsServiceClient constructs a client for the
@ -177,10 +175,10 @@ func NewSubscriptionsServiceClient(httpClient connect.HTTPClient, baseURL string
connect.WithSchema(subscriptionsServiceCreateEnterpriseSubscriptionMethodDescriptor),
connect.WithClientOptions(opts...),
),
updateSubscriptionMembership: connect.NewClient[v1.UpdateSubscriptionMembershipRequest, v1.UpdateSubscriptionMembershipResponse](
updateEnterpriseSubscriptionMembership: connect.NewClient[v1.UpdateEnterpriseSubscriptionMembershipRequest, v1.UpdateEnterpriseSubscriptionMembershipResponse](
httpClient,
baseURL+SubscriptionsServiceUpdateSubscriptionMembershipProcedure,
connect.WithSchema(subscriptionsServiceUpdateSubscriptionMembershipMethodDescriptor),
baseURL+SubscriptionsServiceUpdateEnterpriseSubscriptionMembershipProcedure,
connect.WithSchema(subscriptionsServiceUpdateEnterpriseSubscriptionMembershipMethodDescriptor),
connect.WithIdempotency(connect.IdempotencyIdempotent),
connect.WithClientOptions(opts...),
),
@ -189,15 +187,15 @@ func NewSubscriptionsServiceClient(httpClient connect.HTTPClient, baseURL string
// subscriptionsServiceClient implements SubscriptionsServiceClient.
type subscriptionsServiceClient struct {
getEnterpriseSubscription *connect.Client[v1.GetEnterpriseSubscriptionRequest, v1.GetEnterpriseSubscriptionResponse]
listEnterpriseSubscriptions *connect.Client[v1.ListEnterpriseSubscriptionsRequest, v1.ListEnterpriseSubscriptionsResponse]
listEnterpriseSubscriptionLicenses *connect.Client[v1.ListEnterpriseSubscriptionLicensesRequest, v1.ListEnterpriseSubscriptionLicensesResponse]
createEnterpriseSubscriptionLicense *connect.Client[v1.CreateEnterpriseSubscriptionLicenseRequest, v1.CreateEnterpriseSubscriptionLicenseResponse]
revokeEnterpriseSubscriptionLicense *connect.Client[v1.RevokeEnterpriseSubscriptionLicenseRequest, v1.RevokeEnterpriseSubscriptionLicenseResponse]
updateEnterpriseSubscription *connect.Client[v1.UpdateEnterpriseSubscriptionRequest, v1.UpdateEnterpriseSubscriptionResponse]
archiveEnterpriseSubscription *connect.Client[v1.ArchiveEnterpriseSubscriptionRequest, v1.ArchiveEnterpriseSubscriptionResponse]
createEnterpriseSubscription *connect.Client[v1.CreateEnterpriseSubscriptionRequest, v1.CreateEnterpriseSubscriptionResponse]
updateSubscriptionMembership *connect.Client[v1.UpdateSubscriptionMembershipRequest, v1.UpdateSubscriptionMembershipResponse]
getEnterpriseSubscription *connect.Client[v1.GetEnterpriseSubscriptionRequest, v1.GetEnterpriseSubscriptionResponse]
listEnterpriseSubscriptions *connect.Client[v1.ListEnterpriseSubscriptionsRequest, v1.ListEnterpriseSubscriptionsResponse]
listEnterpriseSubscriptionLicenses *connect.Client[v1.ListEnterpriseSubscriptionLicensesRequest, v1.ListEnterpriseSubscriptionLicensesResponse]
createEnterpriseSubscriptionLicense *connect.Client[v1.CreateEnterpriseSubscriptionLicenseRequest, v1.CreateEnterpriseSubscriptionLicenseResponse]
revokeEnterpriseSubscriptionLicense *connect.Client[v1.RevokeEnterpriseSubscriptionLicenseRequest, v1.RevokeEnterpriseSubscriptionLicenseResponse]
updateEnterpriseSubscription *connect.Client[v1.UpdateEnterpriseSubscriptionRequest, v1.UpdateEnterpriseSubscriptionResponse]
archiveEnterpriseSubscription *connect.Client[v1.ArchiveEnterpriseSubscriptionRequest, v1.ArchiveEnterpriseSubscriptionResponse]
createEnterpriseSubscription *connect.Client[v1.CreateEnterpriseSubscriptionRequest, v1.CreateEnterpriseSubscriptionResponse]
updateEnterpriseSubscriptionMembership *connect.Client[v1.UpdateEnterpriseSubscriptionMembershipRequest, v1.UpdateEnterpriseSubscriptionMembershipResponse]
}
// GetEnterpriseSubscription calls
@ -248,10 +246,10 @@ func (c *subscriptionsServiceClient) CreateEnterpriseSubscription(ctx context.Co
return c.createEnterpriseSubscription.CallUnary(ctx, req)
}
// UpdateSubscriptionMembership calls
// enterpriseportal.subscriptions.v1.SubscriptionsService.UpdateSubscriptionMembership.
func (c *subscriptionsServiceClient) UpdateSubscriptionMembership(ctx context.Context, req *connect.Request[v1.UpdateSubscriptionMembershipRequest]) (*connect.Response[v1.UpdateSubscriptionMembershipResponse], error) {
return c.updateSubscriptionMembership.CallUnary(ctx, req)
// UpdateEnterpriseSubscriptionMembership calls
// enterpriseportal.subscriptions.v1.SubscriptionsService.UpdateEnterpriseSubscriptionMembership.
func (c *subscriptionsServiceClient) UpdateEnterpriseSubscriptionMembership(ctx context.Context, req *connect.Request[v1.UpdateEnterpriseSubscriptionMembershipRequest]) (*connect.Response[v1.UpdateEnterpriseSubscriptionMembershipResponse], error) {
return c.updateEnterpriseSubscriptionMembership.CallUnary(ctx, req)
}
// SubscriptionsServiceHandler is an implementation of the
@ -274,8 +272,7 @@ type SubscriptionsServiceHandler interface {
// Enterprise subscription, permanently disabling its use for features
// managed by Sourcegraph. Revocation cannot be undone.
RevokeEnterpriseSubscriptionLicense(context.Context, *connect.Request[v1.RevokeEnterpriseSubscriptionLicenseRequest]) (*connect.Response[v1.RevokeEnterpriseSubscriptionLicenseResponse], error)
// UpdateEnterpriseSubscription updates an existing Enterprise subscription.
// Only properties specified by the update_mask are applied.
// UpdateEnterpriseSubscription updates an existing enterprise subscription.
UpdateEnterpriseSubscription(context.Context, *connect.Request[v1.UpdateEnterpriseSubscriptionRequest]) (*connect.Response[v1.UpdateEnterpriseSubscriptionResponse], error)
// ArchiveEnterpriseSubscriptionRequest archives an existing Enterprise
// subscription. This is a permanent operation, and cannot be undone.
@ -285,9 +282,8 @@ type SubscriptionsServiceHandler interface {
ArchiveEnterpriseSubscription(context.Context, *connect.Request[v1.ArchiveEnterpriseSubscriptionRequest]) (*connect.Response[v1.ArchiveEnterpriseSubscriptionResponse], error)
// CreateEnterpriseSubscription creates an Enterprise subscription.
CreateEnterpriseSubscription(context.Context, *connect.Request[v1.CreateEnterpriseSubscriptionRequest]) (*connect.Response[v1.CreateEnterpriseSubscriptionResponse], error)
// UpdateSubscriptionMembership updates a subscription membership. It creates
// a new one if it does not exist and allow_missing is set to true.
UpdateSubscriptionMembership(context.Context, *connect.Request[v1.UpdateSubscriptionMembershipRequest]) (*connect.Response[v1.UpdateSubscriptionMembershipResponse], error)
// UpdateEnterpriseSubscriptionMembership updates an enterprise subscription membership.
UpdateEnterpriseSubscriptionMembership(context.Context, *connect.Request[v1.UpdateEnterpriseSubscriptionMembershipRequest]) (*connect.Response[v1.UpdateEnterpriseSubscriptionMembershipResponse], error)
}
// NewSubscriptionsServiceHandler builds an HTTP handler from the service implementation. It returns
@ -350,10 +346,10 @@ func NewSubscriptionsServiceHandler(svc SubscriptionsServiceHandler, opts ...con
connect.WithSchema(subscriptionsServiceCreateEnterpriseSubscriptionMethodDescriptor),
connect.WithHandlerOptions(opts...),
)
subscriptionsServiceUpdateSubscriptionMembershipHandler := connect.NewUnaryHandler(
SubscriptionsServiceUpdateSubscriptionMembershipProcedure,
svc.UpdateSubscriptionMembership,
connect.WithSchema(subscriptionsServiceUpdateSubscriptionMembershipMethodDescriptor),
subscriptionsServiceUpdateEnterpriseSubscriptionMembershipHandler := connect.NewUnaryHandler(
SubscriptionsServiceUpdateEnterpriseSubscriptionMembershipProcedure,
svc.UpdateEnterpriseSubscriptionMembership,
connect.WithSchema(subscriptionsServiceUpdateEnterpriseSubscriptionMembershipMethodDescriptor),
connect.WithIdempotency(connect.IdempotencyIdempotent),
connect.WithHandlerOptions(opts...),
)
@ -375,8 +371,8 @@ func NewSubscriptionsServiceHandler(svc SubscriptionsServiceHandler, opts ...con
subscriptionsServiceArchiveEnterpriseSubscriptionHandler.ServeHTTP(w, r)
case SubscriptionsServiceCreateEnterpriseSubscriptionProcedure:
subscriptionsServiceCreateEnterpriseSubscriptionHandler.ServeHTTP(w, r)
case SubscriptionsServiceUpdateSubscriptionMembershipProcedure:
subscriptionsServiceUpdateSubscriptionMembershipHandler.ServeHTTP(w, r)
case SubscriptionsServiceUpdateEnterpriseSubscriptionMembershipProcedure:
subscriptionsServiceUpdateEnterpriseSubscriptionMembershipHandler.ServeHTTP(w, r)
default:
http.NotFound(w, r)
}
@ -418,6 +414,6 @@ func (UnimplementedSubscriptionsServiceHandler) CreateEnterpriseSubscription(con
return nil, connect.NewError(connect.CodeUnimplemented, errors.New("enterpriseportal.subscriptions.v1.SubscriptionsService.CreateEnterpriseSubscription is not implemented"))
}
func (UnimplementedSubscriptionsServiceHandler) UpdateSubscriptionMembership(context.Context, *connect.Request[v1.UpdateSubscriptionMembershipRequest]) (*connect.Response[v1.UpdateSubscriptionMembershipResponse], error) {
return nil, connect.NewError(connect.CodeUnimplemented, errors.New("enterpriseportal.subscriptions.v1.SubscriptionsService.UpdateSubscriptionMembership is not implemented"))
func (UnimplementedSubscriptionsServiceHandler) UpdateEnterpriseSubscriptionMembership(context.Context, *connect.Request[v1.UpdateEnterpriseSubscriptionMembershipRequest]) (*connect.Response[v1.UpdateEnterpriseSubscriptionMembershipResponse], error) {
return nil, connect.NewError(connect.CodeUnimplemented, errors.New("enterpriseportal.subscriptions.v1.SubscriptionsService.UpdateEnterpriseSubscriptionMembership is not implemented"))
}

View File

@ -14,6 +14,7 @@ require (
github.com/fatih/color v1.15.0
github.com/ghodss/yaml v1.0.0
github.com/go-enry/go-enry/v2 v2.8.4
github.com/go-redsync/redsync/v4 v4.13.0
github.com/gobwas/glob v0.2.3
github.com/google/go-cmp v0.6.0
github.com/google/uuid v1.6.0
@ -27,6 +28,7 @@ require (
github.com/mitchellh/copystructure v1.2.0
github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6
github.com/muesli/termenv v0.12.0
github.com/redis/go-redis/v9 v9.5.3
github.com/sourcegraph/conc v0.3.1-0.20240108182409-4afefce20f9b
github.com/sourcegraph/go-diff v0.6.2-0.20221123165719-f8cd299c40f3
github.com/sourcegraph/jsonx v0.0.0-20200629203448-1a936bd500cf
@ -59,10 +61,12 @@ require (
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 // indirect
github.com/aymerick/douceur v0.2.0 // indirect
github.com/bufbuild/buf v1.4.0 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
github.com/dave/jennifer v1.5.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/dlclark/regexp2 v1.7.0 // indirect
github.com/dustin/go-humanize v1.0.0 // indirect
github.com/envoyproxy/protoc-gen-validate v1.0.2 // indirect
@ -75,6 +79,8 @@ require (
github.com/golang/protobuf v1.5.3 // indirect
github.com/google/gofuzz v1.2.0 // indirect
github.com/gorilla/css v1.0.0 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/hexops/gotextdiff v1.0.3 // indirect
github.com/hexops/valast v1.4.3 // indirect
github.com/huandu/xstrings v1.3.2 // indirect

View File

@ -22,9 +22,15 @@ github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuP
github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=
github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A=
github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=
github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0=
github.com/bufbuild/buf v1.4.0 h1:GqE3a8CMmcFvWPzuY3Mahf9Kf3S9XgZ/ORpfYFzO+90=
github.com/bufbuild/buf v1.4.0/go.mod h1:mwHG7klTHnX+rM/ym8LXGl7vYpVmnwT96xWoRB4H5QI=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/charmbracelet/glamour v0.5.0 h1:wu15ykPdB7X6chxugG/NNfDUbyyrCLV9XBalj5wdu3g=
github.com/charmbracelet/glamour v0.5.0/go.mod h1:9ZRtG19AUIzcTm7FGLGbq3D5WKQ5UyZBbQsMQN0XIqc=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
@ -59,6 +65,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/derision-test/go-mockgen/v2 v2.0.1 h1:2rzcJH6DT2jVfOt2spkmRJ8J6vQr9RQy3pXlQZ2pxNs=
github.com/derision-test/go-mockgen/v2 v2.0.1/go.mod h1:1FvbovTCW7wmMxpBu2LtbhRgbX36MC5LLa6dw1GIhGc=
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/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
github.com/dlclark/regexp2 v1.7.0 h1:7lJfhqlPssTb1WQx4yvTHN0uElPEv52sbaECrAQxjAo=
github.com/dlclark/regexp2 v1.7.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
@ -84,6 +92,14 @@ github.com/go-enry/go-oniguruma v1.2.1 h1:k8aAMuJfMrqm/56SG2lV9Cfti6tC4x8673aHCc
github.com/go-enry/go-oniguruma v1.2.1/go.mod h1:bWDhYP+S6xZQgiRL7wlTScFYBe023B6ilRZbCAD5Hf4=
github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
github.com/go-redis/redis v6.15.9+incompatible h1:K0pv1D7EQUjfyoMql+r/jZqCLizCGKFlFgcHWWmHQjg=
github.com/go-redis/redis v6.15.9+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
github.com/go-redis/redis/v7 v7.4.1 h1:PASvf36gyUpr2zdOUS/9Zqc80GbM+9BDyiJSJDDOrTI=
github.com/go-redis/redis/v7 v7.4.1/go.mod h1:JDNMw23GTyLNC4GZu9njt15ctBQVn7xjRfnwdHj/Dcg=
github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI=
github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo=
github.com/go-redsync/redsync/v4 v4.13.0 h1:49X6GJfnbLGaIpBBREM/zA4uIMDXKAh1NDkvQ1EkZKA=
github.com/go-redsync/redsync/v4 v4.13.0/go.mod h1:HMW4Q224GZQz6x1Xc7040Yfgacukdzu7ifTDAKiyErQ=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
@ -112,6 +128,8 @@ github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/gomodule/redigo v1.8.9 h1:Sl3u+2BI/kk+VEatbj0scLdrFhjPmbxOc1myhDP41ws=
github.com/gomodule/redigo v1.8.9/go.mod h1:7ArFNvsTjH8GMMzB4uy1snslv2BwmginuMs06a1uzZE=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
@ -136,6 +154,11 @@ github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY=
github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c=
github.com/grafana/regexp v0.0.0-20221123153739-15dc172cd2db h1:7aN5cccjIqCLTzedH7MZzRZt5/lsAHch6Z3L2ZGn5FA=
github.com/grafana/regexp v0.0.0-20221123153739-15dc172cd2db/go.mod h1:M5qHK+eWfAv8VR/265dIuEpL3fNfeC21tXXp9itM24A=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
github.com/hexops/autogold v0.8.1/go.mod h1:97HLDXyG23akzAoRYJh/2OBs3kd80eHyKPvZw0S5ZBY=
github.com/hexops/autogold v1.3.1 h1:YgxF9OHWbEIUjhDbpnLhgVsjUDsiHDTyDfy2lrfdlzo=
github.com/hexops/autogold v1.3.1/go.mod h1:sQO+mQUCVfxOKPht+ipDSkJ2SCJ7BNJVHZexsXqWMx4=
@ -288,6 +311,10 @@ github.com/pseudomuto/protoc-gen-doc v1.5.1 h1:Ah259kcrio7Ix1Rhb6u8FCaOkzf9qRBqX
github.com/pseudomuto/protoc-gen-doc v1.5.1/go.mod h1:XpMKYg6zkcpgfpCfQ8GcWBDRtRxOmMR5w7pz4Xo+dYM=
github.com/pseudomuto/protokit v0.2.0 h1:hlnBDcy3YEDXH7kc9gV+NLaN0cDzhDvD1s7Y6FZ8RpM=
github.com/pseudomuto/protokit v0.2.0/go.mod h1:2PdH30hxVHsup8KpBTOXTBeMVhJZVio3Q8ViKSAXT0Q=
github.com/redis/go-redis/v9 v9.5.3 h1:fOAp1/uJG+ZtcITgZOfYFmTKPE7n4Vclj1wZFgRciUU=
github.com/redis/go-redis/v9 v9.5.3/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M=
github.com/redis/rueidis v1.0.19 h1:s65oWtotzlIFN8eMPhyYwxlwLR1lUdhza2KtWprKYSo=
github.com/redis/rueidis v1.0.19/go.mod h1:8B+r5wdnjwK3lTFml5VtxjzGOQAC+5UmujoD12pDrEo=
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.4.2 h1:YwD0ulJSJytLpiaWua0sBDusfsCZohxjxzVTYjwxfV8=
@ -339,6 +366,8 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stvp/tempredis v0.0.0-20181119212430-b82af8480203 h1:QVqDTf3h2WHt08YuiTGPZLls0Wq99X9bWd0Q5ZSBesM=
github.com/stvp/tempredis v0.0.0-20181119212430-b82af8480203/go.mod h1:oqN97ltKNihBbwlX8dLpwxCl3+HnXKV/R0e+sRLd9C8=
github.com/urfave/cli/v2 v2.23.7 h1:YHDQ46s3VghFHFf1DdF+Sh7H4RqhcM+t0TmZRJx4oJY=
github.com/urfave/cli/v2 v2.23.7/go.mod h1:GHupkWPMM0M/sj1a2b4wUrWBPzazNrIjouW6fmdJLxc=
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=

View File

@ -1,13 +1,11 @@
module github.com/sourcegraph/sourcegraph/lib/managedservicesplatform
go 1.22
toolchain go1.22.0
go 1.22.4
replace github.com/sourcegraph/sourcegraph/lib => ../
require (
cloud.google.com/go/bigquery v1.57.1
cloud.google.com/go/bigquery v1.59.1
cloud.google.com/go/cloudsqlconn v1.5.1
cloud.google.com/go/profiler v0.4.0
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.45.0
@ -17,59 +15,77 @@ require (
github.com/go-logr/stdr v1.2.2
github.com/google/uuid v1.6.0
github.com/hexops/autogold/v2 v2.2.1
github.com/jackc/pgx/v5 v5.5.4
github.com/prometheus/client_golang v1.18.0
github.com/jackc/pgx/v5 v5.5.5
github.com/openfga/api/proto v0.0.0-20240529184453-5b0b4941f3e0
github.com/openfga/language/pkg/go v0.0.0-20240409225820-a53ea2892d6d
github.com/openfga/openfga v1.5.4
github.com/pressly/goose/v3 v3.20.0
github.com/prometheus/client_golang v1.19.0
github.com/redis/go-redis/v9 v9.5.3
github.com/sourcegraph/conc v0.3.1-0.20240108182409-4afefce20f9b
github.com/sourcegraph/log v0.0.0-20231018134238-fbadff7458bb
github.com/sourcegraph/sourcegraph/lib v0.0.0-20231122233253-1f857814717c
github.com/stretchr/testify v1.8.4
github.com/stretchr/testify v1.9.0
go.opentelemetry.io/contrib/detectors/gcp v1.24.0
go.opentelemetry.io/contrib/propagators/jaeger v1.24.0
go.opentelemetry.io/contrib/propagators/ot v1.24.0
go.opentelemetry.io/otel v1.24.0
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.24.0
go.opentelemetry.io/otel v1.26.0
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.25.0
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.25.0
go.opentelemetry.io/otel/exporters/prometheus v0.46.0
go.opentelemetry.io/otel/metric v1.24.0
go.opentelemetry.io/otel/sdk v1.24.0
go.opentelemetry.io/otel/metric v1.26.0
go.opentelemetry.io/otel/sdk v1.25.0
go.opentelemetry.io/otel/sdk/metric v1.24.0
go.opentelemetry.io/otel/trace v1.24.0
google.golang.org/api v0.156.0
go.opentelemetry.io/otel/trace v1.26.0
go.uber.org/zap v1.27.0
google.golang.org/api v0.169.0
gorm.io/driver/postgres v1.5.9
gorm.io/gorm v1.25.10
)
require (
cloud.google.com/go v0.111.0 // indirect
cloud.google.com/go/compute v1.23.3 // indirect
cloud.google.com/go/compute/metadata v0.2.4-0.20230617002413-005d2dfb6b68 // indirect
cloud.google.com/go/iam v1.1.5 // indirect
cloud.google.com/go/monitoring v1.17.0 // indirect
cloud.google.com/go/trace v1.10.4 // indirect
cloud.google.com/go v0.112.1 // indirect
cloud.google.com/go/compute/metadata v0.3.0 // indirect
cloud.google.com/go/iam v1.1.6 // indirect
cloud.google.com/go/monitoring v1.18.0 // indirect
cloud.google.com/go/trace v1.10.5 // indirect
filippo.io/edwards25519 v1.1.0 // indirect
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.21.0 // indirect
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.45.0 // indirect
github.com/andybalholm/brotli v1.0.5 // indirect
github.com/apache/arrow/go/v12 v12.0.0 // indirect
github.com/apache/thrift v0.16.0 // indirect
github.com/Masterminds/squirrel v1.5.4 // indirect
github.com/antlr4-go/antlr/v4 v4.13.0 // indirect
github.com/apache/arrow/go/v14 v14.0.2 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/cenkalti/backoff/v4 v4.2.1 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/cockroachdb/errors v1.11.1 // indirect
github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect
github.com/cockroachdb/redact v1.1.5 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/envoyproxy/protoc-gen-validate v1.0.4 // indirect
github.com/fatih/color v1.15.0 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/goccy/go-json v0.9.11 // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/go-redsync/redsync/v4 v4.13.0 // indirect
github.com/go-sql-driver/mysql v1.8.1 // indirect
github.com/goccy/go-json v0.10.2 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/google/flatbuffers v2.0.8+incompatible // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/google/cel-go v0.20.1 // indirect
github.com/google/flatbuffers v23.5.26+incompatible // indirect
github.com/google/go-cmp v0.6.0 // indirect
github.com/google/pprof v0.0.0-20230602150820-91b7bce49751 // indirect
github.com/google/s2a-go v0.1.7 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect
github.com/googleapis/gax-go/v2 v2.12.0 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0 // indirect
github.com/googleapis/gax-go/v2 v2.12.2 // indirect
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/hexops/gotextdiff v1.0.3 // indirect
github.com/hexops/valast v1.4.4 // indirect
github.com/jackc/chunkreader/v2 v2.0.1 // indirect
@ -77,50 +93,70 @@ require (
github.com/jackc/pgio v1.0.0 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgproto3/v2 v2.3.3 // indirect
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9 // indirect
github.com/jackc/puddle/v2 v2.2.1 // indirect
github.com/klauspost/asmfmt v1.3.2 // indirect
github.com/klauspost/compress v1.16.0 // indirect
github.com/klauspost/cpuid/v2 v2.0.9 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/karlseguin/ccache/v3 v3.0.5 // indirect
github.com/klauspost/compress v1.17.2 // indirect
github.com/klauspost/cpuid/v2 v2.2.5 // indirect
github.com/kr/pretty v0.3.1 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect
github.com/magiconair/properties v1.8.7 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.19 // indirect
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect
github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8 // indirect
github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mfridman/interpolate v0.0.2 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/natefinch/wrap v0.2.0 // indirect
github.com/nightlyone/lockfile v1.0.0 // indirect
github.com/pierrec/lz4/v4 v4.1.15 // indirect
github.com/oklog/ulid/v2 v2.1.0 // indirect
github.com/pelletier/go-toml/v2 v2.1.1 // indirect
github.com/pierrec/lz4/v4 v4.1.18 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/prometheus/client_model v0.6.0 // indirect
github.com/prometheus/common v0.45.0 // indirect
github.com/prometheus/common v0.48.0 // indirect
github.com/prometheus/procfs v0.12.0 // indirect
github.com/rogpeppe/go-internal v1.11.0 // indirect
github.com/sagikazarmark/locafero v0.4.0 // indirect
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
github.com/sethvargo/go-retry v0.2.4 // indirect
github.com/spf13/afero v1.11.0 // indirect
github.com/spf13/cast v1.6.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/spf13/viper v1.18.2 // indirect
github.com/stoewer/go-strcase v1.3.0 // indirect
github.com/subosito/gotenv v1.6.0 // indirect
github.com/zeebo/xxh3 v1.0.2 // indirect
go.opencensus.io v0.24.0 // indirect
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1 // indirect
go.opentelemetry.io/proto/otlp v1.1.0 // indirect
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.50.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.51.0 // indirect
go.opentelemetry.io/proto/otlp v1.2.0 // indirect
go.uber.org/atomic v1.11.0 // indirect
go.uber.org/mock v0.4.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.24.0 // indirect
golang.org/x/crypto v0.24.0 // indirect
golang.org/x/exp v0.0.0-20240409090435-93d18d7e34b8 // indirect
golang.org/x/mod v0.17.0 // indirect
golang.org/x/net v0.26.0 // indirect
golang.org/x/oauth2 v0.16.0 // indirect
golang.org/x/oauth2 v0.20.0 // indirect
golang.org/x/sync v0.7.0 // indirect
golang.org/x/sys v0.21.0 // indirect
golang.org/x/text v0.16.0 // indirect
golang.org/x/time v0.5.0 // indirect
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
google.golang.org/appengine v1.6.8 // indirect
google.golang.org/genproto v0.0.0-20240108191215-35c7eff3a6b1 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20240108191215-35c7eff3a6b1 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240108191215-35c7eff3a6b1 // indirect
google.golang.org/grpc v1.61.1 // indirect
google.golang.org/protobuf v1.33.0 // indirect
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect
google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157 // indirect
google.golang.org/grpc v1.64.0 // indirect
google.golang.org/protobuf v1.34.1 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
mvdan.cc/gofumpt v0.5.0 // indirect
)
// Pending: https://github.com/shurcooL/httpgzip/pull/9
replace github.com/openfga/openfga => github.com/sourcegraph/openfga v0.0.0-20240614204729-de6b563022de

View File

@ -1,30 +1,34 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.111.0 h1:YHLKNupSD1KqjDbQ3+LVdQ81h/UJbJyZG203cEfnQgM=
cloud.google.com/go v0.111.0/go.mod h1:0mibmpKP1TyOOFYQY5izo0LnT+ecvOQ0Sg3OdmMiNRU=
cloud.google.com/go/bigquery v1.57.1 h1:FiULdbbzUxWD0Y4ZGPSVCDLvqRSyCIO6zKV7E2nf5uA=
cloud.google.com/go/bigquery v1.57.1/go.mod h1:iYzC0tGVWt1jqSzBHqCr3lrRn0u13E8e+AqowBsDgug=
cloud.google.com/go v0.112.1 h1:uJSeirPke5UNZHIb4SxfZklVSiWWVqW4oXlETwZziwM=
cloud.google.com/go v0.112.1/go.mod h1:+Vbu+Y1UU+I1rjmzeMOb/8RfkKJK2Gyxi1X6jJCZLo4=
cloud.google.com/go/bigquery v1.59.1 h1:CpT+/njKuKT3CEmswm6IbhNu9u35zt5dO4yPDLW+nG4=
cloud.google.com/go/bigquery v1.59.1/go.mod h1:VP1UJYgevyTwsV7desjzNzDND5p6hZB+Z8gZJN1GQUc=
cloud.google.com/go/cloudsqlconn v1.5.1 h1:rMtPv66pkuk2K1ciCicjZY8Ma1DSyOYSoqwPUw/Timo=
cloud.google.com/go/cloudsqlconn v1.5.1/go.mod h1:DPWjhwD5Fhv43M0RP/+7J37xo4PByfNWCzMlKa9OBwE=
cloud.google.com/go/compute v1.23.3 h1:6sVlXXBmbd7jNX0Ipq0trII3e4n1/MsADLK6a+aiVlk=
cloud.google.com/go/compute v1.23.3/go.mod h1:VCgBUoMnIVIR0CscqQiPJLAG25E3ZRZMzcFZeQ+h8CI=
cloud.google.com/go/compute/metadata v0.2.4-0.20230617002413-005d2dfb6b68 h1:aRVqY1p2IJaBGStWMsQMpkAa83cPkCDLl80eOj0Rbz4=
cloud.google.com/go/compute/metadata v0.2.4-0.20230617002413-005d2dfb6b68/go.mod h1:1a3eRNYX12fs5UABBIXS8HXVvQbX9hRB/RkEBPORpe8=
cloud.google.com/go/datacatalog v1.19.0 h1:rbYNmHwvAOOwnW2FPXYkaK3Mf1MmGqRzK0mMiIEyLdo=
cloud.google.com/go/datacatalog v1.19.0/go.mod h1:5FR6ZIF8RZrtml0VUao22FxhdjkoG+a0866rEnObryM=
cloud.google.com/go/iam v1.1.5 h1:1jTsCu4bcsNsE4iiqNT5SHwrDRCfRmIaaaVFhRveTJI=
cloud.google.com/go/iam v1.1.5/go.mod h1:rB6P/Ic3mykPbFio+vo7403drjlgvoWfYpJhMXEbzv8=
cloud.google.com/go/compute/metadata v0.3.0 h1:Tz+eQXMEqDIKRsmY3cHTL6FVaynIjX2QxYC4trgAKZc=
cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k=
cloud.google.com/go/datacatalog v1.19.3 h1:A0vKYCQdxQuV4Pi0LL9p39Vwvg4jH5yYveMv50gU5Tw=
cloud.google.com/go/datacatalog v1.19.3/go.mod h1:ra8V3UAsciBpJKQ+z9Whkxzxv7jmQg1hfODr3N3YPJ4=
cloud.google.com/go/iam v1.1.6 h1:bEa06k05IO4f4uJonbB5iAgKTPpABy1ayxaIZV/GHVc=
cloud.google.com/go/iam v1.1.6/go.mod h1:O0zxdPeGBoFdWW3HWmBxJsk0pfvNM/p/qa82rWOGTwI=
cloud.google.com/go/logging v1.9.0 h1:iEIOXFO9EmSiTjDmfpbRjOxECO7R8C7b8IXUGOj7xZw=
cloud.google.com/go/logging v1.9.0/go.mod h1:1Io0vnZv4onoUnsVUQY3HZ3Igb1nBchky0A0y7BBBhE=
cloud.google.com/go/longrunning v0.5.4 h1:w8xEcbZodnA2BbW6sVirkkoC+1gP8wS57EUUgGS0GVg=
cloud.google.com/go/longrunning v0.5.4/go.mod h1:zqNVncI0BOP8ST6XQD1+VcvuShMmq7+xFSzOL++V0dI=
cloud.google.com/go/monitoring v1.17.0 h1:blrdvF0MkPPivSO041ihul7rFMhXdVp8Uq7F59DKXTU=
cloud.google.com/go/monitoring v1.17.0/go.mod h1:KwSsX5+8PnXv5NJnICZzW2R8pWTis8ypC4zmdRD63Tw=
cloud.google.com/go/longrunning v0.5.5 h1:GOE6pZFdSrTb4KAiKnXsJBtlE6mEyaW44oKyMILWnOg=
cloud.google.com/go/longrunning v0.5.5/go.mod h1:WV2LAxD8/rg5Z1cNW6FJ/ZpX4E4VnDnoTk0yawPBB7s=
cloud.google.com/go/monitoring v1.18.0 h1:NfkDLQDG2UR3WYZVQE8kwSbUIEyIqJUPl+aOQdFH1T4=
cloud.google.com/go/monitoring v1.18.0/go.mod h1:c92vVBCeq/OB4Ioyo+NbN2U7tlg5ZH41PZcdvfc+Lcg=
cloud.google.com/go/profiler v0.4.0 h1:ZeRDZbsOBDyRG0OiK0Op1/XWZ3xeLwJc9zjkzczUxyY=
cloud.google.com/go/profiler v0.4.0/go.mod h1:RvPlm4dilIr3oJtAOeFQU9Lrt5RoySHSDj4pTd6TWeU=
cloud.google.com/go/storage v1.30.1 h1:uOdMxAs8HExqBlnLtnQyP0YkvbiDpdGShGKtx6U/oNM=
cloud.google.com/go/storage v1.30.1/go.mod h1:NfxhC0UJE1aXSx7CIIbCf7y9HKT7BiccwkR7+P7gN8E=
cloud.google.com/go/trace v1.10.4 h1:2qOAuAzNezwW3QN+t41BtkDJOG42HywL73q8x/f6fnM=
cloud.google.com/go/trace v1.10.4/go.mod h1:Nso99EDIK8Mj5/zmB+iGr9dosS/bzWCJ8wGmE6TXNWY=
cloud.google.com/go/storage v1.38.0 h1:Az68ZRGlnNTpIBbLjSMIV2BDcwwXYlRlQzis0llkpJg=
cloud.google.com/go/storage v1.38.0/go.mod h1:tlUADB0mAb9BgYls9lq+8MGkfzOXuLrnHXlpHmvFJoY=
cloud.google.com/go/trace v1.10.5 h1:0pr4lIKJ5XZFYD9GtxXEWr0KkVeigc3wlGpZco0X1oA=
cloud.google.com/go/trace v1.10.5/go.mod h1:9hjCV1nGBCtXbAE4YK7OqJ8pmPYSxPA0I67JwRd5s3M=
dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0=
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.21.0 h1:aNyyrkRcLMWFum5qgYbXl6Ut+MMOmfH/kLjZJ5YJP/I=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.21.0/go.mod h1:BEOBnuYVyPt9wxVRQqqpKUK9FXVcL2+LOjZ8apLa9ao=
@ -36,27 +40,30 @@ github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.45.0/go.mod h1:WntFIMzxcU+PMBuekFc34UOsEZ9sP+vsnBYTyaNBkOs=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.45.0 h1:o/Nf55GfyLwGDaHkVAkRGgBXeExce73L6N9w2PZTB3k=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.45.0/go.mod h1:qkFPtMouQjW5ugdHIOthiTbweVHUTqbS0Qsu55KqXks=
github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c h1:RGWPOewvKIROun94nF7v2cua9qP+thov/7M50KEoeSU=
github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c/go.mod h1:X0CRv0ky0k6m906ixxpzmDRLvX58TFUKS2eePweuyxk=
github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs=
github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
github.com/apache/arrow/go/v12 v12.0.0 h1:xtZE63VWl7qLdB0JObIXvvhGjoVNrQ9ciIHG2OK5cmc=
github.com/apache/arrow/go/v12 v12.0.0/go.mod h1:d+tV/eHZZ7Dz7RPrFKtPK02tpr+c9/PEd/zm8mDS9Vg=
github.com/apache/thrift v0.16.0 h1:qEy6UW60iVOlUy+b9ZR0d5WzUWYGOo4HfopoyBaNmoY=
github.com/apache/thrift v0.16.0/go.mod h1:PHK3hniurgQaNMZYaCLEqXKsYK8upmhPbmdP2FXSqgU=
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
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.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
github.com/Microsoft/hcsshim v0.11.4 h1:68vKo2VN8DE9AdN4tnkWnmdhqdbpUFM8OF3Airm7fz8=
github.com/Microsoft/hcsshim v0.11.4/go.mod h1:smjE4dvqPX9Zldna+t5FG3rnoHhaB7QYxPRqGcpAD9w=
github.com/antlr4-go/antlr/v4 v4.13.0 h1:lxCg3LAv+EUK6t1i0y1V6/SLeUi0eKEKdhQAlS8TVTI=
github.com/antlr4-go/antlr/v4 v4.13.0/go.mod h1:pfChB/xh/Unjila75QW7+VU4TSnWnnk9UTnmpPaOR2g=
github.com/apache/arrow/go/v14 v14.0.2 h1:N8OkaJEOfI3mEZt07BIkvo4sC6XDbL+48MBPWO5IONw=
github.com/apache/arrow/go/v14 v14.0.2/go.mod h1:u3fgh3EdgN/YQ8cVQRguVW3R+seMybFg8QBQ5LU+eBY=
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM=
github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=
github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0=
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cncf/xds/go v0.0.0-20231109132714-523115ebc101 h1:7To3pQ+pZo0i3dsWEbinPNFs5gPSBOsJtx3wTT94VBY=
github.com/cncf/xds/go v0.0.0-20231109132714-523115ebc101/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
github.com/cockroachdb/errors v1.11.1 h1:xSEW75zKaKCWzR3OfxXUxgrk/NtT4G1MiOv5lWZazG8=
github.com/cockroachdb/errors v1.11.1/go.mod h1:8MUxA3Gi6b25tYlFEBGLf+D8aISL+M4MIpiWMSNRfxw=
@ -64,44 +71,80 @@ github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b h1:r6VH0faHjZe
github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs=
github.com/cockroachdb/redact v1.1.5 h1:u1PMllDkdFfPWaNGMyLD1+so+aq3uUItthCFqzwPJ30=
github.com/cockroachdb/redact v1.1.5/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg=
github.com/containerd/containerd v1.7.12 h1:+KQsnv4VnzyxWcfO9mlxxELaoztsDEjOuCMPAuPqgU0=
github.com/containerd/containerd v1.7.12/go.mod h1:/5OMpE1p0ylxtEUGY8kuCYkDRzJm9NO1TFMWjUpdevk=
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/cpuguy83/dockercfg v0.3.1 h1:/FpZ+JaygUR/lZP2NlFI2DVfrOEMAIKP5wWEJdoYe9E=
github.com/cpuguy83/dockercfg v0.3.1/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc=
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/derision-test/go-mockgen/v2 v2.0.1 h1:2rzcJH6DT2jVfOt2spkmRJ8J6vQr9RQy3pXlQZ2pxNs=
github.com/derision-test/go-mockgen/v2 v2.0.1/go.mod h1:1FvbovTCW7wmMxpBu2LtbhRgbX36MC5LLa6dw1GIhGc=
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/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK2OFGvA0=
github.com/distribution/reference v0.5.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
github.com/docker/docker v26.0.2+incompatible h1:yGVmKUFGgcxA6PXWAokO0sQL22BrQ67cgVjko8tGdXE=
github.com/docker/docker v26.0.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc=
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/envoyproxy/protoc-gen-validate v1.0.2 h1:QkIBuU5k+x7/QXPvPPnWXWlCdaBFApVqftFV6k087DA=
github.com/envoyproxy/protoc-gen-validate v1.0.2/go.mod h1:GpiZQP3dDbg4JouG/NNS7QWXpgx6x8QiMKdmN72jogE=
github.com/envoyproxy/protoc-gen-validate v1.0.4 h1:gVPz/FMfvh57HdSJQyvBtF00j8JU4zdyUgIUNhlgg0A=
github.com/envoyproxy/protoc-gen-validate v1.0.4/go.mod h1:qys6tmnRsYrQqIhm2bvKZH4Blx/1gTIZ2UKVY1M+Yew=
github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs=
github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw=
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps=
github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY=
github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
github.com/getsentry/sentry-go v0.25.0 h1:q6Eo+hS+yoJlTO3uu/azhQadsD8V+jQn2D8VvX1eOyI=
github.com/getsentry/sentry-go v0.25.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY=
github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI=
github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/go-redis/redis v6.15.9+incompatible h1:K0pv1D7EQUjfyoMql+r/jZqCLizCGKFlFgcHWWmHQjg=
github.com/go-redis/redis v6.15.9+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
github.com/go-redis/redis/v7 v7.4.1 h1:PASvf36gyUpr2zdOUS/9Zqc80GbM+9BDyiJSJDDOrTI=
github.com/go-redis/redis/v7 v7.4.1/go.mod h1:JDNMw23GTyLNC4GZu9njt15ctBQVn7xjRfnwdHj/Dcg=
github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI=
github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo=
github.com/go-redsync/redsync/v4 v4.13.0 h1:49X6GJfnbLGaIpBBREM/zA4uIMDXKAh1NDkvQ1EkZKA=
github.com/go-redsync/redsync/v4 v4.13.0/go.mod h1:HMW4Q224GZQz6x1Xc7040Yfgacukdzu7ifTDAKiyErQ=
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/goccy/go-json v0.9.11 h1:/pAaQDLHEoCq/5FFmSKBswWmK6H0e8g4159Kc/X/nqk=
github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg=
github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0ktxqI+Sida1w446QrXBRJ0nee3SNZlA=
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A=
@ -111,11 +154,11 @@ github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4er
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8=
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
@ -123,14 +166,14 @@ github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:W
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/flatbuffers v2.0.8+incompatible h1:ivUb1cGomAB101ZM1T0nOiWz9pSrTMoa9+EiY7igmkM=
github.com/google/flatbuffers v2.0.8+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/gomodule/redigo v1.8.9 h1:Sl3u+2BI/kk+VEatbj0scLdrFhjPmbxOc1myhDP41ws=
github.com/gomodule/redigo v1.8.9/go.mod h1:7ArFNvsTjH8GMMzB4uy1snslv2BwmginuMs06a1uzZE=
github.com/google/cel-go v0.20.1 h1:nDx9r8S3L4pE61eDdt8igGj8rf5kjYR3ILxWIpWNi84=
github.com/google/cel-go v0.20.1/go.mod h1:kWcIzTsPX0zmQ+H3TirHstLLf9ep5QTsZBN9u4dOYLg=
github.com/google/flatbuffers v23.5.26+incompatible h1:M9dgRyhJemaM4Sw8+66GHBu8ioaQmyPLg1b8VwK5WJg=
github.com/google/flatbuffers v23.5.26+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
@ -138,7 +181,6 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
@ -155,10 +197,28 @@ 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=
github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs=
github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0=
github.com/googleapis/gax-go/v2 v2.12.0 h1:A+gCJKdRfqXkr+BIRGtZLibNXf0m1f9E4HG56etFpas=
github.com/googleapis/gax-go/v2 v2.12.0/go.mod h1:y+aIqrI5eb1YGMVJfuV3185Ts/D7qKpsEkdD5+I6QGU=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0 h1:Wqo399gCIufwto+VfwCSvsnfGpF/w5E9CNxSwbpD6No=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0/go.mod h1:qmOFXW2epJhM0qSnUUYpldc7gVz2KMQwJ/QYCDIa7XU=
github.com/googleapis/gax-go/v2 v2.12.2 h1:mhN09QQW1jEWeMF74zGR81R30z4VJzjZsfkUhuHF+DA=
github.com/googleapis/gax-go/v2 v2.12.2/go.mod h1:61M8vcyyXR2kqKFxKrfA22jaA8JGF7Dc8App1U3H6jc=
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/v2 v2.1.0 h1:pRhl55Yx1eC7BZ1N+BBWwnKaMyD8uC+34TLdndZMAKk=
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0/go.mod h1:XKMd7iuf/RGPSMJ/U4HP0zS2Z9Fh8Ps9a+6X26m/tmI=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 h1:bkypFPDjIYGfCYD5mRBvpqxfYX1YCS1PXdKYWi8FsN0=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0/go.mod h1:P+Lt/0by1T8bfcF3z737NnSbmxQAppXMRziHUxPOC8k=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
github.com/hashicorp/go-retryablehttp v0.7.5 h1:bJj+Pj19UZMIweq/iie+1u5YCdGrnxCT9yvm0e+Nd5M=
github.com/hashicorp/go-retryablehttp v0.7.5/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8=
github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc=
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/hexops/autogold v0.8.1/go.mod h1:97HLDXyG23akzAoRYJh/2OBs3kd80eHyKPvZw0S5ZBY=
github.com/hexops/autogold v1.3.1 h1:YgxF9OHWbEIUjhDbpnLhgVsjUDsiHDTyDfy2lrfdlzo=
github.com/hexops/autogold v1.3.1/go.mod h1:sQO+mQUCVfxOKPht+ipDSkJ2SCJ7BNJVHZexsXqWMx4=
@ -168,6 +228,8 @@ github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUq
github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg=
github.com/hexops/valast v1.4.4 h1:rETyycw+/L2ZVJHHNxEBgh8KUn+87WugH9MxcEv9PGs=
github.com/hexops/valast v1.4.4/go.mod h1:Jcy1pNH7LNraVaAZDLyv21hHg2WBv9Nf9FL6fGxU7o4=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo=
github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8=
@ -198,8 +260,9 @@ github.com/jackc/pgproto3/v2 v2.3.2/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwX
github.com/jackc/pgproto3/v2 v2.3.3 h1:1HLSx5H+tXR9pW3in3zaztoEwQYRC9SQaYUHjTSUOag=
github.com/jackc/pgproto3/v2 v2.3.3/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E=
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk=
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9 h1:L0QtFUgDarD7Fpv9jeVMgy/+Ec0mtnmYuImjTz6dtDA=
github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg=
github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc=
github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw=
@ -210,20 +273,24 @@ github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9
github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc=
github.com/jackc/pgx/v4 v4.18.1 h1:YP7G1KABtKpB5IHrO9vYwSrCOhs7p3uqhvhhQBptya0=
github.com/jackc/pgx/v4 v4.18.1/go.mod h1:FydWkUyadDmdNH/mHnGob881GawxeEm7TcMCzkb+qQE=
github.com/jackc/pgx/v5 v5.5.4 h1:Xp2aQS8uXButQdnCMWNmvx6UysWQQC+u1EoizjguY+8=
github.com/jackc/pgx/v5 v5.5.4/go.mod h1:ez9gk+OAat140fv9ErkZDYFWmXLfV+++K0uAOiwgm1A=
github.com/jackc/pgx/v5 v5.5.5 h1:amBjrZVmksIdNjxGW/IiIMzxMKZFelXbUoPNb+8sjQw=
github.com/jackc/pgx/v5 v5.5.5/go.mod h1:ez9gk+OAat140fv9ErkZDYFWmXLfV+++K0uAOiwgm1A=
github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk=
github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/karlseguin/ccache/v3 v3.0.5 h1:hFX25+fxzNjsRlREYsoGNa2LoVEw5mPF8wkWq/UnevQ=
github.com/karlseguin/ccache/v3 v3.0.5/go.mod h1:qxC372+Qn+IBj8Pe3KvGjHPj0sWwEF7AeZVhsNPZ6uY=
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/asmfmt v1.3.2 h1:4Ri7ox3EwapiOjCki+hw14RyKk201CN4rzyCJRFLpK4=
github.com/klauspost/asmfmt v1.3.2/go.mod h1:AG8TuvYojzulgDAMCnYn50l/5QV3Bs/tp6j0HLHbNSE=
github.com/klauspost/compress v1.16.0 h1:iULayQNOReoYUe+1qtKOqw9CwJv3aNQu8ivo7lw1HU4=
github.com/klauspost/compress v1.16.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
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/compress v1.17.2 h1:RlWWUY/Dr4fL8qk9YG7DTZ7PDgME2V4csBXA8L/ixi4=
github.com/klauspost/compress v1.17.2/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg=
github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
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/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
@ -235,9 +302,17 @@ github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 h1:SOEGU9fKiNWd/HOJuq6+3iTQz8KNCLtVX6idSoTLdUw=
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0/go.mod h1:dXGbAdH5GtBTC4WfIxhKZfyBF/HBFgRZSWwZ9g/He9o=
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 h1:P6pPBnrTSX3DEVR4fDembhRWSsG5rVo6hYhAB/ADZrk=
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0/go.mod h1:vmVJ0l/dxyfGW6FmdpVm2joNMFikkuWg0EoCKLGUMNw=
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4=
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
@ -245,37 +320,77 @@ github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hd
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg=
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k=
github.com/microsoft/go-mssqldb v1.6.0 h1:mM3gYdVwEPFrlg/Dvr2DNVEgYFG7L42l+dGc67NNNpc=
github.com/microsoft/go-mssqldb v1.6.0/go.mod h1:00mDtPbeQCRGC1HwOOR5K/gr30P1NcEG0vx6Kbv2aJU=
github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8 h1:AMFGa4R4MiIpspGNG7Z948v4n35fFGB3RR3G/ry4FWs=
github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8/go.mod h1:mC1jAcsrzbxHt8iiaC+zU4b1ylILSosueou12R++wfY=
github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3 h1:+n/aFZefKZp7spd8DFdX7uMikMLXX4oubIzJF4kv/wI=
github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3/go.mod h1:RagcQ7I8IeTMnF8JTXieKnO4Z6JCsikNEzj0DwauVzE=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mfridman/interpolate v0.0.2 h1:pnuTK7MQIxxFz1Gr+rjSIx9u7qVjf5VOoM/u6BbAxPY=
github.com/mfridman/interpolate v0.0.2/go.mod h1:p+7uk6oE07mpE/Ik1b8EckO0O4ZXiGAfshKBWLUM9Xg=
github.com/microsoft/go-mssqldb v1.7.0 h1:sgMPW0HA6Ihd37Yx0MzHyKD726C2kY/8KJsQtXHNaAs=
github.com/microsoft/go-mssqldb v1.7.0/go.mod h1:kOvZKUdrhhFQmxLZqbwUV0rHkNkZpthMITIb2Ko1IoA=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk=
github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc=
github.com/moby/sys/sequential v0.5.0 h1:OPvI35Lzn9K04PBbCLW0g4LcFAJgHsvXsRyewg5lXtc=
github.com/moby/sys/sequential v0.5.0/go.mod h1:tH2cOOs5V9MlPiXcQzRC+eEyab644PWKGRYaaV5ZZlo=
github.com/moby/sys/user v0.1.0 h1:WmZ93f5Ux6het5iituh9x2zAG7NFY9Aqi49jjE1PaQg=
github.com/moby/sys/user v0.1.0/go.mod h1:fKJhFOnsCN6xZ5gSfbM6zaHGgDJMrqt9/reuj4T7MmU=
github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0=
github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y=
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
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/nightlyone/lockfile v1.0.0 h1:RHep2cFKK4PonZJDdEl4GmkabuhbsRMgk/k3uAmxBiA=
github.com/nightlyone/lockfile v1.0.0/go.mod h1:rywoIealpdNse2r832aiD9jRk8ErCatROs6LzC841CI=
github.com/pierrec/lz4/v4 v4.1.15 h1:MO0/ucJhngq7299dKLwIMtgTfbkoSPF6AoMYDd8Q4q0=
github.com/pierrec/lz4/v4 v4.1.15/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
github.com/oklog/ulid/v2 v2.1.0 h1:+9lhoxAP56we25tyYETBBY1YLA2SaoLvUFgrP2miPJU=
github.com/oklog/ulid/v2 v2.1.0/go.mod h1:rcEKHmBBKfef9DhnvX7y1HZBYxjXb0cP5ExxNsTT1QQ=
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.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug=
github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM=
github.com/openfga/api/proto v0.0.0-20240529184453-5b0b4941f3e0 h1:tSJl/atdqsDACjRQQPCbXe2GfEvcOkhdrUNmDToAjTA=
github.com/openfga/api/proto v0.0.0-20240529184453-5b0b4941f3e0/go.mod h1:XnvYrdU//9i70Aou6n4H5DJ0bdRPB3IlmE/Vx6qhnm8=
github.com/openfga/language/pkg/go v0.0.0-20240409225820-a53ea2892d6d h1:n44DfITs+CLCYJIgsryJkG2ElwOZJ3huekPZKydPi7U=
github.com/openfga/language/pkg/go v0.0.0-20240409225820-a53ea2892d6d/go.mod h1:wkI4GcY3yNNuFMU2ncHPWqBaF7XylQTkJYfBi2pIpK8=
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/pborman/getopt v0.0.0-20170112200414-7148bc3a4c30/go.mod h1:85jBQOZwpVEaDAr341tbn15RS4fCAsIst0qp7i8ex1o=
github.com/pelletier/go-toml/v2 v2.1.1 h1:LWAJwfNvjQZCFIDKWYQaM62NcYeYViCmWIwmOStowAI=
github.com/pelletier/go-toml/v2 v2.1.1/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
github.com/pierrec/lz4/v4 v4.1.18 h1:xaKrnTkyoqfh1YItXl56+6KJNVYWlEEPuAQW9xsplYQ=
github.com/pierrec/lz4/v4 v4.1.18/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4=
github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v1.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk=
github.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlkOQntgjkJWKrN5txjA=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw=
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
github.com/pressly/goose/v3 v3.20.0 h1:uPJdOxF/Ipj7ABVNOAMJXSxwFXZGwMGHNqjC8e61VA0=
github.com/pressly/goose/v3 v3.20.0/go.mod h1:BRfF2GcG4FTG12QfdBVy3q1yveaf4ckL9vWwEcIO3lA=
github.com/prometheus/client_golang v1.19.0 h1:ygXvpU1AoN1MhdzckN+PyD9QJOSD4x7kmXYlnfbA6JU=
github.com/prometheus/client_golang v1.19.0/go.mod h1:ZRM9uEAypZakd+q/x7+gmsvXdURP+DABIEIjnmDdp+k=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.6.0 h1:k1v3CzpSRUTrKMppY35TLwPvxHqBu0bYgxZzqGIgaos=
github.com/prometheus/client_model v0.6.0/go.mod h1:NTQHnmxFpouOD0DpvP4XujX3CdOAGQPoaGhyTchlyt8=
github.com/prometheus/common v0.45.0 h1:2BGz0eBc2hdMDLnO/8n0jeB3oPrt2D08CekT0lneoxM=
github.com/prometheus/common v0.45.0/go.mod h1:YJmSTw9BoKxJplESWWxlbyttQR4uaEcGyv9MZjVOJsY=
github.com/prometheus/common v0.48.0 h1:QO8U2CdOzSn1BBsmXJXduaaW+dY/5QLjfB8svtSzKKE=
github.com/prometheus/common v0.48.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc=
github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
github.com/redis/go-redis/v9 v9.5.3 h1:fOAp1/uJG+ZtcITgZOfYFmTKPE7n4Vclj1wZFgRciUU=
github.com/redis/go-redis/v9 v9.5.3/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M=
github.com/redis/rueidis v1.0.19 h1:s65oWtotzlIFN8eMPhyYwxlwLR1lUdhza2KtWprKYSo=
github.com/redis/rueidis v1.0.19/go.mod h1:8B+r5wdnjwK3lTFml5VtxjzGOQAC+5UmujoD12pDrEo=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
@ -284,14 +399,40 @@ github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUz
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
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/sethvargo/go-retry v0.2.4 h1:T+jHEQy/zKJf5s95UkguisicE0zuF9y7+/vgz08Ocec=
github.com/sethvargo/go-retry v0.2.4/go.mod h1:1afjQuvh7s4gflMObvjLPaWgluLLyhA1wmVZ6KLpICw=
github.com/shirou/gopsutil/v3 v3.23.12 h1:z90NtUkp3bMtmICZKpC4+WaknU1eXtp5vtbQ11DgpE4=
github.com/shirou/gopsutil/v3 v3.23.12/go.mod h1:1FrWgea594Jp7qmjHUUPlJDTPgcsb9mGnXDxavtikzM=
github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM=
github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ=
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/sourcegraph/conc v0.3.1-0.20240108182409-4afefce20f9b h1:0FsjN+u9fNXTS2C1JnJ6G/gkgcUg8dscyyfu3PwHWUQ=
github.com/sourcegraph/conc v0.3.1-0.20240108182409-4afefce20f9b/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
github.com/sourcegraph/log v0.0.0-20231018134238-fbadff7458bb h1:tHKdC+bXxxGJ0cy/R06kg6Z0zqwVGOWMx8uWsIwsaoY=
github.com/sourcegraph/log v0.0.0-20231018134238-fbadff7458bb/go.mod h1:IDp09QkoqS8Z3CyN2RW6vXjgABkNpDbyjLIHNQwQ8P8=
github.com/sourcegraph/openfga v0.0.0-20240614204729-de6b563022de h1:0p4KNG4nvdNCHZjyoL9ju9PxttiwtPni5g5aJTldXv4=
github.com/sourcegraph/openfga v0.0.0-20240614204729-de6b563022de/go.mod h1:8bRAwVDc00rzddY2V19Vwug+h8FWfS1IlVWvblN7THE=
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.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0=
github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0=
github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho=
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.18.2 h1:LUXCnvUvSM6FXAsj6nnfc8Q2tp1dIgUfY9Kc8GsSOiQ=
github.com/spf13/viper v1.18.2/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMVB+yk=
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.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
@ -305,11 +446,28 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/stvp/tempredis v0.0.0-20181119212430-b82af8480203 h1:QVqDTf3h2WHt08YuiTGPZLls0Wq99X9bWd0Q5ZSBesM=
github.com/stvp/tempredis v0.0.0-20181119212430-b82af8480203/go.mod h1:oqN97ltKNihBbwlX8dLpwxCl3+HnXKV/R0e+sRLd9C8=
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
github.com/testcontainers/testcontainers-go v0.30.0 h1:jmn/XS22q4YRrcMwWg0pAwlClzs/abopbsBzrepyc4E=
github.com/testcontainers/testcontainers-go v0.30.0/go.mod h1:K+kHNGiM5zjklKjgTtcrEetF3uhWbMUyqAQoyoh8Pf0=
github.com/testcontainers/testcontainers-go/modules/mysql v0.30.0 h1:wrePvxfU/2HFALKyBqpNs6VoPPvThzHy9aN+PCxse9g=
github.com/testcontainers/testcontainers-go/modules/mysql v0.30.0/go.mod h1:Srnlf7wwA7s6K4sKKhjAoBHJcKorRINR/i5dCA4ZyGk=
github.com/testcontainers/testcontainers-go/modules/postgres v0.30.0 h1:D3HFqpZS90iRGAN7M85DFiuhPfvYvFNnx8urQ6mPAvo=
github.com/testcontainers/testcontainers-go/modules/postgres v0.30.0/go.mod h1:e1sKxwUOkqzvaqdHl/oV9mUtFmkDPTfBGp0po2tnWQU=
github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU=
github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI=
github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk=
github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw=
github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
github.com/zeebo/assert v1.3.0 h1:g7C04CbJuIDKNPFHmsk4hwZDO5O+kntRxzaUoNXj+IQ=
github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0=
github.com/zeebo/xxh3 v1.0.2 h1:xZmwmqxHZA8AI603jOQ0tMqmBr9lPeFwGg6d+xy9DC0=
@ -319,45 +477,51 @@ go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
go.opentelemetry.io/contrib/detectors/gcp v1.24.0 h1:1Szzq5d735VbnwbEmwPUJ/FIpY9CPM9KYfCRsSNjPgw=
go.opentelemetry.io/contrib/detectors/gcp v1.24.0/go.mod h1:KAZHUFgklT30k9ZaYrDyg6v/T5EfBq6Eqg03H6ywN6Q=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1 h1:SpGay3w+nEwMpfVnbqOLH5gY52/foP8RE8UzTZ1pdSE=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1/go.mod h1:4UoMYEZOC0yN/sPGH76KPkkU7zgiEWYWL9vwmbnTJPE=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1 h1:aFJWCqJMNjENlcleuuOkGAPH82y0yULBScfXcIEdS24=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1/go.mod h1:sEGXWArGqc3tVa+ekntsN65DmVbVeW+7lTKTjZF3/Fo=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.50.0 h1:zvpPXY7RfYAGSdYQLjp6zxdJNSYD/+FFoCTQN9IPxBs=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.50.0/go.mod h1:BMn8NB1vsxTljvuorms2hyOs8IBuuBEq0pl7ltOfy30=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.51.0 h1:Xs2Ncz0gNihqu9iosIZ5SkBbWo5T8JhhLJFMQL1qmLI=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.51.0/go.mod h1:vy+2G/6NvVMpwGX/NyLqcC41fxepnuKHk16E6IZUcJc=
go.opentelemetry.io/contrib/propagators/jaeger v1.24.0 h1:CKtIfwSgDvJmaWsZROcHzONZgmQdMYn9mVYWypOWT5o=
go.opentelemetry.io/contrib/propagators/jaeger v1.24.0/go.mod h1:Q5JA/Cfdy/ta+5VeEhrMJRWGyS6UNRwFbl+yS3W1h5I=
go.opentelemetry.io/contrib/propagators/ot v1.24.0 h1:6lf4HoYefKDOTUSCatwkpzliUYihAvlN0omfpOn5IDs=
go.opentelemetry.io/contrib/propagators/ot v1.24.0/go.mod h1:A406hNQ7A0EWsOFzWI1p53YaYQXe12C9f6wGHUxfh0g=
go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo=
go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0 h1:t6wl9SPayj+c7lEIFgm4ooDBZVb01IhLB4InpomhRw8=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0/go.mod h1:iSDOcsnSA5INXzZtwaBPrKp/lWu/V14Dd+llD0oI2EA=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.24.0 h1:Mw5xcxMwlqoJd97vwPxA8isEaIoxsta9/Q51+TTJLGE=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.24.0/go.mod h1:CQNu9bj7o7mC6U7+CA/schKEYakYXWr79ucDHTMGhCM=
go.opentelemetry.io/otel v1.26.0 h1:LQwgL5s/1W7YiiRwxf03QGnWLb2HW4pLiAhaA5cZXBs=
go.opentelemetry.io/otel v1.26.0/go.mod h1:UmLkJHUAidDval2EICqBMbnAd0/m2vmpf/dAM+fvFs4=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.25.0 h1:dT33yIHtmsqpixFsSQPwNeY5drM9wTcoL8h0FWF4oGM=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.25.0/go.mod h1:h95q0LBGh7hlAC08X2DhSeyIG02YQ0UyioTCVAqRPmc=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.25.0 h1:vOL89uRfOCCNIjkisd0r7SEdJF3ZJFyCNY34fdZs8eU=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.25.0/go.mod h1:8GlBGcDk8KKi7n+2S4BT/CPZQYH3erLu0/k64r1MYgo=
go.opentelemetry.io/otel/exporters/prometheus v0.46.0 h1:I8WIFXR351FoLJYuloU4EgXbtNX2URfU/85pUPheIEQ=
go.opentelemetry.io/otel/exporters/prometheus v0.46.0/go.mod h1:ztwVUHe5DTR/1v7PeuGRnU5Bbd4QKYwApWmuutKsJSs=
go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI=
go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco=
go.opentelemetry.io/otel/sdk v1.24.0 h1:YMPPDNymmQN3ZgczicBY3B6sf9n62Dlj9pWD3ucgoDw=
go.opentelemetry.io/otel/sdk v1.24.0/go.mod h1:KVrIYw6tEubO9E96HQpcmpTKDVn9gdv35HoYiQWGDFg=
go.opentelemetry.io/otel/metric v1.26.0 h1:7S39CLuY5Jgg9CrnA9HHiEjGMF/X2VHvoXGgSllRz30=
go.opentelemetry.io/otel/metric v1.26.0/go.mod h1:SY+rHOI4cEawI9a7N1A4nIg/nTQXe1ccCNWYOJUrpX4=
go.opentelemetry.io/otel/sdk v1.25.0 h1:PDryEJPC8YJZQSyLY5eqLeafHtG+X7FWnf3aXMtxbqo=
go.opentelemetry.io/otel/sdk v1.25.0/go.mod h1:oFgzCM2zdsxKzz6zwpTZYLLQsFwc+K0daArPdIhuxkw=
go.opentelemetry.io/otel/sdk/metric v1.24.0 h1:yyMQrPzF+k88/DbH7o4FMAs80puqd+9osbiBrJrz/w8=
go.opentelemetry.io/otel/sdk/metric v1.24.0/go.mod h1:I6Y5FjH6rvEnTTAYQz3Mmv2kl6Ek5IIrmwTLqMrrOE0=
go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI=
go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU=
go.opentelemetry.io/proto/otlp v1.1.0 h1:2Di21piLrCqJ3U3eXGCTPHE9R8Nh+0uglSnOyxikMeI=
go.opentelemetry.io/proto/otlp v1.1.0/go.mod h1:GpBHCBWiqvVLDqmHZsoMM3C5ySeKTC7ej/RNTae6MdY=
go.opentelemetry.io/otel/trace v1.26.0 h1:1ieeAUb4y0TE26jUFrCIXKpTuVK7uJGN9/Z/2LP5sQA=
go.opentelemetry.io/otel/trace v1.26.0/go.mod h1:4iDxvGDQuUkHve82hJJ8UqrwswHYsZuWCBllGV2U2y0=
go.opentelemetry.io/proto/otlp v1.2.0 h1:pVeZGk7nXDC9O2hncA6nHldxEjm6LByfA2aN8IOkz94=
go.opentelemetry.io/proto/otlp v1.2.0/go.mod h1:gGpR8txAl5M03pDhMC79G6SdqNV26naRm/KDsgaHD8A=
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
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.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
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.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
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.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60=
go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg=
go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI=
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
@ -372,11 +536,12 @@ golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98y
golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI=
golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20220827204233-334a2380cb91 h1:tnebWN09GYg9OLPss1KXj8txwZc6X6uMr6VFdcGNbHw=
golang.org/x/exp v0.0.0-20220827204233-334a2380cb91/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE=
golang.org/x/exp v0.0.0-20240409090435-93d18d7e34b8 h1:ESSUROHIBHg7USnszlcdmjBEwdMj9VUvU+OPk4yl2mc=
golang.org/x/exp v0.0.0-20240409090435-93d18d7e34b8/go.mod h1:/lliqkxwWAhPjf5oSOIJup2XcqJaw8RGS6k3TGEc7GI=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
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=
@ -406,8 +571,8 @@ golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI=
golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ=
golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.16.0 h1:aDkGMBSYxElaoP81NpoUoz2oo2R2wHdZpGToUxfyQrQ=
golang.org/x/oauth2 v0.16.0/go.mod h1:hqZ+0LWXsiVoZpeld6jVt06P3adbS2Uu911W1SsJv2o=
golang.org/x/oauth2 v0.20.0 h1:4mQdhULixXKP1rwYBW0vAijoXnkTG0BLCDRzfe1idMo=
golang.org/x/oauth2 v0.20.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@ -431,6 +596,7 @@ golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@ -457,7 +623,6 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
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=
@ -473,6 +638,7 @@ golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3
golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
@ -489,32 +655,32 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk=
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
gonum.org/v1/gonum v0.11.0 h1:f1IJhK4Km5tBJmaiJXtk/PkL4cdVX6J+tGiM187uT5E=
gonum.org/v1/gonum v0.11.0/go.mod h1:fSG4YDCxxUZQJ7rKsQrj0gMOg00Il0Z96/qMA4bVQhA=
google.golang.org/api v0.156.0 h1:yloYcGbBtVYjLKQe4enCunxvwn3s2w/XPrrhVf6MsvQ=
google.golang.org/api v0.156.0/go.mod h1:bUSmn4KFO0Q+69zo9CNIDp4Psi6BqM0np0CbzKRSiSY=
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU=
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90=
gonum.org/v1/gonum v0.12.0 h1:xKuo6hzt+gMav00meVPUlXwSdoEJP46BR+wdxQEFK2o=
gonum.org/v1/gonum v0.12.0/go.mod h1:73TDxJfAAHeA8Mk9mf8NlIppyhQNo5GLTcYeqgo2lvY=
google.golang.org/api v0.169.0 h1:QwWPy71FgMWqJN/l6jVlFHUa29a7dcUy02I8o799nPY=
google.golang.org/api v0.169.0/go.mod h1:gpNOiMA2tZ4mf5R9Iwf4rK/Dcz0fbdIgWYWVoxmsyLg=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM=
google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto v0.0.0-20240108191215-35c7eff3a6b1 h1:/IWabOtPziuXTEtI1KYCpM6Ss7vaAkeMxk+uXV/xvZs=
google.golang.org/genproto v0.0.0-20240108191215-35c7eff3a6b1/go.mod h1:+Rvu7ElI+aLzyDQhpHMFMMltsD6m7nqpuWDd2CwJw3k=
google.golang.org/genproto/googleapis/api v0.0.0-20240108191215-35c7eff3a6b1 h1:OPXtXn7fNMaXwO3JvOmF1QyTc00jsSFFz1vXXBOdCDo=
google.golang.org/genproto/googleapis/api v0.0.0-20240108191215-35c7eff3a6b1/go.mod h1:B5xPO//w8qmBDjGReYLpR6UJPnkldGkCSMoH/2vxJeg=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240108191215-35c7eff3a6b1 h1:gphdwh0npgs8elJ4T6J+DQJHPVF7RsuJHCfwztUb4J4=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240108191215-35c7eff3a6b1/go.mod h1:daQN87bsDqDoe316QbbvX60nMoJQa4r6Ds0ZuoAe5yA=
google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 h1:9+tzLLstTlPTRyJTh+ah5wIMsBW5c4tQwGTN3thOW9Y=
google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9/go.mod h1:mqHbVIp48Muh7Ywss/AD6I5kNVKZMmAa/QEW58Gxp2s=
google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157 h1:7whR9kGa5LUwFtpLm2ArCEejtnxlGeLbAyjFY8sGNFw=
google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157/go.mod h1:99sLkeliLXfdj2J75X3Ho+rrVCaJze0uwN7zDDkjPVU=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157 h1:Zy9XzmMEflZ/MAaA7vNcoebnRAld7FsPW1EeBB7V0m8=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157/go.mod h1:EfXuqaE1J41VCDicxHzUDm+8rk+7ZdXzHV0IhO/I6s0=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
google.golang.org/grpc v1.61.1 h1:kLAiWrZs7YeDM6MumDe7m3y4aM6wacLzM1Y/wiLP9XY=
google.golang.org/grpc v1.61.1/go.mod h1:VUbo7IFqmF1QtCAstipjG0GIoq49KvMe9+h1jFLBNJs=
google.golang.org/grpc v1.64.0 h1:KH3VH9y/MgNQg1dE7b3XfVK0GsPSIzJwdF617gUSbvY=
google.golang.org/grpc v1.64.0/go.mod h1:oxjF8E3FBnjp+/gVFYdWacaLDx9na1aqy9oovLpxQYg=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
@ -524,22 +690,42 @@ google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gorm.io/driver/postgres v1.5.9 h1:DkegyItji119OlcaLjqN11kHoUgZ/j13E0jkJZgD6A8=
gorm.io/driver/postgres v1.5.9/go.mod h1:DX3GReXH+3FPWGrrgffdvCk3DQ1dwDPdmbenSkweRGI=
gorm.io/gorm v1.25.10 h1:dQpO+33KalOA+aFYGlK+EfxcI5MbO7EP2yYygwh9h+s=
gorm.io/gorm v1.25.10/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6 h1:5D53IMaUuA5InSeMu9eJtlQXS2NxAhyWQvkKEgXZhHI=
modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6/go.mod h1:Qz0X07sNOR1jWYCrJMEnbW/X55x206Q7Vt4mz6/wHp4=
modernc.org/libc v1.41.0 h1:g9YAc6BkKlgORsUWj+JwqoB1wU3o4DE3bM3yvA3k+Gk=
modernc.org/libc v1.41.0/go.mod h1:w0eszPsiXoOnoMJgrXjglgLuDy/bt5RR4y3QzUUeodY=
modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4=
modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo=
modernc.org/memory v1.7.2 h1:Klh90S215mmH8c9gO98QxQFsY+W451E8AnzjoE2ee1E=
modernc.org/memory v1.7.2/go.mod h1:NO4NVCQy0N7ln+T9ngWqOQfi7ley4vpwvARR+Hjw95E=
modernc.org/sqlite v1.29.6 h1:0lOXGrycJPptfHDuohfYgNqoe4hu+gYuN/pKgY5XjS4=
modernc.org/sqlite v1.29.6/go.mod h1:S02dvcmm7TnTRvGhv8IGYyLnIt7AS2KPaB1F/71p75U=
modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA=
modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0=
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=
modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
mvdan.cc/gofumpt v0.4.0/go.mod h1:PljLOHDeZqgS8opHRKLzp2It2VBuSdteAgqUfzMTxlQ=
mvdan.cc/gofumpt v0.5.0 h1:0EQ+Z56k8tXjj/6TQD25BFNKQXpCvT0rnansIc7Ug5E=
mvdan.cc/gofumpt v0.5.0/go.mod h1:HBeVDtMKRZpXyxFciAirzdKklDlGu8aAy1wEbH5Y9js=

View File

@ -0,0 +1,35 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "iam",
srcs = [
"client.go",
"database.go",
"iam.go",
"openfga_server.go",
],
importpath = "github.com/sourcegraph/sourcegraph/lib/managedservicesplatform/iam",
visibility = ["//visibility:public"],
deps = [
"//lib/errors",
"//lib/managedservicesplatform/runtime",
"//lib/redislock",
"@com_github_openfga_api_proto//openfga/v1:openfga",
"@com_github_openfga_language_pkg_go//transformer",
"@com_github_openfga_openfga//assets",
"@com_github_openfga_openfga//pkg/server",
"@com_github_openfga_openfga//pkg/storage/postgres",
"@com_github_openfga_openfga//pkg/storage/sqlcommon",
"@com_github_pressly_goose_v3//:goose",
"@com_github_redis_go_redis_v9//:go-redis",
"@com_github_sourcegraph_log//:log",
"@io_gorm_driver_postgres//:postgres",
"@io_gorm_gorm//:gorm",
"@io_gorm_gorm//logger",
"@io_opentelemetry_go_otel//:otel",
"@io_opentelemetry_go_otel//attribute",
"@io_opentelemetry_go_otel//codes",
"@io_opentelemetry_go_otel_trace//:trace",
"@org_uber_go_zap//:zap",
],
)

View File

@ -0,0 +1,221 @@
package iam
import (
"context"
"strings"
openfgav1 "github.com/openfga/api/proto/openfga/v1"
"github.com/redis/go-redis/v9"
"github.com/sourcegraph/log"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/codes"
"github.com/sourcegraph/sourcegraph/lib/errors"
"github.com/sourcegraph/sourcegraph/lib/managedservicesplatform/runtime"
)
var iamTracer = otel.Tracer("msp/iam")
// ClientV1 provides helpers to interact with MSP IAM framework v1.
type ClientV1 struct {
server openfgav1.OpenFGAServiceServer
// storeID is the OpenFGA-server-generated ID of the store.
storeID string
// authorizationModelID is the OpenFGA-server-generated ID of the authorization
// model.
authorizationModelID string
}
type ClientV1Config struct {
// StoreName is the name of the store to create. Changing the name of the store
// will cause the IAM to create a new store without migrating the data. It is
// recommended to be machine-friendly, e.g. "enterprise-portal".
StoreName string
// AuthorizationModelDSL is the DSL to define the authorization model. See
// https://openfga.dev/docs/configuration-language for documentation.
AuthorizationModelDSL string
}
func (opts ClientV1Config) validate() error {
if opts.StoreName == "" {
return errors.New("store name is required")
}
if len(opts.AuthorizationModelDSL) == 0 {
return errors.New("authorization model DSL is required")
}
return nil
}
// NewClientV1 initializes and returns a new MSP IAM client by initializing with
// the given configuration. The returned `close` function should be called upon
// service shutdown.
func NewClientV1(ctx context.Context, logger log.Logger, contract runtime.Contract, redisClient *redis.Client, opts ClientV1Config) (_ *ClientV1, close func(), err error) {
ctx, span := iamTracer.Start(ctx, "iam.NewClientV1")
defer func() {
if err != nil {
span.RecordError(err)
span.SetStatus(codes.Error, err.Error())
}
span.End()
}()
if err = opts.validate(); err != nil {
return nil, nil, err
}
opts.AuthorizationModelDSL = strings.TrimSpace(opts.AuthorizationModelDSL)
sqlDB, err := contract.PostgreSQL.OpenDatabase(ctx, databaseName)
if err != nil {
return nil, nil, errors.Wrap(err, "open database")
}
metadata, err := migrateAndReconcile(ctx, logger, sqlDB, redisClient)
if err != nil {
if !contract.MSP && strings.Contains(err.Error(), "(SQLSTATE 3D000)") {
return nil, nil, errors.Newf("database '%[1]s' not found, please run 'createdb -h $PGHOST -p $PGPORT -U $PGUSER %[1]s'", databaseName)
}
return nil, nil, errors.Wrap(err, "migrate and recon")
}
srv, err := newOpenFGAServer(logger, sqlDB)
defer func() {
// Proactively close the server if there is an error to be returned.
if err != nil {
srv.Close()
}
}()
storeID, authorizationModelID, err := initServerSetup(
ctx,
initServerSetupOptions{
Logger: logger,
DB: sqlDB,
Server: srv,
StoreName: opts.StoreName,
AuthorizationModelDSL: opts.AuthorizationModelDSL,
Metadata: metadata,
},
)
if err != nil {
return nil, nil, errors.Wrap(err, "init server setup")
}
return &ClientV1{
server: srv,
storeID: storeID,
authorizationModelID: authorizationModelID,
}, func() { srv.Close() }, nil
}
type ListObjectsOptions struct {
Type TupleType
Relation TupleRelation
Subject TupleSubject
}
// ListObjects returns a list of object IDs that satisfy the given options.
func (c *ClientV1) ListObjects(ctx context.Context, opts ListObjectsOptions) ([]string, error) {
resp, err := c.server.ListObjects(
ctx,
&openfgav1.ListObjectsRequest{
StoreId: c.storeID,
AuthorizationModelId: c.authorizationModelID,
Type: string(opts.Type),
Relation: string(opts.Relation),
User: string(opts.Subject),
},
)
if err != nil {
return nil, err
}
return resp.GetObjects(), nil
}
type TupleKey struct {
Object TupleObject
TupleRelation TupleRelation
Subject TupleSubject
}
type WriteOptions struct {
Writes []TupleKey
Deletes []TupleKey
}
// Write upserts and/or deletes the relation tuples.
func (c *ClientV1) Write(ctx context.Context, opts WriteOptions) error {
writes := make([]*openfgav1.TupleKey, 0, len(opts.Writes))
for _, w := range opts.Writes {
writes = append(
writes,
&openfgav1.TupleKey{
User: string(w.Subject),
Relation: string(w.TupleRelation),
Object: string(w.Object),
},
)
}
deletes := make([]*openfgav1.TupleKeyWithoutCondition, 0, len(opts.Deletes))
for _, d := range opts.Deletes {
deletes = append(
deletes,
&openfgav1.TupleKeyWithoutCondition{
User: string(d.Subject),
Relation: string(d.TupleRelation),
Object: string(d.Object),
},
)
}
var requestWrites *openfgav1.WriteRequestWrites
var requestDeletes *openfgav1.WriteRequestDeletes
if len(writes) > 0 {
requestWrites = &openfgav1.WriteRequestWrites{TupleKeys: writes}
}
if len(deletes) > 0 {
requestDeletes = &openfgav1.WriteRequestDeletes{TupleKeys: deletes}
}
if requestWrites == nil && requestDeletes == nil {
return nil
}
_, err := c.server.Write(
ctx,
&openfgav1.WriteRequest{
StoreId: c.storeID,
AuthorizationModelId: c.authorizationModelID,
Writes: requestWrites,
Deletes: requestDeletes,
},
)
if err != nil {
return err
}
return nil
}
type CheckOptions struct {
TupleKey TupleKey
}
// Check checks whether a relationship exists (thus permission allowed) using
// the given tuple key as the check condition.
func (c *ClientV1) Check(ctx context.Context, opts CheckOptions) (allowed bool, _ error) {
resp, err := c.server.Check(
ctx,
&openfgav1.CheckRequest{
StoreId: c.storeID,
AuthorizationModelId: c.authorizationModelID,
TupleKey: &openfgav1.CheckRequestTupleKey{
User: string(opts.TupleKey.Subject),
Relation: string(opts.TupleKey.TupleRelation),
Object: string(opts.TupleKey.Object),
},
},
)
if err != nil {
return false, err
}
return resp.GetAllowed(), nil
}

View File

@ -0,0 +1,122 @@
package iam
import (
"context"
"database/sql"
"fmt"
"time"
"github.com/openfga/openfga/assets"
"github.com/pressly/goose/v3"
"github.com/redis/go-redis/v9"
"github.com/sourcegraph/log"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/codes"
"gorm.io/driver/postgres"
"gorm.io/gorm"
gormlogger "gorm.io/gorm/logger"
"github.com/sourcegraph/sourcegraph/lib/errors"
"github.com/sourcegraph/sourcegraph/lib/redislock"
)
const databaseName = "msp_iam"
type metadata struct {
AuthorizationModelID string `gorm:"column:authorization_model_id"`
AuthorizationModelDSL string `gorm:"column:authorization_model_dsl"`
UpdatedAt time.Time `gorm:"not null"`
}
// migrateAndReconcile migrates the "msp-iam" database schema (when needed) and
// reconciles the framework metadata.
func migrateAndReconcile(ctx context.Context, logger log.Logger, sqlDB *sql.DB, redisClient *redis.Client) (_ *metadata, err error) {
ctx, span := iamTracer.Start(ctx, "iam.migrateAndReconcile")
defer func() {
if err != nil {
span.RecordError(err)
span.SetStatus(codes.Error, err.Error())
}
span.End()
}()
conn, err := gorm.Open(
postgres.New(postgres.Config{Conn: sqlDB}),
&gorm.Config{
SkipDefaultTransaction: true,
NowFunc: func() time.Time {
return time.Now().UTC().Truncate(time.Microsecond)
},
},
)
if err != nil {
return nil, errors.Wrap(err, "open connection")
}
goose.SetBaseFS(assets.EmbedMigrations)
goose.SetLogger(&gooseLoggerShim{Logger: logger})
currentVersion, err := goose.GetDBVersion(sqlDB)
if err != nil {
return nil, errors.Wrap(err, "get DB version")
}
span.SetAttributes(attribute.Int64("currentVersion", currentVersion))
// We want to make sure only one instance of the server is doing auto-migration
// at a time.
err = redislock.OnlyOne(
logger,
redisClient,
fmt.Sprintf("%s:auto-migrate", databaseName),
15*time.Second,
func() error {
span.AddEvent("lock.acquired")
// Create a session that ignore debug logging.
sess := conn.Session(&gorm.Session{
Logger: gormlogger.Default.LogMode(gormlogger.Warn),
})
// Auto-migrate database table definitions.
for _, table := range []any{&metadata{}} {
err := sess.AutoMigrate(table)
if err != nil {
return errors.Wrapf(err, "auto migrating table for %s", errors.Safe(fmt.Sprintf("%T", table)))
}
}
// Migrate OpenFGA's database schema.
err = goose.UpContext(
ctx,
sqlDB,
assets.PostgresMigrationDir,
)
if err != nil {
return errors.Wrap(err, "run migrations")
}
return nil
},
)
if err != nil {
return nil, errors.Wrap(err, "auto-migrate")
}
var md metadata
if err = conn.FirstOrCreate(&md).Error; err != nil {
return nil, errors.Wrap(err, "init metadata")
}
return &md, nil
}
type gooseLoggerShim struct {
log.Logger
}
func (l *gooseLoggerShim) Fatalf(format string, v ...interface{}) {
l.Fatal(fmt.Sprintf(format, v...),
log.Error(errors.New("fatal Goose error")), // Sentinel error to trigger Sentry alerts.
)
}
func (l *gooseLoggerShim) Printf(format string, v ...interface{}) {
l.Debug(fmt.Sprintf(format, v...))
}

View File

@ -0,0 +1,47 @@
package iam
import (
"fmt"
)
type TupleType string
// Resource types.
const (
TupleTypeSubscriptionCodyAnalytics TupleType = "subscription_cody_analytics"
)
// Role objects.
const (
TupleTypeCustomerAdmin TupleType = "customer_admin"
TupleTypeUser TupleType = "user"
)
type TupleObject string
// ToTupleObject creates a TupleObject from the given type and ID, e.g.
// "subscription_cody_analytics:80ca12e2-54b4-448c-a61a-390b1a9c1224".
func ToTupleObject(typ TupleType, id string) TupleObject {
return TupleObject(fmt.Sprintf("%s:%s", typ, id))
}
type TupleRelation string
const (
TupleRelationMember TupleRelation = "member"
TupleRelationView TupleRelation = "view"
)
type TupleSubject string
// ToTupleSubjectUser creates a TupleSubject from a SAMS account ID for users,
// e.g. "user:018d21f2-04a6-7aaf-9f6f-6fc58c4187b9".
func ToTupleSubjectUser(samsAccountID string) TupleSubject {
return TupleSubject(fmt.Sprintf("%s:%s", TupleTypeUser, samsAccountID))
}
// ToTupleSubjectCustomerAdmin creates a TupleSubject from the given ID and
// relation customer admins, e.g. "customer_admin:80ca12e2-54b4-448c-a61a-390b1a9c1224#member".
func ToTupleSubjectCustomerAdmin(id string, relation TupleRelation) TupleSubject {
return TupleSubject(fmt.Sprintf("%s:%s#%s", TupleTypeCustomerAdmin, id, relation))
}

View File

@ -0,0 +1,229 @@
package iam
import (
"context"
"database/sql"
"math"
"time"
openfgav1 "github.com/openfga/api/proto/openfga/v1"
"github.com/openfga/language/pkg/go/transformer"
"github.com/openfga/openfga/pkg/server"
"github.com/openfga/openfga/pkg/storage/postgres"
"github.com/openfga/openfga/pkg/storage/sqlcommon"
"github.com/sourcegraph/log"
"go.opentelemetry.io/otel/codes"
oteltrace "go.opentelemetry.io/otel/trace"
"go.uber.org/zap" //nolint:logging // dependencies require direct usage of zap
"github.com/sourcegraph/sourcegraph/lib/errors"
)
func newOpenFGAServer(logger log.Logger, sqlDB *sql.DB) (*server.Server, error) {
openfgaLogger := &openfgaLoggerShim{Logger: logger}
// Defaults are all coming from github.com/openfga/internal/server/config/config.go,
// we cannot directly use them because of "internal" package.
datastore, err := postgres.NewWithDB(
sqlDB,
sqlcommon.NewConfig(
sqlcommon.WithLogger(openfgaLogger),
sqlcommon.WithMaxTuplesPerWrite(100), // Default
sqlcommon.WithMaxTypesPerAuthorizationModel(256*1_024), // Default
sqlcommon.WithMaxOpenConns(30), // Default
sqlcommon.WithMaxIdleConns(10), // Default
sqlcommon.WithConnMaxLifetime(time.Minute),
sqlcommon.WithMetrics(),
),
)
if err != nil {
return nil, errors.Wrap(err, "initialize postgres datastore")
}
// Defaults are all coming from github.com/openfga/internal/server/config/config.go,
// we cannot directly use them because of "internal" package.
srv, err := server.NewServerWithOpts(
server.WithDatastore(datastore),
server.WithAuthorizationModelCacheSize(100000), // Default
server.WithLogger(openfgaLogger),
server.WithResolveNodeLimit(25), // Default
server.WithResolveNodeBreadthLimit(100), // Default
server.WithChangelogHorizonOffset(0), // Default
server.WithListObjectsDeadline(3*time.Second), // Default
server.WithListObjectsMaxResults(1000), // Default
server.WithListUsersDeadline(3*time.Second), // Default
server.WithListUsersMaxResults(1000), // Default
server.WithMaxConcurrentReadsForListObjects(math.MaxUint32), // Default
server.WithMaxConcurrentReadsForCheck(math.MaxUint32), // Default
server.WithMaxConcurrentReadsForListUsers(math.MaxUint32), // Default
server.WithCheckQueryCacheEnabled(false), // Default
server.WithCheckQueryCacheLimit(10000), // Default
server.WithCheckQueryCacheTTL(10*time.Second), // Default
server.WithRequestDurationByQueryHistogramBuckets([]uint{50, 200}), // Default
server.WithRequestDurationByDispatchCountHistogramBuckets([]uint{50, 200}), // Default
server.WithMaxAuthorizationModelSizeInBytes(256*1_024), // Default
server.WithDispatchThrottlingCheckResolverEnabled(false), // Default
server.WithDispatchThrottlingCheckResolverFrequency(10*time.Microsecond), // Default
server.WithDispatchThrottlingCheckResolverThreshold(100), // Default
server.WithDispatchThrottlingCheckResolverMaxThreshold(0), // Default, 0 means use the default threshold as max.
server.WithListObjectsDispatchThrottlingEnabled(false), // Default
server.WithListObjectsDispatchThrottlingFrequency(10*time.Microsecond), // Default
server.WithListObjectsDispatchThrottlingThreshold(100), // Default
server.WithListObjectsDispatchThrottlingMaxThreshold(0), // Default, 0 means use the default threshold as max.
)
if err != nil {
return nil, errors.Wrap(err, "initialize server")
}
return srv, nil
}
type openfgaLoggerShim struct {
log.Logger
}
func (l *openfgaLoggerShim) Panic(s string, field ...zap.Field) {
l.Error(s, field...)
}
func (l *openfgaLoggerShim) DebugWithContext(ctx context.Context, s string, field ...zap.Field) {
l.WithTrace(traceContext(ctx)).Debug(s, field...)
}
func (l *openfgaLoggerShim) InfoWithContext(ctx context.Context, s string, field ...zap.Field) {
l.WithTrace(traceContext(ctx)).Info(s, field...)
}
func (l *openfgaLoggerShim) WarnWithContext(ctx context.Context, s string, field ...zap.Field) {
l.WithTrace(traceContext(ctx)).Warn(s, field...)
}
func (l *openfgaLoggerShim) ErrorWithContext(ctx context.Context, s string, field ...zap.Field) {
l.WithTrace(traceContext(ctx)).Error(s, field...)
}
func (l *openfgaLoggerShim) PanicWithContext(ctx context.Context, s string, field ...zap.Field) {
l.WithTrace(traceContext(ctx)).Error(s, field...)
}
func (l *openfgaLoggerShim) FatalWithContext(ctx context.Context, s string, field ...zap.Field) {
l.WithTrace(traceContext(ctx)).Fatal(s, field...)
}
// traceContext retrieves the full trace context, if any, from context - this
// includes both TraceID and SpanID.
func traceContext(ctx context.Context) log.TraceContext {
if otelSpan := oteltrace.SpanContextFromContext(ctx); otelSpan.IsValid() {
return log.TraceContext{
TraceID: otelSpan.TraceID().String(),
SpanID: otelSpan.SpanID().String(),
}
}
// no span found
return log.TraceContext{}
}
type initServerSetupOptions struct {
Logger log.Logger
DB *sql.DB
Server *server.Server
StoreName string
AuthorizationModelDSL string
Metadata *metadata
}
func (opts initServerSetupOptions) validate() error {
if opts.Logger == nil {
return errors.New("logger is required")
}
if opts.DB == nil {
return errors.New("database is required")
}
if opts.Server == nil {
return errors.New("server is required")
}
if opts.StoreName == "" {
return errors.New("store name is required")
}
if opts.AuthorizationModelDSL == "" {
return errors.New("authorization model DSL is required")
}
if opts.Metadata == nil {
return errors.New("metadata is required")
}
return nil
}
func initServerSetup(ctx context.Context, opts initServerSetupOptions) (storeID, authorizationModelID string, err error) {
ctx, span := iamTracer.Start(ctx, "iam.initServerSetup")
defer func() {
if err != nil {
span.RecordError(err)
span.SetStatus(codes.Error, err.Error())
}
span.End()
}()
if err = opts.validate(); err != nil {
return "", "", err
}
// Ensure the store exists.
listStoresResp, err := opts.Server.ListStores(ctx, &openfgav1.ListStoresRequest{})
if err != nil {
return "", "", errors.Wrap(err, "list stores")
}
for _, store := range listStoresResp.GetStores() {
if store.GetName() == opts.StoreName {
storeID = store.GetId()
break
}
}
if storeID == "" {
resp, err := opts.Server.CreateStore(
ctx,
&openfgav1.CreateStoreRequest{Name: opts.StoreName},
)
if err != nil {
return "", "", errors.Wrap(err, "create store")
}
storeID = resp.GetId()
}
// Ensure the authorization model is up-to-date.
if opts.Metadata.AuthorizationModelDSL == opts.AuthorizationModelDSL {
return storeID, opts.Metadata.AuthorizationModelID, nil
}
proto, err := transformer.TransformDSLToProto(opts.AuthorizationModelDSL)
if err != nil {
return "", "", errors.Wrap(err, "transform DSL to proto")
}
writeAuthorizationModelResp, err := opts.Server.WriteAuthorizationModel(
ctx,
&openfgav1.WriteAuthorizationModelRequest{
StoreId: storeID,
TypeDefinitions: proto.GetTypeDefinitions(),
SchemaVersion: proto.GetSchemaVersion(),
Conditions: nil,
},
)
if err != nil {
return "", "", errors.Wrap(err, "write authorization model")
}
authorizationModelID = writeAuthorizationModelResp.GetAuthorizationModelId()
_, err = opts.DB.ExecContext(
ctx,
"UPDATE metadata SET authorization_model_id = $1, authorization_model_dsl = $2, updated_at = $3",
authorizationModelID,
opts.AuthorizationModelDSL,
time.Now().UTC(),
)
if err != nil {
return "", "", errors.Wrap(err, "update metadata")
}
return storeID, authorizationModelID, nil
}

28
lib/redislock/BUILD.bazel Normal file
View File

@ -0,0 +1,28 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
load("//dev:go_defs.bzl", "go_test")
go_library(
name = "redislock",
srcs = ["mutex.go"],
importpath = "github.com/sourcegraph/sourcegraph/lib/redislock",
visibility = ["//visibility:public"],
deps = [
"//lib/errors",
"@com_github_go_redsync_redsync_v4//:redsync",
"@com_github_go_redsync_redsync_v4//redis/goredis/v9:goredis",
"@com_github_redis_go_redis_v9//:go-redis",
"@com_github_sourcegraph_log//:log",
],
)
go_test(
name = "redislock_test",
srcs = ["mutex_test.go"],
embed = [":redislock"],
deps = [
"@com_github_redis_go_redis_v9//:go-redis",
"@com_github_sourcegraph_log//logtest",
"@com_github_stretchr_testify//assert",
"@com_github_stretchr_testify//require",
],
)

View File

@ -1,6 +1,7 @@
package redislock
import (
"os"
"testing"
"time"
@ -8,15 +9,16 @@ import (
"github.com/sourcegraph/log/logtest"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/sourcegraph/sourcegraph/internal/rcache"
)
func TestOnlyOne(t *testing.T) {
rcache.SetupForTest(t)
addr := os.ExpandEnv("$REDIS_HOST:$REDIS_PORT")
if addr == ":" {
t.Skip("REDIS_HOST and REDIS_PORT not set")
}
logger := logtest.NoOp(t)
client := redis.NewClient(&redis.Options{Addr: rcache.TestAddr})
client := redis.NewClient(&redis.Options{Addr: addr})
// If the algorithm is correct, there should be no data race detected in tests,
// and the final count should be 10.

View File

@ -438,4 +438,9 @@
- path: github.com/sourcegraph/sourcegraph/cmd/cody-gateway/internal/actor/productsubscription
interfaces:
- EnterprisePortalClient
- filename: cmd/enterprise-portal/internal/subscriptionsservice/mocks_test.go
package: subscriptionsservice
sources:
- path: github.com/sourcegraph/sourcegraph/cmd/enterprise-portal/internal/subscriptionsservice
interfaces:
- StoreV1

View File

@ -31,7 +31,7 @@ replace (
require (
github.com/benbjohnson/clock v1.3.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/cockroachdb/errors v1.11.1 // indirect
github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect
github.com/cockroachdb/redact v1.1.5 // indirect

View File

@ -43,8 +43,8 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/chromedp/cdproto v0.0.0-20210526005521-9e51b9051fd0/go.mod h1:At5TxYYdxkbQL0TSefRjhLE3Q0lgvqKKMSFUglJ7i1U=
github.com/chromedp/cdproto v0.0.0-20210706234513-2bc298e8be7f h1:lg5k1KAxmknil6Z19LaaeiEs5Pje7hPzRfyWSSnWLP0=
github.com/chromedp/cdproto v0.0.0-20210706234513-2bc298e8be7f/go.mod h1:At5TxYYdxkbQL0TSefRjhLE3Q0lgvqKKMSFUglJ7i1U=

View File

@ -415,6 +415,8 @@ commands:
export GCFLAGS='all=-N -l'
fi
go build -gcflags="$GCFLAGS" -o .bin/enterprise-portal github.com/sourcegraph/sourcegraph/cmd/enterprise-portal
# Ensure the "msp_iam" database exists (PostgreSQL has no "IF NOT EXISTS" option).
createdb -h $PGHOST -p $PGPORT -U $PGUSER msp_iam || true
checkBinary: .bin/enterprise-portal
env:
PORT: '6081'

View File

@ -0,0 +1 @@
exports_files(glob(["*.patch"]))

View File

@ -0,0 +1,85 @@
diff --git a/cel/BUILD.bazel b/cel/BUILD.bazel
index 6e2fc07..002b59e 100644
--- a/cel/BUILD.bazel
+++ b/cel/BUILD.bazel
@@ -4,6 +4,12 @@ package(
licenses = ["notice"], # Apache 2.0
)
+alias(
+ name = "cel",
+ actual = ":go_default_library",
+ visibility = ["//visibility:public"],
+)
+
go_library(
name = "go_default_library",
srcs = [
diff --git a/common/BUILD.bazel b/common/BUILD.bazel
index eef7f28..10b57a2 100644
--- a/common/BUILD.bazel
+++ b/common/BUILD.bazel
@@ -5,6 +5,12 @@ package(
licenses = ["notice"], # Apache 2.0
)
+alias(
+ name = "common",
+ actual = ":go_default_library",
+ visibility = ["//visibility:public"],
+)
+
go_library(
name = "go_default_library",
srcs = [
diff --git a/common/types/BUILD.bazel b/common/types/BUILD.bazel
index b5e44ff..ae133b3 100644
--- a/common/types/BUILD.bazel
+++ b/common/types/BUILD.bazel
@@ -5,6 +5,12 @@ package(
licenses = ["notice"], # Apache 2.0
)
+alias(
+ name = "types",
+ actual = ":go_default_library",
+ visibility = ["//visibility:public"],
+)
+
go_library(
name = "go_default_library",
srcs = [
diff --git a/common/types/ref/BUILD.bazel b/common/types/ref/BUILD.bazel
index 79330c3..1260306 100644
--- a/common/types/ref/BUILD.bazel
+++ b/common/types/ref/BUILD.bazel
@@ -5,6 +5,12 @@ package(
licenses = ["notice"], # Apache 2.0
)
+alias(
+ name = "ref",
+ actual = ":go_default_library",
+ visibility = ["//visibility:public"],
+)
+
go_library(
name = "go_default_library",
srcs = [
diff --git a/common/types/traits/BUILD.bazel b/common/types/traits/BUILD.bazel
index b19eb83..5c54558 100644
--- a/common/types/traits/BUILD.bazel
+++ b/common/types/traits/BUILD.bazel
@@ -5,6 +5,12 @@ package(
licenses = ["notice"], # Apache 2.0
)
+alias(
+ name = "traits",
+ actual = ":go_default_library",
+ visibility = ["//visibility:public"],
+)
+
go_library(
name = "go_default_library",
srcs = [