Ejemplo n.º 1
0
    def test_complex_propagation_count(self):
        """Test multiple object ACL propagation.

    This test is meant to catch invalid ACL entries for propagation that can
    not happen.
    Example for this is propagation control -> relationships -> document. In
    that propagation rule we should only propagate control acl entries to
    relationships to documents. But what can happen is; when a control has
    multiple relationships, some to objects and only one to document, all of
    those relationships would get an ACL entry even though in some cases that
    is a propagation dead end.

    Setup for this test is:

    Objects:
      control
      regulation
      objective
      program
      audit
      assessment, assessment_2

    Relationships:
      control - regulation
      control - objective
      objective - regulations
      program - control, regulation, objective, audit
      audit - assessment, assessment_2,
      audit - control-snapshot, regulation-snapshot, objective-snapshot
      control_snapshot - regulation_snapshot
      control_snapshot - objective_snapshot
      objective_snapshot - regulations_snapshot
      document - regulation, objective, control
      evidence - assessment
    """
        with factories.single_commit():
            person = factories.PersonFactory()
            control = factories.ControlFactory()
            regulation = factories.RegulationFactory()
            objective = factories.ObjectiveFactory()
            normal_objects = [control, regulation, objective]

            for obj1, obj2 in itertools.combinations(normal_objects, 2):
                factories.RelationshipFactory(source=obj1, destination=obj2)

            assessment = factories.AssessmentFactory()
            assessment_2 = factories.AssessmentFactory(audit=assessment.audit)
            factories.RelationshipFactory(
                source=assessment,
                destination=assessment.audit,
            )
            factories.RelationshipFactory(
                source=assessment_2,
                destination=assessment.audit,
            )
            factories.RelationshipFactory(
                source=assessment.audit,
                destination=assessment.audit.program,
            )
            for obj in normal_objects:
                factories.RelationshipFactory(
                    source=assessment.audit.program,
                    destination=obj,
                )

            snapshots = self._create_snapshots(assessment.audit,
                                               normal_objects)
            for snapshot in snapshots:
                factories.RelationshipFactory(
                    source=assessment.audit,
                    destination=snapshot,
                )

            for obj1, obj2 in itertools.combinations(snapshots, 2):
                factories.RelationshipFactory(source=obj1, destination=obj2)

            for obj in normal_objects:
                document = factories.DocumentFactory()
                factories.RelationshipFactory(source=obj, destination=document)

            evidence = factories.EvidenceUrlFactory()
            factories.RelationshipFactory(source=evidence,
                                          destination=assessment)

        acl_entry = factories.AccessControlListFactory(
            person=person,
            ac_role=self.roles["Control"]["Admin"],
            object=control,
        )

        propagation._propagate([acl_entry.id])

        self.assertEqual(
            all_models.AccessControlList.query.count(),
            3,  # 1 for control, 1 for relationship to document and 1 for document.
        )

        acl_entry = factories.AccessControlListFactory(
            person=person,
            ac_role=self.roles["Program"]["Program Editors"],
            object=assessment.audit.program,
        )
        propagation._propagate([acl_entry.id])

        self.assertEqual(
            all_models.AccessControlList.query.count(),
            3 + 1 + 2 + 4 + 6 + 2 + 6 + 6
            # 3 previous entries for control
            # 1 original program ACL entry
            # 2 for audit (relationship + audit propagation)
            # 4 for assessments (2 assessments and 2 relationships for them)
            # 6 for snapshots (3 snapshots with relationships)
            # 2 assessment document with relationships
            # 6 for normal objects
            # 6 for normal object documents
        )
Ejemplo n.º 2
0
  def test_changing_assessment_urls_triggers_notifications(self, _):
    """Test that changing Assessment URLs results in change notification.

    Adding (removing) a URL to (from) Assessment should be detected and
    considered an Assessment change.
    """
    self.import_file("assessment_with_templates.csv")
    asmts = {asmt.slug: asmt for asmt in Assessment.query}

    self.client.get("/_notifications/send_daily_digest")
    self.assertEqual(self._get_notifications().count(), 0)

    asmt = Assessment.query.get(asmts["A 5"].id)

    # add a URL, there should be no notifications because the Assessment
    # has not been started yet
    url = factories.DocumentFactory(link="www.foo.com")
    response, relationship = self.objgen.generate_relationship(url, asmt)
    self.assertEqual(response.status_code, 201)

    change_notifs = self._get_notifications(notif_type="assessment_updated")
    self.assertEqual(change_notifs.count(), 0)
    asmt = Assessment.query.get(asmts["A 5"].id)

    # move Assessment to to "In Progress" state and clear notifications
    self.api_helper.modify_object(
        asmt, {"status": Assessment.PROGRESS_STATE})

    self.client.get("/_notifications/send_daily_digest")
    self.assertEqual(self._get_notifications().count(), 0)
    asmt = Assessment.query.get(asmts["A 5"].id)

    # add another URL, change notification should be created
    url2 = factories.DocumentFactory(link="www.bar.com")
    response, _ = self.objgen.generate_relationship(url2, asmt)
    self.assertEqual(response.status_code, 201)

    change_notifs = self._get_notifications(notif_type="assessment_updated")
    self.assertEqual(change_notifs.count(), 1)

    # clear notifications, delete a URL, test for change notification
    self.client.get("/_notifications/send_daily_digest")
    self.assertEqual(change_notifs.count(), 0)
    asmt = Assessment.query.get(asmts["A 5"].id)

    self.api_helper.delete(relationship)

    change_notifs = self._get_notifications(notif_type="assessment_updated")
    self.assertEqual(change_notifs.count(), 1)

    # changing URLs if completed should result in "reopened" notification
    asmt = Assessment.query.get(asmts["A 5"].id)
    self.api_helper.modify_object(
        asmt, {"status": Assessment.FINAL_STATE})
    self.client.get("/_notifications/send_daily_digest")
    self.assertEqual(self._get_notifications().count(), 0)
    asmt = Assessment.query.get(asmts["A 5"].id)

    url = factories.DocumentFactory(link="www.abc.com")
    response, relationship = self.objgen.generate_relationship(url, asmt)
    self.assertEqual(response.status_code, 201)

    reopened_notifs = self._get_notifications(notif_type="assessment_reopened")
    self.assertEqual(reopened_notifs.count(), 1)
Ejemplo n.º 3
0
    def test_complex_propagation_count(self):
        """Test multiple object ACL propagation.

    This test is meant to catch invalid ACL entries for propagation that can
    not happen.
    Example for this is propagation control -> relationships -> document. In
    that propagation rule we should only propagate control acl entries to
    relationships to documents. But what can happen is; when a control has
    multiple relationships, some to objects and only one to document, all of
    those relationships would get an ACL entry even though in some cases that
    is a propagation dead end.

    Setup for this test is:

    Objects:
      control
      regulation
      objective
      program
      audit
      assessment, assessment_2

    Relationships:
      control - regulation
      control - objective
      objective - regulations
      program - control, regulation, objective, audit
      audit - assessment, assessment_2,
      audit - control-snapshot, regulation-snapshot, objective-snapshot
      control_snapshot - regulation_snapshot
      control_snapshot - objective_snapshot
      objective_snapshot - regulations_snapshot
      document - regulation, objective, control
      evidence - assessment
    """
        # pylint: disable=too-many-locals
        with factories.single_commit():
            control = factories.ControlFactory()
            regulation = factories.RegulationFactory()
            objective = factories.ObjectiveFactory()
            normal_objects = [control, regulation, objective]

            for obj1, obj2 in itertools.combinations(normal_objects, 2):
                if control in (obj1, obj2):
                    with mock.patch(
                            'ggrc.models.relationship.is_external_app_user',
                            return_value=True):
                        factories.RelationshipFactory(source=obj1,
                                                      destination=obj2,
                                                      is_external=True)
                else:
                    factories.RelationshipFactory(source=obj1,
                                                  destination=obj2)

            assessment = factories.AssessmentFactory()
            assessment_2 = factories.AssessmentFactory(audit=assessment.audit)
            factories.RelationshipFactory(
                source=assessment,
                destination=assessment.audit,
            )
            factories.RelationshipFactory(
                source=assessment_2,
                destination=assessment.audit,
            )
            factories.RelationshipFactory(
                source=assessment.audit,
                destination=assessment.audit.program,
            )
            for obj in normal_objects:
                factories.RelationshipFactory(
                    source=assessment.audit.program,
                    destination=obj,
                )

            snapshots = self._create_snapshots(assessment.audit,
                                               normal_objects)
            for snapshot in snapshots:
                factories.RelationshipFactory(
                    source=assessment.audit,
                    destination=snapshot,
                )

            for obj1, obj2 in itertools.combinations(snapshots, 2):
                factories.RelationshipFactory(source=obj1, destination=obj2)

            for obj in normal_objects:
                document = factories.DocumentFactory()
                factories.RelationshipFactory(source=obj, destination=document)

            evidence = factories.EvidenceUrlFactory()
            factories.RelationshipFactory(source=evidence,
                                          destination=assessment)

        acl_entry = control._access_control_list[0]

        propagation._propagate([acl_entry.id], self.user_id)

        self.assertEqual(
            all_models.AccessControlList.query.filter(
                all_models.AccessControlList.parent_id.isnot(None)).count(),
            2,  # 1 for relationship to document and 1 for document.
        )

        acl_entry = next(
            acl for acl in assessment.audit.program._access_control_list
            if acl.ac_role.name == "Program Editors")
        propagation._propagate([acl_entry.id], self.user_id)

        self.assertEqual(
            all_models.AccessControlList.query.filter(
                all_models.AccessControlList.parent_id.isnot(None)).count(),
            2 + 2 + 4 + 6 + 2 + 6 + 6
            # 2 previous entries for control
            # 2 for audit (relationship + audit propagation)
            # 4 for assessments (2 assessments and 2 relationships for them)
            # 6 for snapshots (3 snapshots with relationships)
            # 2 assessment document with relationships
            # 6 for normal objects
            # 6 for normal object documents
        )
Ejemplo n.º 4
0
    def test_changing_assessment_attachment_triggers_notifications(self, _):
        """Test that changing Assessment attachment results in change notification.

    Adding (removing) an attachment to (from) Assessment should be detected and
    considered an Assessment change.
    """
        self.import_file("assessment_with_templates.csv")
        asmts = {asmt.slug: asmt for asmt in Assessment.query}

        self.client.get("/_notifications/send_daily_digest")
        self.assertEqual(self._get_notifications().count(), 0)

        asmt = Assessment.query.get(asmts["A 5"].id)

        # add an attachment, there should be no notifications because the
        # Assessment has not been started yet
        pdf_doc = factories.DocumentFactory(title="foo.pdf")
        data = {
            "document": {
                "type": pdf_doc.type,
                "id": pdf_doc.id
            },
            "documentable": {
                "type": asmt.type,
                "id": asmt.id
            }
        }
        response, obj_doc = self.objgen.generate_object(ObjectDocument,
                                                        data=data)
        self.assertEqual(response.status_code, 201)

        change_notifs = self._get_notifications(
            notif_type="assessment_updated")
        self.assertEqual(change_notifs.count(), 0)
        asmt = Assessment.query.get(asmts["A 5"].id)

        # move Assessment to to "In Progress" state and clear notifications
        self.api_helper.modify_object(asmt,
                                      {"status": Assessment.PROGRESS_STATE})

        self.client.get("/_notifications/send_daily_digest")
        self.assertEqual(self._get_notifications().count(), 0)
        asmt = Assessment.query.get(asmts["A 5"].id)

        # attach another document, change notification should be created
        image = factories.DocumentFactory(link="foobar.png")
        data = {
            "document": {
                "type": image.type,
                "id": image.id
            },
            "documentable": {
                "type": asmt.type,
                "id": asmt.id
            }
        }
        response, _ = self.objgen.generate_object(ObjectDocument, data=data)
        self.assertEqual(response.status_code, 201)

        change_notifs = self._get_notifications(
            notif_type="assessment_updated")
        self.assertEqual(change_notifs.count(), 1)

        # clear notifications, remove an attachment, test for change notification
        self.client.get("/_notifications/send_daily_digest")
        self.assertEqual(change_notifs.count(), 0)
        asmt = Assessment.query.get(asmts["A 5"].id)

        self.api_helper.delete(obj_doc)

        change_notifs = self._get_notifications(
            notif_type="assessment_updated")
        self.assertEqual(change_notifs.count(), 1)

        # changing attachments completed should result in "reopened" notification
        asmt = Assessment.query.get(asmts["A 5"].id)
        self.api_helper.modify_object(asmt, {"status": Assessment.FINAL_STATE})
        self.client.get("/_notifications/send_daily_digest")
        self.assertEqual(self._get_notifications().count(), 0)
        asmt = Assessment.query.get(asmts["A 5"].id)

        file_foo = factories.DocumentFactory(link="foo.txt")
        data = {
            "document": {
                "type": file_foo.type,
                "id": file_foo.id
            },
            "documentable": {
                "type": asmt.type,
                "id": asmt.id
            }
        }
        response, _ = self.objgen.generate_object(ObjectDocument, data=data)
        self.assertEqual(response.status_code, 201)

        reopened_notifs = self._get_notifications(
            notif_type="assessment_reopened")
        self.assertEqual(reopened_notifs.count(), 1)
Ejemplo n.º 5
0
  def test_multiply_actions(self):
    """Test multiply actions"""
    assessment = factories.AssessmentFactory()
    doc_map = factories.DocumentFactory(link="google1.com")
    doc_del = factories.DocumentFactory(link="google2.com")
    factories.RelationshipFactory(source=assessment,
                                  destination=doc_del)

    ca_def = factories.CustomAttributeDefinitionFactory(
        title="def1",
        definition_type="assessment",
        definition_id=assessment.id,
        attribute_type="Dropdown",
        multi_choice_options="no,yes",
        multi_choice_mandatory="0,3"
    )
    ca_val = factories.CustomAttributeValueFactory(
        custom_attribute=ca_def,
        attributable=assessment,
        attribute_value="no"
    )
    response = self.api.put(assessment, {
        "custom_attribute_values": [
            {
                "id": ca_val.id,
                "custom_attribute_id": ca_def.id,
                "attribute_value": "yes",
                "type": "CustomAttributeValue",
            }],
        "actions": {"add_related": [
            {
                "id": None,
                "type": "Document",
                "document_type": "EVIDENCE",
                "title": "evidence1",
                "link": "google3.com",
            },
            {
                "id": doc_map.id,
                "type": "Document",
            },
            {
                "id": None,
                "type": "Comment",
                "description": "comment1",
                "custom_attribute_definition_id": ca_def.id,
            }
        ], "remove_related": [
            {
                "id": doc_del.id,
                "type": "Document",
            }]}})
    self.assert200(response)

    preconditions_failed = response.json["assessment"]["preconditions_failed"]
    self.assertIs(preconditions_failed, True)

    assessment_by_url = self.simple_query(
        "Assessment",
        expression=["evidence url", "~", "google1.com"]
    )
    self.assertEqual(len(assessment_by_url), 1)
    assessment_by_url = self.simple_query(
        "Assessment",
        expression=["evidence url", "~", "google2.com"]
    )
    self.assertFalse(assessment_by_url)
    assessment_by_evidence = self.simple_query(
        "Assessment",
        expression=["evidence file", "~", "google3.com"]
    )
    self.assertEqual(len(assessment_by_evidence), 1)
    assessment_by_comment = self.simple_query(
        "Assessment",
        expression=["comment", "~", "comment1"]
    )
    self.assertEqual(len(assessment_by_comment), 1)