def user_admin_perm_to_auditors(session, groups): # noqa: F811 """Adds a USER_ADMIN permission to the "auditors" group""" user_admin_perm, is_new = get_or_create_permission( session, USER_ADMIN, description="grouper.admin.users permission") session.commit() grant_permission(groups["auditors"], user_admin_perm)
def test_graph_desc_to_ances(session, graph, users, groups): # noqa: F811 """ Test adding members where all descendants already exist.""" setup_desc_to_ances(session, users, groups) session.commit() graph.update_from_db(session) assert get_users(graph, "team-sre") == set(["*****@*****.**", "*****@*****.**"]) assert get_users(graph, "tech-ops") == set(["*****@*****.**", "*****@*****.**"]) assert get_users(graph, "team-infra") == set(["*****@*****.**", "*****@*****.**"]) assert get_users(graph, "team-infra", cutoff=1) == set(["*****@*****.**"]) assert get_users(graph, "all-teams") == set(["*****@*****.**", "*****@*****.**", "*****@*****.**"]) assert get_users(graph, "all-teams", cutoff=1) == set(["*****@*****.**"]) assert get_groups(graph, "*****@*****.**") == set( ["team-sre", "all-teams", "tech-ops", "team-infra"] ) assert get_groups(graph, "*****@*****.**", cutoff=1) == set(["team-sre", "tech-ops", "team-infra"]) assert get_groups(graph, "*****@*****.**") == set( ["team-sre", "all-teams", "tech-ops", "team-infra"] ) assert get_groups(graph, "*****@*****.**", cutoff=1) == set(["team-sre", "tech-ops"]) assert get_groups(graph, "*****@*****.**") == set(["all-teams"]) assert get_groups(graph, "*****@*****.**", cutoff=1) == set(["all-teams"])
def user_enable_perm_to_sre(session, groups): # noqa: F811 """Adds the (USER_ENABLE, *) permission to the group `team-sre` """ user_enable_perm, is_new = get_or_create_permission( session, USER_ENABLE, description="grouper.user.enable perm") session.commit() grant_permission(groups["team-sre"], user_enable_perm, argument="*")
def test_group_logdump(session, tmpdir, users, groups): # noqa: F811 groupname = "team-sre" group_id = groups[groupname].id yesterday = date.today() - timedelta(days=1) fn = tmpdir.join("out.csv").strpath call_main( session, tmpdir, "group", "log_dump", groupname, yesterday.isoformat(), "--outfile", fn ) with open(fn, "r") as fh: out = fh.read() assert not out, "nothing yet" AuditLog.log( session, users["*****@*****.**"].id, "make_noise", "making some noise", on_group_id=group_id ) session.commit() call_main( session, tmpdir, "group", "log_dump", groupname, yesterday.isoformat(), "--outfile", fn ) with open(fn, "r") as fh: entries = [x for x in csv.reader(fh)] assert len(entries) == 1, "should capture our new audit log entry" log_time, actor, description, action, extra = entries[0] assert groupname in extra
def test_basic_request(graph, groups, permissions, session, standard_graph, users): # noqa: F811 group_sre = groups["team-sre"] group_not_sre = [g for name, g in groups.items() if name != "team-sre"] assert not any([ get_requests_by_group(session, group, status="pending").all() for group in groups.values() if not is_role_user(session, group=group) ]), "no group should start with pending requests" group_sre.add_member(users["*****@*****.**"], users["*****@*****.**"], reason="for the lulz") session.commit() request_not_sre = [ get_requests_by_group(session, group, status="pending").all() for group in group_not_sre ] assert not any( request_not_sre), "only affected group should show pending requests" request_sre = get_requests_by_group(session, group_sre, status="pending").all() assert len(request_sre) == 1, "affected group should have request" request = session.query(Request).filter_by(id=request_sre[0].id).scalar() request.update_status(users["*****@*****.**"], "actioned", "for being a good person") session.commit() assert not any([ get_requests_by_group(session, group, status="pending").all() for group in groups.values() ]), "no group should have requests after being actioned"
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_graph_desc_to_ances(session, graph, users, groups): # noqa: F811 """ Test adding members where all descendants already exist.""" setup_desc_to_ances(session, users, groups) session.commit() graph.update_from_db(session) assert get_users(graph, "team-sre") == set(["*****@*****.**", "*****@*****.**"]) assert get_users(graph, "tech-ops") == set(["*****@*****.**", "*****@*****.**"]) assert get_users(graph, "team-infra") == set(["*****@*****.**", "*****@*****.**"]) assert get_users(graph, "team-infra", cutoff=1) == set(["*****@*****.**"]) assert get_users(graph, "all-teams") == set( ["*****@*****.**", "*****@*****.**", "*****@*****.**"]) assert get_users(graph, "all-teams", cutoff=1) == set(["*****@*****.**"]) assert get_groups(graph, "*****@*****.**") == set( ["team-sre", "all-teams", "tech-ops", "team-infra"]) assert get_groups(graph, "*****@*****.**", cutoff=1) == set(["team-sre", "tech-ops", "team-infra"]) assert get_groups(graph, "*****@*****.**") == set( ["team-sre", "all-teams", "tech-ops", "team-infra"]) assert get_groups(graph, "*****@*****.**", cutoff=1) == set(["team-sre", "tech-ops"]) assert get_groups(graph, "*****@*****.**") == set(["all-teams"]) assert get_groups(graph, "*****@*****.**", cutoff=1) == set(["all-teams"])
def test_basic_request(graph, groups, permissions, session, standard_graph, users): # noqa: F811 group_sre = groups["team-sre"] group_not_sre = [g for name, g in iteritems(groups) if name != "team-sre"] assert not any( [ get_requests_by_group(session, group, status="pending").all() for group in itervalues(groups) ] ), "no group should start with pending requests" group_sre.add_member(users["*****@*****.**"], users["*****@*****.**"], reason="for the lulz") session.commit() request_not_sre = [ get_requests_by_group(session, group, status="pending").all() for group in group_not_sre ] assert not any(request_not_sre), "only affected group should show pending requests" request_sre = get_requests_by_group(session, group_sre, status="pending").all() assert len(request_sre) == 1, "affected group should have request" request = session.query(Request).filter_by(id=request_sre[0].id).scalar() request.update_status(users["*****@*****.**"], "actioned", "for being a good person") session.commit() assert not any( [ get_requests_by_group(session, group, status="pending").all() for group in itervalues(groups) ] ), "no group should have requests after being actioned"
def test_group_logdump(session, tmpdir, users, groups): # noqa: F811 groupname = "team-sre" group_id = groups[groupname].id yesterday = date.today() - timedelta(days=1) fn = tmpdir.join("out.csv").strpath call_main(session, tmpdir, "group", "log_dump", groupname, yesterday.isoformat(), "--outfile", fn) with open(fn, "r") as fh: out = fh.read() assert not out, "nothing yet" AuditLog.log(session, users["*****@*****.**"].id, "make_noise", "making some noise", on_group_id=group_id) session.commit() call_main(session, tmpdir, "group", "log_dump", groupname, yesterday.isoformat(), "--outfile", fn) with open(fn, "r") as fh: entries = [x for x in csv.reader(fh)] assert len(entries) == 1, "should capture our new audit log entry" log_time, actor, description, action, extra = entries[0] assert groupname in extra
def test_request_emails_reference( session, groups, permissions, users, base_url, http_client # noqa: F811 ): tech = groups["tech-ops"] tech.canjoin = "canask" tech.add(session) session.commit() # Explicitly requery because pulling from the users dict causes DetachedSessionErrors user = session.query(User).filter_by(username="******").scalar() fe_url = url(base_url, "/groups/{}/join".format(tech.groupname)) resp = yield http_client.fetch( fe_url, method="POST", body=urlencode({ "reason": "Test Request Please Ignore", "member": "User: {}".format(user.name) }), headers={"X-Grouper-User": user.username}, ) assert resp.code == 200 zay_emails = _get_unsent_and_mark_as_sent_emails_with_username( session, "*****@*****.**") assert any(["References: " in email.body for email in zay_emails])
def test_custom_json_serializer(session, app): # noqa user, prompt = make_user(), make_prompt() composition = make_composition(user=user, prompt=prompt) session.add_all([user, prompt, composition]) session.commit() jsonified = jsonify(composition) output = json.loads(jsonified.data.decode()) assert output['created_at'] == composition.created_at.isoformat()
def grantable_permissions(session, standard_graph): # noqa: F811 perm_grant = create_permission(session, PERMISSION_GRANT) perm0 = create_permission(session, "grantable") perm1 = create_permission(session, "grantable.one") perm2 = create_permission(session, "grantable.two") session.commit() return perm_grant, perm0, perm1, perm2
def user_enable_perm_to_sre(session, groups): # noqa: F811 """Adds the (USER_ENABLE, *) permission to the group `team-sre` """ user_enable_perm, is_new = get_or_create_permission( session, USER_ENABLE, description="grouper.user.enable perm" ) session.commit() grant_permission(groups["team-sre"], user_enable_perm, argument="*")
def test_current_user(db, session): user = User(name="sam", institution="UofM") entry = Entry(description="desc", template="temp", user=user) session.add_all([user, entry]) session.commit() current_users = [user[0] for user in db.session.query(User.name).all()] assert user.name in current_users
def user_admin_perm_to_auditors(session, groups): # noqa: F811 """Adds a USER_ADMIN permission to the "auditors" group""" user_admin_perm, is_new = get_or_create_permission( session, USER_ADMIN, description="grouper.admin.users permission" ) session.commit() grant_permission(groups["auditors"], user_admin_perm)
def test_grant_permission_to_tag(users, http_client, base_url, session): # noqa: F811 user = session.query(User).filter_by(username="******").scalar() perm = create_permission(session, TAG_EDIT) session.commit() grant_permission( session.query(Group).filter_by(groupname="all-teams").scalar(), get_permission(session, TAG_EDIT), "*", ) fe_url = url(base_url, "/tags") resp = yield http_client.fetch( fe_url, method="POST", body=urlencode({"tagname": "tyler_was_here", "description": "Test Tag Please Ignore"}), headers={"X-Grouper-User": user.username}, ) tag = PublicKeyTag.get(session, name="tyler_was_here") user = session.query(User).filter_by(username="******").scalar() fe_url = url(base_url, "/permissions/grant_tag/{}".format(tag.name)) resp = yield http_client.fetch( fe_url, method="POST", body=urlencode({"permission": TAG_EDIT, "argument": "*"}), headers={"X-Grouper-User": user.username}, ) assert resp.code == 200 tag = PublicKeyTag.get(session, name="tyler_was_here") perm = get_permission(session, TAG_EDIT) assert ( len(get_public_key_tag_permissions(session, tag)) == 1 ), "The tag should have exactly 1 permission" assert ( get_public_key_tag_permissions(session, tag)[0].name == perm.name ), "The tag's permission should be the one we added" assert ( get_public_key_tag_permissions(session, tag)[0].argument == "*" ), "The tag's permission should be the one we added" # Make sure trying to add a permission to a tag doesn't fail horribly if it's already there user = session.query(User).filter_by(username="******").scalar() fe_url = url(base_url, "/permissions/grant_tag/{}".format(tag.name)) resp = yield http_client.fetch( fe_url, method="POST", body=urlencode({"permission": TAG_EDIT, "argument": "*"}), headers={"X-Grouper-User": user.username}, ) assert resp.code == 200
def _get_unsent_emails_and_send(session): # noqa: F811 """Helper to count unsent emails and then mark them as sent.""" emails = session.query(AsyncNotification).filter_by(sent=False).all() for email in emails: email.sent = True session.commit() return emails
def _get_unsent_and_mark_as_sent_emails_with_username(session, username): # noqa: F811 """Helper to count unsent emails and then mark them as sent.""" emails = session.query(AsyncNotification).filter_by(sent=False, email=username).all() for email in emails: email.sent = True session.commit() return emails
def test_created_at(app, db, session): # noqa u = make_user() p1 = make_prompt(date=dt.date.today() - dt.timedelta(days=1)) p2 = make_prompt(date=dt.date.today()) c1 = make_composition(user=u, prompt=p1) c2 = make_composition(user=u, prompt=p2) session.add_all([u, p1, p2, c1, c2]) session.commit() assert type(c1.created_at) is dt.datetime
def test_feed_accessible_with_login(client, session): # noqa u = make_user() session.add(u) session.commit() with client.session_transaction() as sess: sess['user_id'] = str(u.id) res = client.get(flask.url_for('routes.get_feed_route')) assert res.status_code == 200
def test_many_many_relationship(db, session): user = User(name="sam", institution="UofM") entry = Entry(description="desc", template="temp", user_saves=user) session.add_all([user, entry]) session.commit() assert entry in user.saved_entries assert user in entry.user_saves
def test_add_friends_from_fb_ids(app, db, session): # noqa u1, u2, u3, u4, u5 = make_users(5) session.add_all([u1, u2, u3, u4, u5]) session.commit() u1.add_friends_from_fb_ids(['fb2', 'fb3', 'fb6']) assert set(u1.all_friends) == set([u2, u3]) assert set(u2.all_friends) == set([u1])
def do_action_requests(session, permissions, users, do_request_perms): # noqa: F811 # Action (approve) the request for PERM_WITH_GRANTER, and # cancel (deny) the request for PERM_NO_GRANTER. all_requests = session.query(PermissionRequest) for request in all_requests: if request.status == "pending" and request.permission.name == PERM_WITH_GRANTER: update_request(session, request, users[GRANTING_USER], "actioned", REASON) if request.status == "pending" and request.permission.name == PERM_NO_GRANTER: update_request(session, request, users[ADMIN_USER], "cancelled", REASON) session.commit()
def test_revoke_permission_from_tag(users, http_client, base_url, session): # noqa: F811 user = session.query(User).filter_by(username="******").scalar() create_permission(session, TAG_EDIT) session.commit() grant_permission( session.query(Group).filter_by(groupname="all-teams").scalar(), get_permission(session, TAG_EDIT), "*", ) fe_url = url(base_url, "/tags") resp = yield http_client.fetch( fe_url, method="POST", body=urlencode({"tagname": "tyler_was_here", "description": "Test Tag Please Ignore"}), headers={"X-Grouper-User": user.username}, ) tag = PublicKeyTag.get(session, name="tyler_was_here") user = session.query(User).filter_by(username="******").scalar() fe_url = url(base_url, "/permissions/grant_tag/{}".format(tag.name)) resp = yield http_client.fetch( fe_url, method="POST", body=urlencode({"permission": TAG_EDIT, "argument": "*"}), headers={"X-Grouper-User": user.username}, ) assert resp.code == 200 tag = PublicKeyTag.get(session, name="tyler_was_here") get_permission(session, TAG_EDIT) assert ( len(get_public_key_tag_permissions(session, tag)) == 1 ), "The tag should have exactly 1 permission" user = session.query(User).filter_by(username="******").scalar() mapping = get_public_key_tag_permissions(session, tag)[0] fe_url = url(base_url, "/permissions/{}/revoke_tag/{}".format(TAG_EDIT, mapping.mapping_id)) resp = yield http_client.fetch( fe_url, method="POST", body="", headers={"X-Grouper-User": user.username} ) assert resp.code == 200 tag = PublicKeyTag.get(session, name="tyler_was_here") assert ( len(get_public_key_tag_permissions(session, tag)) == 0 ), "The tag should have no permissions"
def test_written_by_friend(session): # noqa u1, u2, u3 = make_users(3) p = make_prompt() c = make_composition(user=u1, prompt=p) session.add_all([u1, u2, u3, p, c]) session.commit() u2.all_friends.append(u1) assert u2.written_by_friend(c) is True assert u3.written_by_friend(c) is False
def test_groups_email(groups, session, graph, http_client, base_url): # noqa: F811 expected_address = "*****@*****.**" sad = groups["sad-team"] sad.email_address = expected_address session.commit() Counter.incr(session, "updates") graph.update_from_db(session) api_url = url(base_url, "/groups/{}".format(sad.name)) resp = yield http_client.fetch(api_url) body = json.loads(resp.body) assert body["data"]["group"]["contacts"]["email"] == expected_address
def test_relationship(db, session): user = User(name="Sam", institution="UofM") entry = Entry(description="Smarty", template="template", user=user) print(db.session.execute('show tables').fetchall()) print(db.session.execute('select * from entries').fetchall()) print(db.session.execute('select * from test.entries').fetchall()) session.add_all([user, entry]) session.commit() assert entry in user.submissions assert entry.user is user
def test_views(session): # noqa u1, u2, u3, u4, u5 = make_users(5) p = make_prompt() c = make_composition(user=u1, prompt=p) session.add_all([u1, u2, u3, u4, u5, p, c]) session.commit() u2.views.append(c) u4.views.append(c) assert set(c.user_views) == set([u2, u4]) assert u2.viewed(c) is True assert u3.viewed(c) is False
def test_graph_edit_role( session, graph, standard_graph, groups, users, http_client, base_url # noqa: F811 ): """Test that membership role changes are refected in the graph.""" user_role = graph.get_group_details( "tech-ops")["users"]["*****@*****.**"]["rolename"] assert user_role == "np-owner" # Ensure they are auditors so that they can be owner. add_member(groups["auditors"], users["*****@*****.**"]) session.commit() # np-owner cannot upgrade themselves to owner resp = yield http_client.fetch( url(base_url, "/groups/tech-ops/edit/user/[email protected]"), method="POST", headers={"X-Grouper-User": "******"}, body=urlencode({ "role": "owner", "reason": "testing" }), ) assert resp.code == 200 graph.update_from_db(session) user_role = graph.get_group_details( "tech-ops")["users"]["*****@*****.**"]["rolename"] assert user_role == "np-owner" # but an owner can resp = yield http_client.fetch( url(base_url, "/groups/tech-ops/edit/user/[email protected]"), method="POST", headers={"X-Grouper-User": "******"}, body=urlencode({ "role": "owner", "reason": "testing" }), ) assert resp.code == 200 graph.update_from_db(session) user_role = graph.get_group_details( "tech-ops")["users"]["*****@*****.**"]["rolename"] assert user_role == "owner"
def test_users_who_have_not_written_yet(app, db, session): # noqa user, user2, prompt = make_user(), make_user(), make_prompt() session.add_all([user, user2, prompt]) session.commit() assert set([user, user2]) == set(users_who_have_not_written_yet()) now = datetime.utcnow() two_days_ago = now - timedelta(days=2) two_minutes_ago = now - timedelta(minutes=2) make_composition(user=user, prompt=prompt, created_at=two_days_ago) assert set([user, user2]) == set(users_who_have_not_written_yet()) make_composition(user=user, prompt=prompt, created_at=two_minutes_ago) assert set([user2]) == set(users_who_have_not_written_yet())
def test_graph_cycle_indirect(session, graph, users, groups): # noqa: F811 """ Test adding a member that will create a cycle. gary zay testuser | | | sre <----- tech-ops <----- team-infra <-- | | | | --------> all-teams -------------------- """ add_member(groups["team-sre"], users["*****@*****.**"]) add_member(groups["tech-ops"], users["*****@*****.**"]) add_member(groups["team-infra"], users["*****@*****.**"]) add_member(groups["team-sre"], groups["tech-ops"]) add_member(groups["tech-ops"], groups["team-infra"]) add_member(groups["team-infra"], groups["all-teams"]) add_member(groups["all-teams"], groups["team-sre"]) session.commit() graph.update_from_db(session) all_users = set(["*****@*****.**", "*****@*****.**", "*****@*****.**"]) all_groups = set(["team-sre", "all-teams", "tech-ops", "team-infra"]) assert get_users(graph, "team-sre") == all_users assert get_users(graph, "team-sre", cutoff=1) == set(["*****@*****.**"]) assert get_users(graph, "tech-ops") == all_users assert get_users(graph, "tech-ops", cutoff=1) == set(["*****@*****.**"]) assert get_users(graph, "team-infra") == all_users assert get_users(graph, "team-infra", cutoff=1) == set(["*****@*****.**"]) assert get_users(graph, "all-teams") == all_users assert get_users(graph, "all-teams", cutoff=1) == set([]) assert get_groups(graph, "*****@*****.**") == all_groups assert get_groups(graph, "*****@*****.**", cutoff=1) == set(["team-sre"]) assert get_groups(graph, "*****@*****.**") == all_groups assert get_groups(graph, "*****@*****.**", cutoff=1) == set(["tech-ops"]) assert get_groups(graph, "*****@*****.**") == all_groups assert get_groups(graph, "*****@*****.**", cutoff=1) == set(["team-infra"])
def test_cant_revoke_last_npowner(get_plugin_proxy, session, groups, users): # noqa: F811 get_plugin_proxy.return_value = PluginProxy([GroupOwnershipPolicyPlugin()]) group = groups["team-infra"] first_owner = users["*****@*****.**"] second_owner = users["*****@*****.**"] add_member(group, first_owner, role="np-owner") add_member(group, second_owner, role="np-owner") # Revoking the first owner does not raise an exception revoke_member(group, first_owner) session.commit() with pytest.raises(PluginRejectedGroupMembershipUpdate): revoke_member(group, second_owner)
def expired_graph(session, graph, groups, users): # noqa: F811 now = datetime.utcnow() # expired user membership add_member(groups["team-sre"], users["*****@*****.**"], role="owner") add_member(groups["team-sre"], users["*****@*****.**"], expiration=now) # expired group membership add_member(groups["serving-team"], users["*****@*****.**"], role="owner") add_member(groups["serving-team"], groups["team-sre"], expiration=now) # expired user membership in disabled group add_member(groups["sad-team"], users["*****@*****.**"], expiration=now) groups["sad-team"].disable() session.commit() return graph
def test_edit_tag(users, http_client, base_url, session): # noqa: F811 user = session.query(User).filter_by(username="******").scalar() create_permission(session, TAG_EDIT) session.commit() grant_permission( session.query(Group).filter_by(groupname="all-teams").scalar(), get_permission(session, TAG_EDIT), "*", ) fe_url = url(base_url, "/tags") resp = yield http_client.fetch( fe_url, method="POST", body=urlencode({ "tagname": "tyler_was_here", "description": "Test Tag Please Ignore" }), headers={"X-Grouper-User": user.username}, ) tag = PublicKeyTag.get(session, name="tyler_was_here") assert (tag.description == "Test Tag Please Ignore" ), "The description should match what we created it with" user = session.query(User).filter_by(username="******").scalar() fe_url = url(base_url, "/tags/{}/edit".format(tag.id)) resp = yield http_client.fetch( fe_url, method="POST", body=urlencode({"description": "Don't tag me bro"}), headers={"X-Grouper-User": user.username}, ) assert resp.code == 200 tag = PublicKeyTag.get(session, name="tyler_was_here") assert tag.description == "Don't tag me bro", "The description should have been updated"
def do_request_perms(groups, permissions, session, users): # noqa: F811 # Create the two test perms + PERMISSION_GRANT + PERMISSION_ADMIN, give GRANTING_TEAM # appropriate PERMISSION_GRANT, and make sure there's an admin (has PERMISSION_ADMIN) test_perm_granter = get_or_create_permission( session, PERM_WITH_GRANTER, description="perm with granter" )[0] test_perm_nogranter = get_or_create_permission( session, PERM_NO_GRANTER, description="perm without granter" )[0] grant_perm = get_or_create_permission(session, PERMISSION_GRANT)[0] admin_perm = get_or_create_permission(session, PERMISSION_ADMIN)[0] session.commit() grant_permission( groups[GRANTING_TEAM], grant_perm, argument="{}/{}".format(PERM_WITH_GRANTER, ARGUMENT) ) grant_permission(groups[ADMIN_TEAM], admin_perm, argument="") # Request the two test perms from REQUESTING_TEAM create_request( session, users[REQUESTING_USER], groups[REQUESTING_TEAM], test_perm_granter, ARGUMENT, REASON, ) create_request( session, users[REQUESTING_USER], groups[REQUESTING_TEAM], test_perm_nogranter, ARGUMENT, REASON, ) # Finally make one more request from a user other than REQUESTING_USER create_request( session, users[GRANTING_USER], groups[GRANTING_TEAM], admin_perm, ARGUMENT, REASON ) session.commit()
def test_graph_add_member_existing(session, graph, users, groups): # noqa: F811 """ Test adding members to an existing relationship.""" add_member(groups["team-sre"], users["*****@*****.**"], role="owner") add_member(groups["tech-ops"], users["*****@*****.**"], role="owner") add_member(groups["team-infra"], users["*****@*****.**"], role="owner") add_member(groups["team-infra"], groups["team-sre"]) add_member(groups["team-infra"], groups["tech-ops"]) add_member(groups["all-teams"], users["*****@*****.**"], role="owner") add_member(groups["all-teams"], groups["team-infra"]) add_member(groups["team-sre"], users["*****@*****.**"]) add_member(groups["tech-ops"], users["*****@*****.**"]) session.commit() graph.update_from_db(session) assert get_users(graph, "team-sre") == set(["*****@*****.**", "*****@*****.**"]) assert get_users(graph, "tech-ops") == set(["*****@*****.**", "*****@*****.**"]) assert get_users(graph, "team-infra") == set(["*****@*****.**", "*****@*****.**"]) assert get_users(graph, "team-infra", cutoff=1) == set(["*****@*****.**"]) assert get_users(graph, "all-teams") == set( ["*****@*****.**", "*****@*****.**", "*****@*****.**"]) assert get_users(graph, "all-teams", cutoff=1) == set(["*****@*****.**"]) assert get_groups(graph, "*****@*****.**") == set( ["team-sre", "all-teams", "tech-ops", "team-infra"]) assert get_groups(graph, "*****@*****.**", cutoff=1) == set(["team-sre", "tech-ops", "team-infra"]) assert get_groups(graph, "*****@*****.**") == set( ["team-sre", "all-teams", "tech-ops", "team-infra"]) assert get_groups(graph, "*****@*****.**", cutoff=1) == set(["team-sre", "tech-ops"]) assert get_groups(graph, "*****@*****.**") == set(["all-teams"]) assert get_groups(graph, "*****@*****.**", cutoff=1) == set(["all-teams"])
def test_list_public_keys(async_server, browser, session, users, groups): # noqa: F811 permission = Permission.get_or_create(session, name=AUDIT_SECURITY, description="")[0] user = users["*****@*****.**"] group = groups["group-admins"] add_member(group, user, role="owner") grant_permission(group, permission, "public_keys") # Pagination defaults to 100 keys per page for i in range(120): key = PublicKey( user=user, public_key="KEY:{}".format(i), fingerprint="MD5:{}".format(i), fingerprint_sha256="SHA256:{}".format(i), key_size=4096, key_type="ssh-rsa", comment="", ) key.add(session) session.commit() fe_url = url(async_server, "/users/public-keys") browser.get(fe_url) page = PublicKeysPage(browser) row = page.find_public_key_row("SHA256:0") assert row.user == user.username assert row.key_size == "4096" assert row.key_type == "ssh-rsa" assert page.find_public_key_row("SHA256:99") with pytest.raises(NoSuchElementException): page.find_public_key_row("SHA256:100")
def test_graph_add_member_existing(session, graph, users, groups): # noqa: F811 """ Test adding members to an existing relationship.""" add_member(groups["team-sre"], users["*****@*****.**"], role="owner") add_member(groups["tech-ops"], users["*****@*****.**"], role="owner") add_member(groups["team-infra"], users["*****@*****.**"], role="owner") add_member(groups["team-infra"], groups["team-sre"]) add_member(groups["team-infra"], groups["tech-ops"]) add_member(groups["all-teams"], users["*****@*****.**"], role="owner") add_member(groups["all-teams"], groups["team-infra"]) add_member(groups["team-sre"], users["*****@*****.**"]) add_member(groups["tech-ops"], users["*****@*****.**"]) session.commit() graph.update_from_db(session) assert get_users(graph, "team-sre") == set(["*****@*****.**", "*****@*****.**"]) assert get_users(graph, "tech-ops") == set(["*****@*****.**", "*****@*****.**"]) assert get_users(graph, "team-infra") == set(["*****@*****.**", "*****@*****.**"]) assert get_users(graph, "team-infra", cutoff=1) == set(["*****@*****.**"]) assert get_users(graph, "all-teams") == set(["*****@*****.**", "*****@*****.**", "*****@*****.**"]) assert get_users(graph, "all-teams", cutoff=1) == set(["*****@*****.**"]) assert get_groups(graph, "*****@*****.**") == set( ["team-sre", "all-teams", "tech-ops", "team-infra"] ) assert get_groups(graph, "*****@*****.**", cutoff=1) == set(["team-sre", "tech-ops", "team-infra"]) assert get_groups(graph, "*****@*****.**") == set( ["team-sre", "all-teams", "tech-ops", "team-infra"] ) assert get_groups(graph, "*****@*****.**", cutoff=1) == set(["team-sre", "tech-ops"]) assert get_groups(graph, "*****@*****.**") == set(["all-teams"]) assert get_groups(graph, "*****@*****.**", cutoff=1) == set(["all-teams"])
def test_graph_cycle_direct(session, graph, users, groups): # noqa: F811 """ Test adding members where all descendants already exist.""" add_member(groups["team-sre"], users["*****@*****.**"]) add_member(groups["tech-ops"], users["*****@*****.**"]) add_member(groups["team-sre"], groups["tech-ops"]) add_member(groups["tech-ops"], groups["team-sre"]) session.commit() graph.update_from_db(session) assert get_users(graph, "team-sre") == set(["*****@*****.**", "*****@*****.**"]) assert get_users(graph, "team-sre", cutoff=1) == set(["*****@*****.**"]) assert get_users(graph, "tech-ops") == set(["*****@*****.**", "*****@*****.**"]) assert get_users(graph, "tech-ops", cutoff=1) == set(["*****@*****.**"]) assert get_groups(graph, "*****@*****.**") == set(["team-sre", "tech-ops"]) assert get_groups(graph, "*****@*****.**", cutoff=1) == set(["team-sre"]) assert get_groups(graph, "*****@*****.**") == set(["team-sre", "tech-ops"]) assert get_groups(graph, "*****@*****.**", cutoff=1) == set(["tech-ops"])
def test_request_emails_reference( session, groups, permissions, users, base_url, http_client # noqa: F811 ): tech = groups["tech-ops"] tech.canjoin = "canask" tech.add(session) session.commit() # Explicitly requery because pulling from the users dict causes DetachedSessionErrors user = session.query(User).filter_by(username="******").scalar() fe_url = url(base_url, "/groups/{}/join".format(tech.groupname)) resp = yield http_client.fetch( fe_url, method="POST", body=urlencode( {"reason": "Test Request Please Ignore", "member": "User: {}".format(user.name)} ), headers={"X-Grouper-User": user.username}, ) assert resp.code == 200 zay_emails = _get_unsent_and_mark_as_sent_emails_with_username(session, "*****@*****.**") assert any(["References: " in email.body for email in zay_emails])
def run(self, session, **kwargs): if kwargs.get("group"): Group.get_or_create(session, groupname=groupname) session.commit() elif kwargs.get("key") == "valuewith=": User.get_or_create(session, username=other_username) session.commit() else: User.get_or_create(session, username=username) session.commit()
def test_request_emails( graph, groups, permissions, session, standard_graph, users, base_url, http_client # noqa: F811 ): tech = groups["tech-ops"] tech.canjoin = "canask" tech.add(session) session.commit() # REQUEST 1 before_reqs = session.query(Request).count() # Explicitly requery because pulling from the users dict causes DetachedSessionErrors user = session.query(User).filter_by(username="******").scalar() fe_url = url(base_url, "/groups/{}/join".format(tech.groupname)) resp = yield http_client.fetch( fe_url, method="POST", body=urlencode( {"reason": "Test Request Please Ignore", "member": "User: {}".format(user.name)} ), headers={"X-Grouper-User": user.username}, ) assert resp.code == 200 zaya_emails = len(_get_unsent_and_mark_as_sent_emails_with_username(session, "*****@*****.**")) fh_emails = len(_get_unsent_and_mark_as_sent_emails_with_username(session, "*****@*****.**")) assert ( zaya_emails + fh_emails == 2 ), "Only approvers for the requested group should receive an email" assert zaya_emails == 1, "Owners should receive exactly one email per canask request" assert fh_emails == 1, "NP-Owners should receive exactly one email per canask request" assert ( session.query(Request).count() == before_reqs + 1 ), "There should only be one added request" # Explicitly requery because pulling from the users dict causes DetachedSessionErrors user = session.query(User).filter_by(username="******").scalar() request_id = ( session.query(Request).filter_by(requesting_id=tech.id, requester_id=user.id).scalar().id ) fe_url = url(base_url, "/groups/{}/requests/{}".format(tech.groupname, request_id)) resp = yield http_client.fetch( fe_url, method="POST", body=urlencode({"reason": "Test Response Please Ignore", "status": "actioned"}), headers={"X-Grouper-User": "******"}, ) assert resp.code == 200 fh_emails = len(_get_unsent_and_mark_as_sent_emails_with_username(session, "*****@*****.**")) testuser_emails = len( _get_unsent_and_mark_as_sent_emails_with_username(session, "*****@*****.**") ) assert ( fh_emails + testuser_emails == 2 ), "Only the approver that didn't action the request and the reqester should get an email" assert fh_emails == 1, "NP-owners that did not action the request should receive an email" assert ( testuser_emails == 1 ), "The requester should receive an email when the request is handled" # REQUEST 2 before_reqs = session.query(Request).count() # Explicitly requery because pulling from the users dict causes DetachedSessionErrors user = session.query(User).filter_by(username="******").scalar() fe_url = url(base_url, "/groups/{}/join".format(tech.groupname)) resp = yield http_client.fetch( fe_url, method="POST", body=urlencode( {"reason": "Test Request Please Ignore 2", "member": "User: {}".format(user.name)} ), headers={"X-Grouper-User": user.username}, ) assert resp.code == 200 zaya_emails = len(_get_unsent_and_mark_as_sent_emails_with_username(session, "*****@*****.**")) fh_emails = len(_get_unsent_and_mark_as_sent_emails_with_username(session, "*****@*****.**")) assert ( zaya_emails + fh_emails == 2 ), "Only approvers for the requested group should receive an email" assert zaya_emails == 1, "Owners should receive exactly one email per canask request" assert fh_emails == 1, "NP-Owners should receive exactly one email per canask request" assert ( session.query(Request).count() == before_reqs + 1 ), "There should only be one added request" # Explicitly requery because pulling from the users dict causes DetachedSessionErrors user = session.query(User).filter_by(username="******").scalar() request_id = ( session.query(Request).filter_by(requesting_id=tech.id, requester_id=user.id).scalar().id ) fe_url = url(base_url, "/groups/{}/requests/{}".format(tech.groupname, request_id)) resp = yield http_client.fetch( fe_url, method="POST", body=urlencode({"reason": "Test Response Please Ignore 2", "status": "actioned"}), headers={"X-Grouper-User": "******"}, ) assert resp.code == 200 zaya_emails = len(_get_unsent_and_mark_as_sent_emails_with_username(session, "*****@*****.**")) oliver_emails = len(_get_unsent_and_mark_as_sent_emails_with_username(session, "*****@*****.**")) assert ( zaya_emails + oliver_emails == 2 ), "Only the approver that didn't action the request and the reqester should get an email" assert zaya_emails == 1, "NP-owners that did not action the request should receive an email" assert oliver_emails == 1, "The requester should receive an email when the request is handled"
def test_permission_grant_to_owners( session, standard_graph, groups, grantable_permissions, permissions # noqa: F811 ): """Test we're getting correct owners according to granted 'grouper.permission.grant' permissions.""" perm_grant, _, perm1, perm2 = grantable_permissions # Disable the group with permission admin since otherwise they're an approver on everything, # and check that there are then no approvers. groups["permission-admins"].disable() session.commit() assert not get_owners_by_grantable_permission(session), "nothing to begin with" # grant a grant on a non-existent permission grant_permission(groups["auditors"], perm_grant, argument="notgrantable.one") assert not get_owners_by_grantable_permission(session), "ignore grants for non-existent perms" # grant a wildcard grant -- make sure all permissions are represented and # the grant isn't inherited grant_permission(groups["all-teams"], perm_grant, argument="grantable.*") owners_by_arg_by_perm = get_owners_by_grantable_permission(session) expected = [groups["all-teams"]] assert owners_by_arg_by_perm[perm1.name]["*"] == expected, "grants are not inherited" assert len(owners_by_arg_by_perm) == 2 assert len(owners_by_arg_by_perm[perm1.name]) == 1 assert len(owners_by_arg_by_perm[perm2.name]) == 1 # grant on argument substring grant_permission( groups["team-sre"], perm_grant, argument="{}/somesubstring*".format(perm1.name) ) owners_by_arg_by_perm = get_owners_by_grantable_permission(session) expected = [groups["all-teams"]] assert owners_by_arg_by_perm[perm1.name]["*"] == expected expected = [groups["team-sre"]] assert owners_by_arg_by_perm[perm1.name]["somesubstring*"] == expected # make sure get_owner() respect substrings res = [ o.groupname for o, a in get_owner_arg_list( session, perm1, "somesubstring", owners_by_arg_by_perm=owners_by_arg_by_perm ) ] assert sorted(res) == ["all-teams", "team-sre"], "should include substring wildcard matches" res = [ o.groupname for o, a in get_owner_arg_list( session, perm1, "othersubstring", owners_by_arg_by_perm=owners_by_arg_by_perm ) ] assert sorted(res) == ["all-teams"], "negative test of substring wildcard matches" # permission admins have all the power grant_permission(groups["security-team"], permissions[PERMISSION_ADMIN]) owners_by_arg_by_perm = get_owners_by_grantable_permission(session) all_permissions = get_all_permissions(session) for perm in all_permissions: assert perm.name in owners_by_arg_by_perm, "all permission should be represented" assert ( groups["security-team"] in owners_by_arg_by_perm[perm.name]["*"] ), "permission admin should be wildcard owners"
def test_mysql_to_sqlite(session): Base.metadata.create_all(bind=session.bind) foo = Foo(foo=1) session.add(foo) session.commit() assert [(1,)] == session.query(Foo.foo).all()
def test_aggregate_request( graph, groups, permissions, session, standard_graph, users # noqa: F811 ): gary = users["*****@*****.**"] not_involved = [ user for name, user in iteritems(users) if name not in ("*****@*****.**", "*****@*****.**") ] assert not any( [user_requests_aggregate(session, u).all() for u in itervalues(users)] ), "should have no pending requests to begin with" # one request to one team groups["team-sre"].add_member( users["*****@*****.**"], users["*****@*****.**"], reason="for the lulz" ) session.commit() assert len(user_requests_aggregate(session, gary).all()) == 1, "one pending request for owner" assert not any( [user_requests_aggregate(session, u).all() for u in not_involved] ), "no pending requests if you're not the owner" # two request to two teams, same owner groups["team-infra"].add_member( users["*****@*****.**"], users["*****@*****.**"], reason="for the lulz" ) session.commit() request_gary = user_requests_aggregate(session, gary).all() assert len(request_gary) == 2, "two pending request for owner" assert not any( [user_requests_aggregate(session, u).all() for u in not_involved] ), "no pending requests if you're not the owner" # resolving one request should reflect request = session.query(Request).filter_by(id=request_gary[0].id).scalar() request.update_status(users["*****@*****.**"], "actioned", "for being a good person") session.commit() assert len(user_requests_aggregate(session, gary).all()) == 1, "one pending request for owner" assert not any( [user_requests_aggregate(session, u).all() for u in not_involved] ), "no pending requests if you're not the owner" # requests to dependent teams should reflect apprpriately groups["security-team"].add_member( users["*****@*****.**"], users["*****@*****.**"], reason="for the lulz" ) session.commit() assert ( len(user_requests_aggregate(session, gary).all()) == 1 ), "super owner should not get request" assert ( len(user_requests_aggregate(session, users["*****@*****.**"]).all()) == 1 ), "owner should get request" user_not_gary_oliver = [ u for n, u in iteritems(users) if n not in ("*****@*****.**", "*****@*****.**") ] assert not any([user_requests_aggregate(session, u).all() for u in user_not_gary_oliver]) # manager and np-owner should get requests figurehead = users["*****@*****.**"] add_member(groups["audited-team"], figurehead, role="manager") assert ( len(user_requests_aggregate(session, figurehead).all()) == 0 ), "no request for np-owner at first" groups["tech-ops"].add_member( users["*****@*****.**"], users["*****@*****.**"], reason="for the lulz" ) assert len(user_requests_aggregate(session, figurehead).all()) == 1, "request for np-owner" groups["audited-team"].add_member( users["*****@*****.**"], users["*****@*****.**"], reason="for the lulz" ) assert ( len(user_requests_aggregate(session, figurehead).all()) == 2 ), "request for np-owner and manager"
def test_usertokens(users, session, http_client, base_url): # noqa: F811 user = users["*****@*****.**"] tok, secret = add_new_user_token(session, UserToken(user=user, name="Foo")) session.commit() api_url = url(base_url, "/token/validate") # Completely bogus input resp = yield http_client.fetch(api_url, method="POST", body=urlencode({"token": "invalid"})) body = json.loads(resp.body) assert resp.code == 200 assert body["status"] == "error" assert len(body["errors"]) == 1 assert body["errors"][0]["code"] == 1 valid_token = str(tok) + ":" + secret # Valid token resp = yield http_client.fetch(api_url, method="POST", body=urlencode({"token": valid_token})) body = json.loads(resp.body) assert resp.code == 200 assert body["status"] == "ok" assert body["data"]["identity"] == str(tok) assert body["data"]["owner"] == user.username assert body["data"]["act_as_owner"] assert body["data"]["valid"] # Token with the last character changed to something invalid bad_char = "1" if secret[-1].isalpha() else "a" token_with_bad_secret = str(tok) + ":" + secret[:-1] + bad_char resp = yield http_client.fetch( api_url, method="POST", body=urlencode({"token": token_with_bad_secret}) ) body = json.loads(resp.body) assert resp.code == 200 assert body["status"] == "error" assert len(body["errors"]) == 1 assert body["errors"][0]["code"] == 4 # Token with the token name frobbed to be something invalid token_with_bad_name = str(tok) + "z:" + secret resp = yield http_client.fetch( api_url, method="POST", body=urlencode({"token": token_with_bad_name}) ) body = json.loads(resp.body) assert resp.code == 200 assert body["status"] == "error" assert len(body["errors"]) == 1 assert body["errors"][0]["code"] == 2 # Token with the user frobbed to be something invalid token_with_bad_user = "******" + str(tok) + ":" + secret resp = yield http_client.fetch( api_url, method="POST", body=urlencode({"token": token_with_bad_user}) ) body = json.loads(resp.body) assert resp.code == 200 assert body["status"] == "error" assert len(body["errors"]) == 1 assert body["errors"][0]["code"] == 2 # Token with the user changed to another valid, but wrong user token_with_wrong_user = "******" + tok.name + ":" + secret resp = yield http_client.fetch( api_url, method="POST", body=urlencode({"token": token_with_wrong_user}) ) body = json.loads(resp.body) assert resp.code == 200 assert body["status"] == "error" assert len(body["errors"]) == 1 assert body["errors"][0]["code"] == 2 # Disabled, but otherwise valid token disable_user_token(session, tok) session.commit() resp = yield http_client.fetch(api_url, method="POST", body=urlencode({"token": valid_token})) body = json.loads(resp.body) assert resp.code == 200 assert body["status"] == "error" assert len(body["errors"]) == 1 assert body["errors"][0]["code"] == 3
def test_request_autoexpiration( graph, groups, permissions, session, standard_graph, users, base_url, http_client # noqa: F811 ): tech = groups["tech-ops"] sre = groups["team-sre"] security = groups["security-team"] sad = groups["sad-team"] infra = groups["team-infra"] tech.canjoin = "canask" tech.auto_expire = timedelta(days=5) tech.add(session) session.commit() sre.canjoin = "canjoin" sre.auto_expire = timedelta(days=500) sre.add(session) session.commit() security.canjoin = "canjoin" security.add(session) session.commit() sad.canjoin = "canjoin" sad.add(session) session.commit() infra.canjoin = "canjoin" infra.add(session) session.commit() # REQUEST 1 # Explicitly requery because pulling from the users dict causes DetachedSessionErrors user = session.query(User).filter_by(username="******").scalar() tech = session.query(Group).filter_by(groupname="tech-ops").scalar() fe_url = url(base_url, "/groups/{}/join".format(tech.groupname)) resp = yield http_client.fetch( fe_url, method="POST", body=urlencode( {"reason": "Test Request Please Ignore", "member": "User: {}".format(user.name)} ), headers={"X-Grouper-User": user.username}, ) assert resp.code == 200 # Explicitly requery because pulling from the users dict causes DetachedSessionErrors user = session.query(User).filter_by(username="******").scalar() request = ( session.query(Request).filter_by(requesting_id=tech.id, requester_id=user.id).scalar() ) assert datetime.strptime(request.changes["expiration"], "%m/%d/%Y").date() == ( datetime.utcnow().date() + tech.auto_expire ), "Request expirations should be the current date + group.auto_expire for canask groups" # REQUEST 2 # Explicitly requery because pulling from the users dict causes DetachedSessionErrors user = session.query(User).filter_by(username="******").scalar() sre = session.query(Group).filter_by(groupname="team-sre").scalar() fe_url = url(base_url, "/groups/{}/join".format(sre.groupname)) resp = yield http_client.fetch( fe_url, method="POST", body=urlencode( {"reason": "Test Request Please Ignore", "member": "User: {}".format(user.name)} ), headers={"X-Grouper-User": user.username}, ) assert resp.code == 200 # Explicitly requery because pulling from the users dict causes DetachedSessionErrors user = session.query(User).filter_by(username="******").scalar() request = session.query(Request).filter_by(requesting_id=sre.id, requester_id=user.id).scalar() assert datetime.strptime(request.changes["expiration"], "%m/%d/%Y").date() == ( datetime.utcnow().date() + sre.auto_expire ), "Request expirations should be the current date + group.auto_expire for canjoin groups" # REQUEST 3 # Explicitly requery because pulling from the users dict causes DetachedSessionErrors user = session.query(User).filter_by(username="******").scalar() security = session.query(Group).filter_by(groupname="security-team").scalar() fe_url = url(base_url, "/groups/{}/join".format(security.groupname)) resp = yield http_client.fetch( fe_url, method="POST", body=urlencode( {"reason": "Test Request Please Ignore", "member": "User: {}".format(user.name)} ), headers={"X-Grouper-User": user.username}, ) assert resp.code == 200 # Explicitly requery because pulling from the users dict causes DetachedSessionErrors user = session.query(User).filter_by(username="******").scalar() request = ( session.query(Request).filter_by(requesting_id=security.id, requester_id=user.id).scalar() ) assert "expiration" not in request.changes, ( "The request should not have an expiration if none is provided and there is no" " auto_expiration" ) # REQUEST 4 # Explicitly requery because pulling from the users dict causes DetachedSessionErrors user = session.query(User).filter_by(username="******").scalar() sad = session.query(Group).filter_by(groupname="sad-team").scalar() fe_url = url(base_url, "/groups/{}/join".format(sad.groupname)) resp = yield http_client.fetch( fe_url, method="POST", body=urlencode( { "reason": "Test Request Please Ignore", "member": "User: {}".format(user.name), "expiration": "01/19/2038", } ), headers={"X-Grouper-User": user.username}, ) assert resp.code == 200 # Explicitly requery because pulling from the users dict causes DetachedSessionErrors user = session.query(User).filter_by(username="******").scalar() request = session.query(Request).filter_by(requesting_id=sad.id, requester_id=user.id).scalar() assert datetime.strptime(request.changes["expiration"], "%m/%d/%Y").date() == date( year=2038, month=1, day=19 ), "User provided expiration times should not be overwritten by the auto_expiration" # REQUEST 5 # Explicitly requery because pulling from the users dict causes DetachedSessionErrors user = session.query(User).filter_by(username="******").scalar() infra = session.query(Group).filter_by(groupname="team-infra").scalar() fe_url = url(base_url, "/groups/{}/add".format(infra.groupname)) resp = yield http_client.fetch( fe_url, method="POST", body=urlencode( {"reason": "Test Request Please Ignore", "member": "User: {}".format(user.name)} ), headers={"X-Grouper-User": "******"}, ) assert resp.code == 200 # Explicitly requery because pulling from the users dict causes DetachedSessionErrors user = session.query(User).filter_by(username="******").scalar() request = ( session.query(Request).filter_by(requesting_id=infra.id, requester_id=user.id).scalar() ) assert "expiration" not in request.changes, ( "The request should not have an expiration if none is provided and the request was" " created by adding a member" ) # REQUEST 6 # Explicitly requery because pulling from the users dict causes DetachedSessionErrors user = session.query(User).filter_by(username="******").scalar() sre = session.query(Group).filter_by(groupname="team-sre").scalar() fe_url = url(base_url, "/groups/{}/edit/user/{}".format(sre.groupname, user.name)) resp = yield http_client.fetch( fe_url, method="POST", body=urlencode( { "reason": "Test Request Please Ignore", "member": "User: {}".format(user.name), "role": "member", "expiration": "", } ), headers={"X-Grouper-User": "******"}, ) assert resp.code == 200 # Explicitly requery because pulling from the users dict causes DetachedSessionErrors user = session.query(User).filter_by(username="******").scalar() group_edge = session.query(GroupEdge).filter_by(group_id=sre.id, member_pk=user.id).scalar() assert group_edge.expiration is None, ( "The request should not have an expiration if none is provided and the user was edited" " by an approver" )