mirror of https://github.com/harness/drone.git
[code-1524] audit trails package (#1176)
parent
fea9e46dc8
commit
227aac90b5
|
@ -34,6 +34,7 @@ import (
|
|||
"github.com/harness/gitness/app/services/settings"
|
||||
"github.com/harness/gitness/app/store"
|
||||
"github.com/harness/gitness/app/url"
|
||||
"github.com/harness/gitness/audit"
|
||||
"github.com/harness/gitness/git"
|
||||
"github.com/harness/gitness/lock"
|
||||
"github.com/harness/gitness/store/database/dbtx"
|
||||
|
@ -68,6 +69,7 @@ type Controller struct {
|
|||
indexer keywordsearch.Indexer
|
||||
resourceLimiter limiter.ResourceLimiter
|
||||
locker *locker.Locker
|
||||
auditService audit.Service
|
||||
mtxManager lock.MutexManager
|
||||
identifierCheck check.RepoIdentifier
|
||||
repoCheck Check
|
||||
|
@ -93,6 +95,7 @@ func NewController(
|
|||
indexer keywordsearch.Indexer,
|
||||
limiter limiter.ResourceLimiter,
|
||||
locker *locker.Locker,
|
||||
auditService audit.Service,
|
||||
mtxManager lock.MutexManager,
|
||||
identifierCheck check.RepoIdentifier,
|
||||
repoCheck Check,
|
||||
|
@ -118,6 +121,7 @@ func NewController(
|
|||
indexer: indexer,
|
||||
resourceLimiter: limiter,
|
||||
locker: locker,
|
||||
auditService: auditService,
|
||||
mtxManager: mtxManager,
|
||||
identifierCheck: identifierCheck,
|
||||
repoCheck: repoCheck,
|
||||
|
|
|
@ -28,6 +28,8 @@ import (
|
|||
"github.com/harness/gitness/app/auth"
|
||||
"github.com/harness/gitness/app/bootstrap"
|
||||
"github.com/harness/gitness/app/githook"
|
||||
"github.com/harness/gitness/app/paths"
|
||||
"github.com/harness/gitness/audit"
|
||||
"github.com/harness/gitness/git"
|
||||
"github.com/harness/gitness/resources"
|
||||
"github.com/harness/gitness/types"
|
||||
|
@ -121,6 +123,17 @@ func (c *Controller) Create(ctx context.Context, session *auth.Session, in *Crea
|
|||
return nil, err
|
||||
}
|
||||
|
||||
err = c.auditService.Log(ctx,
|
||||
session.Principal,
|
||||
audit.NewResource(audit.ResourceTypeRepository, repo.Identifier),
|
||||
audit.ActionCreated,
|
||||
paths.Space(repo.Path),
|
||||
audit.WithNewObject(repo),
|
||||
)
|
||||
if err != nil {
|
||||
log.Ctx(ctx).Warn().Msgf("failed to insert audit log for create repository operation: %s", err)
|
||||
}
|
||||
|
||||
// backfil GitURL
|
||||
repo.GitURL = c.urlProvider.GenerateGITCloneURL(repo.Path)
|
||||
|
||||
|
|
|
@ -23,10 +23,14 @@ import (
|
|||
"github.com/harness/gitness/app/auth"
|
||||
"github.com/harness/gitness/app/bootstrap"
|
||||
repoevents "github.com/harness/gitness/app/events/repo"
|
||||
"github.com/harness/gitness/app/paths"
|
||||
"github.com/harness/gitness/audit"
|
||||
"github.com/harness/gitness/contextutil"
|
||||
"github.com/harness/gitness/git"
|
||||
"github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
type UpdateDefaultBranchInput struct {
|
||||
|
@ -44,7 +48,7 @@ func (c *Controller) UpdateDefaultBranch(
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
repoClone := repo.Clone()
|
||||
// the max time we give an update default branch to succeed
|
||||
const timeout = 2 * time.Minute
|
||||
|
||||
|
@ -91,6 +95,18 @@ func (c *Controller) UpdateDefaultBranch(
|
|||
return nil, fmt.Errorf("failed to update the repo default branch on db:%w", err)
|
||||
}
|
||||
|
||||
err = c.auditService.Log(ctx,
|
||||
session.Principal,
|
||||
audit.NewResource(audit.ResourceTypeRepository, repo.Identifier),
|
||||
audit.ActionUpdated,
|
||||
paths.Space(repo.Path),
|
||||
audit.WithOldObject(repoClone),
|
||||
audit.WithNewObject(repo),
|
||||
)
|
||||
if err != nil {
|
||||
log.Ctx(ctx).Warn().Msgf("failed to insert audit log for update default branch operation: %s", err)
|
||||
}
|
||||
|
||||
c.eventReporter.DefaultBranchUpdated(ctx, &repoevents.DefaultBranchUpdatedPayload{
|
||||
RepoID: repo.ID,
|
||||
PrincipalID: bootstrap.NewSystemServiceSession().Principal.ID,
|
||||
|
|
|
@ -22,10 +22,14 @@ import (
|
|||
|
||||
"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/types"
|
||||
"github.com/harness/gitness/types/check"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
type RuleCreateInput struct {
|
||||
|
@ -112,6 +116,17 @@ func (c *Controller) RuleCreate(ctx context.Context,
|
|||
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.ActionCreated,
|
||||
paths.Space(repo.Path),
|
||||
audit.WithNewObject(r),
|
||||
)
|
||||
if err != nil {
|
||||
log.Ctx(ctx).Warn().Msgf("failed to insert audit log for create branch rule operation: %s", err)
|
||||
}
|
||||
|
||||
r.Users, err = c.getRuleUsers(ctx, r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
|
@ -19,7 +19,11 @@ 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.
|
||||
|
@ -43,5 +47,16 @@ func (c *Controller) RuleDelete(ctx context.Context,
|
|||
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.ActionDeleted,
|
||||
paths.Space(repo.Path),
|
||||
audit.WithOldObject(r),
|
||||
)
|
||||
if err != nil {
|
||||
log.Ctx(ctx).Warn().Msgf("failed to insert audit log for delete branch rule operation: %s", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -21,10 +21,14 @@ import (
|
|||
|
||||
"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/types"
|
||||
"github.com/harness/gitness/types/check"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
type RuleUpdateInput struct {
|
||||
|
@ -96,7 +100,7 @@ func (c *Controller) RuleUpdate(ctx context.Context,
|
|||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get a repository rule by its identifier: %w", err)
|
||||
}
|
||||
|
||||
oldRule := r.Clone()
|
||||
if in.isEmpty() {
|
||||
r.Users, err = c.getRuleUsers(ctx, r)
|
||||
if err != nil {
|
||||
|
@ -134,5 +138,17 @@ func (c *Controller) RuleUpdate(ctx context.Context,
|
|||
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.ActionUpdated,
|
||||
paths.Space(repo.Path),
|
||||
audit.WithOldObject(oldRule),
|
||||
audit.WithNewObject(r),
|
||||
)
|
||||
if err != nil {
|
||||
log.Ctx(ctx).Warn().Msgf("failed to insert audit log for update branch rule operation: %s", err)
|
||||
}
|
||||
|
||||
return r, nil
|
||||
}
|
||||
|
|
|
@ -22,6 +22,8 @@ import (
|
|||
apiauth "github.com/harness/gitness/app/api/auth"
|
||||
"github.com/harness/gitness/app/api/usererror"
|
||||
"github.com/harness/gitness/app/auth"
|
||||
"github.com/harness/gitness/app/paths"
|
||||
"github.com/harness/gitness/audit"
|
||||
"github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
|
||||
|
@ -62,6 +64,17 @@ func (c *Controller) SoftDelete(
|
|||
return nil, fmt.Errorf("failed to soft delete repo: %w", err)
|
||||
}
|
||||
|
||||
err = c.auditService.Log(ctx,
|
||||
session.Principal,
|
||||
audit.NewResource(audit.ResourceTypeRepository, repo.Identifier),
|
||||
audit.ActionDeleted,
|
||||
paths.Space(repo.Path),
|
||||
audit.WithOldObject(repo),
|
||||
)
|
||||
if err != nil {
|
||||
log.Ctx(ctx).Warn().Msgf("failed to insert audit log for delete repository operation: %s", err)
|
||||
}
|
||||
|
||||
return &SoftDeleteResponse{DeletedAt: now}, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -20,9 +20,13 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/harness/gitness/app/auth"
|
||||
"github.com/harness/gitness/app/paths"
|
||||
"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"
|
||||
)
|
||||
|
||||
// UpdateInput is used for updating a repo.
|
||||
|
@ -47,6 +51,8 @@ func (c *Controller) Update(ctx context.Context,
|
|||
return nil, err
|
||||
}
|
||||
|
||||
repoClone := repo.Clone()
|
||||
|
||||
if !in.hasChanges(repo) {
|
||||
return repo, nil
|
||||
}
|
||||
|
@ -70,6 +76,18 @@ func (c *Controller) Update(ctx context.Context,
|
|||
return nil, err
|
||||
}
|
||||
|
||||
err = c.auditService.Log(ctx,
|
||||
session.Principal,
|
||||
audit.NewResource(audit.ResourceTypeRepository, repo.Identifier),
|
||||
audit.ActionUpdated,
|
||||
paths.Space(repo.Path),
|
||||
audit.WithOldObject(repoClone),
|
||||
audit.WithNewObject(repo),
|
||||
)
|
||||
if err != nil {
|
||||
log.Ctx(ctx).Warn().Msgf("failed to insert audit log for update repository operation: %s", err)
|
||||
}
|
||||
|
||||
// backfill repo url
|
||||
repo.GitURL = c.urlProvider.GenerateGITCloneURL(repo.Path)
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@ import (
|
|||
"github.com/harness/gitness/app/services/settings"
|
||||
"github.com/harness/gitness/app/store"
|
||||
"github.com/harness/gitness/app/url"
|
||||
"github.com/harness/gitness/audit"
|
||||
"github.com/harness/gitness/git"
|
||||
"github.com/harness/gitness/lock"
|
||||
"github.com/harness/gitness/store/database/dbtx"
|
||||
|
@ -60,6 +61,7 @@ func ProvideController(
|
|||
indexer keywordsearch.Indexer,
|
||||
limiter limiter.ResourceLimiter,
|
||||
locker *locker.Locker,
|
||||
auditService audit.Service,
|
||||
mtxManager lock.MutexManager,
|
||||
identifierCheck check.RepoIdentifier,
|
||||
repoChecks Check,
|
||||
|
@ -68,7 +70,7 @@ func ProvideController(
|
|||
authorizer, repoStore,
|
||||
spaceStore, pipelineStore,
|
||||
principalStore, ruleStore, settings, principalInfoCache, protectionManager, rpcClient, importer,
|
||||
codeOwners, reporeporter, indexer, limiter, locker, mtxManager, identifierCheck, repoChecks)
|
||||
codeOwners, reporeporter, indexer, limiter, locker, auditService, mtxManager, identifierCheck, repoChecks)
|
||||
}
|
||||
|
||||
func ProvideRepoCheck() Check {
|
||||
|
|
|
@ -97,3 +97,8 @@ func IsAncesterOf(path string, other string) bool {
|
|||
path+types.PathSeparator,
|
||||
)
|
||||
}
|
||||
|
||||
func Space(repoPath string) string {
|
||||
spacePath, _, _ := DisectLeaf(repoPath)
|
||||
return spacePath
|
||||
}
|
||||
|
|
|
@ -72,6 +72,7 @@ import (
|
|||
"github.com/harness/gitness/app/api/request"
|
||||
"github.com/harness/gitness/app/auth/authn"
|
||||
"github.com/harness/gitness/app/githook"
|
||||
"github.com/harness/gitness/audit"
|
||||
"github.com/harness/gitness/git"
|
||||
"github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
|
@ -141,6 +142,8 @@ func NewAPIHandler(
|
|||
// for now always attempt auth - enforced per operation.
|
||||
r.Use(middlewareauthn.Attempt(authenticator))
|
||||
|
||||
r.Use(audit.Middleware())
|
||||
|
||||
r.Route("/v1", func(r chi.Router) {
|
||||
setupRoutesV1(r, appCtx, config, repoCtrl, repoSettingsCtrl, executionCtrl, triggerCtrl, logCtrl, pipelineCtrl,
|
||||
connectorCtrl, templateCtrl, pluginCtrl, secretCtrl, spaceCtrl, pullreqCtrl,
|
||||
|
|
|
@ -0,0 +1,175 @@
|
|||
// 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"
|
||||
|
||||
"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")
|
||||
)
|
||||
|
||||
type Action string
|
||||
|
||||
const (
|
||||
ActionCreated Action = "created"
|
||||
ActionUpdated Action = "updated" // update default branch, switching default branch, updating description
|
||||
ActionDeleted Action = "deleted"
|
||||
)
|
||||
|
||||
func (a Action) Validate() error {
|
||||
switch a {
|
||||
case ActionCreated, ActionUpdated, ActionDeleted:
|
||||
return nil
|
||||
default:
|
||||
return ErrActionUndefined
|
||||
}
|
||||
}
|
||||
|
||||
type ResourceType string
|
||||
|
||||
const (
|
||||
ResourceTypeRepository ResourceType = "repository"
|
||||
ResourceTypeBranchRule ResourceType = "branch_rule"
|
||||
)
|
||||
|
||||
func (a ResourceType) Validate() error {
|
||||
switch a {
|
||||
case ResourceTypeRepository, ResourceTypeBranchRule:
|
||||
return nil
|
||||
default:
|
||||
return ErrResourceTypeUndefined
|
||||
}
|
||||
}
|
||||
|
||||
type Resource struct {
|
||||
Type ResourceType
|
||||
Identifier string
|
||||
}
|
||||
|
||||
func NewResource(rtype ResourceType, identifier string) Resource {
|
||||
return Resource{
|
||||
Type: rtype,
|
||||
Identifier: identifier,
|
||||
}
|
||||
}
|
||||
|
||||
func (r Resource) Validate() error {
|
||||
if err := r.Type.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
if r.Identifier == "" {
|
||||
return ErrResourceIdentifierIsRequired
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
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
|
||||
Data map[string]string // internal data like correlationID/requestID
|
||||
}
|
||||
|
||||
func (e *Event) Validate() error {
|
||||
if err := e.Action.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
if e.User.UID == "" {
|
||||
return ErrUserIsRequired
|
||||
}
|
||||
if e.SpacePath == "" {
|
||||
return ErrSpacePathIsRequired
|
||||
}
|
||||
if err := e.Resource.Validate(); err != nil {
|
||||
return 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 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
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
// 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"
|
||||
|
||||
type key int
|
||||
|
||||
const (
|
||||
realIPKey key = iota
|
||||
requestID
|
||||
requestMethod
|
||||
)
|
||||
|
||||
// GetRealIP returns IP address from context.
|
||||
func GetRealIP(ctx context.Context) string {
|
||||
ip, ok := ctx.Value(realIPKey).(string)
|
||||
if !ok {
|
||||
return ""
|
||||
}
|
||||
|
||||
return ip
|
||||
}
|
||||
|
||||
// GetRequestID returns requestID from context.
|
||||
func GetRequestID(ctx context.Context) string {
|
||||
id, ok := ctx.Value(requestID).(string)
|
||||
if !ok {
|
||||
return ""
|
||||
}
|
||||
|
||||
return id
|
||||
}
|
||||
|
||||
// GetRequestMethod returns http method from context.
|
||||
func GetRequestMethod(ctx context.Context) string {
|
||||
method, ok := ctx.Value(requestMethod).(string)
|
||||
if !ok {
|
||||
return ""
|
||||
}
|
||||
|
||||
return method
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
// 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"
|
||||
|
||||
"github.com/harness/gitness/types"
|
||||
)
|
||||
|
||||
type Service interface {
|
||||
Log(
|
||||
ctx context.Context,
|
||||
user types.Principal,
|
||||
resource Resource,
|
||||
action Action,
|
||||
spacePath string,
|
||||
options ...Option,
|
||||
) error
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
// 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"
|
||||
"net"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var (
|
||||
trueClientIP = http.CanonicalHeaderKey("True-Client-IP")
|
||||
xForwardedFor = http.CanonicalHeaderKey("X-Forwarded-For")
|
||||
xRealIP = http.CanonicalHeaderKey("X-Real-IP")
|
||||
)
|
||||
|
||||
// Middleware process request headers to fill internal info data.
|
||||
func Middleware() func(next http.Handler) http.Handler {
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
if rip := realIP(r); rip != "" {
|
||||
ctx = context.WithValue(ctx, realIPKey, rip)
|
||||
}
|
||||
|
||||
ctx = context.WithValue(ctx, requestMethod, r.Method)
|
||||
ctx = context.WithValue(ctx, requestID, w.Header().Get("X-Request-Id"))
|
||||
|
||||
r = r.WithContext(ctx)
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func realIP(r *http.Request) string {
|
||||
var ip string
|
||||
|
||||
if tcip := r.Header.Get(trueClientIP); tcip != "" {
|
||||
ip = tcip
|
||||
} else if xrip := r.Header.Get(xRealIP); xrip != "" {
|
||||
ip = xrip
|
||||
} else if xff := r.Header.Get(xForwardedFor); xff != "" {
|
||||
i := strings.Index(xff, ",")
|
||||
if i == -1 {
|
||||
i = len(xff)
|
||||
}
|
||||
ip = xff[:i]
|
||||
} else {
|
||||
ip = strings.Split(r.RemoteAddr, ":")[0]
|
||||
}
|
||||
if ip == "" || net.ParseIP(ip) == nil {
|
||||
return ""
|
||||
}
|
||||
return ip
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
// 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 "github.com/google/wire"
|
||||
|
||||
var WireSet = wire.NewSet(
|
||||
ProvideAuditService,
|
||||
)
|
||||
|
||||
func ProvideAuditService() Service {
|
||||
return New()
|
||||
}
|
|
@ -75,6 +75,7 @@ import (
|
|||
"github.com/harness/gitness/app/store/database"
|
||||
"github.com/harness/gitness/app/store/logs"
|
||||
"github.com/harness/gitness/app/url"
|
||||
"github.com/harness/gitness/audit"
|
||||
"github.com/harness/gitness/blob"
|
||||
cliserver "github.com/harness/gitness/cli/operations/server"
|
||||
"github.com/harness/gitness/encrypt"
|
||||
|
@ -189,6 +190,7 @@ func initSystem(ctx context.Context, config *types.Config) (*cliserver.System, e
|
|||
usergroup.WireSet,
|
||||
openapi.WireSet,
|
||||
repo.ProvideRepoCheck,
|
||||
audit.WireSet,
|
||||
)
|
||||
return &cliserver.System{}, nil
|
||||
}
|
||||
|
|
|
@ -74,6 +74,7 @@ import (
|
|||
"github.com/harness/gitness/app/store/database"
|
||||
"github.com/harness/gitness/app/store/logs"
|
||||
"github.com/harness/gitness/app/url"
|
||||
"github.com/harness/gitness/audit"
|
||||
"github.com/harness/gitness/blob"
|
||||
"github.com/harness/gitness/cli/operations/server"
|
||||
"github.com/harness/gitness/encrypt"
|
||||
|
@ -193,9 +194,10 @@ func initSystem(ctx context.Context, config *types.Config) (*server.System, erro
|
|||
return nil, err
|
||||
}
|
||||
lockerLocker := locker.ProvideLocker(mutexManager)
|
||||
auditService := audit.ProvideAuditService()
|
||||
repoIdentifier := check.ProvideRepoIdentifierCheck()
|
||||
repoCheck := repo.ProvideRepoCheck()
|
||||
repoController := repo.ProvideController(config, transactor, provider, authorizer, repoStore, spaceStore, pipelineStore, principalStore, ruleStore, settingsService, principalInfoCache, protectionManager, gitInterface, repository, codeownersService, reporter, indexer, resourceLimiter, lockerLocker, mutexManager, repoIdentifier, repoCheck)
|
||||
repoController := repo.ProvideController(config, transactor, provider, authorizer, repoStore, spaceStore, pipelineStore, principalStore, ruleStore, settingsService, principalInfoCache, protectionManager, gitInterface, repository, codeownersService, reporter, indexer, resourceLimiter, lockerLocker, auditService, mutexManager, repoIdentifier, repoCheck)
|
||||
reposettingsController := reposettings.ProvideController(authorizer, repoStore, settingsService)
|
||||
executionStore := database.ProvideExecutionStore(db)
|
||||
checkStore := database.ProvideCheckStore(db, principalInfoCache)
|
||||
|
|
2
go.mod
2
go.mod
|
@ -176,5 +176,5 @@ require (
|
|||
golang.org/x/tools v0.13.0 // indirect
|
||||
google.golang.org/genproto v0.0.0-20230706204954-ccb25ca9f130 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
)
|
||||
|
|
|
@ -23,37 +23,48 @@ import (
|
|||
// Repository represents a code repository.
|
||||
type Repository struct {
|
||||
// TODO: int64 ID doesn't match DB
|
||||
ID int64 `json:"id"`
|
||||
Version int64 `json:"-"`
|
||||
ParentID int64 `json:"parent_id"`
|
||||
Identifier string `json:"identifier"`
|
||||
Path string `json:"path"`
|
||||
Description string `json:"description"`
|
||||
IsPublic bool `json:"is_public"`
|
||||
CreatedBy int64 `json:"created_by"`
|
||||
Created int64 `json:"created"`
|
||||
Updated int64 `json:"updated"`
|
||||
Deleted *int64 `json:"deleted,omitempty"`
|
||||
ID int64 `json:"id" yaml:"id"`
|
||||
Version int64 `json:"-" yaml:"version"`
|
||||
ParentID int64 `json:"parent_id" yaml:"parent_id"`
|
||||
Identifier string `json:"identifier" yaml:"identifier"`
|
||||
Path string `json:"path" yaml:"path"`
|
||||
Description string `json:"description" yaml:"description"`
|
||||
IsPublic bool `json:"is_public" yaml:"is_public"`
|
||||
CreatedBy int64 `json:"created_by" yaml:"created_by"`
|
||||
Created int64 `json:"created" yaml:"created"`
|
||||
Updated int64 `json:"updated" yaml:"updated"`
|
||||
Deleted *int64 `json:"deleted,omitempty" yaml:"deleted"`
|
||||
|
||||
Size int64 `json:"size"`
|
||||
SizeUpdated int64 `json:"size_updated"`
|
||||
Size int64 `json:"size" yaml:"size"`
|
||||
SizeUpdated int64 `json:"size_updated" yaml:"size_updated"`
|
||||
|
||||
GitUID string `json:"-"`
|
||||
DefaultBranch string `json:"default_branch"`
|
||||
ForkID int64 `json:"fork_id"`
|
||||
PullReqSeq int64 `json:"-"`
|
||||
GitUID string `json:"-" yaml:"-"`
|
||||
DefaultBranch string `json:"default_branch" yaml:"default_branch"`
|
||||
ForkID int64 `json:"fork_id" yaml:"fork_id"`
|
||||
PullReqSeq int64 `json:"-" yaml:"-"`
|
||||
|
||||
NumForks int `json:"num_forks"`
|
||||
NumPulls int `json:"num_pulls"`
|
||||
NumClosedPulls int `json:"num_closed_pulls"`
|
||||
NumOpenPulls int `json:"num_open_pulls"`
|
||||
NumMergedPulls int `json:"num_merged_pulls"`
|
||||
NumForks int `json:"num_forks" yaml:"num_forks"`
|
||||
NumPulls int `json:"num_pulls" yaml:"num_pulls"`
|
||||
NumClosedPulls int `json:"num_closed_pulls" yaml:"num_closed_pulls"`
|
||||
NumOpenPulls int `json:"num_open_pulls" yaml:"num_open_pulls"`
|
||||
NumMergedPulls int `json:"num_merged_pulls" yaml:"num_merged_pulls"`
|
||||
|
||||
Importing bool `json:"importing"`
|
||||
IsEmpty bool `json:"is_empty,omitempty"`
|
||||
Importing bool `json:"importing" yaml:"-"`
|
||||
IsEmpty bool `json:"is_empty,omitempty" yaml:"is_empty"`
|
||||
|
||||
// git urls
|
||||
GitURL string `json:"git_url"`
|
||||
GitURL string `json:"git_url" yaml:"git_url"`
|
||||
}
|
||||
|
||||
// Clone makes deep copy of repository object.
|
||||
func (r Repository) Clone() Repository {
|
||||
var deleted *int64
|
||||
if r.Deleted != nil {
|
||||
id := *r.Deleted
|
||||
deleted = &id
|
||||
}
|
||||
r.Deleted = deleted
|
||||
return r
|
||||
}
|
||||
|
||||
// TODO [CODE-1363]: remove after identifier migration.
|
||||
|
|
|
@ -19,6 +19,8 @@ import (
|
|||
"fmt"
|
||||
|
||||
"github.com/harness/gitness/types/enum"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
type Rule struct {
|
||||
|
@ -59,6 +61,69 @@ func (r Rule) MarshalJSON() ([]byte, error) {
|
|||
})
|
||||
}
|
||||
|
||||
func (r Rule) MarshalYAML() (interface{}, error) {
|
||||
// yaml cannot marshal json.RawMessage
|
||||
pattern := make(map[string]any)
|
||||
err := yaml.Unmarshal(r.Pattern, pattern)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
definition := make(map[string]any)
|
||||
err = yaml.Unmarshal(r.Definition, definition)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return map[string]any{
|
||||
"id": r.ID,
|
||||
"version": r.Version,
|
||||
"created": r.Created,
|
||||
"updated": r.Updated,
|
||||
"created_by": r.CreatedBy,
|
||||
"identifier": r.Identifier,
|
||||
"description": r.Description,
|
||||
"type": r.Type,
|
||||
"state": r.State,
|
||||
"pattern": pattern,
|
||||
"definition": definition,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Clone makes deep copy of the rule object.
|
||||
func (r Rule) Clone() Rule {
|
||||
var repoID *int64
|
||||
var spaceID *int64
|
||||
|
||||
if r.RepoID != nil {
|
||||
id := *r.RepoID
|
||||
repoID = &id
|
||||
}
|
||||
|
||||
if r.SpaceID != nil {
|
||||
id := *r.SpaceID
|
||||
spaceID = &id
|
||||
}
|
||||
|
||||
r.RepoID = repoID
|
||||
r.SpaceID = spaceID
|
||||
|
||||
pattern := make(json.RawMessage, len(r.Pattern))
|
||||
copy(pattern, r.Pattern)
|
||||
r.Pattern = pattern
|
||||
|
||||
definition := make(json.RawMessage, len(r.Definition))
|
||||
copy(definition, r.Definition)
|
||||
r.Definition = definition
|
||||
|
||||
users := make(map[int64]*PrincipalInfo, len(r.Users))
|
||||
for key, value := range r.Users {
|
||||
cloned := *value
|
||||
users[key] = &cloned
|
||||
}
|
||||
r.Users = users
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
type RuleType string
|
||||
|
||||
type RuleFilter struct {
|
||||
|
|
Loading…
Reference in New Issue