Skip to content

Commit

Permalink
feat: logs activity of shield entities
Browse files Browse the repository at this point in the history
  • Loading branch information
FemiNoviaLina committed Apr 3, 2024
1 parent 81b8706 commit 6ec8f98
Show file tree
Hide file tree
Showing 29 changed files with 748 additions and 50 deletions.
42 changes: 26 additions & 16 deletions cmd/serve.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (

"github.com/goto/shield/config"
"github.com/goto/shield/core/action"
"github.com/goto/shield/core/activity"
"github.com/goto/shield/core/group"
"github.com/goto/shield/core/namespace"
"github.com/goto/shield/core/organization"
Expand Down Expand Up @@ -90,18 +91,24 @@ func StartServer(logger *log.Zap, cfg *config.Shield) error {
}

//
activityRepository := postgres.NewActivityRepository(dbClient)
activityService := activity.NewService(activityRepository)

userRepository := postgres.NewUserRepository(dbClient)
userService := user.NewService(userRepository, activityService)

actionRepository := postgres.NewActionRepository(dbClient)
actionService := action.NewService(actionRepository)
actionService := action.NewService(actionRepository, userService, activityService)

roleRepository := postgres.NewRoleRepository(dbClient)
roleService := role.NewService(roleRepository)
roleService := role.NewService(roleRepository, userService, activityService)

policyPGRepository := postgres.NewPolicyRepository(dbClient)
policySpiceRepository := spicedb.NewPolicyRepository(spiceDBClient)
policyService := policy.NewService(policyPGRepository)
policyService := policy.NewService(policyPGRepository, userService, activityService)

namespaceRepository := postgres.NewNamespaceRepository(dbClient)
namespaceService := namespace.NewService(namespaceRepository)
namespaceService := namespace.NewService(namespaceRepository, userService, activityService)

s := schema.NewSchemaMigrationService(
blob.NewSchemaConfigRepository(resourceBlobFS),
Expand Down Expand Up @@ -159,37 +166,40 @@ func BuildAPIDependencies(
dbc *db.Client,
sdb *spicedb.SpiceDB,
) (api.Deps, error) {
activityRepository := postgres.NewActivityRepository(dbc)
activityService := activity.NewService(activityRepository)

userRepository := postgres.NewUserRepository(dbc)
userService := user.NewService(userRepository, activityService)

actionRepository := postgres.NewActionRepository(dbc)
actionService := action.NewService(actionRepository)
actionService := action.NewService(actionRepository, userService, activityService)

namespaceRepository := postgres.NewNamespaceRepository(dbc)
namespaceService := namespace.NewService(namespaceRepository)

userRepository := postgres.NewUserRepository(dbc)
userService := user.NewService(userRepository)
namespaceService := namespace.NewService(namespaceRepository, userService, activityService)

roleRepository := postgres.NewRoleRepository(dbc)
roleService := role.NewService(roleRepository)
roleService := role.NewService(roleRepository, userService, activityService)

relationPGRepository := postgres.NewRelationRepository(dbc)
relationSpiceRepository := spicedb.NewRelationRepository(sdb)
relationService := relation.NewService(relationPGRepository, relationSpiceRepository)
relationService := relation.NewService(relationPGRepository, relationSpiceRepository, userService, activityService)

groupRepository := postgres.NewGroupRepository(dbc)
groupService := group.NewService(groupRepository, relationService, userService)
groupService := group.NewService(groupRepository, relationService, userService, activityService)

organizationRepository := postgres.NewOrganizationRepository(dbc)
organizationService := organization.NewService(organizationRepository, relationService, userService)
organizationService := organization.NewService(organizationRepository, relationService, userService, activityService)

projectRepository := postgres.NewProjectRepository(dbc)
projectService := project.NewService(projectRepository, relationService, userService)
projectService := project.NewService(projectRepository, relationService, userService, activityService)

policyPGRepository := postgres.NewPolicyRepository(dbc)
policyService := policy.NewService(policyPGRepository)
policyService := policy.NewService(policyPGRepository, userService, activityService)

resourcePGRepository := postgres.NewResourceRepository(dbc)
resourceService := resource.NewService(
resourcePGRepository, resourceBlobRepository, relationService, userService, projectService, organizationService, groupService)
resourcePGRepository, resourceBlobRepository, relationService, userService, projectService, organizationService, groupService, activityService)

relationAdapter := adapter.NewRelation(groupService, userService, relationService)

Expand Down
1 change: 1 addition & 0 deletions core/action/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ var (
ErrInvalidID = errors.New("action id is invalid")
ErrNotExist = errors.New("action doesn't exist")
ErrInvalidDetail = errors.New("invalid action detail")
ErrLogActivity = errors.New("error while logging activity")
)
52 changes: 49 additions & 3 deletions core/action/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,37 @@ package action

import (
"context"

"github.com/goto/shield/core/user"
grpczap "github.com/grpc-ecosystem/go-grpc-middleware/logging/zap/ctxzap"
)

const (
AuditKeyActionCreate = "action.create"
AuditKeyActionUpdate = "action.update"

AuditEntity = "action"
)

type UserService interface {
FetchCurrentUser(ctx context.Context) (user.User, error)
}

type ActivityService interface {
Log(ctx context.Context, action string, actor string, data map[string]string) error
}

type Service struct {
repository Repository
repository Repository
userService UserService
activityService ActivityService
}

func NewService(repository Repository) *Service {
func NewService(repository Repository, userService UserService, activityService ActivityService) *Service {
return &Service{
repository: repository,
repository: repository,
userService: userService,
activityService: activityService,
}
}

Expand All @@ -24,6 +46,18 @@ func (s Service) Create(ctx context.Context, action Action) (Action, error) {
return Action{}, err
}

currentUser, _ := s.userService.FetchCurrentUser(ctx)
logData := map[string]string{
"entity": AuditEntity,
"id": newAction.ID,
"name": newAction.Name,
"namespaceId": newAction.NamespaceID,
}
if err := s.activityService.Log(ctx, AuditKeyActionCreate, currentUser.ID, logData); err != nil {
logger := grpczap.Extract(ctx)
logger.Error(ErrLogActivity.Error())
}

return newAction, nil
}

Expand All @@ -41,5 +75,17 @@ func (s Service) Update(ctx context.Context, id string, action Action) (Action,
return Action{}, err
}

currentUser, _ := s.userService.FetchCurrentUser(ctx)
logData := map[string]string{
"entity": AuditEntity,
"id": updatedAction.ID,
"name": updatedAction.Name,
"namespaceId": updatedAction.NamespaceID,
}
if err := s.activityService.Log(ctx, AuditKeyActionUpdate, currentUser.ID, logData); err != nil {
logger := grpczap.Extract(ctx)
logger.Error(ErrLogActivity.Error())
}

return updatedAction, nil
}
11 changes: 11 additions & 0 deletions core/activity/activity.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package activity

import (
"context"

"github.com/goto/salt/audit"
)

type Repository interface {
Insert(ctx context.Context, log *audit.Log) error
}
36 changes: 36 additions & 0 deletions core/activity/service.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package activity

import (
"context"
"time"

"github.com/goto/salt/audit"
"github.com/goto/shield/config"
)

type Service struct {
repository Repository
}

func NewService(repository Repository) *Service {
return &Service{
repository: repository,
}
}

func (s Service) Log(ctx context.Context, action string, actor string, data map[string]string) error {
metadata := map[string]string{
"app_name": "shield",
"app_version": config.Version,
}

log := &audit.Log{
Timestamp: time.Now(),
Action: action,
Data: data,
Actor: actor,
Metadata: metadata,
}

return s.repository.Insert(ctx, log)
}
1 change: 1 addition & 0 deletions core/group/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@ var (
ErrListingGroupRelations = errors.New("error while listing relations")
ErrFetchingUsers = errors.New("error while fetching users")
ErrFetchingGroups = errors.New("error while fetching groups")
ErrLogActivity = errors.New("error while logging activity")
)
54 changes: 51 additions & 3 deletions core/group/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package group
import (
"context"
"fmt"
"maps"
"strings"

"github.com/goto/shield/core/action"
Expand All @@ -12,6 +13,14 @@ import (
"github.com/goto/shield/internal/schema"
"github.com/goto/shield/pkg/str"
"github.com/goto/shield/pkg/uuid"
grpczap "github.com/grpc-ecosystem/go-grpc-middleware/logging/zap/ctxzap"
)

const (
AuditKeyGroupCreate = "group.create"
AuditKeyGroupUpdate = "group.update"

AuditEntity = "group"
)

type RelationService interface {
Expand All @@ -26,22 +35,28 @@ type UserService interface {
GetByIDs(ctx context.Context, userIDs []string) ([]user.User, error)
}

type ActivityService interface {
Log(ctx context.Context, action string, actor string, data map[string]string) error
}

type Service struct {
repository Repository
relationService RelationService
userService UserService
activityService ActivityService
}

func NewService(repository Repository, relationService RelationService, userService UserService) *Service {
func NewService(repository Repository, relationService RelationService, userService UserService, activityService ActivityService) *Service {
return &Service{
repository: repository,
relationService: relationService,
userService: userService,
activityService: activityService,
}
}

func (s Service) Create(ctx context.Context, grp Group) (Group, error) {
_, err := s.userService.FetchCurrentUser(ctx)
currentUser, err := s.userService.FetchCurrentUser(ctx)
if err != nil {
return Group{}, fmt.Errorf("%w: %s", user.ErrInvalidEmail, err.Error())
}
Expand All @@ -55,6 +70,19 @@ func (s Service) Create(ctx context.Context, grp Group) (Group, error) {
return Group{}, err
}

logData := map[string]string{
"entity": AuditEntity,
"id": newGroup.ID,
"name": newGroup.Name,
"slug": newGroup.Slug,
"orgId": newGroup.OrganizationID,
}
maps.Copy(logData, newGroup.Metadata.ToStringValueMap())
if err := s.activityService.Log(ctx, AuditKeyGroupCreate, currentUser.ID, logData); err != nil {
logger := grpczap.Extract(ctx)
logger.Error(ErrLogActivity.Error())
}

return newGroup, nil
}

Expand All @@ -81,7 +109,27 @@ func (s Service) Update(ctx context.Context, grp Group) (Group, error) {
if strings.TrimSpace(grp.ID) != "" {
return s.repository.UpdateByID(ctx, grp)
}
return s.repository.UpdateBySlug(ctx, grp)

updatedGroup, err := s.repository.UpdateBySlug(ctx, grp)
if err != nil {
return Group{}, err
}

currentUser, _ := s.userService.FetchCurrentUser(ctx)
logData := map[string]string{
"entity": AuditEntity,
"id": updatedGroup.ID,
"name": updatedGroup.Name,
"slug": updatedGroup.Slug,
"orgId": updatedGroup.ID,
}
maps.Copy(logData, updatedGroup.Metadata.ToStringValueMap())
if err := s.activityService.Log(ctx, AuditKeyGroupUpdate, currentUser.ID, logData); err != nil {
logger := grpczap.Extract(ctx)
logger.Error(ErrLogActivity.Error())
}

return updatedGroup, nil
}

func (s Service) ListUserGroups(ctx context.Context, userId string, roleId string) ([]Group, error) {
Expand Down
1 change: 1 addition & 0 deletions core/namespace/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ var (
ErrNotExist = errors.New("namespace doesn't exist")
ErrConflict = errors.New("namespace name already exist")
ErrInvalidDetail = errors.New("invalid namespace detail")
ErrLogActivity = errors.New("error while logging activity")
)
Loading

0 comments on commit 6ec8f98

Please sign in to comment.