diff --git a/internal/api/auth/pipeline.go b/internal/api/auth/pipeline.go new file mode 100644 index 000000000..73d24fac8 --- /dev/null +++ b/internal/api/auth/pipeline.go @@ -0,0 +1,29 @@ +// Copyright 2022 Harness Inc. All rights reserved. +// Use of this source code is governed by the Polyform Free Trial License +// that can be found in the LICENSE.md file for this repository. + +package auth + +import ( + "context" + + "github.com/harness/gitness/internal/auth" + "github.com/harness/gitness/internal/auth/authz" + "github.com/harness/gitness/types" + "github.com/harness/gitness/types/enum" +) + +// CheckRepo checks if a repo specific permission is granted for the current auth session +// in the scope of its parent. +// Returns nil if the permission is granted, otherwise returns an error. +// NotAuthenticated, NotAuthorized, or any underlying error. +func CheckPipeline(ctx context.Context, authorizer authz.Authorizer, session *auth.Session, + parentPath, uid string, permission enum.Permission) error { + scope := &types.Scope{SpacePath: parentPath} + resource := &types.Resource{ + Type: enum.ResourceTypeRepo, + Name: uid, + } + + return Check(ctx, authorizer, session, scope, resource, permission) +} diff --git a/internal/api/controller/execution/create.go b/internal/api/controller/execution/create.go index 8e098b815..62a8679ef 100644 --- a/internal/api/controller/execution/create.go +++ b/internal/api/controller/execution/create.go @@ -9,9 +9,11 @@ import ( "fmt" "time" + apiauth "github.com/harness/gitness/internal/api/auth" "github.com/harness/gitness/internal/api/usererror" "github.com/harness/gitness/internal/auth" "github.com/harness/gitness/types" + "github.com/harness/gitness/types/enum" ) var ( @@ -27,12 +29,6 @@ type CreateInput struct { // Create creates a new execution func (c *Controller) Create(ctx context.Context, session *auth.Session, spaceRef string, uid string, in *CreateInput) (*types.Execution, error) { - // TODO: Add auth - // parentSpace, err := c.getSpaceCheckAuthRepoCreation(ctx, session, in.ParentRef) - // if err != nil { - // return nil, err - // } - space, err := c.spaceStore.FindByRef(ctx, spaceRef) if err != nil { return nil, fmt.Errorf("could not find space: %w", err) @@ -47,6 +43,11 @@ func (c *Controller) Create(ctx context.Context, session *auth.Session, spaceRef return nil, err } + err = apiauth.CheckPipeline(ctx, c.authorizer, session, space.Path, pipeline.UID, enum.PermissionPipelineExecute) + if err != nil { + return nil, err + } + pipeline, err = c.pipelineStore.Increment(ctx, pipeline) if err != nil { return nil, err diff --git a/internal/api/controller/execution/delete.go b/internal/api/controller/execution/delete.go index 8f308e8fd..f60562c77 100644 --- a/internal/api/controller/execution/delete.go +++ b/internal/api/controller/execution/delete.go @@ -8,7 +8,9 @@ import ( "context" "fmt" + apiauth "github.com/harness/gitness/internal/api/auth" "github.com/harness/gitness/internal/auth" + "github.com/harness/gitness/types/enum" ) // Delete deletes a pipeline. @@ -17,15 +19,16 @@ func (c *Controller) Delete(ctx context.Context, session *auth.Session, spaceRef if err != nil { return err } - // TODO: Add auth - // if err = apiauth.CheckSpace(ctx, c.authorizer, session, space, enum.PermissionSpaceDelete, false); err != nil { - // return err - // } + // TODO: uncomment when soft delete is implemented pipeline, err := c.pipelineStore.FindByUID(ctx, space.ID, uid) if err != nil { return err } + err = apiauth.CheckPipeline(ctx, c.authorizer, session, space.Path, pipeline.UID, enum.PermissionPipelineDelete) + if err != nil { + return err + } err = c.executionStore.Delete(ctx, pipeline.ID, n) if err != nil { return fmt.Errorf("could not delete execution: %w", err) diff --git a/internal/api/controller/execution/find.go b/internal/api/controller/execution/find.go index 670bb729e..ce3c23be0 100644 --- a/internal/api/controller/execution/find.go +++ b/internal/api/controller/execution/find.go @@ -7,8 +7,10 @@ package execution import ( "context" + apiauth "github.com/harness/gitness/internal/api/auth" "github.com/harness/gitness/internal/auth" "github.com/harness/gitness/types" + "github.com/harness/gitness/types/enum" ) // Find finds a pipeline. @@ -17,15 +19,16 @@ func (c *Controller) Find(ctx context.Context, session *auth.Session, spaceRef s if err != nil { return nil, err } - // TODO: Add auth - // if err = apiauth.CheckSpace(ctx, c.authorizer, session, space, enum.PermissionSpaceDelete, false); err != nil { - // return err - // } pipeline, err := c.pipelineStore.FindByUID(ctx, space.ID, uid) if err != nil { return nil, err } + err = apiauth.CheckPipeline(ctx, c.authorizer, session, space.Path, pipeline.UID, enum.PermissionPipelineView) + if err != nil { + return nil, err + } + return c.executionStore.Find(ctx, pipeline.ID, n) } diff --git a/internal/api/controller/execution/list.go b/internal/api/controller/execution/list.go index 12907a8ab..3e4550c23 100644 --- a/internal/api/controller/execution/list.go +++ b/internal/api/controller/execution/list.go @@ -6,12 +6,13 @@ package execution import ( "context" + apiauth "github.com/harness/gitness/internal/api/auth" "github.com/harness/gitness/internal/auth" "github.com/harness/gitness/types" + "github.com/harness/gitness/types/enum" ) -// ListRepositories lists the repositories of a space. -// TODO: move to different file +// List lists the executions in a pipeline. func (c *Controller) List( ctx context.Context, session *auth.Session, @@ -27,10 +28,11 @@ func (c *Controller) List( return nil, 0, err } - // TODO: Add auth - // if err = apiauth.CheckSpace(ctx, c.authorizer, session, space, enum.PermissionRepoView, true); err != nil { - // return nil, 0, err - // } + err = apiauth.CheckPipeline(ctx, c.authorizer, session, space.Path, pipeline.UID, enum.PermissionPipelineView) + if err != nil { + return nil, 0, err + } + executions, err := c.executionStore.List(ctx, pipeline.ID, filter) if err != nil { return nil, 0, err diff --git a/internal/api/controller/execution/update.go b/internal/api/controller/execution/update.go index 2dfee2f42..f18758771 100644 --- a/internal/api/controller/execution/update.go +++ b/internal/api/controller/execution/update.go @@ -7,8 +7,10 @@ package execution import ( "context" + apiauth "github.com/harness/gitness/internal/api/auth" "github.com/harness/gitness/internal/auth" "github.com/harness/gitness/types" + "github.com/harness/gitness/types/enum" ) // UpdateInput is used for updating a repo. @@ -29,6 +31,11 @@ func (c *Controller) Update( return nil, err } + err = apiauth.CheckPipeline(ctx, c.authorizer, session, space.Path, uid, enum.PermissionPipelineEdit) + if err != nil { + return nil, err + } + pipeline, err := c.pipelineStore.FindByUID(ctx, space.ID, uid) if err != nil { return nil, err @@ -43,10 +50,5 @@ func (c *Controller) Update( execution.Status = in.Status } - // TODO: Add auth - // if err = apiauth.CheckRepo(ctx, c.authorizer, session, repo, enum.PermissionRepoEdit, false); err != nil { - // return nil, err - // } - return c.executionStore.Update(ctx, execution) } diff --git a/internal/api/controller/pipeline/create.go b/internal/api/controller/pipeline/create.go index 495742ea8..d90f9c7b4 100644 --- a/internal/api/controller/pipeline/create.go +++ b/internal/api/controller/pipeline/create.go @@ -11,6 +11,7 @@ import ( "strings" "time" + apiauth "github.com/harness/gitness/internal/api/auth" "github.com/harness/gitness/internal/api/usererror" "github.com/harness/gitness/internal/auth" "github.com/harness/gitness/store/database/dbtx" @@ -37,16 +38,16 @@ type CreateInput struct { // Create creates a new pipeline func (c *Controller) Create(ctx context.Context, session *auth.Session, in *CreateInput) (*types.Pipeline, error) { - // TODO: Add auth - // parentSpace, err := c.getSpaceCheckAuthRepoCreation(ctx, session, in.ParentRef) - // if err != nil { - // return nil, err - // } - parentSpace, err := c.spaceStore.FindByRef(ctx, in.ParentRef) if err != nil { return nil, fmt.Errorf("could not find parent by ref: %w", err) } + + err = apiauth.CheckPipeline(ctx, c.authorizer, session, parentSpace.Path, in.UID, enum.PermissionPipelineEdit) + if err != nil { + return nil, err + } + var repoID int64 if in.RepoType == enum.ScmTypeGitness { @@ -93,6 +94,31 @@ func (c *Controller) Create(ctx context.Context, session *auth.Session, in *Crea return pipeline, nil } +func (c *Controller) getSpaceCheckAuthRepoCreation( + ctx context.Context, + session *auth.Session, + parentRef string, +) (*types.Space, error) { + space, err := c.spaceStore.FindByRef(ctx, parentRef) + if err != nil { + return nil, fmt.Errorf("parent space not found: %w", err) + } + + // create is a special case - check permission without specific resource + scope := &types.Scope{SpacePath: space.Path} + resource := &types.Resource{ + Type: enum.ResourceTypeRepo, + Name: "", + } + + err = apiauth.Check(ctx, c.authorizer, session, scope, resource, enum.PermissionRepoEdit) + if err != nil { + return nil, fmt.Errorf("auth check failed: %w", err) + } + + return space, nil +} + func (c *Controller) sanitizeCreateInput(in *CreateInput) error { parentRefAsID, err := strconv.ParseInt(in.ParentRef, 10, 64) diff --git a/internal/api/controller/pipeline/delete.go b/internal/api/controller/pipeline/delete.go index 29f93935c..56668ceaf 100644 --- a/internal/api/controller/pipeline/delete.go +++ b/internal/api/controller/pipeline/delete.go @@ -8,7 +8,9 @@ import ( "context" "fmt" + apiauth "github.com/harness/gitness/internal/api/auth" "github.com/harness/gitness/internal/auth" + "github.com/harness/gitness/types/enum" ) // Delete deletes a pipeline. @@ -17,11 +19,11 @@ func (c *Controller) Delete(ctx context.Context, session *auth.Session, spaceRef if err != nil { return err } - // TODO: Add auth - // if err = apiauth.CheckSpace(ctx, c.authorizer, session, space, enum.PermissionSpaceDelete, false); err != nil { - // return err - // } - // TODO: uncomment when soft delete is implemented + + err = apiauth.CheckPipeline(ctx, c.authorizer, session, space.Path, uid, enum.PermissionPipelineDelete) + if err != nil { + return err + } err = c.pipelineStore.DeleteByUID(ctx, space.ID, uid) if err != nil { return fmt.Errorf("could not delete pipeline: %w", err) diff --git a/internal/api/controller/pipeline/find.go b/internal/api/controller/pipeline/find.go index ad8604f58..128dad3e3 100644 --- a/internal/api/controller/pipeline/find.go +++ b/internal/api/controller/pipeline/find.go @@ -7,8 +7,10 @@ package pipeline import ( "context" + apiauth "github.com/harness/gitness/internal/api/auth" "github.com/harness/gitness/internal/auth" "github.com/harness/gitness/types" + "github.com/harness/gitness/types/enum" ) // Find finds a pipeline. @@ -17,10 +19,9 @@ func (c *Controller) Find(ctx context.Context, session *auth.Session, spaceRef s if err != nil { return nil, err } - // TODO: Add auth - // if err = apiauth.CheckSpace(ctx, c.authorizer, session, space, enum.PermissionSpaceDelete, false); err != nil { - // return err - // } - // TODO: uncomment when soft delete is implemented + err = apiauth.CheckPipeline(ctx, c.authorizer, session, space.Path, uid, enum.PermissionPipelineView) + if err != nil { + return nil, err + } return c.pipelineStore.FindByUID(ctx, space.ID, uid) } diff --git a/internal/api/controller/pipeline/update.go b/internal/api/controller/pipeline/update.go index d2f4b9453..bd57a6ea0 100644 --- a/internal/api/controller/pipeline/update.go +++ b/internal/api/controller/pipeline/update.go @@ -7,8 +7,10 @@ package pipeline import ( "context" + apiauth "github.com/harness/gitness/internal/api/auth" "github.com/harness/gitness/internal/auth" "github.com/harness/gitness/types" + "github.com/harness/gitness/types/enum" ) // UpdateInput is used for updating a repo. @@ -30,6 +32,11 @@ func (c *Controller) Update( return nil, err } + err = apiauth.CheckPipeline(ctx, c.authorizer, session, space.Path, uid, enum.PermissionPipelineEdit) + if err != nil { + return nil, err + } + pipeline, err := c.pipelineStore.FindByUID(ctx, space.ID, uid) if err != nil { return nil, err @@ -45,10 +52,5 @@ func (c *Controller) Update( pipeline.ConfigPath = in.ConfigPath } - // TODO: Add auth - // if err = apiauth.CheckRepo(ctx, c.authorizer, session, repo, enum.PermissionRepoEdit, false); err != nil { - // return nil, err - // } - return c.pipelineStore.Update(ctx, pipeline) } diff --git a/internal/api/controller/space/list_pipelines.go b/internal/api/controller/space/list_pipelines.go index b2af52a7a..f2da69dac 100644 --- a/internal/api/controller/space/list_pipelines.go +++ b/internal/api/controller/space/list_pipelines.go @@ -6,12 +6,13 @@ package space import ( "context" + apiauth "github.com/harness/gitness/internal/api/auth" "github.com/harness/gitness/internal/auth" "github.com/harness/gitness/types" + "github.com/harness/gitness/types/enum" ) -// ListRepositories lists the repositories of a space. -// TODO: move to different file +// ListPipelines lists the pipelines in a space. func (c *Controller) ListPipelines(ctx context.Context, session *auth.Session, spaceRef string, filter *types.PipelineFilter) ([]types.Pipeline, int, error) { space, err := c.spaceStore.FindByRef(ctx, spaceRef) @@ -19,10 +20,10 @@ func (c *Controller) ListPipelines(ctx context.Context, session *auth.Session, return nil, 0, err } - // TODO: Add auth - // if err = apiauth.CheckSpace(ctx, c.authorizer, session, space, enum.PermissionRepoView, true); err != nil { - // return nil, 0, err - // } + err = apiauth.CheckSpace(ctx, c.authorizer, session, space, enum.PermissionSpaceView, true) + if err != nil { + return nil, 0, err + } pipelines, err := c.pipelineStore.List(ctx, space.ID, filter) if err != nil { return nil, 0, err diff --git a/internal/auth/authz/membership.go b/internal/auth/authz/membership.go index 0bcfc4f19..9610d1b5c 100644 --- a/internal/auth/authz/membership.go +++ b/internal/auth/authz/membership.go @@ -63,6 +63,9 @@ func (a *MembershipAuthorizer) Check( case enum.ResourceTypeServiceAccount: spaceRef = scope.SpacePath + case enum.ResourceTypePipeline: + spaceRef = scope.SpacePath + case enum.ResourceTypeUser: // a user is allowed to view / edit themselves if resource.Name == session.Principal.UID && diff --git a/internal/store/database/migrate/ci/ci_migrations.sql b/internal/store/database/migrate/ci/ci_migrations.sql index 1cd33a689..ac926c4ae 100644 --- a/internal/store/database/migrate/ci/ci_migrations.sql +++ b/internal/store/database/migrate/ci/ci_migrations.sql @@ -74,4 +74,9 @@ CREATE TABLE IF NOT EXISTS executions ( REFERENCES pipelines (pipeline_id) MATCH SIMPLE ON UPDATE NO ACTION ON DELETE CASCADE -); \ No newline at end of file +); + +CREATE TABLE IF NOT EXISTS secrets ( + secret_id INTEGER PRIMARY KEY AUTOINCREMENT, + +) \ No newline at end of file diff --git a/types/enum/membership_role.go b/types/enum/membership_role.go index f7888d2c2..b957491cc 100644 --- a/types/enum/membership_role.go +++ b/types/enum/membership_role.go @@ -24,10 +24,12 @@ var membershipRoleReaderPermissions = slices.Clip(slices.Insert([]Permission{}, PermissionRepoView, PermissionSpaceView, PermissionServiceAccountView, + PermissionPipelineView, )) var membershipRoleExecutorPermissions = slices.Clip(slices.Insert(membershipRoleReaderPermissions, 0, PermissionCommitCheckReport, + PermissionPipelineExecute, )) var membershipRoleContributorPermissions = slices.Clip(slices.Insert(membershipRoleReaderPermissions, 0, @@ -47,6 +49,10 @@ var membershipRoleSpaceOwnerPermissions = slices.Clip(slices.Insert(membershipRo PermissionServiceAccountCreate, PermissionServiceAccountEdit, PermissionServiceAccountDelete, + + PermissionPipelineEdit, + PermissionPipelineExecute, + PermissionPipelineDelete, )) func init() { diff --git a/types/enum/permission.go b/types/enum/permission.go index 6824f035a..c917f0fed 100644 --- a/types/enum/permission.go +++ b/types/enum/permission.go @@ -13,6 +13,7 @@ const ( ResourceTypeUser ResourceType = "USER" ResourceTypeServiceAccount ResourceType = "SERVICEACCOUNT" ResourceTypeService ResourceType = "SERVICE" + ResourceTypePipeline ResourceType = "PIPELINE" // ResourceType_Branch ResourceType = "BRANCH" ) @@ -71,6 +72,16 @@ const ( PermissionServiceEditAdmin Permission = "service_editAdmin" ) +const ( + /* + ----- PIPELINE ----- + */ + PermissionPipelineView Permission = "pipeline_view" + PermissionPipelineEdit Permission = "pipeline_edit" + PermissionPipelineDelete Permission = "pipeline_delete" + PermissionPipelineExecute Permission = "pipeline_execute" +) + const ( /* ----- COMMIT CHECK -----