2024-04-19 01:36:03 +00:00

146 lines
3.3 KiB
Go

// 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 protection
import (
"bytes"
"context"
"encoding/json"
"errors"
"fmt"
"github.com/harness/gitness/app/store"
"github.com/harness/gitness/types"
)
type (
Sanitizer interface {
// Sanitize validates if the definition is valid and automatically corrects minor issues.
Sanitize() error
}
Protection interface {
MergeVerifier
RefChangeVerifier
UserIDs() ([]int64, error)
}
Definition interface {
Sanitizer
Protection
}
// DefinitionGenerator is the function that creates blank rules.
DefinitionGenerator func() Definition
// Manager is used to enforce protection rules.
Manager struct {
defGenMap map[types.RuleType]DefinitionGenerator
ruleStore store.RuleStore
}
)
var (
ErrUnrecognizedType = errors.New("unrecognized protection type")
ErrAlreadyRegistered = errors.New("protection type already registered")
ErrPatternEmpty = errors.New("name pattern can't be empty")
ErrInvalidGlobstarPattern = errors.New("invalid globstar pattern")
)
func IsCritical(violations []types.RuleViolations) bool {
for i := range violations {
if violations[i].IsCritical() {
return true
}
}
return false
}
func IsBypassed(violations []types.RuleViolations) bool {
for i := range violations {
if violations[i].IsBypassed() {
return true
}
}
return false
}
// NewManager creates new protection Manager.
func NewManager(ruleStore store.RuleStore) *Manager {
return &Manager{
defGenMap: make(map[types.RuleType]DefinitionGenerator),
ruleStore: ruleStore,
}
}
// Register registers new types.RuleType.
func (m *Manager) Register(ruleType types.RuleType, gen DefinitionGenerator) error {
_, ok := m.defGenMap[ruleType]
if ok {
return ErrAlreadyRegistered
}
m.defGenMap[ruleType] = gen
return nil
}
func (m *Manager) FromJSON(ruleType types.RuleType, message json.RawMessage, strict bool) (Protection, error) {
gen := m.defGenMap[ruleType]
if gen == nil {
return nil, ErrUnrecognizedType
}
decoder := json.NewDecoder(bytes.NewReader(message))
if strict {
decoder.DisallowUnknownFields()
}
r := gen()
if err := decoder.Decode(&r); err != nil {
return nil, err
}
if err := r.Sanitize(); err != nil {
return nil, err
}
return r, nil
}
func (m *Manager) SanitizeJSON(ruleType types.RuleType, message json.RawMessage) (json.RawMessage, error) {
r, err := m.FromJSON(ruleType, message, true)
if err != nil {
return nil, err
}
return ToJSON(r)
}
func (m *Manager) ForRepository(ctx context.Context, repoID int64) (Protection, error) {
ruleInfos, err := m.ruleStore.ListAllRepoRules(ctx, repoID)
if err != nil {
return nil, fmt.Errorf("failed to list rules for repository: %w", err)
}
return ruleSet{
rules: ruleInfos,
manager: m,
}, nil
}