update audit logs to include repo is-public

gitness-public-repo-testing
atefeh 2024-04-26 18:50:00 -07:00
parent e4d46d8a30
commit 3d5fb186c4
12 changed files with 98 additions and 63 deletions

View File

@ -53,6 +53,18 @@ type Repository struct {
IsPublic bool `json:"is_public"`
}
// Clone makes deep copy of repository object.
func (r Repository) Clone() Repository {
var deleted *int64
if r.Repository.Deleted != nil {
id := *r.Repository.Deleted
deleted = &id
}
r.Repository.Deleted = deleted
return r
}
type Controller struct {
defaultBranch string
publicResourceCreationEnabled bool

View File

@ -35,7 +35,6 @@ import (
"github.com/harness/gitness/types"
"github.com/harness/gitness/types/check"
"github.com/harness/gitness/types/enum"
"github.com/pkg/errors"
"github.com/rs/zerolog/log"
)
@ -129,20 +128,25 @@ func (c *Controller) Create(ctx context.Context, session *auth.Session, in *Crea
return nil, err
}
// backfil GitURL
repo.GitURL = c.urlProvider.GenerateGITCloneURL(repo.Path)
repoData := &Repository{
Repository: *repo,
IsPublic: in.IsPublic,
}
err = c.auditService.Log(ctx,
session.Principal,
audit.NewResource(audit.ResourceTypeRepository, repo.Identifier),
audit.ActionCreated,
paths.Space(repo.Path),
audit.WithNewObject(repo),
audit.WithNewObject(repoData),
)
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)
// index repository if files are created
if !repo.IsEmpty {
err = c.indexer.Index(ctx, repo)
@ -151,10 +155,7 @@ func (c *Controller) Create(ctx context.Context, session *auth.Session, in *Crea
}
}
return &Repository{
Repository: *repo,
IsPublic: in.IsPublic,
}, nil
return repoData, nil
}
func (c *Controller) getSpaceCheckAuthRepoCreation(

View File

@ -48,7 +48,9 @@ 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
@ -56,7 +58,7 @@ func (c *Controller) UpdateDefaultBranch(
// requests will wait for previous ones to compelete before proceed
unlock, err := c.locker.LockDefaultBranch(
ctx,
repo.ID,
repo.Repository.ID,
in.Name, // branch name only used for logging (lock is on repo)
timeout+30*time.Second, // add 30s to the lock to give enough time for updating default branch
)
@ -86,7 +88,7 @@ func (c *Controller) UpdateDefaultBranch(
return nil, fmt.Errorf("failed to update the repo default branch: %w", err)
}
oldName := repo.DefaultBranch
oldName := repo.Repository.DefaultBranch
repoBase, err := c.repoStore.UpdateOptLock(ctx, &repo.Repository, func(r *types.Repository) error {
r.DefaultBranch = in.Name
return nil
@ -95,11 +97,16 @@ func (c *Controller) UpdateDefaultBranch(
return nil, fmt.Errorf("failed to update the repo default branch on db:%w", err)
}
repo = &Repository{
Repository: *repoBase,
IsPublic: repo.IsPublic,
}
err = c.auditService.Log(ctx,
session.Principal,
audit.NewResource(audit.ResourceTypeRepository, repo.Identifier),
audit.NewResource(audit.ResourceTypeRepository, repo.Repository.Identifier),
audit.ActionUpdated,
paths.Space(repo.Path),
paths.Space(repo.Repository.Path),
audit.WithOldObject(repoClone),
audit.WithNewObject(repo),
)
@ -108,14 +115,11 @@ func (c *Controller) UpdateDefaultBranch(
}
c.eventReporter.DefaultBranchUpdated(ctx, &repoevents.DefaultBranchUpdatedPayload{
RepoID: repo.ID,
RepoID: repoBase.ID,
PrincipalID: bootstrap.NewSystemServiceSession().Principal.ID,
OldName: oldName,
NewName: repo.DefaultBranch,
NewName: repoBase.DefaultBranch,
})
return &Repository{
Repository: *repoBase,
IsPublic: repo.IsPublic,
}, nil
return repo, nil
}

View File

@ -20,35 +20,39 @@ import (
"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"
"github.com/rs/zerolog/log"
)
type VisibilityInput struct {
type PublicAccessUpdateInput struct {
EnablePublic bool `json:"enable_public"`
}
type VisibilityOutput struct {
type PublicAccessUpdateOutput struct {
IsPublic bool `json:"is_public"`
}
func (c *Controller) VisibilityUpdate(ctx context.Context,
func (c *Controller) PublicAccessUpdate(ctx context.Context,
session *auth.Session,
repoRef string,
in *VisibilityInput,
) (*VisibilityOutput, error) {
in *PublicAccessUpdateInput,
) (*PublicAccessUpdateOutput, error) {
repo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionRepoEdit)
if err != nil {
return nil, err
}
repoClone := repo.Clone()
if err = c.sanitizeVisibilityInput(in); err != nil {
return nil, fmt.Errorf("failed to sanitize input: %w", err)
}
parentSpace, name, err := paths.DisectLeaf(repo.Path)
parentSpace, name, err := paths.DisectLeaf(repo.Repository.Path)
if err != nil {
return nil, fmt.Errorf("Failed to disect path '%s': %w", repo.Path, err)
return nil, fmt.Errorf("failed to disect path '%s': %w", repo.Repository.Path, err)
}
scope := &types.Scope{SpacePath: parentSpace}
@ -61,13 +65,28 @@ func (c *Controller) VisibilityUpdate(ctx context.Context,
return nil, fmt.Errorf("failed to set public access: %w", err)
}
return &VisibilityOutput{
err = c.auditService.Log(ctx,
session.Principal,
audit.NewResource(audit.ResourceTypeRepository, repo.Repository.Identifier),
audit.ActionUpdated,
paths.Space(repo.Repository.Path),
audit.WithOldObject(repoClone),
audit.WithNewObject(&Repository{
Repository: repo.Repository,
IsPublic: in.EnablePublic,
}),
)
if err != nil {
log.Ctx(ctx).Warn().Msgf("failed to insert audit log for update repository operation: %s", err)
}
return &PublicAccessUpdateOutput{
in.EnablePublic,
}, nil
}
func (c *Controller) sanitizeVisibilityInput(in *VisibilityInput) error {
func (c *Controller) sanitizeVisibilityInput(in *PublicAccessUpdateInput) error {
if in.EnablePublic && !c.publicResourceCreationEnabled {
return errPublicRepoCreationDisabled
}

View File

@ -100,7 +100,7 @@ func (c *Controller) RuleCreate(ctx context.Context,
CreatedBy: session.Principal.ID,
Created: now,
Updated: now,
RepoID: &repo.ID,
RepoID: &repo.Repository.ID,
SpaceID: nil,
Type: in.Type,
State: in.State,
@ -120,7 +120,7 @@ func (c *Controller) RuleCreate(ctx context.Context,
session.Principal,
audit.NewResource(audit.ResourceTypeBranchRule, r.Identifier),
audit.ActionCreated,
paths.Space(repo.Path),
paths.Space(repo.Repository.Path),
audit.WithNewObject(r),
)
if err != nil {

View File

@ -37,7 +37,7 @@ func (c *Controller) RuleDelete(ctx context.Context,
return err
}
r, err := c.ruleStore.FindByIdentifier(ctx, nil, &repo.ID, identifier)
r, err := c.ruleStore.FindByIdentifier(ctx, nil, &repo.Repository.ID, identifier)
if err != nil {
return fmt.Errorf("failed to find repository-level protection rule by identifier: %w", err)
}
@ -51,7 +51,7 @@ func (c *Controller) RuleDelete(ctx context.Context,
session.Principal,
audit.NewResource(audit.ResourceTypeBranchRule, r.Identifier),
audit.ActionDeleted,
paths.Space(repo.Path),
paths.Space(repo.Repository.Path),
audit.WithOldObject(r),
)
if err != nil {

View File

@ -96,7 +96,7 @@ func (c *Controller) RuleUpdate(ctx context.Context,
return nil, err
}
r, err := c.ruleStore.FindByIdentifier(ctx, nil, &repo.ID, identifier)
r, err := c.ruleStore.FindByIdentifier(ctx, nil, &repo.Repository.ID, identifier)
if err != nil {
return nil, fmt.Errorf("failed to get a repository rule by its identifier: %w", err)
}
@ -142,7 +142,7 @@ func (c *Controller) RuleUpdate(ctx context.Context,
session.Principal,
audit.NewResource(audit.ResourceTypeBranchRule, r.Identifier),
audit.ActionUpdated,
paths.Space(repo.Path),
paths.Space(repo.Repository.Path),
audit.WithOldObject(oldRule),
audit.WithNewObject(r),
)

View File

@ -64,12 +64,20 @@ func (c *Controller) SoftDelete(
return nil, fmt.Errorf("failed to soft delete repo: %w", err)
}
isPublic, err := apiauth.CheckRepoIsPublic(ctx, c.publicAccess, repo)
if err != nil {
log.Ctx(ctx).Warn().Msgf("failed to check repo public access for audit logs: %s", err)
}
err = c.auditService.Log(ctx,
session.Principal,
audit.NewResource(audit.ResourceTypeRepository, repo.Identifier),
audit.ActionDeleted,
paths.Space(repo.Path),
audit.WithOldObject(repo),
audit.WithOldObject(&Repository{
Repository: *repo,
IsPublic: isPublic,
}),
)
if err != nil {
log.Ctx(ctx).Warn().Msgf("failed to insert audit log for delete repository operation: %s", err)

View File

@ -72,11 +72,23 @@ func (c *Controller) Update(ctx context.Context,
return nil, err
}
// backfill repo url
repo.Repository.GitURL = c.urlProvider.GenerateGITCloneURL(repo.Repository.Path)
isPublic, err := apiauth.CheckRepoIsPublic(ctx, c.publicAccess, repoBase)
if err != nil {
return nil, fmt.Errorf("failed to get resource public access mode: %w", err)
}
repo = &Repository{
Repository: *repoBase,
IsPublic: isPublic,
}
err = c.auditService.Log(ctx,
session.Principal,
audit.NewResource(audit.ResourceTypeRepository, repo.Identifier),
audit.NewResource(audit.ResourceTypeRepository, repo.Repository.Identifier),
audit.ActionUpdated,
paths.Space(repo.Path),
paths.Space(repo.Repository.Path),
audit.WithOldObject(repoClone),
audit.WithNewObject(repo),
)
@ -84,17 +96,7 @@ func (c *Controller) Update(ctx context.Context,
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)
isPublic, err := apiauth.CheckRepoIsPublic(ctx, c.publicAccess, repoBase)
if err != nil {
return nil, fmt.Errorf("failed to get resource public access mode: %w", err)
}
return &Repository{
Repository: *repoBase,
IsPublic: isPublic,
}, nil
return repo, nil
}
func (c *Controller) sanitizeUpdateInput(in *UpdateInput) error {

View File

@ -23,7 +23,7 @@ import (
"github.com/harness/gitness/app/api/request"
)
func HandleVisibilityUpdate(repoCtrl *repo.Controller) http.HandlerFunc {
func HandlePublicAccessUpdate(repoCtrl *repo.Controller) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
session, _ := request.AuthSessionFrom(ctx)
@ -34,14 +34,14 @@ func HandleVisibilityUpdate(repoCtrl *repo.Controller) http.HandlerFunc {
return
}
in := new(repo.VisibilityInput)
in := new(repo.PublicAccessUpdateInput)
err = json.NewDecoder(r.Body).Decode(in)
if err != nil {
render.BadRequestf(ctx, w, "Invalid Request Body: %s.", err)
return
}
res, err := repoCtrl.VisibilityUpdate(ctx, session, repoRef, in)
res, err := repoCtrl.PublicAccessUpdate(ctx, session, repoRef, in)
if err != nil {
render.TranslatedUserError(ctx, w, err)
return

View File

@ -276,7 +276,7 @@ func setupRepos(r chi.Router,
r.Delete("/", handlerrepo.HandleSoftDelete(repoCtrl))
r.Post("/purge", handlerrepo.HandlePurge(repoCtrl))
r.Post("/restore", handlerrepo.HandleRestore(repoCtrl))
r.Patch("/visibility", handlerrepo.HandleVisibilityUpdate(repoCtrl))
r.Post("/public-access", handlerrepo.HandlePublicAccessUpdate(repoCtrl))
r.Get("/settings/security", handlerreposettings.HandleSecurityFind(repoSettingsCtrl))
r.Patch("/settings/security", handlerreposettings.HandleSecurityUpdate(repoSettingsCtrl))

View File

@ -55,17 +55,6 @@ type Repository struct {
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.
func (r Repository) MarshalJSON() ([]byte, error) {
// alias allows us to embed the original object while avoiding an infinite loop of marshaling.