From 23f612162aa2853ddf07e5bf4eeae9f792e070a1 Mon Sep 17 00:00:00 2001 From: Vistaar Juneja Date: Mon, 21 Aug 2023 17:29:10 +0100 Subject: [PATCH] add connector/template permissions, add in controllers for connectors and templates --- internal/api/auth/connector.go | 29 +++++++ internal/api/auth/template.go | 29 +++++++ .../api/controller/connector/controller.go | 40 +++++++++ internal/api/controller/connector/create.go | 85 +++++++++++++++++++ internal/api/controller/connector/delete.go | 31 +++++++ internal/api/controller/connector/find.go | 36 ++++++++ internal/api/controller/connector/update.go | 59 +++++++++++++ internal/api/controller/connector/wire.go | 29 +++++++ .../api/controller/template/controller.go | 40 +++++++++ internal/api/controller/template/create.go | 84 ++++++++++++++++++ internal/api/controller/template/delete.go | 31 +++++++ internal/api/controller/template/find.go | 36 ++++++++ internal/api/controller/template/update.go | 59 +++++++++++++ internal/api/controller/template/wire.go | 29 +++++++ types/enum/membership_role.go | 14 +++ types/enum/permission.go | 22 +++++ 16 files changed, 653 insertions(+) create mode 100644 internal/api/auth/connector.go create mode 100644 internal/api/auth/template.go create mode 100644 internal/api/controller/connector/controller.go create mode 100644 internal/api/controller/connector/create.go create mode 100644 internal/api/controller/connector/delete.go create mode 100644 internal/api/controller/connector/find.go create mode 100644 internal/api/controller/connector/update.go create mode 100644 internal/api/controller/connector/wire.go create mode 100644 internal/api/controller/template/controller.go create mode 100644 internal/api/controller/template/create.go create mode 100644 internal/api/controller/template/delete.go create mode 100644 internal/api/controller/template/find.go create mode 100644 internal/api/controller/template/update.go create mode 100644 internal/api/controller/template/wire.go diff --git a/internal/api/auth/connector.go b/internal/api/auth/connector.go new file mode 100644 index 000000000..44db3fac8 --- /dev/null +++ b/internal/api/auth/connector.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" +) + +// CheckConnector 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 CheckConnector(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.ResourceTypeConnector, + Name: uid, + } + + return Check(ctx, authorizer, session, scope, resource, permission) +} diff --git a/internal/api/auth/template.go b/internal/api/auth/template.go new file mode 100644 index 000000000..87243b63b --- /dev/null +++ b/internal/api/auth/template.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" +) + +// CheckTemplate 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 CheckTemplate(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.ResourceTypeTemplate, + Name: uid, + } + + return Check(ctx, authorizer, session, scope, resource, permission) +} diff --git a/internal/api/controller/connector/controller.go b/internal/api/controller/connector/controller.go new file mode 100644 index 000000000..0d7c57b75 --- /dev/null +++ b/internal/api/controller/connector/controller.go @@ -0,0 +1,40 @@ +// 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 connector + +import ( + "github.com/harness/gitness/internal/auth/authz" + "github.com/harness/gitness/internal/store" + "github.com/harness/gitness/types/check" + + "github.com/jmoiron/sqlx" +) + +type Controller struct { + db *sqlx.DB + uidCheck check.PathUID + pathStore store.PathStore + connectorStore store.ConnectorStore + authorizer authz.Authorizer + spaceStore store.SpaceStore +} + +func NewController( + db *sqlx.DB, + uidCheck check.PathUID, + authorizer authz.Authorizer, + pathStore store.PathStore, + connectorStore store.ConnectorStore, + spaceStore store.SpaceStore, +) *Controller { + return &Controller{ + db: db, + uidCheck: uidCheck, + pathStore: pathStore, + connectorStore: connectorStore, + authorizer: authorizer, + spaceStore: spaceStore, + } +} diff --git a/internal/api/controller/connector/create.go b/internal/api/controller/connector/create.go new file mode 100644 index 000000000..8939203fd --- /dev/null +++ b/internal/api/controller/connector/create.go @@ -0,0 +1,85 @@ +// 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 connector + +import ( + "context" + "fmt" + "strconv" + "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/types" + "github.com/harness/gitness/types/check" + "github.com/harness/gitness/types/enum" +) + +var ( + // errConnectorRequiresParent if the user tries to create a connector without a parent space. + errConnectorRequiresParent = usererror.BadRequest( + "Parent space required - standalone connector are not supported.") +) + +type CreateInput struct { + Description string `json:"description"` + SpaceRef string `json:"space_ref"` // Ref of the parent space + UID string `json:"uid"` + Type string `json:"type"` + Data string `json:"data"` +} + +func (c *Controller) Create(ctx context.Context, session *auth.Session, in *CreateInput) (*types.Connector, error) { + parentSpace, err := c.spaceStore.FindByRef(ctx, in.SpaceRef) + if err != nil { + return nil, fmt.Errorf("could not find parent by ref: %w", err) + } + + err = apiauth.CheckConnector(ctx, c.authorizer, session, parentSpace.Path, in.UID, enum.PermissionConnectorEdit) + if err != nil { + return nil, err + } + + if err := c.sanitizeCreateInput(in); err != nil { + return nil, fmt.Errorf("failed to sanitize input: %w", err) + } + + var connector *types.Connector + now := time.Now().UnixMilli() + connector = &types.Connector{ + Description: in.Description, + Data: in.Data, + Type: in.Type, + SpaceID: parentSpace.ID, + UID: in.UID, + Created: now, + Updated: now, + Version: 0, + } + err = c.connectorStore.Create(ctx, connector) + if err != nil { + return nil, fmt.Errorf("connector creation failed: %w", err) + } + + return connector, nil +} + +func (c *Controller) sanitizeCreateInput(in *CreateInput) error { + parentRefAsID, err := strconv.ParseInt(in.SpaceRef, 10, 64) + + if (err == nil && parentRefAsID <= 0) || (len(strings.TrimSpace(in.SpaceRef)) == 0) { + return errConnectorRequiresParent + } + + if err := c.uidCheck(in.UID, false); err != nil { + return err + } + + in.Description = strings.TrimSpace(in.Description) + return check.Description(in.Description) + +} diff --git a/internal/api/controller/connector/delete.go b/internal/api/controller/connector/delete.go new file mode 100644 index 000000000..502b75219 --- /dev/null +++ b/internal/api/controller/connector/delete.go @@ -0,0 +1,31 @@ +// 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 connector + +import ( + "context" + "fmt" + + apiauth "github.com/harness/gitness/internal/api/auth" + "github.com/harness/gitness/internal/auth" + "github.com/harness/gitness/types/enum" +) + +func (c *Controller) Delete(ctx context.Context, session *auth.Session, spaceRef string, uid string) error { + space, err := c.spaceStore.FindByRef(ctx, spaceRef) + if err != nil { + return fmt.Errorf("could not find space: %w", err) + } + + err = apiauth.CheckConnector(ctx, c.authorizer, session, space.Path, uid, enum.PermissionConnectorDelete) + if err != nil { + return fmt.Errorf("failed to authorize: %w", err) + } + err = c.connectorStore.DeleteByUID(ctx, space.ID, uid) + if err != nil { + return fmt.Errorf("could not delete connector: %w", err) + } + return nil +} diff --git a/internal/api/controller/connector/find.go b/internal/api/controller/connector/find.go new file mode 100644 index 000000000..add4037e2 --- /dev/null +++ b/internal/api/controller/connector/find.go @@ -0,0 +1,36 @@ +// 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 connector + +import ( + "context" + "fmt" + + 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" +) + +func (c *Controller) Find( + ctx context.Context, + session *auth.Session, + spaceRef string, + uid string, +) (*types.Connector, error) { + space, err := c.spaceStore.FindByRef(ctx, spaceRef) + if err != nil { + return nil, fmt.Errorf("could not find space: %w", err) + } + err = apiauth.CheckConnector(ctx, c.authorizer, session, space.Path, uid, enum.PermissionConnectorView) + if err != nil { + return nil, fmt.Errorf("failed to authorize: %w", err) + } + connector, err := c.connectorStore.FindByUID(ctx, space.ID, uid) + if err != nil { + return nil, fmt.Errorf("could not find connector: %w", err) + } + return connector, nil +} diff --git a/internal/api/controller/connector/update.go b/internal/api/controller/connector/update.go new file mode 100644 index 000000000..ec4d9d129 --- /dev/null +++ b/internal/api/controller/connector/update.go @@ -0,0 +1,59 @@ +// 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 connector + +import ( + "context" + "fmt" + + 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 connector. +type UpdateInput struct { + Description string `json:"description"` + UID string `json:"uid"` + Data string `json:"data"` +} + +func (c *Controller) Update( + ctx context.Context, + session *auth.Session, + spaceRef string, + uid string, + in *UpdateInput, +) (*types.Connector, error) { + space, err := c.spaceStore.FindByRef(ctx, spaceRef) + if err != nil { + return nil, fmt.Errorf("could not find space: %w", err) + } + + err = apiauth.CheckConnector(ctx, c.authorizer, session, space.Path, uid, enum.PermissionConnectorEdit) + if err != nil { + return nil, fmt.Errorf("failed to authorize: %w", err) + } + + connector, err := c.connectorStore.FindByUID(ctx, space.ID, uid) + if err != nil { + return nil, fmt.Errorf("could not find connector: %w", err) + } + + return c.connectorStore.UpdateOptLock(ctx, connector, func(original *types.Connector) error { + if in.Description != "" { + original.Description = in.Description + } + if in.Data != "" { + original.Data = in.Data + } + if in.UID != "" { + original.UID = in.UID + } + + return nil + }) +} diff --git a/internal/api/controller/connector/wire.go b/internal/api/controller/connector/wire.go new file mode 100644 index 000000000..c990f2d8a --- /dev/null +++ b/internal/api/controller/connector/wire.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 connector + +import ( + "github.com/harness/gitness/internal/auth/authz" + "github.com/harness/gitness/internal/store" + "github.com/harness/gitness/types/check" + + "github.com/google/wire" + "github.com/jmoiron/sqlx" +) + +// WireSet provides a wire set for this package. +var WireSet = wire.NewSet( + ProvideController, +) + +func ProvideController(db *sqlx.DB, + uidCheck check.PathUID, + pathStore store.PathStore, + connectorStore store.ConnectorStore, + authorizer authz.Authorizer, + spaceStore store.SpaceStore, +) *Controller { + return NewController(db, uidCheck, authorizer, pathStore, connectorStore, spaceStore) +} diff --git a/internal/api/controller/template/controller.go b/internal/api/controller/template/controller.go new file mode 100644 index 000000000..7346bdc8b --- /dev/null +++ b/internal/api/controller/template/controller.go @@ -0,0 +1,40 @@ +// 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 template + +import ( + "github.com/harness/gitness/internal/auth/authz" + "github.com/harness/gitness/internal/store" + "github.com/harness/gitness/types/check" + + "github.com/jmoiron/sqlx" +) + +type Controller struct { + db *sqlx.DB + uidCheck check.PathUID + pathStore store.PathStore + templateStore store.TemplateStore + authorizer authz.Authorizer + spaceStore store.SpaceStore +} + +func NewController( + db *sqlx.DB, + uidCheck check.PathUID, + authorizer authz.Authorizer, + pathStore store.PathStore, + templateStore store.TemplateStore, + spaceStore store.SpaceStore, +) *Controller { + return &Controller{ + db: db, + uidCheck: uidCheck, + pathStore: pathStore, + templateStore: templateStore, + authorizer: authorizer, + spaceStore: spaceStore, + } +} diff --git a/internal/api/controller/template/create.go b/internal/api/controller/template/create.go new file mode 100644 index 000000000..34df4ab56 --- /dev/null +++ b/internal/api/controller/template/create.go @@ -0,0 +1,84 @@ +// 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 template + +import ( + "context" + "fmt" + "strconv" + "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/types" + "github.com/harness/gitness/types/check" + "github.com/harness/gitness/types/enum" +) + +var ( + // errTemplateRequiresParent if the user tries to create a template without a parent space. + errTemplateRequiresParent = usererror.BadRequest( + "Parent space required - standalone templates are not supported.") +) + +type CreateInput struct { + Description string `json:"description"` + SpaceRef string `json:"space_ref"` // Ref of the parent space + UID string `json:"uid"` + Type string `json:"type"` + Data string `json:"data"` +} + +func (c *Controller) Create(ctx context.Context, session *auth.Session, in *CreateInput) (*types.Template, error) { + parentSpace, err := c.spaceStore.FindByRef(ctx, in.SpaceRef) + if err != nil { + return nil, fmt.Errorf("could not find parent by ref: %w", err) + } + + err = apiauth.CheckTemplate(ctx, c.authorizer, session, parentSpace.Path, in.UID, enum.PermissionTemplateEdit) + if err != nil { + return nil, err + } + + if err := c.sanitizeCreateInput(in); err != nil { + return nil, fmt.Errorf("failed to sanitize input: %w", err) + } + + var template *types.Template + now := time.Now().UnixMilli() + template = &types.Template{ + Description: in.Description, + Data: in.Data, + SpaceID: parentSpace.ID, + UID: in.UID, + Created: now, + Updated: now, + Version: 0, + } + err = c.templateStore.Create(ctx, template) + if err != nil { + return nil, fmt.Errorf("template creation failed: %w", err) + } + + return template, nil +} + +func (c *Controller) sanitizeCreateInput(in *CreateInput) error { + parentRefAsID, err := strconv.ParseInt(in.SpaceRef, 10, 64) + + if (err == nil && parentRefAsID <= 0) || (len(strings.TrimSpace(in.SpaceRef)) == 0) { + return errTemplateRequiresParent + } + + if err := c.uidCheck(in.UID, false); err != nil { + return err + } + + in.Description = strings.TrimSpace(in.Description) + return check.Description(in.Description) + +} diff --git a/internal/api/controller/template/delete.go b/internal/api/controller/template/delete.go new file mode 100644 index 000000000..3a1c30679 --- /dev/null +++ b/internal/api/controller/template/delete.go @@ -0,0 +1,31 @@ +// 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 template + +import ( + "context" + "fmt" + + apiauth "github.com/harness/gitness/internal/api/auth" + "github.com/harness/gitness/internal/auth" + "github.com/harness/gitness/types/enum" +) + +func (c *Controller) Delete(ctx context.Context, session *auth.Session, spaceRef string, uid string) error { + space, err := c.spaceStore.FindByRef(ctx, spaceRef) + if err != nil { + return fmt.Errorf("could not find space: %w", err) + } + + err = apiauth.CheckTemplate(ctx, c.authorizer, session, space.Path, uid, enum.PermissionTemplateDelete) + if err != nil { + return fmt.Errorf("failed to authorize: %w", err) + } + err = c.templateStore.DeleteByUID(ctx, space.ID, uid) + if err != nil { + return fmt.Errorf("could not delete template: %w", err) + } + return nil +} diff --git a/internal/api/controller/template/find.go b/internal/api/controller/template/find.go new file mode 100644 index 000000000..0b769d246 --- /dev/null +++ b/internal/api/controller/template/find.go @@ -0,0 +1,36 @@ +// 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 template + +import ( + "context" + "fmt" + + 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" +) + +func (c *Controller) Find( + ctx context.Context, + session *auth.Session, + spaceRef string, + uid string, +) (*types.Template, error) { + space, err := c.spaceStore.FindByRef(ctx, spaceRef) + if err != nil { + return nil, fmt.Errorf("could not find space: %w", err) + } + err = apiauth.CheckTemplate(ctx, c.authorizer, session, space.Path, uid, enum.PermissionTemplateView) + if err != nil { + return nil, fmt.Errorf("failed to authorize: %w", err) + } + template, err := c.templateStore.FindByUID(ctx, space.ID, uid) + if err != nil { + return nil, fmt.Errorf("could not find template: %w", err) + } + return template, nil +} diff --git a/internal/api/controller/template/update.go b/internal/api/controller/template/update.go new file mode 100644 index 000000000..533d33949 --- /dev/null +++ b/internal/api/controller/template/update.go @@ -0,0 +1,59 @@ +// 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 template + +import ( + "context" + "fmt" + + 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 template. +type UpdateInput struct { + Description string `json:"description"` + UID string `json:"uid"` + Data string `json:"data"` +} + +func (c *Controller) Update( + ctx context.Context, + session *auth.Session, + spaceRef string, + uid string, + in *UpdateInput, +) (*types.Template, error) { + space, err := c.spaceStore.FindByRef(ctx, spaceRef) + if err != nil { + return nil, fmt.Errorf("could not find space: %w", err) + } + + err = apiauth.CheckTemplate(ctx, c.authorizer, session, space.Path, uid, enum.PermissionTemplateEdit) + if err != nil { + return nil, fmt.Errorf("failed to authorize: %w", err) + } + + template, err := c.templateStore.FindByUID(ctx, space.ID, uid) + if err != nil { + return nil, fmt.Errorf("could not find template: %w", err) + } + + return c.templateStore.UpdateOptLock(ctx, template, func(original *types.Template) error { + if in.Description != "" { + original.Description = in.Description + } + if in.Data != "" { + original.Data = in.Data + } + if in.UID != "" { + original.UID = in.UID + } + + return nil + }) +} diff --git a/internal/api/controller/template/wire.go b/internal/api/controller/template/wire.go new file mode 100644 index 000000000..1e482b5bc --- /dev/null +++ b/internal/api/controller/template/wire.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 template + +import ( + "github.com/harness/gitness/internal/auth/authz" + "github.com/harness/gitness/internal/store" + "github.com/harness/gitness/types/check" + + "github.com/google/wire" + "github.com/jmoiron/sqlx" +) + +// WireSet provides a wire set for this package. +var WireSet = wire.NewSet( + ProvideController, +) + +func ProvideController(db *sqlx.DB, + uidCheck check.PathUID, + pathStore store.PathStore, + templateStore store.TemplateStore, + authorizer authz.Authorizer, + spaceStore store.SpaceStore, +) *Controller { + return NewController(db, uidCheck, authorizer, pathStore, templateStore, spaceStore) +} diff --git a/types/enum/membership_role.go b/types/enum/membership_role.go index fbe2b9d6a..acc393b08 100644 --- a/types/enum/membership_role.go +++ b/types/enum/membership_role.go @@ -26,12 +26,16 @@ var membershipRoleReaderPermissions = slices.Clip(slices.Insert([]Permission{}, PermissionServiceAccountView, PermissionPipelineView, PermissionSecretView, + PermissionConnectorView, + PermissionTemplateView, )) var membershipRoleExecutorPermissions = slices.Clip(slices.Insert(membershipRoleReaderPermissions, 0, PermissionCommitCheckReport, PermissionPipelineExecute, PermissionSecretAccess, + PermissionConnectorAccess, + PermissionTemplateAccess, )) var membershipRoleContributorPermissions = slices.Clip(slices.Insert(membershipRoleReaderPermissions, 0, @@ -61,6 +65,16 @@ var membershipRoleSpaceOwnerPermissions = slices.Clip(slices.Insert(membershipRo PermissionSecretDelete, PermissionSecretEdit, PermissionSecretView, + + PermissionConnectorAccess, + PermissionConnectorDelete, + PermissionConnectorEdit, + PermissionConnectorView, + + PermissionTemplateAccess, + PermissionTemplateDelete, + PermissionTemplateEdit, + PermissionTemplateView, )) func init() { diff --git a/types/enum/permission.go b/types/enum/permission.go index fe8d0fc6e..2a6651803 100644 --- a/types/enum/permission.go +++ b/types/enum/permission.go @@ -15,6 +15,8 @@ const ( ResourceTypeService ResourceType = "SERVICE" ResourceTypePipeline ResourceType = "PIPELINE" ResourceTypeSecret ResourceType = "SECRET" + ResourceTypeConnector ResourceType = "CONNECTOR" + ResourceTypeTemplate ResourceType = "TEMPLATE" // ResourceType_Branch ResourceType = "BRANCH" ) @@ -93,6 +95,26 @@ const ( PermissionSecretAccess Permission = "secret_access" ) +const ( + /* + ----- CONNECTOR ----- + */ + PermissionConnectorView Permission = "connector_view" + PermissionConnectorEdit Permission = "connector_edit" + PermissionConnectorDelete Permission = "connector_delete" + PermissionConnectorAccess Permission = "connector_access" +) + +const ( + /* + ----- TEMPLATE ----- + */ + PermissionTemplateView Permission = "template_view" + PermissionTemplateEdit Permission = "template_edit" + PermissionTemplateDelete Permission = "template_delete" + PermissionTemplateAccess Permission = "template_access" +) + const ( /* ----- COMMIT CHECK -----