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")
Exemple #4
0
    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)
Exemple #5
0
    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"))
Exemple #6
0
    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"))
Exemple #7
0
    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()
Exemple #8
0
    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()
Exemple #9
0
    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)
Exemple #10
0
    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")
Exemple #11
0
    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)
Exemple #12
0
 def execute(self):
     logger.debug("adding trigger policy....")
     policy = Policy(kind=Policy.TRIGGER)
     self.save_to_policy(policy)
Exemple #13
0
 def execute(self):
     policy = Policy(kind=Policy.CONSTITUTION)
     self.save_to_policy(policy)
Exemple #14
0
 def execute(self):
     policy = Policy(kind=Policy.PLATFORM)
     self.save_to_policy(policy)
Exemple #15
0
    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"))