mirror of https://github.com/harness/drone.git
Support Public Access (#2021)
parent
831cf18abc
commit
c365ef246a
|
@ -30,7 +30,6 @@ import (
|
|||
)
|
||||
|
||||
var (
|
||||
ErrNotAuthenticated = errors.New("not authenticated")
|
||||
ErrNotAuthorized = errors.New("not authorized")
|
||||
ErrParentResourceTypeUnknown = errors.New("Unknown parent resource type")
|
||||
ErrPrincipalTypeUnknown = errors.New("Unknown principal type")
|
||||
|
@ -42,10 +41,6 @@ var (
|
|||
func Check(ctx context.Context, authorizer authz.Authorizer, session *auth.Session,
|
||||
scope *types.Scope, resource *types.Resource, permission enum.Permission,
|
||||
) error {
|
||||
if session == nil {
|
||||
return ErrNotAuthenticated
|
||||
}
|
||||
|
||||
authorized, err := authorizer.Check(
|
||||
ctx,
|
||||
session,
|
||||
|
@ -104,7 +99,7 @@ func getScopeForParent(ctx context.Context, spaceStore store.SpaceStore, repoSto
|
|||
|
||||
spacePath, repoName, err := paths.DisectLeaf(repo.Path)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "Failed to disect path '%s'", repo.Path)
|
||||
return nil, fmt.Errorf("failed to disect path '%s': %w", repo.Path, err)
|
||||
}
|
||||
|
||||
return &types.Scope{SpacePath: spacePath, Repo: repoName}, nil
|
||||
|
|
|
@ -16,14 +16,13 @@ package auth
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/harness/gitness/app/auth"
|
||||
"github.com/harness/gitness/app/auth/authz"
|
||||
"github.com/harness/gitness/app/paths"
|
||||
"github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// CheckPipeline checks if a pipeline specific permission is granted for the current auth session
|
||||
|
@ -34,7 +33,7 @@ func CheckPipeline(ctx context.Context, authorizer authz.Authorizer, session *au
|
|||
repoPath string, pipelineIdentifier string, permission enum.Permission) error {
|
||||
spacePath, repoName, err := paths.DisectLeaf(repoPath)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "Failed to disect path '%s'", repoPath)
|
||||
return fmt.Errorf("failed to disect path '%s': %w", repoPath, err)
|
||||
}
|
||||
scope := &types.Scope{SpacePath: spacePath, Repo: repoName}
|
||||
resource := &types.Resource{
|
||||
|
|
|
@ -37,15 +37,10 @@ func CheckRepo(
|
|||
session *auth.Session,
|
||||
repo *types.Repository,
|
||||
permission enum.Permission,
|
||||
orPublic bool,
|
||||
) error {
|
||||
if orPublic && repo.IsPublic {
|
||||
return nil
|
||||
}
|
||||
|
||||
parentSpace, name, err := paths.DisectLeaf(repo.Path)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "Failed to disect path '%s'", repo.Path)
|
||||
return fmt.Errorf("failed to disect path '%s': %w", repo.Path, err)
|
||||
}
|
||||
|
||||
scope := &types.Scope{SpacePath: parentSpace}
|
||||
|
@ -64,7 +59,7 @@ func IsRepoOwner(
|
|||
repo *types.Repository,
|
||||
) (bool, error) {
|
||||
// for now we use repoedit as permission to verify if someone is a SpaceOwner and hence a RepoOwner.
|
||||
err := CheckRepo(ctx, authorizer, session, repo, enum.PermissionRepoEdit, false)
|
||||
err := CheckRepo(ctx, authorizer, session, repo, enum.PermissionRepoEdit)
|
||||
if err != nil && !errors.Is(err, ErrNotAuthorized) {
|
||||
return false, fmt.Errorf("failed to check access user access: %w", err)
|
||||
}
|
||||
|
|
|
@ -16,14 +16,13 @@ package auth
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/harness/gitness/app/auth"
|
||||
"github.com/harness/gitness/app/auth/authz"
|
||||
"github.com/harness/gitness/app/paths"
|
||||
"github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// CheckSpace checks if a space specific permission is granted for the current auth session
|
||||
|
@ -35,15 +34,10 @@ func CheckSpace(
|
|||
session *auth.Session,
|
||||
space *types.Space,
|
||||
permission enum.Permission,
|
||||
orPublic bool,
|
||||
) error {
|
||||
if orPublic && space.IsPublic {
|
||||
return nil
|
||||
}
|
||||
|
||||
parentSpace, name, err := paths.DisectLeaf(space.Path)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "Failed to disect path '%s'", space.Path)
|
||||
return fmt.Errorf("failed to disect path '%s': %w", space.Path, err)
|
||||
}
|
||||
|
||||
scope := &types.Scope{SpacePath: parentSpace}
|
||||
|
@ -65,12 +59,7 @@ func CheckSpaceScope(
|
|||
space *types.Space,
|
||||
resourceType enum.ResourceType,
|
||||
permission enum.Permission,
|
||||
orPublic bool,
|
||||
) error {
|
||||
if orPublic && space.IsPublic {
|
||||
return nil
|
||||
}
|
||||
|
||||
scope := &types.Scope{SpacePath: space.Path}
|
||||
resource := &types.Resource{
|
||||
Type: resourceType,
|
||||
|
|
|
@ -68,7 +68,7 @@ func (c *Controller) getRepoCheckAccess(ctx context.Context,
|
|||
return nil, fmt.Errorf("failed to find repository: %w", err)
|
||||
}
|
||||
|
||||
if err = apiauth.CheckRepo(ctx, c.authorizer, session, repo, reqPermission, false); err != nil {
|
||||
if err = apiauth.CheckRepo(ctx, c.authorizer, session, repo, reqPermission); err != nil {
|
||||
return nil, fmt.Errorf("access check failed: %w", err)
|
||||
}
|
||||
|
||||
|
|
|
@ -15,15 +15,18 @@
|
|||
package principal
|
||||
|
||||
import (
|
||||
"github.com/harness/gitness/app/auth/authz"
|
||||
"github.com/harness/gitness/app/store"
|
||||
)
|
||||
|
||||
type controller struct {
|
||||
principalStore store.PrincipalStore
|
||||
authorizer authz.Authorizer
|
||||
}
|
||||
|
||||
func newController(principalStore store.PrincipalStore) *controller {
|
||||
func newController(principalStore store.PrincipalStore, authorizer authz.Authorizer) *controller {
|
||||
return &controller{
|
||||
principalStore: principalStore,
|
||||
authorizer: authorizer,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,15 +16,44 @@ package principal
|
|||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
|
||||
apiauth "github.com/harness/gitness/app/api/auth"
|
||||
"github.com/harness/gitness/app/api/usererror"
|
||||
"github.com/harness/gitness/app/auth"
|
||||
"github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
)
|
||||
|
||||
func (c controller) Find(ctx context.Context, principalID int64) (*types.PrincipalInfo, error) {
|
||||
func (c controller) Find(
|
||||
ctx context.Context,
|
||||
session *auth.Session,
|
||||
principalID int64,
|
||||
) (*types.PrincipalInfo, error) {
|
||||
principal, err := c.principalStore.Find(ctx, principalID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if principal.Type != enum.PrincipalTypeUser {
|
||||
return nil, usererror.Newf(
|
||||
http.StatusNotImplemented,
|
||||
"only user principals are supported currently.",
|
||||
)
|
||||
}
|
||||
|
||||
if err := apiauth.Check(
|
||||
ctx,
|
||||
c.authorizer,
|
||||
session,
|
||||
&types.Scope{},
|
||||
&types.Resource{
|
||||
Type: enum.ResourceTypeUser,
|
||||
},
|
||||
enum.PermissionUserView,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return principal.ToPrincipalInfo(), nil
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ package principal
|
|||
import (
|
||||
"context"
|
||||
|
||||
"github.com/harness/gitness/app/auth"
|
||||
"github.com/harness/gitness/types"
|
||||
)
|
||||
|
||||
|
@ -24,6 +25,6 @@ import (
|
|||
// principal related information.
|
||||
type Controller interface {
|
||||
// List lists the principals based on the provided filter.
|
||||
List(ctx context.Context, opts *types.PrincipalFilter) ([]*types.PrincipalInfo, error)
|
||||
Find(ctx context.Context, principalID int64) (*types.PrincipalInfo, error)
|
||||
List(ctx context.Context, session *auth.Session, opts *types.PrincipalFilter) ([]*types.PrincipalInfo, error)
|
||||
Find(ctx context.Context, session *auth.Session, principalID int64) (*types.PrincipalInfo, error)
|
||||
}
|
||||
|
|
|
@ -16,12 +16,44 @@ package principal
|
|||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
|
||||
apiauth "github.com/harness/gitness/app/api/auth"
|
||||
"github.com/harness/gitness/app/api/request"
|
||||
"github.com/harness/gitness/app/api/usererror"
|
||||
"github.com/harness/gitness/app/auth"
|
||||
"github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
)
|
||||
|
||||
func (c controller) List(ctx context.Context, opts *types.PrincipalFilter) (
|
||||
[]*types.PrincipalInfo, error) {
|
||||
func (c controller) List(
|
||||
ctx context.Context,
|
||||
session *auth.Session,
|
||||
opts *types.PrincipalFilter,
|
||||
) ([]*types.PrincipalInfo, error) {
|
||||
// only user search is supported right now!
|
||||
if len(opts.Types) != 1 || opts.Types[0] != enum.PrincipalTypeUser {
|
||||
return nil, usererror.Newf(
|
||||
http.StatusNotImplemented,
|
||||
"Only listing of users is supported at this moment (use query '%s=%s').",
|
||||
request.QueryParamType,
|
||||
enum.PrincipalTypeUser,
|
||||
)
|
||||
}
|
||||
|
||||
if err := apiauth.Check(
|
||||
ctx,
|
||||
c.authorizer,
|
||||
session,
|
||||
&types.Scope{},
|
||||
&types.Resource{
|
||||
Type: enum.ResourceTypeUser,
|
||||
},
|
||||
enum.PermissionUserView,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
principals, err := c.principalStore.List(ctx, opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
package principal
|
||||
|
||||
import (
|
||||
"github.com/harness/gitness/app/auth/authz"
|
||||
"github.com/harness/gitness/app/store"
|
||||
|
||||
"github.com/google/wire"
|
||||
|
@ -25,6 +26,6 @@ var WireSet = wire.NewSet(
|
|||
ProvideController,
|
||||
)
|
||||
|
||||
func ProvideController(principalStore store.PrincipalStore) Controller {
|
||||
return newController(principalStore)
|
||||
func ProvideController(principalStore store.PrincipalStore, authorizer authz.Authorizer) Controller {
|
||||
return newController(principalStore, authorizer)
|
||||
}
|
||||
|
|
|
@ -156,7 +156,7 @@ func (c *Controller) getRepoCheckAccess(ctx context.Context,
|
|||
return nil, usererror.BadRequest("Repository import is in progress.")
|
||||
}
|
||||
|
||||
if err = apiauth.CheckRepo(ctx, c.authorizer, session, repo, reqPermission, false); err != nil {
|
||||
if err = apiauth.CheckRepo(ctx, c.authorizer, session, repo, reqPermission); err != nil {
|
||||
return nil, fmt.Errorf("access check failed: %w", err)
|
||||
}
|
||||
|
||||
|
|
|
@ -60,7 +60,7 @@ func (c *Controller) Create(
|
|||
|
||||
sourceRepo := targetRepo
|
||||
if in.SourceRepoRef != "" {
|
||||
sourceRepo, err = c.getRepoCheckAccess(ctx, session, in.SourceRepoRef, enum.PermissionRepoView)
|
||||
sourceRepo, err = c.getRepoCheckAccess(ctx, session, in.SourceRepoRef, enum.PermissionRepoPush)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to acquire access to source repo: %w", err)
|
||||
}
|
||||
|
|
|
@ -79,7 +79,7 @@ func (c *Controller) State(ctx context.Context,
|
|||
}
|
||||
|
||||
if err = apiauth.CheckRepo(ctx, c.authorizer, session, sourceRepo,
|
||||
enum.PermissionRepoView, false); err != nil {
|
||||
enum.PermissionRepoView); err != nil {
|
||||
return nil, fmt.Errorf("failed to acquire access to source repo: %w", err)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -74,7 +74,7 @@ func (c *Controller) Update(ctx context.Context,
|
|||
}
|
||||
|
||||
if err = apiauth.CheckRepo(ctx, c.authorizer, session, sourceRepo,
|
||||
enum.PermissionRepoView, false); err != nil {
|
||||
enum.PermissionRepoView); err != nil {
|
||||
return nil, fmt.Errorf("failed to acquire access to source repo: %w", err)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -87,7 +87,7 @@ func (c *Controller) ReviewerAdd(
|
|||
if err = apiauth.CheckRepo(ctx, c.authorizer, &auth.Session{
|
||||
Principal: *reviewerPrincipal,
|
||||
Metadata: nil,
|
||||
}, repo, enum.PermissionRepoView, false); err != nil {
|
||||
}, repo, enum.PermissionRepoView); err != nil {
|
||||
log.Ctx(ctx).Info().Msgf("Reviewer principal: %s access error: %s", reviewerInfo.UID, err)
|
||||
return nil, usererror.BadRequest("The reviewer doesn't have enough permissions for the repository.")
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@ func (c *Controller) Archive(
|
|||
params api.ArchiveParams,
|
||||
w io.Writer,
|
||||
) error {
|
||||
repo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionRepoView, true)
|
||||
repo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionRepoView)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ func (c *Controller) Blame(ctx context.Context,
|
|||
return nil, usererror.BadRequest("Line range must be valid.")
|
||||
}
|
||||
|
||||
repo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionRepoView, true)
|
||||
repo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionRepoView)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ func (c *Controller) CodeOwnersValidate(
|
|||
repoRef string,
|
||||
ref string,
|
||||
) (*types.CodeOwnersValidation, error) {
|
||||
repo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionRepoView, true)
|
||||
repo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionRepoView)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -62,7 +62,7 @@ func (c *Controller) CommitFiles(ctx context.Context,
|
|||
repoRef string,
|
||||
in *CommitFilesOptions,
|
||||
) (types.CommitFilesResponse, []types.RuleViolations, error) {
|
||||
repo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionRepoPush, false)
|
||||
repo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionRepoPush)
|
||||
if err != nil {
|
||||
return types.CommitFilesResponse{}, nil, err
|
||||
}
|
||||
|
|
|
@ -101,7 +101,7 @@ func (c *Controller) GetContent(ctx context.Context,
|
|||
repoPath string,
|
||||
includeLatestCommit bool,
|
||||
) (*GetContentOutput, error) {
|
||||
repo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionRepoView, true)
|
||||
repo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionRepoView)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ func (c *Controller) PathsDetails(ctx context.Context,
|
|||
gitRef string,
|
||||
input PathsDetailsInput,
|
||||
) (PathsDetailsOutput, error) {
|
||||
repo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionRepoView, true)
|
||||
repo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionRepoView)
|
||||
if err != nil {
|
||||
return PathsDetailsOutput{}, err
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ package repo
|
|||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
@ -31,6 +32,7 @@ import (
|
|||
"github.com/harness/gitness/app/services/keywordsearch"
|
||||
"github.com/harness/gitness/app/services/locker"
|
||||
"github.com/harness/gitness/app/services/protection"
|
||||
"github.com/harness/gitness/app/services/publicaccess"
|
||||
"github.com/harness/gitness/app/services/settings"
|
||||
"github.com/harness/gitness/app/store"
|
||||
"github.com/harness/gitness/app/url"
|
||||
|
@ -43,13 +45,28 @@ import (
|
|||
"github.com/harness/gitness/types/enum"
|
||||
)
|
||||
|
||||
var (
|
||||
errPublicRepoCreationDisabled = usererror.BadRequestf("Public repository creation is disabled.")
|
||||
)
|
||||
var errPublicRepoCreationDisabled = usererror.BadRequestf("Public repository creation is disabled.")
|
||||
|
||||
type RepositoryOutput struct {
|
||||
types.Repository
|
||||
IsPublic bool `json:"is_public" yaml:"is_public"`
|
||||
}
|
||||
|
||||
// TODO [CODE-1363]: remove after identifier migration.
|
||||
func (r RepositoryOutput) MarshalJSON() ([]byte, error) {
|
||||
// alias allows us to embed the original object while avoiding an infinite loop of marshaling.
|
||||
type alias RepositoryOutput
|
||||
return json.Marshal(&struct {
|
||||
alias
|
||||
UID string `json:"uid"`
|
||||
}{
|
||||
alias: (alias)(r),
|
||||
UID: r.Identifier,
|
||||
})
|
||||
}
|
||||
|
||||
type Controller struct {
|
||||
defaultBranch string
|
||||
publicResourceCreationEnabled bool
|
||||
defaultBranch string
|
||||
|
||||
tx dbtx.Transactor
|
||||
urlProvider url.Provider
|
||||
|
@ -73,6 +90,7 @@ type Controller struct {
|
|||
mtxManager lock.MutexManager
|
||||
identifierCheck check.RepoIdentifier
|
||||
repoCheck Check
|
||||
publicAccess publicaccess.Service
|
||||
}
|
||||
|
||||
func NewController(
|
||||
|
@ -99,32 +117,33 @@ func NewController(
|
|||
mtxManager lock.MutexManager,
|
||||
identifierCheck check.RepoIdentifier,
|
||||
repoCheck Check,
|
||||
publicAccess publicaccess.Service,
|
||||
) *Controller {
|
||||
return &Controller{
|
||||
defaultBranch: config.Git.DefaultBranch,
|
||||
publicResourceCreationEnabled: config.PublicResourceCreationEnabled,
|
||||
tx: tx,
|
||||
urlProvider: urlProvider,
|
||||
authorizer: authorizer,
|
||||
repoStore: repoStore,
|
||||
spaceStore: spaceStore,
|
||||
pipelineStore: pipelineStore,
|
||||
principalStore: principalStore,
|
||||
ruleStore: ruleStore,
|
||||
settings: settings,
|
||||
principalInfoCache: principalInfoCache,
|
||||
protectionManager: protectionManager,
|
||||
git: git,
|
||||
importer: importer,
|
||||
codeOwners: codeOwners,
|
||||
eventReporter: eventReporter,
|
||||
indexer: indexer,
|
||||
resourceLimiter: limiter,
|
||||
locker: locker,
|
||||
auditService: auditService,
|
||||
mtxManager: mtxManager,
|
||||
identifierCheck: identifierCheck,
|
||||
repoCheck: repoCheck,
|
||||
defaultBranch: config.Git.DefaultBranch,
|
||||
tx: tx,
|
||||
urlProvider: urlProvider,
|
||||
authorizer: authorizer,
|
||||
repoStore: repoStore,
|
||||
spaceStore: spaceStore,
|
||||
pipelineStore: pipelineStore,
|
||||
principalStore: principalStore,
|
||||
ruleStore: ruleStore,
|
||||
settings: settings,
|
||||
principalInfoCache: principalInfoCache,
|
||||
protectionManager: protectionManager,
|
||||
git: git,
|
||||
importer: importer,
|
||||
codeOwners: codeOwners,
|
||||
eventReporter: eventReporter,
|
||||
indexer: indexer,
|
||||
resourceLimiter: limiter,
|
||||
locker: locker,
|
||||
auditService: auditService,
|
||||
mtxManager: mtxManager,
|
||||
identifierCheck: identifierCheck,
|
||||
repoCheck: repoCheck,
|
||||
publicAccess: publicAccess,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -147,7 +166,6 @@ func (c *Controller) getRepoCheckAccess(
|
|||
session *auth.Session,
|
||||
repoRef string,
|
||||
reqPermission enum.Permission,
|
||||
orPublic bool,
|
||||
) (*types.Repository, error) {
|
||||
return GetRepoCheckAccess(
|
||||
ctx,
|
||||
|
@ -156,7 +174,6 @@ func (c *Controller) getRepoCheckAccess(
|
|||
session,
|
||||
repoRef,
|
||||
reqPermission,
|
||||
orPublic,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -62,7 +62,7 @@ type CreateInput struct {
|
|||
// Create creates a new repository.
|
||||
//
|
||||
//nolint:gocognit
|
||||
func (c *Controller) Create(ctx context.Context, session *auth.Session, in *CreateInput) (*types.Repository, error) {
|
||||
func (c *Controller) Create(ctx context.Context, session *auth.Session, in *CreateInput) (*RepositoryOutput, error) {
|
||||
if err := c.sanitizeCreateInput(in); err != nil {
|
||||
return nil, fmt.Errorf("failed to sanitize input: %w", err)
|
||||
}
|
||||
|
@ -72,11 +72,28 @@ func (c *Controller) Create(ctx context.Context, session *auth.Session, in *Crea
|
|||
return nil, err
|
||||
}
|
||||
|
||||
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 %q: %w",
|
||||
parentSpace.Path,
|
||||
err,
|
||||
)
|
||||
}
|
||||
if in.IsPublic && !isPublicAccessSupported {
|
||||
return nil, errPublicRepoCreationDisabled
|
||||
}
|
||||
|
||||
err = c.repoCheck.Create(ctx, session, in)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
gitResp, isEmpty, err := c.createGitRepository(ctx, session, in)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error creating repository on git: %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 {
|
||||
|
@ -89,11 +106,6 @@ func (c *Controller) Create(ctx context.Context, session *auth.Session, in *Crea
|
|||
return fmt.Errorf("failed to find the parent space: %w", err)
|
||||
}
|
||||
|
||||
gitResp, isEmpty, err := c.createGitRepository(ctx, session, in)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error creating repository on git: %w", err)
|
||||
}
|
||||
|
||||
now := time.Now().UnixMilli()
|
||||
repo = &types.Repository{
|
||||
Version: 0,
|
||||
|
@ -101,7 +113,6 @@ func (c *Controller) Create(ctx context.Context, session *auth.Session, in *Crea
|
|||
Identifier: in.Identifier,
|
||||
GitUID: gitResp.UID,
|
||||
Description: in.Description,
|
||||
IsPublic: in.IsPublic,
|
||||
CreatedBy: session.Principal.ID,
|
||||
Created: now,
|
||||
Updated: now,
|
||||
|
@ -109,34 +120,53 @@ func (c *Controller) Create(ctx context.Context, session *auth.Session, in *Crea
|
|||
DefaultBranch: in.DefaultBranch,
|
||||
IsEmpty: isEmpty,
|
||||
}
|
||||
err = c.repoStore.Create(ctx, repo)
|
||||
if err != nil {
|
||||
if dErr := c.DeleteGitRepository(ctx, session, repo); dErr != nil {
|
||||
log.Ctx(ctx).Warn().Err(dErr).Msg("failed to delete repo for cleanup")
|
||||
}
|
||||
return fmt.Errorf("failed to create repository in storage: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
return c.repoStore.Create(ctx, repo)
|
||||
}, sql.TxOptions{Isolation: sql.LevelSerializable})
|
||||
if err != nil {
|
||||
// best effort cleanup
|
||||
if dErr := c.DeleteGitRepository(ctx, session, repo); dErr != nil {
|
||||
log.Ctx(ctx).Warn().Err(dErr).Msg("failed to delete repo for cleanup")
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = c.publicAccess.Set(ctx, enum.PublicResourceTypeRepo, repo.Path, in.IsPublic)
|
||||
if err != nil {
|
||||
if dErr := c.publicAccess.Delete(ctx, enum.PublicResourceTypeRepo, repo.Path); dErr != nil {
|
||||
return nil, fmt.Errorf("failed to set repo public access (and public access cleanup: %w): %w", dErr, err)
|
||||
}
|
||||
|
||||
// only cleanup repo itself if cleanup of public access succeeded (to avoid leaking public access)
|
||||
if dErr := c.PurgeNoAuth(ctx, session, repo); dErr != nil {
|
||||
return nil, fmt.Errorf("failed to set repo public access (and repo purge: %w): %w", dErr, err)
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("failed to set repo public access (succesfull cleanup): %w", err)
|
||||
}
|
||||
|
||||
// backfil GitURL
|
||||
repo.GitURL = c.urlProvider.GenerateGITCloneURL(repo.Path)
|
||||
|
||||
repoOutput := &RepositoryOutput{
|
||||
Repository: *repo,
|
||||
IsPublic: in.IsPublic,
|
||||
}
|
||||
|
||||
err = c.auditService.Log(ctx,
|
||||
session.Principal,
|
||||
audit.NewResource(audit.ResourceTypeRepository, repo.Identifier),
|
||||
audit.ActionCreated,
|
||||
paths.Parent(repo.Path),
|
||||
audit.WithNewObject(repo),
|
||||
audit.WithNewObject(audit.RepositoryObject{
|
||||
Repository: repoOutput.Repository,
|
||||
IsPublic: repoOutput.IsPublic,
|
||||
}),
|
||||
)
|
||||
if err != nil {
|
||||
log.Ctx(ctx).Warn().Msgf("failed to insert audit log for create repository operation: %s", err)
|
||||
}
|
||||
|
||||
// backfil GitURL
|
||||
repo.GitURL = c.urlProvider.GenerateGITCloneURL(repo.Path)
|
||||
|
||||
// index repository if files are created
|
||||
if !repo.IsEmpty {
|
||||
err = c.indexer.Index(ctx, repo)
|
||||
|
@ -145,7 +175,7 @@ func (c *Controller) Create(ctx context.Context, session *auth.Session, in *Crea
|
|||
}
|
||||
}
|
||||
|
||||
return repo, nil
|
||||
return repoOutput, nil
|
||||
}
|
||||
|
||||
func (c *Controller) getSpaceCheckAuthRepoCreation(
|
||||
|
@ -166,7 +196,6 @@ func (c *Controller) getSpaceCheckAuthRepoCreation(
|
|||
space,
|
||||
enum.ResourceTypeRepo,
|
||||
enum.PermissionRepoEdit,
|
||||
false,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("auth check failed: %w", err)
|
||||
|
@ -181,10 +210,6 @@ func (c *Controller) sanitizeCreateInput(in *CreateInput) error {
|
|||
in.Identifier = in.UID
|
||||
}
|
||||
|
||||
if in.IsPublic && !c.publicResourceCreationEnabled {
|
||||
return errPublicRepoCreationDisabled
|
||||
}
|
||||
|
||||
if err := c.validateParentRef(in.ParentRef); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -43,7 +43,7 @@ func (c *Controller) CreateBranch(ctx context.Context,
|
|||
repoRef string,
|
||||
in *CreateBranchInput,
|
||||
) (*Branch, []types.RuleViolations, error) {
|
||||
repo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionRepoPush, false)
|
||||
repo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionRepoPush)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
|
|
@ -47,7 +47,7 @@ func (c *Controller) CreateCommitTag(ctx context.Context,
|
|||
repoRef string,
|
||||
in *CreateCommitTagInput,
|
||||
) (*CommitTag, []types.RuleViolations, error) {
|
||||
repo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionRepoPush, false)
|
||||
repo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionRepoPush)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
|
|
@ -43,11 +43,12 @@ func (c *Controller) UpdateDefaultBranch(
|
|||
session *auth.Session,
|
||||
repoRef string,
|
||||
in *UpdateDefaultBranchInput,
|
||||
) (*types.Repository, error) {
|
||||
repo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionRepoEdit, false)
|
||||
) (*RepositoryOutput, error) {
|
||||
repo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionRepoEdit)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
repoClone := repo.Clone()
|
||||
// the max time we give an update default branch to succeed
|
||||
const timeout = 2 * time.Minute
|
||||
|
@ -95,13 +96,24 @@ func (c *Controller) UpdateDefaultBranch(
|
|||
return nil, fmt.Errorf("failed to update the repo default branch on db:%w", err)
|
||||
}
|
||||
|
||||
repoOutput, err := GetRepoOutput(ctx, c.publicAccess, repo)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get repo output: %w", err)
|
||||
}
|
||||
|
||||
err = c.auditService.Log(ctx,
|
||||
session.Principal,
|
||||
audit.NewResource(audit.ResourceTypeRepository, repo.Identifier),
|
||||
audit.ActionUpdated,
|
||||
paths.Parent(repo.Path),
|
||||
audit.WithOldObject(repoClone),
|
||||
audit.WithNewObject(repo),
|
||||
audit.WithOldObject(audit.RepositoryObject{
|
||||
Repository: repoClone,
|
||||
IsPublic: repoOutput.IsPublic,
|
||||
}),
|
||||
audit.WithNewObject(audit.RepositoryObject{
|
||||
Repository: *repo,
|
||||
IsPublic: repoOutput.IsPublic,
|
||||
}),
|
||||
)
|
||||
if err != nil {
|
||||
log.Ctx(ctx).Warn().Msgf("failed to insert audit log for update default branch operation: %s", err)
|
||||
|
@ -114,5 +126,5 @@ func (c *Controller) UpdateDefaultBranch(
|
|||
NewName: repo.DefaultBranch,
|
||||
})
|
||||
|
||||
return repo, nil
|
||||
return repoOutput, nil
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ func (c *Controller) DeleteBranch(ctx context.Context,
|
|||
branchName string,
|
||||
bypassRules bool,
|
||||
) ([]types.RuleViolations, error) {
|
||||
repo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionRepoPush, false)
|
||||
repo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionRepoPush)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@ func (c *Controller) DeleteTag(ctx context.Context,
|
|||
tagName string,
|
||||
bypassRules bool,
|
||||
) ([]types.RuleViolations, error) {
|
||||
repo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionRepoPush, false)
|
||||
repo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionRepoPush)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -36,7 +36,7 @@ func (c *Controller) RawDiff(
|
|||
path string,
|
||||
files ...gittypes.FileDiffRequest,
|
||||
) error {
|
||||
repo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionRepoView, true)
|
||||
repo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionRepoView)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -61,7 +61,7 @@ func (c *Controller) CommitDiff(
|
|||
rev string,
|
||||
w io.Writer,
|
||||
) error {
|
||||
repo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionRepoView, true)
|
||||
repo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionRepoView)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -104,7 +104,7 @@ func (c *Controller) DiffStats(
|
|||
return types.DiffStats{}, err
|
||||
}
|
||||
|
||||
if err = apiauth.CheckRepo(ctx, c.authorizer, session, repo, enum.PermissionRepoView, false); err != nil {
|
||||
if err = apiauth.CheckRepo(ctx, c.authorizer, session, repo, enum.PermissionRepoView); err != nil {
|
||||
return types.DiffStats{}, err
|
||||
}
|
||||
|
||||
|
@ -139,7 +139,7 @@ func (c *Controller) Diff(
|
|||
return nil, err
|
||||
}
|
||||
|
||||
if err = apiauth.CheckRepo(ctx, c.authorizer, session, repo, enum.PermissionRepoView, false); err != nil {
|
||||
if err = apiauth.CheckRepo(ctx, c.authorizer, session, repo, enum.PermissionRepoView); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
|
|
@ -19,24 +19,23 @@ import (
|
|||
|
||||
apiauth "github.com/harness/gitness/app/api/auth"
|
||||
"github.com/harness/gitness/app/auth"
|
||||
"github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
)
|
||||
|
||||
// Find finds a repo.
|
||||
func (c *Controller) Find(ctx context.Context, session *auth.Session, repoRef string) (*types.Repository, error) {
|
||||
func (c *Controller) Find(ctx context.Context, session *auth.Session, repoRef string) (*RepositoryOutput, error) {
|
||||
// note: can't use c.getRepoCheckAccess because even repositories that are currently being imported can be fetched.
|
||||
repo, err := c.repoStore.FindByRef(ctx, repoRef)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err = apiauth.CheckRepo(ctx, c.authorizer, session, repo, enum.PermissionRepoView, true); err != nil {
|
||||
if err = apiauth.CheckRepo(ctx, c.authorizer, session, repo, enum.PermissionRepoView); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// backfill clone url
|
||||
repo.GitURL = c.urlProvider.GenerateGITCloneURL(repo.Path)
|
||||
|
||||
return repo, nil
|
||||
return GetRepoOutput(ctx, c.publicAccess, repo)
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ func (c *Controller) GetBranch(ctx context.Context,
|
|||
repoRef string,
|
||||
branchName string,
|
||||
) (*Branch, error) {
|
||||
repo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionRepoView, true)
|
||||
repo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionRepoView)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@ func (c *Controller) GetCommit(ctx context.Context,
|
|||
repoRef string,
|
||||
sha string,
|
||||
) (*types.Commit, error) {
|
||||
repo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionRepoView, true)
|
||||
repo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionRepoView)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -54,7 +54,7 @@ func (c *Controller) GetCommitDivergences(ctx context.Context,
|
|||
repoRef string,
|
||||
in *GetCommitDivergencesInput,
|
||||
) ([]CommitDivergence, error) {
|
||||
repo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionRepoView, true)
|
||||
repo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionRepoView)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@ func (c *Controller) GitInfoRefs(
|
|||
gitProtocol string,
|
||||
w io.Writer,
|
||||
) error {
|
||||
repo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionRepoView, true)
|
||||
repo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionRepoView)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to verify repo access: %w", err)
|
||||
}
|
||||
|
|
|
@ -43,7 +43,7 @@ func (c *Controller) GitServicePack(
|
|||
permission = enum.PermissionRepoPush
|
||||
}
|
||||
|
||||
repo, err := c.getRepoCheckAccess(ctx, session, repoRef, permission, !isWriteOperation)
|
||||
repo, err := c.getRepoCheckAccess(ctx, session, repoRef, permission)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to verify repo access: %w", err)
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ import (
|
|||
"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/publicaccess"
|
||||
"github.com/harness/gitness/app/store"
|
||||
"github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
|
@ -58,16 +59,31 @@ func GetRepoCheckAccess(
|
|||
session *auth.Session,
|
||||
repoRef string,
|
||||
reqPermission enum.Permission,
|
||||
orPublic bool,
|
||||
) (*types.Repository, error) {
|
||||
repo, err := GetRepo(ctx, repoStore, repoRef)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to find repo: %w", err)
|
||||
}
|
||||
|
||||
if err = apiauth.CheckRepo(ctx, authorizer, session, repo, reqPermission, orPublic); err != nil {
|
||||
if err = apiauth.CheckRepo(ctx, authorizer, session, repo, reqPermission); err != nil {
|
||||
return nil, fmt.Errorf("access check failed: %w", err)
|
||||
}
|
||||
|
||||
return repo, nil
|
||||
}
|
||||
|
||||
func GetRepoOutput(
|
||||
ctx context.Context,
|
||||
publicAccess publicaccess.Service,
|
||||
repo *types.Repository,
|
||||
) (*RepositoryOutput, error) {
|
||||
isPublic, err := publicAccess.Get(ctx, enum.PublicResourceTypeRepo, repo.Path)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to check if repo is public: %w", err)
|
||||
}
|
||||
|
||||
return &RepositoryOutput{
|
||||
Repository: *repo,
|
||||
IsPublic: isPublic,
|
||||
}, nil
|
||||
}
|
||||
|
|
|
@ -23,7 +23,6 @@ import (
|
|||
"github.com/harness/gitness/app/paths"
|
||||
"github.com/harness/gitness/app/services/importer"
|
||||
"github.com/harness/gitness/audit"
|
||||
"github.com/harness/gitness/types"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
@ -42,7 +41,7 @@ type ImportInput struct {
|
|||
}
|
||||
|
||||
// Import creates a new empty repository and starts git import to it from a remote repository.
|
||||
func (c *Controller) Import(ctx context.Context, session *auth.Session, in *ImportInput) (*types.Repository, error) {
|
||||
func (c *Controller) Import(ctx context.Context, session *auth.Session, in *ImportInput) (*RepositoryOutput, error) {
|
||||
if err := c.sanitizeImportInput(in); err != nil {
|
||||
return nil, fmt.Errorf("failed to sanitize input: %w", err)
|
||||
}
|
||||
|
@ -52,24 +51,24 @@ func (c *Controller) Import(ctx context.Context, session *auth.Session, in *Impo
|
|||
return nil, err
|
||||
}
|
||||
|
||||
var repo *types.Repository
|
||||
remoteRepository, provider, err := importer.LoadRepositoryFromProvider(ctx, in.Provider, in.ProviderRepo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
repo, isPublic := remoteRepository.ToRepo(
|
||||
parentSpace.ID,
|
||||
parentSpace.Path,
|
||||
in.Identifier,
|
||||
in.Description,
|
||||
&session.Principal,
|
||||
)
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
remoteRepository, provider, err := importer.LoadRepositoryFromProvider(ctx, in.Provider, in.ProviderRepo)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
repo = remoteRepository.ToRepo(
|
||||
parentSpace.ID,
|
||||
in.Identifier,
|
||||
in.Description,
|
||||
&session.Principal,
|
||||
c.publicResourceCreationEnabled,
|
||||
)
|
||||
|
||||
// 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 {
|
||||
|
@ -84,6 +83,7 @@ func (c *Controller) Import(ctx context.Context, session *auth.Session, in *Impo
|
|||
err = c.importer.Run(ctx,
|
||||
provider,
|
||||
repo,
|
||||
isPublic,
|
||||
remoteRepository.CloneURL,
|
||||
in.Pipelines,
|
||||
)
|
||||
|
@ -104,13 +104,19 @@ func (c *Controller) Import(ctx context.Context, session *auth.Session, in *Impo
|
|||
audit.NewResource(audit.ResourceTypeRepository, repo.Identifier),
|
||||
audit.ActionCreated,
|
||||
paths.Parent(repo.Path),
|
||||
audit.WithNewObject(repo),
|
||||
audit.WithNewObject(audit.RepositoryObject{
|
||||
Repository: *repo,
|
||||
IsPublic: false,
|
||||
}),
|
||||
)
|
||||
if err != nil {
|
||||
log.Warn().Msgf("failed to insert audit log for import repository operation: %s", err)
|
||||
}
|
||||
|
||||
return repo, nil
|
||||
return &RepositoryOutput{
|
||||
Repository: *repo,
|
||||
IsPublic: false,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c *Controller) sanitizeImportInput(in *ImportInput) error {
|
||||
|
|
|
@ -38,7 +38,7 @@ func (c *Controller) ImportProgress(ctx context.Context,
|
|||
return job.Progress{}, err
|
||||
}
|
||||
|
||||
if err = apiauth.CheckRepo(ctx, c.authorizer, session, repo, enum.PermissionRepoView, false); err != nil {
|
||||
if err = apiauth.CheckRepo(ctx, c.authorizer, session, repo, enum.PermissionRepoView); err != nil {
|
||||
return job.Progress{}, err
|
||||
}
|
||||
|
||||
|
|
|
@ -38,7 +38,7 @@ func (c *Controller) ListBranches(ctx context.Context,
|
|||
includeCommit bool,
|
||||
filter *types.BranchFilter,
|
||||
) ([]Branch, error) {
|
||||
repo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionRepoView, true)
|
||||
repo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionRepoView)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -42,7 +42,7 @@ func (c *Controller) ListCommitTags(ctx context.Context,
|
|||
includeCommit bool,
|
||||
filter *types.TagFilter,
|
||||
) ([]CommitTag, error) {
|
||||
repo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionRepoView, true)
|
||||
repo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionRepoView)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ func (c *Controller) ListCommits(ctx context.Context,
|
|||
gitRef string,
|
||||
filter *types.CommitFilter,
|
||||
) (types.ListCommitResponse, error) {
|
||||
repo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionRepoView, true)
|
||||
repo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionRepoView)
|
||||
if err != nil {
|
||||
return types.ListCommitResponse{}, err
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ func (c *Controller) ListPaths(ctx context.Context,
|
|||
gitRef string,
|
||||
includeDirectories bool,
|
||||
) (ListPathsOutput, error) {
|
||||
repo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionRepoView, true)
|
||||
repo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionRepoView)
|
||||
if err != nil {
|
||||
return ListPathsOutput{}, err
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ func (c *Controller) MergeCheck(
|
|||
repoRef string,
|
||||
diffPath string,
|
||||
) (MergeCheck, error) {
|
||||
repo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionRepoView, false)
|
||||
repo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionRepoView)
|
||||
if err != nil {
|
||||
return MergeCheck{}, err
|
||||
}
|
||||
|
|
|
@ -48,7 +48,7 @@ func (c *Controller) Move(ctx context.Context,
|
|||
session *auth.Session,
|
||||
repoRef string,
|
||||
in *MoveInput,
|
||||
) (*types.Repository, error) {
|
||||
) (*RepositoryOutput, error) {
|
||||
if err := c.sanitizeMoveInput(in); err != nil {
|
||||
return nil, fmt.Errorf("failed to sanitize input: %w", err)
|
||||
}
|
||||
|
@ -62,14 +62,31 @@ func (c *Controller) Move(ctx context.Context,
|
|||
return nil, usererror.BadRequest("can't move a repo that is being imported")
|
||||
}
|
||||
|
||||
if err = apiauth.CheckRepo(ctx, c.authorizer, session, repo, enum.PermissionRepoEdit, false); err != nil {
|
||||
if err = apiauth.CheckRepo(ctx, c.authorizer, session, repo, enum.PermissionRepoEdit); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !in.hasChanges(repo) {
|
||||
return repo, nil
|
||||
return GetRepoOutput(ctx, c.publicAccess, repo)
|
||||
}
|
||||
|
||||
oldIdentifier := repo.Identifier
|
||||
|
||||
isPublic, err := c.publicAccess.Get(ctx, enum.PublicResourceTypeRepo, repo.Path)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get repo public access: %w", err)
|
||||
}
|
||||
|
||||
// remove public access from old repo path to avoid leaking it
|
||||
if err := c.publicAccess.Delete(
|
||||
ctx,
|
||||
enum.PublicResourceTypeRepo,
|
||||
repo.Path,
|
||||
); err != nil {
|
||||
return nil, fmt.Errorf("failed to remove public access on the original path: %w", err)
|
||||
}
|
||||
|
||||
// TODO add a repo level lock here to avoid racing condition or partial repo update w/o setting repo public access
|
||||
repo, err = c.repoStore.UpdateOptLock(ctx, repo, func(r *types.Repository) error {
|
||||
if in.Identifier != nil {
|
||||
r.Identifier = *in.Identifier
|
||||
|
@ -80,9 +97,42 @@ func (c *Controller) Move(ctx context.Context,
|
|||
return nil, fmt.Errorf("failed to update repo: %w", err)
|
||||
}
|
||||
|
||||
// set public access for the new repo path
|
||||
if err := c.publicAccess.Set(ctx, enum.PublicResourceTypeRepo, repo.Path, isPublic); err != nil {
|
||||
// ensure public access for new repo path is cleaned up first or we risk leaking it
|
||||
if dErr := c.publicAccess.Delete(ctx, enum.PublicResourceTypeRepo, repo.Path); dErr != nil {
|
||||
return nil, fmt.Errorf("failed to set repo public access (and public access cleanup: %w): %w", dErr, err)
|
||||
}
|
||||
|
||||
// revert identifier changes first
|
||||
var dErr error
|
||||
repo, dErr = c.repoStore.UpdateOptLock(ctx, repo, func(r *types.Repository) error {
|
||||
r.Identifier = oldIdentifier
|
||||
return nil
|
||||
})
|
||||
if dErr != nil {
|
||||
return nil, fmt.Errorf(
|
||||
"failed to set public access for new path (and reverting of move: %w): %w",
|
||||
dErr,
|
||||
err,
|
||||
)
|
||||
}
|
||||
|
||||
// revert public access changes only after we successfully restored original path
|
||||
if dErr = c.publicAccess.Set(ctx, enum.PublicResourceTypeRepo, repo.Path, isPublic); dErr != nil {
|
||||
return nil, fmt.Errorf(
|
||||
"failed to set public access for new path (and reverting of public access: %w): %w",
|
||||
dErr,
|
||||
err,
|
||||
)
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("failed to set repo public access for new path (cleanup successful): %w", err)
|
||||
}
|
||||
|
||||
repo.GitURL = c.urlProvider.GenerateGITCloneURL(repo.Path)
|
||||
|
||||
return repo, nil
|
||||
return GetRepoOutput(ctx, c.publicAccess, repo)
|
||||
}
|
||||
|
||||
func (c *Controller) sanitizeMoveInput(in *MoveInput) error {
|
||||
|
|
|
@ -29,7 +29,7 @@ func (c *Controller) PipelineGenerate(
|
|||
session *auth.Session,
|
||||
repoRef string,
|
||||
) ([]byte, error) {
|
||||
repo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionRepoView, true)
|
||||
repo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionRepoView)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -43,7 +43,7 @@ func (c *Controller) Purge(
|
|||
return fmt.Errorf("failed to find the repo (deleted at %d): %w", deletedAt, err)
|
||||
}
|
||||
|
||||
if err = apiauth.CheckRepo(ctx, c.authorizer, session, repo, enum.PermissionRepoDelete, false); err != nil {
|
||||
if err = apiauth.CheckRepo(ctx, c.authorizer, session, repo, enum.PermissionRepoDelete); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@ func (c *Controller) Raw(ctx context.Context,
|
|||
gitRef string,
|
||||
path string,
|
||||
) (io.ReadCloser, int64, sha.SHA, error) {
|
||||
repo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionRepoView, true)
|
||||
repo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionRepoView)
|
||||
if err != nil {
|
||||
return nil, 0, sha.Nil, err
|
||||
}
|
||||
|
|
|
@ -40,13 +40,13 @@ func (c *Controller) Restore(
|
|||
repoRef string,
|
||||
deletedAt int64,
|
||||
in *RestoreInput,
|
||||
) (*types.Repository, error) {
|
||||
) (*RepositoryOutput, error) {
|
||||
repo, err := c.repoStore.FindByRefAndDeletedAt(ctx, repoRef, deletedAt)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to find repository: %w", err)
|
||||
}
|
||||
|
||||
if err = apiauth.CheckRepo(ctx, c.authorizer, session, repo, enum.PermissionRepoEdit, false); err != nil {
|
||||
if err = apiauth.CheckRepo(ctx, c.authorizer, session, repo, enum.PermissionRepoEdit); err != nil {
|
||||
return nil, fmt.Errorf("access check failed: %w", err)
|
||||
}
|
||||
|
||||
|
@ -75,7 +75,7 @@ func (c *Controller) RestoreNoAuth(
|
|||
repo *types.Repository,
|
||||
newIdentifier *string,
|
||||
newParentID int64,
|
||||
) (*types.Repository, error) {
|
||||
) (*RepositoryOutput, error) {
|
||||
var err error
|
||||
err = c.tx.WithTx(ctx, func(ctx context.Context) error {
|
||||
if err := c.resourceLimiter.RepoCount(ctx, newParentID, 1); err != nil {
|
||||
|
@ -93,5 +93,9 @@ func (c *Controller) RestoreNoAuth(
|
|||
return nil, fmt.Errorf("failed to restore the repo: %w", err)
|
||||
}
|
||||
|
||||
return repo, nil
|
||||
// Repos restored as private since public access data has been deleted upon deletion.
|
||||
return &RepositoryOutput{
|
||||
Repository: *repo,
|
||||
IsPublic: false,
|
||||
}, nil
|
||||
}
|
||||
|
|
|
@ -85,7 +85,7 @@ func (c *Controller) RuleCreate(ctx context.Context,
|
|||
return nil, err
|
||||
}
|
||||
|
||||
repo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionRepoEdit, false)
|
||||
repo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionRepoEdit)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ func (c *Controller) RuleDelete(ctx context.Context,
|
|||
repoRef string,
|
||||
identifier string,
|
||||
) error {
|
||||
repo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionRepoEdit, false)
|
||||
repo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionRepoEdit)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ func (c *Controller) RuleFind(ctx context.Context,
|
|||
repoRef string,
|
||||
identifier string,
|
||||
) (*types.Rule, error) {
|
||||
repo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionRepoView, true)
|
||||
repo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionRepoView)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ func (c *Controller) RuleList(ctx context.Context,
|
|||
repoRef string,
|
||||
filter *types.RuleFilter,
|
||||
) ([]types.Rule, int64, error) {
|
||||
repo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionRepoView, true)
|
||||
repo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionRepoView)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
|
|
@ -91,7 +91,7 @@ func (c *Controller) RuleUpdate(ctx context.Context,
|
|||
return nil, err
|
||||
}
|
||||
|
||||
repo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionRepoEdit, false)
|
||||
repo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionRepoEdit)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -46,7 +46,7 @@ func (c *Controller) SoftDelete(
|
|||
return nil, fmt.Errorf("failed to find the repo for soft delete: %w", err)
|
||||
}
|
||||
|
||||
if err = apiauth.CheckRepo(ctx, c.authorizer, session, repo, enum.PermissionRepoDelete, false); err != nil {
|
||||
if err = apiauth.CheckRepo(ctx, c.authorizer, session, repo, enum.PermissionRepoDelete); err != nil {
|
||||
return nil, fmt.Errorf("access check failed: %w", err)
|
||||
}
|
||||
|
||||
|
@ -54,6 +54,11 @@ func (c *Controller) SoftDelete(
|
|||
return nil, usererror.BadRequest("repository has been already deleted")
|
||||
}
|
||||
|
||||
isPublic, err := c.publicAccess.Get(ctx, enum.PublicResourceTypeRepo, repo.Path)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to check current public access status: %w", err)
|
||||
}
|
||||
|
||||
log.Ctx(ctx).Info().
|
||||
Int64("repo.id", repo.ID).
|
||||
Str("repo.path", repo.Path).
|
||||
|
@ -69,7 +74,10 @@ func (c *Controller) SoftDelete(
|
|||
audit.NewResource(audit.ResourceTypeRepository, repo.Identifier),
|
||||
audit.ActionDeleted,
|
||||
paths.Parent(repo.Path),
|
||||
audit.WithOldObject(repo),
|
||||
audit.WithOldObject(audit.RepositoryObject{
|
||||
Repository: *repo,
|
||||
IsPublic: isPublic,
|
||||
}),
|
||||
)
|
||||
if err != nil {
|
||||
log.Ctx(ctx).Warn().Msgf("failed to insert audit log for delete repository operation: %s", err)
|
||||
|
@ -84,12 +92,16 @@ func (c *Controller) SoftDeleteNoAuth(
|
|||
repo *types.Repository,
|
||||
deletedAt int64,
|
||||
) error {
|
||||
err := c.publicAccess.Delete(ctx, enum.PublicResourceTypeRepo, repo.Path)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to delete public access for repo: %w", err)
|
||||
}
|
||||
|
||||
if repo.Importing {
|
||||
return c.PurgeNoAuth(ctx, session, repo)
|
||||
}
|
||||
|
||||
err := c.repoStore.SoftDelete(ctx, repo, deletedAt)
|
||||
if err != nil {
|
||||
if err := c.repoStore.SoftDelete(ctx, repo, deletedAt); err != nil {
|
||||
return fmt.Errorf("failed to soft delete repo from db: %w", err)
|
||||
}
|
||||
|
||||
|
|
|
@ -32,12 +32,10 @@ import (
|
|||
// UpdateInput is used for updating a repo.
|
||||
type UpdateInput struct {
|
||||
Description *string `json:"description"`
|
||||
IsPublic *bool `json:"is_public"`
|
||||
}
|
||||
|
||||
func (in *UpdateInput) hasChanges(repo *types.Repository) bool {
|
||||
return (in.Description != nil && *in.Description != repo.Description) ||
|
||||
(in.IsPublic != nil && *in.IsPublic != repo.IsPublic)
|
||||
return in.Description != nil && *in.Description != repo.Description
|
||||
}
|
||||
|
||||
// Update updates a repository.
|
||||
|
@ -45,8 +43,8 @@ func (c *Controller) Update(ctx context.Context,
|
|||
session *auth.Session,
|
||||
repoRef string,
|
||||
in *UpdateInput,
|
||||
) (*types.Repository, error) {
|
||||
repo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionRepoEdit, false)
|
||||
) (*RepositoryOutput, error) {
|
||||
repo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionRepoEdit)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -54,7 +52,7 @@ func (c *Controller) Update(ctx context.Context,
|
|||
repoClone := repo.Clone()
|
||||
|
||||
if !in.hasChanges(repo) {
|
||||
return repo, nil
|
||||
return GetRepoOutput(ctx, c.publicAccess, repo)
|
||||
}
|
||||
|
||||
if err = c.sanitizeUpdateInput(in); err != nil {
|
||||
|
@ -66,9 +64,6 @@ func (c *Controller) Update(ctx context.Context,
|
|||
if in.Description != nil {
|
||||
repo.Description = *in.Description
|
||||
}
|
||||
if in.IsPublic != nil {
|
||||
repo.IsPublic = *in.IsPublic
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
@ -91,16 +86,10 @@ func (c *Controller) Update(ctx context.Context,
|
|||
// backfill repo url
|
||||
repo.GitURL = c.urlProvider.GenerateGITCloneURL(repo.Path)
|
||||
|
||||
return repo, nil
|
||||
return GetRepoOutput(ctx, c.publicAccess, repo)
|
||||
}
|
||||
|
||||
func (c *Controller) sanitizeUpdateInput(in *UpdateInput) error {
|
||||
if in.IsPublic != nil {
|
||||
if *in.IsPublic && !c.publicResourceCreationEnabled {
|
||||
return errPublicRepoCreationDisabled
|
||||
}
|
||||
}
|
||||
|
||||
if in.Description != nil {
|
||||
*in.Description = strings.TrimSpace(*in.Description)
|
||||
if err := check.Description(*in.Description); err != nil {
|
||||
|
|
|
@ -0,0 +1,101 @@
|
|||
// 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 repo
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/harness/gitness/app/auth"
|
||||
"github.com/harness/gitness/app/paths"
|
||||
"github.com/harness/gitness/audit"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
type UpdatePublicAccessInput struct {
|
||||
IsPublic bool `json:"is_public"`
|
||||
}
|
||||
|
||||
func (c *Controller) UpdatePublicAccess(ctx context.Context,
|
||||
session *auth.Session,
|
||||
repoRef string,
|
||||
in *UpdatePublicAccessInput,
|
||||
) (*RepositoryOutput, error) {
|
||||
repo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionRepoEdit)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
parentPath, _, err := paths.DisectLeaf(repo.Path)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to disect path %q: %w", repo.Path, err)
|
||||
}
|
||||
isPublicAccessSupported, err := c.publicAccess.IsPublicAccessSupported(ctx, parentPath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf(
|
||||
"failed to check if public access is supported for parent space %q: %w",
|
||||
parentPath,
|
||||
err,
|
||||
)
|
||||
}
|
||||
if in.IsPublic && !isPublicAccessSupported {
|
||||
return nil, errPublicRepoCreationDisabled
|
||||
}
|
||||
|
||||
isPublic, err := c.publicAccess.Get(ctx, enum.PublicResourceTypeRepo, repo.Path)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to check current public access status: %w", err)
|
||||
}
|
||||
|
||||
// no op
|
||||
if isPublic == in.IsPublic {
|
||||
return &RepositoryOutput{
|
||||
Repository: *repo,
|
||||
IsPublic: isPublic,
|
||||
}, nil
|
||||
}
|
||||
|
||||
if err = c.publicAccess.Set(ctx, enum.PublicResourceTypeRepo, repo.Path, in.IsPublic); err != nil {
|
||||
return nil, fmt.Errorf("failed to update repo public access: %w", err)
|
||||
}
|
||||
|
||||
// backfill GitURL
|
||||
repo.GitURL = c.urlProvider.GenerateGITCloneURL(repo.Path)
|
||||
|
||||
err = c.auditService.Log(ctx,
|
||||
session.Principal,
|
||||
audit.NewResource(audit.ResourceTypeRepository, repo.Identifier),
|
||||
audit.ActionUpdated,
|
||||
paths.Parent(repo.Path),
|
||||
audit.WithOldObject(audit.RepositoryObject{
|
||||
Repository: *repo,
|
||||
IsPublic: isPublic,
|
||||
}),
|
||||
audit.WithNewObject(audit.RepositoryObject{
|
||||
Repository: *repo,
|
||||
IsPublic: in.IsPublic,
|
||||
}),
|
||||
)
|
||||
if err != nil {
|
||||
log.Ctx(ctx).Warn().Msgf("failed to insert audit log for update repository operation: %s", err)
|
||||
}
|
||||
|
||||
return &RepositoryOutput{
|
||||
Repository: *repo,
|
||||
IsPublic: in.IsPublic,
|
||||
}, nil
|
||||
}
|
|
@ -23,6 +23,7 @@ import (
|
|||
"github.com/harness/gitness/app/services/keywordsearch"
|
||||
"github.com/harness/gitness/app/services/locker"
|
||||
"github.com/harness/gitness/app/services/protection"
|
||||
"github.com/harness/gitness/app/services/publicaccess"
|
||||
"github.com/harness/gitness/app/services/settings"
|
||||
"github.com/harness/gitness/app/store"
|
||||
"github.com/harness/gitness/app/url"
|
||||
|
@ -65,12 +66,14 @@ func ProvideController(
|
|||
mtxManager lock.MutexManager,
|
||||
identifierCheck check.RepoIdentifier,
|
||||
repoChecks Check,
|
||||
publicAccess publicaccess.Service,
|
||||
) *Controller {
|
||||
return NewController(config, tx, urlProvider,
|
||||
authorizer, repoStore,
|
||||
spaceStore, pipelineStore,
|
||||
authorizer,
|
||||
repoStore, spaceStore, pipelineStore,
|
||||
principalStore, ruleStore, settings, principalInfoCache, protectionManager, rpcClient, importer,
|
||||
codeOwners, reporeporter, indexer, limiter, locker, auditService, mtxManager, identifierCheck, repoChecks)
|
||||
codeOwners, reporeporter, indexer, limiter, locker, auditService, mtxManager, identifierCheck,
|
||||
repoChecks, publicAccess)
|
||||
}
|
||||
|
||||
func ProvideRepoCheck() Check {
|
||||
|
|
|
@ -55,7 +55,6 @@ func (c *Controller) getRepoCheckAccess(
|
|||
session *auth.Session,
|
||||
repoRef string,
|
||||
reqPermission enum.Permission,
|
||||
orPublic bool,
|
||||
) (*types.Repository, error) {
|
||||
return repo.GetRepoCheckAccess(
|
||||
ctx,
|
||||
|
@ -64,6 +63,5 @@ func (c *Controller) getRepoCheckAccess(
|
|||
session,
|
||||
repoRef,
|
||||
reqPermission,
|
||||
orPublic,
|
||||
)
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ func (c *Controller) GeneralFind(
|
|||
session *auth.Session,
|
||||
repoRef string,
|
||||
) (*GeneralSettings, error) {
|
||||
repo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionRepoView, true)
|
||||
repo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionRepoView)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@ func (c *Controller) GeneralUpdate(
|
|||
repoRef string,
|
||||
in *GeneralSettings,
|
||||
) (*GeneralSettings, error) {
|
||||
repo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionRepoEdit, false)
|
||||
repo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionRepoEdit)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ func (c *Controller) SecurityFind(
|
|||
session *auth.Session,
|
||||
repoRef string,
|
||||
) (*SecuritySettings, error) {
|
||||
repo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionRepoView, true)
|
||||
repo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionRepoView)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@ func (c *Controller) SecurityUpdate(
|
|||
repoRef string,
|
||||
in *SecuritySettings,
|
||||
) (*SecuritySettings, error) {
|
||||
repo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionRepoEdit, false)
|
||||
repo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionRepoEdit)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -15,12 +15,15 @@
|
|||
package space
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/harness/gitness/app/api/controller/limiter"
|
||||
"github.com/harness/gitness/app/api/controller/repo"
|
||||
"github.com/harness/gitness/app/api/usererror"
|
||||
"github.com/harness/gitness/app/auth/authz"
|
||||
"github.com/harness/gitness/app/services/exporter"
|
||||
"github.com/harness/gitness/app/services/importer"
|
||||
"github.com/harness/gitness/app/services/publicaccess"
|
||||
"github.com/harness/gitness/app/sse"
|
||||
"github.com/harness/gitness/app/store"
|
||||
"github.com/harness/gitness/app/url"
|
||||
|
@ -36,9 +39,27 @@ var (
|
|||
errPublicSpaceCreationDisabled = usererror.BadRequestf("Public space creation is disabled.")
|
||||
)
|
||||
|
||||
//nolint:revive
|
||||
type SpaceOutput struct {
|
||||
types.Space
|
||||
IsPublic bool `json:"is_public" yaml:"is_public"`
|
||||
}
|
||||
|
||||
// TODO [CODE-1363]: remove after identifier migration.
|
||||
func (s SpaceOutput) MarshalJSON() ([]byte, error) {
|
||||
// alias allows us to embed the original object while avoiding an infinite loop of marshaling.
|
||||
type alias SpaceOutput
|
||||
return json.Marshal(&struct {
|
||||
alias
|
||||
UID string `json:"uid"`
|
||||
}{
|
||||
alias: (alias)(s),
|
||||
UID: s.Identifier,
|
||||
})
|
||||
}
|
||||
|
||||
type Controller struct {
|
||||
nestedSpacesEnabled bool
|
||||
publicResourceCreationEnabled bool
|
||||
nestedSpacesEnabled bool
|
||||
|
||||
tx dbtx.Transactor
|
||||
urlProvider url.Provider
|
||||
|
@ -58,6 +79,7 @@ type Controller struct {
|
|||
importer *importer.Repository
|
||||
exporter *exporter.Repository
|
||||
resourceLimiter limiter.ResourceLimiter
|
||||
publicAccess publicaccess.Service
|
||||
auditService audit.Service
|
||||
}
|
||||
|
||||
|
@ -67,29 +89,29 @@ func NewController(config *types.Config, tx dbtx.Transactor, urlProvider url.Pro
|
|||
connectorStore store.ConnectorStore, templateStore store.TemplateStore, spaceStore store.SpaceStore,
|
||||
repoStore store.RepoStore, principalStore store.PrincipalStore, repoCtrl *repo.Controller,
|
||||
membershipStore store.MembershipStore, importer *importer.Repository, exporter *exporter.Repository,
|
||||
limiter limiter.ResourceLimiter, auditService audit.Service,
|
||||
limiter limiter.ResourceLimiter, publicAccess publicaccess.Service, auditService audit.Service,
|
||||
) *Controller {
|
||||
return &Controller{
|
||||
nestedSpacesEnabled: config.NestedSpacesEnabled,
|
||||
publicResourceCreationEnabled: config.PublicResourceCreationEnabled,
|
||||
tx: tx,
|
||||
urlProvider: urlProvider,
|
||||
sseStreamer: sseStreamer,
|
||||
identifierCheck: identifierCheck,
|
||||
authorizer: authorizer,
|
||||
spacePathStore: spacePathStore,
|
||||
pipelineStore: pipelineStore,
|
||||
secretStore: secretStore,
|
||||
connectorStore: connectorStore,
|
||||
templateStore: templateStore,
|
||||
spaceStore: spaceStore,
|
||||
repoStore: repoStore,
|
||||
principalStore: principalStore,
|
||||
repoCtrl: repoCtrl,
|
||||
membershipStore: membershipStore,
|
||||
importer: importer,
|
||||
exporter: exporter,
|
||||
resourceLimiter: limiter,
|
||||
auditService: auditService,
|
||||
nestedSpacesEnabled: config.NestedSpacesEnabled,
|
||||
tx: tx,
|
||||
urlProvider: urlProvider,
|
||||
sseStreamer: sseStreamer,
|
||||
identifierCheck: identifierCheck,
|
||||
authorizer: authorizer,
|
||||
spacePathStore: spacePathStore,
|
||||
pipelineStore: pipelineStore,
|
||||
secretStore: secretStore,
|
||||
connectorStore: connectorStore,
|
||||
templateStore: templateStore,
|
||||
spaceStore: spaceStore,
|
||||
repoStore: repoStore,
|
||||
principalStore: principalStore,
|
||||
repoCtrl: repoCtrl,
|
||||
membershipStore: membershipStore,
|
||||
importer: importer,
|
||||
exporter: exporter,
|
||||
resourceLimiter: limiter,
|
||||
publicAccess: publicAccess,
|
||||
auditService: auditService,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -52,7 +52,7 @@ func (c *Controller) Create(
|
|||
ctx context.Context,
|
||||
session *auth.Session,
|
||||
in *CreateInput,
|
||||
) (*types.Space, error) {
|
||||
) (*SpaceOutput, error) {
|
||||
if err := c.sanitizeCreateInput(in); err != nil {
|
||||
return nil, fmt.Errorf("failed to sanitize input: %w", err)
|
||||
}
|
||||
|
@ -62,6 +62,18 @@ func (c *Controller) Create(
|
|||
return nil, err
|
||||
}
|
||||
|
||||
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 %q: %w",
|
||||
parentSpace.Path,
|
||||
err,
|
||||
)
|
||||
}
|
||||
if in.IsPublic && !isPublicAccessSupported {
|
||||
return nil, errPublicSpaceCreationDisabled
|
||||
}
|
||||
|
||||
var space *types.Space
|
||||
err = c.tx.WithTx(ctx, func(ctx context.Context) error {
|
||||
space, err = c.createSpaceInnerInTX(ctx, session, parentSpace.ID, in)
|
||||
|
@ -71,7 +83,21 @@ func (c *Controller) Create(
|
|||
return nil, err
|
||||
}
|
||||
|
||||
return space, nil
|
||||
err = c.publicAccess.Set(ctx, enum.PublicResourceTypeSpace, space.Path, in.IsPublic)
|
||||
if err != nil {
|
||||
if dErr := c.publicAccess.Delete(ctx, enum.PublicResourceTypeSpace, space.Path); dErr != nil {
|
||||
return nil, fmt.Errorf("failed to set space public access (and public access cleanup: %w): %w", dErr, err)
|
||||
}
|
||||
|
||||
// only cleanup space itself if cleanup of public access succeeded or we risk leaking public access
|
||||
if dErr := c.PurgeNoAuth(ctx, session, space); dErr != nil {
|
||||
return nil, fmt.Errorf("failed to set space public access (and space purge: %w): %w", dErr, err)
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("failed to set space public access (succesfull cleanup): %w", err)
|
||||
}
|
||||
|
||||
return GetSpaceOutput(ctx, c.publicAccess, space)
|
||||
}
|
||||
|
||||
func (c *Controller) createSpaceInnerInTX(
|
||||
|
@ -102,7 +128,6 @@ func (c *Controller) createSpaceInnerInTX(
|
|||
ParentID: parentID,
|
||||
Identifier: in.Identifier,
|
||||
Description: in.Description,
|
||||
IsPublic: in.IsPublic,
|
||||
Path: spacePath,
|
||||
CreatedBy: session.Principal.ID,
|
||||
Created: now,
|
||||
|
@ -158,7 +183,7 @@ func (c *Controller) getSpaceCheckAuthSpaceCreation(
|
|||
parentRefAsID, err := strconv.ParseInt(parentRef, 10, 64)
|
||||
if (parentRefAsID <= 0 && err == nil) || (len(strings.TrimSpace(parentRef)) == 0) {
|
||||
// TODO: Restrict top level space creation - should be move to authorizer?
|
||||
if session == nil {
|
||||
if auth.IsAnonymousSession(session) {
|
||||
return nil, fmt.Errorf("anonymous user not allowed to create top level spaces: %w", usererror.ErrUnauthorized)
|
||||
}
|
||||
|
||||
|
@ -177,7 +202,6 @@ func (c *Controller) getSpaceCheckAuthSpaceCreation(
|
|||
parentSpace,
|
||||
enum.ResourceTypeSpace,
|
||||
enum.PermissionSpaceEdit,
|
||||
false,
|
||||
); err != nil {
|
||||
return nil, fmt.Errorf("authorization failed: %w", err)
|
||||
}
|
||||
|
@ -196,10 +220,6 @@ func (c *Controller) sanitizeCreateInput(in *CreateInput) error {
|
|||
return errNestedSpacesNotSupported
|
||||
}
|
||||
|
||||
if in.IsPublic && !c.publicResourceCreationEnabled {
|
||||
return errPublicSpaceCreationDisabled
|
||||
}
|
||||
|
||||
parentRefAsID, err := strconv.ParseInt(in.ParentRef, 10, 64)
|
||||
if err == nil && parentRefAsID < 0 {
|
||||
return errParentIDNegative
|
||||
|
|
|
@ -34,7 +34,7 @@ func (c *Controller) Events(
|
|||
return nil, nil, nil, fmt.Errorf("failed to find space ref: %w", err)
|
||||
}
|
||||
|
||||
if err = apiauth.CheckSpace(ctx, c.authorizer, session, space, enum.PermissionSpaceView, true); err != nil {
|
||||
if err = apiauth.CheckSpace(ctx, c.authorizer, session, space, enum.PermissionSpaceView); err != nil {
|
||||
return nil, nil, nil, fmt.Errorf("failed to authorize stream: %w", err)
|
||||
}
|
||||
|
||||
|
|
|
@ -41,7 +41,7 @@ func (c *Controller) Export(ctx context.Context, session *auth.Session, spaceRef
|
|||
return err
|
||||
}
|
||||
|
||||
if err = apiauth.CheckSpace(ctx, c.authorizer, session, space, enum.PermissionSpaceEdit, false); err != nil {
|
||||
if err = apiauth.CheckSpace(ctx, c.authorizer, session, space, enum.PermissionSpaceEdit); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
|
@ -42,7 +42,7 @@ func (c *Controller) ExportProgress(ctx context.Context,
|
|||
return ExportProgressOutput{}, err
|
||||
}
|
||||
|
||||
if err = apiauth.CheckSpace(ctx, c.authorizer, session, space, enum.PermissionSpaceView, false); err != nil {
|
||||
if err = apiauth.CheckSpace(ctx, c.authorizer, session, space, enum.PermissionSpaceView); err != nil {
|
||||
return ExportProgressOutput{}, err
|
||||
}
|
||||
|
||||
|
|
|
@ -19,22 +19,21 @@ import (
|
|||
|
||||
apiauth "github.com/harness/gitness/app/api/auth"
|
||||
"github.com/harness/gitness/app/auth"
|
||||
"github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
)
|
||||
|
||||
/*
|
||||
* Find finds a space.
|
||||
*/
|
||||
func (c *Controller) Find(ctx context.Context, session *auth.Session, spaceRef string) (*types.Space, error) {
|
||||
func (c *Controller) Find(ctx context.Context, session *auth.Session, spaceRef string) (*SpaceOutput, error) {
|
||||
space, err := c.spaceStore.FindByRef(ctx, spaceRef)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err = apiauth.CheckSpace(ctx, c.authorizer, session, space, enum.PermissionSpaceView, true); err != nil {
|
||||
if err = apiauth.CheckSpace(ctx, c.authorizer, session, space, enum.PermissionSpaceView); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return space, nil
|
||||
return GetSpaceOutput(ctx, c.publicAccess, space)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
// 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 space
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/harness/gitness/app/services/publicaccess"
|
||||
"github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
)
|
||||
|
||||
func GetSpaceOutput(
|
||||
ctx context.Context,
|
||||
publicAccess publicaccess.Service,
|
||||
space *types.Space,
|
||||
) (*SpaceOutput, error) {
|
||||
isPublic, err := publicAccess.Get(ctx, enum.PublicResourceTypeSpace, space.Path)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get resource public access mode: %w", err)
|
||||
}
|
||||
|
||||
return &SpaceOutput{
|
||||
Space: *space,
|
||||
IsPublic: isPublic,
|
||||
}, nil
|
||||
}
|
|
@ -41,7 +41,9 @@ type ImportInput struct {
|
|||
}
|
||||
|
||||
// Import creates new space and starts import of all repositories from the remote provider's space into it.
|
||||
func (c *Controller) Import(ctx context.Context, session *auth.Session, in *ImportInput) (*types.Space, error) {
|
||||
//
|
||||
//nolint:gocognit
|
||||
func (c *Controller) Import(ctx context.Context, session *auth.Session, in *ImportInput) (*SpaceOutput, error) {
|
||||
parentSpace, err := c.getSpaceCheckAuthSpaceCreation(ctx, session, in.ParentRef)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -67,6 +69,7 @@ func (c *Controller) Import(ctx context.Context, session *auth.Session, in *Impo
|
|||
}
|
||||
|
||||
repoIDs := make([]int64, len(remoteRepositories))
|
||||
repoIsPublicVals := make([]bool, len(remoteRepositories))
|
||||
cloneURLs := make([]string, len(remoteRepositories))
|
||||
repos := make([]*types.Repository, 0, len(remoteRepositories))
|
||||
|
||||
|
@ -83,12 +86,12 @@ func (c *Controller) Import(ctx context.Context, session *auth.Session, in *Impo
|
|||
}
|
||||
|
||||
for i, remoteRepository := range remoteRepositories {
|
||||
repo := remoteRepository.ToRepo(
|
||||
repo, isPublic := remoteRepository.ToRepo(
|
||||
space.ID,
|
||||
space.Path,
|
||||
remoteRepository.Identifier,
|
||||
"",
|
||||
&session.Principal,
|
||||
c.publicResourceCreationEnabled,
|
||||
)
|
||||
|
||||
err = c.repoStore.Create(ctx, repo)
|
||||
|
@ -98,6 +101,7 @@ func (c *Controller) Import(ctx context.Context, session *auth.Session, in *Impo
|
|||
repos = append(repos, repo)
|
||||
repoIDs[i] = repo.ID
|
||||
cloneURLs[i] = remoteRepository.CloneURL
|
||||
repoIsPublicVals[i] = isPublic
|
||||
}
|
||||
|
||||
jobGroupID := fmt.Sprintf("space-import-%d", space.ID)
|
||||
|
@ -105,6 +109,7 @@ func (c *Controller) Import(ctx context.Context, session *auth.Session, in *Impo
|
|||
jobGroupID,
|
||||
provider,
|
||||
repoIDs,
|
||||
repoIsPublicVals,
|
||||
cloneURLs,
|
||||
in.Pipelines,
|
||||
)
|
||||
|
@ -124,14 +129,17 @@ func (c *Controller) Import(ctx context.Context, session *auth.Session, in *Impo
|
|||
audit.NewResource(audit.ResourceTypeRepository, repo.Identifier),
|
||||
audit.ActionCreated,
|
||||
paths.Parent(repo.Path),
|
||||
audit.WithNewObject(repo),
|
||||
audit.WithNewObject(audit.RepositoryObject{
|
||||
Repository: *repo,
|
||||
IsPublic: false, // in import we configure public access and create a new audit log.
|
||||
}),
|
||||
)
|
||||
if err != nil {
|
||||
log.Warn().Msgf("failed to insert audit log for import repository operation: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
return space, nil
|
||||
return GetSpaceOutput(ctx, c.publicAccess, space)
|
||||
}
|
||||
|
||||
func (c *Controller) sanitizeImportInput(in *ImportInput) error {
|
||||
|
|
|
@ -71,6 +71,8 @@ func (c *Controller) getSpaceCheckAuthRepoCreation(
|
|||
|
||||
// ImportRepositories imports repositories into an existing space. It ignores and continues on
|
||||
// repo naming conflicts.
|
||||
//
|
||||
//nolint:gocognit
|
||||
func (c *Controller) ImportRepositories(
|
||||
ctx context.Context,
|
||||
session *auth.Session,
|
||||
|
@ -92,10 +94,25 @@ func (c *Controller) ImportRepositories(
|
|||
return ImportRepositoriesOutput{}, usererror.BadRequestf("found no repositories at %s", in.ProviderSpace)
|
||||
}
|
||||
|
||||
repoIDs := make([]int64, 0, len(remoteRepositories))
|
||||
cloneURLs := make([]string, 0, len(remoteRepositories))
|
||||
repos := make([]*types.Repository, 0, len(remoteRepositories))
|
||||
duplicateRepos := make([]*types.Repository, 0, len(remoteRepositories))
|
||||
repoIDs := make([]int64, 0, len(remoteRepositories))
|
||||
repoIsPublicVals := make([]bool, 0, len(remoteRepositories))
|
||||
cloneURLs := make([]string, 0, len(remoteRepositories))
|
||||
|
||||
for _, remoteRepository := range remoteRepositories {
|
||||
repo, isPublic := remoteRepository.ToRepo(
|
||||
space.ID,
|
||||
space.Path,
|
||||
remoteRepository.Identifier,
|
||||
"",
|
||||
&session.Principal,
|
||||
)
|
||||
|
||||
repos = append(repos, repo)
|
||||
repoIsPublicVals = append(repoIsPublicVals, isPublic)
|
||||
cloneURLs = append(cloneURLs, remoteRepository.CloneURL)
|
||||
}
|
||||
|
||||
err = c.tx.WithTx(ctx, func(ctx context.Context) error {
|
||||
// lock the space for update during repo creation to prevent racing conditions with space soft delete.
|
||||
|
@ -109,26 +126,20 @@ func (c *Controller) ImportRepositories(
|
|||
return fmt.Errorf("resource limit exceeded: %w", limiter.ErrMaxNumReposReached)
|
||||
}
|
||||
|
||||
for _, remoteRepository := range remoteRepositories {
|
||||
repo := remoteRepository.ToRepo(
|
||||
space.ID,
|
||||
remoteRepository.Identifier,
|
||||
"",
|
||||
&session.Principal,
|
||||
c.publicResourceCreationEnabled,
|
||||
)
|
||||
|
||||
for _, repo := range repos {
|
||||
err = c.repoStore.Create(ctx, repo)
|
||||
if errors.Is(err, store.ErrDuplicate) {
|
||||
log.Ctx(ctx).Warn().Err(err).Msg("skipping duplicate repo")
|
||||
duplicateRepos = append(duplicateRepos, repo)
|
||||
l := len(repoIDs)
|
||||
repoIsPublicVals = append(repoIsPublicVals[:l], repoIsPublicVals[l+1:]...)
|
||||
cloneURLs = append(cloneURLs[:l], cloneURLs[l+1:]...)
|
||||
continue
|
||||
} else if err != nil {
|
||||
return fmt.Errorf("failed to create repository in storage: %w", err)
|
||||
}
|
||||
repos = append(repos, repo)
|
||||
|
||||
repoIDs = append(repoIDs, repo.ID)
|
||||
cloneURLs = append(cloneURLs, remoteRepository.CloneURL)
|
||||
}
|
||||
if len(repoIDs) == 0 {
|
||||
return nil
|
||||
|
@ -139,6 +150,7 @@ func (c *Controller) ImportRepositories(
|
|||
jobGroupID,
|
||||
provider,
|
||||
repoIDs,
|
||||
repoIsPublicVals,
|
||||
cloneURLs,
|
||||
in.Pipelines,
|
||||
)
|
||||
|
@ -158,7 +170,10 @@ func (c *Controller) ImportRepositories(
|
|||
audit.NewResource(audit.ResourceTypeRepository, repo.Identifier),
|
||||
audit.ActionCreated,
|
||||
paths.Parent(repo.Path),
|
||||
audit.WithNewObject(repo),
|
||||
audit.WithNewObject(audit.RepositoryObject{
|
||||
Repository: *repo,
|
||||
IsPublic: false, // in import we configure public access and create a new audit log.
|
||||
}),
|
||||
)
|
||||
if err != nil {
|
||||
log.Warn().Msgf("failed to insert audit log for import repository operation: %s", err)
|
||||
|
|
|
@ -19,7 +19,9 @@ import (
|
|||
"fmt"
|
||||
|
||||
apiauth "github.com/harness/gitness/app/api/auth"
|
||||
repoCtrl "github.com/harness/gitness/app/api/controller/repo"
|
||||
"github.com/harness/gitness/app/auth"
|
||||
"github.com/harness/gitness/store/database/dbtx"
|
||||
"github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
)
|
||||
|
@ -30,7 +32,7 @@ func (c *Controller) ListRepositories(
|
|||
session *auth.Session,
|
||||
spaceRef string,
|
||||
filter *types.RepoFilter,
|
||||
) ([]*types.Repository, int64, error) {
|
||||
) ([]*repoCtrl.RepositoryOutput, int64, error) {
|
||||
space, err := c.spaceStore.FindByRef(ctx, spaceRef)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
|
@ -43,7 +45,6 @@ func (c *Controller) ListRepositories(
|
|||
space,
|
||||
enum.ResourceTypeRepo,
|
||||
enum.PermissionRepoView,
|
||||
true,
|
||||
); err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
@ -56,21 +57,39 @@ func (c *Controller) ListRepositoriesNoAuth(
|
|||
ctx context.Context,
|
||||
spaceID int64,
|
||||
filter *types.RepoFilter,
|
||||
) ([]*types.Repository, int64, error) {
|
||||
count, err := c.repoStore.Count(ctx, spaceID, filter)
|
||||
) ([]*repoCtrl.RepositoryOutput, int64, error) {
|
||||
var repos []*types.Repository
|
||||
var count int64
|
||||
|
||||
err := c.tx.WithTx(ctx, func(ctx context.Context) (err error) {
|
||||
count, err = c.repoStore.Count(ctx, spaceID, filter)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to count child repos: %w", err)
|
||||
}
|
||||
|
||||
repos, err = c.repoStore.List(ctx, spaceID, filter)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to list child repos: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}, dbtx.TxDefaultReadOnly)
|
||||
if err != nil {
|
||||
return nil, 0, fmt.Errorf("failed to count child repos: %w", err)
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
repos, err := c.repoStore.List(ctx, spaceID, filter)
|
||||
if err != nil {
|
||||
return nil, 0, fmt.Errorf("failed to list child repos: %w", err)
|
||||
}
|
||||
|
||||
// backfill URLs
|
||||
var reposOut []*repoCtrl.RepositoryOutput
|
||||
for _, repo := range repos {
|
||||
// backfill URLs
|
||||
repo.GitURL = c.urlProvider.GenerateGITCloneURL(repo.Path)
|
||||
|
||||
repoOut, err := repoCtrl.GetRepoOutput(ctx, c.publicAccess, repo)
|
||||
if err != nil {
|
||||
return nil, 0, fmt.Errorf("failed to get repo %q output: %w", repo.Path, err)
|
||||
}
|
||||
|
||||
reposOut = append(reposOut, repoOut)
|
||||
}
|
||||
|
||||
return repos, count, nil
|
||||
return reposOut, count, nil
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ func (c *Controller) ListSpaces(ctx context.Context,
|
|||
session *auth.Session,
|
||||
spaceRef string,
|
||||
filter *types.SpaceFilter,
|
||||
) ([]*types.Space, int64, error) {
|
||||
) ([]*SpaceOutput, int64, error) {
|
||||
space, err := c.spaceStore.FindByRef(ctx, spaceRef)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
|
@ -43,10 +43,10 @@ func (c *Controller) ListSpaces(ctx context.Context,
|
|||
space,
|
||||
enum.ResourceTypeSpace,
|
||||
enum.PermissionSpaceView,
|
||||
true,
|
||||
); err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
return c.ListSpacesNoAuth(ctx, space.ID, filter)
|
||||
}
|
||||
|
||||
|
@ -55,7 +55,7 @@ func (c *Controller) ListSpacesNoAuth(
|
|||
ctx context.Context,
|
||||
spaceID int64,
|
||||
filter *types.SpaceFilter,
|
||||
) ([]*types.Space, int64, error) {
|
||||
) ([]*SpaceOutput, int64, error) {
|
||||
var spaces []*types.Space
|
||||
var count int64
|
||||
|
||||
|
@ -76,5 +76,16 @@ func (c *Controller) ListSpacesNoAuth(
|
|||
return nil, 0, err
|
||||
}
|
||||
|
||||
return spaces, count, nil
|
||||
// backfill public access mode
|
||||
var spacesOut []*SpaceOutput
|
||||
for _, space := range spaces {
|
||||
spaceOut, err := GetSpaceOutput(ctx, c.publicAccess, space)
|
||||
if err != nil {
|
||||
return nil, 0, fmt.Errorf("failed to get space %q output: %w", space.Path, err)
|
||||
}
|
||||
|
||||
spacesOut = append(spacesOut, spaceOut)
|
||||
}
|
||||
|
||||
return spacesOut, count, nil
|
||||
}
|
||||
|
|
|
@ -66,7 +66,7 @@ func (c *Controller) MembershipAdd(ctx context.Context,
|
|||
return nil, err
|
||||
}
|
||||
|
||||
if err = apiauth.CheckSpace(ctx, c.authorizer, session, space, enum.PermissionSpaceEdit, false); err != nil {
|
||||
if err = apiauth.CheckSpace(ctx, c.authorizer, session, space, enum.PermissionSpaceEdit); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
|
|
@ -35,7 +35,7 @@ func (c *Controller) MembershipDelete(ctx context.Context,
|
|||
return err
|
||||
}
|
||||
|
||||
if err = apiauth.CheckSpace(ctx, c.authorizer, session, space, enum.PermissionSpaceEdit, false); err != nil {
|
||||
if err = apiauth.CheckSpace(ctx, c.authorizer, session, space, enum.PermissionSpaceEdit); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
|
@ -36,7 +36,7 @@ func (c *Controller) MembershipList(ctx context.Context,
|
|||
return nil, 0, err
|
||||
}
|
||||
|
||||
if err = apiauth.CheckSpace(ctx, c.authorizer, session, space, enum.PermissionSpaceView, false); err != nil {
|
||||
if err = apiauth.CheckSpace(ctx, c.authorizer, session, space, enum.PermissionSpaceView); err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
|
|
|
@ -58,7 +58,7 @@ func (c *Controller) MembershipUpdate(ctx context.Context,
|
|||
return nil, err
|
||||
}
|
||||
|
||||
if err = apiauth.CheckSpace(ctx, c.authorizer, session, space, enum.PermissionSpaceEdit, false); err != nil {
|
||||
if err = apiauth.CheckSpace(ctx, c.authorizer, session, space, enum.PermissionSpaceEdit); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
|
|
@ -49,13 +49,13 @@ func (c *Controller) Move(
|
|||
session *auth.Session,
|
||||
spaceRef string,
|
||||
in *MoveInput,
|
||||
) (*types.Space, error) {
|
||||
) (*SpaceOutput, error) {
|
||||
space, err := c.spaceStore.FindByRef(ctx, spaceRef)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err = apiauth.CheckSpace(ctx, c.authorizer, session, space, enum.PermissionSpaceEdit, false); err != nil {
|
||||
if err = apiauth.CheckSpace(ctx, c.authorizer, session, space, enum.PermissionSpaceEdit); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
@ -65,7 +65,7 @@ func (c *Controller) Move(
|
|||
|
||||
// exit early if there are no changes
|
||||
if !in.hasChanges(space) {
|
||||
return space, nil
|
||||
return GetSpaceOutput(ctx, c.publicAccess, space)
|
||||
}
|
||||
|
||||
if err = c.moveInner(
|
||||
|
@ -77,7 +77,7 @@ func (c *Controller) Move(
|
|||
return nil, err
|
||||
}
|
||||
|
||||
return space, nil
|
||||
return GetSpaceOutput(ctx, c.publicAccess, space)
|
||||
}
|
||||
|
||||
func (c *Controller) sanitizeMoveInput(in *MoveInput, isRoot bool) error {
|
||||
|
|
|
@ -43,12 +43,12 @@ func (c *Controller) Purge(
|
|||
|
||||
// authz will check the permission within the first existing parent since space was deleted.
|
||||
// purge top level space is limited to admin only.
|
||||
err = apiauth.CheckSpace(ctx, c.authorizer, session, space, enum.PermissionSpaceDelete, false)
|
||||
err = apiauth.CheckSpace(ctx, c.authorizer, session, space, enum.PermissionSpaceDelete)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to authorize on space purge: %w", err)
|
||||
}
|
||||
|
||||
return c.PurgeNoAuth(ctx, session, space.ID, deletedAt)
|
||||
return c.PurgeNoAuth(ctx, session, space)
|
||||
}
|
||||
|
||||
// PurgeNoAuth purges the space - no authorization is verified.
|
||||
|
@ -56,8 +56,7 @@ func (c *Controller) Purge(
|
|||
func (c *Controller) PurgeNoAuth(
|
||||
ctx context.Context,
|
||||
session *auth.Session,
|
||||
spaceID int64,
|
||||
deletedAt int64,
|
||||
space *types.Space,
|
||||
) error {
|
||||
// the max time we give a purge space to succeed
|
||||
const timeout = 15 * time.Minute
|
||||
|
@ -71,11 +70,11 @@ func (c *Controller) PurgeNoAuth(
|
|||
var toBeDeletedRepos []*types.Repository
|
||||
var err error
|
||||
err = c.tx.WithTx(ctx, func(ctx context.Context) error {
|
||||
toBeDeletedRepos, err = c.purgeSpaceInnerInTx(ctx, spaceID, deletedAt)
|
||||
toBeDeletedRepos, err = c.purgeSpaceInnerInTx(ctx, space.ID, *space.Deleted)
|
||||
return err
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to purge space %d in a tnx: %w", spaceID, err)
|
||||
return fmt.Errorf("failed to purge space %d in a tnx: %w", space.ID, err)
|
||||
}
|
||||
|
||||
// permanently purge all repositories in the space and its subspaces after successful space purge tnx.
|
||||
|
|
|
@ -45,7 +45,7 @@ func (c *Controller) Restore(
|
|||
spaceRef string,
|
||||
deletedAt int64,
|
||||
in *RestoreInput,
|
||||
) (*types.Space, error) {
|
||||
) (*SpaceOutput, error) {
|
||||
if err := c.sanitizeRestoreInput(in); err != nil {
|
||||
return nil, fmt.Errorf("failed to sanitize restore input: %w", err)
|
||||
}
|
||||
|
@ -56,7 +56,7 @@ func (c *Controller) Restore(
|
|||
}
|
||||
|
||||
// check view permission on the original ref.
|
||||
err = apiauth.CheckSpace(ctx, c.authorizer, session, space, enum.PermissionSpaceView, false)
|
||||
err = apiauth.CheckSpace(ctx, c.authorizer, session, space, enum.PermissionSpaceView)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to authorize on space restore: %w", err)
|
||||
}
|
||||
|
@ -74,7 +74,6 @@ func (c *Controller) Restore(
|
|||
parentSpace,
|
||||
enum.ResourceTypeSpace,
|
||||
enum.PermissionSpaceEdit,
|
||||
false,
|
||||
); err != nil {
|
||||
return nil, fmt.Errorf("authorization failed on space restore: %w", err)
|
||||
}
|
||||
|
@ -98,7 +97,11 @@ func (c *Controller) Restore(
|
|||
return nil, fmt.Errorf("failed to restore space in a tnx: %w", err)
|
||||
}
|
||||
|
||||
return space, nil
|
||||
// restored spaces will be private since public access data has deleted upon deletion.
|
||||
return &SpaceOutput{
|
||||
Space: *space,
|
||||
IsPublic: false,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c *Controller) restoreSpaceInnerInTx(
|
||||
|
|
|
@ -47,7 +47,6 @@ func (c *Controller) SoftDelete(
|
|||
session,
|
||||
space,
|
||||
enum.PermissionSpaceDelete,
|
||||
false,
|
||||
); err != nil {
|
||||
return nil, fmt.Errorf("failed to check access: %w", err)
|
||||
}
|
||||
|
@ -62,9 +61,12 @@ func (c *Controller) SoftDeleteNoAuth(
|
|||
session *auth.Session,
|
||||
space *types.Space,
|
||||
) (*SoftDeleteResponse, error) {
|
||||
var softDelRes *SoftDeleteResponse
|
||||
var err error
|
||||
err := c.publicAccess.Delete(ctx, enum.PublicResourceTypeSpace, space.Path)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to delete public access for space: %w", err)
|
||||
}
|
||||
|
||||
var softDelRes *SoftDeleteResponse
|
||||
err = c.tx.WithTx(ctx, func(ctx context.Context) error {
|
||||
softDelRes, err = c.softDeleteInnerInTx(ctx, session, space)
|
||||
return err
|
||||
|
|
|
@ -29,28 +29,30 @@ import (
|
|||
// UpdateInput is used for updating a space.
|
||||
type UpdateInput struct {
|
||||
Description *string `json:"description"`
|
||||
IsPublic *bool `json:"is_public"`
|
||||
}
|
||||
|
||||
func (in *UpdateInput) hasChanges(space *types.Space) bool {
|
||||
return (in.Description != nil && *in.Description != space.Description) ||
|
||||
(in.IsPublic != nil && *in.IsPublic != space.IsPublic)
|
||||
return in.Description != nil && *in.Description != space.Description
|
||||
}
|
||||
|
||||
// Update updates a space.
|
||||
func (c *Controller) Update(ctx context.Context, session *auth.Session,
|
||||
spaceRef string, in *UpdateInput) (*types.Space, error) {
|
||||
func (c *Controller) Update(
|
||||
ctx context.Context,
|
||||
session *auth.Session,
|
||||
spaceRef string,
|
||||
in *UpdateInput,
|
||||
) (*SpaceOutput, error) {
|
||||
space, err := c.spaceStore.FindByRef(ctx, spaceRef)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err = apiauth.CheckSpace(ctx, c.authorizer, session, space, enum.PermissionSpaceEdit, false); err != nil {
|
||||
if err = apiauth.CheckSpace(ctx, c.authorizer, session, space, enum.PermissionSpaceEdit); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !in.hasChanges(space) {
|
||||
return space, nil
|
||||
return GetSpaceOutput(ctx, c.publicAccess, space)
|
||||
}
|
||||
|
||||
if err = c.sanitizeUpdateInput(in); err != nil {
|
||||
|
@ -62,9 +64,6 @@ func (c *Controller) Update(ctx context.Context, session *auth.Session,
|
|||
if in.Description != nil {
|
||||
space.Description = *in.Description
|
||||
}
|
||||
if in.IsPublic != nil {
|
||||
space.IsPublic = *in.IsPublic
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
@ -72,16 +71,10 @@ func (c *Controller) Update(ctx context.Context, session *auth.Session,
|
|||
return nil, err
|
||||
}
|
||||
|
||||
return space, nil
|
||||
return GetSpaceOutput(ctx, c.publicAccess, space)
|
||||
}
|
||||
|
||||
func (c *Controller) sanitizeUpdateInput(in *UpdateInput) error {
|
||||
if in.IsPublic != nil {
|
||||
if *in.IsPublic && !c.publicResourceCreationEnabled {
|
||||
return errPublicSpaceCreationDisabled
|
||||
}
|
||||
}
|
||||
|
||||
if in.Description != nil {
|
||||
*in.Description = strings.TrimSpace(*in.Description)
|
||||
if err := check.Description(*in.Description); err != nil {
|
||||
|
|
|
@ -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 space
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
apiauth "github.com/harness/gitness/app/api/auth"
|
||||
"github.com/harness/gitness/app/auth"
|
||||
"github.com/harness/gitness/app/paths"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
)
|
||||
|
||||
type UpdatePublicAccessInput struct {
|
||||
IsPublic bool `json:"is_public"`
|
||||
}
|
||||
|
||||
func (c *Controller) UpdatePublicAccess(ctx context.Context,
|
||||
session *auth.Session,
|
||||
spaceRef string,
|
||||
in *UpdatePublicAccessInput,
|
||||
) (*SpaceOutput, error) {
|
||||
space, err := c.spaceStore.FindByRef(ctx, spaceRef)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err = apiauth.CheckSpace(ctx, c.authorizer, session, space, enum.PermissionSpaceEdit); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
parentPath, _, err := paths.DisectLeaf(space.Path)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to disect path %q: %w", space.Path, err)
|
||||
}
|
||||
isPublicAccessSupported, err := c.publicAccess.IsPublicAccessSupported(ctx, parentPath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf(
|
||||
"failed to check if public access is supported for parent space %q: %w",
|
||||
parentPath,
|
||||
err,
|
||||
)
|
||||
}
|
||||
if in.IsPublic && !isPublicAccessSupported {
|
||||
return nil, errPublicSpaceCreationDisabled
|
||||
}
|
||||
|
||||
isPublic, err := c.publicAccess.Get(ctx, enum.PublicResourceTypeSpace, space.Path)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to check current public access status: %w", err)
|
||||
}
|
||||
|
||||
// no op
|
||||
if isPublic == in.IsPublic {
|
||||
return &SpaceOutput{
|
||||
Space: *space,
|
||||
IsPublic: isPublic,
|
||||
}, nil
|
||||
}
|
||||
|
||||
if err = c.publicAccess.Set(ctx, enum.PublicResourceTypeSpace, space.Path, in.IsPublic); err != nil {
|
||||
return nil, fmt.Errorf("failed to update space public access: %w", err)
|
||||
}
|
||||
|
||||
return &SpaceOutput{
|
||||
Space: *space,
|
||||
IsPublic: in.IsPublic,
|
||||
}, nil
|
||||
}
|
|
@ -20,6 +20,7 @@ import (
|
|||
"github.com/harness/gitness/app/auth/authz"
|
||||
"github.com/harness/gitness/app/services/exporter"
|
||||
"github.com/harness/gitness/app/services/importer"
|
||||
"github.com/harness/gitness/app/services/publicaccess"
|
||||
"github.com/harness/gitness/app/sse"
|
||||
"github.com/harness/gitness/app/store"
|
||||
"github.com/harness/gitness/app/url"
|
||||
|
@ -42,11 +43,12 @@ func ProvideController(config *types.Config, tx dbtx.Transactor, urlProvider url
|
|||
connectorStore store.ConnectorStore, templateStore store.TemplateStore,
|
||||
spaceStore store.SpaceStore, repoStore store.RepoStore, principalStore store.PrincipalStore,
|
||||
repoCtrl *repo.Controller, membershipStore store.MembershipStore, importer *importer.Repository,
|
||||
exporter *exporter.Repository, limiter limiter.ResourceLimiter, auditService audit.Service,
|
||||
exporter *exporter.Repository, limiter limiter.ResourceLimiter, publicAccess publicaccess.Service,
|
||||
auditService audit.Service,
|
||||
) *Controller {
|
||||
return NewController(config, tx, urlProvider, sseStreamer, identifierCheck, authorizer,
|
||||
spacePathStore, pipelineStore, secretStore,
|
||||
connectorStore, templateStore,
|
||||
spaceStore, repoStore, principalStore,
|
||||
repoCtrl, membershipStore, importer, exporter, limiter, auditService)
|
||||
repoCtrl, membershipStore, importer, exporter, limiter, publicAccess, auditService)
|
||||
}
|
||||
|
|
|
@ -65,7 +65,6 @@ func (c *Controller) getRepoCheckAccess(ctx context.Context,
|
|||
session *auth.Session,
|
||||
repoRef string,
|
||||
reqPermission enum.Permission,
|
||||
orPublic bool,
|
||||
) (*types.Repository, error) {
|
||||
if repoRef == "" {
|
||||
return nil, usererror.BadRequest("A valid repository reference must be provided.")
|
||||
|
@ -76,7 +75,7 @@ func (c *Controller) getRepoCheckAccess(ctx context.Context,
|
|||
return nil, fmt.Errorf("failed to find repo: %w", err)
|
||||
}
|
||||
|
||||
if err = apiauth.CheckRepo(ctx, c.authorizer, session, repo, reqPermission, orPublic); err != nil {
|
||||
if err = apiauth.CheckRepo(ctx, c.authorizer, session, repo, reqPermission); err != nil {
|
||||
return nil, fmt.Errorf("failed to verify authorization: %w", err)
|
||||
}
|
||||
|
||||
|
|
|
@ -31,7 +31,7 @@ func (c *Controller) Download(
|
|||
repoRef string,
|
||||
filePath string,
|
||||
) (string, io.ReadCloser, error) {
|
||||
repo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionRepoView, true)
|
||||
repo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionRepoView)
|
||||
if err != nil {
|
||||
return "", nil, fmt.Errorf("failed to acquire access to repo: %w", err)
|
||||
}
|
||||
|
|
|
@ -42,7 +42,7 @@ func (c *Controller) Upload(ctx context.Context,
|
|||
file io.Reader,
|
||||
) (*Result, error) {
|
||||
// Permission check to see if the user in request has access to the repo.
|
||||
repo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionRepoView, false)
|
||||
repo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionRepoView)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to acquire access to repo: %w", err)
|
||||
}
|
||||
|
|
|
@ -74,7 +74,7 @@ func (c *Controller) getRepoCheckAccess(ctx context.Context,
|
|||
return nil, fmt.Errorf("failed to find repo: %w", err)
|
||||
}
|
||||
|
||||
if err = apiauth.CheckRepo(ctx, c.authorizer, session, repo, reqPermission, false); err != nil {
|
||||
if err = apiauth.CheckRepo(ctx, c.authorizer, session, repo, reqPermission); err != nil {
|
||||
return nil, fmt.Errorf("failed to verify authorization: %w", err)
|
||||
}
|
||||
|
||||
|
|
|
@ -25,14 +25,14 @@ import (
|
|||
func HandleFind(principalCtrl principal.Controller) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
|
||||
session, _ := request.AuthSessionFrom(ctx)
|
||||
principalID, err := request.GetPrincipalIDFromPath(r)
|
||||
if err != nil {
|
||||
render.TranslatedUserError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
|
||||
principalInfo, err := principalCtrl.Find(ctx, principalID)
|
||||
principalInfo, err := principalCtrl.Find(ctx, session, principalID)
|
||||
if err != nil {
|
||||
render.TranslatedUserError(ctx, w, err)
|
||||
return
|
||||
|
|
|
@ -26,8 +26,9 @@ func HandleList(principalCtrl principal.Controller) http.HandlerFunc {
|
|||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
|
||||
session, _ := request.AuthSessionFrom(ctx)
|
||||
principalFilter := request.ParsePrincipalFilter(r)
|
||||
principalInfos, err := principalCtrl.List(ctx, principalFilter)
|
||||
principalInfos, err := principalCtrl.List(ctx, session, principalFilter)
|
||||
if err != nil {
|
||||
render.TranslatedUserError(ctx, w, err)
|
||||
return
|
||||
|
|
|
@ -23,6 +23,7 @@ import (
|
|||
"github.com/harness/gitness/app/api/controller/repo"
|
||||
"github.com/harness/gitness/app/api/render"
|
||||
"github.com/harness/gitness/app/api/request"
|
||||
"github.com/harness/gitness/app/auth"
|
||||
"github.com/harness/gitness/app/url"
|
||||
)
|
||||
|
||||
|
@ -51,7 +52,7 @@ func HandleGitInfoRefs(repoCtrl *repo.Controller, urlProvider url.Provider) http
|
|||
w.Header().Set("Content-Type", fmt.Sprintf("application/x-git-%s-advertisement", service))
|
||||
|
||||
err = repoCtrl.GitInfoRefs(ctx, session, repoRef, service, gitProtocol, w)
|
||||
if errors.Is(err, apiauth.ErrNotAuthenticated) {
|
||||
if errors.Is(err, apiauth.ErrNotAuthorized) && auth.IsAnonymousSession(session) {
|
||||
renderBasicAuth(w, urlProvider)
|
||||
return
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ import (
|
|||
"github.com/harness/gitness/app/api/controller/repo"
|
||||
"github.com/harness/gitness/app/api/render"
|
||||
"github.com/harness/gitness/app/api/request"
|
||||
"github.com/harness/gitness/app/auth"
|
||||
"github.com/harness/gitness/app/url"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
|
||||
|
@ -71,7 +72,7 @@ func HandleGitServicePack(
|
|||
w.Header().Set("Content-Type", fmt.Sprintf("application/x-git-%s-result", service))
|
||||
|
||||
err = repoCtrl.GitServicePack(ctx, session, repoRef, service, gitProtocol, dataReader, w)
|
||||
if errors.Is(err, apiauth.ErrNotAuthenticated) {
|
||||
if errors.Is(err, apiauth.ErrNotAuthorized) && auth.IsAnonymousSession(session) {
|
||||
renderBasicAuth(w, urlProvider)
|
||||
return
|
||||
}
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
// 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 repo
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
"github.com/harness/gitness/app/api/controller/repo"
|
||||
"github.com/harness/gitness/app/api/render"
|
||||
"github.com/harness/gitness/app/api/request"
|
||||
)
|
||||
|
||||
func HandleUpdatePublicAccess(repoCtrl *repo.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(repo.UpdatePublicAccessInput)
|
||||
err = json.NewDecoder(r.Body).Decode(in)
|
||||
if err != nil {
|
||||
render.BadRequestf(ctx, w, "Invalid Request Body: %s.", err)
|
||||
return
|
||||
}
|
||||
|
||||
res, err := repoCtrl.UpdatePublicAccess(ctx, session, repoRef, in)
|
||||
if err != nil {
|
||||
render.TranslatedUserError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
|
||||
render.JSON(w, http.StatusOK, res)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
// 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 space
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
"github.com/harness/gitness/app/api/controller/space"
|
||||
"github.com/harness/gitness/app/api/render"
|
||||
"github.com/harness/gitness/app/api/request"
|
||||
)
|
||||
|
||||
// HandleUpdatePublicAccess updates public access mode of an existing space.
|
||||
func HandleUpdatePublicAccess(spaceCtrl *space.Controller) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
session, _ := request.AuthSessionFrom(ctx)
|
||||
spaceRef, err := request.GetSpaceRefFromPath(r)
|
||||
if err != nil {
|
||||
render.TranslatedUserError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
|
||||
in := new(space.UpdatePublicAccessInput)
|
||||
err = json.NewDecoder(r.Body).Decode(in)
|
||||
if err != nil {
|
||||
render.BadRequestf(ctx, w, "Invalid request body: %s.", err)
|
||||
return
|
||||
}
|
||||
|
||||
space, err := spaceCtrl.UpdatePublicAccess(ctx, session, spaceRef, in)
|
||||
if err != nil {
|
||||
render.TranslatedUserError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
|
||||
render.JSON(w, http.StatusOK, space)
|
||||
}
|
||||
}
|
|
@ -20,6 +20,7 @@ import (
|
|||
|
||||
"github.com/harness/gitness/app/api/render"
|
||||
"github.com/harness/gitness/app/api/request"
|
||||
"github.com/harness/gitness/app/auth"
|
||||
"github.com/harness/gitness/app/auth/authn"
|
||||
|
||||
"github.com/rs/zerolog"
|
||||
|
@ -29,50 +30,24 @@ import (
|
|||
// Attempt returns an http.HandlerFunc middleware that authenticates
|
||||
// the http.Request if authentication payload is available.
|
||||
func Attempt(authenticator authn.Authenticator) func(http.Handler) http.Handler {
|
||||
return performAuthentication(authenticator, false)
|
||||
}
|
||||
|
||||
// Required returns an http.HandlerFunc middleware that authenticates
|
||||
// the http.Request and fails the request if no auth data was available.
|
||||
func Required(authenticator authn.Authenticator) func(http.Handler) http.Handler {
|
||||
return performAuthentication(authenticator, true)
|
||||
}
|
||||
|
||||
// performAuthentication returns an http.HandlerFunc middleware that authenticates
|
||||
// the http.Request if authentication payload is available.
|
||||
// Depending on whether it is required or not, the request will be failed.
|
||||
func performAuthentication(
|
||||
authenticator authn.Authenticator,
|
||||
required bool,
|
||||
) func(http.Handler) http.Handler {
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
log := hlog.FromRequest(r)
|
||||
|
||||
session, err := authenticator.Authenticate(r)
|
||||
if err != nil {
|
||||
if !errors.Is(err, authn.ErrNoAuthData) {
|
||||
// log error to help with investigating any auth related errors
|
||||
log.Warn().Err(err).Msg("authentication failed")
|
||||
}
|
||||
if err != nil && !errors.Is(err, authn.ErrNoAuthData) {
|
||||
log.Debug().Err(err).Msg("authentication failed")
|
||||
|
||||
if required {
|
||||
render.Unauthorized(ctx, w)
|
||||
return
|
||||
}
|
||||
|
||||
// if there was no (valid) auth data in the request, then continue without session
|
||||
next.ServeHTTP(w, r)
|
||||
render.Unauthorized(ctx, w)
|
||||
return
|
||||
}
|
||||
|
||||
if session == nil {
|
||||
// when err == nil session should never be nil!
|
||||
log.Error().Msg("auth session is nil eventhough the authenticator didn't return any error!")
|
||||
|
||||
render.InternalError(ctx, w)
|
||||
return
|
||||
if errors.Is(err, authn.ErrNoAuthData) {
|
||||
log.Info().Msg("No authentication data found, continue as anonymous")
|
||||
session = &auth.Session{
|
||||
Principal: auth.AnonymousPrincipal,
|
||||
}
|
||||
}
|
||||
|
||||
// Update the logging context and inject principal in context
|
||||
|
|
|
@ -200,6 +200,11 @@ type restoreRequest struct {
|
|||
repo.RestoreInput
|
||||
}
|
||||
|
||||
type updateRepoPublicAccessRequest struct {
|
||||
repoRequest
|
||||
repo.UpdatePublicAccessInput
|
||||
}
|
||||
|
||||
type securitySettingsRequest struct {
|
||||
repoRequest
|
||||
reposettings.SecuritySettings
|
||||
|
@ -605,7 +610,7 @@ func repoOperations(reflector *openapi3.Reflector) {
|
|||
createRepository.WithMapOfAnything(map[string]interface{}{"operationId": "createRepository"})
|
||||
createRepository.WithParameters(queryParameterSpacePath)
|
||||
_ = reflector.SetRequest(&createRepository, new(createRepositoryRequest), http.MethodPost)
|
||||
_ = reflector.SetJSONResponse(&createRepository, new(types.Repository), http.StatusCreated)
|
||||
_ = reflector.SetJSONResponse(&createRepository, new(repo.RepositoryOutput), http.StatusCreated)
|
||||
_ = reflector.SetJSONResponse(&createRepository, new(usererror.Error), http.StatusBadRequest)
|
||||
_ = reflector.SetJSONResponse(&createRepository, new(usererror.Error), http.StatusInternalServerError)
|
||||
_ = reflector.SetJSONResponse(&createRepository, new(usererror.Error), http.StatusUnauthorized)
|
||||
|
@ -617,7 +622,7 @@ func repoOperations(reflector *openapi3.Reflector) {
|
|||
importRepository.WithMapOfAnything(map[string]interface{}{"operationId": "importRepository"})
|
||||
importRepository.WithParameters(queryParameterSpacePath)
|
||||
_ = reflector.SetRequest(&importRepository, &struct{ repo.ImportInput }{}, http.MethodPost)
|
||||
_ = reflector.SetJSONResponse(&importRepository, new(types.Repository), http.StatusCreated)
|
||||
_ = reflector.SetJSONResponse(&importRepository, new(repo.RepositoryOutput), http.StatusCreated)
|
||||
_ = reflector.SetJSONResponse(&importRepository, new(usererror.Error), http.StatusBadRequest)
|
||||
_ = reflector.SetJSONResponse(&importRepository, new(usererror.Error), http.StatusInternalServerError)
|
||||
_ = reflector.SetJSONResponse(&importRepository, new(usererror.Error), http.StatusUnauthorized)
|
||||
|
@ -628,7 +633,7 @@ func repoOperations(reflector *openapi3.Reflector) {
|
|||
opFind.WithTags("repository")
|
||||
opFind.WithMapOfAnything(map[string]interface{}{"operationId": "findRepository"})
|
||||
_ = reflector.SetRequest(&opFind, new(repoRequest), http.MethodGet)
|
||||
_ = reflector.SetJSONResponse(&opFind, new(types.Repository), http.StatusOK)
|
||||
_ = reflector.SetJSONResponse(&opFind, new(repo.RepositoryOutput), http.StatusOK)
|
||||
_ = reflector.SetJSONResponse(&opFind, new(usererror.Error), http.StatusInternalServerError)
|
||||
_ = reflector.SetJSONResponse(&opFind, new(usererror.Error), http.StatusUnauthorized)
|
||||
_ = reflector.SetJSONResponse(&opFind, new(usererror.Error), http.StatusForbidden)
|
||||
|
@ -639,7 +644,7 @@ func repoOperations(reflector *openapi3.Reflector) {
|
|||
opUpdate.WithTags("repository")
|
||||
opUpdate.WithMapOfAnything(map[string]interface{}{"operationId": "updateRepository"})
|
||||
_ = reflector.SetRequest(&opUpdate, new(updateRepoRequest), http.MethodPatch)
|
||||
_ = reflector.SetJSONResponse(&opUpdate, new(types.Repository), http.StatusOK)
|
||||
_ = reflector.SetJSONResponse(&opUpdate, new(repo.RepositoryOutput), http.StatusOK)
|
||||
_ = reflector.SetJSONResponse(&opUpdate, new(usererror.Error), http.StatusBadRequest)
|
||||
_ = reflector.SetJSONResponse(&opUpdate, new(usererror.Error), http.StatusInternalServerError)
|
||||
_ = reflector.SetJSONResponse(&opUpdate, new(usererror.Error), http.StatusUnauthorized)
|
||||
|
@ -675,7 +680,7 @@ func repoOperations(reflector *openapi3.Reflector) {
|
|||
opRestore.WithMapOfAnything(map[string]interface{}{"operationId": "restoreRepository"})
|
||||
opRestore.WithParameters(queryParameterDeletedAt)
|
||||
_ = reflector.SetRequest(&opRestore, new(restoreRequest), http.MethodPost)
|
||||
_ = reflector.SetJSONResponse(&opRestore, new(types.Repository), http.StatusOK)
|
||||
_ = reflector.SetJSONResponse(&opRestore, new(repo.RepositoryOutput), http.StatusOK)
|
||||
_ = reflector.SetJSONResponse(&opRestore, new(usererror.Error), http.StatusBadRequest)
|
||||
_ = reflector.SetJSONResponse(&opRestore, new(usererror.Error), http.StatusInternalServerError)
|
||||
_ = reflector.SetJSONResponse(&opRestore, new(usererror.Error), http.StatusUnauthorized)
|
||||
|
@ -687,13 +692,28 @@ func repoOperations(reflector *openapi3.Reflector) {
|
|||
opMove.WithTags("repository")
|
||||
opMove.WithMapOfAnything(map[string]interface{}{"operationId": "moveRepository"})
|
||||
_ = reflector.SetRequest(&opMove, new(moveRepoRequest), http.MethodPost)
|
||||
_ = reflector.SetJSONResponse(&opMove, new(types.Repository), http.StatusOK)
|
||||
_ = reflector.SetJSONResponse(&opMove, new(repo.RepositoryOutput), http.StatusOK)
|
||||
_ = reflector.SetJSONResponse(&opMove, new(usererror.Error), http.StatusBadRequest)
|
||||
_ = reflector.SetJSONResponse(&opMove, new(usererror.Error), http.StatusInternalServerError)
|
||||
_ = reflector.SetJSONResponse(&opMove, new(usererror.Error), http.StatusUnauthorized)
|
||||
_ = reflector.SetJSONResponse(&opMove, new(usererror.Error), http.StatusForbidden)
|
||||
_ = reflector.Spec.AddOperation(http.MethodPost, "/repos/{repo_ref}/move", opMove)
|
||||
|
||||
opUpdatePublicAccess := openapi3.Operation{}
|
||||
opUpdatePublicAccess.WithTags("repository")
|
||||
opUpdatePublicAccess.WithMapOfAnything(
|
||||
map[string]interface{}{"operationId": "updatePublicAccess"})
|
||||
_ = reflector.SetRequest(
|
||||
&opUpdatePublicAccess, new(updateRepoPublicAccessRequest), http.MethodPost)
|
||||
_ = reflector.SetJSONResponse(&opUpdatePublicAccess, new(repo.RepositoryOutput), http.StatusOK)
|
||||
_ = reflector.SetJSONResponse(&opUpdatePublicAccess, new(usererror.Error), http.StatusBadRequest)
|
||||
_ = reflector.SetJSONResponse(&opUpdatePublicAccess, new(usererror.Error), http.StatusInternalServerError)
|
||||
_ = reflector.SetJSONResponse(&opUpdatePublicAccess, new(usererror.Error), http.StatusUnauthorized)
|
||||
_ = reflector.SetJSONResponse(&opUpdatePublicAccess, new(usererror.Error), http.StatusForbidden)
|
||||
_ = reflector.SetJSONResponse(&opUpdatePublicAccess, new(usererror.Error), http.StatusNotFound)
|
||||
_ = reflector.Spec.AddOperation(
|
||||
http.MethodPost, "/repos/{repo_ref}/public-access", opUpdatePublicAccess)
|
||||
|
||||
opServiceAccounts := openapi3.Operation{}
|
||||
opServiceAccounts.WithTags("repository")
|
||||
opServiceAccounts.WithMapOfAnything(map[string]interface{}{"operationId": "listRepositoryServiceAccounts"})
|
||||
|
|
|
@ -40,6 +40,10 @@ type updateSpaceRequest struct {
|
|||
space.UpdateInput
|
||||
}
|
||||
|
||||
type updateSpacePublicAccessRequest struct {
|
||||
spaceRequest
|
||||
space.UpdatePublicAccessInput
|
||||
}
|
||||
type moveSpaceRequest struct {
|
||||
spaceRequest
|
||||
space.MoveInput
|
||||
|
@ -173,7 +177,7 @@ func spaceOperations(reflector *openapi3.Reflector) {
|
|||
opCreate.WithTags("space")
|
||||
opCreate.WithMapOfAnything(map[string]interface{}{"operationId": "createSpace"})
|
||||
_ = reflector.SetRequest(&opCreate, new(createSpaceRequest), http.MethodPost)
|
||||
_ = reflector.SetJSONResponse(&opCreate, new(types.Space), http.StatusCreated)
|
||||
_ = reflector.SetJSONResponse(&opCreate, new(space.SpaceOutput), http.StatusCreated)
|
||||
_ = reflector.SetJSONResponse(&opCreate, new(usererror.Error), http.StatusBadRequest)
|
||||
_ = reflector.SetJSONResponse(&opCreate, new(usererror.Error), http.StatusInternalServerError)
|
||||
_ = reflector.SetJSONResponse(&opCreate, new(usererror.Error), http.StatusUnauthorized)
|
||||
|
@ -184,7 +188,7 @@ func spaceOperations(reflector *openapi3.Reflector) {
|
|||
opImport.WithTags("space")
|
||||
opImport.WithMapOfAnything(map[string]interface{}{"operationId": "importSpace"})
|
||||
_ = reflector.SetRequest(&opImport, &struct{ space.ImportInput }{}, http.MethodPost)
|
||||
_ = reflector.SetJSONResponse(&opImport, new(types.Space), http.StatusCreated)
|
||||
_ = reflector.SetJSONResponse(&opImport, new(space.SpaceOutput), http.StatusCreated)
|
||||
_ = reflector.SetJSONResponse(&opImport, new(usererror.Error), http.StatusBadRequest)
|
||||
_ = reflector.SetJSONResponse(&opImport, new(usererror.Error), http.StatusInternalServerError)
|
||||
_ = reflector.SetJSONResponse(&opImport, new(usererror.Error), http.StatusUnauthorized)
|
||||
|
@ -228,7 +232,7 @@ func spaceOperations(reflector *openapi3.Reflector) {
|
|||
opGet.WithTags("space")
|
||||
opGet.WithMapOfAnything(map[string]interface{}{"operationId": "getSpace"})
|
||||
_ = reflector.SetRequest(&opGet, new(spaceRequest), http.MethodGet)
|
||||
_ = reflector.SetJSONResponse(&opGet, new(types.Space), http.StatusOK)
|
||||
_ = reflector.SetJSONResponse(&opGet, new(space.SpaceOutput), http.StatusOK)
|
||||
_ = reflector.SetJSONResponse(&opGet, new(usererror.Error), http.StatusInternalServerError)
|
||||
_ = reflector.SetJSONResponse(&opGet, new(usererror.Error), http.StatusUnauthorized)
|
||||
_ = reflector.SetJSONResponse(&opGet, new(usererror.Error), http.StatusForbidden)
|
||||
|
@ -239,7 +243,7 @@ func spaceOperations(reflector *openapi3.Reflector) {
|
|||
opUpdate.WithTags("space")
|
||||
opUpdate.WithMapOfAnything(map[string]interface{}{"operationId": "updateSpace"})
|
||||
_ = reflector.SetRequest(&opUpdate, new(updateSpaceRequest), http.MethodPatch)
|
||||
_ = reflector.SetJSONResponse(&opUpdate, new(types.Space), http.StatusOK)
|
||||
_ = reflector.SetJSONResponse(&opUpdate, new(space.SpaceOutput), http.StatusOK)
|
||||
_ = reflector.SetJSONResponse(&opUpdate, new(usererror.Error), http.StatusBadRequest)
|
||||
_ = reflector.SetJSONResponse(&opUpdate, new(usererror.Error), http.StatusInternalServerError)
|
||||
_ = reflector.SetJSONResponse(&opUpdate, new(usererror.Error), http.StatusUnauthorized)
|
||||
|
@ -247,6 +251,21 @@ func spaceOperations(reflector *openapi3.Reflector) {
|
|||
_ = reflector.SetJSONResponse(&opUpdate, new(usererror.Error), http.StatusNotFound)
|
||||
_ = reflector.Spec.AddOperation(http.MethodPatch, "/spaces/{space_ref}", opUpdate)
|
||||
|
||||
opUpdatePublicAccess := openapi3.Operation{}
|
||||
opUpdatePublicAccess.WithTags("space")
|
||||
opUpdatePublicAccess.WithMapOfAnything(
|
||||
map[string]interface{}{"operationId": "updatePublicAccess"})
|
||||
_ = reflector.SetRequest(
|
||||
&opUpdatePublicAccess, new(updateSpacePublicAccessRequest), http.MethodPost)
|
||||
_ = reflector.SetJSONResponse(&opUpdatePublicAccess, new(space.SpaceOutput), http.StatusOK)
|
||||
_ = reflector.SetJSONResponse(&opUpdatePublicAccess, new(usererror.Error), http.StatusBadRequest)
|
||||
_ = reflector.SetJSONResponse(&opUpdatePublicAccess, new(usererror.Error), http.StatusInternalServerError)
|
||||
_ = reflector.SetJSONResponse(&opUpdatePublicAccess, new(usererror.Error), http.StatusUnauthorized)
|
||||
_ = reflector.SetJSONResponse(&opUpdatePublicAccess, new(usererror.Error), http.StatusForbidden)
|
||||
_ = reflector.SetJSONResponse(&opUpdatePublicAccess, new(usererror.Error), http.StatusNotFound)
|
||||
_ = reflector.Spec.AddOperation(
|
||||
http.MethodPost, "/spaces/{space_ref}/public-access", opUpdatePublicAccess)
|
||||
|
||||
opDelete := openapi3.Operation{}
|
||||
opDelete.WithTags("space")
|
||||
opDelete.WithMapOfAnything(map[string]interface{}{"operationId": "deleteSpace"})
|
||||
|
@ -275,7 +294,7 @@ func spaceOperations(reflector *openapi3.Reflector) {
|
|||
opRestore.WithMapOfAnything(map[string]interface{}{"operationId": "restoreSpace"})
|
||||
opRestore.WithParameters(queryParameterDeletedAt)
|
||||
_ = reflector.SetRequest(&opRestore, new(restoreSpaceRequest), http.MethodPost)
|
||||
_ = reflector.SetJSONResponse(&opRestore, new(types.Space), http.StatusOK)
|
||||
_ = reflector.SetJSONResponse(&opRestore, new(space.SpaceOutput), http.StatusOK)
|
||||
_ = reflector.SetJSONResponse(&opRestore, new(usererror.Error), http.StatusBadRequest)
|
||||
_ = reflector.SetJSONResponse(&opRestore, new(usererror.Error), http.StatusInternalServerError)
|
||||
_ = reflector.SetJSONResponse(&opRestore, new(usererror.Error), http.StatusUnauthorized)
|
||||
|
@ -287,7 +306,7 @@ func spaceOperations(reflector *openapi3.Reflector) {
|
|||
opMove.WithTags("space")
|
||||
opMove.WithMapOfAnything(map[string]interface{}{"operationId": "moveSpace"})
|
||||
_ = reflector.SetRequest(&opMove, new(moveSpaceRequest), http.MethodPost)
|
||||
_ = reflector.SetJSONResponse(&opMove, new(types.Space), http.StatusOK)
|
||||
_ = reflector.SetJSONResponse(&opMove, new(space.SpaceOutput), http.StatusOK)
|
||||
_ = reflector.SetJSONResponse(&opMove, new(usererror.Error), http.StatusBadRequest)
|
||||
_ = reflector.SetJSONResponse(&opMove, new(usererror.Error), http.StatusInternalServerError)
|
||||
_ = reflector.SetJSONResponse(&opMove, new(usererror.Error), http.StatusUnauthorized)
|
||||
|
@ -301,7 +320,7 @@ func spaceOperations(reflector *openapi3.Reflector) {
|
|||
opSpaces.WithParameters(queryParameterQuerySpace, queryParameterSortSpace, queryParameterOrder,
|
||||
queryParameterPage, queryParameterLimit)
|
||||
_ = reflector.SetRequest(&opSpaces, new(spaceRequest), http.MethodGet)
|
||||
_ = reflector.SetJSONResponse(&opSpaces, []types.Space{}, http.StatusOK)
|
||||
_ = reflector.SetJSONResponse(&opSpaces, []space.SpaceOutput{}, http.StatusOK)
|
||||
_ = reflector.SetJSONResponse(&opSpaces, new(usererror.Error), http.StatusInternalServerError)
|
||||
_ = reflector.SetJSONResponse(&opSpaces, new(usererror.Error), http.StatusUnauthorized)
|
||||
_ = reflector.SetJSONResponse(&opSpaces, new(usererror.Error), http.StatusForbidden)
|
||||
|
|
|
@ -21,6 +21,7 @@ import (
|
|||
apiauth "github.com/harness/gitness/app/api/auth"
|
||||
"github.com/harness/gitness/app/api/controller/limiter"
|
||||
"github.com/harness/gitness/app/services/codeowners"
|
||||
"github.com/harness/gitness/app/services/publicaccess"
|
||||
"github.com/harness/gitness/app/services/webhook"
|
||||
"github.com/harness/gitness/blob"
|
||||
"github.com/harness/gitness/errors"
|
||||
|
@ -53,8 +54,6 @@ func Translate(ctx context.Context, err error) *Error {
|
|||
return rError
|
||||
|
||||
// api auth errors
|
||||
case errors.Is(err, apiauth.ErrNotAuthenticated):
|
||||
return ErrUnauthorized
|
||||
case errors.Is(err, apiauth.ErrNotAuthorized):
|
||||
return ErrForbidden
|
||||
|
||||
|
@ -113,6 +112,10 @@ func Translate(ctx context.Context, err error) *Error {
|
|||
case errors.As(err, &lockError):
|
||||
return errorFromLockError(lockError)
|
||||
|
||||
// public access errors
|
||||
case errors.Is(err, publicaccess.ErrPublicAccessNotAllowed):
|
||||
return BadRequestf("Public access on resources is not allowed.")
|
||||
|
||||
// unknown error
|
||||
default:
|
||||
log.Ctx(ctx).Warn().Err(err).Msgf("Unable to translate error - returning Internal Error.")
|
||||
|
|
|
@ -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 auth
|
||||
|
||||
import (
|
||||
"github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
)
|
||||
|
||||
// AnonymousPrincipal is an in-memory principal for users with no auth data.
|
||||
// Authorizer is in charge of handling anonymous access.
|
||||
var AnonymousPrincipal = types.Principal{
|
||||
ID: -1,
|
||||
UID: types.AnonymousPrincipalUID,
|
||||
Type: enum.PrincipalTypeUser,
|
||||
}
|
||||
|
||||
func IsAnonymousSession(session *Session) bool {
|
||||
return session != nil && session.Principal.UID == types.AnonymousPrincipalUID
|
||||
}
|
|
@ -20,6 +20,7 @@ import (
|
|||
|
||||
"github.com/harness/gitness/app/auth"
|
||||
"github.com/harness/gitness/app/paths"
|
||||
"github.com/harness/gitness/app/services/publicaccess"
|
||||
"github.com/harness/gitness/app/store"
|
||||
"github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
|
@ -32,15 +33,18 @@ var _ Authorizer = (*MembershipAuthorizer)(nil)
|
|||
type MembershipAuthorizer struct {
|
||||
permissionCache PermissionCache
|
||||
spaceStore store.SpaceStore
|
||||
publicAccess publicaccess.Service
|
||||
}
|
||||
|
||||
func NewMembershipAuthorizer(
|
||||
permissionCache PermissionCache,
|
||||
spaceStore store.SpaceStore,
|
||||
publicAccess publicaccess.Service,
|
||||
) *MembershipAuthorizer {
|
||||
return &MembershipAuthorizer{
|
||||
permissionCache: permissionCache,
|
||||
spaceStore: spaceStore,
|
||||
publicAccess: publicAccess,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -51,7 +55,15 @@ func (a *MembershipAuthorizer) Check(
|
|||
resource *types.Resource,
|
||||
permission enum.Permission,
|
||||
) (bool, error) {
|
||||
// public access - not expected to come here as of now (have to refactor that part)
|
||||
publicAccessAllowed, err := a.CheckPublicAccess(ctx, scope, resource, permission)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("failed to check public access: %w", err)
|
||||
}
|
||||
|
||||
if publicAccessAllowed {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
if session == nil {
|
||||
log.Ctx(ctx).Warn().Msgf(
|
||||
"public access request for %s in scope %#v got to authorizer",
|
||||
|
@ -102,9 +114,14 @@ func (a *MembershipAuthorizer) Check(
|
|||
spacePath = scope.SpacePath
|
||||
|
||||
case enum.ResourceTypeUser:
|
||||
// a user is allowed to view / edit themselves
|
||||
// a user is allowed to edit themselves
|
||||
if resource.Identifier == session.Principal.UID &&
|
||||
(permission == enum.PermissionUserView || permission == enum.PermissionUserEdit) {
|
||||
permission == enum.PermissionUserEdit {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// user can see all other users in the system.
|
||||
if permission == enum.PermissionUserView {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue