@@ -665,6 +665,91 @@ def test_group_membership_grant_auth0_role_not_approved(status, test_auth0_clien
665665 membership_request .grant_auth0_role (test_auth0_client )
666666
667667
668+ @respx .mock
669+ def test_group_membership_revoke_auth0_role (test_auth0_client , persistent_factories ):
670+ group = BiocommonsGroupFactory .create_sync (group_id = "biocommons/group/tsi" , admin_roles = [])
671+ user = BiocommonsUserFactory .create_sync (group_memberships = [])
672+ membership = GroupMembershipFactory .create_sync (group = group , user = user , approval_status = ApprovalStatusEnum .APPROVED .value )
673+ role_data = RoleDataFactory .build (name = group .group_id )
674+ role_lookup = respx .get (
675+ "https://auth0.example.com/api/v2/roles" ,
676+ params = {"name_filter" : group .group_id }
677+ ).respond (status_code = 200 , json = [role_data .model_dump (mode = "json" )])
678+ route = respx .delete (f"https://auth0.example.com/api/v2/users/{ user .id } /roles" ).respond (status_code = 200 )
679+ assert membership .revoke_auth0_role (test_auth0_client )
680+ assert role_lookup .called
681+ assert route .called
682+
683+
684+ @respx .mock
685+ def test_group_membership_revoke_updates_state (test_db_session , test_auth0_client , persistent_factories ):
686+ group = BiocommonsGroupFactory .create_sync (group_id = "biocommons/group/tsi" , admin_roles = [])
687+ admin = BiocommonsUserFactory .create_sync ()
688+ user = BiocommonsUserFactory .create_sync (group_memberships = [])
689+ membership = GroupMembershipFactory .create_sync (group = group , user = user , approval_status = ApprovalStatusEnum .APPROVED .value )
690+ role_data = RoleDataFactory .build (name = group .group_id )
691+ respx .get (
692+ "https://auth0.example.com/api/v2/roles" ,
693+ params = {"name_filter" : group .group_id }
694+ ).respond (status_code = 200 , json = [role_data .model_dump (mode = "json" )])
695+ route = respx .delete (f"https://auth0.example.com/api/v2/users/{ user .id } /roles" ).respond (status_code = 200 )
696+
697+ result = membership .revoke (
698+ auth0_client = test_auth0_client ,
699+ reason = "No longer required" ,
700+ updated_by = admin ,
701+ session = test_db_session ,
702+ )
703+
704+ assert result is True
705+ assert route .called
706+ test_db_session .refresh (membership )
707+ assert membership .approval_status == ApprovalStatusEnum .REVOKED
708+ assert membership .revocation_reason == "No longer required"
709+ assert membership .updated_by_id == admin .id
710+
711+
712+ @pytest .mark .parametrize ("status" , ["pending" , "revoked" ])
713+ @respx .mock
714+ def test_group_membership_revoke_skips_auth0_when_not_approved (status , test_db_session , test_auth0_client , persistent_factories ):
715+ group = BiocommonsGroupFactory .create_sync (group_id = "biocommons/group/tsi" , admin_roles = [])
716+ admin = BiocommonsUserFactory .create_sync ()
717+ user = BiocommonsUserFactory .create_sync (group_memberships = [])
718+ membership = GroupMembershipFactory .create_sync (group = group , user = user , approval_status = status )
719+ role_lookup = respx .get (
720+ "https://auth0.example.com/api/v2/roles" ,
721+ params = {"name_filter" : group .group_id }
722+ ).respond (status_code = 200 , json = [])
723+
724+ result = membership .revoke (
725+ auth0_client = test_auth0_client ,
726+ reason = "Policy update" ,
727+ updated_by = admin ,
728+ session = test_db_session ,
729+ )
730+
731+ assert result is False
732+ assert not role_lookup .called
733+ test_db_session .refresh (membership )
734+ assert membership .approval_status == ApprovalStatusEnum .REVOKED
735+ assert membership .revocation_reason == "Policy update"
736+ assert membership .updated_by_id == admin .id
737+
738+
739+ @pytest .mark .parametrize ("status" , ["pending" , "revoked" ])
740+ @respx .mock
741+ def test_group_membership_revoke_auth0_role_not_approved (status , test_auth0_client , persistent_factories ):
742+ group = BiocommonsGroupFactory .create_sync (group_id = "biocommons/group/tsi" , admin_roles = [])
743+ user = Auth0UserDataFactory .build ()
744+ membership = GroupMembershipFactory .create_sync (group = group , user_id = user .user_id , approval_status = status )
745+ role_lookup = respx .get (
746+ "https://auth0.example.com/api/v2/roles" ,
747+ params = {"name_filter" : group .group_id }
748+ ).respond (status_code = 200 , json = [])
749+ assert membership .revoke_auth0_role (test_auth0_client ) is False
750+ assert not role_lookup .called
751+
752+
668753def test_group_membership_save_with_history (test_db_session , persistent_factories ):
669754 group = BiocommonsGroupFactory .create_sync ()
670755 membership = GroupMembershipFactory .build (group_id = group .group_id )
0 commit comments