diff --git a/Dockerfile b/Dockerfile index 1357f1361..acbf055d3 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,6 +5,11 @@ RUN apk add openssl RUN apk add --no-cache ca-certificates && update-ca-certificates +# odps package has an unhandled (panicking) error that requires this pkg to be installed to avoid the panic: +# https://github.com/aliyun/aliyun-odps-go-sdk/blob/master/odps/restclient/rest_client.go#L171 +# https://github.com/aliyun/aliyun-odps-go-sdk/blob/master/odps/common/http_const.go#L38 +RUN apk --no-cache add tzdata + RUN curl --output /usr/local/share/ca-certificates/SectigoRSADomainValidationSecureServerCA.crt http://crt.sectigo.com/SectigoRSADomainValidationSecureServerCA.crt RUN openssl x509 -inform DER -in /usr/local/share/ca-certificates/SectigoRSADomainValidationSecureServerCA.crt -out /usr/local/share/ca-certificates/SectigoRSADomainValidationSecureServerCA.pem -text diff --git a/core/appeal/mocks/grantService.go b/core/appeal/mocks/grantService.go index 1de2c8039..451c1ff9e 100644 --- a/core/appeal/mocks/grantService.go +++ b/core/appeal/mocks/grantService.go @@ -24,6 +24,49 @@ func (_m *GrantService) EXPECT() *GrantService_Expecter { return &GrantService_Expecter{mock: &_m.Mock} } +// Create provides a mock function with given fields: ctx, _a1 +func (_m *GrantService) Create(ctx context.Context, _a1 *domain.Grant) error { + ret := _m.Called(ctx, _a1) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, *domain.Grant) error); ok { + r0 = rf(ctx, _a1) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// GrantService_Create_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Create' +type GrantService_Create_Call struct { + *mock.Call +} + +// Create is a helper method to define mock.On call +// - ctx context.Context +// - _a1 *domain.Grant +func (_e *GrantService_Expecter) Create(ctx interface{}, _a1 interface{}) *GrantService_Create_Call { + return &GrantService_Create_Call{Call: _e.mock.On("Create", ctx, _a1)} +} + +func (_c *GrantService_Create_Call) Run(run func(ctx context.Context, _a1 *domain.Grant)) *GrantService_Create_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(*domain.Grant)) + }) + return _c +} + +func (_c *GrantService_Create_Call) Return(_a0 error) *GrantService_Create_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *GrantService_Create_Call) RunAndReturn(run func(context.Context, *domain.Grant) error) *GrantService_Create_Call { + _c.Call.Return(run) + return _c +} + // List provides a mock function with given fields: _a0, _a1 func (_m *GrantService) List(_a0 context.Context, _a1 domain.ListGrantsFilter) ([]domain.Grant, error) { ret := _m.Called(_a0, _a1) diff --git a/core/appeal/mocks/providerService.go b/core/appeal/mocks/providerService.go index 877675400..2ec2c6dd8 100644 --- a/core/appeal/mocks/providerService.go +++ b/core/appeal/mocks/providerService.go @@ -76,6 +76,61 @@ func (_c *ProviderService_Find_Call) RunAndReturn(run func(context.Context) ([]* return _c } +// GetDependencyGrants provides a mock function with given fields: _a0, _a1 +func (_m *ProviderService) GetDependencyGrants(_a0 context.Context, _a1 domain.Grant) ([]*domain.Grant, error) { + ret := _m.Called(_a0, _a1) + + var r0 []*domain.Grant + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, domain.Grant) ([]*domain.Grant, error)); ok { + return rf(_a0, _a1) + } + if rf, ok := ret.Get(0).(func(context.Context, domain.Grant) []*domain.Grant); ok { + r0 = rf(_a0, _a1) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*domain.Grant) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, domain.Grant) error); ok { + r1 = rf(_a0, _a1) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// ProviderService_GetDependencyGrants_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetDependencyGrants' +type ProviderService_GetDependencyGrants_Call struct { + *mock.Call +} + +// GetDependencyGrants is a helper method to define mock.On call +// - _a0 context.Context +// - _a1 domain.Grant +func (_e *ProviderService_Expecter) GetDependencyGrants(_a0 interface{}, _a1 interface{}) *ProviderService_GetDependencyGrants_Call { + return &ProviderService_GetDependencyGrants_Call{Call: _e.mock.On("GetDependencyGrants", _a0, _a1)} +} + +func (_c *ProviderService_GetDependencyGrants_Call) Run(run func(_a0 context.Context, _a1 domain.Grant)) *ProviderService_GetDependencyGrants_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(domain.Grant)) + }) + return _c +} + +func (_c *ProviderService_GetDependencyGrants_Call) Return(_a0 []*domain.Grant, _a1 error) *ProviderService_GetDependencyGrants_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *ProviderService_GetDependencyGrants_Call) RunAndReturn(run func(context.Context, domain.Grant) ([]*domain.Grant, error)) *ProviderService_GetDependencyGrants_Call { + _c.Call.Return(run) + return _c +} + // GetPermissions provides a mock function with given fields: _a0, _a1, _a2, _a3 func (_m *ProviderService) GetPermissions(_a0 context.Context, _a1 *domain.ProviderConfig, _a2 string, _a3 string) ([]interface{}, error) { ret := _m.Called(_a0, _a1, _a2, _a3) diff --git a/core/appeal/service.go b/core/appeal/service.go index 2c9741e4c..9e91f91b1 100644 --- a/core/appeal/service.go +++ b/core/appeal/service.go @@ -83,6 +83,7 @@ type providerService interface { ValidateAppeal(context.Context, *domain.Appeal, *domain.Provider, *domain.Policy) error GetPermissions(context.Context, *domain.ProviderConfig, string, string) ([]interface{}, error) IsExclusiveRoleAssignment(context.Context, string, string) bool + GetDependencyGrants(context.Context, domain.Grant) ([]*domain.Grant, error) } //go:generate mockery --name=resourceService --exported --with-expecter @@ -96,6 +97,7 @@ type grantService interface { List(context.Context, domain.ListGrantsFilter) ([]domain.Grant, error) Prepare(context.Context, domain.Appeal) (*domain.Grant, error) Revoke(ctx context.Context, id, actor, reason string, opts ...grant.Option) (*domain.Grant, error) + Create(ctx context.Context, grant *domain.Grant) error } //go:generate mockery --name=auditLogger --exported --with-expecter @@ -1489,10 +1491,52 @@ func (s *Service) GrantAccessToProvider(ctx context.Context, a *domain.Appeal, o } } - if err := s.providerService.GrantAccess(ctx, *a.Grant); err != nil { + appealCopy := *a + appealCopy.Grant = nil + grantWithAppeal := *a.Grant + grantWithAppeal.Appeal = &appealCopy + + // grant access dependencies (if any) + dependencyGrants, err := s.providerService.GetDependencyGrants(ctx, grantWithAppeal) + if err != nil { + return fmt.Errorf("getting grant dependencies: %w", err) + } + for _, dg := range dependencyGrants { + activeDepGrants, err := s.grantService.List(ctx, domain.ListGrantsFilter{ + Statuses: []string{string(domain.GrantStatusActive)}, + AccountIDs: []string{dg.AccountID}, + AccountTypes: []string{dg.AccountType}, + ResourceIDs: []string{dg.Resource.ID}, + Permissions: dg.Permissions, + Size: 1, + }) + if err != nil { + return fmt.Errorf("failed to get existing active grant dependency: %w", err) + } + + if len(activeDepGrants) > 0 { + continue + } + + dg.Status = domain.GrantStatusActive + dg.Appeal = &appealCopy + if err := s.providerService.GrantAccess(ctx, *dg); err != nil { + return fmt.Errorf("failed to grant an access dependency: %w", err) + } + dg.Appeal = nil + + dg.Owner = a.CreatedBy + if err := s.grantService.Create(ctx, dg); err != nil { + return fmt.Errorf("failed to store grant of access dependency: %w", err) + } + } + + // grant main access + if err := s.providerService.GrantAccess(ctx, grantWithAppeal); err != nil { return fmt.Errorf("granting access: %w", err) } + grantWithAppeal.Appeal = nil return nil } diff --git a/core/appeal/service_test.go b/core/appeal/service_test.go index 639f0c620..f6a2164d3 100644 --- a/core/appeal/service_test.go +++ b/core/appeal/service_test.go @@ -12,6 +12,8 @@ import ( "time" "github.com/go-playground/validator/v10" + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" "github.com/google/uuid" "github.com/goto/guardian/core/appeal" appealmocks "github.com/goto/guardian/core/appeal/mocks" @@ -2476,6 +2478,7 @@ func (s *ServiceTestSuite) TestCreate() { h.mockGrantService.EXPECT().List(mock.Anything, mock.Anything).Return([]domain.Grant{}, nil).Once() h.mockGrantService.EXPECT().Prepare(mock.Anything, mock.Anything).Return(&domain.Grant{}, nil).Once() h.mockPolicyService.EXPECT().GetOne(mock.Anything, mock.Anything, mock.Anything).Return(overriddingPolicy, nil).Once() + h.mockProviderService.EXPECT().GetDependencyGrants(mock.Anything, mock.AnythingOfType("domain.Grant")).Return(nil, nil).Once() h.mockProviderService.EXPECT().GrantAccess(mock.Anything, mock.Anything).Return(nil).Once() err := h.service.Create(context.Background(), []*domain.Appeal{input}, appeal.CreateWithAdditionalAppeal()) @@ -2740,6 +2743,7 @@ func (s *ServiceTestSuite) TestCreate__WithExistingAppealAndWithAutoApprovalStep ). Return(preparedGrant, nil).Once() h.mockPolicyService.EXPECT().GetOne(mock.Anything, policies[0].ID, policies[0].Version).Return(policies[0], nil).Once() + h.mockProviderService.EXPECT().GetDependencyGrants(mock.Anything, mock.AnythingOfType("domain.Grant")).Return(nil, nil).Once() h.mockProviderService.EXPECT().GrantAccess(mock.Anything, mock.Anything).Return(nil).Once() h.mockRepository.EXPECT(). @@ -2930,6 +2934,7 @@ func (s *ServiceTestSuite) TestCreate__WithAdditionalAppeals() { h.mockPolicyService.EXPECT().GetOne(mock.AnythingOfType("*context.cancelCtx"), policies[0].ID, policies[0].Version).Return(policies[0], nil).Once() // 2.b grant access for the additional appeal + h.mockProviderService.EXPECT().GetDependencyGrants(mock.Anything, mock.AnythingOfType("domain.Grant")).Return(nil, nil).Once() h.mockProviderService.EXPECT().GrantAccess(mock.AnythingOfType("*context.cancelCtx"), mock.AnythingOfType("domain.Grant")).Return(nil).Once().Run(func(args mock.Arguments) { grant := args.Get(1).(domain.Grant) s.Equal(expectedAdditionalGrant.ID, grant.ID) @@ -2943,6 +2948,7 @@ func (s *ServiceTestSuite) TestCreate__WithAdditionalAppeals() { h.mockNotifier.EXPECT().Notify(h.ctxMatcher, mock.Anything).Return(nil).Once() // 1.b grant access for the main appeal + h.mockProviderService.EXPECT().GetDependencyGrants(mock.Anything, mock.AnythingOfType("domain.Grant")).Return(nil, nil).Once() h.mockProviderService.EXPECT().GrantAccess(h.ctxMatcher, mock.AnythingOfType("domain.Grant")).Return(nil).Once().Run(func(args mock.Arguments) { grant := args.Get(1).(domain.Grant) s.Equal(expectedGrant.ID, grant.ID) @@ -4830,6 +4836,7 @@ func (s *ServiceTestSuite) TestUpdateApproval() { appeal.RevokeReasonForExtension, mock.Anything, mock.Anything). Return(expectedNewGrant, nil).Once() h.mockPolicyService.EXPECT().GetOne(mock.Anything, mock.Anything, mock.Anything).Return(dummyPolicy, nil).Once() + h.mockProviderService.EXPECT().GetDependencyGrants(mock.Anything, mock.AnythingOfType("domain.Grant")).Return(nil, nil).Once() h.mockProviderService.EXPECT().GrantAccess(mock.Anything, mock.Anything).Return(nil).Once() h.mockRepository.EXPECT().Update(h.ctxMatcher, appealDetails).Return(nil).Once() h.mockNotifier.EXPECT().Notify(h.ctxMatcher, mock.Anything).Return(nil).Once() @@ -5276,7 +5283,8 @@ func (s *ServiceTestSuite) TestUpdateApproval() { h.mockGrantService.EXPECT(). Prepare(mock.Anything, mock.Anything).Return(tc.expectedGrant, nil).Once() - h.mockProviderService.EXPECT().GrantAccess(mock.Anything, *tc.expectedGrant).Return(nil).Once() + h.mockProviderService.EXPECT().GetDependencyGrants(mock.Anything, mock.AnythingOfType("domain.Grant")).Return(nil, nil).Once() + h.mockProviderService.EXPECT().GrantAccess(mock.Anything, grantArgMatcher(*tc.expectedGrant)).Return(nil).Once() } h.mockRepository.EXPECT().Update(h.ctxMatcher, tc.expectedResult).Return(nil).Once() @@ -5433,7 +5441,8 @@ func (s *ServiceTestSuite) TestUpdateApproval() { h.mockGrantService.EXPECT(). Prepare(mock.Anything, mock.Anything).Return(tc.expectedGrant, nil).Once() - h.mockProviderService.EXPECT().GrantAccess(mock.Anything, *tc.expectedGrant).Return(nil).Once() + h.mockProviderService.EXPECT().GetDependencyGrants(mock.Anything, mock.AnythingOfType("domain.Grant")).Return(nil, nil).Once() + h.mockProviderService.EXPECT().GrantAccess(mock.Anything, grantArgMatcher(*tc.expectedGrant)).Return(nil).Once() } h.mockRepository.EXPECT().Update(h.ctxMatcher, tc.expectedResult).Return(nil).Once() @@ -5531,6 +5540,7 @@ func (s *ServiceTestSuite) TestUpdateApproval() { h.mockGrantService.EXPECT(). Prepare(mock.Anything, mock.Anything).Return(nil, nil).Once() + h.mockProviderService.EXPECT().GetDependencyGrants(mock.Anything, mock.AnythingOfType("domain.Grant")).Return(nil, nil).Once() h.mockProviderService.EXPECT().GrantAccess(mock.Anything, mock.Anything).Return(nil).Once() h.mockRepository.EXPECT().Update(h.ctxMatcher, mock.Anything).Return(nil).Once() @@ -5611,9 +5621,8 @@ func (s *ServiceTestSuite) TestGrantAccessToProvider() { Version: 1, }, nil).Once() - h.mockProviderService. - On("GrantAccess", mock.Anything, mock.Anything). - Return(fmt.Errorf("error")).Once() + h.mockProviderService.EXPECT().GetDependencyGrants(mock.Anything, mock.AnythingOfType("domain.Grant")).Return(nil, nil).Once() + h.mockProviderService.EXPECT().GrantAccess(mock.Anything, mock.Anything).Return(fmt.Errorf("error")).Once() actualError := h.service.GrantAccessToProvider(context.Background(), &domain.Appeal{ PolicyID: "policy_1", @@ -5633,9 +5642,8 @@ func (s *ServiceTestSuite) TestGrantAccessToProvider() { Version: 1, }, nil).Once() - h.mockProviderService. - On("GrantAccess", mock.Anything, mock.Anything). - Return(nil).Once() + h.mockProviderService.EXPECT().GetDependencyGrants(mock.Anything, mock.AnythingOfType("domain.Grant")).Return(nil, nil).Once() + h.mockProviderService.EXPECT().GrantAccess(mock.Anything, mock.Anything).Return(nil).Once() actualError := h.service.GrantAccessToProvider(context.Background(), &domain.Appeal{ PolicyID: "policy_1", @@ -6295,3 +6303,14 @@ func (s *ServiceTestSuite) TestGetAppealsTotalCount() { s.NoError(actualError) }) } + +func grantArgMatcher(expected domain.Grant) any { + return mock.MatchedBy(func(actual domain.Grant) bool { + return cmp.Equal( + expected, + actual, + cmpopts.EquateApproxTime(time.Millisecond), + cmpopts.IgnoreFields(domain.Grant{}, "Appeal"), + ) + }) +} diff --git a/core/grant/mocks/repository.go b/core/grant/mocks/repository.go index 7ec877220..7b577b437 100644 --- a/core/grant/mocks/repository.go +++ b/core/grant/mocks/repository.go @@ -66,6 +66,49 @@ func (_c *Repository_BulkUpsert_Call) RunAndReturn(run func(context.Context, []* return _c } +// Create provides a mock function with given fields: _a0, _a1 +func (_m *Repository) Create(_a0 context.Context, _a1 *domain.Grant) error { + ret := _m.Called(_a0, _a1) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, *domain.Grant) error); ok { + r0 = rf(_a0, _a1) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Repository_Create_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Create' +type Repository_Create_Call struct { + *mock.Call +} + +// Create is a helper method to define mock.On call +// - _a0 context.Context +// - _a1 *domain.Grant +func (_e *Repository_Expecter) Create(_a0 interface{}, _a1 interface{}) *Repository_Create_Call { + return &Repository_Create_Call{Call: _e.mock.On("Create", _a0, _a1)} +} + +func (_c *Repository_Create_Call) Run(run func(_a0 context.Context, _a1 *domain.Grant)) *Repository_Create_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(*domain.Grant)) + }) + return _c +} + +func (_c *Repository_Create_Call) Return(_a0 error) *Repository_Create_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *Repository_Create_Call) RunAndReturn(run func(context.Context, *domain.Grant) error) *Repository_Create_Call { + _c.Call.Return(run) + return _c +} + // GetByID provides a mock function with given fields: _a0, _a1 func (_m *Repository) GetByID(_a0 context.Context, _a1 string) (*domain.Grant, error) { ret := _m.Called(_a0, _a1) diff --git a/core/grant/service.go b/core/grant/service.go index 499b7e6a8..bc4d69575 100644 --- a/core/grant/service.go +++ b/core/grant/service.go @@ -30,6 +30,7 @@ type repository interface { BulkUpsert(context.Context, []*domain.Grant) error GetGrantsTotalCount(context.Context, domain.ListGrantsFilter) (int64, error) ListUserRoles(context.Context, string) ([]string, error) + Create(context.Context, *domain.Grant) error } //go:generate mockery --name=providerService --exported --with-expecter @@ -110,6 +111,10 @@ func (s *Service) GetByID(ctx context.Context, id string) (*domain.Grant, error) return s.repo.GetByID(ctx, id) } +func (s *Service) Create(ctx context.Context, grant *domain.Grant) error { + return s.repo.Create(ctx, grant) +} + func (s *Service) Update(ctx context.Context, payload *domain.GrantUpdate) (*domain.Grant, error) { grant, err := s.GetByID(ctx, payload.ID) if err != nil { diff --git a/core/provider/service.go b/core/provider/service.go index 241cf7bf7..58448cea3 100644 --- a/core/provider/service.go +++ b/core/provider/service.go @@ -56,6 +56,10 @@ type assignmentTyper interface { IsExclusiveRoleAssignment(context.Context) bool } +type grantDependenciesResolver interface { + GetDependencyGrants(context.Context, domain.Provider, domain.Grant) ([]*domain.Grant, error) +} + //go:generate mockery --name=resourceService --exported --with-expecter type resourceService interface { Find(context.Context, domain.ListResourcesFilter) ([]*domain.Resource, error) @@ -569,6 +573,49 @@ func (s *Service) IsExclusiveRoleAssignment(ctx context.Context, providerType, r return false } +func (s *Service) GetDependencyGrants(ctx context.Context, g domain.Grant) ([]*domain.Grant, error) { + client := s.getClient(g.Resource.ProviderType) + if client == nil { + return nil, ErrInvalidProviderType + } + + c, ok := client.(grantDependenciesResolver) + if !ok { + return nil, nil + } + + p, err := s.getProviderConfig(ctx, g.Resource.ProviderType, g.Resource.ProviderURN) + if err != nil { + return nil, err + } + + dependencies, err := c.GetDependencyGrants(ctx, *p, g) + if err != nil { + return nil, err + } + + for _, d := range dependencies { + resources, err := s.resourceService.Find(ctx, domain.ListResourcesFilter{ + ProviderType: d.Resource.ProviderType, + ProviderURN: d.Resource.ProviderURN, + ResourceType: d.Resource.Type, + ResourceURN: d.Resource.URN, + Size: 1, + }) + if err != nil { + return nil, fmt.Errorf("unable to resolve resource %q for grant dependency: %w", d.Resource.URN, err) + } + if len(resources) == 0 { + return nil, fmt.Errorf("unable to resolve resource %q for grant dependency: not found", d.Resource.URN) + } + + d.ResourceID = resources[0].ID + d.Resource = resources[0] + } + + return dependencies, nil +} + func (s *Service) fetchNewResources(ctx context.Context, p *domain.Provider) ([]*domain.Resource, int, error) { c := s.getClient(p.Type) if c == nil { diff --git a/domain/provider.go b/domain/provider.go index fd8ff102a..4ac795a85 100644 --- a/domain/provider.go +++ b/domain/provider.go @@ -7,17 +7,18 @@ import ( ) const ( - ProviderTypeBigQuery = "bigquery" - ProviderTypeMetabase = "metabase" - ProviderTypeGrafana = "grafana" - ProviderTypeTableau = "tableau" - ProviderTypeGCloudIAM = "gcloud_iam" - ProviderTypeNoOp = "noop" - ProviderTypeGCS = "gcs" - ProviderTypePolicyTag = "dataplex" - ProviderTypeShield = "shield" - ProviderTypeGitlab = "gitlab" - ProviderTypeGate = "gate" + ProviderTypeBigQuery = "bigquery" + ProviderTypeMetabase = "metabase" + ProviderTypeGrafana = "grafana" + ProviderTypeTableau = "tableau" + ProviderTypeGCloudIAM = "gcloud_iam" + ProviderTypeNoOp = "noop" + ProviderTypeGCS = "gcs" + ProviderTypePolicyTag = "dataplex" + ProviderTypeShield = "shield" + ProviderTypeGitlab = "gitlab" + ProviderTypeGate = "gate" + ProviderTypeMaxCompute = "maxcompute" ) // Role is the configuration to define a role and mapping the permissions in the provider @@ -83,6 +84,13 @@ func (pc ProviderConfig) GetResourceTypes() (resourceTypes []string) { return } +func (pc ProviderConfig) GetParameterKeys() (keys []string) { + for _, param := range pc.Parameters { + keys = append(keys, param.Key) + } + return +} + func (pc ProviderConfig) GetFilterForResourceType(resourceType string) string { for _, resource := range pc.Resources { if resource.Type == resourceType { diff --git a/go.mod b/go.mod index 0cf5e3025..e3adb4e41 100644 --- a/go.mod +++ b/go.mod @@ -9,6 +9,11 @@ require ( cloud.google.com/go/storage v1.30.1 github.com/DATA-DOG/go-sqlmock v1.5.2 github.com/MakeNowJust/heredoc v1.0.0 + github.com/alibabacloud-go/darabonba-openapi v0.1.16 + github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.8 + github.com/alibabacloud-go/maxcompute-20220104 v1.4.1 + github.com/alibabacloud-go/sts-20150401 v1.1.2 + github.com/aliyun/aliyun-odps-go-sdk v0.3.15 github.com/antonmedv/expr v1.15.3 github.com/envoyproxy/protoc-gen-validate v1.0.2 github.com/go-playground/validator/v10 v10.4.1 @@ -67,6 +72,15 @@ require ( github.com/Microsoft/go-winio v0.5.2 // indirect github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect github.com/alecthomas/chroma v0.8.2 // indirect + github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.4 // indirect + github.com/alibabacloud-go/debug v1.0.1 // indirect + github.com/alibabacloud-go/endpoint-util v1.1.0 // indirect + github.com/alibabacloud-go/openapi-util v0.1.0 // indirect + github.com/alibabacloud-go/tea v1.2.2 // indirect + github.com/alibabacloud-go/tea-utils v1.4.3 // indirect + github.com/alibabacloud-go/tea-utils/v2 v2.0.5 // indirect + github.com/alibabacloud-go/tea-xml v1.1.3 // indirect + github.com/aliyun/credentials-go v1.3.10 // indirect github.com/andybalholm/brotli v1.0.4 // indirect github.com/apache/arrow/go/v12 v12.0.0 // indirect github.com/apache/thrift v0.16.0 // indirect @@ -74,6 +88,7 @@ require ( github.com/briandowns/spinner v1.18.0 // indirect github.com/cenkalti/backoff/v4 v4.2.1 // indirect github.com/charmbracelet/glamour v0.3.0 // indirect + github.com/clbanning/mxj/v2 v2.5.5 // indirect github.com/cli/safeexec v1.0.0 // indirect github.com/containerd/continuity v0.3.0 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.0 // indirect @@ -97,7 +112,7 @@ require ( 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/google/flatbuffers v23.5.26+incompatible // indirect github.com/google/go-querystring v1.1.0 // indirect github.com/google/s2a-go v0.1.4 // indirect github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect @@ -117,6 +132,7 @@ require ( github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect github.com/jmoiron/sqlx v1.3.5 // indirect + github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/asmfmt v1.3.2 // indirect github.com/klauspost/compress v1.15.9 // indirect github.com/klauspost/cpuid/v2 v2.0.9 // indirect @@ -132,6 +148,8 @@ require ( github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3 // indirect github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect github.com/muesli/reflow v0.2.0 // indirect github.com/muesli/termenv v0.9.0 // indirect github.com/olekukonko/tablewriter v0.0.5 // indirect @@ -139,7 +157,7 @@ require ( github.com/opencontainers/image-spec v1.0.2 // indirect github.com/opencontainers/runc v1.1.2 // indirect github.com/pelletier/go-toml v1.9.3 // indirect - github.com/pierrec/lz4/v4 v4.1.15 // 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/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect @@ -160,6 +178,7 @@ require ( github.com/tidwall/match v1.1.1 // indirect github.com/tidwall/pretty v1.2.1 // indirect github.com/tidwall/sjson v1.2.5 // indirect + github.com/tjfoc/gmsm v1.3.2 // indirect github.com/tklauser/go-sysconf v0.3.14 // indirect github.com/tklauser/numcpus v0.8.0 // indirect github.com/uptrace/opentelemetry-go-extra/otelsql v0.2.4 // indirect @@ -186,6 +205,6 @@ require ( golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect google.golang.org/appengine v1.6.8 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20231002182017-d307bd883b97 // indirect - gopkg.in/ini.v1 v1.62.0 // indirect + gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect ) diff --git a/go.sum b/go.sum index e19cc3aa2..3e15d5b07 100644 --- a/go.sum +++ b/go.sum @@ -77,6 +77,7 @@ cloud.google.com/go/storage v1.30.1 h1:uOdMxAs8HExqBlnLtnQyP0YkvbiDpdGShGKtx6U/o cloud.google.com/go/storage v1.30.1/go.mod h1:NfxhC0UJE1aXSx7CIIbCf7y9HKT7BiccwkR7+P7gN8E= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= gioui.org v0.0.0-20210308172011-57750fc8a0a6/go.mod h1:RSH6KIUZ0p2xy5zHDxgAM4zumjgTw83q2ge/PI+yyw8= +git.sr.ht/~sbinet/gg v0.3.1/go.mod h1:KGYtlADtqsqANL9ueOFkWymvzUvLMQllU5Ixo+8v3pc= github.com/AdaLogics/go-fuzz-headers v0.0.0-20210715213245-6c3934b029d8/go.mod h1:CzsSbkDixRphAF5hS6wbMKq0eI6ccJRb7/A0M6JBnwg= github.com/AlecAivazis/survey/v2 v2.3.5/go.mod h1:4AuI9b7RjAR+G7v9+C4YSlX/YL3K3cWNXgWXOhllqvI= github.com/Azure/azure-pipeline-go v0.2.3/go.mod h1:x841ezTBIMG6O3lAcl8ATHnsOPVl2bqk7S3ta6S6u4k= @@ -144,7 +145,10 @@ github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbt github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ= +github.com/ajstarks/deck v0.0.0-20200831202436-30c9fc6549a9/go.mod h1:JynElWSGnm/4RlzPXRlREEwqTHAN3T56Bv2ITsFT3gY= +github.com/ajstarks/deck/generate v0.0.0-20210309230005-c3f852c02e19/go.mod h1:T13YZdzov6OU0A1+RfKZiZN9ca6VeKdBdyDV+BY97Tk= github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= +github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b/go.mod h1:1KcenG0jGWcpt8ov532z81sp/kMMUG485J2InIOyADM= github.com/alecthomas/assert v0.0.0-20170929043011-405dbfeb8e38 h1:smF2tmSOzy2Mm+0dGI2AIUHY+w0BUc+4tn40djz7+6U= github.com/alecthomas/assert v0.0.0-20170929043011-405dbfeb8e38/go.mod h1:r7bzyVFMNntcxPZXK3/+KdruV1H5KSlyVY0gc+NgInI= github.com/alecthomas/chroma v0.8.2 h1:x3zkuE2lUk/RIekyAJ3XRqSCP4zwWDfcw/YJCuCAACg= @@ -161,6 +165,48 @@ github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRF github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/alexflint/go-filemutex v0.0.0-20171022225611-72bdc8eae2ae/go.mod h1:CgnQgUtFrFz9mxFNtED3jI5tLDjKlOM+oUF/sTk6ps0= github.com/alexflint/go-filemutex v1.1.0/go.mod h1:7P4iRhttt/nUvUOrYIhcpMzv2G6CY9UnI16Z+UJqRyk= +github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.4 h1:iC9YFYKDGEy3n/FtqJnOkZsene9olVspKmkX5A2YBEo= +github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.4/go.mod h1:sCavSAvdzOjul4cEqeVtvlSaSScfNsTQ+46HwlTL1hc= +github.com/alibabacloud-go/darabonba-openapi v0.1.16 h1:f6ZspWKTBurQzyLpZKMVxO51HAePY8aedicwuX3+E20= +github.com/alibabacloud-go/darabonba-openapi v0.1.16/go.mod h1:ZjyqRbbZOaUBSh7keeH8VQN/BzCPvxCQwMuJGDdbmXQ= +github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.8 h1:benoD0QHDrylMzEQVpX/6uKtrN8LohT66ZlKXVJh7pM= +github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.8/go.mod h1:CzQnh+94WDnJOnKZH5YRyouL+OOcdBnXY5VWAf0McgI= +github.com/alibabacloud-go/darabonba-string v1.0.0/go.mod h1:93cTfV3vuPhhEwGGpKKqhVW4jLe7tDpo3LUM0i0g6mA= +github.com/alibabacloud-go/debug v0.0.0-20190504072949-9472017b5c68/go.mod h1:6pb/Qy8c+lqua8cFpEy7g39NRRqOWc3rOwAy8m5Y2BY= +github.com/alibabacloud-go/debug v1.0.0/go.mod h1:8gfgZCCAC3+SCzjWtY053FrOcd4/qlH6IHTI4QyICOc= +github.com/alibabacloud-go/debug v1.0.1 h1:MsW9SmUtbb1Fnt3ieC6NNZi6aEwrXfDksD4QA6GSbPg= +github.com/alibabacloud-go/debug v1.0.1/go.mod h1:8gfgZCCAC3+SCzjWtY053FrOcd4/qlH6IHTI4QyICOc= +github.com/alibabacloud-go/endpoint-util v1.1.0 h1:r/4D3VSw888XGaeNpP994zDUaxdgTSHBbVfZlzf6b5Q= +github.com/alibabacloud-go/endpoint-util v1.1.0/go.mod h1:O5FuCALmCKs2Ff7JFJMudHs0I5EBgecXXxZRyswlEjE= +github.com/alibabacloud-go/maxcompute-20220104 v1.4.1 h1:CwtCWRdr+OT581McaNKfgmSOSY8ShXBPrppMoUzbttw= +github.com/alibabacloud-go/maxcompute-20220104 v1.4.1/go.mod h1:qr4Zu1mwzYoiD6anCUz2wv1/VsNXdLkCtPQkRFaQKxE= +github.com/alibabacloud-go/openapi-util v0.0.10/go.mod h1:sQuElr4ywwFRlCCberQwKRFhRzIyG4QTP/P4y1CJ6Ws= +github.com/alibabacloud-go/openapi-util v0.0.11/go.mod h1:sQuElr4ywwFRlCCberQwKRFhRzIyG4QTP/P4y1CJ6Ws= +github.com/alibabacloud-go/openapi-util v0.1.0 h1:0z75cIULkDrdEhkLWgi9tnLe+KhAFE/r5Pb3312/eAY= +github.com/alibabacloud-go/openapi-util v0.1.0/go.mod h1:sQuElr4ywwFRlCCberQwKRFhRzIyG4QTP/P4y1CJ6Ws= +github.com/alibabacloud-go/sts-20150401 v1.1.2 h1:Bs+5YxsiJf1Zdij1ziWUmvsm8VQM599JALOmom7T1T8= +github.com/alibabacloud-go/sts-20150401 v1.1.2/go.mod h1:JQImPX2JjCaARhUB51H3JUPSpbXCT1PFJkDJvgl+f5I= +github.com/alibabacloud-go/tea v1.1.0/go.mod h1:IkGyUSX4Ba1V+k4pCtJUc6jDpZLFph9QMy2VUPTwukg= +github.com/alibabacloud-go/tea v1.1.7/go.mod h1:/tmnEaQMyb4Ky1/5D+SE1BAsa5zj/KeGOFfwYm3N/p4= +github.com/alibabacloud-go/tea v1.1.8/go.mod h1:/tmnEaQMyb4Ky1/5D+SE1BAsa5zj/KeGOFfwYm3N/p4= +github.com/alibabacloud-go/tea v1.1.11/go.mod h1:/tmnEaQMyb4Ky1/5D+SE1BAsa5zj/KeGOFfwYm3N/p4= +github.com/alibabacloud-go/tea v1.1.17/go.mod h1:nXxjm6CIFkBhwW4FQkNrolwbfon8Svy6cujmKFUq98A= +github.com/alibabacloud-go/tea v1.2.1/go.mod h1:qbzof29bM/IFhLMtJPrgTGK3eauV5J2wSyEUo4OEmnA= +github.com/alibabacloud-go/tea v1.2.2 h1:aTsR6Rl3ANWPfqeQugPglfurloyBJY85eFy7Gc1+8oU= +github.com/alibabacloud-go/tea v1.2.2/go.mod h1:CF3vOzEMAG+bR4WOql8gc2G9H3EkH3ZLAQdpmpXMgwk= +github.com/alibabacloud-go/tea-utils v1.3.1/go.mod h1:EI/o33aBfj3hETm4RLiAxF/ThQdSngxrpF8rKUDJjPE= +github.com/alibabacloud-go/tea-utils v1.4.3 h1:8SzwmmRrOnQ09Hf5a9GyfJc0d7Sjv6fmsZoF4UDbFjo= +github.com/alibabacloud-go/tea-utils v1.4.3/go.mod h1:KNcT0oXlZZxOXINnZBs6YvgOd5aYp9U67G+E3R8fcQw= +github.com/alibabacloud-go/tea-utils/v2 v2.0.5 h1:EUakYEUAwr6L3wLT0vejIw2rc0IA1RSXDwLnIb3f2vU= +github.com/alibabacloud-go/tea-utils/v2 v2.0.5/go.mod h1:dL6vbUT35E4F4bFTHL845eUloqaerYBYPsdWR2/jhe4= +github.com/alibabacloud-go/tea-xml v1.1.3 h1:7LYnm+JbOq2B+T/B0fHC4Ies4/FofC4zHzYtqw7dgt0= +github.com/alibabacloud-go/tea-xml v1.1.3/go.mod h1:Rq08vgCcCAjHyRi/M7xlHKUykZCEtyBy9+DPF6GgEu8= +github.com/aliyun/aliyun-odps-go-sdk v0.3.15 h1:HkWki3g7G0xEAyxSAChqSDxLw8NCl7PFc8KxcECXReQ= +github.com/aliyun/aliyun-odps-go-sdk v0.3.15/go.mod h1:t/tgF/iN5aAs/gLL7sEI8/qdax4NuFCKEjO3OJbHZqI= +github.com/aliyun/credentials-go v1.1.2/go.mod h1:ozcZaMR5kLM7pwtCMEpVmQ242suV6qTJya2bDq4X1Tw= +github.com/aliyun/credentials-go v1.3.1/go.mod h1:8jKYhQuDawt8x2+fusqa1Y6mPxemTsBEN04dgcAcYz0= +github.com/aliyun/credentials-go v1.3.10 h1:45Xxrae/evfzQL9V10zL3xX31eqgLWEaIdCoPipOEQA= +github.com/aliyun/credentials-go v1.3.10/go.mod h1:Jm6d+xIgwJVLVWT561vy67ZRP4lPTQxMbEYRuT2Ti1U= github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY= github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= @@ -230,6 +276,7 @@ github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dR github.com/bool64/shared v0.1.5 h1:fp3eUhBsrSjNCQPcSdQqZxxh9bBwrYiZ+zOKFkM0/2E= github.com/bool64/shared v0.1.5/go.mod h1:081yz68YC9jeFB3+Bbmno2RFWvGKv1lPKkMP6MHJlPs= github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= +github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= github.com/briandowns/spinner v1.18.0 h1:SJs0maNOs4FqhBwiJ3Gr7Z1D39/rukIVGQvpNZVHVcM= github.com/briandowns/spinner v1.18.0/go.mod h1:QOuQk7x+EaDASo80FEXwlwiA+j/PPIcX3FScO+3/ZPQ= github.com/bshuster-repo/logrus-logstash-hook v0.4.1/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk= @@ -265,6 +312,8 @@ github.com/cilium/ebpf v0.2.0/go.mod h1:To2CFviqOWL/M0gIMsvSMlqe7em/l1ALkX1PyjrX github.com/cilium/ebpf v0.4.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= github.com/cilium/ebpf v0.6.2/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= github.com/cilium/ebpf v0.7.0/go.mod h1:/oI2+1shJiTGAMgl6/RgJr36Eo1jzrRcAWbcXO2usCA= +github.com/clbanning/mxj/v2 v2.5.5 h1:oT81vUeEiQQ/DcHbzSytRngP6Ky9O+L+0Bw0zSJag9E= +github.com/clbanning/mxj/v2 v2.5.5/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s= github.com/cli/safeexec v1.0.0 h1:0VngyaIyqACHdcMNWfo6+KdUYnqEr2Sg+bSP1pdF+dI= github.com/cli/safeexec v1.0.0/go.mod h1:Z/D4tTN8Vs5gXYHDCbaM1S/anmEDnJb1iW0+EJ5zx3Q= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= @@ -510,7 +559,10 @@ github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2H github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-fonts/dejavu v0.1.0/go.mod h1:4Wt4I4OU2Nq9asgDCteaAaWZOV24E+0/Pwo0gppep4g= github.com/go-fonts/latin-modern v0.2.0/go.mod h1:rQVLdDMK+mK1xscDwsqM5J8U2jrRa3T0ecnM9pNujks= +github.com/go-fonts/latin-modern v0.3.0/go.mod h1:ysEQXnuT/sCDOAONxC7ImeEDVINbltClhasMAqEtRK0= github.com/go-fonts/liberation v0.1.1/go.mod h1:K6qoJYypsmfVjWg8KOVDQhLc8UDgIK2HYqyqAO9z7GY= +github.com/go-fonts/liberation v0.2.0/go.mod h1:K6qoJYypsmfVjWg8KOVDQhLc8UDgIK2HYqyqAO9z7GY= +github.com/go-fonts/liberation v0.3.0/go.mod h1:jdJ+cqF+F4SUL2V+qxBth8fvBpBDS7yloUL5Fi8GTGY= github.com/go-fonts/stix v0.1.0/go.mod h1:w/c1f0ldAUlJmLBvlbkvVXLAD+tAMqobIIQpmnUIzUY= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -520,6 +572,8 @@ github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2 github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= github.com/go-latex/latex v0.0.0-20210118124228-b3d85cf34e07/go.mod h1:CO1AlKB2CSIqUrmQPqA0gdRIlnLEY0gK5JGjh37zN5U= +github.com/go-latex/latex v0.0.0-20210823091927-c0d11ff05a81/go.mod h1:SX0U8uGpxhq9o2S/CELCSUxEWWAuoCUcVCQWv7G2OCk= +github.com/go-latex/latex v0.0.0-20230307184459-12ec69307ad9/go.mod h1:gWuR/CrFDDeVRFQwHPvsv9soJVB/iqymhuZQuJ3a9OM= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= @@ -551,6 +605,8 @@ github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dp github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= +github.com/go-pdf/fpdf v0.5.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M= +github.com/go-pdf/fpdf v0.6.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M= github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= @@ -666,8 +722,8 @@ github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Z github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= github.com/google/flatbuffers v2.0.0+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= -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/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= @@ -743,8 +799,8 @@ github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2c github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA= github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= -github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= 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/gorilla/handlers v0.0.0-20150720190736-60c7bfde3e33/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= @@ -907,10 +963,10 @@ github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCV github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= -github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= @@ -1068,9 +1124,11 @@ github.com/moby/term v0.0.0-20210610120745-9d4ed1856297/go.mod h1:vgPCkQMyxTZ7ID github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 h1:dcztxKSvZ4Id8iPpHERQBbIJfabdt4wUm5qy3wOL2Zc= github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6/go.mod h1:E2VnQOmVuvZB6UYnnDB0qG5Nq/1tD9acaOpo6xmt0Kw= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= @@ -1164,10 +1222,11 @@ github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCko github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/phpdave11/gofpdf v1.4.2/go.mod h1:zpO6xFn9yxo3YLyMvW8HcKWVdbNqgIfOOp2dXMnm1mY= github.com/phpdave11/gofpdi v1.0.12/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI= +github.com/phpdave11/gofpdi v1.0.13/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pierrec/lz4/v4 v4.1.8/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= -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/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/pkg/browser v0.0.0-20210706143420-7d21f8c997e2/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI= github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -1235,6 +1294,7 @@ github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThC github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod h1:6lfFZQK844Gfx8o5WFuvpxWRwnSoipWe/p622j1v06w= +github.com/ruudk/golang-pdf417 v0.0.0-20201230142125-a7e3863a1245/go.mod h1:pQAZKsJ8yyVxGRWYNEm9oFB8ieLgKFnamEyDmSA0BRk= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/safchain/ethtool v0.0.0-20190326074333-42ed695e3de8/go.mod h1:Z0q5wiBQGYcxhMZ6gUqHn6pYNLypFAvaL3UvgZLR0U4= github.com/safchain/ethtool v0.0.0-20210803160452-9aa261dae9b1/go.mod h1:Z0q5wiBQGYcxhMZ6gUqHn6pYNLypFAvaL3UvgZLR0U4= @@ -1270,10 +1330,9 @@ github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrf github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/assertions v1.1.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo= github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= -github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/snowflakedb/gosnowflake v1.6.3/go.mod h1:6hLajn6yxuJ4xUHZegMekpq9rnQbGJ7TMwXjgTmA6lg= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= @@ -1327,6 +1386,7 @@ 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/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/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= @@ -1348,6 +1408,8 @@ github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4= github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= +github.com/tjfoc/gmsm v1.3.2 h1:7JVkAn5bvUJ7HtU08iW6UiD+UTmJTIToHCfeFzkcCxM= +github.com/tjfoc/gmsm v1.3.2/go.mod h1:HaUcFuY0auTiaHB9MHFGCPx5IaLhTUd2atbCFBQXn9w= github.com/tklauser/go-sysconf v0.3.14 h1:g5vzr9iPFFz24v2KZXs/pvpvh8/V9Fw6vQK5ZZb78yU= github.com/tklauser/go-sysconf v0.3.14/go.mod h1:1ym4lWMLUOhuBOPGtRcJm7tEGX4SCYNEEEtghGG/8uY= github.com/tklauser/numcpus v0.8.0 h1:Mx4Wwe/FjZLeQsK/6kt2EOepwwSl7SmJrK5bV/dXYgY= @@ -1399,6 +1461,7 @@ github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 h1:BHyfKlQyqbsFN5p3Ifn github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.30/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.3/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= @@ -1530,8 +1593,10 @@ golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191219195013-becbf705a915/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= @@ -1544,7 +1609,11 @@ golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220314234659-1baeb1ce4c0b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= golang.org/x/crypto v0.4.0/go.mod h1:3quD/ATkf6oY+rnes5c3ExXTbLc8mueNue5/DoinL80= +golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I= +golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= +golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -1561,8 +1630,9 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -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-20230321023759-10a507213a29/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= +golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1 h1:MGwJjxBy0HJshjDNfLsYO8xppfqWlA5ZT9OhtUUhTNw= +golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= @@ -1572,6 +1642,11 @@ golang.org/x/image v0.0.0-20200430140353-33d19683fad8/go.mod h1:FeLwcggjj3mMvU+o golang.org/x/image v0.0.0-20200618115811-c13761719519/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.0.0-20201208152932-35266b937fa6/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.0.0-20210216034530-4410531fe030/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20210607152325-775e3b0c77b9/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= +golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= +golang.org/x/image v0.0.0-20211028202545-6944b10bf410/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= +golang.org/x/image v0.5.0/go.mod h1:FVC7BI/5Ym8R25iw5OLsgshdUBbT1h5jZTpA+mvAdZ4= +golang.org/x/image v0.6.0/go.mod h1:MXLdDR43H7cDJq5GEGXEVeeNhPgi+YYEQ2pC1byI1x0= 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-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -1597,6 +1672,9 @@ golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.11.0 h1:bUO06HqtnRcc/7l71XBe4WcqTZ+3AH1J59zWDDwLKgU= golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1676,7 +1754,15 @@ golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220812174116-3211cb980234/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/net v0.0.0-20220919232410-f2f64ebce3c1/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ= +golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc= golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= golang.org/x/oauth2 v0.0.0-20180227000427-d7d64896b5ff/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -1721,6 +1807,7 @@ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220923202941-7f9b1623fab7/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ= golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sys v0.0.0-20180224232135-f6cff0780e54/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1781,6 +1868,7 @@ golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200413165638-669c56c373c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200509044756-6aff5f38e54f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1864,7 +1952,12 @@ golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220818161305-2296e01440c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg= golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= @@ -1873,7 +1966,14 @@ golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9sn golang.org/x/term v0.0.0-20210503060354-a79de5458b56/go.mod h1:tfny5GFUkzUvx4ps4ajbZsCe5lw1metzhBm9T3x7oIY= golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.9.0/go.mod h1:M6DEAAIenWoTxdKrOltXcmDY3rSplQUkrvaDU5FcQyo= +golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= +golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= golang.org/x/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q= golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1886,7 +1986,13 @@ golang.org/x/text v0.3.5/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.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= 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.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -1955,6 +2061,7 @@ golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjs golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200509030707-2212a7e161a5/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200616133436-c1934b75d054/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= @@ -1980,6 +2087,9 @@ golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= golang.org/x/tools v0.10.0 h1:tvDr/iQoUqNdohiYm0LmmKcBk+q86lb9EprIUFhHHGg= golang.org/x/tools v0.10.0/go.mod h1:UJwyiVBsOA2uwvK/e5OY3GTpDUJriEd+/YlqAwLPmyM= golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -1996,11 +2106,12 @@ golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNq gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0= gonum.org/v1/gonum v0.9.3/go.mod h1:TZumC3NeyVQskjXqmyWt4S3bINhy7B4eYwW69EbyX+0= -gonum.org/v1/gonum v0.11.0 h1:f1IJhK4Km5tBJmaiJXtk/PkL4cdVX6J+tGiM187uT5E= -gonum.org/v1/gonum v0.11.0/go.mod h1:fSG4YDCxxUZQJ7rKsQrj0gMOg00Il0Z96/qMA4bVQhA= +gonum.org/v1/gonum v0.13.0 h1:a0T3bh+7fhRyqeNbiC3qVHYmkiQgit3wnNan/2c0HMM= +gonum.org/v1/gonum v0.13.0/go.mod h1:/WPYRckkfWrhWefxyYTfrTtQR0KH4iyHNuzxqXAKyAU= gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc= gonum.org/v1/plot v0.9.0/go.mod h1:3Pcqqmp6RHvJI72kgb8fThyUnav364FOsdDo2aGW5lY= +gonum.org/v1/plot v0.10.1/go.mod h1:VZW5OlhkL1mysU9vaqNHnsy86inf6Ot+jB3r+BczCEo= google.golang.org/api v0.0.0-20160322025152-9bf6e6e569ff/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= @@ -2213,6 +2324,7 @@ google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= @@ -2231,8 +2343,10 @@ gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKW gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU= +gopkg.in/ini.v1 v1.56.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= 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.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= @@ -2290,6 +2404,7 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las= k8s.io/api v0.20.1/go.mod h1:KqwcCVogGxQY3nBlRpwt+wpAMF/KjaCc7RpywacvqUo= k8s.io/api v0.20.4/go.mod h1:++lNL1AJMkDymriNniQsWRkMDzRaX2Y/POTUi8yvqYQ= k8s.io/api v0.20.6/go.mod h1:X9e8Qag6JV/bL5G6bU8sdVRltWKmdHsFUGS3eVndqE8= diff --git a/internal/server/services.go b/internal/server/services.go index 04734604d..dcb6a2c03 100644 --- a/internal/server/services.go +++ b/internal/server/services.go @@ -29,6 +29,7 @@ import ( "github.com/goto/guardian/plugins/providers/gcs" "github.com/goto/guardian/plugins/providers/gitlab" "github.com/goto/guardian/plugins/providers/grafana" + "github.com/goto/guardian/plugins/providers/maxcompute" "github.com/goto/guardian/plugins/providers/metabase" "github.com/goto/guardian/plugins/providers/noop" "github.com/goto/guardian/plugins/providers/shield" @@ -123,6 +124,7 @@ func InitServices(deps ServiceDeps) (*Services, error) { shield.NewProvider(domain.ProviderTypeShield, deps.Logger), gitlab.NewProvider(domain.ProviderTypeGitlab, deps.Crypto, deps.Logger), gate.NewProvider(domain.ProviderTypeGate, deps.Crypto), + maxcompute.New(domain.ProviderTypeMaxCompute, deps.Crypto, deps.Logger), } iamManager := identities.NewManager(deps.Crypto, deps.Validator) diff --git a/internal/store/postgres/grant_repository.go b/internal/store/postgres/grant_repository.go index c9038e1b1..ce382eb0f 100644 --- a/internal/store/postgres/grant_repository.go +++ b/internal/store/postgres/grant_repository.go @@ -218,6 +218,27 @@ func (r *GrantRepository) BulkUpsert(ctx context.Context, grants []*domain.Grant }) } +func (r *GrantRepository) Create(ctx context.Context, g *domain.Grant) error { + m := new(model.Grant) + if err := m.FromDomain(*g); err != nil { + return err + } + + return r.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error { + if err := tx.Create(m).Error; err != nil { + return err + } + + newGrant, err := m.ToDomain() + if err != nil { + return err + } + *g = *newGrant + + return nil + }) +} + func upsertResources(tx *gorm.DB, models []*model.Grant) error { uniqueResourcesMap := map[string]*model.Resource{} diff --git a/pkg/stsClient/stsClient.go b/pkg/stsClient/stsClient.go new file mode 100644 index 000000000..75749ba6b --- /dev/null +++ b/pkg/stsClient/stsClient.go @@ -0,0 +1,95 @@ +package sts + +import ( + "fmt" + "time" + + openapi "github.com/alibabacloud-go/darabonba-openapi/client" + openapiV2 "github.com/alibabacloud-go/darabonba-openapi/v2/client" + + "github.com/alibabacloud-go/sts-20150401/client" +) + +var assumeRoleDurationHours int64 = 1 + +type StsClient struct { + client *client.Client + expiryTimeStamp time.Time +} + +type Sts struct { + clients map[string]*StsClient +} + +func NewSTS() *Sts { + return &Sts{ + clients: make(map[string]*StsClient), + } +} + +func (s *Sts) IsSTSTokenValid(clientIdentifier string) bool { + client := s.clients[clientIdentifier] + if client == nil { + return false + } + + return time.Now().Before(client.expiryTimeStamp) +} + +func NewSTSClient(userAccessKeyID, userSecretAccessKey, regionID string) (*client.Client, error) { + stsEndpoint := fmt.Sprintf("sts.%s.aliyuncs.com", regionID) + + config := &openapi.Config{ + AccessKeyId: &userAccessKeyID, + AccessKeySecret: &userSecretAccessKey, + Endpoint: &stsEndpoint, + } + + stsClient, err := client.NewClient(config) + if err != nil { + return nil, fmt.Errorf("failed to initialize STS client: %w", err) + } + + return stsClient, nil +} + +func (s *Sts) GetSTSClient(clientIdentifier, userAccessKeyID, userSecret, regionID string) (*client.Client, error) { + if c, ok := s.clients[clientIdentifier]; ok { + return c.client, nil + } + + stsClient, err := NewSTSClient(userAccessKeyID, userSecret, regionID) + if err != nil { + return nil, err + } + + s.clients[clientIdentifier] = &StsClient{ + client: stsClient, + expiryTimeStamp: time.Now().Add(time.Duration(assumeRoleDurationHours) * time.Hour), + } + + return stsClient, nil +} + +func AssumeRole(stsClient *client.Client, roleArn, roleSessionName, regionID string) (*openapiV2.Config, error) { + durationSeconds := assumeRoleDurationHours * int64(time.Hour.Seconds()) + request := client.AssumeRoleRequest{ + RoleArn: &roleArn, + RoleSessionName: &roleSessionName, + DurationSeconds: &durationSeconds, + } + + res, err := stsClient.AssumeRole(&request) + if err != nil { + return nil, fmt.Errorf("failed to assume role: %w", err) + } + + config := &openapiV2.Config{ + AccessKeyId: res.Body.Credentials.AccessKeyId, + AccessKeySecret: res.Body.Credentials.AccessKeySecret, + SecurityToken: res.Body.Credentials.SecurityToken, + RegionId: ®ionID, + } + + return config, nil +} diff --git a/plugins/providers/maxcompute/config.go b/plugins/providers/maxcompute/config.go new file mode 100644 index 000000000..2a8e6d87d --- /dev/null +++ b/plugins/providers/maxcompute/config.go @@ -0,0 +1,95 @@ +package maxcompute + +import ( + "fmt" + "slices" + "strings" + + "github.com/goto/guardian/domain" + "github.com/goto/guardian/utils" + "github.com/mitchellh/mapstructure" +) + +const ( + accountTypeRAMUser = "ram_user" + accountTypeRAMRole = "ram_role" + + resourceTypeProject = "project" + resourceTypeTable = "table" + + parameterRAMRoleKey = "ram_role" + + projectPermissionMember = "member" +) + +var ( + validResourceTypes = []string{resourceTypeProject, resourceTypeTable} + validTableActions = []string{"describe", "select", "alter", "update", "drop", "showhistory", "all"} +) + +type config struct { + *domain.ProviderConfig +} + +func (c *config) getCredentials() (*credentials, error) { + if creds, ok := c.Credentials.(credentials); ok { // parsed + return &creds, nil + } else if mapCreds, ok := c.Credentials.(map[string]interface{}); ok { // not parsed + var creds credentials + if err := mapstructure.Decode(mapCreds, &creds); err != nil { + return nil, fmt.Errorf("unable to decode credentials: %w", err) + } + return &creds, nil + } + + return nil, fmt.Errorf("invalid credentials type: %T", c.Credentials) +} + +func (c *config) validate() error { + // validate credentials + if c.Credentials == nil { + return fmt.Errorf("credentials is required") + } + creds, err := c.getCredentials() + if err != nil { + return err + } + if err := creds.validate(); err != nil { + return fmt.Errorf("invalid credentials: %w", err) + } + + // validate resource config + for _, rc := range c.Resources { + if !utils.ContainsString(validResourceTypes, rc.Type) { + return fmt.Errorf("invalid resource type: %q", rc.Type) + } + + for _, role := range rc.Roles { + if len(role.Permissions) == 0 { + return fmt.Errorf("permissions are missing for role: %q", role.Name) + } + for _, permission := range role.Permissions { + permissionStr, ok := permission.(string) + if !ok { + return fmt.Errorf("unexpected permission type: %T, expected: string", permission) + } + + switch rc.Type { + case resourceTypeTable: + if !utils.ContainsString(validTableActions, strings.ToLower(permissionStr)) { + return fmt.Errorf("invalid permission %q for table resource", permissionStr) + } + } + } + } + } + + // validate parameters + for _, param := range c.Parameters { + if !slices.Contains([]string{parameterRAMRoleKey}, param.Key) { + return fmt.Errorf("parameter key %q is not supported", param.Key) + } + } + + return nil +} diff --git a/plugins/providers/maxcompute/credentials.go b/plugins/providers/maxcompute/credentials.go new file mode 100644 index 000000000..28ab1bbd7 --- /dev/null +++ b/plugins/providers/maxcompute/credentials.go @@ -0,0 +1,47 @@ +package maxcompute + +import ( + "errors" + + "github.com/goto/guardian/domain" +) + +type credentials struct { + AccessKeyID string `mapstructure:"access_key_id" json:"access_key_id"` + AccessKeySecret string `mapstructure:"access_key_secret" json:"access_key_secret"` + RAMRole string `mapstructure:"ram_role" json:"ram_role"` + RegionID string `mapstructure:"region_id" json:"region_id"` +} + +func (c credentials) validate() error { + if c.AccessKeyID == "" { + return errors.New("access_key_id is required") + } + if c.AccessKeySecret == "" { + return errors.New("access_key_secret is required") + } + if c.RegionID == "" { + return errors.New("region_id is required") + } + return nil +} + +func (c *credentials) encrypt(encryptor domain.Encryptor) error { + encryptedAccessKeySecret, err := encryptor.Encrypt(c.AccessKeySecret) + if err != nil { + return err + } + + c.AccessKeySecret = encryptedAccessKeySecret + return nil +} + +func (c *credentials) decrypt(decryptor domain.Decryptor) error { + decryptedAccessKeySecret, err := decryptor.Decrypt(c.AccessKeySecret) + if err != nil { + return err + } + + c.AccessKeySecret = decryptedAccessKeySecret + return nil +} diff --git a/plugins/providers/maxcompute/provider.go b/plugins/providers/maxcompute/provider.go new file mode 100644 index 000000000..27c6c7095 --- /dev/null +++ b/plugins/providers/maxcompute/provider.go @@ -0,0 +1,521 @@ +package maxcompute + +import ( + "errors" + "fmt" + "net/http" + "slices" + "strings" + "sync" + + maxcompute "github.com/alibabacloud-go/maxcompute-20220104/client" + "github.com/aliyun/aliyun-odps-go-sdk/odps" + "github.com/aliyun/aliyun-odps-go-sdk/odps/account" + "github.com/aliyun/aliyun-odps-go-sdk/odps/restclient" + "github.com/aliyun/aliyun-odps-go-sdk/odps/security" + pv "github.com/goto/guardian/core/provider" + "github.com/goto/guardian/domain" + "github.com/goto/guardian/pkg/log" + sts "github.com/goto/guardian/pkg/stsClient" + "github.com/goto/guardian/utils" + "golang.org/x/net/context" + + openapiV2 "github.com/alibabacloud-go/darabonba-openapi/v2/client" +) + +//go:generate mockery --name=encryptor --exported --with-expecter +type encryptor interface { + domain.Crypto +} + +type ODPSClient struct { + client *odps.Odps + stsClientExist bool +} + +type RestClient struct { + client *maxcompute.Client + stsClientExist bool +} + +type provider struct { + pv.UnimplementedClient + pv.PermissionManager + typeName string + encryptor encryptor + restClients map[string]RestClient + odpsClients map[string]ODPSClient + sts *sts.Sts + logger log.Logger + mu sync.Mutex +} + +func New( + typeName string, + encryptor encryptor, + logger log.Logger, +) *provider { + return &provider{ + typeName: typeName, + encryptor: encryptor, + restClients: make(map[string]RestClient), + odpsClients: make(map[string]ODPSClient), + sts: sts.NewSTS(), + + logger: logger, + } +} + +func (p *provider) GetType() string { + return p.typeName +} + +func (p *provider) GetAccountTypes() []string { + return []string{accountTypeRAMUser, accountTypeRAMRole} +} + +func (p *provider) GetRoles(pc *domain.ProviderConfig, resourceType string) ([]*domain.Role, error) { + return pv.GetRoles(pc, resourceType) +} + +func (p *provider) CreateConfig(pc *domain.ProviderConfig) error { + cfg := &config{pc} + if err := cfg.validate(); err != nil { + return fmt.Errorf("invalid maxcompute config: %w", err) + } + + // encrypt sensitive config + creds, err := cfg.getCredentials() + if err != nil { + return err + } + if err := creds.encrypt(p.encryptor); err != nil { + return fmt.Errorf("failed to encrypt credentials: %w", err) + } + pc.Credentials = creds + + return nil +} + +func (p *provider) GetResources(ctx context.Context, pc *domain.ProviderConfig) ([]*domain.Resource, error) { + client, err := p.getRestClient(pc) + if err != nil { + return nil, fmt.Errorf("failed to initialize maxcompute rest client: %w", err) + } + + resources := make([]*domain.Resource, 0) + availableResourceTypes := pc.GetResourceTypes() + + var marker *string + for { + res, err := client.ListProjects(&maxcompute.ListProjectsRequest{ + Marker: marker, + }) + if err != nil { + return nil, fmt.Errorf("failed to list projects: %w", err) + } + + for _, project := range res.Body.Data.Projects { + accountID := strings.TrimPrefix(*project.Owner, "ALIYUN$") + if slices.Contains(availableResourceTypes, resourceTypeProject) { + resources = append(resources, &domain.Resource{ + ProviderType: pc.Type, + ProviderURN: pc.URN, + Type: resourceTypeProject, + URN: *project.Name, + Name: *project.Name, + GlobalURN: utils.GetGlobalURN("maxcompute", accountID, resourceTypeProject, *project.Name), + }) + } + + if slices.Contains(availableResourceTypes, resourceTypeTable) { + tableRes, err := client.ListTables(project.Name, &maxcompute.ListTablesRequest{}) + if err != nil { + return nil, fmt.Errorf("failed to list tables for project %s: %w", *project.Name, err) + } + + for _, table := range tableRes.Body.Data.Tables { + var urn string + if table.Schema == nil { + urn = fmt.Sprintf("%s.%s", *project.Name, *table.Name) + } else { + urn = fmt.Sprintf("%s.%s.%s", *project.Name, *table.Schema, *table.Name) + } + fmt.Printf("table: %v\n", urn) + resources = append(resources, &domain.Resource{ + ProviderType: pc.Type, + ProviderURN: pc.URN, + Type: resourceTypeTable, + URN: urn, + Name: *table.Name, + GlobalURN: utils.GetGlobalURN("maxcompute", accountID, resourceTypeTable, urn), + }) + } + } + } + + if res.Body.Data.NextToken == nil { + break + } + marker = res.Body.Data.NextToken + } + + return resources, nil +} + +func (p *provider) GrantAccess(ctx context.Context, pc *domain.ProviderConfig, g domain.Grant) error { + var ramRole string + if slices.Contains(pc.GetParameterKeys(), parameterRAMRoleKey) { + r, _, err := getParametersFromGrant[string](g, parameterRAMRoleKey) + if err != nil { + return fmt.Errorf("failed to get %q parameter value from grant: %w", parameterRAMRoleKey, err) + } + ramRole = r + } + client, err := p.getOdpsClient(pc, ramRole) + if err != nil { + return err + } + + switch g.Resource.Type { + case resourceTypeProject: + project := g.Resource.URN + securityManager := client.Project(project).SecurityManager() + + addAsProjectMember := false + var permissions []string + for _, p := range g.Permissions { + if p == projectPermissionMember { + addAsProjectMember = true + continue + } + permissions = append(permissions, p) + } + + if addAsProjectMember { + query := fmt.Sprintf("ADD USER %s", g.AccountID) + job, err := execGrantQuery(securityManager, query) + if err != nil { + return fmt.Errorf("failed to add %q as member in %q: %v", g.AccountID, project, err) + } + if job != nil { + if _, err := job.WaitForSuccess(); err != nil { + return fmt.Errorf("failed to add %q as member in %q: %v", g.AccountID, project, err) + } + } + } + + if len(permissions) > 0 { + mcRoles := strings.Join(permissions, ", ") + query := fmt.Sprintf("GRANT %s TO %s", mcRoles, g.AccountID) + job, err := execGrantQuery(securityManager, query) + if err != nil { + return fmt.Errorf("failed to grant %q to %q for %q: %v", mcRoles, project, g.AccountID, err) + } + if job != nil { + if _, err := job.WaitForSuccess(); err != nil { + return fmt.Errorf("failed to grant %q to %q for %q: %v", mcRoles, project, g.AccountID, err) + } + } + } + case resourceTypeTable: + project := strings.Split(g.Resource.URN, ".")[0] + securityManager := client.Project(project).SecurityManager() + + actions := strings.Join(g.Permissions, ", ") + query := fmt.Sprintf("GRANT %s ON TABLE %s TO USER %s", actions, g.Resource.Name, g.AccountID) + job, err := securityManager.Run(query, true, "") + if err != nil { + return fmt.Errorf("failed to grant %q to %q for %q: %v", actions, g.Resource.URN, g.AccountID, err) + } + + if _, err := job.WaitForSuccess(); err != nil { + return fmt.Errorf("failed to grant %q to %q for %q: %v", actions, g.Resource.URN, g.AccountID, err) + } + default: + return fmt.Errorf("unsupported resource type: %s", g.Resource.Type) + } + + return nil +} + +func (p *provider) RevokeAccess(ctx context.Context, pc *domain.ProviderConfig, g domain.Grant) error { + var ramRole string + if slices.Contains(pc.GetParameterKeys(), parameterRAMRoleKey) { + r, _, err := getParametersFromGrant[string](g, parameterRAMRoleKey) + if err != nil { + return fmt.Errorf("failed to get %q parameter value from grant: %w", parameterRAMRoleKey, err) + } + ramRole = r + } + client, err := p.getOdpsClient(pc, ramRole) + if err != nil { + return err + } + + switch g.Resource.Type { + case resourceTypeProject: + project := g.Resource.URN + securityManager := client.Project(project).SecurityManager() + + revokeFromProjectMember := false + var permissions []string + for _, p := range g.Permissions { + if p == projectPermissionMember { + revokeFromProjectMember = true + continue + } + permissions = append(permissions, p) + } + + if revokeFromProjectMember { + query := fmt.Sprintf("REMOVE USER %s", g.AccountID) + job, err := securityManager.Run(query, true, "") + if err != nil { + return fmt.Errorf("failed to remove %q as member in %q: %v", g.AccountID, project, err) + } + + if _, err := job.WaitForSuccess(); err != nil { + return fmt.Errorf("failed to remove %q as member in %q: %v", g.AccountID, project, err) + } + } + + if len(permissions) > 0 { + mcRoles := strings.Join(permissions, ", ") + query := fmt.Sprintf("REVOKE %s FROM %s", mcRoles, g.AccountID) + job, err := securityManager.Run(query, true, "") + if err != nil { + return fmt.Errorf("failed to revoke %q from %q for %q: %v", mcRoles, project, g.AccountID, err) + } + + if _, err := job.WaitForSuccess(); err != nil { + return fmt.Errorf("failed to revoke %q from %q for %q: %v", mcRoles, project, g.AccountID, err) + } + } + case resourceTypeTable: + project := strings.Split(g.Resource.URN, ".")[0] + securityManager := client.Project(project).SecurityManager() + + actions := strings.Join(g.Permissions, ", ") + query := fmt.Sprintf("REVOKE %s ON TABLE %s FROM USER %s", actions, g.Resource.Name, g.AccountID) + job, err := securityManager.Run(query, true, "") + if err != nil { + return fmt.Errorf("failed to revoke %q from %q for %q: %v", actions, g.Resource.URN, g.AccountID, err) + } + + if _, err := job.WaitForSuccess(); err != nil { + return fmt.Errorf("failed to revoke %q from %q for %q: %v", actions, g.Resource.URN, g.AccountID, err) + } + default: + return fmt.Errorf("unsupported resource type: %s", g.Resource.Type) + } + + return nil +} + +func (p *provider) GetDependencyGrants(ctx context.Context, pd domain.Provider, g domain.Grant) ([]*domain.Grant, error) { + if g.Resource.ProviderType != "maxcompute" { + return nil, fmt.Errorf("unsupported provider type: %q", g.Resource.ProviderType) + } + + var projectName string + switch g.Resource.Type { + case resourceTypeProject: + if !slices.Contains(g.Permissions, projectPermissionMember) { + projectName = g.Resource.URN + } + case resourceTypeTable: + projectName = strings.Split(g.Resource.URN, ".")[0] + default: + return nil, fmt.Errorf("invalid resource type: %q", g.Resource.Type) + } + + if projectName == "" { + return nil, nil + } + + projectMember := &domain.Grant{ + AccountID: g.AccountID, + AccountType: g.AccountType, + Role: projectPermissionMember, + Permissions: []string{projectPermissionMember}, + IsPermanent: true, + Resource: &domain.Resource{ + ProviderType: g.Resource.ProviderType, + ProviderURN: g.Resource.ProviderURN, + Type: resourceTypeProject, + URN: projectName, + }, + } + + return []*domain.Grant{projectMember}, nil +} + +func (p *provider) getCreds(pc *domain.ProviderConfig) (*credentials, error) { + cfg := &config{pc} + creds, err := cfg.getCredentials() + if err != nil { + return nil, err + } + if err := creds.decrypt(p.encryptor); err != nil { + return nil, fmt.Errorf("failed to decrypt credentials: %w", err) + } + return creds, nil +} + +func (p *provider) getRestClient(pc *domain.ProviderConfig) (*maxcompute.Client, error) { + creds, err := p.getCreds(pc) + if err != nil { + return nil, err + } + + ramRole, stsClientID := p.getRamRoleAndStsClientID("rest", creds, "") + if restClient, ok := p.getCachedRestClient(ramRole, stsClientID, pc.URN); ok { + return restClient, nil + } + + var clientConfig *openapiV2.Config + if creds.RAMRole != "" { + stsClient, err := p.sts.GetSTSClient(stsClientID, creds.AccessKeyID, creds.AccessKeySecret, creds.RegionID) + if err != nil { + return nil, err + } + + clientConfig, err = sts.AssumeRole(stsClient, creds.RAMRole, pc.URN, creds.RegionID) + if err != nil { + return nil, err + } + } else { + endpoint := fmt.Sprintf("http://service.%s.maxcompute.aliyun.com/api", creds.RegionID) + clientConfig = &openapiV2.Config{ + AccessKeyId: &creds.AccessKeyID, + AccessKeySecret: &creds.AccessKeySecret, + Endpoint: &endpoint, + } + } + + restClient, err := maxcompute.NewClient(clientConfig) + if err != nil { + return nil, err + } + + p.mu.Lock() + if creds.RAMRole != "" { + p.restClients[creds.RAMRole] = RestClient{client: restClient, stsClientExist: true} + } else { + p.restClients[pc.URN] = RestClient{client: restClient} + } + p.mu.Unlock() + return restClient, nil +} + +func (p *provider) getOdpsClient(pc *domain.ProviderConfig, ramRoleFromAppeal string) (*odps.Odps, error) { + creds, err := p.getCreds(pc) + if err != nil { + return nil, err + } + + // getting client from memory cache + ramRole, stsClientID := p.getRamRoleAndStsClientID("odps", creds, ramRoleFromAppeal) + if odpsClient, ok := p.getCachedOdpsClient(ramRole, stsClientID, pc.URN); ok { + return odpsClient, nil + } + + // initialize new client + var acc account.Account + if ramRole != "" { + stsClient, err := p.sts.GetSTSClient(stsClientID, creds.AccessKeyID, creds.AccessKeySecret, creds.RegionID) + if err != nil { + return nil, err + } + + clientConfig, err := sts.AssumeRole(stsClient, ramRole, pc.URN, creds.RegionID) + if err != nil { + return nil, err + } + acc = account.NewStsAccount(*clientConfig.AccessKeyId, *clientConfig.AccessKeySecret, *clientConfig.SecurityToken) + } else { + acc = account.NewAliyunAccount(creds.AccessKeyID, creds.AccessKeySecret) + } + endpoint := fmt.Sprintf("http://service.%s.maxcompute.aliyun.com/api", creds.RegionID) + client := odps.NewOdps(acc, endpoint) + + p.mu.Lock() + if ramRoleFromAppeal != "" { + p.odpsClients[ramRoleFromAppeal] = ODPSClient{client: client, stsClientExist: true} + } else { + p.odpsClients[pc.URN] = ODPSClient{client: client} + } + p.mu.Unlock() + + return client, nil +} + +func (p *provider) getRamRoleAndStsClientID(clientType string, creds *credentials, ramRoleFromAppeal string) (string, string) { + var ramRole string + switch { + case ramRoleFromAppeal != "": + ramRole = ramRoleFromAppeal + case creds.RAMRole != "": + ramRole = creds.RAMRole + } + stsClientID := clientType + "-" + ramRole + return ramRole, stsClientID +} + +func (p *provider) getCachedOdpsClient(ramRole, stsClientID, urn string) (*odps.Odps, bool) { + if c, ok := p.odpsClients[ramRole]; ok { + if c.stsClientExist && p.sts.IsSTSTokenValid(stsClientID) { + return c.client, true + } + return c.client, true + } + + if c, ok := p.odpsClients[urn]; ok { + return c.client, true + } + + return nil, false +} + +func (p *provider) getCachedRestClient(ramRole, stsClientID, urn string) (*maxcompute.Client, bool) { + c, ok := p.restClients[ramRole] + if ok && c.stsClientExist && p.sts.IsSTSTokenValid(stsClientID) { + return c.client, true + } + + if c, ok := p.restClients[urn]; ok { + return c.client, true + } + + return nil, false +} + +func getParametersFromGrant[T any](g domain.Grant, key string) (T, bool, error) { + var value T + if g.Appeal == nil { + return value, false, fmt.Errorf("appeal is missing in grant") + } + appealParams, _ := g.Appeal.Details[domain.ReservedDetailsKeyProviderParameters].(map[string]any) + if appealParams == nil { + return value, false, nil + } + + value, ok := appealParams[key].(T) + return value, ok, nil +} + +func execGrantQuery(sm security.Manager, query string) (*security.AuthQueryInstance, error) { + instance, err := sm.Run(query, true, "") + if err != nil { + var restErr restclient.HttpError + if errors.As(err, &restErr) { + if restErr.StatusCode == http.StatusConflict && restErr.ErrorMessage.ErrorCode == "ObjectAlreadyExists" { + return nil, nil + } + } + return nil, err + } + + return instance, nil +}