def test_notification_add_new_review(self, notification_type, expected_notifications): """After creation of new review notification should be created""" control = factories.ControlFactory() resp, _ = self.generator.generate_object( all_models.Review, { "reviewable": { "type": control.type, "id": control.id, }, "context": None, "notification_type": notification_type, "status": all_models.Review.STATES.UNREVIEWED, "access_control_list": build_reviewer_acl(), }, ) self.assertEqual(201, resp.status_code) self.assertEqual(expected_notifications, len(all_models.Notification.query.all()))
def test_map_nonsnapshotable(self, nonsnapshotable): """Map '{}' 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 review = all_models.Review.query.get(review_id) self.assertEqual(review.status, all_models.Review.STATES.REVIEWED) self.obj_gen.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_creation_mapped_control(self): """Check creation of new Audit if Program has Control with mapped roles""" control = factories.ControlFactory() # Map original of control to several assessments to get propagated roles self.generate_control_mappings(control) # Existing control should be updated to create new revision with ACL self.api.put(control, {"title": "Test Control"}) program = factories.ProgramFactory() factories.RelationshipFactory(source=program, destination=control) response = self.api.post(all_models.Audit, [{ "audit": { "title": "New Audit", "program": {"id": program.id}, "status": "Planned", "context": None } }]) self.assert200(response)
def test_export_assesments_without_map_control(self): """Test export assesment without related control instance""" audit = factories.AuditFactory() assessment = factories.AssessmentFactory(audit=audit) factories.RelationshipFactory(source=audit, destination=assessment) control = factories.ControlFactory() revision = models.Revision.query.filter( models.Revision.resource_id == control.id, models.Revision.resource_type == control.__class__.__name__ ).order_by( models.Revision.id.desc() ).first() factories.SnapshotFactory( parent=audit, child_id=control.id, child_type=control.__class__.__name__, revision_id=revision.id ) db.session.commit() self.assertColumnExportedValue("", assessment, "map:control")
def test_simple_get(self): """Test simple get""" with factories.single_commit(): control = factories.ControlFactory() review = factories.ReviewFactory( email_message="test email message", notification_type="email", reviewable=control, status=all_models.Review.STATES.UNREVIEWED, ) resp = self.api.get(all_models.Review, review.id) self.assert200(resp) self.assertIn("review", resp.json) resp_review = resp.json["review"] self.assertEqual(all_models.Review.STATES.UNREVIEWED, resp_review["status"]) self.assertEqual(all_models.Review.NotificationTypes.EMAIL_TYPE, resp_review["notification_type"]) self.assertEqual("test email message", resp_review["email_message"])
def test_proposal_apply(self): """Reviewable object changed via proposal -> review.state-> UNREVIEWED""" with factories.single_commit(): control = factories.ControlFactory() review = factories.ReviewFactory( status=all_models.Review.STATES.REVIEWED, reviewable=control) 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)
def test_change_acl_import(self): """Change acl via import Review -> REVIEWED """ control = factories.ControlFactory(title="Test control") resp, review = generate_review_object( control, state=all_models.Review.STATES.REVIEWED) del review control_id = control.id self.assertEqual(201, resp.status_code) person = factories.PersonFactory() import_data = OrderedDict([("object_type", "Control"), ("Code*", control.slug), ("admin", person.email)]) response = self.import_data(import_data) self._check_csv_response(response, {}) control = all_models.Control.query.get(control_id) self.assertEqual(all_models.Review.STATES.REVIEWED, control.review_status)
def test_import_control_with_doc_url_existing(self): """If reference url already mapped to control ignore it""" doc_reference_url = "test_reference_url" with factories.single_commit(): control = factories.ControlFactory() control_slug = control.slug doc = factories.DocumentReferenceUrlFactory(link=doc_reference_url) factories.RelationshipFactory(source=control, destination=doc) response = self.import_data( collections.OrderedDict([ ("object_type", "Control"), ("Code*", control_slug), ("Reference Url", doc_reference_url), ])) documents = all_models.Document.query.filter_by( link=doc_reference_url).all() self.assertEquals(1, len(documents)) self.assertEquals([], response[0]['row_warnings'])
def test_add_admin_to_document(self): """Test evidence should have current user as admin""" control = factories.ControlFactory() self.import_data( collections.OrderedDict([ ("object_type", "Control"), ("code", control.slug), ("Reference Url", "supercool.com"), ])) documents = all_models.Document.query.filter( all_models.Document.kind == all_models.Document.REFERENCE_URL).all() self.assertEquals(len(documents), 1) admin_role = db.session.query(all_models.AccessControlRole).filter_by( name="Admin", object_type="Document").one() current_user = db.session.query( all_models.Person).filter_by(email="*****@*****.**").one() person, acr = documents[0].access_control_list[0] self.assertEquals(acr.ac_role_id, admin_role.id) self.assertEquals(person.id, current_user.id)
def _test_contact_field(self, contact_name_field, search_field): """Util function for test for filtering by contact fields""" person_name = "name" person_email = "*****@*****.**" program = factories.ProgramFactory() program_id = program.id control_kwargs = { contact_name_field: factories.PersonFactory(name=person_name, email=person_email), } control = factories.ControlFactory(**control_kwargs) factories.RelationshipFactory(source=program, destination=control) program = models.Program.query.filter_by(id=program_id).one() self._create_audit(program=program, title="some title") self.assert_rows_number_in_search(search_field, person_name, 1) self.assert_rows_number_in_search(search_field, person_email, 1) self.assert_rows_number_in_search(search_field, "negative_" + person_name, 0) self.assert_rows_number_in_search(search_field, "negative_" + person_email, 0)
def test_import_snapshot_mapped(self, status): """Test notifications for '{}' Assessment if snapshot mapped in import.""" object_generator = ObjectGenerator() _, user = object_generator.generate_person(user_role="Creator") with factories.single_commit(): assessment = factories.AssessmentFactory() control = factories.ControlFactory() # pylint: disable=expression-not-assigned self._create_snapshots(assessment.audit, [control])[0] assessment.add_person_with_role_name(user, "Verifiers") assessment.status = status db.session.commit() response = self.import_data(collections.OrderedDict([ ("object_type", "Assessment"), ("Code*", assessment.slug), ("Map:control versions", control.slug), ])) self._check_csv_response(response, {}) self.assert_asmnt_notifications()
def setUp(self): super(TestIssueAuditMapping, self).setUp() self.generator = generator.ObjectGenerator(fail_no_json=False) control = factories.ControlFactory() revision = all_models.Revision.query.filter( all_models.Revision.resource_type == control.type, all_models.Revision.resource_id == control.id, ).first() with factories.single_commit(): self.audit = factories.AuditFactory() self.snapshot = factories.SnapshotFactory(parent=self.audit, revision=revision) self.other_audits = [factories.AuditFactory() for _ in range(2)] self.issue_mapped = factories.IssueFactory() self.issue_unmapped = factories.IssueFactory() self.issue_audit_mapping = factories.RelationshipFactory( source=self.audit, destination=self.issue_mapped, context=self.audit.context, )
def test_add_person_revision(self): """Test Control revision created if new person is assigned in import.""" user = all_models.Person.query.filter_by( email="*****@*****.**").first() control = factories.ControlFactory(modified_by=user) revisions = db.session.query(all_models.Revision.action).filter_by( resource_type=control.type, resource_id=control.id) self.assertEqual(revisions.all(), [("created", )]) response = self.import_data( collections.OrderedDict([ ("object_type", "Control"), ("Code*", control.slug), ("Admin", "*****@*****.**"), ("Control Operators", "*****@*****.**"), ("Control Owners", "*****@*****.**"), ])) self._check_csv_response(response, {}) self.assertEqual(revisions.all(), [('created', ), ('modified', )])
def test_import_assessment_with_doc_file_blank_multiple(self): """No warnings in Document Files mapping""" doc_file = "test_gdrive_url \n \n test_gdrive_url_2" with factories.single_commit(): control = factories.ControlFactory() control_slug = control.slug doc1 = factories.DocumentFileFactory(link="test_gdrive_url") factories.RelationshipFactory(source=control, destination=doc1) doc2 = factories.DocumentFileFactory(link="test_gdrive_url_2") factories.RelationshipFactory(source=control, destination=doc2) response = self.import_data( collections.OrderedDict([ ("object_type", "Control"), ("Code*", control_slug), ("Document File", doc_file), ])) self.assertEquals([], response[0]['row_warnings'])
def test_without_changes_import(self): """Import snapshotable without changes. Review -> REVIEWED """ control = factories.ControlFactory(title="Test control") resp, review = generate_review_object( control, state=all_models.Review.STATES.REVIEWED) del review control_id = control.id self.assertEqual(201, resp.status_code) import_data = OrderedDict([ ("object_type", "Control"), ("Code*", control.slug), ]) response = self.import_data(import_data) self._check_csv_response(response, {}) control = all_models.Control.query.get(control_id) self.assertEqual(all_models.Review.STATES.REVIEWED, control.review_status)
def test_old_category_revision(self, field, new_value, expected): """Test if old revision content is correct for Control '{0}' field.""" control = factories.ControlFactory() control_revision = all_models.Revision.query.filter_by( resource_type=control.type, resource_id=control.id ).one() revision_content = control_revision.content revision_content[field] = new_value control_revision.content = revision_content db.session.commit() response = self.api.client.get( "/api/revisions" "?resource_type={}&resource_id={}".format(control.type, control.id) ) self.assert200(response) revisions = response.json["revisions_collection"]["revisions"] self.assertEqual(len(revisions), 1) self.assertEqual(revisions[0].get("content", {}).get(field), expected)
def test_assessment_proc_on_map(self, asmnt_plan, asmnt_type, test_plan, expected_plan): """Test if Snapshot test_plan added to Assessment after mapping""" # pylint: disable=too-many-locals with factories.single_commit(): audit = factories.AuditFactory() assessment = factories.AssessmentFactory( audit=audit, assessment_type=asmnt_type, test_plan=asmnt_plan ) factories.RelationshipFactory(source=audit, destination=assessment) controls = [ factories.ControlFactory( test_plan=test_plan.format(i) if test_plan else test_plan ) for i in range(3) ] snapshots = self._create_snapshots(audit, controls) relation = [{ "relationship": { "context": { "context_id": None, "id": assessment.context_id, "type": "Context" }, "destination": { "id": snapshot.id, "type": "Snapshot" }, "source": { "id": assessment.id, "type": "Assessment" } } } for snapshot in snapshots] response = self.api.post(all_models.Relationship, relation) self.assertEqual(response.status_code, 200) asmnt = all_models.Assessment.query.get(assessment.id) self.assertEqual(asmnt.test_plan, expected_plan)
def test_create_mapping_cache(self, count): """Test creation of mapping cache for export.""" with factories.single_commit(): regulations = [factories.RegulationFactory() for _ in range(count)] requirements = [factories.RequirementFactory() for _ in range(count)] controls = [factories.ControlFactory() for _ in range(count)] expected_cache = defaultdict(lambda: defaultdict(list)) for i in range(count): for j in range(i): factories.RelationshipFactory( source=regulations[j] if i % 2 == 0 else requirements[i], destination=regulations[j] if i % 2 == 1 else requirements[i], ) factories.RelationshipFactory( source=regulations[j] if i % 2 == 0 else controls[i], destination=regulations[j] if i % 2 == 1 else controls[i], ) expected_cache[regulations[j].id]["Control"].append( controls[i].slug ) expected_cache[regulations[j].id]["Requirement"].append( requirements[i].slug ) block = base_block.ExportBlockConverter( mock.MagicMock(), object_class=models.Regulation, fields="all", object_ids=[r.id for r in regulations], class_name=models.Regulation.__name__, ) with QueryCounter() as counter: cache = block._create_mapping_cache() self.assertEqual( self.dd_to_dict(cache), self.dd_to_dict(expected_cache), ) self.assertLess(counter.get, self.QUERY_LIMIT)
def test_reviewable_revisions(self): """Check that proper revisions are created""" with factories.single_commit(): control = factories.ControlFactory() control_id = control.id review = factories.ReviewFactory( reviewable=control, status=all_models.Review.STATES.UNREVIEWED) reviewable = review.reviewable control_revisions = all_models.Revision.query.filter_by( resource_id=control_id, resource_type=control.type).order_by( all_models.Revision.created_at, ).all() self.assertEquals(1, len(control_revisions)) self.assertEquals(all_models.Review.STATES.UNREVIEWED, control_revisions[0].content["review_status"]) resp = self.api.put( review, { "status": all_models.Review.STATES.REVIEWED, }, ) self.assert200(resp) control_revisions = all_models.Revision.query.filter_by( resource_id=control_id, resource_type=control.type).order_by( all_models.Revision.created_at, ).all() self.assertEquals(2, len(control_revisions)) self.assertEquals(all_models.Review.STATES.REVIEWED, control_revisions[1].content["review_status"]) resp = self.api.put(reviewable, {"description": "some new description"}) self.assert200(resp) control_revisions = all_models.Revision.query.filter_by( resource_id=control_id, resource_type=control.type).order_by( all_models.Revision.created_at, ).all() self.assertEquals(3, len(control_revisions)) self.assertEquals(all_models.Review.STATES.UNREVIEWED, control_revisions[2].content["review_status"])
def test_change_cad(self): """Test create proposal with change CAVs.""" with factories.single_commit(): control = factories.ControlFactory(title="1") cad = factories.CustomAttributeDefinitionFactory( definition_type="control") factories.CustomAttributeValueFactory(custom_attribute=cad, attributable=control, attribute_value="123") control_id = control.id cad_id = cad.id data = control.log_json() del data["custom_attributes"] data["custom_attribute_values"][0]["attribute_value"] = "321" resp = self.api.post( all_models.Proposal, { "proposal": { "instance": { "id": control.id, "type": control.type, }, # "content": {"123": 123}, "full_instance_content": data, "agenda": "update cav", "context": None, } }) self.assertEqual(201, resp.status_code) control = all_models.Control.query.get(control_id) self.assertEqual(1, len(control.proposals)) self.assertIn("custom_attribute_values", control.proposals[0].content) self.assertEqual( { unicode(cad_id): { "attribute_value": u"321", "attribute_object": None, "remove_cav": False } }, control.proposals[0].content["custom_attribute_values"]) self.assertEqual(1, len(control.comments))
def test_original_object_deleted(self): """ Test that original_object_deleted field is in snapshots which are returned when requesting related_objects of assessment (/api/assessments/1/related_objects). """ with factories.single_commit(): assessment = factories.AssessmentFactory() assessment_id = assessment.id control = factories.ControlFactory() revision = all_models.Revision.query.filter( all_models.Revision.resource_type == "Assessment", all_models.Revision.resource_id == assessment_id, ).first() snapshot = factories.SnapshotFactory( parent=assessment.audit, child_type=control.type, child_id=control.id, revision=revision, ) snapshot_id = snapshot.id factories.RelationshipFactory( source=assessment, destination=snapshot, ) response_data = self.client.get( '/api/assessments/{}/related_objects'.format(assessment_id)).json snapshot = all_models.Snapshot.query.get(snapshot_id) self.assertIn('original_object_deleted', response_data['Snapshot'][0]) self.assertFalse(snapshot.original_object_deleted) self.assertEqual( response_data['Snapshot'][0]['original_object_deleted'], snapshot.original_object_deleted, )
def test_mapped_regulations_read(self): """Test if creators can CRUD mapped Regulations and Objective snapshots.""" self.api.set_user(self.people.get("Editor")) with factories.single_commit(): audit = factories.AuditFactory() assessment = factories.AssessmentFactory(audit=audit) factories.AccessControlListFactory( ac_role_id=self.assignee_roles["Creators"], person=self.people.get("Editor"), object=assessment) factories.AccessControlListFactory( ac_role_id=self.assignee_roles["Assignees"], person=self.people.get("Creator"), object=assessment) factories.RelationshipFactory(source=audit, destination=assessment) control = factories.ControlFactory() objective = factories.ObjectiveFactory() regulation = factories.RegulationFactory() snapshots = self._create_snapshots( audit, [control, objective, regulation]) factories.RelationshipFactory(source=snapshots[0], destination=snapshots[1]) factories.RelationshipFactory(source=snapshots[2], destination=snapshots[0]) factories.RelationshipFactory(source=assessment, destination=snapshots[0]) self.api.set_user(self.people.get("Creator")) for snapshot in snapshots: db.session.add(snapshot) response = self.api.get(type(snapshot), snapshot.id) self.assertEqual( response.status_code, 200, "Cannot GET mapped object. Received {}".format( response.status)) db.session.add(snapshot) response = self.api.delete(snapshot) self.assertEqual( response.status_code, 403, "Can DELETE mapped object. Received {}".format( response.status))
def test_apply_empty_mapping(self): """Test apply empty mapping proposal.""" setuped_kind = all_models.Option.query.filter( all_models.Option.role == "control_kind" ).first() with factories.single_commit(): control = factories.ControlFactory(title="1", kind=setuped_kind) proposal = factories.ProposalFactory( instance=control, content={"mapping_fields": {"kind": None}}, agenda="agenda content") control_id = control.id proposal_id = proposal.id self.assertEqual(proposal.STATES.PROPOSED, proposal.status) revisions = all_models.Revision.query.filter( all_models.Revision.resource_type == control.type, all_models.Revision.resource_id == control.id ).all() self.assertEqual(1, len(revisions)) self.assertEqual(0, len(control.comments)) resp = self.api.put( proposal, { "proposal": { "status": proposal.STATES.APPLIED, "apply_reason": "approved", } }) self.assert200(resp) control = all_models.Control.query.get(control_id) self.assertIsNone(control.kind) proposal = all_models.Proposal.query.get(proposal_id) self.assertEqual(proposal.STATES.APPLIED, proposal.status) revisions = all_models.Revision.query.filter( all_models.Revision.resource_type == control.type, all_models.Revision.resource_id == control.id ).all() self.assertEqual(2, len(revisions)) self.assertIn("kind", revisions[-1].content) self.assertIsNone(revisions[-1].content["kind"]) self.assertEqual(1, len(control.comments))
def test_acl_new_people_update(self): """Test updating of control with acl which contain new people.""" person = self.generator.generate_person(user_role="Creator")[1] with factories.single_commit(): control = factories.ControlFactory() control.add_person_with_role_name(person, "Admin") access_control_list = { "Admin": [{ "email": person.email, "name": person.name, }], "Principal Assignees": [ { "email": person.email, "name": person.name, }, { "email": "*****@*****.**", "name": "user2", }, { "email": "*****@*****.**", "name": "user3", }, ] } response = self.api.put(control, { "access_control_list": access_control_list, }) self.assert200(response) for expected_person in access_control_list["Admin"]: user = all_models.Person.query.filter_by( email=expected_person["email"]).one() self.assertEqual(user.name, expected_person["name"]) self.assertEqual([ur.role.name for ur in user.user_roles], ["Creator"]) control = all_models.Control.query.get(control.id) self.assert_obj_acl(control, access_control_list)
def test_export_deleted_acr(self): """Test exporting snapshots with ACL entries for deleted ACRs.""" # pylint: disable=too-many-locals ac_role = factories.AccessControlRoleFactory( object_type="Control", name="Custom Role", ) with factories.single_commit(): # Create one more custom role control = factories.ControlFactory(slug="Control 1") person = factories.PersonFactory() factories.AccessControlPersonFactory( ac_list=control.acr_acl_map[ac_role], person=person, ) audit = factories.AuditFactory() # pylint: disable=protected-access # This is used to update control revision data with the new ACL entry # without making a put request to that control. factories.ModelFactory._log_event(control) self._create_snapshots(audit, [control]) db.session.delete(ac_role) db.session.commit() search_request = [{ "object_name": "Snapshot", "filters": { "expression": { "left": "child_type", "op": { "name": "=" }, "right": "Control", }, }, }] parsed_data = self.export_parsed_csv( search_request)["Control Snapshot"][0] self.assertNotIn("Custom Role", parsed_data)
def test_admin_has_access(self): """Ensure that global creator has access to created proposal by him""" role_creator = all_models.Role.query.filter( all_models.Role.name == "Creator").one() # prepare - create control, assign roles factories.AccessControlRoleFactory(name="ACL_Reader", object_type="Control", update=0) with factories.single_commit(): control = factories.ControlFactory() person = factories.PersonFactory() rbac_factories.UserRoleFactory(role=role_creator, person=person) factories.AccessControlPersonFactory( ac_list=control.acr_name_acl_map["ACL_Reader"], person=person, ) control_id = control.id # make query to create proposal self.api.set_user(person) self.client.get("/login") acr_class = all_models.AccessControlRole acr = acr_class.query.filter( acr_class.name == 'ProposalEditor', acr_class.object_type == 'Proposal').one() create_data = self._get_create_proposal_request( control_id, acr.id, person.id) self.api.post(all_models.Proposal, create_data) query_data = self._get_query_proposal_request(control_id) headers = { "Content-Type": "application/json", } resp = self.api.client.post("/query", data=json.dumps(query_data), headers=headers).json self.assertEqual(1, len(resp)) self.assertEqual(resp[0]["Proposal"]["count"], 1)
def test_relationship_disallowed_type(self): """Validation fails when source-destination are snapshottable.""" audit = factories.AuditFactory() snapshottable = factories.ControlFactory() ctrl_revision = all_models.Revision.query.filter( all_models.Revision.resource_id == snapshottable.id, all_models.Revision.resource_type == snapshottable.type, ).first() snapshot = factories.SnapshotFactory( parent=audit, revision_id=ctrl_revision.id, child_type=snapshottable.type, child_id=snapshottable.id, ) with self.assertRaises(ValidationError): factories.RelationshipFactory(source=snapshottable, destination=snapshot) with self.assertRaises(ValidationError): factories.RelationshipFactory(source=snapshot, destination=snapshottable)
def setUp(self): with factories.single_commit(): super(TestExportControls, self).setUp() self.client.get("/login") self.headers = { 'Content-Type': 'application/json', "X-Requested-By": "GGRC", "X-export-view": "blocks", } with factories.single_commit(): self.basic_owner = factories.PersonFactory(name="basic owner") self.control = factories.ControlFactory() self.acr_id = all_models.AccessControlRole.query.filter_by( object_type=self.control.type, name="Admin" ).first().id self.owner_object = factories.AccessControlListFactory( person=self.basic_owner, object=self.control, ac_role_id=self.acr_id )
def test_unmap_snapshotable(self): """Unmap snapshotable should change review status""" control = factories.ControlFactory() resp, review = generate_review_object(control) 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)
def _create_snapshot(): """Create snapshot for test""" audit = factories.AuditFactory() assessment = factories.AssessmentFactory(audit=audit) context = factories.ContextFactory(related_object=assessment) assessment.context = context factories.RelationshipFactory(source=audit, destination=assessment) control = factories.ControlFactory(description='control-9') revision = all_models.Revision.query.filter( all_models.Revision.resource_id == control.id, all_models.Revision.resource_type == control.__class__.__name__ ).order_by( all_models.Revision.id.desc() ).first() snapshot = factories.SnapshotFactory( parent=audit, child_id=control.id, child_type=control.__class__.__name__, revision_id=revision.id ) return assessment, snapshot