mirror of https://github.com/harness/drone.git
240 lines
5.7 KiB
Go
240 lines
5.7 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 audit
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
|
|
"github.com/harness/gitness/types"
|
|
)
|
|
|
|
var (
|
|
ErrActionUndefined = errors.New("undefined action")
|
|
ErrResourceTypeUndefined = errors.New("undefined resource type")
|
|
ErrResourceIdentifierIsRequired = errors.New("resource identifier is required")
|
|
ErrUserIsRequired = errors.New("user is required")
|
|
ErrSpacePathIsRequired = errors.New("space path is required")
|
|
)
|
|
|
|
const (
|
|
ResourceName = "resourceName"
|
|
RepoName = "repoName"
|
|
SpaceName = "spaceName"
|
|
BypassedResourceType = "bypassedResourceType"
|
|
BypassedResourceName = "bypassedResourceName"
|
|
RepoPath = "repoPath"
|
|
BypassedResourceTypePullRequest = "pull_request"
|
|
BypassedResourceTypeBranch = "branch"
|
|
BypassedResourceTypeCommit = "commit"
|
|
BypassAction = "bypass_action"
|
|
BypassActionDeleted = "deleted"
|
|
BypassActionCreated = "created"
|
|
BypassActionCommitted = "committed"
|
|
BypassActionMerged = "merged"
|
|
BypassSHALabelFormat = "%s @%s"
|
|
BypassPullReqLabelFormat = "%s #%s"
|
|
)
|
|
|
|
type Action string
|
|
|
|
const (
|
|
ActionCreated Action = "created"
|
|
ActionUpdated Action = "updated" // update default branch, switching default branch, updating description
|
|
ActionDeleted Action = "deleted"
|
|
ActionBypassed Action = "bypassed"
|
|
)
|
|
|
|
func (a Action) Validate() error {
|
|
switch a {
|
|
case ActionCreated, ActionUpdated, ActionDeleted, ActionBypassed:
|
|
return nil
|
|
default:
|
|
return ErrActionUndefined
|
|
}
|
|
}
|
|
|
|
type ResourceType string
|
|
|
|
const (
|
|
ResourceTypeRepository ResourceType = "repository"
|
|
ResourceTypeBranchRule ResourceType = "branch_rule"
|
|
ResourceTypeBranch ResourceType = "branch"
|
|
ResourceTypePullRequest ResourceType = "pull_request"
|
|
ResourceTypeRepositorySettings ResourceType = "repository_settings"
|
|
ResourceTypeRegistry ResourceType = "registry"
|
|
ResourceTypeRegistryUpstreamProxy ResourceType = "registry_upstream_proxy"
|
|
ResourceTypeRegistryArtifact ResourceType = "registry_artifact"
|
|
)
|
|
|
|
func (a ResourceType) Validate() error {
|
|
switch a {
|
|
case ResourceTypeRepository,
|
|
ResourceTypeBranchRule,
|
|
ResourceTypeBranch,
|
|
ResourceTypePullRequest,
|
|
ResourceTypeRepositorySettings,
|
|
ResourceTypeRegistry,
|
|
ResourceTypeRegistryUpstreamProxy,
|
|
ResourceTypeRegistryArtifact:
|
|
return nil
|
|
|
|
default:
|
|
return ErrResourceTypeUndefined
|
|
}
|
|
}
|
|
|
|
type Resource struct {
|
|
Type ResourceType
|
|
Identifier string
|
|
Data map[string]string
|
|
}
|
|
|
|
func NewResource(rtype ResourceType, identifier string, keyValues ...string) Resource {
|
|
r := Resource{
|
|
Type: rtype,
|
|
Identifier: identifier,
|
|
Data: make(map[string]string, len(keyValues)),
|
|
}
|
|
for i := 0; i < len(keyValues); i += 2 {
|
|
k, v := keyValues[i], keyValues[i+1]
|
|
r.Data[k] = v
|
|
}
|
|
return r
|
|
}
|
|
|
|
func (r Resource) Validate() error {
|
|
if err := r.Type.Validate(); err != nil {
|
|
return err
|
|
}
|
|
if r.Identifier == "" {
|
|
return ErrResourceIdentifierIsRequired
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (r Resource) DataAsSlice() []string {
|
|
slice := make([]string, 0, len(r.Data)*2)
|
|
for k, v := range r.Data {
|
|
slice = append(slice, k, v)
|
|
}
|
|
return slice
|
|
}
|
|
|
|
type DiffObject struct {
|
|
OldObject any
|
|
NewObject any
|
|
}
|
|
|
|
type Event struct {
|
|
ID string
|
|
Timestamp int64
|
|
Action Action // example: ActionCreated
|
|
User types.Principal // example: Admin
|
|
SpacePath string // example: /root/projects
|
|
Resource Resource
|
|
DiffObject DiffObject
|
|
ClientIP string
|
|
RequestMethod string
|
|
Data map[string]string // internal data like correlationID/requestID
|
|
}
|
|
|
|
func (e *Event) Validate() error {
|
|
if err := e.Action.Validate(); err != nil {
|
|
return fmt.Errorf("invalid action: %w", err)
|
|
}
|
|
if e.User.UID == "" {
|
|
return ErrUserIsRequired
|
|
}
|
|
if e.SpacePath == "" {
|
|
return ErrSpacePathIsRequired
|
|
}
|
|
if err := e.Resource.Validate(); err != nil {
|
|
return fmt.Errorf("invalid resource: %w", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
type Noop struct{}
|
|
|
|
func New() *Noop {
|
|
return &Noop{}
|
|
}
|
|
|
|
func (s *Noop) Log(
|
|
context.Context,
|
|
types.Principal,
|
|
Resource,
|
|
Action,
|
|
string,
|
|
...Option,
|
|
) error {
|
|
// No implementation
|
|
return nil
|
|
}
|
|
|
|
type FuncOption func(e *Event)
|
|
|
|
func (f FuncOption) Apply(event *Event) {
|
|
f(event)
|
|
}
|
|
|
|
type Option interface {
|
|
Apply(e *Event)
|
|
}
|
|
|
|
func WithID(value string) FuncOption {
|
|
return func(e *Event) {
|
|
e.ID = value
|
|
}
|
|
}
|
|
|
|
func WithNewObject(value any) FuncOption {
|
|
return func(e *Event) {
|
|
e.DiffObject.NewObject = value
|
|
}
|
|
}
|
|
|
|
func WithOldObject(value any) FuncOption {
|
|
return func(e *Event) {
|
|
e.DiffObject.OldObject = value
|
|
}
|
|
}
|
|
|
|
func WithClientIP(value string) FuncOption {
|
|
return func(e *Event) {
|
|
e.ClientIP = value
|
|
}
|
|
}
|
|
|
|
func WithRequestMethod(value string) FuncOption {
|
|
return func(e *Event) {
|
|
e.RequestMethod = value
|
|
}
|
|
}
|
|
|
|
func WithData(keyValues ...string) FuncOption {
|
|
return func(e *Event) {
|
|
if e.Data == nil {
|
|
e.Data = make(map[string]string)
|
|
}
|
|
for i := 0; i < len(keyValues); i += 2 {
|
|
k, v := keyValues[i], keyValues[i+1]
|
|
e.Data[k] = v
|
|
}
|
|
}
|
|
}
|