@@ -443,10 +443,10 @@ describe("PermissionCheckService", () => {
443443 customRoleId : "org_role" ,
444444 } ) ;
445445
446- // Mock team permissions
446+ // Mock team permissions - create implies read
447447 mockRepository . getResourcePermissionsByRoleId
448448 . mockResolvedValueOnce ( [ "create" , "read" ] ) // team permissions
449- . mockResolvedValueOnce ( [ "update" , "delete" ] ) ; // org permissions
449+ . mockResolvedValueOnce ( [ "update" , "delete" , "read" ] ) ; // org permissions - update/delete imply read
450450
451451 const result = await service . getResourcePermissions ( {
452452 userId : 1 ,
@@ -486,10 +486,10 @@ describe("PermissionCheckService", () => {
486486 customRoleId : "org_role" ,
487487 } ) ;
488488
489- // Mock overlapping permissions
489+ // Mock overlapping permissions - both include read, update implies read
490490 mockRepository . getResourcePermissionsByRoleId
491- . mockResolvedValueOnce ( [ "create" , "read" ] ) // team permissions
492- . mockResolvedValueOnce ( [ "read" , "update" ] ) ; // org permissions ( read overlaps)
491+ . mockResolvedValueOnce ( [ "create" , "read" ] ) // team permissions - create implies read
492+ . mockResolvedValueOnce ( [ "read" , "update" ] ) ; // org permissions - update implies read, explicit read
493493
494494 const result = await service . getResourcePermissions ( {
495495 userId : 1 ,
@@ -517,15 +517,16 @@ describe("PermissionCheckService", () => {
517517 customRoleId : "org_role" ,
518518 } ) ;
519519
520- mockRepository . getResourcePermissionsByRoleId . mockResolvedValueOnce ( [ "update" , "delete" ] ) ;
520+ // Update and delete imply read access
521+ mockRepository . getResourcePermissionsByRoleId . mockResolvedValueOnce ( [ "update" , "delete" , "read" ] ) ;
521522
522523 const result = await service . getResourcePermissions ( {
523524 userId : 1 ,
524525 teamId : 1 ,
525526 resource : Resource . EventType ,
526527 } ) ;
527528
528- expect ( result ) . toEqual ( [ "eventType.update" , "eventType.delete" ] ) ;
529+ expect ( result ) . toEqual ( [ "eventType.update" , "eventType.delete" , "eventType.read" ] ) ;
529530 expect ( mockRepository . getResourcePermissionsByRoleId ) . toHaveBeenCalledTimes ( 1 ) ;
530531 expect ( mockRepository . getResourcePermissionsByRoleId ) . toHaveBeenCalledWith (
531532 "org_role" ,
@@ -559,5 +560,50 @@ describe("PermissionCheckService", () => {
559560
560561 expect ( result ) . toEqual ( [ ] ) ;
561562 } ) ;
563+
564+ it ( "should enforce correct hierarchy - org permissions should take precedence over team permissions" , async ( ) => {
565+ mockFeaturesRepository . checkIfTeamHasFeature . mockResolvedValueOnce ( true ) ;
566+ mockRepository . getMembershipByUserAndTeam . mockResolvedValueOnce ( {
567+ id : 1 ,
568+ teamId : 1 ,
569+ userId : 1 ,
570+ customRoleId : "admin_team_role" ,
571+ team : { parentId : 2 } ,
572+ } ) ;
573+ mockRepository . getOrgMembership . mockResolvedValueOnce ( {
574+ id : 2 ,
575+ teamId : 2 ,
576+ userId : 1 ,
577+ customRoleId : "restricted_org_role" ,
578+ } ) ;
579+
580+ // Team role has broad permissions - CUD actions include read
581+ // Org role has restricted permissions (only read)
582+ mockRepository . getResourcePermissionsByRoleId
583+ . mockResolvedValueOnce ( [ "create" , "read" , "update" ] ) // team permissions - CRU
584+ . mockResolvedValueOnce ( [ "delete" ] ) ; // org permissions - delete only
585+
586+ const result = await service . getResourcePermissions ( {
587+ userId : 1 ,
588+ teamId : 1 ,
589+ resource : Resource . EventType ,
590+ } ) ;
591+
592+ // User gets eventType.delete because they have this in the org
593+ expect ( result ) . toEqual ( [ "eventType.create" , "eventType.read" , "eventType.update" , "eventType.delete" ] ) ;
594+
595+ // Verify both team and org permissions were fetched
596+ expect ( mockRepository . getResourcePermissionsByRoleId ) . toHaveBeenCalledTimes ( 2 ) ;
597+ expect ( mockRepository . getResourcePermissionsByRoleId ) . toHaveBeenNthCalledWith (
598+ 1 ,
599+ "admin_team_role" ,
600+ Resource . EventType
601+ ) ;
602+ expect ( mockRepository . getResourcePermissionsByRoleId ) . toHaveBeenNthCalledWith (
603+ 2 ,
604+ "restricted_org_role" ,
605+ Resource . EventType
606+ ) ;
607+ } ) ;
562608 } ) ;
563609} ) ;
0 commit comments