Esempio n. 1
0
class TestReviewStatusUpdate(TestCase):
    """Base TestCase class automatic review status update."""
    def setUp(self):
        super(TestReviewStatusUpdate, self).setUp()
        self.api = Api()
        self.api.client.get("/login")
        self.generator = generator.ObjectGenerator()

    @ddt.data(
        ("title", "new title"),
        ("description", "new description"),
        ("test_plan", "new test_plan"),
        ("notes", "new notes"),
        ("fraud_related", 1),
        ("key_control", 1),
        ("start_date", "2020-01-01"),
        ("status", "Active"),
        ("kind", get_kind_data),
        ("means", get_mean_data),
        ("verify_frequency", get_verify_frequency_data),
        ("assertions", get_assertions_data),
        ("categories", get_categories_data),
    )
    @ddt.unpack
    def test_reviewable_attributes(self, attr_to_modify, new_value):
        """If attribute '{0}' modified move review to Unreviewed state"""
        with factories.single_commit():
            control = factories.ControlFactory()
            review = factories.ReviewFactory(
                status=all_models.Review.STATES.REVIEWED, reviewable=control)
        review_id = review.id
        reviewable = review.reviewable

        self.api.modify_object(reviewable, {
            attr_to_modify:
            new_value() if callable(new_value) else new_value
        })

        review = all_models.Review.query.get(review_id)
        self.assertEqual(review.status, all_models.Review.STATES.UNREVIEWED)

    def test_gca(self):
        """if GCA of reviewable is changed review -> unreviewed"""
        with factories.single_commit():
            ca_factory = factories.CustomAttributeDefinitionFactory
            gca = ca_factory(definition_type="control",
                             title="rich_test_gca",
                             attribute_type="Rich Text")
            control = factories.ControlFactory()
            review = factories.ReviewFactory(
                status=all_models.Review.STATES.REVIEWED, reviewable=control)
        review_id = review.id
        reviewable = review.reviewable

        review = all_models.Review.query.get(review_id)

        self.assertEqual(review.status, all_models.Review.STATES.REVIEWED)

        self.api.modify_object(
            reviewable, {
                "custom_attribute_values": [{
                    "custom_attribute_id": gca.id,
                    "attribute_value": "new_value",
                }],
            })

        review = all_models.Review.query.get(review_id)
        self.assertEqual(review.status, all_models.Review.STATES.UNREVIEWED)

    def test_reference_url(self):
        """If reference url is updated state should not updated"""
        with factories.single_commit():
            control = factories.ControlFactory()
            doc = factories.DocumentReferenceUrlFactory(
                title="Simple title",
                link="some_url.com",
                description="mega description",
                parent_obj={
                    "id": control.id,
                    "type": "Control"
                })
            review = factories.ReviewFactory(
                status=all_models.Review.STATES.REVIEWED, reviewable=control)
        review_id = review.id

        self.api.modify_object(doc, {"link": "new_link.com"})
        review = all_models.Review.query.get(review_id)
        self.assertEqual(review.status, all_models.Review.STATES.REVIEWED)

    def test_acl_roles(self):
        """Update of reviewable ACL shouldn't change review status"""
        with factories.single_commit():
            control = factories.ControlFactory()
            review = factories.ReviewFactory(
                status=all_models.Review.STATES.REVIEWED, reviewable=control)
        review_id = review.id

        ac_role_id = all_models.AccessControlRole.query.filter_by(
            name="Primary Contacts", object_type="Control").one().id

        user_id = all_models.Person.query.filter_by(
            email="*****@*****.**").one().id

        self.api.modify_object(
            control, {
                "access_control_list": [{
                    "ac_role_id": ac_role_id,
                    "person": {
                        "id": user_id
                    },
                }],
            })
        review = all_models.Review.query.get(review_id)
        self.assertEqual(review.status, all_models.Review.STATES.REVIEWED)

    def test_comments(self):
        """Add comment to reviewable shouldn't update review state"""
        with factories.single_commit():
            control = factories.ControlFactory()
            review = factories.ReviewFactory(
                status=all_models.Review.STATES.REVIEWED, reviewable=control)
        review_id = review.id

        self.generator.generate_comment(control,
                                        "Verifiers",
                                        "some comment",
                                        send_notification="false")

        review = all_models.Review.query.get(review_id)
        self.assertEqual(review.status, all_models.Review.STATES.REVIEWED)

    def test_mapping_non_snapshotable(self):
        """Map non-snapshotable shouldn't change review status"""
        with factories.single_commit():
            control = factories.ControlFactory()
            review = factories.ReviewFactory(
                status=all_models.Review.STATES.REVIEWED, reviewable=control)
            review_id = review.id

        factories.RelationshipFactory(source=control,
                                      destination=factories.IssueFactory())

        review = all_models.Review.query.get(review_id)
        self.assertEqual(review.status, all_models.Review.STATES.REVIEWED)

    @ddt.data("Standard", "Regulation", "Requirement", "Objective", "Control",
              "Product", "System", "Process", "AccessGroup", "Contract",
              "DataAsset", "Facility", "Market", "OrgGroup", "Policy", "Risk",
              "Threat", "Vendor")
    def test_map_snapshotable(self, snapshotable):
        """Map '{}' should change review status"""
        with factories.single_commit():
            control = factories.ControlFactory()
            review = factories.ReviewFactory(
                status=all_models.Review.STATES.REVIEWED, reviewable=control)
            review_id = review.id

        self.generator.generate_relationship(
            source=control,
            destination=factories.get_model_factory(snapshotable)(),
            context=None,
        )

        review = all_models.Review.query.get(review_id)
        self.assertEqual(review.status, all_models.Review.STATES.UNREVIEWED)

    def test_unmap_snapshotable(self):
        """Unmap snapshotable should change review status"""
        control = factories.ControlFactory()
        resp, review = self.generator.generate_object(
            all_models.Review,
            {
                "reviewable": {
                    "type": control.type,
                    "id": control.id,
                },
                "context": None,
                "status": all_models.Review.STATES.UNREVIEWED,
                "access_control_list": build_reviewer_acl(),
                "notification_type":
                all_models.Review.NotificationTypes.EMAIL_TYPE
            },
        )
        review_id = review.id

        _, rel = self.generator.generate_relationship(
            source=control,
            destination=factories.ProductFactory(),
            context=None,
        )

        review = all_models.Review.query.get(review_id)
        resp = self.api.modify_object(
            review, {"status": all_models.Review.STATES.REVIEWED})
        self.assert200(resp)

        resp = self.api.delete(rel)
        self.assert200(resp)
        review = all_models.Review.query.get(review_id)
        self.assertEqual(review.status, all_models.Review.STATES.UNREVIEWED)

    @ddt.data(
        "Assessment",
        "Issue",
        "Program",
        "Project",
        "Audit",
        "RiskAssessment",
        "AssessmentTemplate",
        "Person",
    )
    def test_map_nonsnapshotable(self, nonsnapshotable):
        """Map '{}' shouldn't change review status"""
        control = factories.ControlFactory()
        _, review = self.generator.generate_object(
            all_models.Review,
            {
                "reviewable": {
                    "type": control.type,
                    "id": control.id,
                },
                "context": None,
                "status": all_models.Review.STATES.REVIEWED,
                "access_control_list": build_reviewer_acl(),
                "notification_type":
                all_models.Review.NotificationTypes.EMAIL_TYPE
            },
        )
        review_id = review.id

        review = all_models.Review.query.get(review_id)

        self.assertEqual(review.status, all_models.Review.STATES.REVIEWED)

        self.generator.generate_relationship(
            source=control,
            destination=factories.get_model_factory(nonsnapshotable)(),
            context=None,
        )

        review = all_models.Review.query.get(review_id)
        self.assertEqual(review.status, all_models.Review.STATES.REVIEWED)

    def test_unmap_nonsnapshotable(self):
        """Unmap nonsnapshotable shouldn't change review status"""
        control = factories.ControlFactory()
        resp, review = self.generator.generate_object(
            all_models.Review,
            {
                "reviewable": {
                    "type": control.type,
                    "id": control.id,
                },
                "context": None,
                "status": all_models.Review.STATES.REVIEWED,
                "access_control_list": build_reviewer_acl(),
                "notification_type":
                all_models.Review.NotificationTypes.EMAIL_TYPE
            },
        )
        review_id = review.id
        _, rel = self.generator.generate_relationship(
            source=control,
            destination=factories.ProgramFactory(),
            context=None,
        )

        review = all_models.Review.query.get(review_id)
        resp = self.api.modify_object(
            review, {"status": all_models.Review.STATES.REVIEWED})
        self.assert200(resp)
        review = all_models.Review.query.get(review_id)
        self.assertEqual(review.status, all_models.Review.STATES.REVIEWED)

        resp = self.api.delete(rel)
        self.assert200(resp)
        review = all_models.Review.query.get(review_id)
        self.assertEqual(review.status, all_models.Review.STATES.REVIEWED)

    def test_proposal_apply(self):
        """Reviewable object changed via proposal -> review.state-> UNREVIEWED"""
        control = factories.ControlFactory()
        _, review = self.generator.generate_object(
            all_models.Review,
            {
                "reviewable": {
                    "type": control.type,
                    "id": control.id,
                },
                "context": None,
                "status": all_models.Review.STATES.UNREVIEWED,
                "access_control_list": build_reviewer_acl(),
                "notification_type":
                all_models.Review.NotificationTypes.EMAIL_TYPE
            },
        )

        review_id = review.id

        proposal_content = {
            "fields": {
                "title": "new title"
            },
        }
        proposal = factories.ProposalFactory(instance=control,
                                             content=proposal_content,
                                             agenda="agenda content")
        self.api.modify_object(proposal, {"status": proposal.STATES.APPLIED})

        review = all_models.Review.query.get(review_id)
        self.assertEqual(review.status, all_models.Review.STATES.UNREVIEWED)
class TestAuditDeprecated(TestCase):
    """Test for correct working field last_deprecated_date """
    def setUp(self):
        super(TestAuditDeprecated, self).setUp()
        self.api = Api()

    def test_redefine_status(self):
        """Test create audit and change status to Deprecated"""
        audit = factories.AuditFactory()

        with freeze_time("2017-01-25"):
            self.api.modify_object(audit, {"status": "Deprecated"})

        audit_result = all_models.Audit.query.filter(
            all_models.Audit.id == audit.id).one()

        self.assertEquals(audit_result.last_deprecated_date,
                          datetime.date(2017, 1, 25))

    def test_keep_date_unchanged(self):
        """Test set status audit to Deprecated, and then set status to Planned"""
        audit = factories.AuditFactory()

        with freeze_time("2017-01-25"):
            self.api.modify_object(audit, {"status": "Deprecated"})

        with freeze_time("2017-01-26"):
            self.api.modify_object(audit, {"status": "Planned"})

        audit_result = all_models.Audit.query.filter(
            all_models.Audit.id == audit.id).one()

        self.assertEquals(audit_result.status, "Planned")
        self.assertEquals(audit_result.last_deprecated_date,
                          datetime.date(2017, 1, 25))

    def test_repeat_deprecated_state(self):
        """Test set status audit to Deprecated, then to Planned,
    then to Deprecated and then to Planned"""
        audit = factories.AuditFactory()

        with freeze_time("2017-01-25"):
            self.api.modify_object(audit, {"status": "Deprecated"})

        with freeze_time("2017-01-26"):
            self.api.modify_object(audit, {"status": "Planned"})
        with freeze_time("2017-02-25"):
            self.api.modify_object(audit, {"status": "Deprecated"})
        with freeze_time("2017-02-26"):
            self.api.modify_object(audit, {"status": "Planned"})

        audit_result = all_models.Audit.query.filter(
            all_models.Audit.id == audit.id).one()

        self.assertEquals(audit_result.status, "Planned")
        self.assertEquals(audit_result.last_deprecated_date,
                          datetime.date(2017, 2, 25))

    def test_filter_by_deprecated_date(self):
        """Test filter audits by last deprecated date"""
        amount_of_audits = 5
        list_of_ids = []
        with factories.single_commit():
            with freeze_time("2017-01-25"):
                for _ in range(amount_of_audits):
                    list_of_ids.append(
                        factories.AuditFactory(status="Deprecated").id)

        query_request_data = [{
            "object_name": "Audit",
            'filters': {
                'expression': {
                    'left': 'Last Deprecated Date',
                    'op': {
                        'name': '='
                    },
                    'right': "2017-01-25",
                },
            },
            'type': 'ids',
        }]

        result = self.api.send_request(self.api.client.post,
                                       data=query_request_data,
                                       api_link="/query")
        self.assertItemsEqual(list_of_ids, result.json[0]["Audit"]["ids"])

    def test_sort_by_deprecated_date(self):
        """Test sorting results of filter audits by deprecated date"""
        dict_of_dates = {}
        date_list = ["2017-01-25", "2017-01-29", "2017-01-02", "2017-01-26"]
        with factories.single_commit():
            for date in date_list:
                with freeze_time(date):
                    dict_of_dates[factories.AuditFactory(
                        status="Deprecated").id] = date

        sorted_dict = sorted(dict_of_dates.items(), key=operator.itemgetter(1))
        sorted_list_ids = [item[0] for item in sorted_dict]

        query_request_data = [{
            "object_name": "Audit",
            'filters': {
                'expression': {
                    'left': 'Last Deprecated Date',
                    'op': {
                        'name': '='
                    },
                    'right': "2017-01",
                },
            },
            "order_by": [{
                "name": "last_deprecated_date"
            }],
            'type': 'ids',
        }]

        result = self.api.send_request(self.api.client.post,
                                       data=query_request_data,
                                       api_link="/query")

        self.assertItemsEqual(sorted_list_ids, result.json[0]["Audit"]["ids"])
class TestAuditRBAC(TestCase):
  """Test audit RBAC"""
  # pylint: disable=too-many-instance-attributes

  CSV_DIR = join(abspath(dirname(__file__)), "test_csvs")

  def setUp(self):
    """Imports test_csvs/audit_rbac_snapshot_create.csv needed by the tests"""
    TestCase.clear_data()
    self.api = Api()
    self.objgen = integration.ggrc.generator.ObjectGenerator()

    self.csv_files = itertools.cycle([
        "audit_rbac_snapshot_create.csv",
        "audit_rbac_snapshot_update.csv"
    ])

    self._import_file(next(self.csv_files))
    self.people = all_models.Person.eager_query().all()

    self.program = db.session.query(all_models.Program).filter(
        all_models.Program.slug == "PMRBACPROGRAM-1"
    ).one()

    sources = set(r.source for r in self.program.related_sources)
    destinations = set(r.destination
                       for r in self.program.related_destinations)
    related = [obj for obj in sources.union(destinations)
               if not isinstance(obj, all_models.Person)]
    self.related_objects = related

    self.api = Api()
    self.client.get("/login")

    self.audit = self.create_audit()

    self.snapshots = all_models.Snapshot.eager_query().all()

    self.sanity_check()

  def create_audit(self):
    """Create default audit for audit snapshot RBAC tests"""
    _, audit = self.objgen.generate_object(all_models.Audit, {
        "title": "Snapshotable audit",
        "program": {"id": self.program.id},
        "status": "Planned",
        "snapshots": {
            "operation": "create",
        },
        "context": {
            "type": "Context",
            "id": self.program.context_id,
            "href": "/api/contexts/{}".format(self.program.context_id)
        }
    })
    self.add_auditors(audit)
    return audit

  def add_auditors(self, audit):
    """Add auditors to audits via POST user_role call"""
    auditor_emails = [
        "*****@*****.**",
        "*****@*****.**",
        "*****@*****.**",
        "*****@*****.**",
    ]
    program_reader_emails = [
        "*****@*****.**",
    ]
    auditor_role = db.session.query(all_models.Role).filter(
        all_models.Role.name == "Auditor"
    ).one()
    program_reader_role = db.session.query(all_models.Role).filter(
        all_models.Role.name == "ProgramReader"
    ).one()

    program = db.session.query(all_models.Program).filter(
        all_models.Program.slug == "PMRBACPROGRAM-1"
    ).one()

    user_roles = [
        (auditor_emails, auditor_role, audit.context),
        (program_reader_emails, program_reader_role, program.context)
    ]

    for emails, role, context in user_roles:
      for email in emails:
        auditor = all_models.Person.query.filter(
            all_models.Person.email == email).one()
        self.objgen.generate_user_role(auditor, role, context)

  def update_audit(self):
    """Update default audit"""
    self._import_file(next(self.csv_files))

    audit = all_models.Audit.query.filter(
        all_models.Audit.title == "Snapshotable audit"
    ).one()
    self.audit = audit

    self.api.modify_object(self.audit, {
        "snapshots": {
            "operation": "upsert"
        }
    })

  def sanity_check(self):
    """Sanity check if the audit_rbac.csv was imported correctly"""
    assert len(self.people) == 21, \
        "Expecting 21 people not {}.".format(len(self.people))
    assert len(self.related_objects) == 19, \
        "Expecting 19 objects mapped to program not {}.".format(
            len(self.related_objects))
    assert len(self.snapshots) == 19, \
        "Expecting 19 snapshots for default audit not {}.".format(
            len(self.snapshots))
    assert all(ss.parent_id == self.audit.id for ss in self.snapshots), \
        "All snapshots should be in default audit scope!"

  def read(self, objects):
    """Attempt to do a GET request for every object in the objects list"""
    responses = []
    for obj in objects:
      status_code = self.api.get(obj.__class__, obj.id).status_code
      responses.append((obj.type, status_code))
    return responses

  def update(self, objects):
    """Attempt to do a PUT request for every object in the objects list"""
    scope_response = self.api.get(self.audit.__class__, self.audit.id)
    if scope_response.status_code == 200:
      self.update_audit()

    responses = []
    for obj in objects:
      response = self.api.get(obj.__class__, obj.id)
      status_code = response.status_code
      if response.status_code == 200:
        data = response.json
        if obj.type == "Snapshot":
          data.update({
              "update_revision": "latest"
          })
        put_call = self.api.put(obj, data)
        status_code = put_call.status_code
      responses.append((obj.type, status_code))
    return responses

  def call_api(self, method, expected_statuses):
    """Calls the REST api with a given method and returns a list of
       status_codes that do not match the expected_statuses dict"""
    all_errors = []
    for person in self.people:
      self.api.set_user(person)
      responses = method(self.snapshots + [self.audit])
      for type_, code in responses:
        if code != expected_statuses[person.email][type_]:
          all_errors.append("{} does not have {} access to {} ({})".format(
              person.email, method.__name__, type_, code))
    return all_errors

  def test_read_access_on_mapped(self):
    """Test READ access to snapshotted objects of default audit"""
    expected_statuses = defaultdict(lambda: defaultdict(lambda: 200))
    exceptional_users = (
        ("*****@*****.**", DEFAULT_LACK_OF_PERMISSIONS),
    )
    for user, exceptions in exceptional_users:
      for type_, status_code in exceptions.items():
        expected_statuses[user][type_] = status_code
    errors = self.call_api(self.read, expected_statuses)
    assert not errors, "\n".join(errors)

  def test_update_access_on_mapped(self):
    """Test UPDATE access to snapshotted objects of default audit"""
    expected_statuses = defaultdict(lambda: defaultdict(lambda: 200))

    exceptional_users = (
        ("*****@*****.**", DEFAULT_LACK_OF_PERMISSIONS),
        ("*****@*****.**", DEFAULT_LACK_OF_PERMISSIONS),
        ("*****@*****.**", DEFAULT_LACK_OF_PERMISSIONS),
        ("*****@*****.**", DEFAULT_LACK_OF_PERMISSIONS),
        # Auditor roles
        ("*****@*****.**", DEFAULT_AUDITOR_PERMISSIONS),
        ("*****@*****.**", DEFAULT_AUDITOR_PERMISSIONS)
    )

    for user, exceptions in exceptional_users:
      for type_, status_code in exceptions.items():
        expected_statuses[user][type_] = status_code

    errors = self.call_api(self.update, expected_statuses)
    assert not errors, "\n".join(errors)
class TestAuditRBAC(TestCase):
    """Test audit RBAC"""
    # pylint: disable=too-many-instance-attributes

    CSV_DIR = join(abspath(dirname(__file__)), "test_csvs")

    def setUp(self):
        """Imports test_csvs/audit_rbac_snapshot_create.csv needed by the tests"""
        TestCase.clear_data()
        self.api = Api()
        self.objgen = integration.ggrc.generator.ObjectGenerator()

        self.csv_files = itertools.cycle([
            "audit_rbac_snapshot_create.csv", "audit_rbac_snapshot_update.csv"
        ])

        response = self._import_file(next(self.csv_files))
        self._check_csv_response(response, {})

        self.people = all_models.Person.eager_query().all()

        self.program = db.session.query(all_models.Program).filter(
            all_models.Program.slug == "PMRBACPROGRAM-1").one()

        sources = set(r.source for r in self.program.related_sources)
        destinations = set(r.destination
                           for r in self.program.related_destinations)
        related = [
            obj for obj in sources.union(destinations)
            if not isinstance(obj, all_models.Person)
        ]
        self.related_objects = related

        self.api = Api()
        self.client.get("/login")

        self.audit = self.create_audit()

        self.snapshots = all_models.Snapshot.eager_query().all()

    def create_audit(self):
        """Create default audit for audit snapshot RBAC tests"""
        _, audit = self.objgen.generate_object(
            all_models.Audit, {
                "title": "Snapshotable audit",
                "program": {
                    "id": self.program.id
                },
                "status": "Planned",
                "snapshots": {
                    "operation": "create",
                },
                "context": {
                    "type": "Context",
                    "id": self.program.context_id,
                    "href": "/api/contexts/{}".format(self.program.context_id)
                }
            })
        self.add_auditors(audit)
        return audit

    def add_auditors(self, audit):
        """Add auditors to audits via POST user_role call"""
        auditor_emails = [
            "*****@*****.**",
            "*****@*****.**",
            "*****@*****.**",
            "*****@*****.**",
        ]
        program_reader_emails = [
            "*****@*****.**",
        ]
        auditor_role = db.session.query(
            all_models.Role).filter(all_models.Role.name == "Auditor").one()
        program_reader_role = db.session.query(all_models.Role).filter(
            all_models.Role.name == "ProgramReader").one()

        program = db.session.query(all_models.Program).filter(
            all_models.Program.slug == "PMRBACPROGRAM-1").one()

        user_roles = [(auditor_emails, auditor_role, audit.context),
                      (program_reader_emails, program_reader_role,
                       program.context)]

        for emails, role, context in user_roles:
            for email in emails:
                auditor = all_models.Person.query.filter(
                    all_models.Person.email == email).one()
                self.objgen.generate_user_role(auditor, role, context)

    def update_audit(self):
        """Update default audit"""
        response = self._import_file(next(self.csv_files))
        self._check_csv_response(response, {})

        audit = all_models.Audit.query.filter(
            all_models.Audit.title == "Snapshotable audit").one()
        self.audit = audit

        self.api.modify_object(self.audit,
                               {"snapshots": {
                                   "operation": "upsert"
                               }})

    def read(self, objects):
        """Attempt to do a GET request for every object in the objects list"""
        responses = []
        for obj in objects:
            status_code = self.api.get(obj.__class__, obj.id).status_code
            responses.append((obj.type, status_code))
        return responses

    def update(self, objects):
        """Attempt to do a PUT request for every object in the objects list"""
        scope_response = self.api.get(self.audit.__class__, self.audit.id)
        if scope_response.status_code == 200:
            self.update_audit()

        responses = []
        for obj in objects:
            response = self.api.get(obj.__class__, obj.id)
            status_code = response.status_code
            if response.status_code == 200:
                data = response.json
                if obj.type == "Snapshot":
                    data.update({"update_revision": "latest"})
                put_call = self.api.put(obj, data)
                status_code = put_call.status_code
            responses.append((obj.type, status_code))
        return responses

    def call_api(self, method, expected_statuses):
        """Calls the REST api with a given method and returns a list of
       status_codes that do not match the expected_statuses dict"""
        all_errors = []
        for person in self.people:
            self.api.set_user(person)
            responses = method(self.snapshots + [self.audit])
            for type_, code in responses:
                if code != expected_statuses[person.email][type_]:
                    all_errors.append(
                        "{} does not have {} access to {} ({})".format(
                            person.email, method.__name__, type_, code))
        return all_errors

    def test_read_access_on_mapped(self):
        """Test READ access to snapshotted objects of default audit"""
        expected_statuses = defaultdict(lambda: defaultdict(lambda: 200))
        exceptional_users = (("*****@*****.**",
                              DEFAULT_LACK_OF_PERMISSIONS), )
        for user, exceptions in exceptional_users:
            for type_, status_code in exceptions.items():
                expected_statuses[user][type_] = status_code
        errors = self.call_api(self.read, expected_statuses)
        assert not errors, "\n".join(errors)

    def test_update_access_on_mapped(self):
        """Test UPDATE access to snapshotted objects of default audit"""
        expected_statuses = defaultdict(lambda: defaultdict(lambda: 200))

        exceptional_users = (
            ("*****@*****.**", DEFAULT_LACK_OF_PERMISSIONS),
            ("*****@*****.**", DEFAULT_LACK_OF_PERMISSIONS),
            ("*****@*****.**", DEFAULT_LACK_OF_PERMISSIONS),
            ("*****@*****.**", DEFAULT_LACK_OF_PERMISSIONS),
            # Auditor roles
            ("*****@*****.**", DEFAULT_AUDITOR_PERMISSIONS),
            ("*****@*****.**", DEFAULT_AUDITOR_PERMISSIONS))

        for user, exceptions in exceptional_users:
            for type_, status_code in exceptions.items():
                expected_statuses[user][type_] = status_code

        errors = self.call_api(self.update, expected_statuses)
        assert not errors, "\n".join(errors)
Esempio n. 5
0
class TestReviewStatusUpdate(TestCase):
  """Base TestCase class automatic review status update."""

  def setUp(self):
    super(TestReviewStatusUpdate, self).setUp()
    self.api = Api()
    self.api.login_as_external()

    self.generator = generator.ObjectGenerator()

  def test_gca(self):
    """if GCA of reviewable is changed review -> unreviewed"""
    with factories.single_commit():
      ca_factory = factories.CustomAttributeDefinitionFactory
      gca = ca_factory(
          definition_type="risk",
          title="rich_test_gca",
          attribute_type="Rich Text"
      )
      risk = factories.RiskFactory()
      review = factories.ReviewFactory(
          status=all_models.Review.STATES.REVIEWED, reviewable=risk
      )
    review_id = review.id
    reviewable = review.reviewable

    review = all_models.Review.query.get(review_id)

    self.assertEqual(review.status, all_models.Review.STATES.REVIEWED)

    self.api.modify_object(
        reviewable, {
            "custom_attribute_values":
            [{
                "custom_attribute_id": gca.id,
                "attribute_value": "new_value",
            }],
        }
    )

    review = all_models.Review.query.get(review_id)
    self.assertEqual(review.status, all_models.Review.STATES.UNREVIEWED)

  def test_update_gca(self):
    """if existing GCA value changed review -> unreviewed"""
    with factories.single_commit():
      ca_factory = factories.CustomAttributeDefinitionFactory
      gca = ca_factory(
          definition_type="risk",
          title="rich_test_gca",
          attribute_type="Rich Text"
      )
      risk = factories.RiskFactory()

      risk.custom_attribute_values = [{
          "attribute_value": "starting_value",
          "custom_attribute_id": gca.id
      }]
      review = factories.ReviewFactory(
          status=all_models.Review.STATES.REVIEWED, reviewable=risk
      )
    review_id = review.id
    reviewable = review.reviewable

    review = all_models.Review.query.get(review_id)

    self.assertEqual(review.status, all_models.Review.STATES.REVIEWED)

    self.api.modify_object(
        reviewable, {
            "custom_attribute_values":
            [{
                "custom_attribute_id": gca.id,
                "attribute_value": "new_value",
            }],
        }
    )

    review = all_models.Review.query.get(review_id)
    self.assertEqual(review.status, all_models.Review.STATES.UNREVIEWED)

  @ddt.data("custom attr", "slug", "self")
  def test_gca_with_varying_titles(self, title):
    """if GCA with any title is changed review -> unreviewed"""
    with factories.single_commit():
      ca_factory = factories.CustomAttributeDefinitionFactory
      gca = ca_factory(
          definition_type="risk",
          title=title,
          attribute_type="Rich Text"
      )
      risk = factories.RiskFactory()

      risk.custom_attribute_values = [{
          "attribute_value": "starting_value",
          "custom_attribute_id": gca.id
      }]
      review = factories.ReviewFactory(
          status=all_models.Review.STATES.REVIEWED, reviewable=risk
      )
    review_id = review.id
    reviewable = review.reviewable

    review = all_models.Review.query.get(review_id)

    self.assertEqual(review.status, all_models.Review.STATES.REVIEWED)

    self.api.modify_object(
        reviewable, {
            "custom_attribute_values":
            [{
                "custom_attribute_id": gca.id,
                "attribute_value": "new_value",
            }],
        }
    )

    review = all_models.Review.query.get(review_id)
    self.assertEqual(review.status, all_models.Review.STATES.UNREVIEWED)

  def test_map_person_gca(self):
    """if Map:Person GCA value added review -> unreviewed"""
    with factories.single_commit():
      ca_factory = factories.CustomAttributeDefinitionFactory
      gca = ca_factory(
          definition_type="risk",
          title="map_test_gca",
          attribute_type="Map:Person"
      )

      user_id = all_models.Person.query.filter_by(
          email="*****@*****.**"
      ).one().id

      risk = factories.RiskFactory()
      review = factories.ReviewFactory(
          status=all_models.Review.STATES.REVIEWED, reviewable=risk
      )

    review_id = review.id
    reviewable = review.reviewable
    review = all_models.Review.query.get(review_id)

    self.assertEqual(review.status, all_models.Review.STATES.REVIEWED)

    self.api.modify_object(
        reviewable, {
            "custom_attribute_values":
            [{
                "custom_attribute_id": gca.id,
                "attribute_object_id": user_id,
                "attribute_value": "Person",
            }],
        }
    )

    review = all_models.Review.query.get(review_id)
    self.assertEqual(review.status, all_models.Review.STATES.UNREVIEWED)

  def test_update_map_person_gca(self):
    """if existing Map:Person GCA value changed review -> unreviewed"""
    with factories.single_commit():
      ca_factory = factories.CustomAttributeDefinitionFactory
      gca = ca_factory(
          definition_type="risk",
          title="map_test_gca",
          attribute_type="Map:Person"
      )

      first_user_id = all_models.Person.query.filter_by(
          email="*****@*****.**"
      ).one().id
      second_user_id = factories.PersonFactory().id

      risk = factories.RiskFactory()
      risk.custom_attribute_values = [{
          "attribute_object_id": first_user_id,
          "custom_attribute_id": gca.id,
          "attribute_value": "Person"
      }]
      review = factories.ReviewFactory(
          status=all_models.Review.STATES.REVIEWED, reviewable=risk
      )

    review_id = review.id
    reviewable = review.reviewable
    review = all_models.Review.query.get(review_id)

    self.assertEqual(review.status, all_models.Review.STATES.REVIEWED)

    self.api.modify_object(
        reviewable, {
            "custom_attribute_values":
            [{
                "custom_attribute_id": gca.id,
                "attribute_object_id": second_user_id,
                "attribute_value": "Person",
            }],
        }
    )

    review = all_models.Review.query.get(review_id)
    self.assertEqual(review.status, all_models.Review.STATES.UNREVIEWED)

  def test_delete_map_person_gca(self):
    """if existing Map:Person GCA value deleted review -> unreviewed"""
    with factories.single_commit():
      ca_factory = factories.CustomAttributeDefinitionFactory
      gca = ca_factory(
          definition_type="risk",
          title="map_test_gca",
          attribute_type="Map:Person"
      )

      user_id = all_models.Person.query.filter_by(
          email="*****@*****.**"
      ).one().id

      risk = factories.RiskFactory()
      risk.custom_attribute_values = [{
          "attribute_object_id": user_id,
          "custom_attribute_id": gca.id,
          "attribute_value": "Person"
      }]
      review = factories.ReviewFactory(
          status=all_models.Review.STATES.REVIEWED, reviewable=risk
      )

    review_id = review.id
    reviewable = review.reviewable
    review = all_models.Review.query.get(review_id)

    self.assertEqual(review.status, all_models.Review.STATES.REVIEWED)

    self.api.modify_object(
        reviewable, {
            "custom_attribute_values":
            [{
                "custom_attribute_id": gca.id,
                "attribute_object_id": None,
                "attribute_object": None,
                "attribute_value": "Person",
            }],
        }
    )

    review = all_models.Review.query.get(review_id)
    self.assertEqual(review.status, all_models.Review.STATES.UNREVIEWED)

  def test_reference_url(self):
    """If reference url is updated state should not updated"""
    with factories.single_commit():
      risk = factories.RiskFactory()
      doc = factories.DocumentReferenceUrlFactory(
          title="Simple title",
          link="some_url.com",
          description="mega description",
          parent_obj={
              "id": risk.id,
              "type": "Risk"
          }
      )
      review = factories.ReviewFactory(
          status=all_models.Review.STATES.REVIEWED, reviewable=risk
      )
    review_id = review.id

    self.api.modify_object(doc, {"link": "new_link.com"})
    review = all_models.Review.query.get(review_id)
    self.assertEqual(review.status, all_models.Review.STATES.REVIEWED)

  def test_acl_roles(self):
    """Update of reviewable ACL shouldn't change review status"""
    with factories.single_commit():
      risk = factories.RiskFactory()
      review = factories.ReviewFactory(
          status=all_models.Review.STATES.REVIEWED, reviewable=risk
      )
    review_id = review.id

    ac_role_id = all_models.AccessControlRole.query.filter_by(
        name="Admin", object_type="Risk"
    ).one().id

    user_id = all_models.Person.query.filter_by(
        email="*****@*****.**"
    ).one().id

    self.api.modify_object(
        risk, {
            "access_control_list":
            [{
                "ac_role_id": ac_role_id,
                "person": {
                    "id": user_id
                },
            }],
        }
    )
    review = all_models.Review.query.get(review_id)
    self.assertEqual(review.status, all_models.Review.STATES.REVIEWED)

  def test_comments(self):
    """Add comment to reviewable shouldn't update review state"""
    with factories.single_commit():
      risk = factories.RiskFactory()
      review = factories.ReviewFactory(
          status=all_models.Review.STATES.REVIEWED, reviewable=risk
      )
    review_id = review.id

    self.generator.generate_comment(
        risk, "Verifiers", "some comment", send_notification="false"
    )

    review = all_models.Review.query.get(review_id)
    self.assertEqual(review.status, all_models.Review.STATES.REVIEWED)

  def test_mapping_non_snapshotable(self):
    """Map non-snapshotable shouldn't change review status"""
    with factories.single_commit():
      risk = factories.RiskFactory()
      review = factories.ReviewFactory(
          status=all_models.Review.STATES.REVIEWED, reviewable=risk
      )
      review_id = review.id

    factories.RelationshipFactory(
        source=risk, destination=factories.IssueFactory()
    )

    review = all_models.Review.query.get(review_id)
    self.assertEqual(review.status, all_models.Review.STATES.REVIEWED)

  @ddt.data(
      "Standard",
      "Regulation",
      "Requirement",
      "Objective",
      "Control",
      "Product",
      "System",
      "Process",
      "AccessGroup",
      "Contract",
      "DataAsset",
      "Facility",
      "Market",
      "OrgGroup",
      "Policy",
      "Risk",
      "Threat",
      "Vendor"
  )
  def test_map_snapshotable(self, snapshotable):
    """Map '{}' should change review status"""
    with factories.single_commit():
      risk = factories.RiskFactory()
      review = factories.ReviewFactory(
          status=all_models.Review.STATES.REVIEWED, reviewable=risk
      )
      review_id = review.id

    self.generator.generate_relationship(
        source=risk,
        destination=factories.get_model_factory(snapshotable)(),
        context=None,
    )

    review = all_models.Review.query.get(review_id)
    self.assertEqual(review.status, all_models.Review.STATES.UNREVIEWED)

  def test_unmap_snapshotable(self):
    """Unmap snapshotable should change review status"""
    self.api.login_as_normal()

    risk = factories.RiskFactory()
    resp, review = generate_review_object(risk)
    review_id = review.id

    _, rel = self.generator.generate_relationship(
        source=risk,
        destination=factories.ProductFactory(),
        context=None,
    )

    review = all_models.Review.query.get(review_id)
    resp = self.api.modify_object(
        review, {"status": all_models.Review.STATES.REVIEWED}
    )
    self.assert200(resp)

    resp = self.api.delete(rel)
    self.assert200(resp)
    review = all_models.Review.query.get(review_id)
    self.assertEqual(review.status, all_models.Review.STATES.UNREVIEWED)

  @ddt.data(
      "Assessment",
      "Issue",
      "Program",
      "Project",
      "Audit",
      "RiskAssessment",
      "AssessmentTemplate",
      "Person",
  )
  def test_map_nonsnapshotable(self, nonsnapshotable):
    """Map '{}' shouldn't change review status"""
    risk = factories.RiskFactory()
    _, review = generate_review_object(
        risk, state=all_models.Review.STATES.REVIEWED)
    review_id = review.id

    review = all_models.Review.query.get(review_id)

    self.assertEqual(review.status, all_models.Review.STATES.REVIEWED)

    self.generator.generate_relationship(
        source=risk,
        destination=factories.get_model_factory(nonsnapshotable)(),
        context=None,
    )

    review = all_models.Review.query.get(review_id)
    self.assertEqual(review.status, all_models.Review.STATES.REVIEWED)

  def test_unmap_nonsnapshotable(self):
    """Unmap nonsnapshotable shouldn't change review status"""
    self.api.login_as_normal()

    risk = factories.RiskFactory()
    resp, review = generate_review_object(
        risk, state=all_models.Review.STATES.REVIEWED)
    review_id = review.id
    _, rel = self.generator.generate_relationship(
        source=risk,
        destination=factories.ProgramFactory(),
        context=None,
    )

    review = all_models.Review.query.get(review_id)
    resp = self.api.modify_object(
        review, {"status": all_models.Review.STATES.REVIEWED}
    )
    self.assert200(resp)
    review = all_models.Review.query.get(review_id)
    self.assertEqual(review.status, all_models.Review.STATES.REVIEWED)

    resp = self.api.delete(rel)
    self.assert200(resp)
    review = all_models.Review.query.get(review_id)
    self.assertEqual(review.status, all_models.Review.STATES.REVIEWED)

  def test_proposal_apply(self):
    """Reviewable object changed via proposal -> review.state-> UNREVIEWED"""
    risk = factories.RiskFactory()
    _, review = generate_review_object(risk)

    review_id = review.id

    proposal_content = {
        "fields": {
            "title": "new title"
        },
    }
    proposal = factories.ProposalFactory(
        instance=risk, content=proposal_content, agenda="agenda content"
    )
    self.api.modify_object(proposal, {"status": proposal.STATES.APPLIED})

    review = all_models.Review.query.get(review_id)
    self.assertEqual(review.status, all_models.Review.STATES.UNREVIEWED)

  def test_review_status_update(self):
    """Test updating folder preserves review status"""
    risk = factories.RiskFactory()
    factories.ReviewFactory(
        reviewable=risk,
        status=all_models.Review.STATES.REVIEWED,
    )
    self.api.put(risk, {"folder": factories.random_str()})
    risk = all_models.Risk.query.get(risk.id)
    self.assertEqual(risk.review.status, all_models.Review.STATES.REVIEWED)
Esempio n. 6
0
class TestAuditRBAC(TestCase):
    """Test audit RBAC"""

    # pylint: disable=too-many-instance-attributes

    def setUp(self):
        """Imports test_csvs/audit_rbac_snapshot_create.csv needed by the tests"""
        TestCase.clear_data()
        self.api = Api()
        self.objgen = integration.ggrc.generator.ObjectGenerator()

    def create_audit(self, audit_role, userid):
        """Create default audit for audit snapshot RBAC tests"""
        is_auditor = False
        if audit_role == "Auditors":
            is_auditor = True
            auditor_role = all_models.AccessControlRole.query.filter(
                all_models.AccessControlRole.name == "Auditors").one()

        program = db.session.query(all_models.Program).get(self.program_id)
        _, audit = self.objgen.generate_object(
            all_models.Audit, {
                "title":
                "Snapshotable audit",
                "program": {
                    "id": self.program_id
                },
                "status":
                "Planned",
                "snapshots": {
                    "operation": "create",
                },
                "access_control_list":
                [acl_helper.get_acl_json(auditor_role.id, userid)]
                if is_auditor else None,
                "context": {
                    "type": "Context",
                    "id": program.context_id,
                    "href": "/api/contexts/{}".format(program.context_id)
                }
            })
        return audit

    def create_program(self, program_role, userid):
        """Create default program for audit snapshot RBAC tests"""
        if program_role and program_role != "Auditors":
            program_role = all_models.AccessControlRole.query.filter(
                all_models.AccessControlRole.name == program_role).one()
        else:
            program_role = None

        _, program = self.objgen.generate_object(
            all_models.Program, {
                "title":
                "test program",
                "access_control_list":
                [acl_helper.get_acl_json(program_role.id, userid)]
                if program_role else None
            })

        for model_type in Types.all - Types.external:
            model = get_model(model_type)
            _, model_object = self.objgen.generate_object(
                model, {
                    "title": "Test Snapshot - {}".format(model_type),
                })
            self.objgen.generate_relationship(program, model_object)

        return program

    def update_audit(self):
        """Update default audit"""
        for model_type in Types.all - Types.external:
            model = get_model(model_type)
            obj = model.query.filter_by(
                title="Test Snapshot - {}".format(model_type)).first()
            self.api.modify_object(
                obj, {"title": "Test Snapshot - {} EDIT".format(model_type)})

        audit = all_models.Audit.query.filter(
            all_models.Audit.title == "Snapshotable audit").one()

        self.api.modify_object(audit, {"snapshots": {"operation": "upsert"}})

    def read(self, objects):
        """Attempt to do a GET request for every object in the objects list"""
        responses = []
        for obj in objects:
            status_code = self.api.get(obj.__class__, obj.id).status_code
            responses.append((obj.type, status_code))
        return responses

    def update(self, objects):
        """Attempt to do a PUT request for every object in the objects list"""
        scope_response = self.api.get(all_models.Audit, self.audit_id)
        if scope_response.status_code == 200:
            self.update_audit()

        responses = []
        for obj in objects:
            response = self.api.get(obj.__class__, obj.id)
            status_code = response.status_code
            if response.status_code == 200:
                data = response.json
                if obj.type == "Snapshot":
                    data.update({"update_revision": "latest"})
                put_call = self.api.put(obj, data)
                status_code = put_call.status_code
            responses.append((obj.type, status_code))
        return responses

    # pylint: disable=attribute-defined-outside-init
    @ddt.data(
        ("Administrator", "", DEFAULT_PERMISSIONS),
        ("Creator", "", DEFAULT_LACK_OF_PERMISSIONS),
        ("Reader", "", DEFAULT_PERMISSIONS),
        ("Editor", "", DEFAULT_PERMISSIONS),
        ("Administrator", "Program Managers", DEFAULT_PERMISSIONS),
        ("Creator", "Program Managers", DEFAULT_PERMISSIONS),
        ("Reader", "Program Managers", DEFAULT_PERMISSIONS),
        ("Editor", "Program Managers", DEFAULT_PERMISSIONS),
        ("Administrator", "Program Editors", DEFAULT_PERMISSIONS),
        ("Creator", "Program Editors", DEFAULT_PERMISSIONS),
        ("Reader", "Program Editors", DEFAULT_PERMISSIONS),
        ("Editor", "Program Editors", DEFAULT_PERMISSIONS),
        ("Administrator", "Program Readers", DEFAULT_PERMISSIONS),
        ("Creator", "Program Readers", DEFAULT_PERMISSIONS),
        ("Reader", "Program Readers", DEFAULT_PERMISSIONS),
        ("Editor", "Program Readers", DEFAULT_PERMISSIONS),
        ("Administrator", "Auditors", DEFAULT_PERMISSIONS),
        ("Creator", "Auditors", DEFAULT_PERMISSIONS),
        ("Reader", "Auditors", DEFAULT_PERMISSIONS),
        ("Editor", "Auditors", DEFAULT_PERMISSIONS),
    )
    @ddt.unpack
    def test_read_access_on_mapped(self, rolename, object_role,
                                   expected_status):
        """Test if {0} with {1} role, has READ access to
       snapshotted objects of default audit"""

        user = self.create_user_with_role(rolename)
        user_id = user.id

        program = self.create_program(object_role, user_id)
        self.program_id = program.id

        audit = self.create_audit(object_role, user_id)

        snapshots = all_models.Snapshot.eager_query().all()

        objects = snapshots + [audit]

        user = all_models.Person.query.get(user_id)
        self.api.set_user(user)

        responses = self.read(objects)
        all_errors = []
        for type_, code in responses:
            if code != expected_status[type_]:
                all_errors.append(
                    "{} does not have read access to {} ({})".format(
                        user.email, type_, code))
        assert not all_errors, "\n".join(all_errors)

    # pylint: disable=attribute-defined-outside-init
    @ddt.data(
        ("Administrator", "", DEFAULT_PERMISSIONS),
        ("Creator", "", DEFAULT_LACK_OF_PERMISSIONS),
        ("Reader", "", DEFAULT_LACK_OF_PERMISSIONS),
        ("Editor", "", DEFAULT_PERMISSIONS),
        ("Administrator", "Program Managers", DEFAULT_PERMISSIONS),
        ("Creator", "Program Managers", DEFAULT_PERMISSIONS),
        ("Reader", "Program Managers", DEFAULT_PERMISSIONS),
        ("Editor", "Program Managers", DEFAULT_PERMISSIONS),
        ("Administrator", "Program Editors", DEFAULT_PERMISSIONS),
        ("Creator", "Program Editors", DEFAULT_PERMISSIONS),
        ("Reader", "Program Editors", DEFAULT_PERMISSIONS),
        ("Editor", "Program Editors", DEFAULT_PERMISSIONS),
        ("Administrator", "Program Readers", DEFAULT_PERMISSIONS),
        ("Creator", "Program Readers", DEFAULT_LACK_OF_PERMISSIONS),
        ("Reader", "Program Readers", DEFAULT_LACK_OF_PERMISSIONS),
        ("Editor", "Program Readers", DEFAULT_PERMISSIONS),
        ("Administrator", "Auditors", DEFAULT_PERMISSIONS),
        ("Creator", "Auditors", DEFAULT_AUDITOR_PERMISSIONS),
        ("Reader", "Auditors", DEFAULT_AUDITOR_PERMISSIONS),
        ("Editor", "Auditors", DEFAULT_PERMISSIONS),
    )
    @ddt.unpack
    def test_update_access_on_mapped(self, rolename, object_role,
                                     expected_status):
        """Test if {0} with {1} role, has UPDATE access to
       snapshotted objects of default audit"""

        user = self.create_user_with_role(rolename)
        user_id = user.id

        program = self.create_program(object_role, user_id)
        self.program_id = program.id

        audit = self.create_audit(object_role, user_id)
        self.audit_id = audit.id

        snapshots = all_models.Snapshot.eager_query().all()

        objects = snapshots + [audit]

        user = all_models.Person.query.get(user_id)
        self.api.set_user(user)

        responses = self.update(objects)
        all_errors = []
        for type_, code in responses:
            if code != expected_status[type_]:
                all_errors.append(
                    "{} does not have update access to {} ({})".format(
                        user.email, type_, code))
        assert not all_errors, "\n".join(all_errors)
class TestReviewStatusUpdate(TestCase):
    """Base TestCase class automatic review status update."""
    def setUp(self):
        super(TestReviewStatusUpdate, self).setUp()
        self.api = Api()

        self.generator = generator.ObjectGenerator()

    def test_gca(self):
        """if GCA of reviewable is changed review -> unreviewed"""
        with factories.single_commit():
            ca_factory = factories.CustomAttributeDefinitionFactory
            gca = ca_factory(definition_type="program",
                             title="rich_test_gca",
                             attribute_type="Rich Text")
            program = factories.ProgramFactory()
            review = factories.ReviewFactory(
                status=all_models.Review.STATES.REVIEWED, reviewable=program)
        review_id = review.id
        reviewable = review.reviewable

        review = all_models.Review.query.get(review_id)

        self.assertEqual(review.status, all_models.Review.STATES.REVIEWED)

        self.api.modify_object(
            reviewable, {
                "custom_attribute_values": [{
                    "custom_attribute_id": gca.id,
                    "attribute_value": "new_value",
                }],
            })

        review = all_models.Review.query.get(review_id)
        self.assertEqual(review.status, all_models.Review.STATES.UNREVIEWED)

    def test_update_gca(self):
        """if existing GCA value changed review -> unreviewed"""
        with factories.single_commit():
            ca_factory = factories.CustomAttributeDefinitionFactory
            gca = ca_factory(definition_type="program",
                             title="rich_test_gca",
                             attribute_type="Rich Text")
            program = factories.ProgramFactory()

            program.custom_attribute_values = [{
                "attribute_value": "starting_value",
                "custom_attribute_id": gca.id
            }]
            review = factories.ReviewFactory(
                status=all_models.Review.STATES.REVIEWED, reviewable=program)
        review_id = review.id
        reviewable = review.reviewable

        review = all_models.Review.query.get(review_id)

        self.assertEqual(review.status, all_models.Review.STATES.REVIEWED)

        self.api.modify_object(
            reviewable, {
                "custom_attribute_values": [{
                    "custom_attribute_id": gca.id,
                    "attribute_value": "new_value",
                }],
            })

        review = all_models.Review.query.get(review_id)
        self.assertEqual(review.status, all_models.Review.STATES.UNREVIEWED)

    @ddt.data("custom attr", "slug", "self")
    def test_gca_with_varying_titles(self, title):
        """if GCA with any title is changed review -> unreviewed"""
        with factories.single_commit():
            ca_factory = factories.CustomAttributeDefinitionFactory
            gca = ca_factory(definition_type="program",
                             title=title,
                             attribute_type="Rich Text")
            program = factories.ProgramFactory()

            program.custom_attribute_values = [{
                "attribute_value": "starting_value",
                "custom_attribute_id": gca.id
            }]
            review = factories.ReviewFactory(
                status=all_models.Review.STATES.REVIEWED, reviewable=program)
        review_id = review.id
        reviewable = review.reviewable

        review = all_models.Review.query.get(review_id)

        self.assertEqual(review.status, all_models.Review.STATES.REVIEWED)

        self.api.modify_object(
            reviewable, {
                "custom_attribute_values": [{
                    "custom_attribute_id": gca.id,
                    "attribute_value": "new_value",
                }],
            })

        review = all_models.Review.query.get(review_id)
        self.assertEqual(review.status, all_models.Review.STATES.UNREVIEWED)

    def test_map_person_gca(self):
        """if Map:Person GCA value added review -> unreviewed"""
        with factories.single_commit():
            ca_factory = factories.CustomAttributeDefinitionFactory
            gca = ca_factory(definition_type="program",
                             title="map_test_gca",
                             attribute_type="Map:Person")

            user_id = all_models.Person.query.filter_by(
                email="*****@*****.**").one().id

            program = factories.ProgramFactory()
            review = factories.ReviewFactory(
                status=all_models.Review.STATES.REVIEWED, reviewable=program)

        review_id = review.id
        reviewable = review.reviewable
        review = all_models.Review.query.get(review_id)

        self.assertEqual(review.status, all_models.Review.STATES.REVIEWED)

        self.api.modify_object(
            reviewable, {
                "custom_attribute_values": [{
                    "custom_attribute_id": gca.id,
                    "attribute_object_id": user_id,
                    "attribute_value": "Person",
                }],
            })

        review = all_models.Review.query.get(review_id)
        self.assertEqual(review.status, all_models.Review.STATES.UNREVIEWED)

    def test_update_map_person_gca(self):
        """if existing Map:Person GCA value changed review -> unreviewed"""
        with factories.single_commit():
            ca_factory = factories.CustomAttributeDefinitionFactory
            gca = ca_factory(definition_type="program",
                             title="map_test_gca",
                             attribute_type="Map:Person")

            first_user_id = all_models.Person.query.filter_by(
                email="*****@*****.**").one().id
            second_user_id = factories.PersonFactory().id

            program = factories.ProgramFactory()
            program.custom_attribute_values = [{
                "attribute_object_id": first_user_id,
                "custom_attribute_id": gca.id,
                "attribute_value": "Person"
            }]
            review = factories.ReviewFactory(
                status=all_models.Review.STATES.REVIEWED, reviewable=program)

        review_id = review.id
        reviewable = review.reviewable
        review = all_models.Review.query.get(review_id)

        self.assertEqual(review.status, all_models.Review.STATES.REVIEWED)

        self.api.modify_object(
            reviewable, {
                "custom_attribute_values": [{
                    "custom_attribute_id": gca.id,
                    "attribute_object_id": second_user_id,
                    "attribute_value": "Person",
                }],
            })

        review = all_models.Review.query.get(review_id)
        self.assertEqual(review.status, all_models.Review.STATES.UNREVIEWED)

    def test_delete_map_person_gca(self):
        """if existing Map:Person GCA value deleted review -> unreviewed"""
        with factories.single_commit():
            ca_factory = factories.CustomAttributeDefinitionFactory
            gca = ca_factory(definition_type="program",
                             title="map_test_gca",
                             attribute_type="Map:Person")

            user_id = all_models.Person.query.filter_by(
                email="*****@*****.**").one().id

            program = factories.ProgramFactory()
            program.custom_attribute_values = [{
                "attribute_object_id": user_id,
                "custom_attribute_id": gca.id,
                "attribute_value": "Person"
            }]
            review = factories.ReviewFactory(
                status=all_models.Review.STATES.REVIEWED, reviewable=program)

        review_id = review.id
        reviewable = review.reviewable
        review = all_models.Review.query.get(review_id)

        self.assertEqual(review.status, all_models.Review.STATES.REVIEWED)

        self.api.modify_object(
            reviewable, {
                "custom_attribute_values": [{
                    "custom_attribute_id": gca.id,
                    "attribute_object_id": None,
                    "attribute_object": None,
                    "attribute_value": "Person",
                }],
            })

        review = all_models.Review.query.get(review_id)
        self.assertEqual(review.status, all_models.Review.STATES.UNREVIEWED)

    def test_reference_url(self):
        """If reference url is updated state should not updated"""
        with factories.single_commit():
            program = factories.ProgramFactory()
            doc = factories.DocumentReferenceUrlFactory(
                title="Simple title",
                link="some_url.com",
                description="mega description",
                parent_obj={
                    "id": program.id,
                    "type": "Program"
                })
            review = factories.ReviewFactory(
                status=all_models.Review.STATES.REVIEWED, reviewable=program)
        review_id = review.id

        self.api.modify_object(doc, {"link": "new_link.com"})
        review = all_models.Review.query.get(review_id)
        self.assertEqual(review.status, all_models.Review.STATES.REVIEWED)

    def test_acl_roles(self):
        """Update of reviewable ACL shouldn't change review status"""
        with factories.single_commit():
            threat = factories.ThreatFactory()
            review = factories.ReviewFactory(
                status=all_models.Review.STATES.REVIEWED, reviewable=threat)
        review_id = review.id

        ac_role_id = all_models.AccessControlRole.query.filter_by(
            name="Primary Contacts", object_type="Threat").one().id

        user_id = all_models.Person.query.filter_by(
            email="*****@*****.**").one().id

        self.api.modify_object(
            threat, {
                "access_control_list": [{
                    "ac_role_id": ac_role_id,
                    "person": {
                        "id": user_id
                    },
                }],
            })
        review = all_models.Review.query.get(review_id)
        self.assertEqual(review.status, all_models.Review.STATES.REVIEWED)

    def test_comments(self):
        """Add comment to reviewable shouldn't update review state"""
        with factories.single_commit():
            program = factories.ProgramFactory()
            review = factories.ReviewFactory(
                status=all_models.Review.STATES.REVIEWED, reviewable=program)
        review_id = review.id

        self.generator.generate_comment(program,
                                        "Verifiers",
                                        "some comment",
                                        send_notification="false")

        review = all_models.Review.query.get(review_id)
        self.assertEqual(review.status, all_models.Review.STATES.REVIEWED)

    def test_mapping_non_snapshotable(self):
        """Map non-snapshotable shouldn't change review status"""
        with factories.single_commit():
            program = factories.ProgramFactory()
            review = factories.ReviewFactory(
                status=all_models.Review.STATES.REVIEWED, reviewable=program)
            review_id = review.id

        factories.RelationshipFactory(source=program,
                                      destination=factories.IssueFactory())

        review = all_models.Review.query.get(review_id)
        self.assertEqual(review.status, all_models.Review.STATES.REVIEWED)

    @ddt.data("Standard", "Regulation", "Requirement", "Objective", "Control",
              "Product", "System", "Process", "AccessGroup", "Contract",
              "DataAsset", "Facility", "Market", "OrgGroup", "Policy", "Risk",
              "Threat", "Vendor")
    def test_map_snapshotable(self, snapshotable):
        """Map '{}' should change review status"""
        with factories.single_commit():
            program = factories.ProgramFactory()
            review = factories.ReviewFactory(
                status=all_models.Review.STATES.REVIEWED, reviewable=program)
            review_id = review.id

        self.generator.generate_relationship(
            source=program,
            destination=factories.get_model_factory(snapshotable)(),
            context=None,
        )

        review = all_models.Review.query.get(review_id)
        self.assertEqual(review.status, all_models.Review.STATES.UNREVIEWED)

    def test_unmap_snapshotable(self):
        """Unmap snapshotable should change review status"""
        program = factories.ProgramFactory()
        resp, review = generate_review_object(program)
        review_id = review.id

        _, rel = self.generator.generate_relationship(
            source=program,
            destination=factories.ProductFactory(),
            context=None,
        )

        review = all_models.Review.query.get(review_id)
        resp = self.api.modify_object(
            review, {"status": all_models.Review.STATES.REVIEWED})
        self.assert200(resp)

        resp = self.api.delete(rel)
        self.assert200(resp)
        review = all_models.Review.query.get(review_id)
        self.assertEqual(review.status, all_models.Review.STATES.UNREVIEWED)

    @ddt.data(
        "Assessment",
        "Issue",
        "Program",
        "Project",
        "Audit",
        "RiskAssessment",
        "AssessmentTemplate",
        "Person",
    )
    def test_map_nonsnapshotable(self, nonsnapshotable):
        """Map '{}' shouldn't change review status"""
        program = factories.ProgramFactory()
        _, review = generate_review_object(
            program, state=all_models.Review.STATES.REVIEWED)
        review_id = review.id

        review = all_models.Review.query.get(review_id)

        self.assertEqual(review.status, all_models.Review.STATES.REVIEWED)

        self.generator.generate_relationship(
            source=program,
            destination=factories.get_model_factory(nonsnapshotable)(),
            context=None,
        )

        review = all_models.Review.query.get(review_id)
        self.assertEqual(review.status, all_models.Review.STATES.REVIEWED)

    def test_unmap_nonsnapshotable(self):
        """Unmap nonsnapshotable shouldn't change review status"""
        program = factories.ProgramFactory()
        resp, review = generate_review_object(
            program, state=all_models.Review.STATES.REVIEWED)
        review_id = review.id
        _, rel = self.generator.generate_relationship(
            source=program,
            destination=factories.ProgramFactory(),
            context=None,
        )

        review = all_models.Review.query.get(review_id)
        resp = self.api.modify_object(
            review, {"status": all_models.Review.STATES.REVIEWED})
        self.assert200(resp)
        review = all_models.Review.query.get(review_id)
        self.assertEqual(review.status, all_models.Review.STATES.REVIEWED)

        resp = self.api.delete(rel)
        self.assert200(resp)
        review = all_models.Review.query.get(review_id)
        self.assertEqual(review.status, all_models.Review.STATES.REVIEWED)

    def test_proposal_apply(self):
        """Reviewable object changed via proposal -> review.state-> UNREVIEWED"""
        program = factories.ProgramFactory()
        _, review = generate_review_object(program)

        review_id = review.id

        proposal_content = {
            "fields": {
                "title": "new title"
            },
        }
        proposal = factories.ProposalFactory(instance=program,
                                             content=proposal_content,
                                             agenda="agenda content")
        self.api.modify_object(proposal, {"status": proposal.STATES.APPLIED})

        review = all_models.Review.query.get(review_id)
        self.assertEqual(review.status, all_models.Review.STATES.UNREVIEWED)

    def test_review_status_update(self):
        """Test updating folder preserves review status"""
        threat = factories.ThreatFactory()
        factories.ReviewFactory(
            reviewable=threat,
            status=all_models.Review.STATES.REVIEWED,
        )
        self.api.put(threat, {"folder": factories.random_str()})
        program = all_models.Threat.query.get(threat.id)
        self.assertEqual(program.review.status,
                         all_models.Review.STATES.REVIEWED)
Esempio n. 8
0
class TestCycleTaskDeprecated(TestCase):
  """Test for correct working field last_deprecated_date."""

  def setUp(self):
    super(TestCycleTaskDeprecated, self).setUp()
    self.api = Api()

  def test_redefine_status(self):
    """Test cycle task create and change status to Deprecated."""
    cycle_task = factories.get_model_factory("CycleTaskGroupObjectTask")()

    with freeze_time("2017-01-25"):
      self.api.modify_object(cycle_task, {
          "status": "Deprecated"
      })

    cycle_task_result = all_models.CycleTaskGroupObjectTask.query.filter(
        all_models.CycleTaskGroupObjectTask.id == cycle_task.id
    ).one()

    self.assertEquals(cycle_task_result.last_deprecated_date,
                      datetime.date(2017, 1, 25))

  def test_keep_date_unchanged(self):
    """Test set status to Deprecated, and then set status to Finished."""
    cycle_task = factories.get_model_factory("CycleTaskGroupObjectTask")()

    with freeze_time("2017-01-25"):
      self.api.modify_object(cycle_task, {
          "status": "Deprecated"
      })

    with freeze_time("2017-01-26"):
      self.api.modify_object(cycle_task, {
          "status": "Finished"
      })

      cycle_task_result = all_models.CycleTaskGroupObjectTask.query.filter(
          all_models.CycleTaskGroupObjectTask.id == cycle_task.id
      ).one()

    self.assertEquals(cycle_task_result.status, "Finished")
    self.assertEquals(cycle_task_result.last_deprecated_date,
                      datetime.date(2017, 1, 25))

  def test_repeat_deprecated_state(self):
    """Test updating of last deprecated date by multiply changing of status."""
    cycle_task = factories.get_model_factory("CycleTaskGroupObjectTask")()

    with freeze_time("2017-01-25"):
      self.api.modify_object(cycle_task, {
          "status": "Deprecated"
      })

    with freeze_time("2017-01-26"):
      self.api.modify_object(cycle_task, {
          "status": "Finished"
      })
    with freeze_time("2017-02-25"):
      self.api.modify_object(cycle_task, {
          "status": "Deprecated"
      })
    with freeze_time("2017-02-26"):
      self.api.modify_object(cycle_task, {
          "status": "Finished"
      })

    cycle_task_result = all_models.CycleTaskGroupObjectTask.query.filter(
        all_models.CycleTaskGroupObjectTask.id == cycle_task.id
    ).one()

    self.assertEquals(cycle_task_result.status, "Finished")
    self.assertEquals(cycle_task_result.last_deprecated_date,
                      datetime.date(2017, 2, 25))

  def test_filter_by_deprecated_date(self):
    """Test filter cycle task by last deprecated date."""
    amount_of_cycle_tasks = 5
    list_of_ids = []
    cycle_task_factory = factories.get_model_factory(
        "CycleTaskGroupObjectTask")
    with factories.single_commit():
      with freeze_time("2017-01-25"):
        for _ in range(amount_of_cycle_tasks):
          list_of_ids.append(
              cycle_task_factory(status="Deprecated").id
          )

    query_request_data = [{
        "object_name": "CycleTaskGroupObjectTask",
        'filters': {
            'expression': {
                'left': 'task Last Deprecated Date',
                'op': {'name': '='},
                'right': "2017-01-25",
            },
        },
        'type': 'ids',
    }]

    result = self.api.send_request(self.api.client.post,
                                   data=query_request_data,
                                   api_link="/query")
    self.assertItemsEqual(list_of_ids,
                          result.json[0]["CycleTaskGroupObjectTask"]["ids"])

  def test_sort_by_deprecated_date(self):
    """Test sorting results of filter cycle tasks by deprecated date."""
    dict_of_dates = {}
    date_list = ["2017-01-25", "2017-01-29", "2017-01-02", "2017-01-26"]
    cycle_task_factory = factories.get_model_factory(
        "CycleTaskGroupObjectTask")
    with factories.single_commit():
      for date in date_list:
        with freeze_time(date):
          dict_of_dates[cycle_task_factory(status="Deprecated").id] = date

    sorted_dict = sorted(dict_of_dates.items(), key=operator.itemgetter(1))
    sorted_list_ids = [item[0] for item in sorted_dict]

    query_request_data = [{
        "object_name": "CycleTaskGroupObjectTask",
        'filters': {
            'expression': {
                'left': 'task Last Deprecated Date',
                'op': {'name': '='},
                'right': "2017-01",
            },
        },
        "order_by": [{"name": "last_deprecated_date"}],
        'type': 'ids',
    }]

    result = self.api.send_request(self.api.client.post,
                                   data=query_request_data,
                                   api_link="/query")
    self.assertItemsEqual(sorted_list_ids,
                          result.json[0]["CycleTaskGroupObjectTask"]["ids"])
class TestCycleTaskDeprecated(TestCase):
  """Test for correct working field last_deprecated_date."""

  def setUp(self):
    super(TestCycleTaskDeprecated, self).setUp()
    self.api = Api()

  def test_redefine_status(self):
    """Test cycle task create and change status to Deprecated."""
    cycle_task = factories.get_model_factory("CycleTaskGroupObjectTask")()

    with freeze_time("2017-01-25"):
      self.api.modify_object(cycle_task, {
          "status": "Deprecated"
      })

    cycle_task_result = all_models.CycleTaskGroupObjectTask.query.filter(
        all_models.CycleTaskGroupObjectTask.id == cycle_task.id
    ).one()

    self.assertEquals(cycle_task_result.last_deprecated_date,
                      datetime.date(2017, 1, 25))

  def test_keep_date_unchanged(self):
    """Test set status to Deprecated, and then set status to Finished."""
    cycle_task = factories.get_model_factory("CycleTaskGroupObjectTask")()

    with freeze_time("2017-01-25"):
      self.api.modify_object(cycle_task, {
          "status": "Deprecated"
      })

    with freeze_time("2017-01-26"):
      self.api.modify_object(cycle_task, {
          "status": "Finished"
      })

      cycle_task_result = all_models.CycleTaskGroupObjectTask.query.filter(
          all_models.CycleTaskGroupObjectTask.id == cycle_task.id
      ).one()

    self.assertEquals(cycle_task_result.status, "Finished")
    self.assertEquals(cycle_task_result.last_deprecated_date,
                      datetime.date(2017, 1, 25))

  def test_repeat_deprecated_state(self):
    """Test updating of last deprecated date by multiply changing of status."""
    cycle_task = factories.get_model_factory("CycleTaskGroupObjectTask")()

    with freeze_time("2017-01-25"):
      self.api.modify_object(cycle_task, {
          "status": "Deprecated"
      })

    with freeze_time("2017-01-26"):
      self.api.modify_object(cycle_task, {
          "status": "Finished"
      })
    with freeze_time("2017-02-25"):
      self.api.modify_object(cycle_task, {
          "status": "Deprecated"
      })
    with freeze_time("2017-02-26"):
      self.api.modify_object(cycle_task, {
          "status": "Finished"
      })

    cycle_task_result = all_models.CycleTaskGroupObjectTask.query.filter(
        all_models.CycleTaskGroupObjectTask.id == cycle_task.id
    ).one()

    self.assertEquals(cycle_task_result.status, "Finished")
    self.assertEquals(cycle_task_result.last_deprecated_date,
                      datetime.date(2017, 2, 25))

  def test_filter_by_deprecated_date(self):
    """Test filter cycle task by last deprecated date."""
    amount_of_cycle_tasks = 5
    list_of_ids = []
    cycle_task_factory = factories.get_model_factory(
        "CycleTaskGroupObjectTask")
    with factories.single_commit():
      with freeze_time("2017-01-25"):
        for _ in range(amount_of_cycle_tasks):
          list_of_ids.append(
              cycle_task_factory(status="Deprecated").id
          )

    query_request_data = [{
        "object_name": "CycleTaskGroupObjectTask",
        'filters': {
            'expression': {
                'left': 'task Last Deprecated Date',
                'op': {'name': '='},
                'right': "2017-01-25",
            },
        },
        'type': 'ids',
    }]

    result = self.api.send_request(self.api.client.post,
                                   data=query_request_data,
                                   api_link="/query")
    self.assertItemsEqual(list_of_ids,
                          result.json[0]["CycleTaskGroupObjectTask"]["ids"])

  def test_sort_by_deprecated_date(self):
    """Test sorting results of filter cycle tasks by deprecated date."""
    dict_of_dates = {}
    date_list = ["2017-01-25", "2017-01-29", "2017-01-02", "2017-01-26"]
    cycle_task_factory = factories.get_model_factory(
        "CycleTaskGroupObjectTask")
    with factories.single_commit():
      for date in date_list:
        with freeze_time(date):
          dict_of_dates[cycle_task_factory(status="Deprecated").id] = date

    sorted_dict = sorted(dict_of_dates.items(), key=operator.itemgetter(1))
    sorted_list_ids = [item[0] for item in sorted_dict]

    query_request_data = [{
        "object_name": "CycleTaskGroupObjectTask",
        'filters': {
            'expression': {
                'left': 'task Last Deprecated Date',
                'op': {'name': '='},
                'right': "2017-01",
            },
        },
        "order_by": [{"name": "last_deprecated_date"}],
        'type': 'ids',
    }]

    result = self.api.send_request(self.api.client.post,
                                   data=query_request_data,
                                   api_link="/query")
    self.assertItemsEqual(sorted_list_ids,
                          result.json[0]["CycleTaskGroupObjectTask"]["ids"])
Esempio n. 10
0
class TestAuditDeprecated(TestCase):
  """Test for correct working field last_deprecated_date """

  def setUp(self):
    super(TestAuditDeprecated, self).setUp()
    self.api = Api()

  def test_redefine_status(self):
    """Test create audit and change status to Deprecated"""
    audit = factories.AuditFactory()

    with freeze_time("2017-01-25"):
      self.api.modify_object(audit, {
          "status": "Deprecated"
      })

    audit_result = all_models.Audit.query.filter(
        all_models.Audit.id == audit.id
    ).one()

    self.assertEquals(audit_result.last_deprecated_date,
                      datetime.date(2017, 1, 25))

  def test_keep_date_unchanged(self):
    """Test set status audit to Deprecated, and then set status to Planned"""
    audit = factories.AuditFactory()

    with freeze_time("2017-01-25"):
      self.api.modify_object(audit, {
          "status": "Deprecated"
      })

    with freeze_time("2017-01-26"):
      self.api.modify_object(audit, {
          "status": "Planned"
      })

    audit_result = all_models.Audit.query.filter(
        all_models.Audit.id == audit.id
    ).one()

    self.assertEquals(audit_result.status, "Planned")
    self.assertEquals(audit_result.last_deprecated_date,
                      datetime.date(2017, 1, 25))

  def test_repeat_deprecated_state(self):
    """Test set status audit to Deprecated, then to Planned,
    then to Deprecated and then to Planned"""
    audit = factories.AuditFactory()

    with freeze_time("2017-01-25"):
      self.api.modify_object(audit, {
          "status": "Deprecated"
      })

    with freeze_time("2017-01-26"):
      self.api.modify_object(audit, {
          "status": "Planned"
      })
    with freeze_time("2017-02-25"):
      self.api.modify_object(audit, {
          "status": "Deprecated"
      })
    with freeze_time("2017-02-26"):
      self.api.modify_object(audit, {
          "status": "Planned"
      })

    audit_result = all_models.Audit.query.filter(
        all_models.Audit.id == audit.id
    ).one()

    self.assertEquals(audit_result.status, "Planned")
    self.assertEquals(audit_result.last_deprecated_date,
                      datetime.date(2017, 2, 25))

  def test_filter_by_deprecated_date(self):
    """Test filter audits by last deprecated date"""
    amount_of_audits = 5
    list_of_ids = []
    with factories.single_commit():
      with freeze_time("2017-01-25"):
        for _ in range(amount_of_audits):
          list_of_ids.append(
              factories.AuditFactory(status="Deprecated").id
          )

    query_request_data = [{
        "object_name": "Audit",
        'filters': {
            'expression': {
                'left': 'Last Deprecated Date',
                'op': {'name': '='},
                'right': "2017-01-25",
            },
        },
        'type': 'ids',
    }]

    result = self.api.send_request(self.api.client.post,
                                   data=query_request_data,
                                   api_link="/query")
    self.assertItemsEqual(list_of_ids, result.json[0]["Audit"]["ids"])

  def test_sort_by_deprecated_date(self):
    """Test sorting results of filter audits by deprecated date"""
    dict_of_dates = {}
    date_list = ["2017-01-25", "2017-01-29", "2017-01-02", "2017-01-26"]
    with factories.single_commit():
      for date in date_list:
        with freeze_time(date):
          dict_of_dates[factories.AuditFactory(status="Deprecated").id] = date

    sorted_dict = sorted(dict_of_dates.items(), key=operator.itemgetter(1))
    sorted_list_ids = [item[0] for item in sorted_dict]

    query_request_data = [{
        "object_name": "Audit",
        'filters': {
            'expression': {
                'left': 'Last Deprecated Date',
                'op': {'name': '='},
                'right': "2017-01",
            },
        },
        "order_by": [{"name": "last_deprecated_date"}],
        'type': 'ids',
    }]

    result = self.api.send_request(self.api.client.post,
                                   data=query_request_data,
                                   api_link="/query")

    self.assertItemsEqual(sorted_list_ids, result.json[0]["Audit"]["ids"])