@@ -815,6 +815,86 @@ func (q *querier) customRoleEscalationCheck(ctx context.Context, actor rbac.Subj
815
815
return nil
816
816
}
817
817
818
+ // customRoleCheck will validate a custom role for inserting or updating.
819
+ // If the role is not valid, an error will be returned.
820
+ // - Check custom roles are valid for their resource types + actions
821
+ // - Check the actor can create the custom role
822
+ // - Check the custom role does not grant perms the actor does not have
823
+ // - Prevent negative perms
824
+ // - Prevent roles with site and org permissions.
825
+ func (q * querier )customRoleCheck (ctx context.Context ,role database.CustomRole )error {
826
+ act ,ok := ActorFromContext (ctx )
827
+ if ! ok {
828
+ return NoActorError
829
+ }
830
+
831
+ // Org permissions require an org role
832
+ if role .OrganizationID .UUID == uuid .Nil && len (role .OrgPermissions )> 0 {
833
+ return xerrors .Errorf ("organization permissions require specifying an organization id" )
834
+ }
835
+
836
+ // Org roles can only specify org permissions
837
+ if role .OrganizationID .UUID != uuid .Nil && (len (role .SitePermissions )> 0 || len (role .UserPermissions )> 0 ) {
838
+ return xerrors .Errorf ("organization roles specify site or user permissions" )
839
+ }
840
+
841
+ // The rbac.Role has a 'Valid()' function on it that will do a lot
842
+ // of checks.
843
+ rbacRole ,err := rolestore .ConvertDBRole (database.CustomRole {
844
+ Name :role .Name ,
845
+ DisplayName :role .DisplayName ,
846
+ SitePermissions :role .SitePermissions ,
847
+ OrgPermissions :role .OrgPermissions ,
848
+ UserPermissions :role .UserPermissions ,
849
+ OrganizationID :role .OrganizationID ,
850
+ })
851
+ if err != nil {
852
+ return xerrors .Errorf ("invalid args: %w" ,err )
853
+ }
854
+
855
+ err = rbacRole .Valid ()
856
+ if err != nil {
857
+ return xerrors .Errorf ("invalid role: %w" ,err )
858
+ }
859
+
860
+ if len (rbacRole .Org )> 0 && len (rbacRole .Site )> 0 {
861
+ // This is a choice to keep roles simple. If we allow mixing site and org scoped perms, then knowing who can
862
+ // do what gets more complicated.
863
+ return xerrors .Errorf ("invalid custom role, cannot assign both org and site permissions at the same time" )
864
+ }
865
+
866
+ if len (rbacRole .Org )> 1 {
867
+ // Again to avoid more complexity in our roles
868
+ return xerrors .Errorf ("invalid custom role, cannot assign permissions to more than 1 org at a time" )
869
+ }
870
+
871
+ // Prevent escalation
872
+ for _ ,sitePerm := range rbacRole .Site {
873
+ err := q .customRoleEscalationCheck (ctx ,act ,sitePerm , rbac.Object {Type :sitePerm .ResourceType })
874
+ if err != nil {
875
+ return xerrors .Errorf ("site permission: %w" ,err )
876
+ }
877
+ }
878
+
879
+ for orgID ,perms := range rbacRole .Org {
880
+ for _ ,orgPerm := range perms {
881
+ err := q .customRoleEscalationCheck (ctx ,act ,orgPerm , rbac.Object {OrgID :orgID ,Type :orgPerm .ResourceType })
882
+ if err != nil {
883
+ return xerrors .Errorf ("org=%q: %w" ,orgID ,err )
884
+ }
885
+ }
886
+ }
887
+
888
+ for _ ,userPerm := range rbacRole .User {
889
+ err := q .customRoleEscalationCheck (ctx ,act ,userPerm , rbac.Object {Type :userPerm .ResourceType ,Owner :act .ID })
890
+ if err != nil {
891
+ return xerrors .Errorf ("user permission: %w" ,err )
892
+ }
893
+ }
894
+
895
+ return nil
896
+ }
897
+
818
898
func (q * querier )AcquireLock (ctx context.Context ,id int64 )error {
819
899
return q .db .AcquireLock (ctx ,id )
820
900
}
@@ -2571,86 +2651,6 @@ func (q *querier) InsertCustomRole(ctx context.Context, arg database.InsertCusto
2571
2651
return q .db .InsertCustomRole (ctx ,arg )
2572
2652
}
2573
2653
2574
- // customRoleCheck will validate a custom role for inserting or updating.
2575
- // If the role is not valid, an error will be returned.
2576
- // - Check custom roles are valid for their resource types + actions
2577
- // - Check the actor can create the custom role
2578
- // - Check the custom role does not grant perms the actor does not have
2579
- // - Prevent negative perms
2580
- // - Prevent roles with site and org permissions.
2581
- func (q * querier )customRoleCheck (ctx context.Context ,role database.CustomRole )error {
2582
- act ,ok := ActorFromContext (ctx )
2583
- if ! ok {
2584
- return NoActorError
2585
- }
2586
-
2587
- // Org permissions require an org role
2588
- if role .OrganizationID .UUID == uuid .Nil && len (role .OrgPermissions )> 0 {
2589
- return xerrors .Errorf ("organization permissions require specifying an organization id" )
2590
- }
2591
-
2592
- // Org roles can only specify org permissions
2593
- if role .OrganizationID .UUID != uuid .Nil && (len (role .SitePermissions )> 0 || len (role .UserPermissions )> 0 ) {
2594
- return xerrors .Errorf ("organization roles specify site or user permissions" )
2595
- }
2596
-
2597
- // The rbac.Role has a 'Valid()' function on it that will do a lot
2598
- // of checks.
2599
- rbacRole ,err := rolestore .ConvertDBRole (database.CustomRole {
2600
- Name :role .Name ,
2601
- DisplayName :role .DisplayName ,
2602
- SitePermissions :role .SitePermissions ,
2603
- OrgPermissions :role .OrgPermissions ,
2604
- UserPermissions :role .UserPermissions ,
2605
- OrganizationID :role .OrganizationID ,
2606
- })
2607
- if err != nil {
2608
- return xerrors .Errorf ("invalid args: %w" ,err )
2609
- }
2610
-
2611
- err = rbacRole .Valid ()
2612
- if err != nil {
2613
- return xerrors .Errorf ("invalid role: %w" ,err )
2614
- }
2615
-
2616
- if len (rbacRole .Org )> 0 && len (rbacRole .Site )> 0 {
2617
- // This is a choice to keep roles simple. If we allow mixing site and org scoped perms, then knowing who can
2618
- // do what gets more complicated.
2619
- return xerrors .Errorf ("invalid custom role, cannot assign both org and site permissions at the same time" )
2620
- }
2621
-
2622
- if len (rbacRole .Org )> 1 {
2623
- // Again to avoid more complexity in our roles
2624
- return xerrors .Errorf ("invalid custom role, cannot assign permissions to more than 1 org at a time" )
2625
- }
2626
-
2627
- // Prevent escalation
2628
- for _ ,sitePerm := range rbacRole .Site {
2629
- err := q .customRoleEscalationCheck (ctx ,act ,sitePerm , rbac.Object {Type :sitePerm .ResourceType })
2630
- if err != nil {
2631
- return xerrors .Errorf ("site permission: %w" ,err )
2632
- }
2633
- }
2634
-
2635
- for orgID ,perms := range rbacRole .Org {
2636
- for _ ,orgPerm := range perms {
2637
- err := q .customRoleEscalationCheck (ctx ,act ,orgPerm , rbac.Object {OrgID :orgID ,Type :orgPerm .ResourceType })
2638
- if err != nil {
2639
- return xerrors .Errorf ("org=%q: %w" ,orgID ,err )
2640
- }
2641
- }
2642
- }
2643
-
2644
- for _ ,userPerm := range rbacRole .User {
2645
- err := q .customRoleEscalationCheck (ctx ,act ,userPerm , rbac.Object {Type :userPerm .ResourceType ,Owner :act .ID })
2646
- if err != nil {
2647
- return xerrors .Errorf ("user permission: %w" ,err )
2648
- }
2649
- }
2650
-
2651
- return nil
2652
- }
2653
-
2654
2654
func (q * querier )InsertDBCryptKey (ctx context.Context ,arg database.InsertDBCryptKeyParams )error {
2655
2655
if err := q .authorizeContext (ctx ,policy .ActionCreate ,rbac .ResourceSystem );err != nil {
2656
2656
return err
@@ -3103,7 +3103,30 @@ func (q *querier) UpdateAPIKeyByID(ctx context.Context, arg database.UpdateAPIKe
3103
3103
}
3104
3104
3105
3105
func (q * querier )UpdateCustomRole (ctx context.Context ,arg database.UpdateCustomRoleParams ) (database.CustomRole ,error ) {
3106
- panic ("not implemented" )
3106
+ if arg .OrganizationID .UUID != uuid .Nil {
3107
+ if err := q .authorizeContext (ctx ,policy .ActionUpdate ,rbac .ResourceAssignOrgRole .InOrg (arg .OrganizationID .UUID ));err != nil {
3108
+ return database.CustomRole {},err
3109
+ }
3110
+ }else {
3111
+ if err := q .authorizeContext (ctx ,policy .ActionUpdate ,rbac .ResourceAssignRole );err != nil {
3112
+ return database.CustomRole {},err
3113
+ }
3114
+ }
3115
+
3116
+ if err := q .customRoleCheck (ctx , database.CustomRole {
3117
+ Name :arg .Name ,
3118
+ DisplayName :arg .DisplayName ,
3119
+ SitePermissions :arg .SitePermissions ,
3120
+ OrgPermissions :arg .OrgPermissions ,
3121
+ UserPermissions :arg .UserPermissions ,
3122
+ CreatedAt :time .Now (),
3123
+ UpdatedAt :time .Now (),
3124
+ OrganizationID :arg .OrganizationID ,
3125
+ ID :uuid .New (),
3126
+ });err != nil {
3127
+ return database.CustomRole {},err
3128
+ }
3129
+ return q .db .UpdateCustomRole (ctx ,arg )
3107
3130
}
3108
3131
3109
3132
func (q * querier )UpdateExternalAuthLink (ctx context.Context ,arg database.UpdateExternalAuthLinkParams ) (database.ExternalAuthLink ,error ) {