mirror of https://github.com/harness/drone.git
feat: [CODE-2568]: Add rules API for space level (#2865)
* Add openapi spec for space rules * Merge branch 'main' into dd/space-branch-rules * Fix doc comments and space permissions * Merge branch 'main' into dd/space-branch-rules * Add equal check to update rule * Merge branch 'main' into dd/space-branch-rules * Use consistently RuleParentInfo * Add RuleParentInfo type * Merge branch 'main' into dd/space-branch-rules * Rename r to rule in funcs and rule to protection * Merge remote-tracking branch 'origin/main' into dd/space-branch-rules * Unifiy instrumentation and audit handling * Add delete, find, list and patch svc funcs and API endpoints * Add rules API for space levelpull/3590/head
parent
37c7d3c626
commit
fd9a1ad400
|
@ -35,6 +35,7 @@ import (
|
|||
"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/rules"
|
||||
"github.com/harness/gitness/app/services/settings"
|
||||
"github.com/harness/gitness/app/services/usergroup"
|
||||
"github.com/harness/gitness/app/store"
|
||||
|
@ -102,6 +103,7 @@ type Controller struct {
|
|||
publicAccess publicaccess.Service
|
||||
labelSvc *label.Service
|
||||
instrumentation instrument.Service
|
||||
rulesSvc *rules.Service
|
||||
}
|
||||
|
||||
func NewController(
|
||||
|
@ -136,6 +138,7 @@ func NewController(
|
|||
instrumentation instrument.Service,
|
||||
userGroupStore store.UserGroupStore,
|
||||
userGroupService usergroup.SearchService,
|
||||
rulesSvc *rules.Service,
|
||||
) *Controller {
|
||||
return &Controller{
|
||||
defaultBranch: config.Git.DefaultBranch,
|
||||
|
@ -169,6 +172,7 @@ func NewController(
|
|||
instrumentation: instrumentation,
|
||||
userGroupStore: userGroupStore,
|
||||
userGroupService: userGroupService,
|
||||
rulesSvc: rulesSvc,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -249,76 +253,3 @@ func (c *Controller) fetchRules(
|
|||
|
||||
return protectionRules, isRepoOwner, nil
|
||||
}
|
||||
|
||||
func (c *Controller) getRuleUserAndUserGroups(
|
||||
ctx context.Context,
|
||||
r *types.Rule,
|
||||
) (map[int64]*types.PrincipalInfo, map[int64]*types.UserGroupInfo, error) {
|
||||
rule, err := c.parseRule(r)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to parse rule: %w", err)
|
||||
}
|
||||
|
||||
userMap, err := c.getRuleUsers(ctx, rule)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to get rule users: %w", err)
|
||||
}
|
||||
userGroupMap, err := c.getRuleUserGroups(ctx, rule)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to get rule user groups: %w", err)
|
||||
}
|
||||
|
||||
return userMap, userGroupMap, nil
|
||||
}
|
||||
|
||||
func (c *Controller) getRuleUsers(
|
||||
ctx context.Context,
|
||||
rule protection.Protection,
|
||||
) (map[int64]*types.PrincipalInfo, error) {
|
||||
userIDs, err := rule.UserIDs()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get user ID from rule: %w", err)
|
||||
}
|
||||
|
||||
userMap, err := c.principalInfoCache.Map(ctx, userIDs)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get principal infos: %w", err)
|
||||
}
|
||||
|
||||
return userMap, nil
|
||||
}
|
||||
|
||||
func (c *Controller) getRuleUserGroups(
|
||||
ctx context.Context,
|
||||
rule protection.Protection,
|
||||
) (map[int64]*types.UserGroupInfo, error) {
|
||||
groupIDs, err := rule.UserGroupIDs()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get group IDs from rule: %w", err)
|
||||
}
|
||||
|
||||
userGroupInfoMap := make(map[int64]*types.UserGroupInfo)
|
||||
|
||||
if len(groupIDs) == 0 {
|
||||
return userGroupInfoMap, nil
|
||||
}
|
||||
|
||||
groupMap, err := c.userGroupStore.Map(ctx, groupIDs)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get userGroup infos: %w", err)
|
||||
}
|
||||
|
||||
for k, v := range groupMap {
|
||||
userGroupInfoMap[k] = v.ToUserGroupInfo()
|
||||
}
|
||||
return userGroupInfoMap, nil
|
||||
}
|
||||
|
||||
func (c *Controller) parseRule(r *types.Rule) (protection.Protection, error) {
|
||||
rule, err := c.protectionManager.FromJSON(r.Type, r.Definition, false)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse json rule definition: %w", err)
|
||||
}
|
||||
|
||||
return rule, nil
|
||||
}
|
||||
|
|
|
@ -16,139 +16,34 @@ package repo
|
|||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/harness/gitness/app/api/usererror"
|
||||
"github.com/harness/gitness/app/auth"
|
||||
"github.com/harness/gitness/app/paths"
|
||||
"github.com/harness/gitness/app/services/instrument"
|
||||
"github.com/harness/gitness/app/services/protection"
|
||||
"github.com/harness/gitness/audit"
|
||||
"github.com/harness/gitness/app/services/rules"
|
||||
"github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/check"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
type RuleCreateInput struct {
|
||||
Type types.RuleType `json:"type"`
|
||||
State enum.RuleState `json:"state"`
|
||||
// TODO [CODE-1363]: remove after identifier migration.
|
||||
UID string `json:"uid" deprecated:"true"`
|
||||
Identifier string `json:"identifier"`
|
||||
Description string `json:"description"`
|
||||
Pattern protection.Pattern `json:"pattern"`
|
||||
Definition json.RawMessage `json:"definition"`
|
||||
}
|
||||
|
||||
// sanitize validates and sanitizes the create rule input data.
|
||||
func (in *RuleCreateInput) sanitize() error {
|
||||
// TODO [CODE-1363]: remove after identifier migration.
|
||||
if in.Identifier == "" {
|
||||
in.Identifier = in.UID
|
||||
}
|
||||
|
||||
if err := check.Identifier(in.Identifier); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := in.Pattern.Validate(); err != nil {
|
||||
return usererror.BadRequestf("invalid pattern: %s", err)
|
||||
}
|
||||
|
||||
var ok bool
|
||||
in.State, ok = in.State.Sanitize()
|
||||
if !ok {
|
||||
return usererror.BadRequest("rule state is invalid")
|
||||
}
|
||||
|
||||
if in.Type == "" {
|
||||
in.Type = protection.TypeBranch
|
||||
}
|
||||
|
||||
if len(in.Definition) == 0 {
|
||||
return usererror.BadRequest("rule definition missing")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// RuleCreate creates a new protection rule for a repo.
|
||||
func (c *Controller) RuleCreate(ctx context.Context,
|
||||
session *auth.Session,
|
||||
repoRef string,
|
||||
in *RuleCreateInput,
|
||||
in *rules.CreateInput,
|
||||
) (*types.Rule, error) {
|
||||
if err := in.sanitize(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
repo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionRepoEdit)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
in.Definition, err = c.protectionManager.SanitizeJSON(in.Type, in.Definition)
|
||||
if err != nil {
|
||||
return nil, usererror.BadRequestf("invalid rule definition: %s", err.Error())
|
||||
}
|
||||
|
||||
now := time.Now().UnixMilli()
|
||||
r := &types.Rule{
|
||||
CreatedBy: session.Principal.ID,
|
||||
Created: now,
|
||||
Updated: now,
|
||||
RepoID: &repo.ID,
|
||||
SpaceID: nil,
|
||||
Type: in.Type,
|
||||
State: in.State,
|
||||
Identifier: in.Identifier,
|
||||
Description: in.Description,
|
||||
Pattern: in.Pattern.JSON(),
|
||||
Definition: in.Definition,
|
||||
CreatedByInfo: types.PrincipalInfo{},
|
||||
}
|
||||
|
||||
err = c.ruleStore.Create(ctx, r)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create repository-level protection rule: %w", err)
|
||||
}
|
||||
|
||||
err = c.auditService.Log(ctx,
|
||||
session.Principal,
|
||||
audit.NewResource(audit.ResourceTypeBranchRule, r.Identifier, audit.RepoName, repo.Identifier),
|
||||
audit.ActionCreated,
|
||||
paths.Parent(repo.Path),
|
||||
audit.WithNewObject(r),
|
||||
rule, err := c.rulesSvc.Create(
|
||||
ctx, &session.Principal,
|
||||
enum.RuleParentRepo, repo.ID,
|
||||
repo.Identifier, repo.Path,
|
||||
in,
|
||||
)
|
||||
if err != nil {
|
||||
log.Ctx(ctx).Warn().Msgf("failed to insert audit log for create branch rule operation: %s", err)
|
||||
return nil, fmt.Errorf("failed to create repo-level protection rule: %w", err)
|
||||
}
|
||||
|
||||
err = c.instrumentation.Track(ctx, instrument.Event{
|
||||
Type: instrument.EventTypeCreateBranchRule,
|
||||
Principal: session.Principal.ToPrincipalInfo(),
|
||||
Path: repo.Path,
|
||||
Properties: map[instrument.Property]any{
|
||||
instrument.PropertyRepositoryID: repo.ID,
|
||||
instrument.PropertyRepositoryName: repo.Identifier,
|
||||
instrument.PropertyRuleID: r.ID,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
log.Ctx(ctx).Warn().Msgf("failed to insert instrumentation record for create branch rule operation: %s", err)
|
||||
}
|
||||
|
||||
userMap, userGroupMap, err := c.getRuleUserAndUserGroups(ctx, r)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get rule users and user groups: %w", err)
|
||||
}
|
||||
|
||||
r.Users = userMap
|
||||
r.UserGroups = userGroupMap
|
||||
|
||||
return r, nil
|
||||
return rule, nil
|
||||
}
|
||||
|
|
|
@ -19,11 +19,7 @@ import (
|
|||
"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"
|
||||
)
|
||||
|
||||
// RuleDelete deletes a protection rule by identifier.
|
||||
|
@ -37,25 +33,15 @@ func (c *Controller) RuleDelete(ctx context.Context,
|
|||
return err
|
||||
}
|
||||
|
||||
r, err := c.ruleStore.FindByIdentifier(ctx, nil, &repo.ID, identifier)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to find repository-level protection rule by identifier: %w", err)
|
||||
}
|
||||
|
||||
err = c.ruleStore.Delete(ctx, r.ID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to delete repository-level protection rule: %w", err)
|
||||
}
|
||||
|
||||
err = c.auditService.Log(ctx,
|
||||
session.Principal,
|
||||
audit.NewResource(audit.ResourceTypeBranchRule, r.Identifier, audit.RepoName, repo.Identifier),
|
||||
audit.ActionDeleted,
|
||||
paths.Parent(repo.Path),
|
||||
audit.WithOldObject(r),
|
||||
err = c.rulesSvc.Delete(
|
||||
ctx,
|
||||
&session.Principal,
|
||||
enum.RuleParentRepo, repo.ID,
|
||||
repo.Identifier, repo.Path,
|
||||
identifier,
|
||||
)
|
||||
if err != nil {
|
||||
log.Ctx(ctx).Warn().Msgf("failed to insert audit log for delete branch rule operation: %s", err)
|
||||
return fmt.Errorf("failed to delete repo-level protection rule: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
|
@ -34,18 +34,10 @@ func (c *Controller) RuleFind(ctx context.Context,
|
|||
return nil, err
|
||||
}
|
||||
|
||||
r, err := c.ruleStore.FindByIdentifier(ctx, nil, &repo.ID, identifier)
|
||||
rule, err := c.rulesSvc.Find(ctx, enum.RuleParentRepo, repo.ID, identifier)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to find repository-level protection rule by identifier: %w", err)
|
||||
return nil, fmt.Errorf("failed to find repo-level protection rule by identifier: %w", err)
|
||||
}
|
||||
|
||||
userMap, userGroupMap, err := c.getRuleUserAndUserGroups(ctx, r)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get rule users and user groups: %w", err)
|
||||
}
|
||||
|
||||
r.Users = userMap
|
||||
r.UserGroups = userGroupMap
|
||||
|
||||
return r, nil
|
||||
return rule, nil
|
||||
}
|
||||
|
|
|
@ -19,7 +19,6 @@ import (
|
|||
"fmt"
|
||||
|
||||
"github.com/harness/gitness/app/auth"
|
||||
"github.com/harness/gitness/store/database/dbtx"
|
||||
"github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
)
|
||||
|
@ -28,6 +27,7 @@ import (
|
|||
func (c *Controller) RuleList(ctx context.Context,
|
||||
session *auth.Session,
|
||||
repoRef string,
|
||||
inherited bool,
|
||||
filter *types.RuleFilter,
|
||||
) ([]types.Rule, int64, error) {
|
||||
repo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionRepoView)
|
||||
|
@ -35,36 +35,9 @@ func (c *Controller) RuleList(ctx context.Context,
|
|||
return nil, 0, err
|
||||
}
|
||||
|
||||
var list []types.Rule
|
||||
var count int64
|
||||
|
||||
err = c.tx.WithTx(ctx, func(ctx context.Context) error {
|
||||
list, err = c.ruleStore.List(ctx, nil, &repo.ID, filter)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to list repository-level protection rules: %w", err)
|
||||
}
|
||||
|
||||
if filter.Page == 1 && len(list) < filter.Size {
|
||||
count = int64(len(list))
|
||||
return nil
|
||||
}
|
||||
|
||||
count, err = c.ruleStore.Count(ctx, nil, &repo.ID, filter)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to count repository-level protection rules: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}, dbtx.TxDefaultReadOnly)
|
||||
list, count, err := c.rulesSvc.List(ctx, repo.ID, enum.RuleParentRepo, inherited, filter)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
for i := range list {
|
||||
list[i].Users, list[i].UserGroups, err = c.getRuleUserAndUserGroups(ctx, &list[i])
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
return nil, 0, fmt.Errorf("failed to list repo-level protection rules: %w", err)
|
||||
}
|
||||
|
||||
return list, count, nil
|
||||
|
|
|
@ -16,146 +16,38 @@ package repo
|
|||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/harness/gitness/app/api/usererror"
|
||||
"github.com/harness/gitness/app/auth"
|
||||
"github.com/harness/gitness/app/paths"
|
||||
"github.com/harness/gitness/app/services/protection"
|
||||
"github.com/harness/gitness/audit"
|
||||
"github.com/harness/gitness/app/services/rules"
|
||||
"github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/check"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
type RuleUpdateInput struct {
|
||||
// TODO [CODE-1363]: remove after identifier migration.
|
||||
UID *string `json:"uid" deprecated:"true"`
|
||||
Identifier *string `json:"identifier"`
|
||||
State *enum.RuleState `json:"state"`
|
||||
Description *string `json:"description"`
|
||||
Pattern *protection.Pattern `json:"pattern"`
|
||||
Definition *json.RawMessage `json:"definition"`
|
||||
}
|
||||
|
||||
// sanitize validates and sanitizes the update rule input data.
|
||||
func (in *RuleUpdateInput) sanitize() error {
|
||||
// TODO [CODE-1363]: remove after identifier migration.
|
||||
if in.Identifier == nil {
|
||||
in.Identifier = in.UID
|
||||
}
|
||||
|
||||
if in.Identifier != nil {
|
||||
if err := check.Identifier(*in.Identifier); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if in.State != nil {
|
||||
state, ok := in.State.Sanitize()
|
||||
if !ok {
|
||||
return usererror.BadRequest("rule state is invalid")
|
||||
}
|
||||
|
||||
in.State = &state
|
||||
}
|
||||
|
||||
if in.Pattern != nil {
|
||||
if err := in.Pattern.Validate(); err != nil {
|
||||
return usererror.BadRequestf("invalid pattern: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
if in.Definition != nil && len(*in.Definition) == 0 {
|
||||
return usererror.BadRequest("rule definition missing")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (in *RuleUpdateInput) isEmpty() bool {
|
||||
return in.Identifier == nil && in.State == nil && in.Description == nil && in.Pattern == nil && in.Definition == nil
|
||||
}
|
||||
|
||||
// RuleUpdate updates an existing protection rule for a repository.
|
||||
func (c *Controller) RuleUpdate(ctx context.Context,
|
||||
session *auth.Session,
|
||||
repoRef string,
|
||||
identifier string,
|
||||
in *RuleUpdateInput,
|
||||
in *rules.UpdateInput,
|
||||
) (*types.Rule, error) {
|
||||
if err := in.sanitize(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
repo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionRepoEdit)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
r, err := c.ruleStore.FindByIdentifier(ctx, nil, &repo.ID, identifier)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get a repository rule by its identifier: %w", err)
|
||||
}
|
||||
oldRule := r.Clone()
|
||||
if in.isEmpty() {
|
||||
userMap, userGroupMap, err := c.getRuleUserAndUserGroups(ctx, r)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get rule users and user groups: %w", err)
|
||||
}
|
||||
|
||||
r.Users = userMap
|
||||
r.UserGroups = userGroupMap
|
||||
|
||||
return r, nil
|
||||
}
|
||||
|
||||
if in.Identifier != nil {
|
||||
r.Identifier = *in.Identifier
|
||||
}
|
||||
if in.State != nil {
|
||||
r.State = *in.State
|
||||
}
|
||||
if in.Description != nil {
|
||||
r.Description = *in.Description
|
||||
}
|
||||
if in.Pattern != nil {
|
||||
r.Pattern = in.Pattern.JSON()
|
||||
}
|
||||
if in.Definition != nil {
|
||||
r.Definition, err = c.protectionManager.SanitizeJSON(r.Type, *in.Definition)
|
||||
if err != nil {
|
||||
return nil, usererror.BadRequestf("invalid rule definition: %s", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
userMap, userGroupMap, err := c.getRuleUserAndUserGroups(ctx, r)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get rule users and user groups: %w", err)
|
||||
}
|
||||
|
||||
r.Users = userMap
|
||||
r.UserGroups = userGroupMap
|
||||
|
||||
err = c.ruleStore.Update(ctx, r)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to update repository-level protection rule: %w", err)
|
||||
}
|
||||
|
||||
err = c.auditService.Log(ctx,
|
||||
session.Principal,
|
||||
audit.NewResource(audit.ResourceTypeBranchRule, r.Identifier, audit.RepoName, repo.Identifier),
|
||||
audit.ActionUpdated,
|
||||
paths.Parent(repo.Path),
|
||||
audit.WithOldObject(oldRule),
|
||||
audit.WithNewObject(r),
|
||||
rule, err := c.rulesSvc.Update(
|
||||
ctx, &session.Principal,
|
||||
enum.RuleParentRepo,
|
||||
repo.ID,
|
||||
repo.Identifier,
|
||||
repo.Path,
|
||||
identifier,
|
||||
in,
|
||||
)
|
||||
if err != nil {
|
||||
log.Ctx(ctx).Warn().Msgf("failed to insert audit log for update branch rule operation: %s", err)
|
||||
return nil, fmt.Errorf("failed to update repo-level protection rule by identifier: %w", err)
|
||||
}
|
||||
|
||||
return r, nil
|
||||
return rule, nil
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@ import (
|
|||
"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/rules"
|
||||
"github.com/harness/gitness/app/services/settings"
|
||||
"github.com/harness/gitness/app/services/usergroup"
|
||||
"github.com/harness/gitness/app/store"
|
||||
|
@ -77,6 +78,7 @@ func ProvideController(
|
|||
instrumentation instrument.Service,
|
||||
userGroupStore store.UserGroupStore,
|
||||
userGroupService usergroup.SearchService,
|
||||
rulesSvc *rules.Service,
|
||||
) *Controller {
|
||||
return NewController(config, tx, urlProvider,
|
||||
authorizer,
|
||||
|
@ -84,7 +86,9 @@ func ProvideController(
|
|||
principalStore, ruleStore, checkStore, pullReqStore, settings,
|
||||
principalInfoCache, protectionManager, rpcClient, importer,
|
||||
codeOwners, reporeporter, indexer, limiter, locker, auditService, mtxManager, identifierCheck,
|
||||
repoChecks, publicAccess, labelSvc, instrumentation, userGroupStore, userGroupService)
|
||||
repoChecks, publicAccess, labelSvc, instrumentation, userGroupStore, userGroupService,
|
||||
rulesSvc,
|
||||
)
|
||||
}
|
||||
|
||||
func ProvideRepoCheck() Check {
|
||||
|
|
|
@ -28,6 +28,7 @@ import (
|
|||
"github.com/harness/gitness/app/services/label"
|
||||
"github.com/harness/gitness/app/services/publicaccess"
|
||||
"github.com/harness/gitness/app/services/pullreq"
|
||||
"github.com/harness/gitness/app/services/rules"
|
||||
"github.com/harness/gitness/app/sse"
|
||||
"github.com/harness/gitness/app/store"
|
||||
"github.com/harness/gitness/app/url"
|
||||
|
@ -90,6 +91,7 @@ type Controller struct {
|
|||
labelSvc *label.Service
|
||||
instrumentation instrument.Service
|
||||
executionStore store.ExecutionStore
|
||||
rulesSvc *rules.Service
|
||||
}
|
||||
|
||||
func NewController(config *types.Config, tx dbtx.Transactor, urlProvider url.Provider,
|
||||
|
@ -102,6 +104,7 @@ func NewController(config *types.Config, tx dbtx.Transactor, urlProvider url.Pro
|
|||
limiter limiter.ResourceLimiter, publicAccess publicaccess.Service, auditService audit.Service,
|
||||
gitspaceSvc *gitspace.Service, labelSvc *label.Service,
|
||||
instrumentation instrument.Service, executionStore store.ExecutionStore,
|
||||
rulesSvc *rules.Service,
|
||||
) *Controller {
|
||||
return &Controller{
|
||||
nestedSpacesEnabled: config.NestedSpacesEnabled,
|
||||
|
@ -130,5 +133,6 @@ func NewController(config *types.Config, tx dbtx.Transactor, urlProvider url.Pro
|
|||
labelSvc: labelSvc,
|
||||
instrumentation: instrumentation,
|
||||
executionStore: executionStore,
|
||||
rulesSvc: rulesSvc,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/harness/gitness/app/auth"
|
||||
"github.com/harness/gitness/app/services/rules"
|
||||
"github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
)
|
||||
|
||||
// RuleCreate creates a new protection rule for a space.
|
||||
func (c *Controller) RuleCreate(ctx context.Context,
|
||||
session *auth.Session,
|
||||
spaceRef string,
|
||||
in *rules.CreateInput,
|
||||
) (*types.Rule, error) {
|
||||
space, err := c.getSpaceCheckAuth(ctx, session, spaceRef, enum.PermissionSpaceEdit)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to acquire access to space: %w", err)
|
||||
}
|
||||
|
||||
rule, err := c.rulesSvc.Create(
|
||||
ctx,
|
||||
&session.Principal,
|
||||
enum.RuleParentSpace,
|
||||
space.ID,
|
||||
space.Identifier,
|
||||
space.Path,
|
||||
in,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create space-level protection rule: %w", err)
|
||||
}
|
||||
|
||||
return rule, nil
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
// 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/auth"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
)
|
||||
|
||||
// RuleDelete deletes a protection rule by identifier.
|
||||
func (c *Controller) RuleDelete(ctx context.Context,
|
||||
session *auth.Session,
|
||||
spaceRef string,
|
||||
identifier string,
|
||||
) error {
|
||||
space, err := c.getSpaceCheckAuth(ctx, session, spaceRef, enum.PermissionSpaceEdit)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to acquire access to space: %w", err)
|
||||
}
|
||||
|
||||
err = c.rulesSvc.Delete(
|
||||
ctx,
|
||||
&session.Principal,
|
||||
enum.RuleParentSpace,
|
||||
space.ID,
|
||||
space.Identifier,
|
||||
space.Path,
|
||||
identifier,
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to delete space-level protection rule: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
// 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/auth"
|
||||
"github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
)
|
||||
|
||||
// RuleFind returns the protection rule by identifier.
|
||||
func (c *Controller) RuleFind(ctx context.Context,
|
||||
session *auth.Session,
|
||||
spaceRef string,
|
||||
identifier string,
|
||||
) (*types.Rule, error) {
|
||||
space, err := c.getSpaceCheckAuth(ctx, session, spaceRef, enum.PermissionSpaceView)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to acquire access to space: %w", err)
|
||||
}
|
||||
|
||||
rule, err := c.rulesSvc.Find(ctx, enum.RuleParentSpace, space.ID, identifier)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to find space-level protection rule by identifier: %w", err)
|
||||
}
|
||||
|
||||
return rule, nil
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
// 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/auth"
|
||||
"github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
)
|
||||
|
||||
// RuleList returns protection rules for a repository.
|
||||
func (c *Controller) RuleList(ctx context.Context,
|
||||
session *auth.Session,
|
||||
spaceRef string,
|
||||
inherited bool,
|
||||
filter *types.RuleFilter,
|
||||
) ([]types.Rule, int64, error) {
|
||||
space, err := c.getSpaceCheckAuth(ctx, session, spaceRef, enum.PermissionSpaceView)
|
||||
if err != nil {
|
||||
return nil, 0, fmt.Errorf("failed to acquire access to space: %w", err)
|
||||
}
|
||||
|
||||
list, count, err := c.rulesSvc.List(ctx, space.ID, enum.RuleParentSpace, inherited, filter)
|
||||
if err != nil {
|
||||
return nil, 0, fmt.Errorf("failed to list space-level protection rules: %w", err)
|
||||
}
|
||||
|
||||
return list, count, nil
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
// Copyright 2023 Harness, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package space
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/harness/gitness/app/auth"
|
||||
"github.com/harness/gitness/app/services/rules"
|
||||
"github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
)
|
||||
|
||||
// RuleUpdate updates an existing protection rule for a space.
|
||||
func (c *Controller) RuleUpdate(ctx context.Context,
|
||||
session *auth.Session,
|
||||
spaceRef string,
|
||||
identifier string,
|
||||
in *rules.UpdateInput,
|
||||
) (*types.Rule, error) {
|
||||
space, err := c.getSpaceCheckAuth(ctx, session, spaceRef, enum.PermissionSpaceEdit)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to acquire access to space: %w", err)
|
||||
}
|
||||
|
||||
rule, err := c.rulesSvc.Update(
|
||||
ctx,
|
||||
&session.Principal,
|
||||
enum.RuleParentSpace,
|
||||
space.ID,
|
||||
space.Identifier,
|
||||
space.Path,
|
||||
identifier,
|
||||
in,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to update space-level protection rule by identifier: %w", err)
|
||||
}
|
||||
|
||||
return rule, nil
|
||||
}
|
|
@ -25,6 +25,7 @@ import (
|
|||
"github.com/harness/gitness/app/services/label"
|
||||
"github.com/harness/gitness/app/services/publicaccess"
|
||||
"github.com/harness/gitness/app/services/pullreq"
|
||||
"github.com/harness/gitness/app/services/rules"
|
||||
"github.com/harness/gitness/app/sse"
|
||||
"github.com/harness/gitness/app/store"
|
||||
"github.com/harness/gitness/app/url"
|
||||
|
@ -47,18 +48,21 @@ 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, prListService *pullreq.ListService,
|
||||
importer *importer.Repository, exporter *exporter.Repository, limiter limiter.ResourceLimiter,
|
||||
publicAccess publicaccess.Service, auditService audit.Service, gitspaceService *gitspace.Service,
|
||||
importer *importer.Repository,
|
||||
exporter *exporter.Repository, limiter limiter.ResourceLimiter, publicAccess publicaccess.Service,
|
||||
auditService audit.Service, gitspaceService *gitspace.Service,
|
||||
labelSvc *label.Service, instrumentation instrument.Service, executionStore store.ExecutionStore,
|
||||
rulesSvc *rules.Service,
|
||||
) *Controller {
|
||||
return NewController(config, tx, urlProvider,
|
||||
sseStreamer, identifierCheck, authorizer,
|
||||
spacePathStore, pipelineStore, secretStore,
|
||||
connectorStore, templateStore,
|
||||
spaceStore, repoStore, principalStore,
|
||||
repoCtrl, membershipStore, prListService,
|
||||
importer, exporter, limiter,
|
||||
publicAccess, auditService, gitspaceService,
|
||||
repoCtrl, membershipStore, prListService, importer,
|
||||
exporter, limiter, publicAccess,
|
||||
auditService, gitspaceService,
|
||||
labelSvc, instrumentation, executionStore,
|
||||
rulesSvc,
|
||||
)
|
||||
}
|
||||
|
|
|
@ -21,9 +21,10 @@ 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/services/rules"
|
||||
)
|
||||
|
||||
// HandleRuleCreate handles API that adds a new protection rule to a repository.
|
||||
// HandleRuleCreate adds a new protection rule to a repository.
|
||||
func HandleRuleCreate(repoCtrl *repo.Controller) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
|
@ -35,7 +36,7 @@ func HandleRuleCreate(repoCtrl *repo.Controller) http.HandlerFunc {
|
|||
return
|
||||
}
|
||||
|
||||
in := new(repo.RuleCreateInput)
|
||||
in := new(rules.CreateInput)
|
||||
err = json.NewDecoder(r.Body).Decode(in)
|
||||
if err != nil {
|
||||
render.BadRequestf(ctx, w, "Invalid Request Body: %s.", err)
|
||||
|
|
|
@ -22,7 +22,7 @@ import (
|
|||
"github.com/harness/gitness/app/api/request"
|
||||
)
|
||||
|
||||
// HandleRuleDelete handles API that deletes a protection rule.
|
||||
// HandleRuleDelete deletes a protection rule of a repository.
|
||||
func HandleRuleDelete(repoCtrl *repo.Controller) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
|
|
|
@ -22,7 +22,7 @@ import (
|
|||
"github.com/harness/gitness/app/api/request"
|
||||
)
|
||||
|
||||
// HandleRuleFind handles API that returns a protection rule of a repository.
|
||||
// HandleRuleFind finds a protection rule of a repository.
|
||||
func HandleRuleFind(repoCtrl *repo.Controller) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
|
|
|
@ -22,7 +22,7 @@ import (
|
|||
"github.com/harness/gitness/app/api/request"
|
||||
)
|
||||
|
||||
// HandleRuleList handles API that lists a protection rules of a repository.
|
||||
// HandleRuleList lists rotection rules of a repository.
|
||||
func HandleRuleList(repoCtrl *repo.Controller) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
|
@ -36,7 +36,12 @@ func HandleRuleList(repoCtrl *repo.Controller) http.HandlerFunc {
|
|||
|
||||
filter := request.ParseRuleFilter(r)
|
||||
|
||||
rules, rulesCount, err := repoCtrl.RuleList(ctx, session, repoRef, filter)
|
||||
inherited, err := request.ParseInheritedFromQuery(r)
|
||||
if err != nil {
|
||||
render.TranslatedUserError(ctx, w, err)
|
||||
}
|
||||
|
||||
rules, rulesCount, err := repoCtrl.RuleList(ctx, session, repoRef, inherited, filter)
|
||||
if err != nil {
|
||||
render.TranslatedUserError(ctx, w, err)
|
||||
return
|
||||
|
|
|
@ -21,9 +21,10 @@ 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/services/rules"
|
||||
)
|
||||
|
||||
// HandleRuleUpdate handles API that updates a protection rule of a repository.
|
||||
// HandleRuleUpdate updates a protection rule of a repository.
|
||||
func HandleRuleUpdate(repoCtrl *repo.Controller) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
|
@ -41,7 +42,7 @@ func HandleRuleUpdate(repoCtrl *repo.Controller) http.HandlerFunc {
|
|||
return
|
||||
}
|
||||
|
||||
in := new(repo.RuleUpdateInput)
|
||||
in := new(rules.UpdateInput)
|
||||
err = json.NewDecoder(r.Body).Decode(in)
|
||||
if err != nil {
|
||||
render.BadRequestf(ctx, w, "Invalid Request Body: %s.", err)
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
// Copyright 2023 Harness, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package 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"
|
||||
"github.com/harness/gitness/app/services/rules"
|
||||
)
|
||||
|
||||
// HandleRuleCreate adds a new protection rule to a space.
|
||||
func HandleRuleCreate(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(rules.CreateInput)
|
||||
err = json.NewDecoder(r.Body).Decode(in)
|
||||
if err != nil {
|
||||
render.BadRequestf(ctx, w, "Invalid Request Body: %s.", err)
|
||||
return
|
||||
}
|
||||
|
||||
rule, err := spaceCtrl.RuleCreate(ctx, session, spaceRef, in)
|
||||
if err != nil {
|
||||
render.TranslatedUserError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
|
||||
render.JSON(w, http.StatusCreated, rule)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
// 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 (
|
||||
"net/http"
|
||||
|
||||
"github.com/harness/gitness/app/api/controller/space"
|
||||
"github.com/harness/gitness/app/api/render"
|
||||
"github.com/harness/gitness/app/api/request"
|
||||
)
|
||||
|
||||
// HandleRuleDelete deletes a protection rule of a space.
|
||||
func HandleRuleDelete(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
|
||||
}
|
||||
|
||||
ruleIdentifier, err := request.GetRuleIdentifierFromPath(r)
|
||||
if err != nil {
|
||||
render.TranslatedUserError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
|
||||
err = spaceCtrl.RuleDelete(ctx, session, spaceRef, ruleIdentifier)
|
||||
if err != nil {
|
||||
render.TranslatedUserError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
|
||||
render.DeleteSuccessful(w)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
// 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 (
|
||||
"net/http"
|
||||
|
||||
"github.com/harness/gitness/app/api/controller/space"
|
||||
"github.com/harness/gitness/app/api/render"
|
||||
"github.com/harness/gitness/app/api/request"
|
||||
)
|
||||
|
||||
// HandleRuleFind finds a protection rule of a space.
|
||||
func HandleRuleFind(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
|
||||
}
|
||||
|
||||
ruleIdentifier, err := request.GetRuleIdentifierFromPath(r)
|
||||
if err != nil {
|
||||
render.TranslatedUserError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
|
||||
rule, err := spaceCtrl.RuleFind(ctx, session, spaceRef, ruleIdentifier)
|
||||
if err != nil {
|
||||
render.TranslatedUserError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
|
||||
render.JSON(w, http.StatusOK, rule)
|
||||
}
|
||||
}
|
|
@ -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 (
|
||||
"net/http"
|
||||
|
||||
"github.com/harness/gitness/app/api/controller/space"
|
||||
"github.com/harness/gitness/app/api/render"
|
||||
"github.com/harness/gitness/app/api/request"
|
||||
)
|
||||
|
||||
// HandleRuleList lists a protection rules of a space.
|
||||
func HandleRuleList(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
|
||||
}
|
||||
|
||||
filter := request.ParseRuleFilter(r)
|
||||
inherited, err := request.ParseInheritedFromQuery(r)
|
||||
if err != nil {
|
||||
render.TranslatedUserError(ctx, w, err)
|
||||
}
|
||||
|
||||
rules, rulesCount, err := spaceCtrl.RuleList(ctx, session, spaceRef, inherited, filter)
|
||||
if err != nil {
|
||||
render.TranslatedUserError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
|
||||
render.Pagination(r, w, filter.Page, filter.Size, int(rulesCount))
|
||||
render.JSON(w, http.StatusOK, rules)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
// 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"
|
||||
"github.com/harness/gitness/app/services/rules"
|
||||
)
|
||||
|
||||
// HandleRuleUpdate updates a protection rule of a space.
|
||||
func HandleRuleUpdate(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
|
||||
}
|
||||
|
||||
ruleIdentifier, err := request.GetRuleIdentifierFromPath(r)
|
||||
if err != nil {
|
||||
render.TranslatedUserError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
|
||||
in := new(rules.UpdateInput)
|
||||
err = json.NewDecoder(r.Body).Decode(in)
|
||||
if err != nil {
|
||||
render.BadRequestf(ctx, w, "Invalid Request Body: %s.", err)
|
||||
return
|
||||
}
|
||||
|
||||
rule, err := spaceCtrl.RuleUpdate(ctx, session, spaceRef, ruleIdentifier, in)
|
||||
if err != nil {
|
||||
render.TranslatedUserError(ctx, w, err)
|
||||
return
|
||||
}
|
||||
|
||||
render.JSON(w, http.StatusOK, rule)
|
||||
}
|
||||
}
|
|
@ -61,6 +61,7 @@ func (*OpenAPI) Generate() *openapi3.Spec {
|
|||
spaceOperations(&reflector)
|
||||
pluginOperations(&reflector)
|
||||
repoOperations(&reflector)
|
||||
rulesOperations(&reflector)
|
||||
pipelineOperations(&reflector)
|
||||
connectorOperations(&reflector)
|
||||
templateOperations(&reflector)
|
||||
|
|
|
@ -21,7 +21,6 @@ import (
|
|||
"github.com/harness/gitness/app/api/controller/reposettings"
|
||||
"github.com/harness/gitness/app/api/request"
|
||||
"github.com/harness/gitness/app/api/usererror"
|
||||
"github.com/harness/gitness/app/services/protection"
|
||||
"github.com/harness/gitness/git"
|
||||
gittypes "github.com/harness/gitness/git/api"
|
||||
"github.com/harness/gitness/types"
|
||||
|
@ -175,31 +174,6 @@ type codeOwnersValidate struct {
|
|||
repoRequest
|
||||
}
|
||||
|
||||
// ruleType is a plugin for types.RuleType to allow using oneof.
|
||||
type ruleType string
|
||||
|
||||
func (ruleType) Enum() []interface{} {
|
||||
return []interface{}{protection.TypeBranch}
|
||||
}
|
||||
|
||||
// ruleDefinition is a plugin for types.Rule Definition to allow using oneof.
|
||||
type ruleDefinition struct{}
|
||||
|
||||
func (ruleDefinition) JSONSchemaOneOf() []interface{} {
|
||||
return []interface{}{protection.Branch{}}
|
||||
}
|
||||
|
||||
type rule struct {
|
||||
types.Rule
|
||||
|
||||
// overshadow Type and Definition to enable oneof.
|
||||
Type ruleType `json:"type"`
|
||||
Definition ruleDefinition `json:"definition"`
|
||||
|
||||
// overshadow Pattern to correct the type
|
||||
Pattern protection.Pattern `json:"pattern"`
|
||||
}
|
||||
|
||||
type restoreRequest struct {
|
||||
repoRequest
|
||||
repo.RestoreInput
|
||||
|
@ -1142,88 +1116,6 @@ func repoOperations(reflector *openapi3.Reflector) {
|
|||
_ = reflector.SetJSONResponse(&opMergeCheck, new(usererror.Error), http.StatusForbidden)
|
||||
_ = reflector.Spec.AddOperation(http.MethodPost, "/repos/{repo_ref}/merge-check/{range}", opMergeCheck)
|
||||
|
||||
opRuleAdd := openapi3.Operation{}
|
||||
opRuleAdd.WithTags("repository")
|
||||
opRuleAdd.WithMapOfAnything(map[string]interface{}{"operationId": "ruleAdd"})
|
||||
_ = reflector.SetRequest(&opRuleAdd, struct {
|
||||
repoRequest
|
||||
repo.RuleCreateInput
|
||||
|
||||
// overshadow "definition"
|
||||
Type ruleType `json:"type"`
|
||||
Definition ruleDefinition `json:"definition"`
|
||||
}{}, http.MethodPost)
|
||||
_ = reflector.SetJSONResponse(&opRuleAdd, rule{}, http.StatusCreated)
|
||||
_ = reflector.SetJSONResponse(&opRuleAdd, new(usererror.Error), http.StatusInternalServerError)
|
||||
_ = reflector.SetJSONResponse(&opRuleAdd, new(usererror.Error), http.StatusUnauthorized)
|
||||
_ = reflector.SetJSONResponse(&opRuleAdd, new(usererror.Error), http.StatusForbidden)
|
||||
_ = reflector.SetJSONResponse(&opRuleAdd, new(usererror.Error), http.StatusNotFound)
|
||||
_ = reflector.Spec.AddOperation(http.MethodPost, "/repos/{repo_ref}/rules", opRuleAdd)
|
||||
|
||||
opRuleDelete := openapi3.Operation{}
|
||||
opRuleDelete.WithTags("repository")
|
||||
opRuleDelete.WithMapOfAnything(map[string]interface{}{"operationId": "ruleDelete"})
|
||||
_ = reflector.SetRequest(&opRuleDelete, struct {
|
||||
repoRequest
|
||||
RuleIdentifier string `path:"rule_identifier"`
|
||||
}{}, http.MethodDelete)
|
||||
_ = reflector.SetJSONResponse(&opRuleDelete, nil, http.StatusNoContent)
|
||||
_ = reflector.SetJSONResponse(&opRuleDelete, new(usererror.Error), http.StatusInternalServerError)
|
||||
_ = reflector.SetJSONResponse(&opRuleDelete, new(usererror.Error), http.StatusUnauthorized)
|
||||
_ = reflector.SetJSONResponse(&opRuleDelete, new(usererror.Error), http.StatusForbidden)
|
||||
_ = reflector.SetJSONResponse(&opRuleDelete, new(usererror.Error), http.StatusNotFound)
|
||||
_ = reflector.Spec.AddOperation(http.MethodDelete, "/repos/{repo_ref}/rules/{rule_identifier}", opRuleDelete)
|
||||
|
||||
opRuleUpdate := openapi3.Operation{}
|
||||
opRuleUpdate.WithTags("repository")
|
||||
opRuleUpdate.WithMapOfAnything(map[string]interface{}{"operationId": "ruleUpdate"})
|
||||
_ = reflector.SetRequest(&opRuleUpdate, &struct {
|
||||
repoRequest
|
||||
Identifier string `path:"rule_identifier"`
|
||||
repo.RuleUpdateInput
|
||||
|
||||
// overshadow Type and Definition to enable oneof.
|
||||
Type ruleType `json:"type"`
|
||||
Definition ruleDefinition `json:"definition"`
|
||||
}{}, http.MethodPatch)
|
||||
_ = reflector.SetJSONResponse(&opRuleUpdate, rule{}, http.StatusOK)
|
||||
_ = reflector.SetJSONResponse(&opRuleUpdate, new(usererror.Error), http.StatusInternalServerError)
|
||||
_ = reflector.SetJSONResponse(&opRuleUpdate, new(usererror.Error), http.StatusUnauthorized)
|
||||
_ = reflector.SetJSONResponse(&opRuleUpdate, new(usererror.Error), http.StatusForbidden)
|
||||
_ = reflector.SetJSONResponse(&opRuleUpdate, new(usererror.Error), http.StatusNotFound)
|
||||
_ = reflector.Spec.AddOperation(http.MethodPatch, "/repos/{repo_ref}/rules/{rule_identifier}", opRuleUpdate)
|
||||
|
||||
opRuleList := openapi3.Operation{}
|
||||
opRuleList.WithTags("repository")
|
||||
opRuleList.WithMapOfAnything(map[string]interface{}{"operationId": "ruleList"})
|
||||
opRuleList.WithParameters(
|
||||
queryParameterQueryRuleList,
|
||||
queryParameterOrder, queryParameterSortRuleList,
|
||||
QueryParameterPage, QueryParameterLimit)
|
||||
_ = reflector.SetRequest(&opRuleList, &struct {
|
||||
repoRequest
|
||||
}{}, http.MethodGet)
|
||||
_ = reflector.SetJSONResponse(&opRuleList, []rule{}, http.StatusOK)
|
||||
_ = reflector.SetJSONResponse(&opRuleList, new(usererror.Error), http.StatusInternalServerError)
|
||||
_ = reflector.SetJSONResponse(&opRuleList, new(usererror.Error), http.StatusUnauthorized)
|
||||
_ = reflector.SetJSONResponse(&opRuleList, new(usererror.Error), http.StatusForbidden)
|
||||
_ = reflector.SetJSONResponse(&opRuleList, new(usererror.Error), http.StatusNotFound)
|
||||
_ = reflector.Spec.AddOperation(http.MethodGet, "/repos/{repo_ref}/rules", opRuleList)
|
||||
|
||||
opRuleGet := openapi3.Operation{}
|
||||
opRuleGet.WithTags("repository")
|
||||
opRuleGet.WithMapOfAnything(map[string]interface{}{"operationId": "ruleGet"})
|
||||
_ = reflector.SetRequest(&opRuleGet, &struct {
|
||||
repoRequest
|
||||
Identifier string `path:"rule_identifier"`
|
||||
}{}, http.MethodGet)
|
||||
_ = reflector.SetJSONResponse(&opRuleGet, rule{}, http.StatusOK)
|
||||
_ = reflector.SetJSONResponse(&opRuleGet, new(usererror.Error), http.StatusInternalServerError)
|
||||
_ = reflector.SetJSONResponse(&opRuleGet, new(usererror.Error), http.StatusUnauthorized)
|
||||
_ = reflector.SetJSONResponse(&opRuleGet, new(usererror.Error), http.StatusForbidden)
|
||||
_ = reflector.SetJSONResponse(&opRuleGet, new(usererror.Error), http.StatusNotFound)
|
||||
_ = reflector.Spec.AddOperation(http.MethodGet, "/repos/{repo_ref}/rules/{rule_identifier}", opRuleGet)
|
||||
|
||||
opCodeOwnerValidate := openapi3.Operation{}
|
||||
opCodeOwnerValidate.WithTags("repository")
|
||||
opCodeOwnerValidate.WithMapOfAnything(map[string]interface{}{"operationId": "codeOwnersValidate"})
|
||||
|
|
|
@ -0,0 +1,217 @@
|
|||
// 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 openapi
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/harness/gitness/app/api/usererror"
|
||||
"github.com/harness/gitness/app/services/protection"
|
||||
"github.com/harness/gitness/app/services/rules"
|
||||
"github.com/harness/gitness/types"
|
||||
|
||||
"github.com/swaggest/openapi-go/openapi3"
|
||||
)
|
||||
|
||||
// ruleType is a plugin for types.RuleType to allow using oneof.
|
||||
type ruleType string
|
||||
|
||||
func (ruleType) Enum() []interface{} {
|
||||
return []interface{}{protection.TypeBranch}
|
||||
}
|
||||
|
||||
// ruleDefinition is a plugin for types.Rule Definition to allow using oneof.
|
||||
type ruleDefinition struct{}
|
||||
|
||||
func (ruleDefinition) JSONSchemaOneOf() []interface{} {
|
||||
return []interface{}{protection.Branch{}}
|
||||
}
|
||||
|
||||
type rule struct {
|
||||
types.Rule
|
||||
|
||||
// overshadow Type and Definition to enable oneof.
|
||||
Type ruleType `json:"type"`
|
||||
Definition ruleDefinition `json:"definition"`
|
||||
|
||||
// overshadow Pattern to correct the type
|
||||
Pattern protection.Pattern `json:"pattern"`
|
||||
}
|
||||
|
||||
func rulesOperations(reflector *openapi3.Reflector) {
|
||||
opSpaceRuleAdd := openapi3.Operation{}
|
||||
opSpaceRuleAdd.WithTags("space")
|
||||
opSpaceRuleAdd.WithMapOfAnything(map[string]interface{}{"operationId": "spaceRuleAdd"})
|
||||
_ = reflector.SetRequest(&opSpaceRuleAdd, struct {
|
||||
spaceRequest
|
||||
rules.CreateInput
|
||||
|
||||
// overshadow "definition"
|
||||
Type ruleType `json:"type"`
|
||||
Definition ruleDefinition `json:"definition"`
|
||||
}{}, http.MethodPost)
|
||||
_ = reflector.SetJSONResponse(&opSpaceRuleAdd, rule{}, http.StatusCreated)
|
||||
_ = reflector.SetJSONResponse(&opSpaceRuleAdd, new(usererror.Error), http.StatusInternalServerError)
|
||||
_ = reflector.SetJSONResponse(&opSpaceRuleAdd, new(usererror.Error), http.StatusUnauthorized)
|
||||
_ = reflector.SetJSONResponse(&opSpaceRuleAdd, new(usererror.Error), http.StatusForbidden)
|
||||
_ = reflector.SetJSONResponse(&opSpaceRuleAdd, new(usererror.Error), http.StatusNotFound)
|
||||
_ = reflector.Spec.AddOperation(http.MethodPost, "/spaces/{space_ref}/rules", opSpaceRuleAdd)
|
||||
|
||||
opSpaceRuleDelete := openapi3.Operation{}
|
||||
opSpaceRuleDelete.WithTags("space")
|
||||
opSpaceRuleDelete.WithMapOfAnything(map[string]interface{}{"operationId": "spaceRuleDelete"})
|
||||
_ = reflector.SetRequest(&opSpaceRuleDelete, struct {
|
||||
spaceRequest
|
||||
RuleIdentifier string `path:"rule_identifier"`
|
||||
}{}, http.MethodDelete)
|
||||
_ = reflector.SetJSONResponse(&opSpaceRuleDelete, nil, http.StatusNoContent)
|
||||
_ = reflector.SetJSONResponse(&opSpaceRuleDelete, new(usererror.Error), http.StatusInternalServerError)
|
||||
_ = reflector.SetJSONResponse(&opSpaceRuleDelete, new(usererror.Error), http.StatusUnauthorized)
|
||||
_ = reflector.SetJSONResponse(&opSpaceRuleDelete, new(usererror.Error), http.StatusForbidden)
|
||||
_ = reflector.SetJSONResponse(&opSpaceRuleDelete, new(usererror.Error), http.StatusNotFound)
|
||||
_ = reflector.Spec.AddOperation(http.MethodDelete, "/spaces/{space_ref}/rules/{rule_identifier}", opSpaceRuleDelete)
|
||||
|
||||
opSpaceRuleUpdate := openapi3.Operation{}
|
||||
opSpaceRuleUpdate.WithTags("space")
|
||||
opSpaceRuleUpdate.WithMapOfAnything(map[string]interface{}{"operationId": "spaceRuleUpdate"})
|
||||
_ = reflector.SetRequest(&opSpaceRuleUpdate, &struct {
|
||||
spaceRequest
|
||||
Identifier string `path:"rule_identifier"`
|
||||
rules.UpdateInput
|
||||
|
||||
// overshadow Type and Definition to enable oneof.
|
||||
Type ruleType `json:"type"`
|
||||
Definition ruleDefinition `json:"definition"`
|
||||
}{}, http.MethodPatch)
|
||||
_ = reflector.SetJSONResponse(&opSpaceRuleUpdate, rule{}, http.StatusOK)
|
||||
_ = reflector.SetJSONResponse(&opSpaceRuleUpdate, new(usererror.Error), http.StatusInternalServerError)
|
||||
_ = reflector.SetJSONResponse(&opSpaceRuleUpdate, new(usererror.Error), http.StatusUnauthorized)
|
||||
_ = reflector.SetJSONResponse(&opSpaceRuleUpdate, new(usererror.Error), http.StatusForbidden)
|
||||
_ = reflector.SetJSONResponse(&opSpaceRuleUpdate, new(usererror.Error), http.StatusNotFound)
|
||||
_ = reflector.Spec.AddOperation(http.MethodPatch, "/spaces/{space_ref}/rules/{rule_identifier}", opSpaceRuleUpdate)
|
||||
|
||||
opSpaceRuleList := openapi3.Operation{}
|
||||
opSpaceRuleList.WithTags("space")
|
||||
opSpaceRuleList.WithMapOfAnything(map[string]interface{}{"operationId": "spaceRuleList"})
|
||||
opSpaceRuleList.WithParameters(
|
||||
queryParameterQueryRuleList,
|
||||
queryParameterOrder, queryParameterSortRuleList,
|
||||
QueryParameterPage, QueryParameterLimit)
|
||||
_ = reflector.SetRequest(&opSpaceRuleList, &struct {
|
||||
spaceRequest
|
||||
}{}, http.MethodGet)
|
||||
_ = reflector.SetJSONResponse(&opSpaceRuleList, []rule{}, http.StatusOK)
|
||||
_ = reflector.SetJSONResponse(&opSpaceRuleList, new(usererror.Error), http.StatusInternalServerError)
|
||||
_ = reflector.SetJSONResponse(&opSpaceRuleList, new(usererror.Error), http.StatusUnauthorized)
|
||||
_ = reflector.SetJSONResponse(&opSpaceRuleList, new(usererror.Error), http.StatusForbidden)
|
||||
_ = reflector.SetJSONResponse(&opSpaceRuleList, new(usererror.Error), http.StatusNotFound)
|
||||
_ = reflector.Spec.AddOperation(http.MethodGet, "/spaces/{space_ref}/rules", opSpaceRuleList)
|
||||
|
||||
opSpaceRuleGet := openapi3.Operation{}
|
||||
opSpaceRuleGet.WithTags("space")
|
||||
opSpaceRuleGet.WithMapOfAnything(map[string]interface{}{"operationId": "spaceRuleGet"})
|
||||
_ = reflector.SetRequest(&opSpaceRuleGet, &struct {
|
||||
spaceRequest
|
||||
Identifier string `path:"rule_identifier"`
|
||||
}{}, http.MethodGet)
|
||||
_ = reflector.SetJSONResponse(&opSpaceRuleGet, rule{}, http.StatusOK)
|
||||
_ = reflector.SetJSONResponse(&opSpaceRuleGet, new(usererror.Error), http.StatusInternalServerError)
|
||||
_ = reflector.SetJSONResponse(&opSpaceRuleGet, new(usererror.Error), http.StatusUnauthorized)
|
||||
_ = reflector.SetJSONResponse(&opSpaceRuleGet, new(usererror.Error), http.StatusForbidden)
|
||||
_ = reflector.SetJSONResponse(&opSpaceRuleGet, new(usererror.Error), http.StatusNotFound)
|
||||
_ = reflector.Spec.AddOperation(http.MethodGet, "/spaces/{space_ref}/rules/{rule_identifier}", opSpaceRuleGet)
|
||||
|
||||
opRepoRuleAdd := openapi3.Operation{}
|
||||
opRepoRuleAdd.WithTags("repository")
|
||||
opRepoRuleAdd.WithMapOfAnything(map[string]interface{}{"operationId": "repoRuleAdd"})
|
||||
_ = reflector.SetRequest(&opRepoRuleAdd, struct {
|
||||
repoRequest
|
||||
rules.CreateInput
|
||||
|
||||
// overshadow "definition"
|
||||
Type ruleType `json:"type"`
|
||||
Definition ruleDefinition `json:"definition"`
|
||||
}{}, http.MethodPost)
|
||||
_ = reflector.SetJSONResponse(&opRepoRuleAdd, rule{}, http.StatusCreated)
|
||||
_ = reflector.SetJSONResponse(&opRepoRuleAdd, new(usererror.Error), http.StatusInternalServerError)
|
||||
_ = reflector.SetJSONResponse(&opRepoRuleAdd, new(usererror.Error), http.StatusUnauthorized)
|
||||
_ = reflector.SetJSONResponse(&opRepoRuleAdd, new(usererror.Error), http.StatusForbidden)
|
||||
_ = reflector.SetJSONResponse(&opRepoRuleAdd, new(usererror.Error), http.StatusNotFound)
|
||||
_ = reflector.Spec.AddOperation(http.MethodPost, "/repos/{repo_ref}/rules", opRepoRuleAdd)
|
||||
|
||||
opRepoRuleDelete := openapi3.Operation{}
|
||||
opRepoRuleDelete.WithTags("repository")
|
||||
opRepoRuleDelete.WithMapOfAnything(map[string]interface{}{"operationId": "repoRuleDelete"})
|
||||
_ = reflector.SetRequest(&opRepoRuleDelete, struct {
|
||||
repoRequest
|
||||
RuleIdentifier string `path:"rule_identifier"`
|
||||
}{}, http.MethodDelete)
|
||||
_ = reflector.SetJSONResponse(&opRepoRuleDelete, nil, http.StatusNoContent)
|
||||
_ = reflector.SetJSONResponse(&opRepoRuleDelete, new(usererror.Error), http.StatusInternalServerError)
|
||||
_ = reflector.SetJSONResponse(&opRepoRuleDelete, new(usererror.Error), http.StatusUnauthorized)
|
||||
_ = reflector.SetJSONResponse(&opRepoRuleDelete, new(usererror.Error), http.StatusForbidden)
|
||||
_ = reflector.SetJSONResponse(&opRepoRuleDelete, new(usererror.Error), http.StatusNotFound)
|
||||
_ = reflector.Spec.AddOperation(http.MethodDelete, "/repos/{repo_ref}/rules/{rule_identifier}", opRepoRuleDelete)
|
||||
|
||||
opRepoRuleUpdate := openapi3.Operation{}
|
||||
opRepoRuleUpdate.WithTags("repository")
|
||||
opRepoRuleUpdate.WithMapOfAnything(map[string]interface{}{"operationId": "repoRuleUpdate"})
|
||||
_ = reflector.SetRequest(&opRepoRuleUpdate, &struct {
|
||||
repoRequest
|
||||
Identifier string `path:"rule_identifier"`
|
||||
rules.UpdateInput
|
||||
|
||||
// overshadow Type and Definition to enable oneof.
|
||||
Type ruleType `json:"type"`
|
||||
Definition ruleDefinition `json:"definition"`
|
||||
}{}, http.MethodPatch)
|
||||
_ = reflector.SetJSONResponse(&opRepoRuleUpdate, rule{}, http.StatusOK)
|
||||
_ = reflector.SetJSONResponse(&opRepoRuleUpdate, new(usererror.Error), http.StatusInternalServerError)
|
||||
_ = reflector.SetJSONResponse(&opRepoRuleUpdate, new(usererror.Error), http.StatusUnauthorized)
|
||||
_ = reflector.SetJSONResponse(&opRepoRuleUpdate, new(usererror.Error), http.StatusForbidden)
|
||||
_ = reflector.SetJSONResponse(&opRepoRuleUpdate, new(usererror.Error), http.StatusNotFound)
|
||||
_ = reflector.Spec.AddOperation(http.MethodPatch, "/repos/{repo_ref}/rules/{rule_identifier}", opRepoRuleUpdate)
|
||||
|
||||
opRepoRuleList := openapi3.Operation{}
|
||||
opRepoRuleList.WithTags("repository")
|
||||
opRepoRuleList.WithMapOfAnything(map[string]interface{}{"operationId": "repoRuleList"})
|
||||
opRepoRuleList.WithParameters(
|
||||
queryParameterQueryRuleList,
|
||||
queryParameterOrder, queryParameterSortRuleList,
|
||||
QueryParameterPage, QueryParameterLimit)
|
||||
_ = reflector.SetRequest(&opRepoRuleList, &struct {
|
||||
repoRequest
|
||||
}{}, http.MethodGet)
|
||||
_ = reflector.SetJSONResponse(&opRepoRuleList, []rule{}, http.StatusOK)
|
||||
_ = reflector.SetJSONResponse(&opRepoRuleList, new(usererror.Error), http.StatusInternalServerError)
|
||||
_ = reflector.SetJSONResponse(&opRepoRuleList, new(usererror.Error), http.StatusUnauthorized)
|
||||
_ = reflector.SetJSONResponse(&opRepoRuleList, new(usererror.Error), http.StatusForbidden)
|
||||
_ = reflector.SetJSONResponse(&opRepoRuleList, new(usererror.Error), http.StatusNotFound)
|
||||
_ = reflector.Spec.AddOperation(http.MethodGet, "/repos/{repo_ref}/rules", opRepoRuleList)
|
||||
|
||||
opRepoRuleGet := openapi3.Operation{}
|
||||
opRepoRuleGet.WithTags("repository")
|
||||
opRepoRuleGet.WithMapOfAnything(map[string]interface{}{"operationId": "repoRuleGet"})
|
||||
_ = reflector.SetRequest(&opRepoRuleGet, &struct {
|
||||
repoRequest
|
||||
Identifier string `path:"rule_identifier"`
|
||||
}{}, http.MethodGet)
|
||||
_ = reflector.SetJSONResponse(&opRepoRuleGet, rule{}, http.StatusOK)
|
||||
_ = reflector.SetJSONResponse(&opRepoRuleGet, new(usererror.Error), http.StatusInternalServerError)
|
||||
_ = reflector.SetJSONResponse(&opRepoRuleGet, new(usererror.Error), http.StatusUnauthorized)
|
||||
_ = reflector.SetJSONResponse(&opRepoRuleGet, new(usererror.Error), http.StatusForbidden)
|
||||
_ = reflector.SetJSONResponse(&opRepoRuleGet, new(usererror.Error), http.StatusNotFound)
|
||||
_ = reflector.Spec.AddOperation(http.MethodGet, "/repos/{repo_ref}/rules/{rule_identifier}", opRepoRuleGet)
|
||||
}
|
|
@ -293,6 +293,7 @@ func setupSpaces(
|
|||
|
||||
SetupSpaceLabels(r, spaceCtrl)
|
||||
SetupWebhookSpace(r, webhookCtrl)
|
||||
SetupRulesSpace(r, spaceCtrl)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
@ -341,6 +342,19 @@ func SetupWebhookSpace(r chi.Router, webhookCtrl *webhook.Controller) {
|
|||
})
|
||||
}
|
||||
|
||||
func SetupRulesSpace(r chi.Router, spaceCtrl *space.Controller) {
|
||||
r.Route("/rules", func(r chi.Router) {
|
||||
r.Post("/", handlerspace.HandleRuleCreate(spaceCtrl))
|
||||
r.Get("/", handlerspace.HandleRuleList(spaceCtrl))
|
||||
|
||||
r.Route(fmt.Sprintf("/{%s}", request.PathParamRuleIdentifier), func(r chi.Router) {
|
||||
r.Patch("/", handlerspace.HandleRuleUpdate(spaceCtrl))
|
||||
r.Delete("/", handlerspace.HandleRuleDelete(spaceCtrl))
|
||||
r.Get("/", handlerspace.HandleRuleFind(spaceCtrl))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func setupRepos(r chi.Router,
|
||||
repoCtrl *repo.Controller,
|
||||
repoSettingsCtrl *reposettings.Controller,
|
||||
|
@ -460,7 +474,7 @@ func setupRepos(r chi.Router,
|
|||
|
||||
SetupUploads(r, uploadCtrl)
|
||||
|
||||
SetupRules(r, repoCtrl)
|
||||
SetupRulesRepo(r, repoCtrl)
|
||||
|
||||
SetupRepoLabels(r, repoCtrl)
|
||||
})
|
||||
|
@ -742,7 +756,7 @@ func SetupChecks(r chi.Router, checkCtrl *check.Controller) {
|
|||
})
|
||||
}
|
||||
|
||||
func SetupRules(r chi.Router, repoCtrl *repo.Controller) {
|
||||
func SetupRulesRepo(r chi.Router, repoCtrl *repo.Controller) {
|
||||
r.Route("/rules", func(r chi.Router) {
|
||||
r.Post("/", handlerrepo.HandleRuleCreate(repoCtrl))
|
||||
r.Get("/", handlerrepo.HandleRuleList(repoCtrl))
|
||||
|
|
|
@ -42,6 +42,9 @@ const (
|
|||
PropertyIsDefaultBranch Property = "is_default_branch"
|
||||
PropertyDecision Property = "decision"
|
||||
PropertyRepositories Property = "repositories"
|
||||
|
||||
PropertySpaceID Property = "space_id"
|
||||
PropertySpaceName Property = "space_name"
|
||||
)
|
||||
|
||||
type EventType string
|
||||
|
|
|
@ -0,0 +1,96 @@
|
|||
// 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 rules
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/harness/gitness/app/services/protection"
|
||||
"github.com/harness/gitness/types"
|
||||
)
|
||||
|
||||
func (s *Service) getRuleUserAndUserGroups(
|
||||
ctx context.Context,
|
||||
rule *types.Rule,
|
||||
) (map[int64]*types.PrincipalInfo, map[int64]*types.UserGroupInfo, error) {
|
||||
protection, err := s.parseRule(rule)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to parse rule: %w", err)
|
||||
}
|
||||
|
||||
userMap, err := s.getRuleUsers(ctx, protection)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to get rule users: %w", err)
|
||||
}
|
||||
userGroupMap, err := s.getRuleUserGroups(ctx, protection)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to get rule user groups: %w", err)
|
||||
}
|
||||
|
||||
return userMap, userGroupMap, nil
|
||||
}
|
||||
|
||||
func (s *Service) getRuleUsers(
|
||||
ctx context.Context,
|
||||
protection protection.Protection,
|
||||
) (map[int64]*types.PrincipalInfo, error) {
|
||||
userIDs, err := protection.UserIDs()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get user ID from rule: %w", err)
|
||||
}
|
||||
|
||||
userMap, err := s.principalInfoCache.Map(ctx, userIDs)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get principal infos: %w", err)
|
||||
}
|
||||
|
||||
return userMap, nil
|
||||
}
|
||||
|
||||
func (s *Service) getRuleUserGroups(
|
||||
ctx context.Context,
|
||||
protection protection.Protection,
|
||||
) (map[int64]*types.UserGroupInfo, error) {
|
||||
groupIDs, err := protection.UserGroupIDs()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get group IDs from rule: %w", err)
|
||||
}
|
||||
|
||||
userGroupInfoMap := make(map[int64]*types.UserGroupInfo)
|
||||
|
||||
if len(groupIDs) == 0 {
|
||||
return userGroupInfoMap, nil
|
||||
}
|
||||
|
||||
groupMap, err := s.userGroupStore.Map(ctx, groupIDs)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get userGroup infos: %w", err)
|
||||
}
|
||||
|
||||
for k, v := range groupMap {
|
||||
userGroupInfoMap[k] = v.ToUserGroupInfo()
|
||||
}
|
||||
return userGroupInfoMap, nil
|
||||
}
|
||||
|
||||
func (s *Service) parseRule(rule *types.Rule) (protection.Protection, error) {
|
||||
protection, err := s.protectionManager.FromJSON(rule.Type, rule.Definition, false)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse json rule definition: %w", err)
|
||||
}
|
||||
|
||||
return protection, nil
|
||||
}
|
|
@ -0,0 +1,197 @@
|
|||
// 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 rules
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/harness/gitness/app/api/usererror"
|
||||
"github.com/harness/gitness/app/paths"
|
||||
"github.com/harness/gitness/app/services/instrument"
|
||||
"github.com/harness/gitness/app/services/protection"
|
||||
"github.com/harness/gitness/audit"
|
||||
"github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/check"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
type CreateInput struct {
|
||||
Type types.RuleType `json:"type"`
|
||||
State enum.RuleState `json:"state"`
|
||||
// TODO [CODE-1363]: remove after identifier migration.
|
||||
UID string `json:"uid" deprecated:"true"`
|
||||
Identifier string `json:"identifier"`
|
||||
Description string `json:"description"`
|
||||
Pattern protection.Pattern `json:"pattern"`
|
||||
Definition json.RawMessage `json:"definition"`
|
||||
}
|
||||
|
||||
// sanitize validates and sanitizes the create rule input data.
|
||||
func (in *CreateInput) sanitize() error {
|
||||
// TODO [CODE-1363]: remove after identifier migration.
|
||||
if in.Identifier == "" {
|
||||
in.Identifier = in.UID
|
||||
}
|
||||
|
||||
if err := check.Identifier(in.Identifier); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := in.Pattern.Validate(); err != nil {
|
||||
return usererror.BadRequestf("invalid pattern: %s", err)
|
||||
}
|
||||
|
||||
var ok bool
|
||||
in.State, ok = in.State.Sanitize()
|
||||
if !ok {
|
||||
return usererror.BadRequest("rule state is invalid")
|
||||
}
|
||||
|
||||
if in.Type == "" {
|
||||
in.Type = protection.TypeBranch
|
||||
}
|
||||
|
||||
if len(in.Definition) == 0 {
|
||||
return usererror.BadRequest("rule definition missing")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Create creates a new protection rule for a scope.
|
||||
func (s *Service) Create(ctx context.Context,
|
||||
principal *types.Principal,
|
||||
parentType enum.RuleParent,
|
||||
parentID int64,
|
||||
scopeIdentifier string,
|
||||
path string,
|
||||
in *CreateInput,
|
||||
) (*types.Rule, error) {
|
||||
if err := in.sanitize(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var err error
|
||||
in.Definition, err = s.protectionManager.SanitizeJSON(in.Type, in.Definition)
|
||||
if err != nil {
|
||||
return nil, usererror.BadRequestf("invalid rule definition: %s", err.Error())
|
||||
}
|
||||
|
||||
now := time.Now().UnixMilli()
|
||||
rule := &types.Rule{
|
||||
CreatedBy: principal.ID,
|
||||
Created: now,
|
||||
Updated: now,
|
||||
Type: in.Type,
|
||||
State: in.State,
|
||||
Identifier: in.Identifier,
|
||||
Description: in.Description,
|
||||
Pattern: in.Pattern.JSON(),
|
||||
Definition: in.Definition,
|
||||
CreatedByInfo: types.PrincipalInfo{},
|
||||
}
|
||||
|
||||
nameKey := audit.RepoName
|
||||
if parentType == enum.RuleParentRepo {
|
||||
rule.RepoID = &parentID
|
||||
} else if parentType == enum.RuleParentSpace {
|
||||
nameKey = audit.SpaceName
|
||||
rule.SpaceID = &parentID
|
||||
}
|
||||
|
||||
err = s.ruleStore.Create(ctx, rule)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create protection rule: %w", err)
|
||||
}
|
||||
|
||||
err = s.auditService.Log(ctx,
|
||||
*principal,
|
||||
audit.NewResource(audit.ResourceTypeBranchRule, rule.Identifier, nameKey, scopeIdentifier),
|
||||
audit.ActionCreated,
|
||||
paths.Parent(path),
|
||||
audit.WithNewObject(rule),
|
||||
)
|
||||
if err != nil {
|
||||
log.Ctx(ctx).Warn().Msgf("failed to insert audit log for create branch rule operation: %s", err)
|
||||
}
|
||||
|
||||
userMap, userGroupMap, err := s.getRuleUserAndUserGroups(ctx, rule)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get rule users and user groups: %w", err)
|
||||
}
|
||||
|
||||
rule.Users = userMap
|
||||
rule.UserGroups = userGroupMap
|
||||
|
||||
var event instrument.Event
|
||||
if parentType == enum.RuleParentRepo {
|
||||
event = instrumentEventRepo(
|
||||
rule.ID, principal.ToPrincipalInfo(), parentID, scopeIdentifier, path,
|
||||
)
|
||||
} else if parentType == enum.RuleParentSpace {
|
||||
event = instrumentEventSpace(
|
||||
rule.ID, principal.ToPrincipalInfo(), parentID, scopeIdentifier, path,
|
||||
)
|
||||
}
|
||||
err = s.instrumentation.Track(ctx, event)
|
||||
if err != nil {
|
||||
log.Ctx(ctx).Warn().Msgf("failed to insert instrumentation record for create branch rule operation: %s", err)
|
||||
}
|
||||
|
||||
return rule, nil
|
||||
}
|
||||
|
||||
func instrumentEventRepo(
|
||||
ruleID int64,
|
||||
principalInfo *types.PrincipalInfo,
|
||||
scopeID int64,
|
||||
scopeIdentifier string,
|
||||
path string,
|
||||
) instrument.Event {
|
||||
return instrument.Event{
|
||||
Type: instrument.EventTypeCreateBranchRule,
|
||||
Principal: principalInfo,
|
||||
Path: path,
|
||||
Properties: map[instrument.Property]any{
|
||||
instrument.PropertyRepositoryID: scopeID,
|
||||
instrument.PropertyRepositoryName: scopeIdentifier,
|
||||
instrument.PropertyRuleID: ruleID,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func instrumentEventSpace(
|
||||
ruleID int64,
|
||||
principalInfo *types.PrincipalInfo,
|
||||
scopeID int64,
|
||||
scopeIdentifier string,
|
||||
path string,
|
||||
) instrument.Event {
|
||||
return instrument.Event{
|
||||
Type: instrument.EventTypeCreateBranchRule,
|
||||
Principal: principalInfo,
|
||||
Path: path,
|
||||
Properties: map[instrument.Property]any{
|
||||
instrument.PropertySpaceID: scopeID,
|
||||
instrument.PropertySpaceName: scopeIdentifier,
|
||||
instrument.PropertyRuleID: ruleID,
|
||||
},
|
||||
}
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
// 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 rules
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/harness/gitness/app/paths"
|
||||
"github.com/harness/gitness/audit"
|
||||
"github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
// Delete deletes a protection rule by identifier.
|
||||
func (s *Service) Delete(ctx context.Context,
|
||||
principal *types.Principal,
|
||||
parentType enum.RuleParent,
|
||||
parentID int64,
|
||||
scopeIdentifier string,
|
||||
path string,
|
||||
identifier string,
|
||||
) error {
|
||||
rule, err := s.ruleStore.FindByIdentifier(ctx, parentType, parentID, identifier)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to find protection rule by identifier: %w", err)
|
||||
}
|
||||
|
||||
err = s.ruleStore.Delete(ctx, rule.ID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to delete protection rule: %w", err)
|
||||
}
|
||||
|
||||
nameKey := audit.RepoName
|
||||
if parentType == enum.RuleParentSpace {
|
||||
nameKey = audit.SpaceName
|
||||
}
|
||||
err = s.auditService.Log(ctx,
|
||||
*principal,
|
||||
audit.NewResource(
|
||||
audit.ResourceTypeBranchRule,
|
||||
rule.Identifier,
|
||||
nameKey,
|
||||
scopeIdentifier,
|
||||
),
|
||||
audit.ActionDeleted,
|
||||
paths.Parent(path),
|
||||
audit.WithOldObject(rule),
|
||||
)
|
||||
if err != nil {
|
||||
log.Ctx(ctx).Warn().Msgf("failed to insert audit log for delete branch rule operation: %s", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
// 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 rules
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
)
|
||||
|
||||
// Find returns the protection rule by identifier.
|
||||
func (s *Service) Find(ctx context.Context,
|
||||
parentType enum.RuleParent,
|
||||
parentID int64,
|
||||
identifier string,
|
||||
) (*types.Rule, error) {
|
||||
rule, err := s.ruleStore.FindByIdentifier(ctx, parentType, parentID, identifier)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to find protection rule by identifier: %w", err)
|
||||
}
|
||||
|
||||
userMap, userGroupMap, err := s.getRuleUserAndUserGroups(ctx, rule)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get rule users and user groups: %w", err)
|
||||
}
|
||||
|
||||
rule.Users = userMap
|
||||
rule.UserGroups = userGroupMap
|
||||
|
||||
return rule, nil
|
||||
}
|
|
@ -0,0 +1,147 @@
|
|||
// 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 rules
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/harness/gitness/store/database/dbtx"
|
||||
"github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
)
|
||||
|
||||
// List returns protection rules for a scope.
|
||||
func (s *Service) List(ctx context.Context,
|
||||
parentID int64,
|
||||
parentType enum.RuleParent,
|
||||
inherited bool,
|
||||
filter *types.RuleFilter,
|
||||
) ([]types.Rule, int64, error) {
|
||||
var parents []types.RuleParentInfo
|
||||
var err error
|
||||
|
||||
switch parentType {
|
||||
case enum.RuleParentRepo:
|
||||
parents, err = s.getParentInfoRepo(ctx, parentID, inherited)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
case enum.RuleParentSpace:
|
||||
parents, err = s.getParentInfoSpace(ctx, parentID, inherited)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
default:
|
||||
return nil, 0, fmt.Errorf("webhook type %s is not supported", parentType)
|
||||
}
|
||||
|
||||
var list []types.Rule
|
||||
var count int64
|
||||
|
||||
err = s.tx.WithTx(ctx, func(ctx context.Context) error {
|
||||
list, err = s.ruleStore.List(ctx, parents, filter)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to list protection rules: %w", err)
|
||||
}
|
||||
|
||||
if filter.Page == 1 && len(list) < filter.Size {
|
||||
count = int64(len(list))
|
||||
return nil
|
||||
}
|
||||
|
||||
count, err = s.ruleStore.Count(ctx, parents, filter)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to count protection rules: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}, dbtx.TxDefaultReadOnly)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
for i := range list {
|
||||
list[i].Users, list[i].UserGroups, err = s.getRuleUserAndUserGroups(ctx, &list[i])
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
}
|
||||
|
||||
return list, count, nil
|
||||
}
|
||||
|
||||
func (s *Service) getParentInfoRepo(
|
||||
ctx context.Context,
|
||||
repoID int64,
|
||||
inherited bool,
|
||||
) ([]types.RuleParentInfo, error) {
|
||||
var parents []types.RuleParentInfo
|
||||
|
||||
parents = append(parents, types.RuleParentInfo{
|
||||
ID: repoID,
|
||||
Type: enum.RuleParentRepo,
|
||||
})
|
||||
|
||||
if inherited {
|
||||
repo, err := s.repoStore.Find(ctx, repoID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get repo: %w", err)
|
||||
}
|
||||
|
||||
ids, err := s.spaceStore.GetAncestorIDs(ctx, repo.ParentID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get parent space ids: %w", err)
|
||||
}
|
||||
|
||||
for _, id := range ids {
|
||||
parents = append(parents, types.RuleParentInfo{
|
||||
Type: enum.RuleParentSpace,
|
||||
ID: id,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return parents, nil
|
||||
}
|
||||
|
||||
func (s *Service) getParentInfoSpace(
|
||||
ctx context.Context,
|
||||
spaceID int64,
|
||||
inherited bool,
|
||||
) ([]types.RuleParentInfo, error) {
|
||||
var parents []types.RuleParentInfo
|
||||
|
||||
if inherited {
|
||||
ids, err := s.spaceStore.GetAncestorIDs(ctx, spaceID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get parent space ids: %w", err)
|
||||
}
|
||||
|
||||
for _, id := range ids {
|
||||
parents = append(parents, types.RuleParentInfo{
|
||||
Type: enum.RuleParentSpace,
|
||||
ID: id,
|
||||
})
|
||||
}
|
||||
} else {
|
||||
parents = append(parents, types.RuleParentInfo{
|
||||
Type: enum.RuleParentSpace,
|
||||
ID: spaceID,
|
||||
})
|
||||
}
|
||||
|
||||
return parents, nil
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
// 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 rules
|
||||
|
||||
import (
|
||||
"github.com/harness/gitness/app/services/instrument"
|
||||
"github.com/harness/gitness/app/services/protection"
|
||||
"github.com/harness/gitness/app/services/usergroup"
|
||||
"github.com/harness/gitness/app/store"
|
||||
"github.com/harness/gitness/audit"
|
||||
"github.com/harness/gitness/store/database/dbtx"
|
||||
)
|
||||
|
||||
// Service is responsible for processing rules.
|
||||
type Service struct {
|
||||
tx dbtx.Transactor
|
||||
|
||||
ruleStore store.RuleStore
|
||||
repoStore store.RepoStore
|
||||
spaceStore store.SpaceStore
|
||||
protectionManager *protection.Manager
|
||||
auditService audit.Service
|
||||
instrumentation instrument.Service
|
||||
principalInfoCache store.PrincipalInfoCache
|
||||
userGroupStore store.UserGroupStore
|
||||
userGroupService usergroup.SearchService
|
||||
}
|
||||
|
||||
func NewService(
|
||||
tx dbtx.Transactor,
|
||||
ruleStore store.RuleStore,
|
||||
repoStore store.RepoStore,
|
||||
spaceStore store.SpaceStore,
|
||||
protectionManager *protection.Manager,
|
||||
auditService audit.Service,
|
||||
instrumentation instrument.Service,
|
||||
principalInfoCache store.PrincipalInfoCache,
|
||||
userGroupStore store.UserGroupStore,
|
||||
userGroupService usergroup.SearchService,
|
||||
|
||||
) *Service {
|
||||
return &Service{
|
||||
tx: tx,
|
||||
ruleStore: ruleStore,
|
||||
repoStore: repoStore,
|
||||
spaceStore: spaceStore,
|
||||
protectionManager: protectionManager,
|
||||
auditService: auditService,
|
||||
instrumentation: instrumentation,
|
||||
principalInfoCache: principalInfoCache,
|
||||
userGroupStore: userGroupStore,
|
||||
userGroupService: userGroupService,
|
||||
}
|
||||
}
|
|
@ -0,0 +1,167 @@
|
|||
// 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 rules
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/harness/gitness/app/api/usererror"
|
||||
"github.com/harness/gitness/app/paths"
|
||||
"github.com/harness/gitness/app/services/protection"
|
||||
"github.com/harness/gitness/audit"
|
||||
"github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/check"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
type UpdateInput struct {
|
||||
// TODO [CODE-1363]: remove after identifier migration.
|
||||
UID *string `json:"uid" deprecated:"true"`
|
||||
Identifier *string `json:"identifier"`
|
||||
State *enum.RuleState `json:"state"`
|
||||
Description *string `json:"description"`
|
||||
Pattern *protection.Pattern `json:"pattern"`
|
||||
Definition *json.RawMessage `json:"definition"`
|
||||
}
|
||||
|
||||
// sanitize validates and sanitizes the update rule input data.
|
||||
func (in *UpdateInput) sanitize() error {
|
||||
// TODO [CODE-1363]: remove after identifier migration.
|
||||
if in.Identifier == nil {
|
||||
in.Identifier = in.UID
|
||||
}
|
||||
|
||||
if in.Identifier != nil {
|
||||
if err := check.Identifier(*in.Identifier); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if in.State != nil {
|
||||
state, ok := in.State.Sanitize()
|
||||
if !ok {
|
||||
return usererror.BadRequest("rule state is invalid")
|
||||
}
|
||||
|
||||
in.State = &state
|
||||
}
|
||||
|
||||
if in.Pattern != nil {
|
||||
if err := in.Pattern.Validate(); err != nil {
|
||||
return usererror.BadRequestf("invalid pattern: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
if in.Definition != nil && len(*in.Definition) == 0 {
|
||||
return usererror.BadRequest("rule definition missing")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (in *UpdateInput) isEmpty() bool {
|
||||
return in.Identifier == nil && in.State == nil && in.Description == nil && in.Pattern == nil && in.Definition == nil
|
||||
}
|
||||
|
||||
// Update updates an existing protection rule for a repository.
|
||||
func (s *Service) Update(ctx context.Context,
|
||||
principal *types.Principal,
|
||||
parentType enum.RuleParent,
|
||||
parentID int64,
|
||||
scopeIdentifier string,
|
||||
path string,
|
||||
identifier string,
|
||||
in *UpdateInput,
|
||||
) (*types.Rule, error) {
|
||||
if err := in.sanitize(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rule, err := s.ruleStore.FindByIdentifier(ctx, parentType, parentID, identifier)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get a repository rule by its identifier: %w", err)
|
||||
}
|
||||
oldRule := rule.Clone()
|
||||
|
||||
if in.isEmpty() {
|
||||
userMap, userGroupMap, err := s.getRuleUserAndUserGroups(ctx, rule)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get rule users and user groups: %w", err)
|
||||
}
|
||||
|
||||
rule.Users = userMap
|
||||
rule.UserGroups = userGroupMap
|
||||
|
||||
return rule, nil
|
||||
}
|
||||
|
||||
if in.Identifier != nil {
|
||||
rule.Identifier = *in.Identifier
|
||||
}
|
||||
if in.State != nil {
|
||||
rule.State = *in.State
|
||||
}
|
||||
if in.Description != nil {
|
||||
rule.Description = *in.Description
|
||||
}
|
||||
if in.Pattern != nil {
|
||||
rule.Pattern = in.Pattern.JSON()
|
||||
}
|
||||
if in.Definition != nil {
|
||||
rule.Definition, err = s.protectionManager.SanitizeJSON(rule.Type, *in.Definition)
|
||||
if err != nil {
|
||||
return nil, usererror.BadRequestf("invalid rule definition: %s", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
userMap, userGroupMap, err := s.getRuleUserAndUserGroups(ctx, rule)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get rule users and user groups: %w", err)
|
||||
}
|
||||
|
||||
rule.Users = userMap
|
||||
rule.UserGroups = userGroupMap
|
||||
|
||||
if rule.IsEqual(&oldRule) {
|
||||
return rule, nil
|
||||
}
|
||||
|
||||
err = s.ruleStore.Update(ctx, rule)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to update repository-level protection rule: %w", err)
|
||||
}
|
||||
|
||||
nameKey := audit.RepoName
|
||||
if parentType == enum.RuleParentSpace {
|
||||
nameKey = audit.SpaceName
|
||||
}
|
||||
err = s.auditService.Log(ctx,
|
||||
*principal,
|
||||
audit.NewResource(audit.ResourceTypeBranchRule, rule.Identifier, nameKey, scopeIdentifier),
|
||||
audit.ActionUpdated,
|
||||
paths.Parent(path),
|
||||
audit.WithOldObject(oldRule),
|
||||
audit.WithNewObject(rule),
|
||||
)
|
||||
if err != nil {
|
||||
log.Ctx(ctx).Warn().Msgf("failed to insert audit log for update branch rule operation: %s", err)
|
||||
}
|
||||
|
||||
return rule, nil
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
// 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 rules
|
||||
|
||||
import (
|
||||
"github.com/harness/gitness/app/services/instrument"
|
||||
"github.com/harness/gitness/app/services/protection"
|
||||
"github.com/harness/gitness/app/services/usergroup"
|
||||
"github.com/harness/gitness/app/store"
|
||||
"github.com/harness/gitness/audit"
|
||||
"github.com/harness/gitness/store/database/dbtx"
|
||||
|
||||
"github.com/google/wire"
|
||||
)
|
||||
|
||||
// WireSet provides a wire set for this package.
|
||||
var WireSet = wire.NewSet(
|
||||
ProvideService,
|
||||
)
|
||||
|
||||
func ProvideService(
|
||||
tx dbtx.Transactor,
|
||||
ruleStore store.RuleStore,
|
||||
repoStore store.RepoStore,
|
||||
spaceStore store.SpaceStore,
|
||||
protectionManager *protection.Manager,
|
||||
auditService audit.Service,
|
||||
instrumentation instrument.Service,
|
||||
principalInfoCache store.PrincipalInfoCache,
|
||||
userGroupStore store.UserGroupStore,
|
||||
userGroupService usergroup.SearchService,
|
||||
) *Service {
|
||||
return NewService(
|
||||
tx,
|
||||
ruleStore,
|
||||
repoStore,
|
||||
spaceStore,
|
||||
protectionManager,
|
||||
auditService,
|
||||
instrumentation,
|
||||
principalInfoCache,
|
||||
userGroupStore,
|
||||
userGroupService,
|
||||
)
|
||||
}
|
|
@ -526,7 +526,12 @@ type (
|
|||
Find(ctx context.Context, id int64) (*types.Rule, error)
|
||||
|
||||
// FindByIdentifier finds a protection rule by parent ID and identifier.
|
||||
FindByIdentifier(ctx context.Context, spaceID, repoID *int64, identifier string) (*types.Rule, error)
|
||||
FindByIdentifier(
|
||||
ctx context.Context,
|
||||
parentType enum.RuleParent,
|
||||
parentID int64,
|
||||
identifier string,
|
||||
) (*types.Rule, error)
|
||||
|
||||
// Create inserts a new protection rule.
|
||||
Create(ctx context.Context, rule *types.Rule) error
|
||||
|
@ -537,14 +542,19 @@ type (
|
|||
// Delete removes a protection rule by its ID.
|
||||
Delete(ctx context.Context, id int64) error
|
||||
|
||||
// DeleteByIdentifier removes a protection rule by its identifier.
|
||||
DeleteByIdentifier(ctx context.Context, spaceID, repoID *int64, identifier string) error
|
||||
// Count returns count of protection rules of a repository or a space.
|
||||
Count(
|
||||
ctx context.Context,
|
||||
parents []types.RuleParentInfo,
|
||||
filter *types.RuleFilter,
|
||||
) (int64, error)
|
||||
|
||||
// Count returns count of protection rules matching the provided criteria.
|
||||
Count(ctx context.Context, spaceID, repoID *int64, filter *types.RuleFilter) (int64, error)
|
||||
|
||||
// List returns a list of protection rules of a repository or a space that matches the provided criteria.
|
||||
List(ctx context.Context, spaceID, repoID *int64, filter *types.RuleFilter) ([]types.Rule, error)
|
||||
// List returns a list of protection rules of a repository or a space.
|
||||
List(
|
||||
ctx context.Context,
|
||||
parents []types.RuleParentInfo,
|
||||
filter *types.RuleFilter,
|
||||
) ([]types.Rule, error)
|
||||
|
||||
// ListAllRepoRules returns a list of all protection rules that can be applied on a repository.
|
||||
ListAllRepoRules(ctx context.Context, repoID int64) ([]types.RuleInfoInternal, error)
|
||||
|
|
|
@ -114,15 +114,23 @@ func (s *RuleStore) Find(ctx context.Context, id int64) (*types.Rule, error) {
|
|||
|
||||
func (s *RuleStore) FindByIdentifier(
|
||||
ctx context.Context,
|
||||
spaceID *int64,
|
||||
repoID *int64,
|
||||
parentType enum.RuleParent,
|
||||
parentID int64,
|
||||
identifier string,
|
||||
) (*types.Rule, error) {
|
||||
stmt := database.Builder.
|
||||
Select(ruleColumns).
|
||||
From("rules").
|
||||
Where("LOWER(rule_uid) = ?", strings.ToLower(identifier))
|
||||
stmt = s.applyParentID(stmt, spaceID, repoID)
|
||||
|
||||
switch parentType {
|
||||
case enum.RuleParentRepo:
|
||||
stmt = stmt.Where("rule_repo_id = ?", parentID)
|
||||
case enum.RuleParentSpace:
|
||||
stmt = stmt.Where("rule_space_id = ?", parentID)
|
||||
default:
|
||||
return nil, fmt.Errorf("rule parent type '%s' is not supported", parentType)
|
||||
}
|
||||
|
||||
sql, args, err := stmt.ToSql()
|
||||
if err != nil {
|
||||
|
@ -252,40 +260,21 @@ func (s *RuleStore) Delete(ctx context.Context, id int64) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (s *RuleStore) DeleteByIdentifier(ctx context.Context, spaceID, repoID *int64, identifier string) error {
|
||||
stmt := database.Builder.
|
||||
Delete("rules").
|
||||
Where("LOWER(rule_uid) = ?", strings.ToLower(identifier))
|
||||
|
||||
if spaceID != nil {
|
||||
stmt = stmt.Where("rule_space_id = ?", *spaceID)
|
||||
}
|
||||
|
||||
if repoID != nil {
|
||||
stmt = stmt.Where("rule_repo_id = ?", *repoID)
|
||||
}
|
||||
|
||||
sql, args, err := stmt.ToSql()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to convert delete rule by identifier to sql: %w", err)
|
||||
}
|
||||
|
||||
db := dbtx.GetAccessor(ctx, s.db)
|
||||
|
||||
if _, err = db.ExecContext(ctx, sql, args...); err != nil {
|
||||
return database.ProcessSQLErrorf(ctx, err, "Failed executing delete rule by identifier query")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Count returns count of protection rules matching the provided criteria.
|
||||
func (s *RuleStore) Count(ctx context.Context, spaceID, repoID *int64, filter *types.RuleFilter) (int64, error) {
|
||||
func (s *RuleStore) Count(
|
||||
ctx context.Context,
|
||||
parents []types.RuleParentInfo,
|
||||
filter *types.RuleFilter,
|
||||
) (int64, error) {
|
||||
stmt := database.Builder.
|
||||
Select("count(*)").
|
||||
From("rules")
|
||||
|
||||
stmt = s.applyParentID(stmt, spaceID, repoID)
|
||||
err := selectRuleParents(parents, &stmt)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("failed to select rule parents: %w", err)
|
||||
}
|
||||
|
||||
stmt = s.applyFilter(stmt, filter)
|
||||
|
||||
sql, args, err := stmt.ToSql()
|
||||
|
@ -306,12 +295,20 @@ func (s *RuleStore) Count(ctx context.Context, spaceID, repoID *int64, filter *t
|
|||
}
|
||||
|
||||
// List returns a list of protection rules of a repository or a space.
|
||||
func (s *RuleStore) List(ctx context.Context, spaceID, repoID *int64, filter *types.RuleFilter) ([]types.Rule, error) {
|
||||
func (s *RuleStore) List(
|
||||
ctx context.Context,
|
||||
parents []types.RuleParentInfo,
|
||||
filter *types.RuleFilter,
|
||||
) ([]types.Rule, error) {
|
||||
stmt := database.Builder.
|
||||
Select(ruleColumns).
|
||||
From("rules")
|
||||
|
||||
stmt = s.applyParentID(stmt, spaceID, repoID)
|
||||
err := selectRuleParents(parents, &stmt)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to select rule parents: %w", err)
|
||||
}
|
||||
|
||||
stmt = s.applyFilter(stmt, filter)
|
||||
|
||||
stmt = stmt.Limit(database.Limit(filter.Size))
|
||||
|
@ -427,21 +424,6 @@ func (s *RuleStore) ListAllRepoRules(ctx context.Context, repoID int64) ([]types
|
|||
return s.mapToRuleInfos(result), nil
|
||||
}
|
||||
|
||||
func (*RuleStore) applyParentID(
|
||||
stmt squirrel.SelectBuilder,
|
||||
spaceID, repoID *int64,
|
||||
) squirrel.SelectBuilder {
|
||||
if spaceID != nil {
|
||||
stmt = stmt.Where("rule_space_id = ?", *spaceID)
|
||||
}
|
||||
|
||||
if repoID != nil {
|
||||
stmt = stmt.Where("rule_repo_id = ?", *repoID)
|
||||
}
|
||||
|
||||
return stmt
|
||||
}
|
||||
|
||||
func (*RuleStore) applyFilter(
|
||||
stmt squirrel.SelectBuilder,
|
||||
filter *types.RuleFilter,
|
||||
|
@ -544,3 +526,28 @@ func (s *RuleStore) mapToRuleInfos(
|
|||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func selectRuleParents(
|
||||
parents []types.RuleParentInfo,
|
||||
stmt *squirrel.SelectBuilder,
|
||||
) error {
|
||||
var parentSelector squirrel.Or
|
||||
for _, parent := range parents {
|
||||
switch parent.Type {
|
||||
case enum.RuleParentRepo:
|
||||
parentSelector = append(parentSelector, squirrel.Eq{
|
||||
"rule_repo_id": parent.ID,
|
||||
})
|
||||
case enum.RuleParentSpace:
|
||||
parentSelector = append(parentSelector, squirrel.Eq{
|
||||
"rule_space_id": parent.ID,
|
||||
})
|
||||
default:
|
||||
return fmt.Errorf("rule parent type '%s' is not supported", parent.Type)
|
||||
}
|
||||
}
|
||||
|
||||
*stmt = stmt.Where(parentSelector)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -352,9 +352,9 @@ func (s *WebhookStore) Count(
|
|||
Select("count(*)").
|
||||
From("webhooks")
|
||||
|
||||
err := selectParents(parents, &stmt)
|
||||
err := selectWebhookParents(parents, &stmt)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("failed to select parents: %w", err)
|
||||
return 0, fmt.Errorf("failed to select webhook parents: %w", err)
|
||||
}
|
||||
|
||||
stmt = applyWebhookFilter(opts, stmt)
|
||||
|
@ -384,9 +384,9 @@ func (s *WebhookStore) List(
|
|||
Select(webhookColumns).
|
||||
From("webhooks")
|
||||
|
||||
err := selectParents(parents, &stmt)
|
||||
err := selectWebhookParents(parents, &stmt)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to select parents: %w", err)
|
||||
return nil, fmt.Errorf("failed to select webhook parents: %w", err)
|
||||
}
|
||||
|
||||
stmt = applyWebhookFilter(opts, stmt)
|
||||
|
@ -559,7 +559,7 @@ func applyWebhookFilter(
|
|||
return stmt
|
||||
}
|
||||
|
||||
func selectParents(
|
||||
func selectWebhookParents(
|
||||
parents []types.WebhookParentInfo,
|
||||
stmt *squirrel.SelectBuilder,
|
||||
) error {
|
||||
|
|
|
@ -33,6 +33,7 @@ var (
|
|||
const (
|
||||
ResourceName = "resourceName"
|
||||
RepoName = "repoName"
|
||||
SpaceName = "spaceName"
|
||||
BypassedResourceType = "bypassedResourceType"
|
||||
BypassedResourceName = "bypassedResourceName"
|
||||
RepoPath = "repoPath"
|
||||
|
|
|
@ -104,6 +104,7 @@ import (
|
|||
"github.com/harness/gitness/app/services/publickey"
|
||||
pullreqservice "github.com/harness/gitness/app/services/pullreq"
|
||||
reposervice "github.com/harness/gitness/app/services/repo"
|
||||
"github.com/harness/gitness/app/services/rules"
|
||||
secretservice "github.com/harness/gitness/app/services/secret"
|
||||
"github.com/harness/gitness/app/services/settings"
|
||||
systemsvc "github.com/harness/gitness/app/services/system"
|
||||
|
@ -243,6 +244,7 @@ func initSystem(ctx context.Context, config *types.Config) (*cliserver.System, e
|
|||
gitspaceevent.WireSet,
|
||||
cliserver.ProvideKeywordSearchConfig,
|
||||
keywordsearch.WireSet,
|
||||
rules.WireSet,
|
||||
controllerkeywordsearch.WireSet,
|
||||
settings.WireSet,
|
||||
systemsvc.WireSet,
|
||||
|
|
|
@ -95,6 +95,7 @@ import (
|
|||
"github.com/harness/gitness/app/services/publickey"
|
||||
"github.com/harness/gitness/app/services/pullreq"
|
||||
repo2 "github.com/harness/gitness/app/services/repo"
|
||||
"github.com/harness/gitness/app/services/rules"
|
||||
secret3 "github.com/harness/gitness/app/services/secret"
|
||||
"github.com/harness/gitness/app/services/settings"
|
||||
system2 "github.com/harness/gitness/app/services/system"
|
||||
|
@ -251,7 +252,8 @@ func initSystem(ctx context.Context, config *types.Config) (*server.System, erro
|
|||
instrumentService := instrument.ProvideService()
|
||||
userGroupStore := database.ProvideUserGroupStore(db)
|
||||
searchService := usergroup.ProvideSearchService()
|
||||
repoController := repo.ProvideController(config, transactor, provider, authorizer, repoStore, spaceStore, pipelineStore, principalStore, executionStore, ruleStore, checkStore, pullReqStore, settingsService, principalInfoCache, protectionManager, gitInterface, repository, codeownersService, reporter, indexer, resourceLimiter, lockerLocker, auditService, mutexManager, repoIdentifier, repoCheck, publicaccessService, labelService, instrumentService, userGroupStore, searchService)
|
||||
rulesService := rules.ProvideService(transactor, ruleStore, repoStore, spaceStore, protectionManager, auditService, instrumentService, principalInfoCache, userGroupStore, searchService)
|
||||
repoController := repo.ProvideController(config, transactor, provider, authorizer, repoStore, spaceStore, pipelineStore, principalStore, executionStore, ruleStore, checkStore, pullReqStore, settingsService, principalInfoCache, protectionManager, gitInterface, repository, codeownersService, reporter, indexer, resourceLimiter, lockerLocker, auditService, mutexManager, repoIdentifier, repoCheck, publicaccessService, labelService, instrumentService, userGroupStore, searchService, rulesService)
|
||||
reposettingsController := reposettings.ProvideController(authorizer, repoStore, settingsService, auditService)
|
||||
stageStore := database.ProvideStageStore(db)
|
||||
schedulerScheduler, err := scheduler.ProvideScheduler(stageStore, mutexManager)
|
||||
|
@ -324,7 +326,7 @@ func initSystem(ctx context.Context, config *types.Config) (*server.System, erro
|
|||
resolverFactory := secret.ProvideResolverFactory(passwordResolver)
|
||||
orchestratorOrchestrator := orchestrator.ProvideOrchestrator(scmSCM, infraProviderResourceStore, infraProvisioner, containerOrchestrator, eventsReporter, orchestratorConfig, vsCode, vsCodeWeb, resolverFactory)
|
||||
gitspaceService := gitspace.ProvideGitspace(transactor, gitspaceConfigStore, gitspaceInstanceStore, eventsReporter, gitspaceEventStore, spaceStore, infraproviderService, orchestratorOrchestrator, scmSCM, config)
|
||||
spaceController := space.ProvideController(config, transactor, provider, streamer, spaceIdentifier, authorizer, spacePathStore, pipelineStore, secretStore, connectorStore, templateStore, spaceStore, repoStore, principalStore, repoController, membershipStore, listService, repository, exporterRepository, resourceLimiter, publicaccessService, auditService, gitspaceService, labelService, instrumentService, executionStore)
|
||||
spaceController := space.ProvideController(config, transactor, provider, streamer, spaceIdentifier, authorizer, spacePathStore, pipelineStore, secretStore, connectorStore, templateStore, spaceStore, repoStore, principalStore, repoController, membershipStore, listService, repository, exporterRepository, resourceLimiter, publicaccessService, auditService, gitspaceService, labelService, instrumentService, executionStore, rulesService)
|
||||
reporter3, err := events5.ProvideReporter(eventsSystem)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
|
@ -83,3 +83,21 @@ func ParseRuleSortAttr(s string) RuleSort {
|
|||
|
||||
return RuleSortIdentifier
|
||||
}
|
||||
|
||||
// RuleParent defines different types of parents of a rule.
|
||||
type RuleParent string
|
||||
|
||||
func (RuleParent) Enum() []interface{} { return toInterfaceSlice(RuleParents) }
|
||||
|
||||
const (
|
||||
// RuleParentRepo describes a repo as Rule owner.
|
||||
RuleParentRepo RuleParent = "repo"
|
||||
|
||||
// RuleParentSpace describes a space as Rule owner.
|
||||
RuleParentSpace RuleParent = "space"
|
||||
)
|
||||
|
||||
var RuleParents = sortEnum([]RuleParent{
|
||||
RuleParentRepo,
|
||||
RuleParentSpace,
|
||||
})
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
package types
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
|
@ -124,6 +125,12 @@ func (r Rule) Clone() Rule {
|
|||
return r
|
||||
}
|
||||
|
||||
func (r *Rule) IsEqual(rule *Rule) bool {
|
||||
return r.Identifier == rule.Identifier && r.State == rule.State &&
|
||||
r.Description == rule.Description && bytes.Equal(r.Pattern, rule.Pattern) &&
|
||||
bytes.Equal(r.Definition, rule.Definition)
|
||||
}
|
||||
|
||||
type RuleType string
|
||||
|
||||
type RuleFilter struct {
|
||||
|
@ -211,3 +218,8 @@ type DryRunRulesOutput struct {
|
|||
DryRunRules bool `json:"dry_run_rules,omitempty"`
|
||||
RuleViolations []RuleViolations `json:"rule_violations,omitempty"`
|
||||
}
|
||||
|
||||
type RuleParentInfo struct {
|
||||
Type enum.RuleParent
|
||||
ID int64
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue