def test_remove_last_owner_via_audit(async_server, browser, users, groups, session): 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_aggregate_request(graph, groups, permissions, session, standard_graph, users): gary = users["*****@*****.**"] testuser = users["*****@*****.**"] not_involved = [user for name,user in users.items() if name not in ("*****@*****.**", "*****@*****.**")] assert not any([user_requests_aggregate(session, u).all() for u in users.values()]), \ "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 users.items() 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_can_add_owner_twice(get_plugin_proxy, session, groups, users): get_plugin_proxy.return_value = PluginProxy([GroupOwnershipPolicyPlugin()]) group = groups["team-infra"] owner = users["*****@*****.**"] add_member(group, owner, role="owner") add_member(group, owner, role="owner")
def test_can_disable_member(get_plugin_proxy, session, groups, users): get_plugin_proxy.return_value = PluginProxy([GroupOwnershipPolicyPlugin()]) group = groups["team-infra"] member = users["*****@*****.**"] add_member(group, member) disable_user(session, member)
def test_cant_disable_last_owner(get_plugin_proxy, session, groups, users): get_plugin_proxy.return_value = PluginProxy([GroupOwnershipPolicyPlugin()]) group = groups["team-infra"] owner = users["*****@*****.**"] add_member(group, owner, role="owner") with pytest.raises(PluginRejectedDisablingUser): disable_user(session, owner)
def test_cant_demote_last_owner(get_plugin_proxy, groups, users): get_plugin_proxy.return_value = PluginProxy([GroupOwnershipPolicyPlugin()]) group = groups["team-infra"] owner = users["*****@*****.**"] add_member(group, owner, role="owner") with pytest.raises(PluginRejectedGroupMembershipUpdate): group.edit_member(owner, owner, "Unit Testing", role="member")
def test_cant_expire_last_owner(get_plugin_proxy, groups, users): get_plugin_proxy.return_value = PluginProxy([GroupOwnershipPolicyPlugin()]) group = groups["team-infra"] owner = users["*****@*****.**"] expiration = datetime.utcnow() + timedelta(1) add_member(group, owner, role="owner") with pytest.raises(PluginRejectedGroupMembershipUpdate): group.edit_member(owner, owner, "Unit Testing", expiration=expiration)
def test_can_always_revoke_members(get_plugin_proxy, groups, users): get_plugin_proxy.return_value = PluginProxy([GroupOwnershipPolicyPlugin()]) group = groups["team-infra"] owner = users["*****@*****.**"] member = users["*****@*****.**"] expiration = datetime.utcnow() + timedelta(1) add_member(group, owner, role="owner", expiration=expiration) add_member(group, member) revoke_member(group, member)
def test_cant_revoke_last_permanent_owner(get_plugin_proxy, groups, users): get_plugin_proxy.return_value = PluginProxy([GroupOwnershipPolicyPlugin()]) group = groups["team-infra"] first_owner = users["*****@*****.**"] second_owner = users["*****@*****.**"] expiration = datetime.utcnow() + timedelta(1) add_member(group, first_owner, role="owner", expiration=expiration) add_member(group, second_owner, role="owner") with pytest.raises(PluginRejectedGroupMembershipUpdate): revoke_member(group, second_owner)
def expired_graph(session, graph, groups, users): 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_cant_revoke_last_npowner(get_plugin_proxy, session, groups, users): 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 test_cant_revoke_last_owner(get_plugins, session, groups, users): get_plugins.return_value = [GroupOwnershipPolicyPlugin()] group = groups["team-infra"] first_owner = users["*****@*****.**"] second_owner = users["*****@*****.**"] add_member(group, first_owner, role="owner") add_member(group, second_owner, role="owner") assert len(group.my_owners()) == 2 # Revoking the first owner does not raise an exception revoke_member(group, first_owner) session.commit() assert len(group.my_owners()) == 1 with pytest.raises(PluginRejectedGroupMembershipUpdate): revoke_member(group, second_owner) assert len(group.my_owners()) == 1
def test_graph_cycle_direct(session, graph, users, groups): # noqa """ 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_expiration_notifications(expiring_graph, session, users, groups, permissions): # noqa now = datetime.utcnow() note_exp_now = now + timedelta(settings.expiration_notice_days) day = timedelta(1) week = timedelta(7) # What expirations are coming up in the next day? Next week? upcoming_expirations = _get_unsent_expirations(session, now+day) assert upcoming_expirations == [] upcoming_expirations = _get_unsent_expirations(session, now+week) assert sorted(upcoming_expirations) == [ # Group, subgroup, subgroup owners. ("serving-team", "team-sre", "*****@*****.**"), ("serving-team", "team-sre", "*****@*****.**"), # Group, user, user. ("team-sre", "*****@*****.**", "*****@*****.**"), ] # Make someone expire a week from now. edit_member(groups["team-sre"], users["*****@*****.**"], expiration=note_exp_now+week) upcoming_expirations = _get_unsent_expirations(session, now+week) assert sorted(upcoming_expirations) == [ # Group, subgroup, subgroup owners. ("serving-team", "team-sre", "*****@*****.**"), ("serving-team", "team-sre", "*****@*****.**"), # Group, user, user. ("team-sre", "*****@*****.**", "*****@*****.**"), ("team-sre", "*****@*****.**", "*****@*****.**"), ] # Now cancel that expiration. edit_member(groups["team-sre"], users["*****@*****.**"], expiration=None) upcoming_expirations = _get_unsent_expirations(session, now+week) assert sorted(upcoming_expirations) == [ # Group, subgroup, subgroup owners. ("serving-team", "team-sre", "*****@*****.**"), ("serving-team", "team-sre", "*****@*****.**"), # Group, user, user. ("team-sre", "*****@*****.**", "*****@*****.**"), ] # Make an ordinary member an owner. edit_member(groups["team-sre"], users["*****@*****.**"], role="owner") upcoming_expirations = _get_unsent_expirations(session, now+week) assert sorted(upcoming_expirations) == [ # Group, subgroup, subgroup owners. ("serving-team", "team-sre", "*****@*****.**"), ("serving-team", "team-sre", "*****@*****.**"), ("serving-team", "team-sre", "*****@*****.**"), # Group, user, user. ("team-sre", "*****@*****.**", "*****@*****.**"), ] # Make an owner an ordinary member. edit_member(groups["team-sre"], users["*****@*****.**"], role="member") upcoming_expirations = _get_unsent_expirations(session, now+week) assert sorted(upcoming_expirations) == [ # Group, subgroup, subgroup owners. ("serving-team", "team-sre", "*****@*****.**"), ("serving-team", "team-sre", "*****@*****.**"), # Group, user, user. ("team-sre", "*****@*****.**", "*****@*****.**"), ] # Send notices about expirations coming up in the next day, next week. notices_sent = process_async_emails(settings, session, now+day, dry_run=True) assert notices_sent == 0 notices_sent = process_async_emails(settings, session, now+week, dry_run=True) assert notices_sent == 3 # ("serving-team", "team-sre", "*****@*****.**") # ("serving-team", "team-sre", "*****@*****.**") # ("team-sre", "*****@*****.**", "*****@*****.**") # Notices in the upcoming week have already been sent, but there's another # two weeks from now. upcoming_expirations = _get_unsent_expirations(session, now+week) assert upcoming_expirations == [] upcoming_expirations = _get_unsent_expirations(session, now+2*week) assert upcoming_expirations == [ ("tech-ops", "*****@*****.**", "*****@*****.**"), ] # We already sent these notices. notices_sent = process_async_emails(settings, session, now+week, dry_run=True) assert notices_sent == 0 # Extend gary's membership to beyond worth mentioning expiration in two weeks. add_member(groups["tech-ops"], users["*****@*****.**"], expiration=note_exp_now+3*week) upcoming_expirations = _get_unsent_expirations(session, now+2*week) assert upcoming_expirations == [] notices_sent = process_async_emails(settings, session, now+2*week, dry_run=True) assert notices_sent == 0
def expiring_graph(session, graph, users, groups, permissions): now = datetime.utcnow() note_exp_now = now + timedelta(settings.expiration_notice_days) week = timedelta(7) add_member(groups["team-sre"], users["*****@*****.**"], role="owner") add_member(groups["team-sre"], users["*****@*****.**"], role="owner") add_member(groups["team-sre"], users["*****@*****.**"], expiration=note_exp_now+week) add_member(groups["team-sre"], users["*****@*****.**"]) add_member(groups["team-sre"], users["*****@*****.**"], role="owner", expiration=note_exp_now+week) revoke_member(groups["team-sre"], users["*****@*****.**"]) grant_permission(groups["team-sre"], permissions["ssh"], argument="*") add_member(groups["serving-team"], users["*****@*****.**"], role="owner") add_member(groups["serving-team"], groups["team-sre"], expiration=note_exp_now+week) add_member(groups["serving-team"], groups["tech-ops"]) grant_permission(groups["serving-team"], permissions["audited"]) add_member(groups["tech-ops"], users["*****@*****.**"], role="owner") add_member(groups["tech-ops"], users["*****@*****.**"], expiration=note_exp_now+2*week) grant_permission(groups["tech-ops"], permissions["ssh"], argument="shell") return graph
def test_graph_cycle_indirect(session, graph, users, groups): # noqa """ 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_aggregate_request(graph, groups, permissions, session, standard_graph, users): gary = users["*****@*****.**"] testuser = users["*****@*****.**"] not_involved = [ user for name, user in users.items() if name not in ("*****@*****.**", "*****@*****.**") ] assert not any([user_requests_aggregate(session, u).all() for u in users.values()]), \ "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 users.items() 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_audit_end_to_end(session, users, groups, http_client, base_url, graph): # noqa """ Tests an end-to-end audit cycle. """ groupname = 'audited-team' zay_id = users["*****@*****.**"].id gary_id = users["*****@*****.**"].id # make everyone an auditor or global audit will have issues add_member(groups["auditors"], users["*****@*****.**"]) add_member(groups["auditors"], users["*****@*****.**"]) add_member(groups["auditors"], users["*****@*****.**"]) add_member(groups["auditors"], users["*****@*****.**"]) # add some users to test removal add_member(groups[groupname], users["*****@*****.**"]) add_member(groups[groupname], users["*****@*****.**"]) graph.update_from_db(session) # start the audit end_at_str = (datetime.now() + timedelta(days=10)).strftime('%m/%d/%Y') fe_url = url(base_url, '/audits/create') resp = yield http_client.fetch(fe_url, method="POST", body=urlencode({'ends_at': end_at_str}), headers={'X-Grouper-User': '******'}) assert resp.code == 200 open_audits = get_audits(session, only_open=True).all() assert len(open_audits) == 4, 'audits created' assert groupname in [x.group.name for x in open_audits ], 'group we expect also gets audit' # pull all the info we need to resolve audits, avoids detached sqlalchemy sessions AuditMember = namedtuple('AuditMember', 'am_id, edge_type, edge_id') Audit = namedtuple('Audit', 'audit_id, owner_name, group_name, audit_members') all_group_ids = [x.group.id for x in open_audits] open_audits = [ Audit(x.id, x.group.my_owners().iterkeys().next(), x.group.name, [ AuditMember(am.id, am.edge.member_type, am.edge_id) for am in x.my_members() ]) for x in open_audits ] # approve everything but the one we added members to for one_audit in open_audits: fe_url = url(base_url, '/audits/{}/complete'.format(one_audit.audit_id)) if one_audit.group_name == groupname: continue # blanket approval body = urlencode({ "audit_{}".format(am.am_id): "approved" for am in one_audit.audit_members }) resp = yield http_client.fetch( fe_url, method="POST", body=body, headers={'X-Grouper-User': one_audit.owner_name}) assert resp.code == 200 open_audits = get_audits(session, only_open=True).all() assert len(open_audits) == 1, 'only our test group remaining' one_audit = open_audits[0] one_audit.id body_dict = {} for am in one_audit.my_members(): if gary_id == am.member.id: # deny body_dict["audit_{}".format(am.id)] = "remove" else: # approve body_dict["audit_{}".format(am.id)] = "approved" owner_name = one_audit.group.my_owners().iterkeys().next() fe_url = url(base_url, '/audits/{}/complete'.format(one_audit.id)) resp = yield http_client.fetch(fe_url, method="POST", body=urlencode(body_dict), headers={'X-Grouper-User': owner_name}) assert resp.code == 200 # check all the logs assert len(AuditLog.get_entries( session, action='start_audit')) == 1, 'global start is logged' assert len(AuditLog.get_entries( session, action='complete_global_audit')) == 1, 'global complete is logged' for group_id in all_group_ids: assert len( AuditLog.get_entries(session, on_group_id=group_id, action='complete_audit', category=AuditLogCategory.audit) ) == 1, 'complete entry for each group' assert len( AuditLog.get_entries(session, on_user_id=gary_id, category=AuditLogCategory.audit) ) == 1, 'removal AuditLog entry on user'
def test_audit_end_to_end(session, users, groups, http_client, base_url): # noqa """ Tests an end-to-end audit cycle. """ groupname = 'audited-team' zay_id = users["*****@*****.**"].id gary_id = users["*****@*****.**"].id # make everyone an auditor or global audit will have issues add_member(groups["auditors"], users["*****@*****.**"]) add_member(groups["auditors"], users["*****@*****.**"]) add_member(groups["auditors"], users["*****@*****.**"]) add_member(groups["auditors"], users["*****@*****.**"]) # add some users to test removal add_member(groups[groupname], users["*****@*****.**"]) add_member(groups[groupname], users["*****@*****.**"]) # start the audit end_at_str = (datetime.now() + timedelta(days=10)).strftime('%m/%d/%Y') fe_url = url(base_url, '/audits/create') resp = yield http_client.fetch(fe_url, method="POST", body=urlencode({'ends_at': end_at_str}), headers={'X-Grouper-User': '******'}) assert resp.code == 200 open_audits = get_audits(session, only_open=True).all() assert len(open_audits) == 4, 'audits created' assert groupname in [x.group.name for x in open_audits], 'group we expect also gets audit' # pull all the info we need to resolve audits, avoids detached sqlalchemy sessions AuditMember = namedtuple('AuditMember', 'am_id, edge_type, edge_id') Audit = namedtuple('Audit', 'audit_id, owner_name, group_name, audit_members') all_group_ids = [x.group.id for x in open_audits] open_audits = [Audit(x.id, x.group.my_owners().iterkeys().next(), x.group.name, [AuditMember(am.id, am.edge.member_type, am.edge_id) for am in x.my_members()]) for x in open_audits] # approve everything but the one we added members to for one_audit in open_audits: fe_url = url(base_url, '/audits/{}/complete'.format(one_audit.audit_id)) if one_audit.group_name == groupname: continue # blanket approval body = urlencode({"audit_{}".format(am.am_id): "approved" for am in one_audit.audit_members}) resp = yield http_client.fetch(fe_url, method="POST", body=body, headers={'X-Grouper-User': one_audit.owner_name}) assert resp.code == 200 open_audits = get_audits(session, only_open=True).all() assert len(open_audits) == 1, 'only our test group remaining' one_audit = open_audits[0] one_audit.id body_dict = {} for am in one_audit.my_members(): if gary_id == am.member.id: # deny body_dict["audit_{}".format(am.id)] = "remove" else: # approve body_dict["audit_{}".format(am.id)] = "approved" owner_name = one_audit.group.my_owners().iterkeys().next() fe_url = url(base_url, '/audits/{}/complete'.format(one_audit.id)) resp = yield http_client.fetch(fe_url, method="POST", body=urlencode(body_dict), headers={'X-Grouper-User': owner_name}) assert resp.code == 200 # check all the logs assert len(AuditLog.get_entries(session, action='start_audit')) == 1, 'global start is logged' assert len(AuditLog.get_entries(session, action='complete_global_audit')) == 1, 'global complete is logged' for group_id in all_group_ids: assert len(AuditLog.get_entries(session, on_group_id=group_id, action='complete_audit', category=AuditLogCategory.audit)) == 1, 'complete entry for each group' assert len(AuditLog.get_entries(session, on_user_id=gary_id, category=AuditLogCategory.audit)) == 1, 'removal AuditLog entry on user'
def setup_desc_to_ances(session, users, groups): # noqa add_member(groups["team-sre"], users["*****@*****.**"], role="owner") add_member(groups["team-sre"], users["*****@*****.**"]) add_member(groups["tech-ops"], users["*****@*****.**"], role="owner") add_member(groups["tech-ops"], users["*****@*****.**"]) 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"])
def standard_graph(session, graph, users, groups, permissions): """Setup a standard graph used for many tests. In graph form: +-----------------------+ | | | team-sre | | * gary (o) +---------------------------------+ | * zay | | | * zorkian | +-----------v-----------+ | | | | +-----------------------+ | serving-team | +-----------------------+ +---------> * zorkian (o) | | | | | | | tech-ops | | +-----------+-----------+ | * zay (o) | | | | * gary +-----------+ | | * figurehead (np) | | | | | +-----------------------+ | +-----------------------+ +-----------v-----------+ | | | | | security-team | | team-infra | | * oliver (o) +---------------------> * gary (o) | | * figurehead | | | | | +-----------+-----------+ +-----------------------+ | +-----------------------+ | | | | | sad-team | | | * zorkian (o) | | | * oliver | +-----------v-----------+ | | | | +-----------------------+ | all-teams | +-----------------------+ | * testuser (o) | | | | | | audited-team | +-----------------------+ | * zorkian (o) | | | | | +-----------------------+ +-----------------------+ | | | auditors | | * zorkian (o) | | | +-----------------------+ +-----------------------+ | | | user-admins | | * tyleromeara (o) | | | +-----------------------+ Arrows denote member of the source in the destination group. (o) for owners, (np) for non-permissioned owners. """ add_member(groups["team-sre"], users["*****@*****.**"], role="owner") add_member(groups["team-sre"], users["*****@*****.**"]) add_member(groups["team-sre"], users["*****@*****.**"]) grant_permission(groups["team-sre"], permissions["ssh"], argument="*") grant_permission(groups["team-sre"], permissions["team-sre"], argument="*") add_member(groups["serving-team"], users["*****@*****.**"], role="owner") add_member(groups["serving-team"], groups["team-sre"]) add_member(groups["serving-team"], groups["tech-ops"]) grant_permission(groups["serving-team"], permissions["audited"]) add_member(groups["tech-ops"], users["*****@*****.**"], role="owner") add_member(groups["tech-ops"], users["*****@*****.**"]) add_member(groups["tech-ops"], users["*****@*****.**"], role="np-owner") grant_permission(groups["tech-ops"], permissions["ssh"], argument="shell") add_member(groups["security-team"], users["*****@*****.**"], role="owner") add_member(groups["security-team"], users["*****@*****.**"], role="member") add_member(groups["sad-team"], users["*****@*****.**"], role="owner") add_member(groups["sad-team"], users["*****@*****.**"]) add_member(groups["audited-team"], users["*****@*****.**"], role="owner") grant_permission(groups["audited-team"], permissions["audited"]) add_member(groups["team-infra"], users["*****@*****.**"], role="owner") add_member(groups["team-infra"], groups["serving-team"]) add_member(groups["team-infra"], groups["security-team"]) grant_permission(groups["team-infra"], permissions["sudo"], argument="shell") add_member(groups["auditors"], users["*****@*****.**"], role="owner") grant_permission(groups["auditors"], permissions[AUDIT_MANAGER]) grant_permission(groups["auditors"], permissions[PERMISSION_AUDITOR]) add_member(groups["all-teams"], users["*****@*****.**"], role="owner") add_member(groups["all-teams"], groups["team-infra"]) add_member(groups["user-admins"], users["*****@*****.**"], role="owner") grant_permission(groups["user-admins"], permissions[USER_ADMIN]) session.commit() graph.update_from_db(session) return graph
def test_graph_add_member_existing(session, graph, users, groups): # noqa """ 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_expire_nonauditors(standard_graph, users, groups, session, permissions): """ Test expiration auditing and notification. """ graph = standard_graph # noqa # Test audit autoexpiration for all approvers approver_roles = ["owner", "np-owner", "manager"] for role in approver_roles: # Add non-auditor as an owner to an audited group add_member(groups["audited-team"], users["*****@*****.**"], role=role) session.commit() graph.update_from_db(session) group_md = graph.get_group_details("audited-team") assert group_md.get('audited', False) # Expire the edges. background = BackgroundThread(settings, None) background.expire_nonauditors(session) # Check that the edges are now marked as inactive. edge = session.query(GroupEdge).filter_by(group_id=groups["audited-team"].id, member_pk=users["*****@*****.**"].id).scalar() assert edge.expiration is not None assert edge.expiration < datetime.utcnow() + timedelta(days=settings.nonauditor_expiration_days) assert edge.expiration > datetime.utcnow() + timedelta(days=settings.nonauditor_expiration_days - 1) assert any(["Subject: Membership in audited-team set to expire" in email.body and "To: [email protected]" in email.body for email in _get_unsent_emails_and_send(session)]) audits = AuditLog.get_entries(session, action="nonauditor_flagged") assert len(audits) == 3 + 1 * (approver_roles.index(role) + 1) revoke_member(groups["audited-team"], users["*****@*****.**"]) # Ensure nonauditor, nonapprovers in audited groups do not get set to expired member_roles = ["member"] for role in member_roles: # Add non-auditor as an owner to an audited group add_member(groups["audited-team"], users["*****@*****.**"], role=role) session.commit() graph.update_from_db(session) group_md = graph.get_group_details("audited-team") assert group_md.get('audited', False) # Expire the edges. background = BackgroundThread(settings, None) background.expire_nonauditors(session) # Check that the edges are now marked as inactive. edge = session.query(GroupEdge).filter_by(group_id=groups["audited-team"].id, member_pk=users["*****@*****.**"].id).scalar() assert edge.expiration is None assert not any(["Subject: Membership in audited-team set to expire" in email.body and "To: [email protected]" in email.body for email in _get_unsent_emails_and_send(session)]) audits = AuditLog.get_entries(session, action="nonauditor_flagged") assert len(audits) == 3 + 1 * len(approver_roles) revoke_member(groups["audited-team"], users["*****@*****.**"])
def standard_graph(session, graph, users, groups, permissions): add_member(groups["team-sre"], users["gary"], role="owner") add_member(groups["team-sre"], users["zay"]) add_member(groups["team-sre"], users["zorkian"]) grant_permission(groups["team-sre"], permissions["ssh"], argument="*") add_member(groups["serving-team"], users["zorkian"], role="owner") add_member(groups["serving-team"], groups["team-sre"]) add_member(groups["serving-team"], groups["tech-ops"]) grant_permission(groups["serving-team"], permissions["audited"]) add_member(groups["tech-ops"], users["zay"], role="owner") add_member(groups["tech-ops"], users["gary"]) add_member(groups["tech-ops"], users["figurehead"], role="np-owner") grant_permission(groups["tech-ops"], permissions["ssh"], argument="shell") add_member(groups["security-team"], users["oliver"], role="owner") add_member(groups["security-team"], users["figurehead"], role="member") add_member(groups["sad-team"], users["zorkian"], role="owner") add_member(groups["sad-team"], users["oliver"]) add_member(groups["audited-team"], users["zorkian"], role="owner") grant_permission(groups["audited-team"], permissions["audited"]) add_member(groups["team-infra"], users["gary"], role="owner") add_member(groups["team-infra"], groups["serving-team"]) add_member(groups["team-infra"], groups["security-team"]) grant_permission(groups["team-infra"], permissions["sudo"], argument="shell") add_member(groups["auditors"], users["zorkian"], role="owner") grant_permission(groups["auditors"], permissions[PERMISSION_AUDITOR]) add_member(groups["all-teams"], users["testuser"], role="owner") add_member(groups["all-teams"], groups["team-infra"]) session.commit() graph.update_from_db(session) return graph
def standard_graph(session, graph, users, groups, permissions): add_member(groups["team-sre"], users["gary"], role="owner") add_member(groups["team-sre"], users["zay"]) add_member(groups["team-sre"], users["zorkian"]) grant_permission(groups["team-sre"], permissions["ssh"], argument="*") add_member(groups["serving-team"], users["zorkian"], role="owner") add_member(groups["serving-team"], groups["team-sre"]) add_member(groups["serving-team"], groups["tech-ops"]) grant_permission(groups["serving-team"], permissions["audited"]) add_member(groups["tech-ops"], users["zay"], role="owner") add_member(groups["tech-ops"], users["gary"]) grant_permission(groups["tech-ops"], permissions["ssh"], argument="shell") add_member(groups["security-team"], users["oliver"], role="owner") add_member(groups["sad-team"], users["zorkian"], role="owner") add_member(groups["sad-team"], users["oliver"]) add_member(groups["audited-team"], users["zorkian"], role="owner") grant_permission(groups["audited-team"], permissions["audited"]) add_member(groups["team-infra"], users["gary"], role="owner") add_member(groups["team-infra"], groups["serving-team"]) add_member(groups["team-infra"], groups["security-team"]) grant_permission(groups["team-infra"], permissions["sudo"], argument="shell") add_member(groups["auditors"], users["zorkian"], role="owner") grant_permission(groups["auditors"], permissions[PERMISSION_AUDITOR]) add_member(groups["all-teams"], users["testuser"], role="owner") add_member(groups["all-teams"], groups["team-infra"]) session.commit() graph.update_from_db(session) return graph
def test_graph_add_member_existing(session, graph, users, groups): # noqa """ 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 standard_graph(session, graph, users, groups, permissions): """Setup a standard graph used for many tests. In graph form: +-----------------------+ | | | team-sre | | * gary (o) +---------------------------------+ | * zay | | | * zorkian | +-----------v-----------+ | | | | +-----------------------+ | serving-team | +-----------------------+ +---------> * zorkian (o) | | | | | | | tech-ops | | +-----------+-----------+ | * zay (o) | | | | * gary +-----------+ | | * figurehead (np) | | | | | +-----------------------+ | +-----------------------+ +-----------v-----------+ | | | | | security-team | | team-infra | | * oliver (o) +---------------------> * gary (o) | | * figurehead | | | | | +-----------+-----------+ +-----------------------+ | +-----------------------+ | | | | | sad-team | | | * zorkian (o) | | | * oliver | +-----------v-----------+ | | | | +-----------------------+ | all-teams | +-----------------------+ | * testuser (o) | | | | | | audited-team | +-----------------------+ | * zorkian (o) | | | | | +-----------------------+ +-----------------------+ | | | auditors | | * zorkian (o) | | | +-----------------------+ Arrows denote member of the source in the destination group. (o) for owners, (np) for non-permissioned owners. """ add_member(groups["team-sre"], users["*****@*****.**"], role="owner") add_member(groups["team-sre"], users["*****@*****.**"]) add_member(groups["team-sre"], users["*****@*****.**"]) grant_permission(groups["team-sre"], permissions["ssh"], argument="*") add_member(groups["serving-team"], users["*****@*****.**"], role="owner") add_member(groups["serving-team"], groups["team-sre"]) add_member(groups["serving-team"], groups["tech-ops"]) grant_permission(groups["serving-team"], permissions["audited"]) add_member(groups["tech-ops"], users["*****@*****.**"], role="owner") add_member(groups["tech-ops"], users["*****@*****.**"]) add_member(groups["tech-ops"], users["*****@*****.**"], role="np-owner") grant_permission(groups["tech-ops"], permissions["ssh"], argument="shell") add_member(groups["security-team"], users["*****@*****.**"], role="owner") add_member(groups["security-team"], users["*****@*****.**"], role="member") add_member(groups["sad-team"], users["*****@*****.**"], role="owner") add_member(groups["sad-team"], users["*****@*****.**"]) add_member(groups["audited-team"], users["*****@*****.**"], role="owner") grant_permission(groups["audited-team"], permissions["audited"]) add_member(groups["team-infra"], users["*****@*****.**"], role="owner") add_member(groups["team-infra"], groups["serving-team"]) add_member(groups["team-infra"], groups["security-team"]) grant_permission(groups["team-infra"], permissions["sudo"], argument="shell") add_member(groups["auditors"], users["*****@*****.**"], role="owner") grant_permission(groups["auditors"], permissions[AUDIT_MANAGER]) grant_permission(groups["auditors"], permissions[PERMISSION_AUDITOR]) add_member(groups["all-teams"], users["*****@*****.**"], role="owner") add_member(groups["all-teams"], groups["team-infra"]) session.commit() graph.update_from_db(session) return graph
def test_expire_nonauditors(standard_graph, users, groups, session, permissions): """ Test expiration auditing and notification. """ graph = standard_graph # noqa # Test audit autoexpiration for all approvers approver_roles = ["owner", "np-owner", "manager"] for role in approver_roles: # Add non-auditor as an owner to an audited group add_member(groups["audited-team"], users["*****@*****.**"], role=role) session.commit() graph.update_from_db(session) group_md = graph.get_group_details("audited-team") assert group_md.get('audited', False) # Expire the edges. background = BackgroundProcessor(settings, None) background.expire_nonauditors(session) # Check that the edges are now marked as inactive. edge = session.query(GroupEdge).filter_by(group_id=groups["audited-team"].id, member_pk=users["*****@*****.**"].id).scalar() assert edge.expiration is not None assert edge.expiration < datetime.utcnow() + timedelta(days=settings.nonauditor_expiration_days) assert edge.expiration > datetime.utcnow() + timedelta(days=settings.nonauditor_expiration_days - 1) assert any(["Subject: Membership in audited-team set to expire" in email.body and "To: [email protected]" in email.body for email in _get_unsent_emails_and_send(session)]) audits = AuditLog.get_entries(session, action="nonauditor_flagged") assert len(audits) == 3 + 1 * (approver_roles.index(role) + 1) revoke_member(groups["audited-team"], users["*****@*****.**"]) # Ensure nonauditor, nonapprovers in audited groups do not get set to expired member_roles = ["member"] for role in member_roles: # Add non-auditor as an owner to an audited group add_member(groups["audited-team"], users["*****@*****.**"], role=role) session.commit() graph.update_from_db(session) group_md = graph.get_group_details("audited-team") assert group_md.get('audited', False) # Expire the edges. background = BackgroundProcessor(settings, None) background.expire_nonauditors(session) # Check that the edges are now marked as inactive. edge = session.query(GroupEdge).filter_by(group_id=groups["audited-team"].id, member_pk=users["*****@*****.**"].id).scalar() assert edge.expiration is None assert not any(["Subject: Membership in audited-team set to expire" in email.body and "To: [email protected]" in email.body for email in _get_unsent_emails_and_send(session)]) audits = AuditLog.get_entries(session, action="nonauditor_flagged") assert len(audits) == 3 + 1 * len(approver_roles) revoke_member(groups["audited-team"], users["*****@*****.**"])
def standard_graph(session, graph, users, groups): add_member(groups["team-sre"], users["gary"], role="owner") add_member(groups["team-sre"], users["zay"]) add_member(groups["team-sre"], users["zorkian"]) add_member(groups["tech-ops"], users["zay"], role="owner") add_member(groups["tech-ops"], users["gary"]) add_member(groups["team-infra"], users["gary"], role="owner") add_member(groups["team-infra"], groups["team-sre"]) add_member(groups["team-infra"], groups["tech-ops"]) add_member(groups["all-teams"], users["testuser"], role="owner") add_member(groups["all-teams"], groups["team-infra"]) session.commit() graph.update_from_db(session) return graph