Example #1
0
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()
Example #2
0
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
            }
        },
    }]
Example #3
0
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
Example #4
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"],
    }
Example #5
0
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
Example #6
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),
        },
    ]
Example #7
0
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
Example #8
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
Example #9
0
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
Example #10
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()
Example #11
0
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()
Example #12
0
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
Example #13
0
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()
Example #14
0
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
Example #15
0
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()
Example #16
0
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
Example #17
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
Example #18
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
Example #19
0
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
Example #20
0
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"],
    }
Example #21
0
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"]
Example #22
0
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"],
    }
Example #23
0
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
Example #24
0
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
Example #25
0
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