def test_can_execute_constitution(self): """Test that users with can_execute permissions can execute any constitution action and mark it as 'passed'""" all_actions_fail_policy = { **all_actions_pass_policy, "check": "return FAILED", } policy = Policy( **all_actions_fail_policy, kind=Policy.CONSTITUTION, community=self.slack_community, description="all actions fail", name="all actions fail", ) policy.save() # create a test user with can_execute permissions for PolicykitAddCommunityDoc can_add = Permission.objects.get(name="Can add policykit add community doc") can_execute = Permission.objects.get(name="Can execute policykit add community doc") user_with_can_execute = SlackUser.objects.create(username="******", community=self.slack_community) user_with_can_execute.user_permissions.add(can_add) user_with_can_execute.user_permissions.add(can_execute) self.assertTrue(user_with_can_execute.has_perm("policyengine.add_policykitaddcommunitydoc")) self.assertTrue(user_with_can_execute.has_perm("policyengine.can_execute_policykitaddcommunitydoc")) # action initiated by user with "can_execute" should pass action = PolicykitAddCommunityDoc( name="my doc", initiator=user_with_can_execute, community=self.slack_community ) action.save() self.assertEqual(action.proposal.status, "passed") # action initiated by user without "can_execute" should fail action = PolicykitAddCommunityDoc(name="my other doc", initiator=self.user, community=self.slack_community) action.save() self.assertEqual(action.proposal.status, "failed")
def test_cannot_propose_constitution(self): """Test that action fails when a user does not have permission to propose constitution change""" policy = Policy( **all_actions_pass_policy, kind=Policy.CONSTITUTION, community=self.slack_community, description="all actions pass", name="all actions pass", ) policy.save() # action initiated by user without "can_add" should fail user = SlackUser.objects.create(username="******", community=self.slack_community) self.assertEqual(user.has_perm("policyengine.add_policykitaddcommunitydoc"), False) action = PolicykitAddCommunityDoc(name="my doc", initiator=user, community=self.slack_community) action.save() action.refresh_from_db() # test that it was saved to the db with correct proposal self.assertEqual(action.proposal.status, "failed") # action initiated by user with "can_add" should pass user = SlackUser.objects.create(username="******", community=self.slack_community) can_add = Permission.objects.get(name="Can add policykit add community doc") user.user_permissions.add(can_add) self.assertTrue(user.has_perm("policyengine.add_policykitaddcommunitydoc")) action = PolicykitAddCommunityDoc(name="my other doc", initiator=user, community=self.slack_community) action.save() action.refresh_from_db() # test that it was saved to the db with correct proposal self.assertEqual(action.proposal.status, "passed")
def test_can_execute(self): """Test that users with can_execute permissions can execute any action and mark it as 'passed'""" all_actions_fail_policy = { **all_actions_pass_policy, "check": "return FAILED", } policy = Policy( **all_actions_fail_policy, kind=Policy.PLATFORM, community=self.slack_community, description="all actions fail", name="all actions fail", ) policy.save() # create a test user with can_execute permissions can_execute = Permission.objects.get(name="Can execute slack pin message") can_add = Permission.objects.get(name="Can add slack pin message") user_with_can_execute = SlackUser.objects.create(username="******", community=self.slack_community) user_with_can_execute.user_permissions.add(can_add) user_with_can_execute.user_permissions.add(can_execute) # action initiated by user with "can_execute" should pass action = SlackPinMessage(initiator=user_with_can_execute, community=self.slack_community) action.execute = lambda: None # don't do anything on execute action.save() self.assertEqual(action.proposal.status, "passed") # action initiated by user without "can_execute" should fail action = SlackPinMessage(initiator=self.user, community=self.slack_community) action.execute = lambda: None # don't do anything on execute action.save() self.assertEqual(action.proposal.status, "failed")
def test_can_execute_constitution(self): """Test that users with can_execute permissions can execute any constitution action and mark it as 'passed'""" policy = Policy(**TestUtils.ALL_ACTIONS_FAIL, kind=Policy.CONSTITUTION, community=self.community) policy.save() # create a test user with can_execute permissions for PolicykitAddCommunityDoc can_execute = Permission.objects.get( codename=EXECUTE_COMMUNITIY_DOC_PERM) user_with_can_execute = SlackUser.objects.create( username="******", community=self.slack_community) user_with_can_execute.user_permissions.add(can_execute) self.assertTrue( user_with_can_execute.has_perm( f"constitution.{PROPOSE_COMMUNITY_DOC_PERM}")) self.assertTrue( user_with_can_execute.has_perm( f"constitution.{EXECUTE_COMMUNITIY_DOC_PERM}")) # action initiated by user with "can_execute" should pass action = self.new_policykitaddcommunitydoc( initiator=user_with_can_execute) self.evaluate_action_helper(action, expected_did_execute=True) # action initiated by user without "can_execute" should generate a failed proposal action = self.new_policykitaddcommunitydoc() self.evaluate_action_helper(action, expected_policy=policy, expected_did_execute=False, expected_status=Proposal.FAILED)
def test_close_process(self): """Integration-test metagov process with randomness plugin""" # 1) Create Policy and PlatformAction policy_code = { **all_actions_pass_policy, "initialize": """ metagov.start_process("randomness.delayed-stochastic-vote", {"options": ["one", "two", "three"], "delay": 1}) """, "check": """ result = metagov.close_process() action.data.set('status', result.status) action.data.set('outcome', result.outcome) if result is None: return #still processing if result.errors: return FAILED if result.outcome: return PASSED if result.outcome.get('winner') else FAILED return FAILED """, } policy = Policy( **policy_code, kind=Policy.PLATFORM, community=self.slack_community, description="test", name="test policy", ) policy.save() action = SlackPinMessage() action.initiator = self.user action.community = self.slack_community action.community_origin = True # 2) Save action to trigger policy execution action.save() process = MetagovProcess.objects.filter(action=action, policy=policy).first() self.assertIsNotNone(process) self.assertEqual(action.proposal.status, "passed") self.assertEqual(action.data.get("status"), "completed") self.assertIsNotNone(action.data.get("outcome").get("winner"))
def test_close_process(self): """Integration-test metagov process with randomness plugin. Process is closed from within the policy.""" # 1) Create Policy and GovernableAction policy_code = { **TestUtils.ALL_ACTIONS_PASS, "initialize": """ metagov.start_process("randomness.delayed-stochastic-vote", options=["one", "two", "three"], delay=1) """, "check": """ result = metagov.close_process() proposal.data.set('reached_close', True) if result is None: return #still processing if result.errors: return FAILED if result.outcome: return PASSED if result.outcome.get('winner') else FAILED return FAILED """, } policy = Policy( **policy_code, kind=Policy.PLATFORM, community=self.community, ) policy.save() action = SlackPinMessage() action.initiator = self.user action.community = self.slack_community action.community_origin = True # 2) Save action to trigger policy execution action.save() proposal = Proposal.objects.get(action=action, policy=policy) self.assertEqual(proposal.status, Proposal.PASSED) self.assertTrue(proposal.is_vote_closed) self.assertEqual(proposal.data.get("reached_close"), True) # assert that the process outcome was saved metagov = Metagov(proposal) process_data = metagov.get_process() self.assertEqual(process_data.status, "completed") self.assertIsNotNone(process_data.outcome.get("winner"))
def test_cannot_propose_constitution(self): """Test that action fails when a user does not have permission to propose constitution change""" policy = Policy(**TestUtils.ALL_ACTIONS_PASS, kind=Policy.CONSTITUTION, community=self.community) policy.save() # remove role from CommunityRole base role for this test base_role = CommunityRole.objects.get(community=self.community, is_base_role=True) can_add = Permission.objects.get(codename=PROPOSE_COMMUNITY_DOC_PERM) base_role.permissions.remove(can_add) base_role.save() # action initiated by user without "can_add" should be reverted user = SlackUser.objects.create(username="******", community=self.slack_community) self.assertEqual( user.has_perm(f"constitution.{PROPOSE_COMMUNITY_DOC_PERM}"), False) action = self.new_policykitaddcommunitydoc(initiator=user) self.evaluate_action_helper(action, expected_did_execute=False) # action initiated by user with "can_add" should pass user = SlackUser.objects.create(username="******", community=self.slack_community) user.user_permissions.add(can_add) self.assertTrue( user.has_perm(f"constitution.{PROPOSE_COMMUNITY_DOC_PERM}")) action = self.new_policykitaddcommunitydoc(initiator=user) self.evaluate_action_helper(action, expected_policy=policy, expected_did_execute=True, expected_status=Proposal.PASSED) # add back removed perm base_role.permissions.add(can_add) base_role.save()
def init_kit(self, community, creator_token=None): for policy in self.genericpolicy_set.all(): p = Policy() p.kind = Policy.CONSTITUTION if policy.is_constitution else Policy.PLATFORM p.community = community p.filter = policy.filter p.initialize = policy.initialize p.check = policy.check p.notify = policy.notify p.success = policy.success p.fail = policy.fail p.description = policy.description p.name = policy.name proposal = Proposal.objects.create(status=Proposal.PASSED) p.proposal = proposal p.save() for role in self.genericrole_set.all(): c = None if role.is_base_role: c = community.base_role role.is_base_role = False else: c = CommunityRole() c.community = community c.role_name = role.role_name c.name = "Discord: " + community.community_name + ": " + role.role_name c.description = role.description c.save() for perm in role.permissions.all(): c.permissions.add(perm) jsonDec = json.decoder.JSONDecoder() perm_set = jsonDec.decode(role.plat_perm_set) if 'view' in perm_set: for perm in DISCORD_VIEW_PERMS: p1 = Permission.objects.get(name=perm) c.permissions.add(p1) if 'propose' in perm_set: for perm in DISCORD_PROPOSE_PERMS: p1 = Permission.objects.get(name=perm) c.permissions.add(p1) if 'execute' in perm_set: for perm in DISCORD_EXECUTE_PERMS: p1 = Permission.objects.get(name=perm) c.permissions.add(p1) if role.user_group == "admins": group = CommunityUser.objects.filter(community = community, is_community_admin = True) for user in group: c.user_set.add(user) elif role.user_group == "nonadmins": group = CommunityUser.objects.filter(community = community, is_community_admin = False) for user in group: c.user_set.add(user) elif role.user_group == "all": group = CommunityUser.objects.filter(community = community) for user in group: c.user_set.add(user) elif role.user_group == "creator": user = CommunityUser.objects.get(access_token=creator_token) c.user_set.add(user) c.save()
def test_metagov_slack_trigger(self): """Test receiving a Slack event from Metagov that creates a SlackPinMessage action""" # 1) Create Policy that is triggered by a metagov action policy = Policy(kind=Policy.PLATFORM) policy.community = self.slack_community policy.filter = """return action.action_codename == 'slackpinmessage'""" policy.initialize = "pass" policy.notify = "pass" policy.check = "return PASSED" policy.success = "action.data.set('got here', True)\ndebug('hello world!')" policy.fail = "pass" policy.description = "test" policy.name = "test policy" policy.save() event_payload = { "community": self.slack_community.metagov_slug, "initiator": { "user_id": "alice", "provider": "slack" }, "source": "slack", "event_type": "pin_added", "data": { "channel_id": "123", "item": { "message": { "ts": "123" } } }, } # 2) Mimick an incoming notification from Metagov that the action has occurred client = Client() response = client.post(f"/metagov/internal/action", data=event_payload, content_type="application/json") self.assertEqual(response.status_code, 200) self.assertEqual(SlackPinMessage.objects.all().count(), 1) action = SlackPinMessage.objects.first() self.assertEqual(action.community.platform, "slack") self.assertEqual(action.initiator.username, "alice") self.assertEqual(action.data.get("got here"), True) self.assertEqual(action.proposal.status, "passed") # Check that evaluation debug log was generated self.assertEqual( EvaluationLog.objects.filter(community=policy.community, msg__contains="hello world!").count(), 1)
def test_metagov_trigger(self): """Test policy triggered by generic metagov event""" # 1) Create Policy that is triggered by a metagov action policy = Policy(kind=Policy.PLATFORM) policy.community = self.slack_community policy.filter = """return action.action_codename == 'metagovaction' \ and action.event_type == 'discourse.post_created'""" policy.initialize = "action.data.set('test_verify_username', action.initiator.metagovuser.external_username)" policy.notify = "pass" policy.check = "return PASSED if action.event_data['category'] == 0 else FAILED" policy.success = "pass" policy.fail = "pass" policy.description = "test" policy.name = "test policy" policy.save() event_payload = { "community": self.slack_community.metagov_slug, "initiator": { "user_id": "miriam", "provider": "discourse" }, "source": "discourse", "event_type": "post_created", "data": { "title": "test", "raw": "post text", "category": 0 }, } # 2) Mimick an incoming notification from Metagov that the action has occurred client = Client() response = client.post(f"/metagov/internal/action", data=event_payload, content_type="application/json") self.assertEqual(response.status_code, 200) self.assertEqual(MetagovPlatformAction.objects.all().count(), 1) action = MetagovPlatformAction.objects.filter( event_type="discourse.post_created").first() # the action.community is the community that is connected to metagov self.assertEqual(action.community.platform, "slack") self.assertEqual(action.initiator.username, "discourse.miriam") self.assertEqual(action.initiator.metagovuser.external_username, "miriam") self.assertEqual(action.data.get("test_verify_username"), "miriam") self.assertEqual(action.event_data["raw"], "post text") self.assertEqual(action.proposal.status, "passed")
def test_perform_action(self): """Integration-test metagov.perform_action function with randomness plugin""" # 1) Create Policy that performs a metagov action policy = Policy(kind=Policy.PLATFORM) policy.community = self.slack_community policy.filter = "return True" policy.initialize = "debug('help!')" policy.check = """parameters = {"low": 4, "high": 5} response = metagov.perform_action('randomness.random-int', parameters) if response and response.get('value') == 4: return PASSED return FAILED""" policy.notify = "pass" policy.success = "pass" policy.fail = "pass" policy.description = "test" policy.name = "test policy" policy.save() # 2) Save an action to trigger the policy execution action = SlackPinMessage() action.initiator = self.user action.community = self.slack_community action.community_origin = True action.save() self.assertEqual(action.proposal.status, "passed") # Check that evaluation debug log was generated from django_db_logger.models import EvaluationLog self.assertEqual( EvaluationLog.objects.filter(community=policy.community, msg__contains="help!").count(), 1)
def execute(self): logger.debug("adding trigger policy....") policy = Policy(kind=Policy.TRIGGER) self.save_to_policy(policy)
def execute(self): policy = Policy(kind=Policy.CONSTITUTION) self.save_to_policy(policy)
def execute(self): policy = Policy(kind=Policy.PLATFORM) self.save_to_policy(policy)
def test_outcome_endpoint(self): """Integration-test metagov process is updated via the outcome receiver endpoint in PolicyKit""" # 1) Create Policy and GovernableAction policy_code = { **TestUtils.ALL_ACTIONS_PASS, "initialize": """ metagov.start_process("randomness.delayed-stochastic-vote", options=["one", "two", "three"], delay=1) """, "check": """ result = metagov.get_process() proposal.data.set('process_status', result.status) proposal.data.set('is_vote_closed', proposal.is_vote_closed) if result is None or result.status == "pending": return None #still processing if result.errors: return FAILED if result.outcome: return PASSED if result.outcome.get('winner') else FAILED return FAILED """, } policy = Policy( **policy_code, kind=Policy.PLATFORM, community=self.community, ) policy.save() action = SlackPinMessage() action.initiator = self.user action.community = self.slack_community action.community_origin = True action.revert = lambda: None action.execute = lambda: None # 2) Save action to trigger policy execution action.save() proposal = Proposal.objects.get(action=action, policy=policy) self.assertEqual(proposal.status, Proposal.PROPOSED) self.assertEqual(proposal.data.get("process_status"), "pending") self.assertFalse(proposal.data.get("is_vote_closed")) self.assertFalse(proposal.is_vote_closed) # 2) Close the process, which should emit a signal for PolicyKit to handle proposal.governance_process.update() proposal.governance_process.proxy.close() # re-run proposal using celery task function consider_proposed_actions() proposal.refresh_from_db() self.assertEqual(proposal.status, Proposal.PASSED) metagov = Metagov(proposal) process_data = metagov.get_process() self.assertEqual(process_data.status, "completed") self.assertIsNotNone(process_data.outcome.get("winner"))