Skip to content

Commit

Permalink
[Backport 5.0] log rbac-related backend events (#49245)
Browse files Browse the repository at this point in the history
This PR adds a logger for events, so rbac-related events can be viewed
in the `event_logs` table.
I also removed the constraint where a site admin can't assign a role
to themselves.

## Test plan

<!-- All pull requests REQUIRE a test plan:
https://docs.sourcegraph.com/dev/background-information/testing_principles
-->
* Manual testing
* Update unit tests. <br> Backport
0ac73dd from #49181

Co-authored-by: Bolaji Olajide <25608335+BolajiOlajide@users.noreply.github.com>
  • Loading branch information
github-actions[bot] and BolajiOlajide committed Mar 13, 2023
1 parent 717f971 commit d2d2d14
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 8 deletions.
53 changes: 53 additions & 0 deletions enterprise/cmd/frontend/internal/rbac/resolvers/resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,19 @@ package resolvers

import (
"context"
"encoding/json"
"fmt"

"github.com/sourcegraph/log"

gql "github.com/sourcegraph/sourcegraph/cmd/frontend/graphqlbackend"
"github.com/sourcegraph/sourcegraph/internal/actor"
"github.com/sourcegraph/sourcegraph/internal/auth"
"github.com/sourcegraph/sourcegraph/internal/database"
"github.com/sourcegraph/sourcegraph/internal/deviceid"
"github.com/sourcegraph/sourcegraph/internal/featureflag"
"github.com/sourcegraph/sourcegraph/internal/types"
"github.com/sourcegraph/sourcegraph/internal/usagestats"
)

// Resolver is the GraphQL resolver of all things related to batch changes.
Expand All @@ -17,6 +23,20 @@ type Resolver struct {
db database.DB
}

type roleEventArg struct {
RoleID int32 `json:"role_id"`
}

type rolePermissionEventArgs struct {
RoleID int32 `json:"role_id"`
PermissionIDs []int32 `json:"permission_ids"`
}

type setRolesEventArgs struct {
UserID int32 `json:"user_id"`
RoleIDs []int32 `json:"role_ids"`
}

func New(logger log.Logger, db database.DB) gql.RBACResolver {
return &Resolver{logger: logger, db: db}
}
Expand Down Expand Up @@ -48,6 +68,8 @@ func (r *Resolver) SetPermissions(ctx context.Context, args gql.SetPermissionsAr
return nil, err
}

eventArgs := &rolePermissionEventArgs{RoleID: roleID, PermissionIDs: opts.Permissions}
r.logBackendEvent(ctx, "RolePermissionAssignment", eventArgs)
return &gql.EmptyResponse{}, nil
}

Expand All @@ -73,6 +95,8 @@ func (r *Resolver) DeleteRole(ctx context.Context, args *gql.DeleteRoleArgs) (_
return nil, err
}

eventArg := &roleEventArg{RoleID: roleID}
r.logBackendEvent(ctx, "RoleDeleted", eventArg)
return &gql.EmptyResponse{}, nil
}

Expand All @@ -83,12 +107,14 @@ func (r *Resolver) CreateRole(ctx context.Context, args *gql.CreateRoleArgs) (gq
}

var role *types.Role
eventArg := &rolePermissionEventArgs{}
err := r.db.WithTransact(ctx, func(tx database.DB) (err error) {
role, err = tx.Roles().Create(ctx, args.Name, false)
if err != nil {
return err
}

eventArg.RoleID = role.ID
if len(args.Permissions) > 0 {
opts := database.BulkAssignPermissionsToRoleOpts{RoleID: role.ID}
for _, permissionID := range args.Permissions {
Expand All @@ -98,6 +124,7 @@ func (r *Resolver) CreateRole(ctx context.Context, args *gql.CreateRoleArgs) (gq
}
opts.Permissions = append(opts.Permissions, id)
}
eventArg.PermissionIDs = opts.Permissions
err = tx.RolePermissions().BulkAssignPermissionsToRole(ctx, opts)
if err != nil {
return err
Expand All @@ -110,6 +137,7 @@ func (r *Resolver) CreateRole(ctx context.Context, args *gql.CreateRoleArgs) (gq
return nil, err
}

r.logBackendEvent(ctx, "RoleCreated", eventArg)
return gql.NewRoleResolver(r.db, role), nil
}

Expand Down Expand Up @@ -139,5 +167,30 @@ func (r *Resolver) SetRoles(ctx context.Context, args *gql.SetRolesArgs) (*gql.E
return nil, err
}

eventArgs := &setRolesEventArgs{RoleIDs: opts.Roles, UserID: userID}
r.logBackendEvent(ctx, "UserRoleAssignment", eventArgs)
return &gql.EmptyResponse{}, nil
}

func (r *Resolver) logBackendEvent(ctx context.Context, eventName string, args any) {
a := actor.FromContext(ctx)
if a.IsAuthenticated() && !a.IsMockUser() {
jsonArg, err := json.Marshal(args)
if err != nil {
r.logger.Warn(fmt.Sprintf("Could not log event: %s", eventName), log.Error(err))
return
}
if err := usagestats.LogBackendEvent(
r.db,
a.UID,
deviceid.FromContext(ctx),
eventName,
jsonArg,
jsonArg,
featureflag.GetEvaluatedFlagSet(ctx),
nil,
); err != nil {
r.logger.Warn(fmt.Sprintf("Could not log event: %s", eventName), log.Error(err))
}
}
}
16 changes: 8 additions & 8 deletions enterprise/cmd/frontend/internal/rbac/resolvers/resolver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,10 @@ func TestDeleteRole(t *testing.T) {
db := database.NewDB(logger, dbtest.NewDB(logger, t))

userID := createTestUser(t, db, false).ID
actorCtx := actor.WithActor(ctx, actor.FromUser(userID))
actorCtx := actor.WithActor(ctx, actor.FromMockUser(userID))

adminUserID := createTestUser(t, db, true).ID
adminActorCtx := actor.WithActor(ctx, actor.FromUser(adminUserID))
adminActorCtx := actor.WithActor(ctx, actor.FromMockUser(adminUserID))

r := &Resolver{logger: logger, db: db}
s, err := newSchema(db, r)
Expand Down Expand Up @@ -95,10 +95,10 @@ func TestCreateRole(t *testing.T) {
db := database.NewDB(logger, dbtest.NewDB(logger, t))

userID := createTestUser(t, db, false).ID
actorCtx := actor.WithActor(ctx, actor.FromUser(userID))
actorCtx := actor.WithActor(ctx, actor.FromMockUser(userID))

adminUserID := createTestUser(t, db, true).ID
adminActorCtx := actor.WithActor(ctx, actor.FromUser(adminUserID))
adminActorCtx := actor.WithActor(ctx, actor.FromMockUser(adminUserID))

r := &Resolver{logger: logger, db: db}
s, err := newSchema(db, r)
Expand Down Expand Up @@ -203,8 +203,8 @@ func TestSetPermissions(t *testing.T) {
admin := createTestUser(t, db, true)
user := createTestUser(t, db, false)

adminCtx := actor.WithActor(ctx, actor.FromUser(admin.ID))
userCtx := actor.WithActor(ctx, actor.FromUser(user.ID))
adminCtx := actor.WithActor(ctx, actor.FromMockUser(admin.ID))
userCtx := actor.WithActor(ctx, actor.FromMockUser(user.ID))

s, err := newSchema(db, &Resolver{logger: logger, db: db})
if err != nil {
Expand Down Expand Up @@ -318,10 +318,10 @@ func TestSetRoles(t *testing.T) {

uID := createTestUser(t, db, false).ID
userID := gql.MarshalUserID(uID)
userCtx := actor.WithActor(ctx, actor.FromUser(uID))
userCtx := actor.WithActor(ctx, actor.FromMockUser(uID))

aID := createTestUser(t, db, true).ID
adminCtx := actor.WithActor(ctx, actor.FromUser(aID))
adminCtx := actor.WithActor(ctx, actor.FromMockUser(aID))

s, err := newSchema(db, &Resolver{logger: logger, db: db})
if err != nil {
Expand Down

0 comments on commit d2d2d14

Please sign in to comment.