def test_disabling_group_clears_audit(tmpdir: LocalPath, setup: SetupTest, browser: Chrome) -> None: future = datetime.utcnow() + timedelta(days=60) with setup.transaction(): setup.add_user_to_group("*****@*****.**", "some-group", role="owner") setup.add_user_to_group("*****@*****.**", "some-group") setup.create_permission("some-permission", audited=True) setup.grant_permission_to_group("some-permission", "argument", "some-group") setup.add_user_to_group("*****@*****.**", "auditors") setup.grant_permission_to_group(AUDIT_VIEWER, "", "auditors") setup.grant_permission_to_group(AUDIT_MANAGER, "", "auditors") setup.grant_permission_to_group(PERMISSION_AUDITOR, "", "auditors") with frontend_server(tmpdir, "*****@*****.**") as frontend_url: browser.get(url(frontend_url, "/audits/create")) create_page = AuditsCreatePage(browser) create_page.set_end_date(future.strftime("%m/%d/%Y")) create_page.submit() browser.get(url(frontend_url, "/groups/some-group")) group_page = GroupViewPage(browser) assert group_page.subheading == "some-group AUDIT IN PROGRESS" # Check that this created email reminder messages to the group owner. We have to refresh the # session since otherwise SQLite may not see changes. setup.reopen_database() group = Group.get(setup.session, name="some-group") assert group expected_key = f"audit-{group.id}" emails = setup.session.query(AsyncNotification).filter_by( sent=False, email="*****@*****.**").all() assert len(emails) > 0 assert all((e.key is None or e.key == expected_key for e in emails)) assert all(("Group Audit" in e.subject for e in emails)) # Now, disable the group, which should complete the audit. with frontend_server(tmpdir, "*****@*****.**") as frontend_url: browser.get(url(frontend_url, "/groups/some-group")) page = GroupViewPage(browser) audit_modal = page.get_audit_modal() audit_modal.click_close_button() page.wait_until_audit_modal_clears() page.click_disable_button() modal = page.get_disable_modal() modal.confirm() assert page.subheading == "some-group (disabled)" # And now all of the email messages should be marked sent except the immediate one (the one # that wasn't created with async_send_email). setup.reopen_database() emails = setup.session.query(AsyncNotification).filter_by( sent=False, email="*****@*****.**").all() assert len(emails) == 1 assert emails[0].key is None
def test_remove_last_owner_via_audit(tmpdir: LocalPath, setup: SetupTest, browser: Chrome) -> None: future = datetime.utcnow() + timedelta(1) with setup.transaction(): setup.add_user_to_group("*****@*****.**", "audited-team", role="owner") setup.create_permission("audited", audited=True) setup.grant_permission_to_group("audited", "", "audited-team") setup.add_user_to_group("*****@*****.**", "auditors") setup.add_user_to_group("*****@*****.**", "auditors", role="owner") setup.grant_permission_to_group(AUDIT_VIEWER, "", "auditors") setup.grant_permission_to_group(AUDIT_MANAGER, "", "auditors") setup.grant_permission_to_group(PERMISSION_AUDITOR, "", "auditors") setup.add_user_to_group("*****@*****.**", "audited-team", role="owner", expiration=future) with frontend_server(tmpdir, "*****@*****.**") as frontend_url: browser.get(url(frontend_url, "/audits/create")) create_page = AuditsCreatePage(browser) create_page.set_end_date(future.strftime("%m/%d/%Y")) create_page.submit() browser.get(url(frontend_url, "/groups/audited-team")) group_page = GroupViewPage(browser) audit_modal = group_page.get_audit_modal() audit_modal.find_member_row("*****@*****.**").set_audit_status("remove") audit_modal.confirm() assert group_page.current_url.endswith("/groups/audited-team") assert group_page.has_alert(group_ownership_policy.EXCEPTION_MESSAGE)
def test_remove_last_owner_via_audit(async_server, browser, users, groups, session): # noqa: F811 future = datetime.utcnow() + timedelta(1) add_member(groups["auditors"], users["*****@*****.**"], role="owner") add_member(groups["audited-team"], users["*****@*****.**"], role="owner", expiration=future) session.commit() fe_url = url(async_server, "/audits/create") browser.get(fe_url) page = AuditsCreatePage(browser) page.set_end_date(future.strftime("%m/%d/%Y")) page.submit() fe_url = url(async_server, "/groups/audited-team") browser.get(fe_url) page = GroupViewPage(browser) audit_modal = page.get_audit_modal() audit_modal.find_member_row("*****@*****.**").set_audit_status("remove") audit_modal.confirm() assert page.current_url.endswith("/groups/audited-team") assert page.has_text(group_ownership_policy.EXCEPTION_MESSAGE)
def test_group_create(tmpdir: LocalPath, setup: SetupTest, browser: Chrome) -> None: with frontend_server(tmpdir, "*****@*****.**") as frontend_url: browser.get(url(frontend_url, "/groups")) # First create a group from the view page with an error (an invalid name, doubling as a # test that @ in group names is rejected). This should leave that page and go to the # dedicated group creation page with the form already set up. groups_page = GroupsViewPage(browser) groups_page.click_create_group_button() create_group_modal = groups_page.get_create_group_modal() create_group_modal.set_group_name("test-group@something") create_group_modal.set_description("some description") create_group_modal.confirm() create_page = GroupCreatePage(browser) create_page.has_alert("Group names cannot contain @") create_page.set_group_name("test-group") create_page.submit() view_page = GroupViewPage(browser) assert view_page.subheading == "test-group" row = view_page.find_member_row("*****@*****.**") assert row.role == "owner" assert row.href.endswith("/users/[email protected]")
def test_service_account_lifecycle(async_server, browser): # noqa: F811 browser.get(url(async_server, "/groups/user-admins")) page = GroupViewPage(browser) page.click_add_service_account_button() page = ServiceAccountCreatePage(browser) page.set_name("my-special-service-account") page.submit() page = ServiceAccountViewPage(browser) page.click_disable_button() disable_modal = page.get_disable_modal() disable_modal.confirm() browser.get(url(async_server, "/users")) page = UsersViewPage(browser) page.click_show_disabled_users_button() page.click_show_service_accounts_button() user_row = page.find_user_row( "[email protected] (service)") user_row.click() page = ServiceAccountViewPage(browser) page.click_enable_button() page = ServiceAccountEnablePage(browser) page.select_owner("Group: user-admins") page.submit()
def test_show_group(tmpdir: LocalPath, setup: SetupTest, browser: Chrome) -> None: with setup.transaction(): setup.add_user_to_group("*****@*****.**", "team-sre", role="owner") setup.add_user_to_group("*****@*****.**", "team-sre") setup.grant_permission_to_group("ssh", "*", "team-sre") setup.grant_permission_to_group("team-sre", "foo", "team-sre") setup.grant_permission_to_group("team-sre", "bar", "team-sre") with frontend_server(tmpdir, "*****@*****.**") as frontend_url: browser.get(url(frontend_url, "/groups/team-sre")) page = GroupViewPage(browser) row = page.find_member_row("*****@*****.**") assert row.role == "owner" assert row.href.endswith("/users/[email protected]") row = page.find_member_row("*****@*****.**") assert row.role == "member" assert row.href.endswith("/users/[email protected]") rows = page.find_permission_rows("ssh") assert len(rows) == 1 assert rows[0].argument == "*" assert rows[0].href.endswith("/permissions/ssh") rows = page.find_permission_rows("team-sre") for permission_row in rows: assert permission_row.href.endswith("/permissions/team-sre") assert sorted([r.argument for r in rows]) == ["bar", "foo"]
def test_request_permission(tmpdir: LocalPath, setup: SetupTest, browser: Chrome) -> None: with setup.transaction(): setup.add_user_to_group("*****@*****.**", "some-group", "owner") setup.create_permission("some-permission") setup.add_user_to_group("*****@*****.**", "admins") setup.grant_permission_to_group(PERMISSION_GRANT, "some-permission", "admins") with frontend_server(tmpdir, "*****@*****.**") as frontend_url: browser.get(url(frontend_url, "/groups/some-group")) group_page = GroupViewPage(browser) group_page.click_request_permission_button() request_page = PermissionRequestPage(browser) request_page.set_permission("some-permission") request_page.set_argument_freeform("some-argument") request_page.set_reason("testing") request_page.submit() assert browser.current_url.endswith("/permissions/requests/1") update_page = PermissionRequestUpdatePage(browser) assert update_page.has_text("some-group") assert update_page.has_text("some-argument") assert update_page.has_text("testing")
def test_require_clickthru(tmpdir: LocalPath, setup: SetupTest, browser: Chrome) -> None: with frontend_server(tmpdir, "*****@*****.**") as frontend_url: browser.get(url(frontend_url, "/groups")) groups_page = GroupsViewPage(browser) groups_page.click_create_group_button() create_group_modal = groups_page.get_create_group_modal() create_group_modal.set_group_name("test-group") create_group_modal.set_join_policy(GroupJoinPolicy.CAN_JOIN) create_group_modal.click_require_clickthru_checkbox() create_group_modal.confirm() with frontend_server(tmpdir, "*****@*****.**") as frontend_url: browser.get(url(frontend_url, "/groups/test-group/join")) join_page = GroupJoinPage(browser) join_page.set_reason("Testing") join_page.submit() clickthru_modal = join_page.get_clickthru_modal() clickthru_modal.confirm() group_page = GroupViewPage(browser) assert group_page.current_url.endswith( "/groups/test-group?refresh=yes") assert group_page.find_member_row("*****@*****.**")
def test_service_account_lifecycle(tmpdir: LocalPath, setup: SetupTest, browser: Chrome) -> None: with setup.transaction(): setup.add_user_to_group("*****@*****.**", "user-admins") setup.add_user_to_group("*****@*****.**", "some-group") setup.grant_permission_to_group(USER_ADMIN, "", "user-admins") with frontend_server(tmpdir, "*****@*****.**") as frontend_url: browser.get(url(frontend_url, "/groups/user-admins")) group_page = GroupViewPage(browser) group_page.click_add_service_account_button() # Test with an invalid machine set. create_page = ServiceAccountCreatePage(browser) create_page.set_name("my-special-service-account") create_page.set_description("some description") create_page.set_machine_set("some machines bad-machine") create_page.submit() assert create_page.has_alert("machine_set") expected = "[email protected] has invalid machine set" assert create_page.has_alert(expected) # Fix the machine set but test with an invalid name. create_page.set_name("service@service@service") create_page.set_machine_set("some machines") create_page.submit() assert create_page.has_alert("name") # Fix the name and then creation should succeed. create_page.set_name("my-special-service-account") create_page.submit() view_page = ServiceAccountViewPage(browser) assert view_page.owner == "user-admins" assert view_page.description == "some description" assert view_page.machine_set == "some machines" view_page.click_disable_button() disable_modal = view_page.get_disable_modal() disable_modal.confirm() browser.get(url(frontend_url, "/users")) users_page = UsersViewPage(browser) users_page.click_show_disabled_users_button() users_page.click_show_service_accounts_button() user_row = users_page.find_user_row( "[email protected] (service)") user_row.click() view_page = ServiceAccountViewPage(browser) view_page.click_enable_button() enable_page = ServiceAccountEnablePage(browser) enable_page.select_owner("Group: some-group") enable_page.submit() view_page = ServiceAccountViewPage(browser) assert view_page.owner == "some-group"
def test_grant_permission(tmpdir: LocalPath, setup: SetupTest, browser: Chrome) -> None: with setup.transaction(): setup.add_user_to_group("*****@*****.**", "some-group") setup.grant_permission_to_group(PERMISSION_GRANT, "some-permission", "some-group") setup.create_permission("some-permission") setup.create_group("other-group") with frontend_server(tmpdir, "*****@*****.**") as frontend_url: browser.get(url(frontend_url, "/groups/some-group")) group_page = GroupViewPage(browser) assert group_page.find_permission_rows("some-permission") == [] group_page.click_add_permission_button() grant_page = PermissionGrantPage(browser) grant_page.set_permission("some-permission") grant_page.set_argument("foo") grant_page.submit() rows = group_page.find_permission_rows("some-permission") assert len(rows) == 1 assert rows[0].argument == "foo" # Grant a permission with surrounding and internal whitespace to test whitespace handling. browser.get(url(frontend_url, "/groups/other-group")) assert group_page.find_permission_rows("some-permission") == [] group_page.click_add_permission_button() grant_page.set_permission("some-permission") grant_page.set_argument(" arg u ment ") grant_page.submit() rows = group_page.find_permission_rows("some-permission") assert len(rows) == 1 assert rows[0].argument in ("arg u ment", "arg u ment" ) # browser messes with whitespace # Check directly in the database to make sure the whitespace is stripped, since we may not be # able to see it via the browser. We need to explicitly reopen the database since otherwise # SQLite doesn't always see changes written by the frontend. setup.reopen_database() permission_grant_repository = setup.sql_repository_factory.create_permission_grant_repository( ) grants = permission_grant_repository.permission_grants_for_group( "other-group") assert grants == [ GroupPermissionGrant( group="other-group", permission="some-permission", argument="arg u ment", granted_on=ANY, is_alias=False, grant_id=ANY, ) ]
def test_show_group_hides_aliased_permissions(async_server, browser): # noqa: F811 fe_url = url(async_server, "/groups/sad-team") browser.get(fe_url) page = GroupViewPage(browser) assert len(page.find_permission_rows("owner", "sad-team")) == 1 assert page.find_permission_rows("ssh", "owner=sad-team") == [] assert page.find_permission_rows("sudo", "sad-team") == []
def test_disable_must_be_owner(tmpdir: LocalPath, setup: SetupTest, browser: Chrome) -> None: with setup.transaction(): setup.add_user_to_group("*****@*****.**", "some-group", role="owner") setup.add_user_to_group("*****@*****.**", "some-group") with frontend_server(tmpdir, "*****@*****.**") as frontend_url: browser.get(url(frontend_url, "/groups/some-group")) page = GroupViewPage(browser) with pytest.raises(NoSuchElementException): page.click_disable_button()
def test_leave_as_last_owner(tmpdir: LocalPath, setup: SetupTest, browser: Chrome) -> None: with setup.transaction(): setup.add_user_to_group("*****@*****.**", "some-group", role="owner") setup.add_user_to_group("*****@*****.**", "some-group", role="manager") with frontend_server(tmpdir, "*****@*****.**") as frontend_url: browser.get(url(frontend_url, "/groups/some-group")) view_page = GroupViewPage(browser) with pytest.raises(NoSuchElementException): view_page.click_leave_button()
def test_disable(tmpdir: LocalPath, setup: SetupTest, browser: Chrome) -> None: with setup.transaction(): setup.add_user_to_group("*****@*****.**", "some-group", role="owner") with frontend_server(tmpdir, "*****@*****.**") as frontend_url: browser.get(url(frontend_url, "/groups/some-group")) page = GroupViewPage(browser) page.click_disable_button() modal = page.get_disable_modal() modal.confirm() assert page.subheading == "some-group (disabled)"
def test_rename(tmpdir: LocalPath, setup: SetupTest, browser: Chrome) -> None: with setup.transaction(): setup.add_user_to_group("*****@*****.**", "some-group", role="owner") with frontend_server(tmpdir, "*****@*****.**") as frontend_url: browser.get(url(frontend_url, "/groups/some-group")) view_page = GroupViewPage(browser) view_page.click_edit_button() edit_page = GroupEditPage(browser) edit_page.set_name("other-group") edit_page.submit() assert browser.current_url.endswith("?refresh=yes") assert view_page.subheading == "other-group"
def test_show_group_hides_aliased_permissions( tmpdir: LocalPath, setup: SetupTest, browser: Chrome ) -> None: with setup.transaction(): setup.add_user_to_group("*****@*****.**", "sad-team", role="owner") setup.create_permission("ssh") setup.create_permission("sudo") setup.grant_permission_to_group("owner", "sad-team", "sad-team") with frontend_server(tmpdir, "*****@*****.**") as frontend_url: browser.get(url(frontend_url, "/groups/sad-team")) page = GroupViewPage(browser) assert len(page.find_permission_rows("owner", "sad-team")) == 1 assert page.find_permission_rows("ssh", "owner=sad-team") == [] assert page.find_permission_rows("sudo", "sad-team") == []
def test_group_join_as_owner(tmpdir: LocalPath, setup: SetupTest, browser: Chrome) -> None: with setup.transaction(): setup.create_group("some-group", join_policy=GroupJoinPolicy.CAN_JOIN) with frontend_server(tmpdir, "*****@*****.**") as frontend_url: browser.get(url(frontend_url, "/groups/some-group/join")) join_page = GroupJoinPage(browser) join_page.set_role("Owner") join_page.set_reason("Testing") join_page.submit() view_page = GroupViewPage(browser) with pytest.raises(NoSuchElementException): view_page.find_member_row("*****@*****.**")
def test_expire_last_owner(async_server, browser): # noqa: F811 fe_url = url(async_server, "/groups/sad-team") browser.get(fe_url) page = GroupViewPage(browser) row = page.find_member_row("*****@*****.**") row.click_edit_button() page = GroupEditMemberPage(browser) page.set_expiration("12/31/2999") page.set_reason("Unit Testing") page.submit() assert page.current_url.endswith("/groups/sad-team/edit/user/[email protected]") assert page.has_text(group_ownership_policy.EXCEPTION_MESSAGE)
def test_edit_member_group_role(tmpdir: LocalPath, setup: SetupTest, browser: Chrome) -> None: with setup.transaction(): setup.add_user_to_group("*****@*****.**", "some-group", role="owner") setup.add_group_to_group("other-group", "some-group") with frontend_server(tmpdir, "*****@*****.**") as frontend_url: browser.get(url(frontend_url, "/groups/some-group")) view_page = GroupViewPage(browser) row = view_page.find_member_row("other-group") assert row.role == "member" row.click_edit_button() edit_page = GroupEditMemberPage(browser) with pytest.raises(NoSuchElementException): edit_page.set_role("Owner")
def test_group_join_group(tmpdir: LocalPath, setup: SetupTest, browser: Chrome) -> None: with setup.transaction(): setup.add_user_to_group("*****@*****.**", "some-group", "owner") setup.create_group("parent-group", join_policy=GroupJoinPolicy.CAN_JOIN) with frontend_server(tmpdir, "*****@*****.**") as frontend_url: browser.get(url(frontend_url, "/groups/parent-group/join")) join_page = GroupJoinPage(browser) join_page.set_member("some-group") join_page.set_reason("Testing") join_page.submit() group_page = GroupViewPage(browser) assert group_page.find_member_row("some-group")
def test_remove_last_owner(async_server, browser): # noqa: F811 fe_url = url(async_server, "/groups/team-sre") browser.get(fe_url) page = GroupViewPage(browser) row = page.find_member_row("*****@*****.**") assert row.role == "owner" row.click_remove_button() modal = page.get_remove_user_modal() modal.confirm() row = page.find_member_row("*****@*****.**") assert row.role == "owner" assert page.has_text(group_ownership_policy.EXCEPTION_MESSAGE)
def test_remove_member(async_server, browser): # noqa: F811 fe_url = url(async_server, "/groups/team-sre") browser.get(fe_url) page = GroupViewPage(browser) row = page.find_member_row("*****@*****.**") assert row.role == "member" row.click_remove_button() modal = page.get_remove_user_modal() modal.confirm() assert page.current_url.endswith("/groups/team-sre?refresh=yes") with pytest.raises(NoSuchElementException): assert page.find_member_row("*****@*****.**")
def test_show_group(async_server, browser, groups): # noqa: F811 group = groups["team-sre"] fe_url = url(async_server, "/groups/{}".format(group.name)) browser.get(fe_url) page = GroupViewPage(browser) members = group.my_members() for [_, username], _ in members.iteritems(): row = page.find_member_row(username) assert row.href.endswith("/users/{}".format(username)) for permission in group.my_permissions(): rows = page.find_permission_rows(permission.name) assert len(rows) == 1 assert rows[0].argument == permission.argument assert rows[0].href.endswith("/permissions/{}".format(permission.name))
def test_rename_name_conflict(tmpdir: LocalPath, setup: SetupTest, browser: Chrome) -> None: with setup.transaction(): setup.add_user_to_group("*****@*****.**", "some-group", role="owner") setup.create_group("other-group") setup.disable_group("other-group") with frontend_server(tmpdir, "*****@*****.**") as frontend_url: browser.get(url(frontend_url, "/groups/some-group")) view_page = GroupViewPage(browser) view_page.click_edit_button() edit_page = GroupEditPage(browser) edit_page.set_name("other-group") edit_page.submit() assert edit_page.has_alert( "A group named 'other-group' already exists")
def test_leave(tmpdir: LocalPath, setup: SetupTest, browser: Chrome) -> None: with setup.transaction(): setup.add_user_to_group("*****@*****.**", "some-group") with frontend_server(tmpdir, "*****@*****.**") as frontend_url: browser.get(url(frontend_url, "/groups/some-group")) view_page = GroupViewPage(browser) assert view_page.find_member_row("*****@*****.**") view_page.click_leave_button() leave_page = GroupLeavePage(browser) assert leave_page.subheading == "Leave (some-group)" leave_page.submit() assert browser.current_url.endswith("/groups/some-group?refresh=yes") with pytest.raises(NoSuchElementException): view_page.find_member_row("*****@*****.**")
def test_remove_last_owner(tmpdir: LocalPath, setup: SetupTest, browser: Chrome) -> None: with setup.transaction(): setup.add_user_to_group("*****@*****.**", "team-sre", role="owner") setup.add_user_to_group("*****@*****.**", "admins") setup.grant_permission_to_group(GROUP_ADMIN, "", "admins") with frontend_server(tmpdir, "*****@*****.**") as frontend_url: browser.get(url(frontend_url, "/groups/team-sre")) page = GroupViewPage(browser) row = page.find_member_row("*****@*****.**") assert row.role == "owner" row.click_remove_button() modal = page.get_remove_user_modal() modal.confirm() row = page.find_member_row("*****@*****.**") assert row.role == "owner" assert page.has_alert(group_ownership_policy.EXCEPTION_MESSAGE)
def test_remove_member(tmpdir: LocalPath, setup: SetupTest, browser: Chrome) -> None: with setup.transaction(): setup.add_user_to_group("*****@*****.**", "team-sre", role="owner") setup.add_user_to_group("*****@*****.**", "team-sre") with frontend_server(tmpdir, "*****@*****.**") as frontend_url: browser.get(url(frontend_url, "/groups/team-sre")) page = GroupViewPage(browser) row = page.find_member_row("*****@*****.**") assert row.role == "member" row.click_remove_button() modal = page.get_remove_user_modal() modal.confirm() assert page.current_url.endswith("/groups/team-sre?refresh=yes") with pytest.raises(NoSuchElementException): assert page.find_member_row("*****@*****.**")
def test_end_to_end_whitespace_in_argument(tmpdir, setup, browser): # type: (LocalPath, SetupTest, Chrome) -> None with setup.transaction(): setup.create_group("some-group") setup.create_permission("some-permission") setup.add_user_to_group("*****@*****.**", "some-group", "owner") setup.add_user_to_group("*****@*****.**", "admins") setup.grant_permission_to_group(PERMISSION_GRANT, "some-permission", "admins") with frontend_server(tmpdir, "*****@*****.**") as frontend_url: browser.get(url(frontend_url, "/permissions/some-permission")) permission_page = PermissionPage(browser) assert permission_page.subheading == "some-permission" permission_page.button_to_request_this_permission.click() permission_request_page = PermissionRequestPage(browser) permission_request_page.set_group("some-group") permission_request_page.set_argument_freeform(" arg u ment ") permission_request_page.set_reason("testing whitespace") permission_request_page.submit() with frontend_server(tmpdir, "*****@*****.**") as frontend_url: browser.get(url(frontend_url, "/permissions/requests?status=pending")) requests_page = PermissionRequestsPage(browser) request_rows = requests_page.request_rows assert len(request_rows) == 1 request = request_rows[0] request.click_modify_link() modify_page = PermissionRequestUpdatePage(browser) modify_page.set_status("actioned") modify_page.set_reason("testing whitespace") modify_page.submit() browser.get(url(frontend_url, "/groups/some-group?refresh=yes")) group_page = GroupViewPage(browser) permission_rows = group_page.find_permission_rows("some-permission") assert len(permission_rows) == 1 grant = permission_rows[0] assert grant.name == "some-permission" assert grant.argument in ("arg u ment", "arg u ment") # browser messes with whitespace assert grant.source == "(direct)" # Check directly in the database to make sure the whitespace is stripped, since we may not be # able to see it via the browser. We need to explicitly reopen the database since otherwise # SQLite doesn't always see changes written by the frontend. setup.reopen_database() permission_grant_repository = setup.sql_repository_factory.create_permission_grant_repository() grants = permission_grant_repository.permission_grants_for_group("some-group") assert grants == [ GroupPermissionGrant( group="some-group", permission="some-permission", argument="arg u ment", granted_on=ANY, is_alias=False, grant_id=ANY, ) ]