fix cleanup for failed repo create, cleanup summary git api (#2064)

This commit is contained in:
Johannes Batzill 2024-05-24 00:38:29 +00:00 committed by Harness
parent cc471d0876
commit bc568edd85
13 changed files with 62 additions and 101 deletions

View File

@ -125,7 +125,7 @@ func (c *Controller) Create(ctx context.Context, session *auth.Session, in *Crea
}, sql.TxOptions{Isolation: sql.LevelSerializable}) }, sql.TxOptions{Isolation: sql.LevelSerializable})
if err != nil { if err != nil {
// best effort cleanup // best effort cleanup
if dErr := c.DeleteGitRepository(ctx, session, repo); dErr != nil { if dErr := c.DeleteGitRepository(ctx, session, gitResp.UID); dErr != nil {
log.Ctx(ctx).Warn().Err(dErr).Msg("failed to delete repo for cleanup") log.Ctx(ctx).Warn().Err(dErr).Msg("failed to delete repo for cleanup")
} }
return nil, err return nil, err

View File

@ -19,10 +19,10 @@ import (
"fmt" "fmt"
apiauth "github.com/harness/gitness/app/api/auth" apiauth "github.com/harness/gitness/app/api/auth"
"github.com/harness/gitness/app/api/controller"
"github.com/harness/gitness/app/api/usererror" "github.com/harness/gitness/app/api/usererror"
"github.com/harness/gitness/app/auth" "github.com/harness/gitness/app/auth"
repoevents "github.com/harness/gitness/app/events/repo" repoevents "github.com/harness/gitness/app/events/repo"
"github.com/harness/gitness/app/githook"
"github.com/harness/gitness/errors" "github.com/harness/gitness/errors"
"github.com/harness/gitness/git" "github.com/harness/gitness/git"
"github.com/harness/gitness/types" "github.com/harness/gitness/types"
@ -76,7 +76,7 @@ func (c *Controller) PurgeNoAuth(
return fmt.Errorf("failed to delete repo from db: %w", err) return fmt.Errorf("failed to delete repo from db: %w", err)
} }
if err := c.DeleteGitRepository(ctx, session, repo); err != nil { if err := c.DeleteGitRepository(ctx, session, repo.GitUID); err != nil {
log.Ctx(ctx).Err(err).Msg("failed to remove git repository") log.Ctx(ctx).Err(err).Msg("failed to remove git repository")
} }
@ -92,11 +92,27 @@ func (c *Controller) PurgeNoAuth(
func (c *Controller) DeleteGitRepository( func (c *Controller) DeleteGitRepository(
ctx context.Context, ctx context.Context,
session *auth.Session, session *auth.Session,
repo *types.Repository, gitUID string,
) error { ) error {
writeParams, err := controller.CreateRPCInternalWriteParams(ctx, c.urlProvider, session, repo) // create custom write params for delete as repo might or might not exist in db (similar to create).
envVars, err := githook.GenerateEnvironmentVariables(
ctx,
c.urlProvider.GetInternalAPIURL(),
0, // no repoID
session.Principal.ID,
true,
true,
)
if err != nil { if err != nil {
return fmt.Errorf("failed to create RPC write params: %w", err) return fmt.Errorf("failed to generate git hook environment variables: %w", err)
}
writeParams := git.WriteParams{
Actor: git.Identity{
Name: session.Principal.DisplayName,
Email: session.Principal.Email,
},
RepoUID: gitUID,
EnvVars: envVars,
} }
err = c.git.DeleteRepository(ctx, &git.DeleteRepositoryParams{ err = c.git.DeleteRepository(ctx, &git.DeleteRepositoryParams{
@ -105,10 +121,10 @@ func (c *Controller) DeleteGitRepository(
// deletion should not fail if repo dir does not exist. // deletion should not fail if repo dir does not exist.
if errors.IsNotFound(err) { if errors.IsNotFound(err) {
log.Ctx(ctx).Warn().Str("repo.git_uid", repo.GitUID). log.Ctx(ctx).Warn().Str("repo.git_uid", gitUID).
Msg("git repository directory does not exist") Msg("git repository directory does not exist")
} else if err != nil { } else if err != nil {
return fmt.Errorf("failed to remove git repository %s: %w", repo.GitUID, err) return fmt.Errorf("failed to remove git repository %s: %w", gitUID, err)
} }
return nil return nil
} }

View File

@ -35,7 +35,7 @@ func (c *Controller) Summary(
return nil, fmt.Errorf("access check failed: %w", err) return nil, fmt.Errorf("access check failed: %w", err)
} }
summary, err := c.git.Summary(ctx, &git.ReadParams{RepoUID: repo.GitUID}) summary, err := c.git.Summary(ctx, git.SummaryParams{ReadParams: git.CreateReadParams(repo)})
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to get repo summary: %w", err) return nil, fmt.Errorf("failed to get repo summary: %w", err)
} }

View File

@ -80,7 +80,7 @@ func (c *Controller) PurgeNoAuth(
// permanently purge all repositories in the space and its subspaces after successful space purge tnx. // permanently purge all repositories in the space and its subspaces after successful space purge tnx.
// cleanup will handle failed repository deletions. // cleanup will handle failed repository deletions.
for _, repo := range toBeDeletedRepos { for _, repo := range toBeDeletedRepos {
err := c.repoCtrl.DeleteGitRepository(ctx, session, repo) err := c.repoCtrl.DeleteGitRepository(ctx, session, repo.GitUID)
if err != nil { if err != nil {
log.Ctx(ctx).Warn().Err(err). log.Ctx(ctx).Warn().Err(err).
Str("repo_identifier", repo.Identifier). Str("repo_identifier", repo.Identifier).

View File

@ -29,6 +29,7 @@ import (
// Attempt returns an http.HandlerFunc middleware that authenticates // Attempt returns an http.HandlerFunc middleware that authenticates
// the http.Request if authentication payload is available. // the http.Request if authentication payload is available.
// Otherwise, an anonymous user session is used instead.
func Attempt(authenticator authn.Authenticator) func(http.Handler) http.Handler { func Attempt(authenticator authn.Authenticator) func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler { return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {

View File

@ -55,7 +55,7 @@ func (a *MembershipAuthorizer) Check(
resource *types.Resource, resource *types.Resource,
permission enum.Permission, permission enum.Permission,
) (bool, error) { ) (bool, error) {
publicAccessAllowed, err := a.CheckPublicAccess(ctx, scope, resource, permission) publicAccessAllowed, err := CheckPublicAccess(ctx, a.publicAccess, scope, resource, permission)
if err != nil { if err != nil {
return false, fmt.Errorf("failed to check public access: %w", err) return false, fmt.Errorf("failed to check public access: %w", err)
} }
@ -64,15 +64,6 @@ func (a *MembershipAuthorizer) Check(
return true, nil return true, nil
} }
if session == nil {
log.Ctx(ctx).Warn().Msgf(
"public access request for %s in scope %#v got to authorizer",
permission,
scope,
)
return false, nil
}
log.Ctx(ctx).Debug().Msgf( log.Ctx(ctx).Debug().Msgf(
"[MembershipAuthorizer] %s with id '%d' requests %s for %s '%s' in scope %#v with metadata %#v", "[MembershipAuthorizer] %s with id '%d' requests %s for %s '%s' in scope %#v with metadata %#v",
session.Principal.Type, session.Principal.Type,

View File

@ -16,34 +16,43 @@ package authz
import ( import (
"context" "context"
"fmt"
"github.com/harness/gitness/app/paths" "github.com/harness/gitness/app/paths"
"github.com/harness/gitness/app/services/publicaccess"
"github.com/harness/gitness/types" "github.com/harness/gitness/types"
"github.com/harness/gitness/types/enum" "github.com/harness/gitness/types/enum"
) )
func (a *MembershipAuthorizer) CheckPublicAccess( // CheckPublicAccess checks if the requested permission is public for the provided scope and resource.
func CheckPublicAccess(
ctx context.Context, ctx context.Context,
publicAccess publicaccess.Service,
scope *types.Scope, scope *types.Scope,
resource *types.Resource, resource *types.Resource,
permission enum.Permission, permission enum.Permission,
) (bool, error) { ) (bool, error) {
var pubResType enum.PublicResourceType var pubResType enum.PublicResourceType
var pubResPath string
//nolint:exhaustive //nolint:exhaustive
switch resource.Type { switch resource.Type {
case enum.ResourceTypeSpace: case enum.ResourceTypeSpace:
pubResType = enum.PublicResourceTypeSpace pubResType = enum.PublicResourceTypeSpace
pubResPath = paths.Concatenate(scope.SpacePath, resource.Identifier)
case enum.ResourceTypeRepo: case enum.ResourceTypeRepo:
if resource.Identifier != "" { if resource.Identifier != "" {
pubResType = enum.PublicResourceTypeRepo pubResType = enum.PublicResourceTypeRepo
pubResPath = paths.Concatenate(scope.SpacePath, resource.Identifier)
} else { // for spaceScope checks } else { // for spaceScope checks
pubResType = enum.PublicResourceTypeSpace pubResType = enum.PublicResourceTypeSpace
pubResPath = scope.SpacePath
} }
case enum.ResourceTypePipeline: case enum.ResourceTypePipeline:
pubResType = enum.PublicResourceTypeRepo pubResType = enum.PublicResourceTypeRepo
pubResPath = paths.Concatenate(scope.SpacePath, scope.Repo)
default: default:
return false, nil return false, nil
@ -61,7 +70,10 @@ func (a *MembershipAuthorizer) CheckPublicAccess(
return false, nil return false, nil
} }
pubResPath := paths.Concatenate(scope.SpacePath, resource.Identifier) resourceIsPublic, err := publicAccess.Get(ctx, pubResType, pubResPath)
if err != nil {
return false, fmt.Errorf("failed to check public accessabillity of %s %q: %w", pubResType, pubResPath, err)
}
return a.publicAccess.Get(ctx, pubResType, pubResPath) return resourceIsPublic, nil
} }

View File

@ -1,63 +0,0 @@
// 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 authz
import (
"context"
"github.com/harness/gitness/app/auth"
"github.com/harness/gitness/types"
"github.com/harness/gitness/types/enum"
"github.com/rs/zerolog/log"
)
var _ Authorizer = (*UnsafeAuthorizer)(nil)
/*
* An unsafe authorizer that gives permits any action and simply logs the permission request.
*/
type UnsafeAuthorizer struct{}
func NewUnsafeAuthorizer() *UnsafeAuthorizer {
return &UnsafeAuthorizer{}
}
func (a *UnsafeAuthorizer) Check(ctx context.Context, session *auth.Session,
scope *types.Scope, resource *types.Resource, permission enum.Permission) (bool, error) {
log.Ctx(ctx).Info().Msgf(
"[Authz] %s with id '%d' requests %s for %s '%s' in scope %#v with metadata %#v",
session.Principal.Type,
session.Principal.ID,
permission,
resource.Type,
resource.Identifier,
scope,
session.Metadata,
)
return true, nil
}
func (a *UnsafeAuthorizer) CheckAll(ctx context.Context, session *auth.Session,
permissionChecks ...types.PermissionCheck) (bool, error) {
for i := range permissionChecks {
p := permissionChecks[i]
if _, err := a.Check(ctx, session, &p.Scope, &p.Resource, p.Permission); err != nil {
return false, err
}
}
return true, nil
}

View File

@ -36,8 +36,11 @@ type converter struct {
publicAccess publicaccess.Service publicAccess publicaccess.Service
} }
func newConverter(fileService file.Service) Service { func newConverter(fileService file.Service, publicAccess publicaccess.Service) Service {
return &converter{fileService: fileService} return &converter{
fileService: fileService,
publicAccess: publicAccess,
}
} }
func (c *converter) Convert(ctx context.Context, args *ConvertArgs) (*file.File, error) { func (c *converter) Convert(ctx context.Context, args *ConvertArgs) (*file.File, error) {

View File

@ -16,6 +16,7 @@ package converter
import ( import (
"github.com/harness/gitness/app/pipeline/file" "github.com/harness/gitness/app/pipeline/file"
"github.com/harness/gitness/app/services/publicaccess"
"github.com/google/wire" "github.com/google/wire"
) )
@ -26,6 +27,6 @@ var WireSet = wire.NewSet(
) )
// ProvideService provides a service which can convert templates. // ProvideService provides a service which can convert templates.
func ProvideService(fileService file.Service) Service { func ProvideService(fileService file.Service, publicAccess publicaccess.Service) Service {
return newConverter(fileService) return newConverter(fileService, publicAccess)
} }

View File

@ -213,7 +213,7 @@ func initSystem(ctx context.Context, config *types.Config) (*server.System, erro
cancelerCanceler := canceler.ProvideCanceler(executionStore, streamer, repoStore, schedulerScheduler, stageStore, stepStore) cancelerCanceler := canceler.ProvideCanceler(executionStore, streamer, repoStore, schedulerScheduler, stageStore, stepStore)
commitService := commit.ProvideService(gitInterface) commitService := commit.ProvideService(gitInterface)
fileService := file.ProvideService(gitInterface) fileService := file.ProvideService(gitInterface)
converterService := converter.ProvideService(fileService) converterService := converter.ProvideService(fileService, publicaccessService)
templateStore := database.ProvideTemplateStore(db) templateStore := database.ProvideTemplateStore(db)
pluginStore := database.ProvidePluginStore(db) pluginStore := database.ProvidePluginStore(db)
triggererTriggerer := triggerer.ProvideTriggerer(executionStore, checkStore, stageStore, transactor, pipelineStore, fileService, converterService, schedulerScheduler, repoStore, provider, templateStore, pluginStore, publicaccessService) triggererTriggerer := triggerer.ProvideTriggerer(executionStore, checkStore, stageStore, transactor, pipelineStore, fileService, converterService, schedulerScheduler, repoStore, provider, templateStore, pluginStore, publicaccessService)

View File

@ -38,6 +38,7 @@ type Interface interface {
UpdateDefaultBranch(ctx context.Context, params *UpdateDefaultBranchParams) error UpdateDefaultBranch(ctx context.Context, params *UpdateDefaultBranchParams) error
GetRef(ctx context.Context, params GetRefParams) (GetRefResponse, error) GetRef(ctx context.Context, params GetRefParams) (GetRefResponse, error)
PathsDetails(ctx context.Context, params PathsDetailsParams) (PathsDetailsOutput, error) PathsDetails(ctx context.Context, params PathsDetailsParams) (PathsDetailsOutput, error)
Summary(ctx context.Context, params SummaryParams) (SummaryOutput, error)
// GetRepositorySize calculates the size of a repo in KiB. // GetRepositorySize calculates the size of a repo in KiB.
GetRepositorySize(ctx context.Context, params *GetRepositorySizeParams) (*GetRepositorySizeOutput, error) GetRepositorySize(ctx context.Context, params *GetRepositorySizeParams) (*GetRepositorySizeOutput, error)
@ -102,9 +103,4 @@ type Interface interface {
*/ */
ScanSecrets(ctx context.Context, param *ScanSecretsParams) (*ScanSecretsOutput, error) ScanSecrets(ctx context.Context, param *ScanSecretsParams) (*ScanSecretsOutput, error)
Archive(ctx context.Context, params ArchiveParams, w io.Writer) error Archive(ctx context.Context, params ArchiveParams, w io.Writer) error
/*
* Repo Summary service
*/
Summary(ctx context.Context, params *ReadParams) (*SummaryOutput, error)
} }

View File

@ -24,6 +24,10 @@ import (
"golang.org/x/sync/errgroup" "golang.org/x/sync/errgroup"
) )
type SummaryParams struct {
ReadParams
}
type SummaryOutput struct { type SummaryOutput struct {
CommitCount int CommitCount int
BranchCount int BranchCount int
@ -32,13 +36,13 @@ type SummaryOutput struct {
func (s *Service) Summary( func (s *Service) Summary(
ctx context.Context, ctx context.Context,
params *ReadParams, params SummaryParams,
) (*SummaryOutput, error) { ) (SummaryOutput, error) {
repoPath := getFullPathForRepo(s.reposRoot, params.RepoUID) repoPath := getFullPathForRepo(s.reposRoot, params.RepoUID)
defaultBranch, err := s.git.GetDefaultBranch(ctx, repoPath) defaultBranch, err := s.git.GetDefaultBranch(ctx, repoPath)
if err != nil { if err != nil {
return nil, err return SummaryOutput{}, err
} }
defaultBranch = strings.TrimSpace(defaultBranch) defaultBranch = strings.TrimSpace(defaultBranch)
@ -65,10 +69,10 @@ func (s *Service) Summary(
}) })
if err := g.Wait(); err != nil { if err := g.Wait(); err != nil {
return nil, fmt.Errorf("failed to get repo summary: %w", err) return SummaryOutput{}, fmt.Errorf("failed to get repo summary: %w", err)
} }
return &SummaryOutput{ return SummaryOutput{
CommitCount: commitCount, CommitCount: commitCount,
BranchCount: branchCount, BranchCount: branchCount,
TagCount: tagCount, TagCount: tagCount,