diff --git a/app/api/controller/githook/post_receive.go b/app/api/controller/githook/post_receive.go index 0ddda7790..f7d8e0a2a 100644 --- a/app/api/controller/githook/post_receive.go +++ b/app/api/controller/githook/post_receive.go @@ -62,8 +62,10 @@ func (c *Controller) PostReceive( // as the branch could be different than the configured default value. c.handleEmptyRepoPush(ctx, repo, in.PostReceiveInput, &out) - // report ref events (best effort) - c.reportReferenceEvents(ctx, rgit, repo, in.PrincipalID, in.PostReceiveInput) + // report ref events if repo is in an active state (best effort) + if repo.State == enum.RepoStateActive { + c.reportReferenceEvents(ctx, rgit, repo, in.PrincipalID, in.PostReceiveInput) + } // handle branch updates related to PRs - best effort c.handlePRMessaging(ctx, repo, in.PostReceiveInput, &out) diff --git a/app/api/controller/githook/pre_receive.go b/app/api/controller/githook/pre_receive.go index 35b3bf433..776e21cd8 100644 --- a/app/api/controller/githook/pre_receive.go +++ b/app/api/controller/githook/pre_receive.go @@ -67,13 +67,13 @@ func (c *Controller) PreReceive( } // For external calls (git pushes) block modification of pullreq references. - if !in.Internal && c.blockPullReqRefUpdate(refUpdates) { + if !in.Internal && c.blockPullReqRefUpdate(refUpdates, repo.State) { output.Error = ptr.String(usererror.ErrPullReqRefsCantBeModified.Error()) return output, nil } // For internal calls - through the application interface (API) - no need to verify protection rules. - if !in.Internal { + if !in.Internal && repo.State == enum.RepoStateActive { // TODO: use store.PrincipalInfoCache once we abstracted principals. principal, err := c.principalStore.Find(ctx, in.PrincipalID) if err != nil { @@ -109,7 +109,11 @@ func (c *Controller) PreReceive( return output, nil } -func (c *Controller) blockPullReqRefUpdate(refUpdates changedRefs) bool { +func (c *Controller) blockPullReqRefUpdate(refUpdates changedRefs, state enum.RepoState) bool { + if state == enum.RepoStateMigrateGitPush { + return false + } + fn := func(ref string) bool { return strings.HasPrefix(ref, gitReferenceNamePullReq) } diff --git a/app/api/controller/migrate/controller.go b/app/api/controller/migrate/controller.go index f1c30a381..6449c853d 100644 --- a/app/api/controller/migrate/controller.go +++ b/app/api/controller/migrate/controller.go @@ -15,21 +15,88 @@ package migrate import ( + "context" + "fmt" + + apiauth "github.com/harness/gitness/app/api/auth" + "github.com/harness/gitness/app/api/controller/limiter" + "github.com/harness/gitness/app/api/usererror" + "github.com/harness/gitness/app/auth" "github.com/harness/gitness/app/auth/authz" + "github.com/harness/gitness/app/services/migrate" + "github.com/harness/gitness/app/services/publicaccess" "github.com/harness/gitness/app/store" + "github.com/harness/gitness/app/url" + "github.com/harness/gitness/audit" + "github.com/harness/gitness/git" + "github.com/harness/gitness/store/database/dbtx" + "github.com/harness/gitness/types" + "github.com/harness/gitness/types/check" + "github.com/harness/gitness/types/enum" ) type Controller struct { - authorizer authz.Authorizer - principalStore store.PrincipalStore + authorizer authz.Authorizer + publicAccess publicaccess.Service + git git.Interface + urlProvider url.Provider + pullreqImporter *migrate.PullReq + ruleImporter *migrate.Rule + webhookImporter *migrate.Webhook + resourceLimiter limiter.ResourceLimiter + auditService audit.Service + identifierCheck check.RepoIdentifier + tx dbtx.Transactor + spaceStore store.SpaceStore + repoStore store.RepoStore } func NewController( authorizer authz.Authorizer, - principalStore store.PrincipalStore, + publicAccess publicaccess.Service, + git git.Interface, + urlProvider url.Provider, + pullreqImporter *migrate.PullReq, + ruleImporter *migrate.Rule, + webhookImporter *migrate.Webhook, + resourceLimiter limiter.ResourceLimiter, + auditService audit.Service, + identifierCheck check.RepoIdentifier, + tx dbtx.Transactor, + spaceStore store.SpaceStore, + repoStore store.RepoStore, ) *Controller { return &Controller{ - authorizer: authorizer, - principalStore: principalStore, + authorizer: authorizer, + publicAccess: publicAccess, + git: git, + urlProvider: urlProvider, + pullreqImporter: pullreqImporter, + ruleImporter: ruleImporter, + webhookImporter: webhookImporter, + resourceLimiter: resourceLimiter, + auditService: auditService, + identifierCheck: identifierCheck, + tx: tx, + spaceStore: spaceStore, + repoStore: repoStore, } } + +func (c *Controller) getRepoCheckAccess(ctx context.Context, + session *auth.Session, repoRef string, reqPermission enum.Permission) (*types.Repository, error) { + if repoRef == "" { + return nil, usererror.BadRequest("A valid repository reference must be provided.") + } + + repo, err := c.repoStore.FindByRef(ctx, repoRef) + if err != nil { + return nil, fmt.Errorf("failed to find repo: %w", err) + } + + if err = apiauth.CheckRepo(ctx, c.authorizer, session, repo, reqPermission); err != nil { + return nil, fmt.Errorf("failed to verify authorization: %w", err) + } + + return repo, nil +} diff --git a/app/api/controller/migrate/create_repo.go b/app/api/controller/migrate/create_repo.go new file mode 100644 index 000000000..1cfd88484 --- /dev/null +++ b/app/api/controller/migrate/create_repo.go @@ -0,0 +1,206 @@ +// Copyright 2023 Harness, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package migrate + +import ( + "context" + "database/sql" + "fmt" + "time" + + apiauth "github.com/harness/gitness/app/api/auth" + "github.com/harness/gitness/app/api/controller/limiter" + repoCtrl "github.com/harness/gitness/app/api/controller/repo" + "github.com/harness/gitness/app/auth" + "github.com/harness/gitness/app/bootstrap" + "github.com/harness/gitness/app/githook" + "github.com/harness/gitness/app/paths" + "github.com/harness/gitness/audit" + "github.com/harness/gitness/git" + "github.com/harness/gitness/types" + "github.com/harness/gitness/types/enum" + + "github.com/rs/zerolog/log" +) + +type CreateRepoInput struct { + ParentRef string `json:"parent_ref"` + Identifier string `json:"identifier"` + DefaultBranch string `json:"default_branch"` + IsPublic bool `json:"is_public"` +} + +func (c *Controller) CreateRepo( + ctx context.Context, + session *auth.Session, + in *CreateRepoInput, +) (*repoCtrl.RepositoryOutput, error) { + if err := c.sanitizeCreateRepoInput(in); err != nil { + return nil, fmt.Errorf("failed to sanitize input: %w", err) + } + + parentSpace, err := c.spaceCheckAuth(ctx, session, in.ParentRef) + if err != nil { + return nil, fmt.Errorf("failed to check auth in parent '%s': %w", in.ParentRef, err) + } + + // generate envars (add everything githook CLI needs for execution) + envVars, err := githook.GenerateEnvironmentVariables( + ctx, + c.urlProvider.GetInternalAPIURL(ctx), + 0, + session.Principal.ID, + true, + true, + ) + if err != nil { + return nil, fmt.Errorf("failed to generate git hook environment variables: %w", err) + } + + actor := &git.Identity{ + Name: session.Principal.DisplayName, + Email: session.Principal.Email, + } + committer := bootstrap.NewSystemServiceSession().Principal + now := time.Now() + + gitResp, err := c.git.CreateRepository(ctx, &git.CreateRepositoryParams{ + Actor: *actor, + EnvVars: envVars, + DefaultBranch: in.DefaultBranch, + Files: nil, + Author: actor, + AuthorDate: &now, + Committer: &git.Identity{ + Name: committer.DisplayName, + Email: committer.Email, + }, + CommitterDate: &now, + }) + if err != nil { + return nil, fmt.Errorf("failed to create git repository: %w", err) + } + + var repo *types.Repository + err = c.tx.WithTx(ctx, func(ctx context.Context) error { + if err := c.resourceLimiter.RepoCount(ctx, parentSpace.ID, 1); err != nil { + return fmt.Errorf("resource limit exceeded: %w", limiter.ErrMaxNumReposReached) + } + + // lock the space for update during repo creation to prevent racing conditions with space soft delete. + parentSpace, err = c.spaceStore.FindForUpdate(ctx, parentSpace.ID) + if err != nil { + return fmt.Errorf("failed to find the parent space: %w", err) + } + + repo = &types.Repository{ + Version: 0, + ParentID: parentSpace.ID, + Identifier: in.Identifier, + GitUID: gitResp.UID, + CreatedBy: session.Principal.ID, + Created: now.UnixMilli(), + Updated: now.UnixMilli(), + DefaultBranch: in.DefaultBranch, + IsEmpty: true, + State: enum.RepoStateMigrateGitPush, + } + + return c.repoStore.Create(ctx, repo) + }, sql.TxOptions{Isolation: sql.LevelSerializable}) + if err != nil { + // TODO: best effort cleanup + return nil, fmt.Errorf("failed to create a repo on db: %w", err) + } + + repo.GitURL = c.urlProvider.GenerateGITCloneURL(ctx, repo.Path) + repo.GitSSHURL = c.urlProvider.GenerateGITCloneSSHURL(ctx, repo.Path) + + isPublicAccessSupported, err := c.publicAccess.IsPublicAccessSupported(ctx, parentSpace.Path) + if err != nil { + return nil, fmt.Errorf( + "failed to check if public access is supported for parent space %s: %w", + parentSpace.Path, + err, + ) + } + + isRepoPublic := in.IsPublic + if !isPublicAccessSupported { + log.Debug().Msgf("public access is not supported, create migrating repo %s as private instead", repo.Identifier) + isRepoPublic = false + } + err = c.publicAccess.Set(ctx, enum.PublicResourceTypeRepo, repo.Path, isRepoPublic) + if err != nil { + return nil, fmt.Errorf("failed to set repo access mode: %w", err) + } + + err = c.auditService.Log(ctx, + session.Principal, + audit.NewResource(audit.ResourceTypeRepository, repo.Identifier), + audit.ActionCreated, + paths.Parent(repo.Path), + audit.WithNewObject(audit.RepositoryObject{ + Repository: *repo, + IsPublic: isRepoPublic, + }), + audit.WithData("created by", "migrator"), + ) + if err != nil { + log.Warn().Msgf("failed to insert audit log for import repository operation: %s", err) + } + + return &repoCtrl.RepositoryOutput{ + Repository: *repo, + IsPublic: isRepoPublic, + }, nil +} + +func (c *Controller) spaceCheckAuth( + ctx context.Context, + session *auth.Session, + parentRef string, +) (*types.Space, error) { + space, err := c.spaceStore.FindByRef(ctx, parentRef) + if err != nil { + return nil, fmt.Errorf("parent space not found: %w", err) + } + + // create is a special case - check permission without specific resource + scope := &types.Scope{SpacePath: space.Path} + resource := &types.Resource{ + Type: enum.ResourceTypeRepo, + Identifier: "", + } + + err = apiauth.Check(ctx, c.authorizer, session, scope, resource, enum.PermissionRepoEdit) + if err != nil { + return nil, fmt.Errorf("auth check failed: %w", err) + } + + return space, nil +} + +func (c *Controller) sanitizeCreateRepoInput(in *CreateRepoInput) error { + if err := repoCtrl.ValidateParentRef(in.ParentRef); err != nil { + return err + } + + if err := c.identifierCheck(in.Identifier); err != nil { + return err + } + + return nil +} diff --git a/app/api/controller/migrate/error.go b/app/api/controller/migrate/error.go new file mode 100644 index 000000000..90799c071 --- /dev/null +++ b/app/api/controller/migrate/error.go @@ -0,0 +1,19 @@ +// Copyright 2023 Harness, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package migrate + +import "github.com/harness/gitness/errors" + +var errInvalidRepoState = errors.PreconditionFailed("Repository data can't be imported at this point") diff --git a/app/api/controller/migrate/pullreq.go b/app/api/controller/migrate/pullreq.go new file mode 100644 index 000000000..038a112ee --- /dev/null +++ b/app/api/controller/migrate/pullreq.go @@ -0,0 +1,53 @@ +// Copyright 2023 Harness, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package migrate + +import ( + "context" + "fmt" + + "github.com/harness/gitness/app/auth" + "github.com/harness/gitness/app/services/migrate" + "github.com/harness/gitness/types" + "github.com/harness/gitness/types/enum" +) + +type PullreqsInput struct { + PullRequestData []*migrate.ExternalPullRequest `json:"pull_request_data"` +} + +func (c *Controller) PullRequests( + ctx context.Context, + session *auth.Session, + repoRef string, + in *PullreqsInput, +) ([]*types.PullReq, error) { + repo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionRepoPush) + if err != nil { + return nil, fmt.Errorf("failed to acquire access to repo: %w", err) + } + + if repo.State != enum.RepoStateMigrateDataImport { + return nil, fmt.Errorf("repo state is %s want %s: %w", + repo.State, enum.RepoStateMigrateDataImport, errInvalidRepoState) + } + + pullreqs, err := c.pullreqImporter.Import(ctx, session.Principal, repo, in.PullRequestData) + if err != nil { + return nil, fmt.Errorf("failed to import pull requests and/or comments: %w", err) + } + + return pullreqs, nil +} diff --git a/app/api/controller/migrate/rules.go b/app/api/controller/migrate/rules.go new file mode 100644 index 000000000..b6b6eb0f5 --- /dev/null +++ b/app/api/controller/migrate/rules.go @@ -0,0 +1,54 @@ +// Copyright 2023 Harness, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package migrate + +import ( + "context" + "fmt" + + "github.com/harness/gitness/app/auth" + "github.com/harness/gitness/app/services/migrate" + "github.com/harness/gitness/types" + "github.com/harness/gitness/types/enum" +) + +type RulesInput struct { + Rules []*migrate.ExternalRule `json:"rules"` + Type migrate.ExternalRuleType `json:"type"` +} + +func (c *Controller) Rules( + ctx context.Context, + session *auth.Session, + repoRef string, + in *RulesInput, +) ([]*types.Rule, error) { + repo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionRepoEdit) + if err != nil { + return nil, fmt.Errorf("failed to acquire access to repo: %w", err) + } + + if repo.State != enum.RepoStateMigrateDataImport { + return nil, fmt.Errorf("repo state is %s want %s: %w", + repo.State, enum.RepoStateMigrateDataImport, errInvalidRepoState) + } + + rulesOut, err := c.ruleImporter.Import(ctx, session.Principal, repo, in.Type, in.Rules) + if err != nil { + return nil, fmt.Errorf("failed to import rules: %w", err) + } + + return rulesOut, nil +} diff --git a/app/api/controller/migrate/update_state.go b/app/api/controller/migrate/update_state.go new file mode 100644 index 000000000..4d4695937 --- /dev/null +++ b/app/api/controller/migrate/update_state.go @@ -0,0 +1,71 @@ +// Copyright 2023 Harness, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package migrate + +import ( + "context" + "fmt" + + "github.com/harness/gitness/app/api/usererror" + "github.com/harness/gitness/app/auth" + "github.com/harness/gitness/types" + "github.com/harness/gitness/types/enum" +) + +var validTransitions = map[enum.RepoState][]enum.RepoState{ + enum.RepoStateActive: {enum.RepoStateMigrateDataImport}, + enum.RepoStateMigrateDataImport: {enum.RepoStateActive}, + enum.RepoStateMigrateGitPush: {enum.RepoStateActive, enum.RepoStateMigrateDataImport}, +} + +type UpdateStateInput struct { + State enum.RepoState `json:"state"` +} + +func (c *Controller) UpdateRepoState( + ctx context.Context, + session *auth.Session, + repoRef string, + in *UpdateStateInput, +) (*types.Repository, error) { + repo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionRepoEdit) + if err != nil { + return nil, fmt.Errorf("failed to acquire access to repo: %w", err) + } + + if !stateTransitionValid(repo, in.State) { + return nil, usererror.BadRequestf("Changing repo state from %s to %s is not allowed.", repo.State, in.State) + } + + repo, err = c.repoStore.UpdateOptLock(ctx, repo, func(r *types.Repository) error { + r.State = in.State + return nil + }) + if err != nil { + return nil, fmt.Errorf("failed to update the repo state: %w", err) + } + + return repo, nil +} + +func stateTransitionValid(repo *types.Repository, newState enum.RepoState) bool { + for _, validState := range validTransitions[repo.State] { + if validState == newState { + return true + } + } + + return false +} diff --git a/app/api/controller/migrate/webhooks.go b/app/api/controller/migrate/webhooks.go new file mode 100644 index 000000000..384a58a19 --- /dev/null +++ b/app/api/controller/migrate/webhooks.go @@ -0,0 +1,53 @@ +// Copyright 2023 Harness, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package migrate + +import ( + "context" + "fmt" + + "github.com/harness/gitness/app/auth" + "github.com/harness/gitness/app/services/migrate" + "github.com/harness/gitness/types" + "github.com/harness/gitness/types/enum" +) + +type WebhooksInput struct { + Webhooks []*migrate.ExternalWebhook `json:"hooks"` +} + +func (c *Controller) Webhooks( + ctx context.Context, + session *auth.Session, + repoRef string, + in *WebhooksInput, +) ([]*types.Webhook, error) { + repo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionRepoEdit) + if err != nil { + return nil, fmt.Errorf("failed to acquire access to repo: %w", err) + } + + if repo.State != enum.RepoStateMigrateDataImport { + return nil, fmt.Errorf("repo state is %s want %s: %w", + repo.State, enum.RepoStateMigrateDataImport, errInvalidRepoState) + } + + hookOut, err := c.webhookImporter.Import(ctx, session.Principal, repo, in.Webhooks) + if err != nil { + return nil, fmt.Errorf("failed to import webhooks: %w", err) + } + + return hookOut, nil +} diff --git a/app/api/controller/migrate/wire.go b/app/api/controller/migrate/wire.go index 3cfd731b1..bf3765b86 100644 --- a/app/api/controller/migrate/wire.go +++ b/app/api/controller/migrate/wire.go @@ -15,8 +15,16 @@ package migrate import ( + "github.com/harness/gitness/app/api/controller/limiter" "github.com/harness/gitness/app/auth/authz" + "github.com/harness/gitness/app/services/migrate" + "github.com/harness/gitness/app/services/publicaccess" "github.com/harness/gitness/app/store" + "github.com/harness/gitness/app/url" + "github.com/harness/gitness/audit" + "github.com/harness/gitness/git" + "github.com/harness/gitness/store/database/dbtx" + "github.com/harness/gitness/types/check" "github.com/google/wire" ) @@ -28,10 +36,32 @@ var WireSet = wire.NewSet( func ProvideController( authorizer authz.Authorizer, - principalStore store.PrincipalStore, + publicAccess publicaccess.Service, + rpcClient git.Interface, + urlProvider url.Provider, + pullreqImporter *migrate.PullReq, + ruleImporter *migrate.Rule, + webhookImporter *migrate.Webhook, + resourceLimiter limiter.ResourceLimiter, + auditService audit.Service, + identifierCheck check.RepoIdentifier, + tx dbtx.Transactor, + spaceStore store.SpaceStore, + repoStore store.RepoStore, ) *Controller { return NewController( authorizer, - principalStore, + publicAccess, + rpcClient, + urlProvider, + pullreqImporter, + ruleImporter, + webhookImporter, + resourceLimiter, + auditService, + identifierCheck, + tx, + spaceStore, + repoStore, ) } diff --git a/app/api/controller/pullreq/controller.go b/app/api/controller/pullreq/controller.go index 25ada3950..4ddb60396 100644 --- a/app/api/controller/pullreq/controller.go +++ b/app/api/controller/pullreq/controller.go @@ -26,9 +26,9 @@ import ( pullreqevents "github.com/harness/gitness/app/events/pullreq" "github.com/harness/gitness/app/services/codecomments" "github.com/harness/gitness/app/services/codeowners" - "github.com/harness/gitness/app/services/importer" "github.com/harness/gitness/app/services/label" locker "github.com/harness/gitness/app/services/locker" + "github.com/harness/gitness/app/services/migrate" "github.com/harness/gitness/app/services/protection" "github.com/harness/gitness/app/services/pullreq" "github.com/harness/gitness/app/sse" @@ -66,7 +66,7 @@ type Controller struct { sseStreamer sse.Streamer codeOwners *codeowners.Service locker *locker.Locker - importer *importer.PullReq + importer *migrate.PullReq labelSvc *label.Service } @@ -93,7 +93,7 @@ func NewController( sseStreamer sse.Streamer, codeowners *codeowners.Service, locker *locker.Locker, - importer *importer.PullReq, + importer *migrate.PullReq, labelSvc *label.Service, ) *Controller { return &Controller{ diff --git a/app/api/controller/pullreq/wire.go b/app/api/controller/pullreq/wire.go index 30e6327cc..38a76bfb7 100644 --- a/app/api/controller/pullreq/wire.go +++ b/app/api/controller/pullreq/wire.go @@ -19,9 +19,9 @@ import ( pullreqevents "github.com/harness/gitness/app/events/pullreq" "github.com/harness/gitness/app/services/codecomments" "github.com/harness/gitness/app/services/codeowners" - "github.com/harness/gitness/app/services/importer" "github.com/harness/gitness/app/services/label" "github.com/harness/gitness/app/services/locker" + "github.com/harness/gitness/app/services/migrate" "github.com/harness/gitness/app/services/protection" "github.com/harness/gitness/app/services/pullreq" "github.com/harness/gitness/app/sse" @@ -48,7 +48,7 @@ func ProvideController(tx dbtx.Transactor, urlProvider url.Provider, authorizer checkStore store.CheckStore, rpcClient git.Interface, eventReporter *pullreqevents.Reporter, codeCommentMigrator *codecomments.Migrator, pullreqService *pullreq.Service, ruleManager *protection.Manager, sseStreamer sse.Streamer, - codeOwners *codeowners.Service, locker *locker.Locker, importer *importer.PullReq, + codeOwners *codeowners.Service, locker *locker.Locker, importer *migrate.PullReq, labelSvc *label.Service, ) *Controller { return NewController(tx, urlProvider, authorizer, diff --git a/app/api/controller/repo/controller.go b/app/api/controller/repo/controller.go index 6217958a9..d4b94d8c1 100644 --- a/app/api/controller/repo/controller.go +++ b/app/api/controller/repo/controller.go @@ -203,7 +203,7 @@ func (c *Controller) getRepoCheckAccessForGit( ) } -func (c *Controller) validateParentRef(parentRef string) error { +func ValidateParentRef(parentRef string) error { parentRefAsID, err := strconv.ParseInt(parentRef, 10, 64) if (err == nil && parentRefAsID <= 0) || (len(strings.TrimSpace(parentRef)) == 0) { return errRepositoryRequiresParent diff --git a/app/api/controller/repo/create.go b/app/api/controller/repo/create.go index 4f4f7cc4a..7e3f1e53e 100644 --- a/app/api/controller/repo/create.go +++ b/app/api/controller/repo/create.go @@ -208,7 +208,7 @@ func (c *Controller) sanitizeCreateInput(in *CreateInput) error { in.Identifier = in.UID } - if err := c.validateParentRef(in.ParentRef); err != nil { + if err := ValidateParentRef(in.ParentRef); err != nil { return err } diff --git a/app/api/controller/repo/import.go b/app/api/controller/repo/import.go index 353d292cc..b59af4755 100644 --- a/app/api/controller/repo/import.go +++ b/app/api/controller/repo/import.go @@ -123,7 +123,7 @@ func (c *Controller) sanitizeImportInput(in *ImportInput) error { in.Identifier = in.UID } - if err := c.validateParentRef(in.ParentRef); err != nil { + if err := ValidateParentRef(in.ParentRef); err != nil { return err } diff --git a/app/api/controller/webhook/common.go b/app/api/controller/webhook/common.go index 95ab687fb..5525bf03e 100644 --- a/app/api/controller/webhook/common.go +++ b/app/api/controller/webhook/common.go @@ -32,8 +32,8 @@ const ( var ErrInternalWebhookOperationNotAllowed = usererror.Forbidden("changes to internal webhooks are not allowed") -// checkURL validates the url of a webhook. -func checkURL(rawURL string, allowLoopback bool, allowPrivateNetwork bool) error { +// CheckURL validates the url of a webhook. +func CheckURL(rawURL string, allowLoopback bool, allowPrivateNetwork bool) error { // check URL if len(rawURL) > webhookMaxURLLength { return check.NewValidationErrorf("The URL of a webhook can be at most %d characters long.", @@ -84,8 +84,8 @@ func checkSecret(secret string) error { return nil } -// checkTriggers validates the triggers of a webhook. -func checkTriggers(triggers []enum.WebhookTrigger) error { +// CheckTriggers validates the triggers of a webhook. +func CheckTriggers(triggers []enum.WebhookTrigger) error { // ignore duplicates here, should be deduplicated later for _, trigger := range triggers { if _, ok := trigger.Sanitize(); !ok { @@ -96,8 +96,8 @@ func checkTriggers(triggers []enum.WebhookTrigger) error { return nil } -// deduplicateTriggers de-duplicates the triggers provided by the user. -func deduplicateTriggers(in []enum.WebhookTrigger) []enum.WebhookTrigger { +// DeduplicateTriggers de-duplicates the triggers provided by the user. +func DeduplicateTriggers(in []enum.WebhookTrigger) []enum.WebhookTrigger { if len(in) == 0 { return []enum.WebhookTrigger{} } @@ -114,3 +114,11 @@ func deduplicateTriggers(in []enum.WebhookTrigger) []enum.WebhookTrigger { return out } + +func ConvertTriggers(vals []string) []enum.WebhookTrigger { + res := make([]enum.WebhookTrigger, len(vals)) + for i := range vals { + res[i] = enum.WebhookTrigger(vals[i]) + } + return res +} diff --git a/app/api/controller/webhook/create.go b/app/api/controller/webhook/create.go index 9d2a11049..45c693e31 100644 --- a/app/api/controller/webhook/create.go +++ b/app/api/controller/webhook/create.go @@ -92,7 +92,7 @@ func (c *Controller) Create( Secret: string(encryptedSecret), Enabled: in.Enabled, Insecure: in.Insecure, - Triggers: deduplicateTriggers(in.Triggers), + Triggers: DeduplicateTriggers(in.Triggers), LatestExecutionResult: nil, } @@ -149,13 +149,13 @@ func sanitizeCreateInput(in *CreateInput, allowLoopback bool, allowPrivateNetwor if err := check.Description(in.Description); err != nil { return err } - if err := checkURL(in.URL, allowLoopback, allowPrivateNetwork); err != nil { + if err := CheckURL(in.URL, allowLoopback, allowPrivateNetwork); err != nil { return err } if err := checkSecret(in.Secret); err != nil { return err } - if err := checkTriggers(in.Triggers); err != nil { //nolint:revive + if err := CheckTriggers(in.Triggers); err != nil { //nolint:revive return err } diff --git a/app/api/controller/webhook/update.go b/app/api/controller/webhook/update.go index 9a879912b..929a503aa 100644 --- a/app/api/controller/webhook/update.go +++ b/app/api/controller/webhook/update.go @@ -93,7 +93,7 @@ func (c *Controller) Update( hook.Insecure = *in.Insecure } if in.Triggers != nil { - hook.Triggers = deduplicateTriggers(in.Triggers) + hook.Triggers = DeduplicateTriggers(in.Triggers) } if err = c.webhookStore.Update(ctx, hook); err != nil { @@ -125,7 +125,7 @@ func sanitizeUpdateInput(in *UpdateInput, allowLoopback bool, allowPrivateNetwor } } if in.URL != nil { - if err := checkURL(*in.URL, allowLoopback, allowPrivateNetwork); err != nil { + if err := CheckURL(*in.URL, allowLoopback, allowPrivateNetwork); err != nil { return err } } @@ -135,7 +135,7 @@ func sanitizeUpdateInput(in *UpdateInput, allowLoopback bool, allowPrivateNetwor } } if in.Triggers != nil { - if err := checkTriggers(in.Triggers); err != nil { + if err := CheckTriggers(in.Triggers); err != nil { return err } } diff --git a/app/api/handler/migrate/create_repo.go b/app/api/handler/migrate/create_repo.go new file mode 100644 index 000000000..7c99bcbe0 --- /dev/null +++ b/app/api/handler/migrate/create_repo.go @@ -0,0 +1,47 @@ +// Copyright 2023 Harness, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package migrate + +import ( + "encoding/json" + "net/http" + + "github.com/harness/gitness/app/api/controller/migrate" + "github.com/harness/gitness/app/api/render" + "github.com/harness/gitness/app/api/request" +) + +// HandleCreateRepo handles API that create an empty repo ready for migration. +func HandleCreateRepo(migCtrl *migrate.Controller) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + session, _ := request.AuthSessionFrom(ctx) + + in := new(migrate.CreateRepoInput) + err := json.NewDecoder(r.Body).Decode(in) + if err != nil { + render.BadRequestf(ctx, w, "Invalid Request Body: %s.", err) + return + } + + repo, err := migCtrl.CreateRepo(ctx, session, in) + if err != nil { + render.TranslatedUserError(ctx, w, err) + return + } + + render.JSON(w, http.StatusCreated, repo) + } +} diff --git a/app/api/handler/migrate/pullreq.go b/app/api/handler/migrate/pullreq.go new file mode 100644 index 000000000..13a9c5674 --- /dev/null +++ b/app/api/handler/migrate/pullreq.go @@ -0,0 +1,53 @@ +// Copyright 2023 Harness, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package migrate + +import ( + "encoding/json" + "net/http" + + "github.com/harness/gitness/app/api/controller/migrate" + "github.com/harness/gitness/app/api/render" + "github.com/harness/gitness/app/api/request" +) + +// HandlePullRequests handles API that imports pull requests to a repository. +func HandlePullRequests(migCtrl *migrate.Controller) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + session, _ := request.AuthSessionFrom(ctx) + + repoRef, err := request.GetRepoRefFromPath(r) + if err != nil { + render.TranslatedUserError(ctx, w, err) + return + } + + in := new(migrate.PullreqsInput) + err = json.NewDecoder(r.Body).Decode(in) + if err != nil { + render.BadRequestf(ctx, w, "Invalid Request Body: %s.", err) + return + } + + pullReqs, err := migCtrl.PullRequests(ctx, session, repoRef, in) + if err != nil { + render.TranslatedUserError(ctx, w, err) + return + } + + render.JSON(w, http.StatusCreated, pullReqs) + } +} diff --git a/app/api/handler/migrate/rules.go b/app/api/handler/migrate/rules.go new file mode 100644 index 000000000..c30cf5616 --- /dev/null +++ b/app/api/handler/migrate/rules.go @@ -0,0 +1,53 @@ +// Copyright 2023 Harness, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package migrate + +import ( + "encoding/json" + "net/http" + + "github.com/harness/gitness/app/api/controller/migrate" + "github.com/harness/gitness/app/api/render" + "github.com/harness/gitness/app/api/request" +) + +// HandleRules handles API that imports protection rule(s) to a repository. +func HandleRules(migCtrl *migrate.Controller) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + session, _ := request.AuthSessionFrom(ctx) + + repoRef, err := request.GetRepoRefFromPath(r) + if err != nil { + render.TranslatedUserError(ctx, w, err) + return + } + + in := new(migrate.RulesInput) + err = json.NewDecoder(r.Body).Decode(in) + if err != nil { + render.BadRequestf(ctx, w, "Invalid Request Body: %s.", err) + return + } + + rules, err := migCtrl.Rules(ctx, session, repoRef, in) + if err != nil { + render.TranslatedUserError(ctx, w, err) + return + } + + render.JSON(w, http.StatusCreated, rules) + } +} diff --git a/app/api/handler/migrate/update_state.go b/app/api/handler/migrate/update_state.go new file mode 100644 index 000000000..425438629 --- /dev/null +++ b/app/api/handler/migrate/update_state.go @@ -0,0 +1,53 @@ +// Copyright 2023 Harness, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package migrate + +import ( + "encoding/json" + "net/http" + + "github.com/harness/gitness/app/api/controller/migrate" + "github.com/harness/gitness/app/api/render" + "github.com/harness/gitness/app/api/request" +) + +// HandleUpdateRepoState handles API that updates the repository state. +func HandleUpdateRepoState(migCtrl *migrate.Controller) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + session, _ := request.AuthSessionFrom(ctx) + + repoRef, err := request.GetRepoRefFromPath(r) + if err != nil { + render.TranslatedUserError(ctx, w, err) + return + } + + in := new(migrate.UpdateStateInput) + err = json.NewDecoder(r.Body).Decode(in) + if err != nil { + render.BadRequestf(ctx, w, "Invalid Request Body: %s.", err) + return + } + + repo, err := migCtrl.UpdateRepoState(ctx, session, repoRef, in) + if err != nil { + render.TranslatedUserError(ctx, w, err) + return + } + + render.JSON(w, http.StatusOK, repo) + } +} diff --git a/app/api/handler/migrate/webhooks.go b/app/api/handler/migrate/webhooks.go new file mode 100644 index 000000000..27148a450 --- /dev/null +++ b/app/api/handler/migrate/webhooks.go @@ -0,0 +1,53 @@ +// Copyright 2023 Harness, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package migrate + +import ( + "encoding/json" + "net/http" + + "github.com/harness/gitness/app/api/controller/migrate" + "github.com/harness/gitness/app/api/render" + "github.com/harness/gitness/app/api/request" +) + +// HandleWebhooks returns a http.HandlerFunc that import webhooks. +func HandleWebhooks(migCtrl *migrate.Controller) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + session, _ := request.AuthSessionFrom(ctx) + + repoRef, err := request.GetRepoRefFromPath(r) + if err != nil { + render.TranslatedUserError(ctx, w, err) + return + } + + in := new(migrate.WebhooksInput) + err = json.NewDecoder(r.Body).Decode(in) + if err != nil { + render.BadRequestf(ctx, w, "Invalid Request Body: %s.", err) + return + } + + hooks, err := migCtrl.Webhooks(ctx, session, repoRef, in) + if err != nil { + render.TranslatedUserError(ctx, w, err) + return + } + + render.JSON(w, http.StatusCreated, hooks) + } +} diff --git a/app/api/render/render_error.go b/app/api/render/render_error.go index b89462078..947184fe7 100644 --- a/app/api/render/render_error.go +++ b/app/api/render/render_error.go @@ -43,6 +43,11 @@ func Forbidden(ctx context.Context, w http.ResponseWriter) { UserError(ctx, w, usererror.ErrForbidden) } +// Forbiddenf writes the json-encoded message with a forbidden error. +func Forbiddenf(ctx context.Context, w http.ResponseWriter, format string, args ...interface{}) { + UserError(ctx, w, usererror.Newf(http.StatusForbidden, format, args...)) +} + // BadRequest writes the json-encoded message for a bad request error. func BadRequest(ctx context.Context, w http.ResponseWriter) { UserError(ctx, w, usererror.ErrBadRequest) diff --git a/app/router/api.go b/app/router/api.go index 1d22dbfc3..7e56640e2 100644 --- a/app/router/api.go +++ b/app/router/api.go @@ -52,6 +52,7 @@ import ( handlerinfraProvider "github.com/harness/gitness/app/api/handler/infraprovider" handlerkeywordsearch "github.com/harness/gitness/app/api/handler/keywordsearch" handlerlogs "github.com/harness/gitness/app/api/handler/logs" + handlermigrate "github.com/harness/gitness/app/api/handler/migrate" handlerpipeline "github.com/harness/gitness/app/api/handler/pipeline" handlerplugin "github.com/harness/gitness/app/api/handler/plugin" handlerprincipal "github.com/harness/gitness/app/api/handler/principal" @@ -92,7 +93,8 @@ import ( var ( // terminatedPathPrefixesAPI is the list of prefixes that will require resolving terminated paths. terminatedPathPrefixesAPI = []string{"/v1/spaces/", "/v1/repos/", - "/v1/secrets/", "/v1/connectors", "/v1/templates/step", "/v1/templates/stage", "/v1/gitspaces", "/v1/infraproviders"} + "/v1/secrets/", "/v1/connectors", "/v1/templates/step", "/v1/templates/stage", + "/v1/gitspaces", "/v1/infraproviders", "/v1/migrate/repos"} ) // NewAPIHandler returns a new APIHandler. @@ -658,6 +660,7 @@ func SetupRules(r chi.Router, repoCtrl *repo.Controller) { r.Route("/rules", func(r chi.Router) { r.Post("/", handlerrepo.HandleRuleCreate(repoCtrl)) r.Get("/", handlerrepo.HandleRuleList(repoCtrl)) + r.Route(fmt.Sprintf("/{%s}", request.PathParamRuleIdentifier), func(r chi.Router) { r.Patch("/", handlerrepo.HandleRuleUpdate(repoCtrl)) r.Delete("/", handlerrepo.HandleRuleDelete(repoCtrl)) @@ -813,12 +816,16 @@ func setupAccountWithAuth(r chi.Router, userCtrl *user.Controller, config *types r.Post("/logout", account.HandleLogout(userCtrl, cookieName)) } -func setupMigrate(r chi.Router, ctrl *migrate.Controller) { +func setupMigrate(r chi.Router, migCtrl *migrate.Controller) { r.Route("/migrate", func(r chi.Router) { - SetupMigrateRoutes(r, ctrl) + r.Route("/repos", func(r chi.Router) { + r.Post("/", handlermigrate.HandleCreateRepo(migCtrl)) + r.Route(fmt.Sprintf("/{%s}", request.PathParamRepoRef), func(r chi.Router) { + r.Patch("/update-state", handlermigrate.HandleUpdateRepoState(migCtrl)) + r.Post("/pullreqs", handlermigrate.HandlePullRequests(migCtrl)) + r.Post("/webhooks", handlermigrate.HandleWebhooks(migCtrl)) + r.Post("/rules", handlermigrate.HandleRules(migCtrl)) + }) + }) }) } - -func SetupMigrateRoutes(_ chi.Router, _ *migrate.Controller) { - // add migrate routes with spaces -} diff --git a/app/services/importer/wire.go b/app/services/importer/wire.go index 2358ce957..bab7fa4f2 100644 --- a/app/services/importer/wire.go +++ b/app/services/importer/wire.go @@ -32,7 +32,6 @@ import ( var WireSet = wire.NewSet( ProvideRepoImporter, - ProvidePullReqImporter, ) func ProvideRepoImporter( @@ -74,25 +73,3 @@ func ProvideRepoImporter( return importer, nil } - -func ProvidePullReqImporter( - urlProvider url.Provider, - git git.Interface, - principalStore store.PrincipalStore, - repoStore store.RepoStore, - pullReqStore store.PullReqStore, - pullReqActStore store.PullReqActivityStore, - tx dbtx.Transactor, -) *PullReq { - importer := &PullReq{ - urlProvider: urlProvider, - git: git, - principalStore: principalStore, - repoStore: repoStore, - pullReqStore: pullReqStore, - pullReqActStore: pullReqActStore, - tx: tx, - } - - return importer -} diff --git a/app/services/importer/pullreq.go b/app/services/migrate/pullreq.go similarity index 78% rename from app/services/importer/pullreq.go rename to app/services/migrate/pullreq.go index 3cbae23ec..0d4287bcd 100644 --- a/app/services/importer/pullreq.go +++ b/app/services/migrate/pullreq.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package importer +package migrate import ( "context" @@ -27,6 +27,7 @@ import ( "github.com/harness/gitness/errors" "github.com/harness/gitness/git" "github.com/harness/gitness/git/parser" + gitness_store "github.com/harness/gitness/store" "github.com/harness/gitness/store/database/dbtx" "github.com/harness/gitness/types" "github.com/harness/gitness/types/enum" @@ -34,7 +35,7 @@ import ( "github.com/rs/zerolog/log" ) -// PullReq is pull request importer. +// PullReq is pull request migrate. type PullReq struct { urlProvider url.Provider git git.Interface @@ -45,6 +46,26 @@ type PullReq struct { tx dbtx.Transactor } +func NewPullReq( + urlProvider url.Provider, + git git.Interface, + principalStore store.PrincipalStore, + repoStore store.RepoStore, + pullReqStore store.PullReqStore, + pullReqActStore store.PullReqActivityStore, + tx dbtx.Transactor, +) *PullReq { + return &PullReq{ + urlProvider: urlProvider, + git: git, + principalStore: principalStore, + repoStore: repoStore, + pullReqStore: pullReqStore, + pullReqActStore: pullReqActStore, + tx: tx, + } +} + type repoImportState struct { git git.Interface readParams git.ReadParams @@ -52,29 +73,30 @@ type repoImportState struct { pullReqActivityStore store.PullReqActivityStore branchCheck map[string]*git.Branch principals map[string]*types.Principal + unknownEmails map[int]map[string]bool + migrator types.Principal } // Import load provided pull requests in go-scm format and imports them. // //nolint:gocognit -func (importer PullReq) Import( +func (migrate PullReq) Import( ctx context.Context, + migrator types.Principal, repo *types.Repository, extPullReqs []*ExternalPullRequest, ) ([]*types.PullReq, error) { - if repo.State != enum.RepoStateMigrateDataImport { - return nil, errors.PreconditionFailed("Repository data can't be imported at this point") - } - readParams := git.ReadParams{RepoUID: repo.GitUID} repoState := repoImportState{ - git: importer.git, + git: migrate.git, readParams: readParams, - principalStore: importer.principalStore, - pullReqActivityStore: importer.pullReqActStore, + principalStore: migrate.principalStore, + pullReqActivityStore: migrate.pullReqActStore, branchCheck: map[string]*git.Branch{}, principals: map[string]*types.Principal{}, + unknownEmails: map[int]map[string]bool{}, + migrator: migrator, } pullReqUnique := map[int]struct{}{} @@ -103,13 +125,13 @@ func (importer PullReq) Import( return nil, nil } - err := importer.tx.WithTx(ctx, func(ctx context.Context) error { + err := migrate.tx.WithTx(ctx, func(ctx context.Context) error { var deltaOpen, deltaClosed, deltaMerged int var maxNumber int64 // Store the pull request objects and the comments. for _, pullReq := range pullReqs { - if err := importer.pullReqStore.Create(ctx, pullReq); err != nil { + if err := migrate.pullReqStore.Create(ctx, pullReq); err != nil { return fmt.Errorf("failed to import the pull request %d: %w", pullReq.Number, err) } @@ -131,18 +153,28 @@ func (importer PullReq) Import( return fmt.Errorf("failed to import pull request comments: %w", err) } + // Add a comment if any principal (PR author or commenter) were replaced by the fallback migrator principal + if prUnknownEmails, ok := repoState.unknownEmails[int(pullReq.Number)]; ok && len(prUnknownEmails) != 0 { + infoComment, err := repoState.createInfoComment(ctx, repo, pullReq) + if err != nil { + log.Ctx(ctx).Warn().Err(err).Msg("failed to add an informational comment for replacing non-existing users") + } else { + comments = append(comments, infoComment) + } + } + if len(comments) == 0 { // no need to update the pull request object in the DB if there are no comments. continue } - if err := importer.pullReqStore.Update(ctx, pullReq); err != nil { + if err := migrate.pullReqStore.Update(ctx, pullReq); err != nil { return fmt.Errorf("failed to update pull request after importing of the comments: %w", err) } } // Update the repository - repoUpdate, err := importer.repoStore.Find(ctx, repo.ID) + repoUpdate, err := migrate.repoStore.Find(ctx, repo.ID) if err != nil { return fmt.Errorf("failed to fetch repo in pull request import: %w", err) } @@ -155,7 +187,7 @@ func (importer PullReq) Import( repoUpdate.NumClosedPulls += deltaClosed repoUpdate.NumMergedPulls += deltaMerged - if err := importer.repoStore.Update(ctx, repoUpdate); err != nil { + if err := migrate.repoStore.Update(ctx, repoUpdate); err != nil { return fmt.Errorf("failed to update repo in pull request import: %w", err) } @@ -181,7 +213,7 @@ func (r *repoImportState) convertPullReq( Int("pullreq.number", extPullReq.Number). Logger() - author, err := r.getPrincipalByEmail(ctx, extPullReq.Author.Email) + author, err := r.getPrincipalByEmail(ctx, extPullReq.Author.Email, extPullReq.Number, false) if err != nil { return nil, fmt.Errorf("failed to get pull request author: %w", err) } @@ -200,7 +232,7 @@ func (r *repoImportState) convertPullReq( Edited: updatedAt, Closed: nil, State: enum.PullReqStateOpen, - IsDraft: false, + IsDraft: extPullReq.Draft, CommentCount: 0, UnresolvedCount: 0, Title: extPullReq.Title, @@ -239,14 +271,16 @@ func (r *repoImportState) convertPullReq( pr.MergeCheckStatus = enum.MergeCheckStatusMergeable pr.SourceSHA = extPullReq.Head.SHA pr.MergeTargetSHA = &extPullReq.Base.SHA - pr.MergeBaseSHA = extPullReq.Head.SHA // Don't have the real value. Set the value to SourceSHA. - pr.MergeSHA = nil // Don't have this. + pr.MergeBaseSHA = extPullReq.Base.SHA + pr.MergeSHA = nil // Don't have this. pr.MergeConflicts = nil case enum.PullReqStateClosed: // For closed PR's it's not important to verify existence of branches and commits. // If these don't exist the PR will be impossible to open. - + pr.SourceSHA = extPullReq.Head.SHA + pr.MergeTargetSHA = &extPullReq.Base.SHA + pr.MergeBaseSHA = extPullReq.Base.SHA pr.MergeCheckStatus = enum.MergeCheckStatusUnchecked pr.MergeSHA = nil pr.MergeConflicts = nil @@ -353,11 +387,10 @@ func (r *repoImportState) createComment( order, subOrder, replySeq int, extComment *ExternalComment, ) (*types.PullReqActivity, error) { - commenter, err := r.getPrincipalByEmail(ctx, extComment.Author.Email) + commenter, err := r.getPrincipalByEmail(ctx, extComment.Author.Email, int(pullReq.Number), false) if err != nil { return nil, fmt.Errorf("failed to get comment ID=%d author: %w", extComment.ID, err) } - commentedAt := extComment.Created.UnixMilli() // Mark comments as resolved if the PR is merged, otherwise they are unresolved. @@ -440,17 +473,87 @@ func (r *repoImportState) createComment( return comment, nil } -func (r *repoImportState) getPrincipalByEmail(ctx context.Context, emailAddress string) (*types.Principal, error) { +// createInfoComment creates an informational comment on the PR +// if any of the principals were replaced with the migrator. +func (r *repoImportState) createInfoComment( + ctx context.Context, + repo *types.Repository, + pullReq *types.PullReq, +) (*types.PullReqActivity, error) { + var unknownEmails []string + for email := range r.unknownEmails[int(pullReq.Number)] { + unknownEmails = append(unknownEmails, email) + } + now := time.Now().UnixMilli() + text := fmt.Sprintf(InfoCommentMessage, r.migrator.UID, strings.Join(unknownEmails, ", ")) + comment := &types.PullReqActivity{ + CreatedBy: r.migrator.ID, + Created: now, + Updated: now, + Deleted: nil, + ParentID: nil, + RepoID: repo.ID, + PullReqID: pullReq.ID, + Order: pullReq.ActivitySeq + 1, + SubOrder: 0, + ReplySeq: 0, + Type: enum.PullReqActivityTypeComment, + Kind: enum.PullReqActivityKindComment, + Text: text, + PayloadRaw: json.RawMessage("{}"), + Metadata: nil, + ResolvedBy: &r.migrator.ID, + Resolved: &now, + CodeComment: nil, + Mentions: nil, + } + + if err := r.pullReqActivityStore.Create(ctx, comment); err != nil { + return nil, fmt.Errorf("failed to store the info comment author: %w", err) + } + + pullReq.ActivitySeq++ + pullReq.CommentCount++ + + return comment, nil +} + +func (r *repoImportState) getPrincipalByEmail( + ctx context.Context, + emailAddress string, + prNumber int, + strict bool, +) (*types.Principal, error) { if principal, exists := r.principals[emailAddress]; exists { return principal, nil } principal, err := r.principalStore.FindByEmail(ctx, emailAddress) - if err != nil { + if err != nil && !errors.Is(err, gitness_store.ErrResourceNotFound) { return nil, fmt.Errorf("failed to load principal by email: %w", err) } - return principal, nil + if err == nil { + r.principals[emailAddress] = principal + return principal, nil + } + + if strict { + return nil, fmt.Errorf( + "could not find principal by email %s and automatic replacing unknown prinicapls is disabled: %w", + emailAddress, err) + } + + // ignore not found emails if is not strict + if _, exists := r.unknownEmails[prNumber]; !exists { + r.unknownEmails[prNumber] = make(map[string]bool, 0) + } + + if _, ok := r.unknownEmails[prNumber][emailAddress]; !ok && len(r.unknownEmails[prNumber]) < MaxNumberOfUnknownEmails { + r.unknownEmails[prNumber][emailAddress] = true + } + + return &r.migrator, nil } func timestampMillis(t time.Time, def int64) int64 { diff --git a/app/services/importer/pullreq_test.go b/app/services/migrate/pullreq_test.go similarity index 99% rename from app/services/importer/pullreq_test.go rename to app/services/migrate/pullreq_test.go index bfd21941d..dd6bbcb94 100644 --- a/app/services/importer/pullreq_test.go +++ b/app/services/migrate/pullreq_test.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package importer +package migrate import ( "testing" diff --git a/app/services/migrate/pullreq_types.go b/app/services/migrate/pullreq_types.go new file mode 100644 index 000000000..0dbbf8bdf --- /dev/null +++ b/app/services/migrate/pullreq_types.go @@ -0,0 +1,32 @@ +// Copyright 2023 Harness, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package migrate + +import migratetypes "github.com/harness/harness-migrate/types" + +type ExternalPullRequest = migratetypes.PullRequestData +type ExternalComment = migratetypes.Comment + +type externalCommentThread struct { + TopLevel ExternalComment + Replies []ExternalComment +} + +const ( + InfoCommentMessage = "This pull request has been imported. Non-existent users who were originally listed " + + "as the pull request author or commenter have been replaced by the principal '%s' which performed the migration.\n" + + "Unknown emails: %v" + MaxNumberOfUnknownEmails = 500 // limit keeping unknown users to avoid info comment text exceed ~1000 characters +) diff --git a/app/services/migrate/rule.go b/app/services/migrate/rule.go new file mode 100644 index 000000000..7917bed25 --- /dev/null +++ b/app/services/migrate/rule.go @@ -0,0 +1,178 @@ +// Copyright 2023 Harness, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package migrate + +import ( + "context" + "encoding/json" + "fmt" + "time" + + "github.com/harness/gitness/app/services/protection" + "github.com/harness/gitness/app/store" + "github.com/harness/gitness/errors" + gitness_store "github.com/harness/gitness/store" + "github.com/harness/gitness/store/database/dbtx" + "github.com/harness/gitness/types" + "github.com/harness/gitness/types/check" + "github.com/harness/gitness/types/enum" + + migratetypes "github.com/harness/harness-migrate/types" + "github.com/rs/zerolog/log" +) + +type Rule struct { + ruleStore store.RuleStore + principalStore store.PrincipalStore + tx dbtx.Transactor + + DefDeserializationMap map[migratetypes.RuleType]definitionDeserializer + PatternDeserializationMap map[migratetypes.RuleType]patternDeserializer +} + +func NewRule( + ruleStore store.RuleStore, + tx dbtx.Transactor, + principalStore store.PrincipalStore, +) *Rule { + rule := &Rule{ + ruleStore: ruleStore, + principalStore: principalStore, + tx: tx, + DefDeserializationMap: make(map[ExternalRuleType]definitionDeserializer), + PatternDeserializationMap: make(map[ExternalRuleType]patternDeserializer), + } + + rule.registerDeserializers(principalStore) + + return rule +} + +func (migrate Rule) Import( + ctx context.Context, + migrator types.Principal, + repo *types.Repository, + typ ExternalRuleType, + extRules []*ExternalRule, +) ([]*types.Rule, error) { + rules := make([]*types.Rule, len(extRules)) + for i, extRule := range extRules { + if err := check.Identifier(extRule.Identifier); err != nil { + return nil, fmt.Errorf("branch rule identifier '%s' is invalid: %w", extRule.Identifier, err) + } + + def, err := migrate.DefDeserializationMap[typ](ctx, string(extRule.Definition)) + if err != nil { + return nil, fmt.Errorf("failed to deserialize rule definition: %w", err) + } + + if err = def.Sanitize(); err != nil { + return nil, fmt.Errorf("provided rule definition is invalid: %w", err) + } + + definitionJSON, err := json.Marshal(def) + if err != nil { + return nil, fmt.Errorf("failed to marshal rule definition: %w", err) + } + + pattern, err := migrate.PatternDeserializationMap[typ](ctx, string(extRule.Pattern)) + if err != nil { + return nil, fmt.Errorf("failed to deserialize rule pattern: %w", err) + } + + if err = pattern.Validate(); err != nil { + return nil, fmt.Errorf("provided rule pattern is invalid: %w", err) + } + + now := time.Now().UnixMilli() + r := &types.Rule{ + CreatedBy: migrator.ID, + Created: now, + Updated: now, + RepoID: &repo.ID, + SpaceID: nil, + Type: protection.TypeBranch, + State: enum.RuleStateActive, + Identifier: extRule.Identifier, + Pattern: pattern.JSON(), + Definition: json.RawMessage(definitionJSON), + } + rules[i] = r + } + + err := migrate.tx.WithTx(ctx, func(ctx context.Context) error { + for _, rule := range rules { + err := migrate.ruleStore.Create(ctx, rule) + if err != nil { + return fmt.Errorf("failed to create branch rule: %w", err) + } + } + return nil + }) + if err != nil { + return nil, fmt.Errorf("failed to store external branch rules: %w", err) + } + + return rules, nil +} + +func mapToBranchRules( + ctx context.Context, + rule ExternalDefinition, + principalStore store.PrincipalStore, +) (*protection.Branch, error) { + // map users + var userIDs []int64 + for _, email := range rule.Bypass.UserEmails { + principal, err := principalStore.FindByEmail(ctx, email) + if err != nil && !errors.Is(err, gitness_store.ErrResourceNotFound) { + return nil, fmt.Errorf("failed to find principal by email for '%s': %w", email, err) + } + + if errors.Is(err, gitness_store.ErrResourceNotFound) { + log.Ctx(ctx).Warn().Msgf("skipping principal '%s' on bypass list", email) + continue + } + + userIDs = append(userIDs, principal.ID) + } + + return &protection.Branch{ + Bypass: protection.DefBypass{ + UserIDs: userIDs, + RepoOwners: rule.Bypass.RepoOwners, + }, + + PullReq: protection.DefPullReq{ + Approvals: protection.DefApprovals(rule.PullReq.Approvals), + Comments: protection.DefComments(rule.PullReq.Comments), + StatusChecks: protection.DefStatusChecks(rule.PullReq.StatusChecks), + Merge: protection.DefMerge{ + StrategiesAllowed: convertMergeMethods(rule.PullReq.Merge.StrategiesAllowed), + DeleteBranch: rule.PullReq.Merge.DeleteBranch, + }, + }, + + Lifecycle: protection.DefLifecycle(rule.Lifecycle), + }, nil +} + +func convertMergeMethods(vals []string) []enum.MergeMethod { + res := make([]enum.MergeMethod, len(vals)) + for i := range vals { + res[i] = enum.MergeMethod(vals[i]) + } + return res +} diff --git a/app/services/migrate/rule_types.go b/app/services/migrate/rule_types.go new file mode 100644 index 000000000..0a58c02e5 --- /dev/null +++ b/app/services/migrate/rule_types.go @@ -0,0 +1,82 @@ +// Copyright 2023 Harness, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package migrate + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + + "github.com/harness/gitness/app/services/protection" + "github.com/harness/gitness/app/store" + + migratetypes "github.com/harness/harness-migrate/types" +) + +const ExternalRuleTypeBranch = migratetypes.RuleTypeBranch + +type ( + ExternalRuleType = migratetypes.RuleType + ExternalRule = migratetypes.Rule + + ExternalDefinition = migratetypes.Definition + ExternalBranchPattern = migratetypes.BranchPattern + + definitionDeserializer func(context.Context, string) (protection.Definition, error) + patternDeserializer func(context.Context, string) (*protection.Pattern, error) +) + +func (migrate *Rule) registerDeserializers(principalStore store.PrincipalStore) { + // banch rules definition deserializer + migrate.DefDeserializationMap[ExternalRuleTypeBranch] = func( + ctx context.Context, + rawDef string, + ) (protection.Definition, error) { + // deserialize string into external branch rule type + var extrDef ExternalDefinition + + decoder := json.NewDecoder(bytes.NewReader([]byte(rawDef))) + if err := decoder.Decode(&extrDef); err != nil { + return nil, fmt.Errorf("failed to decode external branch rule definition: %w", err) + } + + rule, err := mapToBranchRules(ctx, extrDef, principalStore) + if err != nil { + return nil, fmt.Errorf("failed to map external branch rule definition to internal: %w", err) + } + + return rule, nil + } + + // branch rules pattern deserializer + migrate.PatternDeserializationMap[ExternalRuleTypeBranch] = func( + _ context.Context, + rawDef string, + ) (*protection.Pattern, error) { + var extrPattern ExternalBranchPattern + + decoder := json.NewDecoder(bytes.NewReader([]byte(rawDef))) + if err := decoder.Decode(&extrPattern); err != nil { + return nil, fmt.Errorf("failed to decode external branch rule pattern: %w", err) + } + + return &protection.Pattern{ + Default: extrPattern.Default, + Include: extrPattern.Include, + Exclude: extrPattern.Exclude, + }, nil + } +} diff --git a/app/services/migrate/webhook.go b/app/services/migrate/webhook.go new file mode 100644 index 000000000..4173218f5 --- /dev/null +++ b/app/services/migrate/webhook.go @@ -0,0 +1,129 @@ +// Copyright 2023 Harness, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package migrate + +import ( + "context" + "fmt" + "time" + + webhookpkg "github.com/harness/gitness/app/api/controller/webhook" + "github.com/harness/gitness/app/services/webhook" + "github.com/harness/gitness/app/store" + "github.com/harness/gitness/store/database/dbtx" + "github.com/harness/gitness/types" + "github.com/harness/gitness/types/check" + "github.com/harness/gitness/types/enum" +) + +// Webhook is webhook migrate. +type Webhook struct { + // webhook configs + allowLoopback bool + allowPrivateNetwork bool + + tx dbtx.Transactor + webhookStore store.WebhookStore +} + +func NewWebhook( + config webhook.Config, + tx dbtx.Transactor, + webhookStore store.WebhookStore, +) *Webhook { + return &Webhook{ + allowLoopback: config.AllowLoopback, + allowPrivateNetwork: config.AllowPrivateNetwork, + tx: tx, + webhookStore: webhookStore, + } +} + +func (migrate Webhook) Import( + ctx context.Context, + migrator types.Principal, + repo *types.Repository, + extWebhooks []*ExternalWebhook, +) ([]*types.Webhook, error) { + now := time.Now().UnixMilli() + hooks := make([]*types.Webhook, len(extWebhooks)) + + // sanitize and convert webhooks + for i, whook := range extWebhooks { + triggers := webhookpkg.ConvertTriggers(whook.Events) + err := sanitizeWebhook(whook, triggers, migrate.allowLoopback, migrate.allowPrivateNetwork) + if err != nil { + return nil, fmt.Errorf("failed to sanitize external webhook input: %w", err) + } + + // create new webhook object + hook := &types.Webhook{ + ID: 0, // the ID will be populated in the data layer + Version: 0, // the Version will be populated in the data layer + CreatedBy: migrator.ID, + Created: now, + Updated: now, + ParentID: repo.ID, + ParentType: enum.WebhookParentRepo, + + // user input + Identifier: whook.Identifier, + DisplayName: whook.Identifier, + URL: whook.Target, + Enabled: whook.Active, + Insecure: whook.SkipVerify, + Triggers: webhookpkg.DeduplicateTriggers(triggers), + LatestExecutionResult: nil, + } + + hooks[i] = hook + } + + err := migrate.tx.WithTx(ctx, func(ctx context.Context) error { + for _, hook := range hooks { + err := migrate.webhookStore.Create(ctx, hook) + if err != nil { + return fmt.Errorf("failed to store webhook: %w", err) + } + } + return nil + }) + if err != nil { + return nil, fmt.Errorf("failed to store external webhooks: %w", err) + } + + return hooks, nil +} + +func sanitizeWebhook( + in *ExternalWebhook, + triggers []enum.WebhookTrigger, + allowLoopback bool, + allowPrivateNetwork bool, +) error { + if err := check.Identifier(in.Identifier); err != nil { + return err + } + + if err := webhookpkg.CheckURL(in.Target, allowLoopback, allowPrivateNetwork); err != nil { + return err + } + + if err := webhookpkg.CheckTriggers(triggers); err != nil { //nolint:revive + return err + } + + return nil +} diff --git a/app/services/importer/pullreq_types.go b/app/services/migrate/webhook_type.go similarity index 68% rename from app/services/importer/pullreq_types.go rename to app/services/migrate/webhook_type.go index 577449496..086721bdc 100644 --- a/app/services/importer/pullreq_types.go +++ b/app/services/migrate/webhook_type.go @@ -12,16 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. -package importer +package migrate -import ( - migratetypes "github.com/harness/harness-migrate/types" +import migratetypes "github.com/harness/harness-migrate/types" + +type ( + ExternalWebhook = migratetypes.Hook ) - -type ExternalPullRequest = migratetypes.PullRequestData -type ExternalComment = migratetypes.Comment - -type externalCommentThread struct { - TopLevel ExternalComment - Replies []ExternalComment -} diff --git a/app/services/migrate/wire.go b/app/services/migrate/wire.go new file mode 100644 index 000000000..98980d637 --- /dev/null +++ b/app/services/migrate/wire.go @@ -0,0 +1,59 @@ +// Copyright 2023 Harness, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package migrate + +import ( + "github.com/harness/gitness/app/services/webhook" + "github.com/harness/gitness/app/store" + "github.com/harness/gitness/app/url" + "github.com/harness/gitness/git" + "github.com/harness/gitness/store/database/dbtx" + + "github.com/google/wire" +) + +var WireSet = wire.NewSet( + ProvidePullReqImporter, + ProvideRuleImporter, + ProvideWebhookImporter, +) + +func ProvidePullReqImporter( + urlProvider url.Provider, + git git.Interface, + principalStore store.PrincipalStore, + repoStore store.RepoStore, + pullReqStore store.PullReqStore, + pullReqActStore store.PullReqActivityStore, + tx dbtx.Transactor, +) *PullReq { + return NewPullReq(urlProvider, git, principalStore, repoStore, pullReqStore, pullReqActStore, tx) +} + +func ProvideRuleImporter( + ruleStore store.RuleStore, + tx dbtx.Transactor, + principalStore store.PrincipalStore, +) *Rule { + return NewRule(ruleStore, tx, principalStore) +} + +func ProvideWebhookImporter( + config webhook.Config, + tx dbtx.Transactor, + webhookStore store.WebhookStore, +) *Webhook { + return NewWebhook(config, tx, webhookStore) +} diff --git a/cmd/gitness/wire.go b/cmd/gitness/wire.go index d77c098a3..c9cf2944e 100644 --- a/cmd/gitness/wire.go +++ b/cmd/gitness/wire.go @@ -74,6 +74,7 @@ import ( svclabel "github.com/harness/gitness/app/services/label" locker "github.com/harness/gitness/app/services/locker" "github.com/harness/gitness/app/services/metric" + migrateservice "github.com/harness/gitness/app/services/migrate" "github.com/harness/gitness/app/services/notification" "github.com/harness/gitness/app/services/notification/mailer" "github.com/harness/gitness/app/services/protection" @@ -203,6 +204,7 @@ func initSystem(ctx context.Context, config *types.Config) (*cliserver.System, e plugin.WireSet, resolver.WireSet, importer.WireSet, + migrateservice.WireSet, canceler.WireSet, exporter.WireSet, metric.WireSet, diff --git a/cmd/gitness/wire_gen.go b/cmd/gitness/wire_gen.go index 99d2900f6..1682fca33 100644 --- a/cmd/gitness/wire_gen.go +++ b/cmd/gitness/wire_gen.go @@ -18,7 +18,7 @@ import ( keywordsearch2 "github.com/harness/gitness/app/api/controller/keywordsearch" "github.com/harness/gitness/app/api/controller/limiter" logs2 "github.com/harness/gitness/app/api/controller/logs" - "github.com/harness/gitness/app/api/controller/migrate" + migrate2 "github.com/harness/gitness/app/api/controller/migrate" "github.com/harness/gitness/app/api/controller/pipeline" "github.com/harness/gitness/app/api/controller/plugin" "github.com/harness/gitness/app/api/controller/principal" @@ -75,6 +75,7 @@ import ( "github.com/harness/gitness/app/services/label" "github.com/harness/gitness/app/services/locker" "github.com/harness/gitness/app/services/metric" + "github.com/harness/gitness/app/services/migrate" "github.com/harness/gitness/app/services/notification" "github.com/harness/gitness/app/services/notification/mailer" "github.com/harness/gitness/app/services/protection" @@ -302,7 +303,7 @@ func initSystem(ctx context.Context, config *types.Config) (*server.System, erro if err != nil { return nil, err } - pullReq := importer.ProvidePullReqImporter(provider, gitInterface, principalStore, repoStore, pullReqStore, pullReqActivityStore, transactor) + pullReq := migrate.ProvidePullReqImporter(provider, gitInterface, principalStore, repoStore, pullReqStore, pullReqActivityStore, transactor) pullreqController := pullreq2.ProvideController(transactor, provider, authorizer, pullReqStore, pullReqActivityStore, codeCommentView, pullReqReviewStore, pullReqReviewerStore, repoStore, principalStore, principalInfoCache, pullReqFileViewStore, membershipStore, checkStore, gitInterface, reporter2, migrator, pullreqService, protectionManager, streamer, codeownersService, lockerLocker, pullReq, labelService) webhookConfig := server.ProvideWebhookConfig(config) webhookStore := database.ProvideWebhookStore(db) @@ -366,7 +367,9 @@ func initSystem(ctx context.Context, config *types.Config) (*server.System, erro orchestratorOrchestrator := orchestrator.ProvideOrchestrator(scmSCM, infraProviderResourceStore, infraProvisioner, containerOrchestrator, reporter4, orchestratorConfig, vsCode, vsCodeWeb) gitspaceEventStore := database.ProvideGitspaceEventStore(db) gitspaceController := gitspace2.ProvideController(transactor, authorizer, infraproviderService, gitspaceConfigStore, gitspaceInstanceStore, spaceStore, reporter4, orchestratorOrchestrator, gitspaceEventStore, statefulLogger, scmSCM, repoStore, gitspaceService) - migrateController := migrate.ProvideController(authorizer, principalStore) + rule := migrate.ProvideRuleImporter(ruleStore, transactor, principalStore) + migrateWebhook := migrate.ProvideWebhookImporter(webhookConfig, transactor, webhookStore) + migrateController := migrate2.ProvideController(authorizer, publicaccessService, gitInterface, provider, pullReq, rule, migrateWebhook, resourceLimiter, auditService, repoIdentifier, transactor, spaceStore, repoStore) openapiService := openapi.ProvideOpenAPIService() routerRouter := router.ProvideRouter(ctx, config, authenticator, repoController, reposettingsController, executionController, logsController, spaceController, pipelineController, secretController, triggerController, connectorController, templateController, pluginController, pullreqController, webhookController, githookController, gitInterface, serviceaccountController, controller, principalController, checkController, systemController, uploadController, keywordsearchController, infraproviderController, gitspaceController, migrateController, provider, openapiService) serverServer := server2.ProvideServer(config, routerRouter) diff --git a/go.mod b/go.mod index fb2d32802..f5d61dc7e 100644 --- a/go.mod +++ b/go.mod @@ -18,7 +18,7 @@ require ( github.com/drone/funcmap v0.0.0-20240227160611-7e19e9cd5a1c github.com/drone/go-convert v0.0.0-20240307072510-6bd371c65e61 github.com/drone/go-generate v1.1.0 - github.com/drone/go-scm v1.38.2 + github.com/drone/go-scm v1.38.4 github.com/drone/runner-go v1.12.0 github.com/drone/spec v0.0.0-20230920145636-3827abdce961 github.com/fatih/color v1.17.0 @@ -36,7 +36,7 @@ require ( github.com/gorhill/cronexpr v0.0.0-20180427100037-88b0669f7d75 github.com/gotidy/ptr v1.4.0 github.com/guregu/null v4.0.0+incompatible - github.com/harness/harness-migrate v0.21.1-0.20240703163651-0641dc7290d8 + github.com/harness/harness-migrate v0.21.1-0.20240804180936-b1de602aa8e7 github.com/hashicorp/go-multierror v1.1.1 github.com/jmoiron/sqlx v1.4.0 github.com/joho/godotenv v1.5.1 @@ -80,6 +80,10 @@ require ( github.com/99designs/httpsignatures-go v0.0.0-20170731043157-88528bf4ca7e // indirect github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect github.com/BobuSumisu/aho-corasick v1.0.3 // indirect + github.com/ProtonMail/go-crypto v0.0.0-20221026131551-cf6655e29de4 // indirect + github.com/acomagu/bufpipe v1.0.3 // indirect + github.com/alecthomas/chroma v0.10.0 // indirect + github.com/alecthomas/kingpin/v2 v2.4.0 // indirect github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be // indirect github.com/antonmedv/expr v1.15.5 // indirect github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect @@ -90,15 +94,21 @@ require ( github.com/cenkalti/backoff/v4 v4.2.0 // indirect github.com/charmbracelet/lipgloss v0.12.1 // indirect github.com/charmbracelet/x/ansi v0.1.4 // indirect + github.com/cloudflare/circl v1.3.3 // indirect github.com/distribution/reference v0.6.0 // indirect + github.com/dlclark/regexp2 v1.4.0 // indirect github.com/docker/distribution v2.7.1+incompatible // indirect github.com/docker/go-units v0.5.0 // indirect github.com/drone/envsubst v1.0.3 // indirect + github.com/emirpasic/gods v1.18.1 // indirect github.com/fatih/semgroup v1.2.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/ghodss/yaml v1.0.0 // indirect github.com/gitleaks/go-gitdiff v0.9.0 // indirect + github.com/go-git/gcfg v1.5.0 // indirect + github.com/go-git/go-billy/v5 v5.4.0 // indirect + github.com/go-git/go-git/v5 v5.5.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect @@ -107,11 +117,15 @@ require ( github.com/googleapis/gax-go/v2 v2.13.0 // indirect github.com/h2non/filetype v1.1.3 // indirect github.com/hashicorp/hcl v1.0.0 // indirect + github.com/imdario/mergo v0.3.13 // indirect github.com/jackc/pgx/v4 v4.12.0 // indirect + github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect + github.com/kevinburke/ssh_config v1.2.0 // indirect github.com/lucasb-eyer/go-colorful v1.2.0 // indirect github.com/magiconair/properties v1.8.7 // indirect github.com/mattn/go-runewidth v0.0.16 // indirect + github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect github.com/muesli/termenv v0.15.2 // indirect @@ -121,6 +135,7 @@ require ( github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.1.0 // indirect github.com/pelletier/go-toml/v2 v2.2.2 // indirect + github.com/pjbgf/sha1cd v0.2.3 // indirect github.com/prometheus/client_golang v1.19.1 // indirect github.com/prometheus/client_model v0.6.1 // indirect github.com/prometheus/common v0.55.0 // indirect @@ -129,12 +144,17 @@ require ( github.com/rogpeppe/go-internal v1.11.0 // indirect github.com/sagikazarmark/locafero v0.6.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect + github.com/schollz/progressbar/v3 v3.13.0 // indirect + github.com/sergi/go-diff v1.3.1 // indirect + github.com/skeema/knownhosts v1.1.0 // indirect github.com/sourcegraph/conc v0.3.0 // 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.19.0 // indirect github.com/subosito/gotenv v1.6.0 // indirect + github.com/xanzy/ssh-agent v0.3.3 // indirect + github.com/xhit/go-str2duration/v2 v2.1.0 // indirect go.opencensus.io v0.24.0 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.51.0 // indirect @@ -150,6 +170,7 @@ require ( google.golang.org/protobuf v1.34.2 // indirect gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect gopkg.in/ini.v1 v1.67.0 // indirect + gopkg.in/warnings.v0 v0.1.2 // indirect sigs.k8s.io/yaml v1.4.0 // indirect ) diff --git a/go.sum b/go.sum index 395804e69..b56110905 100644 --- a/go.sum +++ b/go.sum @@ -34,14 +34,23 @@ github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0 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.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA= +github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= +github.com/ProtonMail/go-crypto v0.0.0-20221026131551-cf6655e29de4 h1:ra2OtmuW0AE5csawV4YXMNGNQQXvLRps3z2Z59OPO+I= +github.com/ProtonMail/go-crypto v0.0.0-20221026131551-cf6655e29de4/go.mod h1:UBYPn8k0D56RtnR8RFQMjmh4KrZzWJ5o7Z9SYjossQ8= github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= +github.com/acomagu/bufpipe v1.0.3 h1:fxAGrHZTgQ9w5QqVItgzwj235/uYZYgbXitB+dLupOk= +github.com/acomagu/bufpipe v1.0.3/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4= github.com/adrg/xdg v0.5.0 h1:dDaZvhMXatArP1NPHhnfaQUqWBLBsmx1h1HXQdMoFCY= github.com/adrg/xdg v0.5.0/go.mod h1:dDdY4M4DF9Rjy4kHPeNL+ilVF+p2lK8IdM9/rTSGcI4= github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= +github.com/alecthomas/chroma v0.10.0 h1:7XDcGkCQopCNKjZHfYrNLraA+M7e0fMiJ/Mfikbfjek= +github.com/alecthomas/chroma v0.10.0/go.mod h1:jtJATyUxlIORhUOFNA9NZDWGAQ8wpxQQqNSB4rjA/1s= +github.com/alecthomas/kingpin/v2 v2.4.0 h1:f48lwail6p8zpO1bC4TxtqACaGqHYA22qkHjHpqDjYY= +github.com/alecthomas/kingpin/v2 v2.4.0/go.mod h1:0gyi0zQnjuFk8xrkNKamJoyUo382HRL7ATRpFZCw6tE= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= @@ -60,6 +69,7 @@ github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A= github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= @@ -86,6 +96,7 @@ github.com/bradrydzewski/spec v1.0.2 h1:spQ8nLjsV4IFieEqHAnob5S4Vfx+0EQG/L91mVVr github.com/bradrydzewski/spec v1.0.2/go.mod h1:ZrrxQBqUvBoqAaH9ClsskjE3LPMHra+NbKdqDIQqRNQ= github.com/buildkite/yaml v2.1.0+incompatible h1:xirI+ql5GzfikVNDmt+yeiXpf/v1Gt03qXTtT5WXdr8= github.com/buildkite/yaml v2.1.0+incompatible/go.mod h1:UoU8vbcwu1+vjZq01+KrpSeLBgQQIjL/H7Y6KwikUrI= +github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/cenkalti/backoff/v4 v4.2.0 h1:HN5dHm3WBOgndBH6E8V0q2jIYIR3s9yglV8k/+MN3u4= @@ -100,6 +111,9 @@ github.com/charmbracelet/x/ansi v0.1.4 h1:IEU3D6+dWwPSgZ6HBH+v6oUuZ/nVawMiWj5831 github.com/charmbracelet/x/ansi v0.1.4/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw= github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cloudflare/circl v1.1.0/go.mod h1:prBCrKB9DV4poKZY1l9zBXg2QJY7mvgRvtMxxK7fi4I= +github.com/cloudflare/circl v1.3.3 h1:fE/Qz0QdIGqeWfnwq0RE0R7MI51s0M2E4Ga9kq5AEMs= +github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= @@ -117,6 +131,7 @@ github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSV github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= 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/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= @@ -133,6 +148,8 @@ github.com/djherbis/buffer v1.2.0 h1:PH5Dd2ss0C7CRRhQCZ2u7MssF+No9ide8Ye71nPHcrQ github.com/djherbis/buffer v1.2.0/go.mod h1:fjnebbZjCUpPinBRD+TDwXSOeNQ7fPQWLfGQqiAiUyE= github.com/djherbis/nio/v3 v3.0.1 h1:6wxhnuppteMa6RHA4L81Dq7ThkZH8SwnDzXDYy95vB4= github.com/djherbis/nio/v3 v3.0.1/go.mod h1:Ng4h80pbZFMla1yKzm61cF0tqqilXZYrogmWgZxOcmg= +github.com/dlclark/regexp2 v1.4.0 h1:F1rxgk7p4uKjwIQxBs9oAXe5CqrXlCduYEJvrF4u93E= +github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= github.com/docker/distribution v0.0.0-20170726174610-edc3ab29cdff/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug= github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= @@ -163,6 +180,8 @@ github.com/drone/go-generate v1.1.0 h1:JoWB4emGS/hlIaKNlcI1Amjvm5ajub1lqocLHMSwu github.com/drone/go-generate v1.1.0/go.mod h1:rnOS/ww//Mz5XM88u6+xT3Bd2ftJdYAYi1k2vtGUkUQ= github.com/drone/go-scm v1.38.2 h1:u8fEuz2vbcn5y93YPiT0nkcmQKKAxNuL08N0xuHCLTY= github.com/drone/go-scm v1.38.2/go.mod h1:DFIJJjhMj0TSXPz+0ni4nyZ9gtTtC40Vh/TGRugtyWw= +github.com/drone/go-scm v1.38.4 h1:KW+znh2tg3tJwbiFfzhjZQ2gbyasJ213V7hZ00QaVpc= +github.com/drone/go-scm v1.38.4/go.mod h1:DFIJJjhMj0TSXPz+0ni4nyZ9gtTtC40Vh/TGRugtyWw= github.com/drone/runner-go v1.12.0 h1:zUjDj9ylsJ4n4Mvy4znddq/Z4EBzcUXzTltpzokKtgs= github.com/drone/runner-go v1.12.0/go.mod h1:vu4pPPYDoeN6vdYQAY01GGGsAIW4aLganJNaa8Fx8zE= github.com/drone/signal v1.0.0/go.mod h1:S8t92eFT0g4WUgEc/LxG+LCuiskpMNsG0ajAMGnyZpc= @@ -173,6 +192,8 @@ github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5m github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= +github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= +github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g= 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= @@ -198,12 +219,21 @@ github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gitleaks/go-gitdiff v0.9.0 h1:SHAU2l0ZBEo8g82EeFewhVy81sb7JCxW76oSPtR/Nqg= github.com/gitleaks/go-gitdiff v0.9.0/go.mod h1:pKz0X4YzCKZs30BL+weqBIG7mx0jl4tF1uXV9ZyNvrA= +github.com/gliderlabs/ssh v0.3.5/go.mod h1:8XB4KraRrX39qHhT6yxPsHedjA08I/uBVwj4xC+/+z4= github.com/gliderlabs/ssh v0.3.7 h1:iV3Bqi942d9huXnzEF2Mt+CY9gLu8DNM4Obd+8bODRE= github.com/gliderlabs/ssh v0.3.7/go.mod h1:zpHEXBstFnQYtGnB8k8kQLol82umzn/2/snG7alWVD8= github.com/go-chi/chi v1.5.5 h1:vOB/HbEMt9QqBqErz07QehcOKHaWFtuj87tTDVz2qXE= github.com/go-chi/chi v1.5.5/go.mod h1:C9JqLr3tIYjDOZpzn+BCuxY8z8vmca43EeMgyZt7irw= github.com/go-chi/cors v1.2.1 h1:xEC8UT3Rlp2QuWNEr4Fs/c2EAGVKBwy/1vHx3bppil4= github.com/go-chi/cors v1.2.1/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58= +github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4= +github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E= +github.com/go-git/go-billy/v5 v5.3.1/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= +github.com/go-git/go-billy/v5 v5.4.0 h1:Vaw7LaSTRJOUric7pe4vnzBSgyuf2KrLsu2Y4ZpQBDE= +github.com/go-git/go-billy/v5 v5.4.0/go.mod h1:vjbugF6Fz7JIflbVpl1hJsGjSHNltrSw45YK/ukIvQg= +github.com/go-git/go-git-fixtures/v4 v4.3.1/go.mod h1:8LHG1a3SRW71ettAD/jW13h8c6AqjVSeL11RAdgaqpo= +github.com/go-git/go-git/v5 v5.5.2 h1:v8lgZa5k9ylUw+OR/roJHTxR4QItsNFI5nKtAXFuynw= +github.com/go-git/go-git/v5 v5.5.2/go.mod h1:BE5hUJ5yaV2YMxhmaP4l6RBQ08kMxKSPD4BlxtH7OjI= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o= @@ -328,6 +358,10 @@ github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 h1:2VTzZjLZBgl62/EtslC github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI= github.com/harness/harness-migrate v0.21.1-0.20240703163651-0641dc7290d8 h1:X0/Nk9aCkIKoF3kavxZcr9EtfARSBqnJK33c59m+xmw= github.com/harness/harness-migrate v0.21.1-0.20240703163651-0641dc7290d8/go.mod h1:HiUX39ZfhBGY+OkEEN6JpglbodNJlbzayOt/l3nkk6w= +github.com/harness/harness-migrate v0.21.1-0.20240801225636-542cd216f84e h1:Do+0drtv74/mOkXo07mj9JMIn6jy6dDlK6FrRW7pgpI= +github.com/harness/harness-migrate v0.21.1-0.20240801225636-542cd216f84e/go.mod h1:DSqjRv/0GKxBTkqgayOOX/rIktw9KTIBMxJUvHdZK4Q= +github.com/harness/harness-migrate v0.21.1-0.20240804180936-b1de602aa8e7 h1:hvQPC9k0V4tSYccVLqYFbT7HPH9kzwRqcInfbK6z7ag= +github.com/harness/harness-migrate v0.21.1-0.20240804180936-b1de602aa8e7/go.mod h1:hlyMG5yMpTUesICvSYz61mInT+dMGN7HdTujv+RHcgU= github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -359,6 +393,8 @@ github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmK github.com/iancoleman/orderedmap v0.3.0 h1:5cbR2grmZR/DiVt+VJopEhtVs9YGInGIxAoMJn+Ichc= github.com/iancoleman/orderedmap v0.3.0/go.mod h1:XuLcCUkdL5owUCQeF2Ue9uuw1EptkJDkXXS7VoV7XGE= github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk= +github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= github.com/jackc/chunkreader v1.0.0 h1:4s39bBR8ByfqH+DKm8rQA3E1LHZWB9XWcrz8fqaZbe0= @@ -419,6 +455,9 @@ github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0f github.com/jackc/puddle v1.1.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.1.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= +github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= +github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= @@ -435,8 +474,11 @@ github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/u github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= 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/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213/go.mod h1:vNUNkEQ1e29fT/6vq2aBdFsgNPmy8qMdSay1npru+Sw= github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8= github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg= +github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= +github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= 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= @@ -444,6 +486,7 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxv github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= @@ -475,6 +518,7 @@ github.com/matoous/go-nanoid v1.5.0 h1:VRorl6uCngneC4oUQqOYtO3S0H5QKFtKuKycFG3eu github.com/matoous/go-nanoid v1.5.0/go.mod h1:zyD2a71IubI24efhpvkJz+ZwfwagzgSO6UNiFsZKN7U= github.com/matoous/go-nanoid/v2 v2.1.0 h1:P64+dmq21hhWdtvZfEAofnvJULaRR1Yib0+PnU669bE= github.com/matoous/go-nanoid/v2 v2.1.0/go.mod h1:KlbGNQ+FhrUNIHUxZdL63t7tl4LaPkZNpUULS8H4uVM= +github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA= github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE= github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= @@ -491,10 +535,12 @@ github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hd github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= 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/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= 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/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mattn/go-sqlite3 v1.14.7/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= @@ -503,6 +549,8 @@ github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxU github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ= +github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= @@ -536,6 +584,7 @@ github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxzi github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs= @@ -573,6 +622,8 @@ github.com/petar/GoLLRB v0.0.0-20130427215148-53be0d36a84c/go.mod h1:HUpKUBZnpzk github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pjbgf/sha1cd v0.2.3 h1:uKQP/7QOzNtKYH7UTohZLcjF5/55EnTw0jO/Ru4jZwI= +github.com/pjbgf/sha1cd v0.2.3/go.mod h1:HOK9QrgzdHpbc2Kzip0Q1yi3M2MFGPADtR6HjG65m5M= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -612,6 +663,7 @@ github.com/redis/go-redis/v9 v9.5.1/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0 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.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rivo/uniseg v0.4.3/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= @@ -633,10 +685,13 @@ github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6g github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= +github.com/schollz/progressbar/v3 v3.13.0 h1:9TeeWRcjW2qd05I8Kf9knPkW4vLM/hYoa6z9ABvxje8= +github.com/schollz/progressbar/v3 v3.13.0/go.mod h1:ZBYnSuLAX2LU8P8UiKN/KgF2DY58AJC8yfVYLPC8Ly4= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/sercand/kuberesolver/v5 v5.1.1 h1:CYH+d67G0sGBj7q5wLK61yzqJJ8gLLC8aeprPTHb6yY= github.com/sercand/kuberesolver/v5 v5.1.1/go.mod h1:Fs1KbKhVRnB2aDWN12NjKCB+RgYMWZJ294T3BtmVCpQ= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= +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/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= @@ -646,8 +701,11 @@ github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeV github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= 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.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/skeema/knownhosts v1.1.0 h1:Wvr9V0MxhjRbl3f9nMnKnFfiWTJmtECJ9Njkea3ysW0= +github.com/skeema/knownhosts v1.1.0/go.mod h1:sKFq3RD6/TKZkSWn8boUbDC7Qkgcv+8XXijpFO6roag= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= @@ -695,8 +753,6 @@ github.com/swaggest/jsonschema-go v0.3.72 h1:IHaGlR1bdBUBPfhe4tfacN2TGAPKENEGiNy github.com/swaggest/jsonschema-go v0.3.72/go.mod h1:OrGyEoVqpfSFJ4Am4V/FQcQ3mlEC1vVeleA+5ggbVW4= github.com/swaggest/openapi-go v0.2.23 h1:DYUezSTyw180z1bL51wUnalYYbTMwHBjp1Itvji8/rs= github.com/swaggest/openapi-go v0.2.23/go.mod h1:T1Koc6EAFAvnCI1MUqOOPDniqGzZy6dOiHtA/j54k14= -github.com/swaggest/openapi-go v0.2.53 h1:lWHKgC9IN48nBYxvuBrmAVJgki/1xsrGZWaWJnOLenE= -github.com/swaggest/openapi-go v0.2.53/go.mod h1:2Q7NpuG9NgpGeTaNOo852GSR6cCzSP4IznA9DNdUTQw= github.com/swaggest/refl v1.3.0 h1:PEUWIku+ZznYfsoyheF97ypSduvMApYyGkYF3nabS0I= github.com/swaggest/refl v1.3.0/go.mod h1:3Ujvbmh1pfSbDYjC6JGG7nMgPvpG0ehQL4iNonnLNbg= github.com/swaggest/swgui v1.8.1 h1:OLcigpoelY0spbpvp6WvBt0I1z+E9egMQlUeEKya+zU= @@ -709,6 +765,11 @@ github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtX github.com/vearutop/statigz v1.4.0 h1:RQL0KG3j/uyA/PFpHeZ/L6l2ta920/MxlOAIGEOuwmU= github.com/vearutop/statigz v1.4.0/go.mod h1:LYTolBLiz9oJISwiVKnOQoIwhO1LWX1A7OECawGS8XE= github.com/vinzenz/yaml v0.0.0-20170920082545-91409cdd725d/go.mod h1:mb5taDqMnJiZNRQ3+02W2IFG+oEz1+dTuCXkp4jpkfo= +github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= +github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw= +github.com/xhit/go-str2duration v1.2.0 h1:BcV5u025cITWxEQKGWr1URRzrcXtu7uk8+luz3Yuhwc= +github.com/xhit/go-str2duration/v2 v2.1.0 h1:lxklc02Drh6ynqX+DdPyp5pCKLUQpRT8bp8Ydu2Bstc= +github.com/xhit/go-str2duration/v2 v2.1.0/go.mod h1:ohY8p+0f07DiV6Em5LKB0s2YpLtXVyJfNt1+BlmyAsU= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/yudai/gojsondiff v1.0.0 h1:27cbfqXLVEJ1o8I6v3y9lg8Ydm53EKqHXAOMxEGlCOA= github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg= @@ -749,8 +810,6 @@ go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lI go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= go.starlark.net v0.0.0-20231121155337-90ade8b19d09 h1:hzy3LFnSN8kuQK8h9tHl4ndF6UruMj47OqwqsS+/Ai4= go.starlark.net v0.0.0-20231121155337-90ade8b19d09/go.mod h1:LcLNIzVOMp4oV+uusnpk+VU+SzXaJakUuBjoCSWH5dM= -go.starlark.net v0.0.0-20240705175910-70002002b310 h1:tEAOMoNmN2MqVNi0MMEWpTtPI4YNCXgxmAGtuv3mST0= -go.starlark.net v0.0.0-20240705175910-70002002b310/go.mod h1:YKMCv9b1WrfWmeqdV5MAuEHWsu5iC+fe6kYl2sQjdI8= 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.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= @@ -782,6 +841,10 @@ golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220826181053-bd7e27e6170d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30= @@ -825,7 +888,10 @@ golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= @@ -872,14 +938,24 @@ golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 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-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/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-20210616094352-59db8d763f22/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-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/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-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.4.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= @@ -890,6 +966,9 @@ golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.0.0-20220722155259-a9ba230a4035/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= +golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= @@ -902,6 +981,7 @@ 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.4.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= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= @@ -993,6 +1073,8 @@ gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gG gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk= 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-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/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/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= @@ -1008,14 +1090,17 @@ gopkg.in/mail.v2 v2.3.1/go.mod h1:htwXN1Qh09vZJ1NVKxQqHPBaCBbzKhp5GzuJEA4VJWw= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0/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= gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU=