def test_list_reports(mock_send, mock_webhook_send, client, create_user, handle_events): user = create_user("opencve") response = client.login("opencve").get("/api/reports") assert response.status_code == 200 assert response.json == [] handle_events("modified_cves/CVE-2018-18074.json") user.vendors.append(Vendor.query.filter_by(name="canonical").first()) db.session.commit() handle_alerts() handle_reports() report = Report.query.first() report.created_at = datetime(2021, 1, 1, tzinfo=timezone.utc) response = client.login("opencve").get("/api/reports") assert response.status_code == 200 assert len(response.json) == 1 assert response.json[0] == { "id": report.public_link, "details": ["canonical"], "created_at": "2021-01-01T00:00:00Z", } db.session.commit()
def test_get_alert(mock_send, mock_webhook_send, client, create_user, create_cve, handle_events): create_cve("CVE-2018-18074") handle_events("modified_cves/CVE-2018-18074_cvss.json") user = create_user("opencve") user.vendors.append(Vendor.query.filter_by(name="canonical").first()) db.session.commit() handle_alerts() handle_reports() report = Report.query.first() report.created_at = datetime(2021, 1, 1, tzinfo=timezone.utc) alert = Alert.query.first() alert.created_at = datetime(2021, 1, 1, tzinfo=timezone.utc) response = client.login("opencve").get( f"/api/reports/{report.public_link}/alerts/{alert.id}") assert response.json == [{ "cve": "CVE-2018-18074", "type": "cvss", "details": { "old": { "v2": 5.0, "v3": 9.8 }, "new": { "v2": 6.0, "v3": 10 } }, }]
def test_report_with_notification(mock_send, create_user, handle_events): handle_events("modified_cves/CVE-2018-18074.json") user = create_user() user.vendors.append(Vendor.query.filter_by(name="canonical").first()) db.session.commit() handle_alerts() handle_reports() reports = Report.query.all() assert len(reports) == 1 assert reports[0].user.id == user.id assert reports[0].details == ["canonical"] assert reports[0].alerts == Alert.query.filter_by(user_id=user.id).all() assert mock_send.called mock_send.assert_called_with( user, **{ "subject": "1 alert on Canonical", "total_alerts": 1, "alerts_sorted": get_sorted_alerts(Alert.query.all()), "report_public_link": Report.query.first().public_link, }, ) assert Alert.query.filter_by(notify=False).count() == 0
def test_alert_vendor_subscription(create_cve, create_user, handle_events): handle_events("modified_cves/CVE-2018-18074.json") cve = Cve.query.first() event = Event.query.first() assert event.type == "new_cve" assert event.review == False # Create a user with a vendor subscription user = create_user() vendor = Vendor.query.filter_by(name="canonical").first() user.vendors.append(vendor) db.session.commit() handle_alerts() assert event.review == True # An alert has been created alerts = Alert.query.all() assert len(alerts) == 1 alert = alerts[0] assert alert.user.id == user.id assert len(alert.events) == 1 assert alert.events[0].id == event.id assert alert.cve.id == cve.id assert alert.notify == False assert alert.details == { "filters": ["new_cve"], "products": [], "vendors": ["canonical"], }
def test_no_alerts(create_cve): handle_alerts() assert Alert.query.count() == 0 # Create a CVE without events create_cve("CVE-2018-18074") assert Alert.query.count() == 0
def test_list_alerts(mock_send, mock_webhook_send, client, create_user, create_cve, handle_events): create_cve("CVE-2018-18074") handle_events("modified_cves/CVE-2018-18074_cvss.json") user = create_user("opencve") user.vendors.append(Vendor.query.filter_by(name="canonical").first()) db.session.commit() handle_alerts() handle_reports() report = Report.query.first() report.created_at = datetime(2021, 1, 1, tzinfo=timezone.utc) alert = Alert.query.first() alert.created_at = datetime(2021, 1, 1, tzinfo=timezone.utc) response = client.login("opencve").get( f"/api/reports/{report.public_link}/alerts") assert response.json == [ { "created_at": "2021-01-01T00:00:00Z", "cve": "CVE-2018-18074", "details": { "filters": ["cvss"], "products": [], "vendors": ["canonical"] }, "id": str(alert.id), }, ]
def test_report_webhook_request_exception(mock_send, mock_post, create_user, handle_events): mock_post.return_value = mock_response( 404, "404 Not Found", raise_exception=HTTPError("404 NOT FOUND")) handle_events("modified_cves/CVE-2018-18074.json") handle_events("modified_cves/CVE-2018-18074_summary.json") user = create_user() user.vendors.append(Vendor.query.filter_by(name="canonical").first()) db.session.commit() handle_alerts() handle_reports() reports = Report.query.all() assert len(reports) == 1 report = reports[0] assert report.user.id == user.id assert report.details == ["canonical"] assert report.alerts == Alert.query.filter_by(user_id=user.id).all() assert len(reports[0].alerts) == 1 assert len(reports[0].alerts[0].events) == 2 assert mock_send.called assert mock_post.called assert Alert.query.filter_by(notify=False).count() == 0
def pre_webhook(create_user): """ Creates a User, Report and Webhook message for further use in testing. :param create_user: Create User fixture to be used to create the user :return: The Webhook message, User, Report and the alerts created during the "handle_alerts" task """ import datetime user = create_user() user.vendors.append(Vendor.query.filter_by(name="canonical").first()) user.enable_notifications = True db.session.commit() handle_alerts() report = Report( public_link="link", created_at=datetime.datetime(2021, 8, 2, 14, 0, 0), updated_at=datetime.datetime(2021, 8, 3, 14, 0, 0), seen=False, details="[canonical]", user_id=user.id, ) alerts = Alert.query.filter_by(user_id=user.id).all() webhook_message = create_webhook_message(report, alerts, user) return webhook_message, user, report, alerts
def test_handle_alerts_no_subscription(create_cve, handle_events): # Create a new CVE with a 'new_cve' event handle_events("modified_cves/CVE-2018-18074.json") event = Event.query.first() assert event.type == "new_cve" assert event.review == False handle_alerts() assert event.review == True assert Alert.query.count() == 0
def test_list(mock_send, app, handle_events, create_user): handle_events("modified_cves/CVE-2018-18074.json") user = create_user() user.vendors.append(Vendor.query.filter_by(name="canonical").first()) db.session.commit() handle_alerts() handle_reports() with app.test_request_context(): reports = ReportController.list_items({"user_id": user.id}) assert len(reports) == 1 assert reports[0].user.id == user.id assert reports[0].details == ["canonical"] assert reports[0].alerts == Alert.query.filter_by(user_id=user.id).all()
def test_list_reports(mock_send, client, login, handle_events): user = User.query.first() handle_events("modified_cves/CVE-2018-18074.json") user.vendors.append(Vendor.query.filter_by(name="canonical").first()) db.session.commit() handle_alerts() handle_reports() report = Report.query.first() report.created_at = datetime(2021, 1, 1, tzinfo=timezone.utc) response = client.get("/reports") assert response.status_code == 200 assert b"Canonical" in response.data assert b"Jan 01 '21 at 00:00" in response.data db.session.commit()
def test_get(mock_send, app, handle_events, create_user): handle_events("modified_cves/CVE-2018-18074.json") user = create_user() user.vendors.append(Vendor.query.filter_by(name="canonical").first()) db.session.commit() handle_alerts() handle_reports() report_1 = Report.query.first() assert report_1.seen == False with app.test_request_context(): report_2 = ReportController.get({"public_link": report_1.public_link}) assert report_1.id == report_2.id assert report_2.seen == True
def test_get_report(mock_send, mock_webhook_send, client, create_user, handle_events): user = create_user("opencve") handle_events("modified_cves/CVE-2018-18074.json") user.vendors.append(Vendor.query.filter_by(name="canonical").first()) db.session.commit() handle_alerts() handle_reports() report = Report.query.first() report.created_at = datetime(2021, 1, 1, tzinfo=timezone.utc) alert = Alert.query.first() alert.created_at = datetime(2021, 1, 1, tzinfo=timezone.utc) response = client.login("opencve").get("/api/reports") assert response.status_code == 200 assert len(response.json) == 1 assert response.json[0] == { "id": report.public_link, "details": ["canonical"], "created_at": "2021-01-01T00:00:00Z", } response = client.login("opencve").get( f"/api/reports/{report.public_link}") assert response.status_code == 200 data = response.json alerts = data.pop("alerts") assert alerts == [{ "id": str(alert.id), "created_at": "2021-01-01T00:00:00Z", "cve": "CVE-2018-18074", "details": { "products": [], "vendors": ["canonical"], "filters": ["new_cve"], }, }] assert data == { "id": report.public_link, "details": ["canonical"], "created_at": "2021-01-01T00:00:00Z", } db.session.commit()
def test_report_without_notification(mock_send, create_user, handle_events): handle_events("modified_cves/CVE-2018-18074.json") user = create_user() user.vendors.append(Vendor.query.filter_by(name="canonical").first()) user.enable_notifications = False db.session.commit() handle_alerts() handle_reports() reports = Report.query.all() assert len(reports) == 1 assert reports[0].user.id == user.id assert reports[0].details == ["canonical"] assert reports[0].alerts == Alert.query.filter_by(user_id=user.id).all() assert not mock_send.called
def test_get_report(mock_send, client, login, handle_events): user = User.query.first() handle_events("modified_cves/CVE-2018-18074.json") user.vendors.append(Vendor.query.filter_by(name="canonical").first()) db.session.commit() handle_alerts() handle_reports() report = Report.query.first() report.created_at = datetime(2021, 1, 1, tzinfo=timezone.utc) response = client.get(f"/reports/{report.public_link}") assert b"1 alert on 01/01/21" in response.data assert b"Canonical" in response.data assert b"CVE-2018-18074" in response.data assert b"9.8" in response.data assert b"New CVE" in response.data db.session.commit()
def test_alert_types_empty_filter(create_cve, create_user, handle_events): create_cve("CVE-2018-18074") vendor = Vendor.query.filter_by(name="canonical").first() handle_events("modified_cves/CVE-2018-18074_summary.json") event = Event.query.first() assert event.type == "summary" # The user doesn't want to be alerted for 'summary' events user = create_user("user1") user.vendors.append(vendor) user.filters_notifications = {"cvss": 1.0, "event_types": []} handle_alerts() assert event.review == True # No alert created alerts = Alert.query.all() assert len(alerts) == 0
def test_report_bad_smtp_config(mock_send, create_user, handle_events): mock_send.side_effect = EmailError("error") handle_events("modified_cves/CVE-2018-18074.json") user = create_user() user.vendors.append(Vendor.query.filter_by(name="canonical").first()) db.session.commit() handle_alerts() handle_reports() reports = Report.query.all() assert len(reports) == 1 assert reports[0].user.id == user.id assert reports[0].details == ["canonical"] assert reports[0].alerts == Alert.query.filter_by(user_id=user.id).all() assert len(reports[0].alerts) == 1 assert Alert.query.filter_by(notify=False).count() == 0
def test_get_users_with_alerts(freezer, create_user, handle_events, hour, count): handle_events("modified_cves/CVE-2018-18074.json") # Create 2 users with different frequency notification user1 = create_user("user1") user1.vendors.append(Vendor.query.filter_by(name="canonical").first()) user1.frequency_notifications = "always" db.session.commit() user2 = create_user("user2") user2.vendors.append(Vendor.query.filter_by(name="canonical").first()) user2.frequency_notifications = "once" db.session.commit() handle_alerts() freezer.move_to(f"2021-01-01 {hour}") users = get_users_with_alerts() assert len(users) == count
def test_report_with_notification_webhook_disabled(mock_send, mock_webhook_send, create_user, handle_events, app): old = app.config["GLOBAL_WEBHOOK_ENABLED"] app.config["GLOBAL_WEBHOOK_ENABLED"] = False handle_events("modified_cves/CVE-2018-18074.json") user = create_user() user.vendors.append(Vendor.query.filter_by(name="canonical").first()) db.session.commit() handle_alerts() handle_reports() reports = Report.query.all() assert len(reports) == 1 report = reports[0] assert report.user.id == user.id assert report.details == ["canonical"] assert report.alerts == Alert.query.filter_by(user_id=user.id).all() alerts = report.alerts assert len(alerts) == 1 assert mock_send.called mock_send.assert_called_with( user, **{ "subject": "1 alert on Canonical", "total_alerts": 1, "alerts_sorted": get_sorted_alerts(Alert.query.all()), "report_public_link": Report.query.first().public_link, }, ) assert not mock_webhook_send.called assert Alert.query.filter_by(notify=False).count() == 0 app.config["GLOBAL_WEBHOOK_ENABLED"] = old
def test_alert_types_filter(create_cve, create_user, handle_events): create_cve("CVE-2018-18074") vendor = Vendor.query.filter_by(name="canonical").first() handle_events("modified_cves/CVE-2018-18074_summary.json") event = Event.query.first() assert event.type == "summary" # User1 will be alerted (notification enabled for 'summary') vendor = Vendor.query.filter_by(name="canonical").first() user1 = create_user("user1") user1.vendors.append(vendor) user1.filters_notifications = { "cvss": 5.0, "event_types": ["new_cve", "references", "summary"], } # User2 will not be alerted (notification disabled for 'summary') user2 = create_user("user2") user2.vendors.append(vendor) user2.filters_notifications = { "cvss": 5.0, "event_types": ["new_cve", "cwes", "references"], } db.session.commit() handle_alerts() assert event.review == True # 1 alert created for user1 alerts = Alert.query.all() assert len(alerts) == 1 alert = alerts[0] assert alert.user.id == user1.id assert alert.notify == False assert alert.details == { "filters": ["summary"], "products": [], "vendors": ["canonical"], }
def test_alert_first_time_filter(create_cve, create_user, create_vendor, handle_events): create_cve("CVE-2018-18074") handle_events("modified_cves/CVE-2018-18074_first_time_1.json") # User1 has subscribed to opencve vendor user1 = create_user("user1") vendor = Vendor.query.filter_by(name="opencveio").first() user1.vendors.append(vendor) db.session.commit() # User2 hasn't subscribed to opencve vendor user2 = create_user("user2") vendor = create_vendor("another_vendor") user2.vendors.append(vendor) db.session.commit() handle_alerts() # There is only 1 alert for user1 alert_1 = Alert.query.first() assert alert_1.user == user1 assert sorted([e.type.code for e in alert_1.events]) == ["cpes", "first_time"] assert sorted( Event.query.filter_by(type="first_time").first().details) == [ "opencveio", "opencveio$PRODUCT$opencve", ] # We trigger another version of this CVE, but there is no new # vendor/product, only a new version of an existing product handle_events("modified_cves/CVE-2018-18074_first_time_2.json") handle_alerts() # The new alert only contains the `cpes` event alerts = Alert.query.all() alerts.remove(alert_1) assert sorted([e.type.code for e in alerts[0].events]) == ["cpes"]
def test_alert_cvss_filter(create_cve, create_user, handle_events): handle_events("modified_cves/CVE-2018-18074.json") # Set the CVSS score to 5.0 cve = Cve.query.first() cve.cvss3 = 5.0 db.session.commit() event = Event.query.first() assert event.type == "new_cve" assert event.review == False # User1 will be alerted (5 > 1) vendor = Vendor.query.filter_by(name="canonical").first() user1 = create_user("user1") user1.vendors.append(vendor) user1.filters_notifications = {"cvss": 1.0, "event_types": ["new_cve"]} # User2 will not be alerted (5 < 6) user2 = create_user("user2") user2.vendors.append(vendor) user2.filters_notifications = {"cvss": 6.0, "event_types": ["new_cve"]} db.session.commit() handle_alerts() assert event.review == True # Only 1 alert has been created for user1 alerts = Alert.query.all() assert len(alerts) == 1 alert = alerts[0] assert alert.user.id == user1.id assert alert.notify == False assert alert.details == { "filters": ["new_cve"], "products": [], "vendors": ["canonical"], }
def test_list_alerts_authentication(mock_send, mock_webhook_send, client, create_user, handle_events): user = create_user("opencve") handle_events("modified_cves/CVE-2018-18074.json") user.vendors.append(Vendor.query.filter_by(name="canonical").first()) db.session.commit() handle_alerts() handle_reports() report = Report.query.first() alert = Alert.query.first() response = client.get(f"/api/reports/{report.public_link}/alerts") assert response.status_code == 401 response = client.get( f"/api/reports/{report.public_link}/alerts/{alert.id}") assert response.status_code == 401 client.login("opencve") response = client.get(f"/api/reports/{report.public_link}/alerts") assert response.status_code == 200 response = client.get(f"/api/reports/{report.public_link}/alerts") assert response.status_code == 200
def test_list_paginated(mock_send, mock_webhook_send, app, handle_events, create_user): old = app.config["REPORTS_PER_PAGE"] app.config["REPORTS_PER_PAGE"] = 2 user = create_user() db.session.commit() handle_events("modified_cves/CVE-2018-18074.json") user.vendors.append(Vendor.query.filter_by(name="canonical").first()) db.session.commit() handle_alerts() handle_reports() handle_events("modified_cves/CVE-2019-17052.json") user.vendors.append(Vendor.query.filter_by(name="linux").first()) db.session.commit() handle_alerts() handle_reports() handle_events("modified_cves/CVE-2020-26116.json") user.vendors.append(Vendor.query.filter_by(name="python").first()) db.session.commit() handle_alerts() handle_reports() with app.test_request_context(): reports = ReportController.list_items({"user_id": user.id}) assert len(reports) == 2 assert reports[0].details == ["python"] assert reports[1].details == ["linux"] reports = ReportController.list_items({"user_id": user.id, "page": 2}) assert len(reports) == 1 assert reports[0].details == ["canonical"] app.config["REPORTS_PER_PAGE"] = old
def test_report_with_notification_webhook_enabled(mock_send, mock_webhook_send, create_user, handle_events, app): handle_events("modified_cves/CVE-2018-18074.json") user = create_user() user.vendors.append(Vendor.query.filter_by(name="canonical").first()) db.session.commit() handle_alerts() handle_reports() reports = Report.query.all() assert len(reports) == 1 report = reports[0] assert report.user.id == user.id assert report.details == ["canonical"] assert report.alerts == Alert.query.filter_by(user_id=user.id).all() alerts = report.alerts assert len(alerts) == 1 alert = alerts[0] cve = alert.cve events = alert.events assert len(events) == 1 event = events[0] assert mock_send.called mock_send.assert_called_with( user, **{ "subject": "1 alert on Canonical", "total_alerts": 1, "alerts_sorted": get_sorted_alerts(Alert.query.all()), "report_public_link": Report.query.first().public_link, }, ) assert mock_webhook_send.called mock_webhook_send.assert_called_with( app.config["WEBHOOK_URL"], { 'username': user.username, 'created_at': report.created_at.isoformat(), 'updated_at': report.updated_at.isoformat(), 'public_link': report.public_link, 'vendors_products_summary': report.details, 'alert_count': len(alerts), 'alerts': [{ 'cve': cve.cve_id, 'description': cve.summary, 'details': alert.details, 'created_at': alert.created_at.isoformat(), # is updated once alert has been read 'updated_at': mock_webhook_send.call_args[0][1]["alerts"][0]["updated_at"], 'vendors': cve.vendors, 'cwes': cve.cwes, 'cvss2': cve.cvss2, 'cvss3': cve.cvss3, 'event_count': len(events), 'events': [{ 'created_at': event.created_at.isoformat(), 'updated_at': event.updated_at.isoformat(), 'type': event.type.code, 'details': {} }] }] }, mock_webhook_send.call_args[0][2]) assert Alert.query.filter_by(notify=False).count() == 0