def test_remove_portfolio_member_ppoc(client, user_session): portfolio = PortfolioFactory.create() user = UserFactory.create() PortfolioRoleFactory.create( portfolio=portfolio, user=user, permission_sets=[ PermissionSets.get(PermissionSets.EDIT_PORTFOLIO_ADMIN) ], ) ppoc_port_role = PortfolioRoles.get(portfolio_id=portfolio.id, user_id=portfolio.owner.id) user_session(user) response = client.post( url_for( "portfolios.remove_member", portfolio_id=portfolio.id, portfolio_role_id=ppoc_port_role.id, ), follow_redirects=False, ) assert response.status_code == 404 assert (PortfolioRoles.get( portfolio_id=portfolio.id, user_id=portfolio.owner.id).status == PortfolioRoleStatus.ACTIVE)
def test_cannot_update_portfolio_ppoc_perms(client, user_session): portfolio = PortfolioFactory.create() ppoc = portfolio.owner ppoc_pf_role = PortfolioRoles.get(portfolio_id=portfolio.id, user_id=ppoc.id) user = UserFactory.create() PortfolioRoleFactory.create(portfolio=portfolio, user=user) user_session(user) assert ppoc_pf_role.has_permission_set(PermissionSets.PORTFOLIO_POC) member_perms_data = { "members_permissions-0-member_id": ppoc_pf_role.id, "members_permissions-0-perms_app_mgmt": "view_portfolio_application_management", "members_permissions-0-perms_funding": "view_portfolio_funding", "members_permissions-0-perms_reporting": "view_portfolio_reports", "members_permissions-0-perms_portfolio_mgmt": "view_portfolio_admin", } response = client.post( url_for("portfolios.edit_members", portfolio_id=portfolio.id), data=member_perms_data, follow_redirects=True, ) assert response.status_code == 404 assert ppoc_pf_role.has_permission_set(PermissionSets.PORTFOLIO_POC)
def test_user_can_access_decorator_portfolio_level(set_current_user, request_ctx): ccpo = UserFactory.create_ccpo() edit_admin = UserFactory.create() view_admin = UserFactory.create() portfolio = PortfolioFactory.create(owner=edit_admin) # factory gives view perms by default PortfolioRoleFactory.create(user=view_admin, portfolio=portfolio) request_ctx.g.portfolio = portfolio request_ctx.g.application = None @user_can_access_decorator(Permissions.EDIT_PORTFOLIO_NAME) def _edit_portfolio_name(*args, **kwargs): return True set_current_user(ccpo) assert _edit_portfolio_name(portfolio_id=portfolio.id) set_current_user(edit_admin) assert _edit_portfolio_name(portfolio_id=portfolio.id) set_current_user(view_admin) with pytest.raises(UnauthorizedError): _edit_portfolio_name(portfolio_id=portfolio.id)
def test_disabled_members_dont_show_up(session): portfolio = PortfolioFactory.create() PortfolioRoleFactory.create(portfolio=portfolio, status=PortfolioRoleStatus.ACTIVE) PortfolioRoleFactory.create(portfolio=portfolio, status=PortfolioRoleStatus.DISABLED) # should only return portfolio owner and ACTIVE member assert len(portfolio.members) == 2
def test_for_user_returns_active_portfolios_for_user(portfolio, portfolio_owner): bob = UserFactory.create() PortfolioRoleFactory.create(user=bob, portfolio=portfolio, status=PortfolioRoleStatus.ACTIVE) PortfolioFactory.create() bobs_portfolios = Portfolios.for_user(bob) assert len(bobs_portfolios) == 1
def test_portfolio_admin_screen_when_not_ppoc(client, user_session): portfolio = PortfolioFactory.create() user = UserFactory.create() permission_sets = PermissionSets.get_many( [PermissionSets.EDIT_PORTFOLIO_ADMIN, PermissionSets.VIEW_PORTFOLIO_ADMIN] ) PortfolioRoleFactory.create( portfolio=portfolio, user=user, permission_sets=permission_sets ) user_session(user) response = client.get(url_for("portfolios.admin", portfolio_id=portfolio.id)) assert response.status_code == 200 assert portfolio.name in response.data.decode() assert translate("fragments.ppoc.update_btn").encode("utf8") not in response.data
def test_unexpired_invite_is_revokable(): portfolio = PortfolioFactory.create() user = UserFactory.create() portfolio_role = PortfolioRoleFactory.create( portfolio=portfolio, user=user, status=PortfolioRoleStatus.PENDING) invite = PortfolioInvitationFactory.create(role=portfolio_role) assert invite.is_revokable
def test_rerender_admin_page_if_member_perms_form_does_not_validate( client, user_session, monkeypatch): portfolio = PortfolioFactory.create() user = UserFactory.create() role = PortfolioRoleFactory.create( user=user, portfolio=portfolio, permission_sets=[ PermissionSets.get(PermissionSets.EDIT_PORTFOLIO_ADMIN) ], ) user_session(user) form_data = { "members_permissions-0-member_id": role.id, "members_permissions-0-perms_app_mgmt": "bad input", "members_permissions-0-perms_funding": "view_portfolio_funding", "members_permissions-0-perms_reporting": "view_portfolio_reports", "members_permissions-0-perms_portfolio_mgmt": "view_portfolio_admin", } mock_route = MagicMock(return_value=("", 200, {})) monkeypatch.setattr("atst.routes.portfolios.admin.render_admin_page", mock_route) client.post(url_for("portfolios.edit_members", portfolio_id=portfolio.id), data=form_data) mock_route.assert_called()
def test_remove_portfolio_member(client, user_session): portfolio = PortfolioFactory.create() user = UserFactory.create() member = PortfolioRoleFactory.create(portfolio=portfolio, user=user) user_session(portfolio.owner) response = client.post( url_for( "portfolios.remove_member", portfolio_id=portfolio.id, portfolio_role_id=member.id, ), follow_redirects=False, ) assert response.status_code == 302 assert response.headers["Location"] == url_for( "portfolios.admin", portfolio_id=portfolio.id, _anchor="portfolio-members", fragment="portfolio-members", _external=True, ) assert (PortfolioRoles.get( portfolio_id=portfolio.id, user_id=user.id).status == PortfolioRoleStatus.DISABLED)
def test_disable_portfolio_role(): portfolio_role = PortfolioRoleFactory.create( status=PortfolioRoleStatus.ACTIVE) assert portfolio_role.status == PortfolioRoleStatus.ACTIVE PortfolioRoles.disable(portfolio_role=portfolio_role) assert portfolio_role.status == PortfolioRoleStatus.DISABLED
def test_invite_is_not_revokable_if_invite_is_not_pending(): portfolio = PortfolioFactory.create() user = UserFactory.create() portfolio_role = PortfolioRoleFactory.create( portfolio=portfolio, user=user, status=PortfolioRoleStatus.PENDING) invite = PortfolioInvitationFactory.create( role=portfolio_role, status=InvitationStatus.ACCEPTED) assert not invite.is_revokable
def test_wrong_user_accepts_invitation(): user = UserFactory.create() portfolio = PortfolioFactory.create() role = PortfolioRoleFactory.create(portfolio=portfolio) wrong_user = UserFactory.create() invite = PortfolioInvitationFactory.create(role=role, dod_id=user.dod_id) with pytest.raises(WrongUserError): PortfolioInvitations.accept(wrong_user, invite.token) assert invite.role.status == PortfolioRoleStatus.PENDING
def test_accept_invitation_twice(): portfolio = PortfolioFactory.create() user = UserFactory.create() role = PortfolioRoleFactory.create(portfolio=portfolio) invite = PortfolioInvitationFactory.create(role=role, dod_id=user.dod_id) PortfolioInvitations.accept(user, invite.token) with pytest.raises(InvitationError): PortfolioInvitations.accept(user, invite.token) assert invite.role.is_active
def test_revoke_invitation(): portfolio = PortfolioFactory.create() user = UserFactory.create() role = PortfolioRoleFactory.create(user=user, portfolio=portfolio) invite = PortfolioInvitationFactory.create(role=role, dod_id=user.dod_id) assert invite.is_pending PortfolioInvitations.revoke(invite.token) assert invite.is_revoked assert invite.role.status == PortfolioRoleStatus.DISABLED
def test_resend_invitation(session): portfolio = PortfolioFactory.create() user = UserFactory.create() role = PortfolioRoleFactory.create(portfolio=portfolio) first_invite = PortfolioInvitationFactory.create(role=role, dod_id=user.dod_id) assert first_invite.is_pending second_invite = PortfolioInvitations.resend(user, first_invite.token) assert first_invite.is_revoked assert second_invite.is_pending
def test_audit_event_for_accepted_invite(): portfolio = PortfolioFactory.create() user = UserFactory.create() role = PortfolioRoleFactory.create(portfolio=portfolio) invite = PortfolioInvitationFactory.create(role=role, dod_id=user.dod_id) invite = PortfolioInvitations.accept(user, invite.token) accepted_event = AuditLog.get_by_resource(invite.id)[0] assert "email" in accepted_event.event_details assert "dod_id" in accepted_event.event_details
def test_accept_revoked_invite(): user = UserFactory.create() portfolio = PortfolioFactory.create() role = PortfolioRoleFactory.create(portfolio=portfolio) invite = PortfolioInvitationFactory.create(status=InvitationStatus.REVOKED, role=role, dod_id=user.dod_id) with pytest.raises(InvitationError): PortfolioInvitations.accept(user, invite.token) assert invite.role.status == PortfolioRoleStatus.PENDING
def test_scoped_portfolio_for_admin_missing_view_apps_perms( portfolio_owner, portfolio): Applications.create( portfolio.owner, portfolio, "My Application 2", "My application 2", ["dev", "staging", "prod"], ) restricted_admin = UserFactory.create() PortfolioRoleFactory.create( portfolio=portfolio, user=restricted_admin, permission_sets=[PermissionSets.get(PermissionSets.VIEW_PORTFOLIO)], ) scoped_portfolio = Portfolios.get(restricted_admin, portfolio.id) assert scoped_portfolio.id == portfolio.id assert len(portfolio.applications) == 1 assert len(scoped_portfolio.applications) == 0
def test_scoped_portfolio_returns_all_applications_for_portfolio_admin( portfolio, portfolio_owner): for _ in range(5): Applications.create( portfolio.owner, portfolio, "My Application", "My application", ["dev", "staging", "prod"], ) admin = UserFactory.create() perm_sets = get_all_portfolio_permission_sets() PortfolioRoleFactory.create(user=admin, portfolio=portfolio, permission_sets=perm_sets) scoped_portfolio = Portfolios.get(admin, portfolio.id) assert len(scoped_portfolio.applications) == 5 assert len(scoped_portfolio.applications[0].environments) == 3
def test_expired_invite_is_not_revokable(): portfolio = PortfolioFactory.create() user = UserFactory.create() portfolio_role = PortfolioRoleFactory.create( portfolio=portfolio, user=user, status=PortfolioRoleStatus.PENDING) invite = PortfolioInvitationFactory.create( expiration_time=datetime.datetime.now() - datetime.timedelta(minutes=60), role=portfolio_role, ) assert not invite.is_revokable
def test_accept_invitation(): portfolio = PortfolioFactory.create() user = UserFactory.create() role = PortfolioRoleFactory.create(user=user, portfolio=portfolio) invite = PortfolioInvitations.create(portfolio.owner, role, user.to_dictionary(), commit=True) assert invite.is_pending accepted_invite = PortfolioInvitations.accept(user, invite.token) assert accepted_invite.is_accepted assert accepted_invite.role.is_active
def test_member_table_access(client, user_session): admin = UserFactory.create() portfolio = PortfolioFactory.create(owner=admin) rando = UserFactory.create() PortfolioRoleFactory.create( user=rando, portfolio=portfolio, permission_sets=[PermissionSets.get(PermissionSets.VIEW_PORTFOLIO_ADMIN)], ) url = url_for("portfolios.admin", portfolio_id=portfolio.id) # editable user_session(admin) edit_resp = client.get(url) assert "<select" in edit_resp.data.decode() # not editable user_session(rando) view_resp = client.get(url) assert "<select" not in view_resp.data.decode()
def test_no_update_member_permissions_without_edit_access( client, user_session): portfolio = PortfolioFactory.create() rando = UserFactory.create() rando_pf_role = PortfolioRoleFactory.create( user=rando, portfolio=portfolio, permission_sets=[ PermissionSets.get(PermissionSets.VIEW_PORTFOLIO_ADMIN) ], ) user = UserFactory.create() PortfolioRoleFactory.create( user=user, portfolio=portfolio, permission_sets=[ PermissionSets.get(PermissionSets.VIEW_PORTFOLIO_ADMIN) ], ) user_session(user) form_data = { "members_permissions-0-member_id": rando_pf_role.id, "members_permissions-0-perms_app_mgmt": "edit_portfolio_application_management", "members_permissions-0-perms_funding": "view_portfolio_funding", "members_permissions-0-perms_reporting": "view_portfolio_reports", "members_permissions-0-perms_portfolio_mgmt": "view_portfolio_admin", } response = client.post( url_for("portfolios.edit_members", portfolio_id=portfolio.id), data=form_data, follow_redirects=True, ) assert response.status_code == 404 assert not rando_pf_role.has_permission_set( PermissionSets.EDIT_PORTFOLIO_APPLICATION_MANAGEMENT)
def test_create_invitation(): portfolio = PortfolioFactory.create() user = UserFactory.create() role = PortfolioRoleFactory.create(user=user, portfolio=portfolio) invite = PortfolioInvitations.create(portfolio.owner, role, user.to_dictionary(), commit=True) assert invite.role == role assert invite.inviter == portfolio.owner assert invite.status == InvitationStatus.PENDING assert re.match(r"^[\w\-_]+$", invite.token) assert invite.role.status == PortfolioRoleStatus.PENDING
def test_has_portfolio_permission(): role_one = PermissionSets.get(PermissionSets.VIEW_PORTFOLIO_FUNDING) role_two = PermissionSets.get(PermissionSets.VIEW_PORTFOLIO_REPORTS) port_role = PortfolioRoleFactory.create( permission_sets=[role_one, role_two]) different_user = UserFactory.create() assert Authorization.has_portfolio_permission( port_role.user, port_role.portfolio, Permissions.VIEW_PORTFOLIO_REPORTS) assert not Authorization.has_portfolio_permission( port_role.user, port_role.portfolio, Permissions.CREATE_TASK_ORDER) assert not Authorization.has_portfolio_permission( different_user, port_role.portfolio, Permissions.VIEW_PORTFOLIO_REPORTS)
def test_does_not_count_disabled_members(session): portfolio = PortfolioFactory.create() PortfolioRoleFactory.create(portfolio=portfolio, status=PortfolioRoleStatus.ACTIVE) PortfolioRoleFactory.create(portfolio=portfolio) PortfolioRoleFactory.create(portfolio=portfolio, status=PortfolioRoleStatus.DISABLED) assert portfolio.user_count == 3
def test_update_portfolio_role_role(portfolio, portfolio_owner): user_data = { "first_name": "New", "last_name": "User", "email": "*****@*****.**", "portfolio_role": "developer", "dod_id": "1234567890", } PortfolioRoleFactory._meta.sqlalchemy_session_persistence = "flush" member = PortfolioRoleFactory.create(portfolio=portfolio) permission_sets = [PermissionSets.EDIT_PORTFOLIO_FUNDING] updated_member = Portfolios.update_member(member, permission_sets=permission_sets) assert updated_member.portfolio == portfolio
def test_user_can_access(): ccpo = UserFactory.create_ccpo() edit_admin = UserFactory.create() view_admin = UserFactory.create() portfolio = PortfolioFactory.create(owner=edit_admin) # factory gives view perms by default view_admin_pr = PortfolioRoleFactory.create(user=view_admin, portfolio=portfolio) # check a site-wide permission assert user_can_access(ccpo, Permissions.VIEW_AUDIT_LOG) with pytest.raises(UnauthorizedError): user_can_access(edit_admin, Permissions.VIEW_AUDIT_LOG) with pytest.raises(UnauthorizedError): user_can_access(view_admin, Permissions.VIEW_AUDIT_LOG) # check a portfolio view permission assert user_can_access(ccpo, Permissions.VIEW_PORTFOLIO, portfolio=portfolio) assert user_can_access(edit_admin, Permissions.VIEW_PORTFOLIO, portfolio=portfolio) assert user_can_access(view_admin, Permissions.VIEW_PORTFOLIO, portfolio=portfolio) # check a portfolio edit permission assert user_can_access(ccpo, Permissions.EDIT_PORTFOLIO_NAME, portfolio=portfolio) assert user_can_access(edit_admin, Permissions.EDIT_PORTFOLIO_NAME, portfolio=portfolio) with pytest.raises(UnauthorizedError): user_can_access(view_admin, Permissions.EDIT_PORTFOLIO_NAME, portfolio=portfolio) # check when portfolio_role is disabled PortfolioRoles.disable(portfolio_role=view_admin_pr) with pytest.raises(UnauthorizedError): user_can_access(view_admin, Permissions.EDIT_PORTFOLIO_NAME, portfolio=portfolio)
def test_accept_expired_invitation(): user = UserFactory.create() portfolio = PortfolioFactory.create() role = PortfolioRoleFactory.create(portfolio=portfolio) increment = PortfolioInvitations.EXPIRATION_LIMIT_MINUTES + 1 expiration_time = datetime.datetime.now() - datetime.timedelta( minutes=increment) invite = PortfolioInvitationFactory.create( expiration_time=expiration_time, status=InvitationStatus.PENDING, role=role, dod_id=user.dod_id, ) with pytest.raises(ExpiredError): PortfolioInvitations.accept(user, invite.token) assert invite.is_rejected assert invite.role.status == PortfolioRoleStatus.PENDING