def test_last_reviewed(self): """last_reviewed_by, last_reviewed_by should be set if reviewed""" risk = factories.RiskFactory() resp, review = self.generator.generate_object( all_models.Review, { "reviewable": { "type": risk.type, "id": risk.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 resp = self.api.put( review, { "status": all_models.Review.STATES.REVIEWED, }, ) self.assert200(resp) self.assertIsNotNone(resp.json["review"]["last_reviewed_by"]) self.assertIsNotNone(resp.json["review"]["last_reviewed_at"]) review = all_models.Review.query.get(review_id) self.assertIsNotNone(review.last_reviewed_by) self.assertIsNotNone(review.last_reviewed_at)
def test_search_risk_by_dates(self, field, attr): """Test query endpoint for risk by dates.""" current_date = datetime.date.today() with factories.single_commit(): factories.RiskFactory(**{attr: current_date}) request_data = [{ "filters": { "expression": { "left": {"left": field, "op": {"name": "~"}, "right": current_date.strftime("%Y-%m-%d")}, "op": {"name": "AND"}, "right": {"left": "Status", "op": {"name": "IN"}, "right": ["Active", "Draft", "Deprecated"]} } }, "object_name": "Risk", "order_by": [{"name": "updated_at", "desc": "true"}], }] response = self.api.post( all_models.Risk, data=request_data, url="/query", ) self.assert200(response) response_data = response.json[0]["Risk"] self.assertEqual(response_data["count"], 1) self.assertEqual(response_data["values"][0][attr], current_date.strftime("%Y-%m-%d"))
def test_get_risk_external_comment(self): """Test query endpoint for risk ExternalComments.""" with factories.single_commit(): risk = factories.RiskFactory() comment = factories.ExternalCommentFactory(description="comment") factories.RelationshipFactory(source=risk, destination=comment) request_data = [{ "filters": { "expression": { "object_name": "Risk", "op": { "name": "relevant" }, "ids": [risk.id] }, }, "object_name":"ExternalComment", "order_by": [{"name": "created_at", "desc": "true"}], }] response = self.api.post( all_models.Risk, data=request_data, url="/query", ) self.assert200(response) response_data = response.json[0]["ExternalComment"] self.assertEqual(response_data["count"], 1) self.assertEqual(response_data["values"][0]["description"], "comment")
def test_search_risk_by_users(self, field, attr): """Test query endpoint for risk by users.""" with factories.single_commit(): person = factories.PersonFactory() factories.RiskFactory(**{attr: person}) request_data = [{ "filters": { "expression": { "left": {"left": field, "op": {"name": "~"}, "right": person.email}, "op": {"name": "AND"}, "right": {"left": "Status", "op": {"name": "IN"}, "right": ["Active", "Draft", "Deprecated"]} } }, "object_name": "Risk", "order_by": [{"name": "updated_at", "desc": "true"}], }] response = self.api.post( all_models.Risk, data=request_data, url="/query", ) self.assert200(response) response_data = response.json[0]["Risk"] self.assertEqual(response_data["count"], 1) self.assertEqual(response_data["values"][0][attr]['email'], person.email)
def _create_external_object(): """Populate external model object that could not be imported.""" with factories.single_commit(): objects = [ factories.ControlFactory(directive=None), factories.RiskFactory() ] ca_definitions = { cad.title: cad for object in objects for cad in object.get_custom_attribute_definitions([ "CA text", "CA rich text", "CA date", "CA multiselect", "CA dropdown" ]) } ca_values = { "CA text": "Control ca text", "CA rich text": "control<br><br>\nrich text", "CA date": "22/02/2022", "CA multiselect": "yes", "CA dropdown": "one" } for title, value in ca_values.items(): for obj in objects: factories.ExternalCustomAttributeValueFactory( custom_attribute=ca_definitions[title], attributable=obj, attribute_value=value )
def test_update_risk_snapshot(self): """Update risk snapshot to the latest version""" with factories.single_commit(): program = factories.ProgramFactory(title="P1") risk = factories.RiskFactory(title="R1") risk_id = risk.id factories.RelationshipFactory(source=program, destination=risk) # Risk snapshot created for audit during mapping audit to program self.objgen.generate_object(all_models.Audit, { "title": "A1", "program": {"id": program.id}, "status": "Planned", "snapshots": { "operation": "create", }, }) # Update risk to get outdated snapshot (new risk revision) risk = all_models.Risk.query.get(risk_id) self.api.put(risk, risk.id, { "title": "New risk title", }) audit = all_models.Audit.query.filter_by(title="A1").one() snapshot = all_models.Snapshot.query.first() self.assertEquals(audit, snapshot.parent) # Update snapshot to the latest revision response = self.api.put(snapshot, snapshot.id, { "update_revision": "latest", }) self.assert200(response) self.assertTrue(response.json["snapshot"]["is_latest_revision"])
def test_apply_mapping_cad(self): """Test apply mapping CAVs proposal.""" with factories.single_commit(): risk = factories.RiskFactory(title="1") cad = factories.CustomAttributeDefinitionFactory( definition_type="risk", attribute_type="Map:Person") person = factories.PersonFactory() cav = factories.CustomAttributeValueFactory( custom_attribute=cad, attributable=risk, attribute_object_id=person.id, attribute_value="Person", ) self.assertEqual(person, risk.custom_attribute_values[0].attribute_object) risk_id = risk.id proposal = factories.ProposalFactory(instance=risk, content={ "custom_attribute_values": { cad.id: { "attribute_value": "Person", "attribute_object": None, }, }, }, agenda="agenda content") with self.number_obj_revisions_for(risk): self.apply_proposal(proposal) risk = all_models.Risk.query.get(risk_id) cav = risk.custom_attribute_values[0] self.assertEqual("Person", cav.attribute_value) self.assertIsNone(cav.attribute_object_id)
def test_mandatory_delete(self, mandatory, exp_response): """Test set empty field via import if acr mandatory is {mandatory}""" role = factories.AccessControlRoleFactory( name=ROLE_NAME, object_type="Risk", mandatory=mandatory, ) with factories.single_commit(): user = factories.PersonFactory() risk = factories.RiskFactory() role_id = role.id factories.AccessControlPersonFactory( ac_list=risk.acr_name_acl_map[ROLE_NAME], person=user, ) response = self.import_data( OrderedDict([ ("object_type", "Risk"), ("Code*", risk.slug), (ROLE_NAME, "--"), ])) self._check_csv_response(response, exp_response) db_data = defaultdict(set) risk = all_models.Risk.query.get(risk.id) for person, acl in risk.access_control_list: db_data[acl.ac_role_id].add(person.id) if mandatory: cur_user = all_models.Person.query.filter_by( email="*****@*****.**").first() self.assertEqual(set([cur_user.id]), db_data[role_id]) else: self.assertFalse(db_data[role_id])
def test_change_cad(self): """Test create proposal with change CAVs.""" with factories.single_commit(): risk = factories.RiskFactory(title="1") cad = factories.CustomAttributeDefinitionFactory( definition_type="risk") factories.CustomAttributeValueFactory(custom_attribute=cad, attributable=risk, attribute_value="123") risk_id = risk.id cad_id = cad.id data = risk.log_json() data["custom_attribute_values"][0]["attribute_value"] = "321" self.create_proposal(risk, full_instance_content=data, agenda="update cav", context=None) risk = all_models.Risk.query.get(risk_id) self.assertEqual(1, len(risk.proposals)) self.assertIn("custom_attribute_values", risk.proposals[0].content) self.assertEqual( { unicode(cad_id): { "attribute_value": u"321", "attribute_object": None } }, risk.proposals[0].content["custom_attribute_values"]) self.assertEqual(1, len(risk.comments))
def test_create_after_objects(self): """Test eager creation of ACLs on existing objects with new ACR.""" risk_id = factories.RiskFactory().id role_name = "New Custom Role" self._post_role(name=role_name, object_type="Risk") risk = all_models.Risk.query.get(risk_id) self.assertIn(role_name, risk.acr_name_acl_map.keys()) self.assertIsNotNone(risk.acr_name_acl_map[role_name])
def test_delete_risk(self): """Test risk delete with internal user.""" risk = factories.RiskFactory() response = self.api.delete(risk) self.assert403(response) risk = all_models.Risk.query.get(risk.id) self.assertIsNotNone(risk.title)
def test_update_risk(self): """Test risk update with internal user.""" risk = factories.RiskFactory() old_title = risk.title response = self.api.put(risk, {"title": "new-title"}) self.assert403(response) risk = all_models.Risk.query.get(risk.id) self.assertEqual(old_title, risk.title)
def test_delete(self): """Test risk delete with internal user.""" risk = factories.RiskFactory() url = "/api/risks/%s" % risk.id response = self.api.delete(url) self.assert403(response) risk = all_models.Risk.query.get(risk.id) self.assertIsNotNone(risk)
def test_update_review_status_to_null(self): """Test review_status is not set to None""" risk = factories.RiskFactory() response = self.api.put(risk, {"review_status": None}) self.assert400(response) self.assertEqual(response.json["message"], "Review status for the object is not specified") risk = db.session.query(all_models.Risk).get(risk.id) self.assertIsNotNone(risk.external_id)
def test_rel_remove_parent(self): """Test if relationship will be removed if parent instance is removed.""" risk = factories.RiskFactory() self.create_proposal_for(risk) self.assertEqual(1, self.proposal_relationships(risk).count()) response = self.api.delete(risk) self.assert200(response) self.assertEqual(0, self.proposal_relationships(risk).count())
def test_rel_remove_proposal(self): """Test if relationship will be removed if proposal is removed.""" risk = factories.RiskFactory() response = self.create_proposal_for(risk) self.assertEqual(1, self.proposal_relationships(risk).count()) proposal = all_models.Proposal.query.get( response.json["proposal"]["id"]) response = self.api.delete(proposal) self.assert200(response) self.assertEqual(0, self.proposal_relationships(risk).count())
def test_update(self): """Test risk update with external user.""" risk = factories.RiskFactory() url = "/api/risks/%s" % risk.id risk_body = self.generate_risk_body() risk_body["id"] = risk.id response = self.api.put(url, {"risk": risk_body}) self.assert200(response) risk = all_models.Risk.query.get(risk.id) self.assert_instance(risk_body, risk)
def test_update(self): """Test risk update with internal user.""" risk = factories.RiskFactory() url = "/api/risks/%s" % risk.id old_title = risk.title data = {"risk": {"title": "new-title", "risk_type": "risk"}} response = self.api.put(url, data) self.assert403(response) risk = all_models.Risk.query.get(risk.id) self.assertEqual(old_title, risk.title)
def test_update_review_status_display_name(self): """Test review_status_display_name is updated""" risk = factories.RiskFactory() new_value = "test123" self.api.put(risk, risk.id, { "review_status_display_name": new_value, "review_status": all_models.Review.STATES.UNREVIEWED }) risk = db.session.query(all_models.Risk).get(risk.id) self.assertEquals(risk.review_status_display_name, new_value)
def test_update_review_status(self): """Test review_status is updated""" risk = factories.RiskFactory() new_value = all_models.Review.STATES.REVIEWED self.api.put( risk, { "review_status": new_value, "review_status_display_name": "some status" }) risk = db.session.query(all_models.Risk).get(risk.id) self.assertEquals(risk.review_status, new_value)
def test_review_status_search(self): """Review status search. The query should take data form review_status_display_name field """ risk_id = factories.RiskFactory( review_status_display_name="Review Needed").id risk_by_review_status = self.simple_query( "Risk", expression=["Review Status", "=", "Review Needed"]) self.assertEquals(1, len(risk_by_review_status)) self.assertEquals(risk_id, risk_by_review_status[0]["id"])
def test_delete_review(self): """Test delete review via API""" with factories.single_commit(): risk = factories.RiskFactory() risk_id = risk.id review = factories.ReviewFactory(reviewable=risk) review_id = review.id resp = self.api.delete(review) self.assert200(resp) review = all_models.Review.query.get(review_id) risk = all_models.Risk.query.get(risk_id) self.assertIsNone(review) self.assertEquals(0, len(risk.related_objects(_types=["Review"])))
def test_nonadmin_has_no_access(self): """Test access to proposal for non creator of proposal""" role_creator = all_models.Role.query.filter( all_models.Role.name == "Creator").one() # prepare - create risk, assign roles factories.AccessControlRoleFactory(name="ACL_Reader", object_type="Risk", update=0) with factories.single_commit(): risk = factories.RiskFactory() person1 = factories.PersonFactory() person2 = factories.PersonFactory() for person in (person1, person2): rbac_factories.UserRoleFactory(role=role_creator, person=person) factories.AccessControlPersonFactory( ac_list=risk.acr_name_acl_map["ACL_Reader"], person=person, ) risk_id = risk.id person2_id = person2.id # make query to create proposal by person1 self.api.set_user(person1) 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( risk_id, acr.id, person1.id) self.api.post(all_models.Proposal, create_data) # login as person2 and make request self.api.set_user(all_models.Person.query.get(person2_id)) self.client.get("/login") query_data = self._get_query_proposal_request(risk_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"], 0)
def test_risk_memcache(self): """Test get updated risk revisions.""" risk = factories.RiskFactory() risk_id = risk.id self.api.put(risk, {"title": "new_title"}) self.update_revisions(risk) db.session.expire_all() risk = all_models.Risk.eager_query().get(risk_id) self.api.put(risk, {"description": "new test description BLA"}) risk = all_models.Risk.eager_query().get(risk_id) self.update_revisions(risk) risk = all_models.Risk.eager_query().get(risk_id) self.api.put(risk, {"description": "BLA bla bla"}) risk = all_models.Risk.eager_query().get(risk_id) self.update_revisions(risk)
def setUp(self): """Set up for Reviewable test cases.""" super(TestExportReviewable, self).setUp() with factories.single_commit(): person1 = factories.PersonFactory() self.person1_email = person1.email person2 = factories.PersonFactory() self.person2_email = person2.email risk = factories.RiskFactory(title="Test risk") review = factories.ReviewFactory(reviewable=risk) review.add_person_with_role_name(person1, 'Reviewers') review.add_person_with_role_name(person2, 'Reviewers') self.client.get("/login")
def test_revision_review_stub(self): """ Test proper review stub population in revision content """ risk = factories.RiskFactory() revisions = _get_revisions(risk) self.assertEqual(len(revisions), 1) self.assertEqual(revisions[0].action, "created") resp = self.api_helper.post( all_models.Review, { "review": { "reviewable": { "type": risk.type, "id": risk.id, }, "context": None, "notification_type": "email", "status": all_models.Review.STATES.REVIEWED, "access_control_list": build_reviewer_acl() }, }, ) self.assertEqual(201, resp.status_code) self.assertIn("review", resp.json) resp_review = resp.json["review"] self.assertEqual(all_models.Review.STATES.REVIEWED, resp_review["status"]) revisions = _get_revisions(risk) self.assertEqual(len(revisions), 2) self.assertEqual(revisions[0].action, "created") self.assertEqual(revisions[1].action, "modified") rev_content = revisions[1].content self.assertIsNotNone(rev_content) self.assertIn("review", rev_content) review = rev_content["review"] self.assertIsNotNone(review) expected = { "context_id": None, "href": "/api/reviews/{}".format(resp_review["id"]), "id": resp_review["id"], "type": resp_review["type"], } self.assertEqual(review, expected)
def test_notification_subject(self, send_mail_mock): """Test that emails are sent with proper subject.""" expected_subject = "GGRC Change requests review digest " \ "for 01/15/2019 04:00:00 PST" reviewer = factories.PersonFactory() reviewer_role_id = all_models.AccessControlRole.query.filter_by( name="Reviewers", object_type="Review", ).one().id with factories.single_commit(): risk_admin = factories.PersonFactory() risk = factories.RiskFactory() risk.add_person_with_role_name(risk_admin, "Admin") email_message = "email email_message" _, review = self.generator.generate_object( all_models.Review, { "reviewable": { "type": risk.type, "id": risk.id, }, "context": None, "notification_type": all_models.Review.NotificationTypes.EMAIL_TYPE, "status": all_models.Review.STATES.REVIEWED, "email_message": email_message, "access_control_list": [{ "ac_role_id": reviewer_role_id, "person": { "id": reviewer.id }, }], }, ) self.api.modify_object(review.reviewable, {"title": "new title"}) with mock.patch.object(fast_digest.DIGEST_TMPL, "render"): fast_digest.send_notification() for call_item in send_mail_mock.call_args_list: self.assertEqual(expected_subject, call_item[1]["subject"])
def test_proposal_apply_review_status(self, notification_type, num_notifications_expected): """Change via proposal with ignorable attrs review status not change""" with factories.single_commit(): risk = factories.RiskFactory() review = factories.ReviewFactory( status=all_models.Review.STATES.REVIEWED, reviewable=risk, notification_type=notification_type ) review_id = review.id user = factories.PersonFactory() acl = factories.AccessControlListFactory( ac_role=factories.AccessControlRoleFactory(object_type="Risk"), object=risk ) proposal_content = { "access_control_list": { acl.ac_role_id: { "added": [{"id": user.id, "email": user.email}], "deleted": [] } } } 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.REVIEWED) review_notif_types = all_models.Review.NotificationObjectTypes notif_unreviewed_type = all_models.Notification.query.join( all_models.NotificationType ).filter( all_models.NotificationType.name == review_notif_types.STATUS_UNREVIEWED ).all() self.assertEqual(num_notifications_expected, len(notif_unreviewed_type))
def test_comment_import(self): """Don't revert state when comment added. Review -> REVIEWED """ risk = factories.RiskFactory() resp, review = generate_review_object( risk, state=all_models.Review.STATES.REVIEWED) del review risk_id = risk.id self.assertEqual(201, resp.status_code) import_data = OrderedDict([("object_type", "Risk"), ("Code*", risk.slug), ("comments", "some comments")]) response = self.import_data(import_data) self._check_csv_response(response, {}) risk = all_models.Risk.query.get(risk_id) self.assertEqual(all_models.Review.STATES.REVIEWED, risk.review_status)
def test_simple_create_proposal(self): """Test simple create proposal.""" new_vulnerability = "2" risk = factories.RiskFactory(vulnerability="1") risk_id = risk.id risk.vulnerability = new_vulnerability self.assertEqual(0, len(risk.comments)) self.create_proposal(risk, full_instance_content=risk.log_json(), agenda="update title from 1 to 2", context=None) risk = all_models.Risk.query.get(risk_id) self.assertEqual(1, len(risk.proposals)) self.assertIn("fields", risk.proposals[0].content) self.assertEqual({"vulnerability": "2"}, risk.proposals[0].content["fields"]) self.assertEqual(1, len(risk.comments))