From 2dc5bbaaf29307be40fd19369cf6111d66c01664 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaspar=20L=C3=B6chte?= Date: Wed, 12 May 2021 17:02:10 +0200 Subject: [PATCH 01/12] Moved Alert related calls and types to seperate file --- gvm/protocols/gmpv208/entities/alerts.py | 653 +++++++++++++++++++++++ gvm/protocols/gmpv208/gmpv208.py | 481 ----------------- gvm/protocols/gmpv208/types.py | 146 ----- 3 files changed, 653 insertions(+), 627 deletions(-) create mode 100644 gvm/protocols/gmpv208/entities/alerts.py diff --git a/gvm/protocols/gmpv208/entities/alerts.py b/gvm/protocols/gmpv208/entities/alerts.py new file mode 100644 index 000000000..15c489be9 --- /dev/null +++ b/gvm/protocols/gmpv208/entities/alerts.py @@ -0,0 +1,653 @@ +# -*- coding: utf-8 -*- +# Copyright (C) 2021 Greenbone Networks GmbH +# +# SPDX-License-Identifier: GPL-3.0-or-later +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# pylint: disable=redefined-builtin +# MAYBE we should change filter to filter_string (everywhere) + +from enum import Enum +from typing import Any, Optional, Union + +from gvm.protocols.gmpv208.entities.report_formats import ( + ReportFormatType, +) # if I use latest, I get circular import :/ +from gvm.errors import RequiredArgument, InvalidArgument, InvalidArgumentType +from gvm.utils import add_filter, to_bool +from gvm.xml import XmlCommand + + +class AlertEvent(Enum): + """Enum for alert event types""" + + TASK_RUN_STATUS_CHANGED = 'Task run status changed' + UPDATED_SECINFO_ARRIVED = 'Updated SecInfo arrived' + NEW_SECINFO_ARRIVED = 'New SecInfo arrived' + TICKET_RECEIVED = 'Ticket received' + ASSIGNED_TICKET_CHANGED = 'Assigned ticket changed' + OWNED_TICKET_CHANGED = 'Owned ticket changed' + + +def get_alert_event_from_string( + alert_event: Optional[str], +) -> Optional[AlertEvent]: + """Convert an alert event string into a AlertEvent instance""" + if not alert_event: + return None + + alert_event = alert_event.lower() + + if alert_event == 'task run status changed': + return AlertEvent.TASK_RUN_STATUS_CHANGED + + if alert_event == 'updated secinfo arrived': + return AlertEvent.UPDATED_SECINFO_ARRIVED + + if alert_event == 'new secinfo arrived': + return AlertEvent.NEW_SECINFO_ARRIVED + + if alert_event == 'ticket received': + return AlertEvent.TICKET_RECEIVED + + if alert_event == 'assigned ticket changed': + return AlertEvent.ASSIGNED_TICKET_CHANGED + + if alert_event == 'owned ticket changed': + return AlertEvent.OWNED_TICKET_CHANGED + + raise InvalidArgument( + argument='alert_event', function=get_alert_event_from_string.__name__ + ) + + +class AlertCondition(Enum): + """Enum for alert condition types""" + + ALWAYS = 'Always' + ERROR = 'Error' + SEVERITY_AT_LEAST = 'Severity at least' + SEVERITY_CHANGED = 'Severity changed' + FILTER_COUNT_CHANGED = 'Filter count changed' + FILTER_COUNT_AT_LEAST = 'Filter count at least' + + +def get_alert_condition_from_string( + alert_condition: Optional[str], +) -> Optional[AlertCondition]: + """Convert an alert condition string into a AlertCondition instance""" + if not alert_condition: + return None + + alert_condition = alert_condition.lower() + + if alert_condition == 'error': + return AlertCondition.ERROR + + if alert_condition == 'always': + return AlertCondition.ALWAYS + + if alert_condition == 'filter count changed': + return AlertCondition.FILTER_COUNT_CHANGED + + if alert_condition == 'filter count at least': + return AlertCondition.FILTER_COUNT_AT_LEAST + + if alert_condition == 'severity at least': + return AlertCondition.SEVERITY_AT_LEAST + + if alert_condition == 'severity changed': + return AlertCondition.SEVERITY_CHANGED + + raise InvalidArgument( + argument='alert_condition', + function=get_alert_condition_from_string.__name__, + ) + + +class AlertMethod(Enum): + """Enum for alert method type""" + + SCP = "SCP" + SEND = "Send" + SMB = "SMB" + SNMP = "SNMP" + SYSLOG = "Syslog" + EMAIL = "Email" + START_TASK = "Start Task" + HTTP_GET = "HTTP Get" + SOURCEFIRE_CONNECTOR = "Sourcefire Connector" + VERINICE_CONNECTOR = "verinice Connector" + TIPPINGPOINT = "TippingPoint SMS" + ALEMBA_VFIRE = "Alemba vFire" + + +def get_alert_method_from_string( + alert_method: Optional[str], +) -> Optional[AlertMethod]: + """Convert an alert method string into a AlertCondition instance""" + if not alert_method: + return None + + alert_method = alert_method.upper() + + if alert_method == 'START TASK': + return AlertMethod.START_TASK + + if alert_method == 'HTTP GET': + return AlertMethod.HTTP_GET + + if alert_method == 'SOURCEFIRE CONNECTOR': + return AlertMethod.SOURCEFIRE_CONNECTOR + + if alert_method == 'VERINICE CONNECTOR': + return AlertMethod.VERINICE_CONNECTOR + + if alert_method == 'TIPPINGPOINT SMS': + return AlertMethod.TIPPINGPOINT + + if alert_method == 'ALEMBA VFIRE': + return AlertMethod.ALEMBA_VFIRE + + try: + return AlertMethod[alert_method] + except KeyError: + raise InvalidArgument( + argument='alert_method', + function=get_alert_method_from_string.__name__, + ) from None + + +def _check_event( + event: AlertEvent, condition: AlertCondition, method: AlertMethod +): + if event == AlertEvent.TASK_RUN_STATUS_CHANGED: + if not condition: + raise RequiredArgument( + "condition is required for event {}".format(event.name) + ) + + if not method: + raise RequiredArgument( + "method is required for event {}".format(event.name) + ) + + if condition not in ( + AlertCondition.ALWAYS, + AlertCondition.FILTER_COUNT_CHANGED, + AlertCondition.FILTER_COUNT_AT_LEAST, + AlertCondition.SEVERITY_AT_LEAST, + AlertCondition.SEVERITY_CHANGED, + ): + raise InvalidArgument( + "Invalid condition {} for event {}".format( + condition.name, event.name + ) + ) + elif event in ( + AlertEvent.NEW_SECINFO_ARRIVED, + AlertEvent.UPDATED_SECINFO_ARRIVED, + ): + if not condition: + raise RequiredArgument( + "condition is required for event {}".format(event.name) + ) + + if not method: + raise RequiredArgument( + "method is required for event {}".format(event.name) + ) + + if condition != AlertCondition.ALWAYS: + raise InvalidArgument( + "Invalid condition {} for event {}".format( + condition.name, event.name + ) + ) + if method not in ( + AlertMethod.SCP, + AlertMethod.SEND, + AlertMethod.SMB, + AlertMethod.SNMP, + AlertMethod.SYSLOG, + AlertMethod.EMAIL, + ): + raise InvalidArgument( + "Invalid method {} for event {}".format(method.name, event.name) + ) + elif event in ( + AlertEvent.TICKET_RECEIVED, + AlertEvent.OWNED_TICKET_CHANGED, + AlertEvent.ASSIGNED_TICKET_CHANGED, + ): + if not condition: + raise RequiredArgument( + "condition is required for event {}".format(event.name) + ) + + if not method: + raise RequiredArgument( + "method is required for event {}".format(event.name) + ) + if condition != AlertCondition.ALWAYS: + raise InvalidArgument( + "Invalid condition {} for event {}".format( + condition.name, event.name + ) + ) + if method not in ( + AlertMethod.EMAIL, + AlertMethod.START_TASK, + AlertMethod.SYSLOG, + ): + raise InvalidArgument( + "Invalid method {} for event {}".format(method.name, event.name) + ) + elif event is not None: + raise InvalidArgument('Invalid event "{}"'.format(event.name)) + + +class AlertsMixin: + def clone_alert(self, alert_id: str) -> Any: + """Clone an existing alert + + Arguments: + alert_id: UUID of an existing alert to clone from + + Returns: + The response. See :py:meth:`send_command` for details. + """ + if not alert_id: + raise RequiredArgument( + function=self.clone_alert.__name__, argument='alert_id' + ) + + cmd = XmlCommand("create_alert") + cmd.add_element("copy", alert_id) + return self._send_xml_command(cmd) + + def create_alert( + self, + name: str, + condition: AlertCondition, + event: AlertEvent, + method: AlertMethod, + *, + method_data: Optional[dict] = None, + event_data: Optional[dict] = None, + condition_data: Optional[dict] = None, + filter_id: Optional[int] = None, + comment: Optional[str] = None, + ) -> Any: + """Create a new alert + + Arguments: + name: Name of the new Alert + condition: The condition that must be satisfied for the alert + to occur; if the event is either 'Updated SecInfo arrived' or + 'New SecInfo arrived', condition must be 'Always'. Otherwise, + condition can also be on of 'Severity at least', 'Filter count + changed' or 'Filter count at least'. + event: The event that must happen for the alert to occur, one + of 'Task run status changed', 'Updated SecInfo arrived' or 'New + SecInfo arrived' + method: The method by which the user is alerted, one of 'SCP', + 'Send', 'SMB', 'SNMP', 'Syslog' or 'Email'; if the event is + neither 'Updated SecInfo arrived' nor 'New SecInfo arrived', + method can also be one of 'Start Task', 'HTTP Get', 'Sourcefire + Connector' or 'verinice Connector'. + condition_data: Data that defines the condition + event_data: Data that defines the event + method_data: Data that defines the method + filter_id: Filter to apply when executing alert + comment: Comment for the alert + + Returns: + The response. See :py:meth:`send_command` for details. + """ + if not name: + raise RequiredArgument( + function=self.create_alert.__name__, argument='name' + ) + + if not condition: + raise RequiredArgument( + function=self.create_alert.__name__, argument='condition' + ) + + if not event: + raise RequiredArgument( + function=self.create_alert.__name__, argument='event' + ) + + if not method: + raise RequiredArgument( + function=self.create_alert.__name__, argument='method' + ) + + if not isinstance(condition, AlertCondition): + raise InvalidArgumentType( + function=self.create_alert.__name__, + argument='condition', + arg_type=AlertCondition.__name__, + ) + + if not isinstance(event, AlertEvent): + raise InvalidArgumentType( + function=self.create_alert.__name__, + argument='even', + arg_type=AlertEvent.__name__, + ) + + if not isinstance(method, AlertMethod): + raise InvalidArgumentType( + function=self.create_alert.__name__, + argument='method', + arg_type=AlertMethod.__name__, + ) + + _check_event(event, condition, method) + + cmd = XmlCommand("create_alert") + cmd.add_element("name", name) + + conditions = cmd.add_element("condition", condition.value) + + if condition_data is not None: + for key, value in condition_data.items(): + _data = conditions.add_element("data", value) + _data.add_element("name", key) + + events = cmd.add_element("event", event.value) + + if event_data is not None: + for key, value in event_data.items(): + _data = events.add_element("data", value) + _data.add_element("name", key) + + methods = cmd.add_element("method", method.value) + + if method_data is not None: + for key, value in method_data.items(): + _data = methods.add_element("data", value) + _data.add_element("name", key) + + if filter_id: + cmd.add_element("filter", attrs={"id": filter_id}) + + if comment: + cmd.add_element("comment", comment) + + return self._send_xml_command(cmd) + + def delete_alert( + self, alert_id: str, *, ultimate: Optional[bool] = False + ) -> Any: + """Deletes an existing alert + + Arguments: + alert_id: UUID of the alert to be deleted. + ultimate: Whether to remove entirely, or to the trashcan. + """ + if not alert_id: + raise RequiredArgument( + function=self.delete_alert.__name__, argument='alert_id' + ) + + cmd = XmlCommand("delete_alert") + cmd.set_attribute("alert_id", alert_id) + cmd.set_attribute("ultimate", to_bool(ultimate)) + + return self._send_xml_command(cmd) + + def get_alerts( + self, + *, + filter: Optional[str] = None, + filter_id: Optional[str] = None, + trash: Optional[bool] = None, + tasks: Optional[bool] = None, + ) -> Any: + """Request a list of alerts + + Arguments: + filter: Filter term to use for the query + filter_id: UUID of an existing filter to use for the query + trash: True to request the alerts in the trashcan + tasks: Whether to include the tasks using the alerts + Returns: + The response. See :py:meth:`send_command` for details. + """ + cmd = XmlCommand("get_alerts") + + add_filter(cmd, filter, filter_id) + + if trash is not None: + cmd.set_attribute("trash", to_bool(trash)) + + if tasks is not None: + cmd.set_attribute("tasks", to_bool(tasks)) + + return self._send_xml_command(cmd) + + def get_alert(self, alert_id: str, *, tasks: Optional[bool] = None) -> Any: + """Request a single alert + + Arguments: + alert_id: UUID of an existing alert + + Returns: + The response. See :py:meth:`send_command` for details. + """ + cmd = XmlCommand("get_alerts") + + if not alert_id: + raise RequiredArgument( + function=self.get_alert.__name__, argument='alert_id' + ) + + cmd.set_attribute("alert_id", alert_id) + + if tasks is not None: + cmd.set_attribute("tasks", to_bool(tasks)) + + return self._send_xml_command(cmd) + + def modify_alert( + self, + alert_id: str, + *, + name: Optional[str] = None, + comment: Optional[str] = None, + filter_id: Optional[str] = None, + event: Optional[AlertEvent] = None, + event_data: Optional[dict] = None, + condition: Optional[AlertCondition] = None, + condition_data: Optional[dict] = None, + method: Optional[AlertMethod] = None, + method_data: Optional[dict] = None, + ) -> Any: + """Modifies an existing alert. + + Arguments: + alert_id: UUID of the alert to be modified. + name: Name of the Alert. + condition: The condition that must be satisfied for the alert to + occur. If the event is either 'Updated SecInfo + arrived' or 'New SecInfo arrived', condition must be 'Always'. + Otherwise, condition can also be on of 'Severity at least', + 'Filter count changed' or 'Filter count at least'. + condition_data: Data that defines the condition + event: The event that must happen for the alert to occur, one of + 'Task run status changed', 'Updated SecInfo arrived' or + 'New SecInfo arrived' + event_data: Data that defines the event + method: The method by which the user is alerted, one of 'SCP', + 'Send', 'SMB', 'SNMP', 'Syslog' or 'Email'; + if the event is neither 'Updated SecInfo arrived' nor + 'New SecInfo arrived', method can also be one of 'Start Task', + 'HTTP Get', 'Sourcefire Connector' or 'verinice Connector'. + method_data: Data that defines the method + filter_id: Filter to apply when executing alert + comment: Comment for the alert + + Returns: + The response. See :py:meth:`send_command` for details. + """ + + if not alert_id: + raise RequiredArgument( + function=self.modify_alert.__name__, argument='alert_id' + ) + + cmd = XmlCommand("modify_alert") + cmd.set_attribute("alert_id", str(alert_id)) + + if name: + cmd.add_element("name", name) + + if comment: + cmd.add_element("comment", comment) + + if filter_id: + cmd.add_element("filter", attrs={"id": filter_id}) + + if condition: + if not isinstance(condition, AlertCondition): + raise InvalidArgumentType( + function=self.modify_alert.__name__, + argument='condition', + arg_type=AlertCondition.__name__, + ) + + conditions = cmd.add_element("condition", condition.value) + + if condition_data is not None: + for key, value in condition_data.items(): + _data = conditions.add_element("data", value) + _data.add_element("name", key) + + if method: + if not isinstance(method, AlertMethod): + raise InvalidArgumentType( + function=self.modify_alert.__name__, + argument='method', + arg_type=AlertMethod.__name__, + ) + + methods = cmd.add_element("method", method.value) + + if method_data is not None: + for key, value in method_data.items(): + _data = methods.add_element("data", value) + _data.add_element("name", key) + + if event: + if not isinstance(event, AlertEvent): + raise InvalidArgumentType( + function=self.modify_alert.__name__, + argument='event', + arg_type=AlertEvent.__name__, + ) + + _check_event(event, condition, method) + + events = cmd.add_element("event", event.value) + + if event_data is not None: + for key, value in event_data.items(): + _data = events.add_element("data", value) + _data.add_element("name", key) + + return self._send_xml_command(cmd) + + def test_alert(self, alert_id: str) -> Any: + """Run an alert + + Invoke a test run of an alert + + Arguments: + alert_id: UUID of the alert to be tested + + Returns: + The response. See :py:meth:`send_command` for details. + """ + if not alert_id: + raise InvalidArgument("test_alert requires an alert_id argument") + + cmd = XmlCommand("test_alert") + cmd.set_attribute("alert_id", alert_id) + + return self._send_xml_command(cmd) + + def trigger_alert( + self, + alert_id: str, + report_id: str, + *, + filter: Optional[str] = None, + filter_id: Optional[str] = None, + report_format_id: Optional[Union[str, ReportFormatType]] = None, + delta_report_id: Optional[str] = None, + ) -> Any: + """Run an alert by ignoring its event and conditions + + The alert is triggered to run immediately with the provided filtered + report by ignoring the even and condition settings. + + Arguments: + alert_id: UUID of the alert to be run + report_id: UUID of the report to be provided to the alert + filter: Filter term to use to filter results in the report + filter_id: UUID of filter to use to filter results in the report + report_format_id: UUID of report format to use + or ReportFormatType (enum) + delta_report_id: UUID of an existing report to compare report to. + + Returns: + The response. See :py:meth:`send_command` for details. + """ + if not alert_id: + raise RequiredArgument( + function=self.trigger_alert.__name__, + argument='alert_id argument', + ) + + if not report_id: + raise RequiredArgument( + function=self.trigger_alert.__name__, + argument='report_id argument', + ) + + cmd = XmlCommand("get_reports") + cmd.set_attribute("report_id", report_id) + cmd.set_attribute("alert_id", alert_id) + + if filter: + cmd.set_attribute("filter", filter) + + if filter_id: + cmd.set_attribute("filt_id", filter_id) + + if report_format_id: + if isinstance(report_format_id, ReportFormatType): + report_format_id = report_format_id.value + + cmd.set_attribute("format_id", report_format_id) + + if delta_report_id: + cmd.set_attribute("delta_report_id", delta_report_id) + + return self._send_xml_command(cmd) diff --git a/gvm/protocols/gmpv208/gmpv208.py b/gvm/protocols/gmpv208/gmpv208.py index ca0ed7685..06edcb095 100644 --- a/gvm/protocols/gmpv208/gmpv208.py +++ b/gvm/protocols/gmpv208/gmpv208.py @@ -60,95 +60,6 @@ logger = logging.getLogger(__name__) -# put this into the Alert Entity -def _check_event( - event: AlertEvent, condition: AlertCondition, method: AlertMethod -): - if event == AlertEvent.TASK_RUN_STATUS_CHANGED: - if not condition: - raise RequiredArgument( - "condition is required for event {}".format(event.name) - ) - - if not method: - raise RequiredArgument( - "method is required for event {}".format(event.name) - ) - - if condition not in ( - AlertCondition.ALWAYS, - AlertCondition.FILTER_COUNT_CHANGED, - AlertCondition.FILTER_COUNT_AT_LEAST, - AlertCondition.SEVERITY_AT_LEAST, - AlertCondition.SEVERITY_CHANGED, - ): - raise InvalidArgument( - "Invalid condition {} for event {}".format( - condition.name, event.name - ) - ) - elif event in ( - AlertEvent.NEW_SECINFO_ARRIVED, - AlertEvent.UPDATED_SECINFO_ARRIVED, - ): - if not condition: - raise RequiredArgument( - "condition is required for event {}".format(event.name) - ) - - if not method: - raise RequiredArgument( - "method is required for event {}".format(event.name) - ) - - if condition != AlertCondition.ALWAYS: - raise InvalidArgument( - "Invalid condition {} for event {}".format( - condition.name, event.name - ) - ) - if method not in ( - AlertMethod.SCP, - AlertMethod.SEND, - AlertMethod.SMB, - AlertMethod.SNMP, - AlertMethod.SYSLOG, - AlertMethod.EMAIL, - ): - raise InvalidArgument( - "Invalid method {} for event {}".format(method.name, event.name) - ) - elif event in ( - AlertEvent.TICKET_RECEIVED, - AlertEvent.OWNED_TICKET_CHANGED, - AlertEvent.ASSIGNED_TICKET_CHANGED, - ): - if not condition: - raise RequiredArgument( - "condition is required for event {}".format(event.name) - ) - - if not method: - raise RequiredArgument( - "method is required for event {}".format(event.name) - ) - if condition != AlertCondition.ALWAYS: - raise InvalidArgument( - "Invalid condition {} for event {}".format( - condition.name, event.name - ) - ) - if method not in ( - AlertMethod.EMAIL, - AlertMethod.START_TASK, - AlertMethod.SYSLOG, - ): - raise InvalidArgument( - "Invalid method {} for event {}".format(method.name, event.name) - ) - elif event is not None: - raise InvalidArgument('Invalid event "{}"'.format(event.name)) - class GmpV208Mixin(GvmProtocol): """Python interface for Greenbone Management Protocol @@ -233,120 +144,6 @@ def authenticate(self, username: str, password: str) -> Any: return self._transform(response) - def create_alert( - self, - name: str, - condition: AlertCondition, - event: AlertEvent, - method: AlertMethod, - *, - method_data: Optional[dict] = None, - event_data: Optional[dict] = None, - condition_data: Optional[dict] = None, - filter_id: Optional[int] = None, - comment: Optional[str] = None, - ) -> Any: - """Create a new alert - - Arguments: - name: Name of the new Alert - condition: The condition that must be satisfied for the alert - to occur; if the event is either 'Updated SecInfo arrived' or - 'New SecInfo arrived', condition must be 'Always'. Otherwise, - condition can also be on of 'Severity at least', 'Filter count - changed' or 'Filter count at least'. - event: The event that must happen for the alert to occur, one - of 'Task run status changed', 'Updated SecInfo arrived' or 'New - SecInfo arrived' - method: The method by which the user is alerted, one of 'SCP', - 'Send', 'SMB', 'SNMP', 'Syslog' or 'Email'; if the event is - neither 'Updated SecInfo arrived' nor 'New SecInfo arrived', - method can also be one of 'Start Task', 'HTTP Get', 'Sourcefire - Connector' or 'verinice Connector'. - condition_data: Data that defines the condition - event_data: Data that defines the event - method_data: Data that defines the method - filter_id: Filter to apply when executing alert - comment: Comment for the alert - - Returns: - The response. See :py:meth:`send_command` for details. - """ - if not name: - raise RequiredArgument( - function=self.create_alert.__name__, argument='name' - ) - - if not condition: - raise RequiredArgument( - function=self.create_alert.__name__, argument='condition' - ) - - if not event: - raise RequiredArgument( - function=self.create_alert.__name__, argument='event' - ) - - if not method: - raise RequiredArgument( - function=self.create_alert.__name__, argument='method' - ) - - if not isinstance(condition, AlertCondition): - raise InvalidArgumentType( - function=self.create_alert.__name__, - argument='condition', - arg_type=AlertCondition.__name__, - ) - - if not isinstance(event, AlertEvent): - raise InvalidArgumentType( - function=self.create_alert.__name__, - argument='even', - arg_type=AlertEvent.__name__, - ) - - if not isinstance(method, AlertMethod): - raise InvalidArgumentType( - function=self.create_alert.__name__, - argument='method', - arg_type=AlertMethod.__name__, - ) - - _check_event(event, condition, method) - - cmd = XmlCommand("create_alert") - cmd.add_element("name", name) - - conditions = cmd.add_element("condition", condition.value) - - if condition_data is not None: - for key, value in condition_data.items(): - _data = conditions.add_element("data", value) - _data.add_element("name", key) - - events = cmd.add_element("event", event.value) - - if event_data is not None: - for key, value in event_data.items(): - _data = events.add_element("data", value) - _data.add_element("name", key) - - methods = cmd.add_element("method", method.value) - - if method_data is not None: - for key, value in method_data.items(): - _data = methods.add_element("data", value) - _data.add_element("name", key) - - if filter_id: - cmd.add_element("filter", attrs={"id": filter_id}) - - if comment: - cmd.add_element("comment", comment) - - return self._send_xml_command(cmd) - def create_audit( self, name: str, @@ -908,114 +705,6 @@ def get_tls_certificate(self, tls_certificate_id: str) -> Any: return self._send_xml_command(cmd) - def modify_alert( - self, - alert_id: str, - *, - name: Optional[str] = None, - comment: Optional[str] = None, - filter_id: Optional[str] = None, - event: Optional[AlertEvent] = None, - event_data: Optional[dict] = None, - condition: Optional[AlertCondition] = None, - condition_data: Optional[dict] = None, - method: Optional[AlertMethod] = None, - method_data: Optional[dict] = None, - ) -> Any: - """Modifies an existing alert. - - Arguments: - alert_id: UUID of the alert to be modified. - name: Name of the Alert. - condition: The condition that must be satisfied for the alert to - occur. If the event is either 'Updated SecInfo - arrived' or 'New SecInfo arrived', condition must be 'Always'. - Otherwise, condition can also be on of 'Severity at least', - 'Filter count changed' or 'Filter count at least'. - condition_data: Data that defines the condition - event: The event that must happen for the alert to occur, one of - 'Task run status changed', 'Updated SecInfo arrived' or - 'New SecInfo arrived' - event_data: Data that defines the event - method: The method by which the user is alerted, one of 'SCP', - 'Send', 'SMB', 'SNMP', 'Syslog' or 'Email'; - if the event is neither 'Updated SecInfo arrived' nor - 'New SecInfo arrived', method can also be one of 'Start Task', - 'HTTP Get', 'Sourcefire Connector' or 'verinice Connector'. - method_data: Data that defines the method - filter_id: Filter to apply when executing alert - comment: Comment for the alert - - Returns: - The response. See :py:meth:`send_command` for details. - """ - - if not alert_id: - raise RequiredArgument( - function=self.modify_alert.__name__, argument='alert_id' - ) - - cmd = XmlCommand("modify_alert") - cmd.set_attribute("alert_id", str(alert_id)) - - if name: - cmd.add_element("name", name) - - if comment: - cmd.add_element("comment", comment) - - if filter_id: - cmd.add_element("filter", attrs={"id": filter_id}) - - if condition: - if not isinstance(condition, AlertCondition): - raise InvalidArgumentType( - function=self.modify_alert.__name__, - argument='condition', - arg_type=AlertCondition.__name__, - ) - - conditions = cmd.add_element("condition", condition.value) - - if condition_data is not None: - for key, value in condition_data.items(): - _data = conditions.add_element("data", value) - _data.add_element("name", key) - - if method: - if not isinstance(method, AlertMethod): - raise InvalidArgumentType( - function=self.modify_alert.__name__, - argument='method', - arg_type=AlertMethod.__name__, - ) - - methods = cmd.add_element("method", method.value) - - if method_data is not None: - for key, value in method_data.items(): - _data = methods.add_element("data", value) - _data.add_element("name", key) - - if event: - if not isinstance(event, AlertEvent): - raise InvalidArgumentType( - function=self.modify_alert.__name__, - argument='event', - arg_type=AlertEvent.__name__, - ) - - _check_event(event, condition, method) - - events = cmd.add_element("event", event.value) - - if event_data is not None: - for key, value in event_data.items(): - _data = events.add_element("data", value) - _data.add_element("name", key) - - return self._send_xml_command(cmd) - def modify_audit( self, audit_id: str, @@ -1385,24 +1074,6 @@ def modify_tls_certificate( return self._send_xml_command(cmd) - def clone_alert(self, alert_id: str) -> Any: - """Clone an existing alert - - Arguments: - alert_id: UUID of an existing alert to clone from - - Returns: - The response. See :py:meth:`send_command` for details. - """ - if not alert_id: - raise RequiredArgument( - function=self.clone_alert.__name__, argument='alert_id' - ) - - cmd = XmlCommand("create_alert") - cmd.add_element("copy", alert_id) - return self._send_xml_command(cmd) - def clone_ticket(self, ticket_id: str) -> Any: """Clone an existing ticket @@ -3360,26 +3031,6 @@ def clone_user(self, user_id: str) -> Any: cmd.add_element("copy", user_id) return self._send_xml_command(cmd) - def delete_alert( - self, alert_id: str, *, ultimate: Optional[bool] = False - ) -> Any: - """Deletes an existing alert - - Arguments: - alert_id: UUID of the alert to be deleted. - ultimate: Whether to remove entirely, or to the trashcan. - """ - if not alert_id: - raise RequiredArgument( - function=self.delete_alert.__name__, argument='alert_id' - ) - - cmd = XmlCommand("delete_alert") - cmd.set_attribute("alert_id", alert_id) - cmd.set_attribute("ultimate", to_bool(ultimate)) - - return self._send_xml_command(cmd) - def delete_asset( self, *, asset_id: Optional[str] = None, report_id: Optional[str] = None ) -> Any: @@ -3678,59 +3329,6 @@ def empty_trashcan(self) -> Any: """ return self._send_xml_command(XmlCommand("empty_trashcan")) - def get_alerts( - self, - *, - filter: Optional[str] = None, - filter_id: Optional[str] = None, - trash: Optional[bool] = None, - tasks: Optional[bool] = None, - ) -> Any: - """Request a list of alerts - - Arguments: - filter: Filter term to use for the query - filter_id: UUID of an existing filter to use for the query - trash: True to request the alerts in the trashcan - tasks: Whether to include the tasks using the alerts - Returns: - The response. See :py:meth:`send_command` for details. - """ - cmd = XmlCommand("get_alerts") - - add_filter(cmd, filter, filter_id) - - if trash is not None: - cmd.set_attribute("trash", to_bool(trash)) - - if tasks is not None: - cmd.set_attribute("tasks", to_bool(tasks)) - - return self._send_xml_command(cmd) - - def get_alert(self, alert_id: str, *, tasks: Optional[bool] = None) -> Any: - """Request a single alert - - Arguments: - alert_id: UUID of an existing alert - - Returns: - The response. See :py:meth:`send_command` for details. - """ - cmd = XmlCommand("get_alerts") - - if not alert_id: - raise RequiredArgument( - function=self.get_alert.__name__, argument='alert_id' - ) - - cmd.set_attribute("alert_id", alert_id) - - if tasks is not None: - cmd.set_attribute("tasks", to_bool(tasks)) - - return self._send_xml_command(cmd) - def get_assets( self, asset_type: AssetType, @@ -5281,85 +4879,6 @@ def sync_scap(self) -> Any: """ return self._send_xml_command(XmlCommand("sync_scap")) - def test_alert(self, alert_id: str) -> Any: - """Run an alert - - Invoke a test run of an alert - - Arguments: - alert_id: UUID of the alert to be tested - - Returns: - The response. See :py:meth:`send_command` for details. - """ - if not alert_id: - raise InvalidArgument("test_alert requires an alert_id argument") - - cmd = XmlCommand("test_alert") - cmd.set_attribute("alert_id", alert_id) - - return self._send_xml_command(cmd) - - def trigger_alert( - self, - alert_id: str, - report_id: str, - *, - filter: Optional[str] = None, - filter_id: Optional[str] = None, - report_format_id: Optional[Union[str, ReportFormatType]] = None, - delta_report_id: Optional[str] = None, - ) -> Any: - """Run an alert by ignoring its event and conditions - - The alert is triggered to run immediately with the provided filtered - report by ignoring the even and condition settings. - - Arguments: - alert_id: UUID of the alert to be run - report_id: UUID of the report to be provided to the alert - filter: Filter term to use to filter results in the report - filter_id: UUID of filter to use to filter results in the report - report_format_id: UUID of report format to use - or ReportFormatType (enum) - delta_report_id: UUID of an existing report to compare report to. - - Returns: - The response. See :py:meth:`send_command` for details. - """ - if not alert_id: - raise RequiredArgument( - function=self.trigger_alert.__name__, - argument='alert_id argument', - ) - - if not report_id: - raise RequiredArgument( - function=self.trigger_alert.__name__, - argument='report_id argument', - ) - - cmd = XmlCommand("get_reports") - cmd.set_attribute("report_id", report_id) - cmd.set_attribute("alert_id", alert_id) - - if filter: - cmd.set_attribute("filter", filter) - - if filter_id: - cmd.set_attribute("filt_id", filter_id) - - if report_format_id: - if isinstance(report_format_id, ReportFormatType): - report_format_id = report_format_id.value - - cmd.set_attribute("format_id", report_format_id) - - if delta_report_id: - cmd.set_attribute("delta_report_id", delta_report_id) - - return self._send_xml_command(cmd) - def verify_report_format( self, report_format_id: Union[str, ReportFormatType] ) -> Any: diff --git a/gvm/protocols/gmpv208/types.py b/gvm/protocols/gmpv208/types.py index f4357142d..ac2160f78 100644 --- a/gvm/protocols/gmpv208/types.py +++ b/gvm/protocols/gmpv208/types.py @@ -26,9 +26,6 @@ __all__ = [ "AggregateStatistic", - "AlertCondition", - "AlertEvent", - "AlertMethod", "AssetType", "CredentialFormat", "CredentialType", @@ -45,9 +42,6 @@ "TimeUnit", "UserAuthType", "get_aggregate_statistic_from_string", - "get_alert_condition_from_string", - "get_alert_event_from_string", - "get_alert_method_from_string", "get_asset_type_from_string", "get_credential_format_from_string", "get_credential_type_from_string", @@ -289,146 +283,6 @@ def get_aggregate_statistic_from_string( ) from None -class AlertEvent(Enum): - """Enum for alert event types""" - - TASK_RUN_STATUS_CHANGED = 'Task run status changed' - UPDATED_SECINFO_ARRIVED = 'Updated SecInfo arrived' - NEW_SECINFO_ARRIVED = 'New SecInfo arrived' - TICKET_RECEIVED = 'Ticket received' - ASSIGNED_TICKET_CHANGED = 'Assigned ticket changed' - OWNED_TICKET_CHANGED = 'Owned ticket changed' - - -def get_alert_event_from_string( - alert_event: Optional[str], -) -> Optional[AlertEvent]: - """Convert an alert event string into a AlertEvent instance""" - if not alert_event: - return None - - alert_event = alert_event.lower() - - if alert_event == 'task run status changed': - return AlertEvent.TASK_RUN_STATUS_CHANGED - - if alert_event == 'updated secinfo arrived': - return AlertEvent.UPDATED_SECINFO_ARRIVED - - if alert_event == 'new secinfo arrived': - return AlertEvent.NEW_SECINFO_ARRIVED - - if alert_event == 'ticket received': - return AlertEvent.TICKET_RECEIVED - - if alert_event == 'assigned ticket changed': - return AlertEvent.ASSIGNED_TICKET_CHANGED - - if alert_event == 'owned ticket changed': - return AlertEvent.OWNED_TICKET_CHANGED - - raise InvalidArgument( - argument='alert_event', function=get_alert_event_from_string.__name__ - ) - - -class AlertCondition(Enum): - """Enum for alert condition types""" - - ALWAYS = 'Always' - ERROR = 'Error' - SEVERITY_AT_LEAST = 'Severity at least' - SEVERITY_CHANGED = 'Severity changed' - FILTER_COUNT_CHANGED = 'Filter count changed' - FILTER_COUNT_AT_LEAST = 'Filter count at least' - - -def get_alert_condition_from_string( - alert_condition: Optional[str], -) -> Optional[AlertCondition]: - """Convert an alert condition string into a AlertCondition instance""" - if not alert_condition: - return None - - alert_condition = alert_condition.lower() - - if alert_condition == 'error': - return AlertCondition.ERROR - - if alert_condition == 'always': - return AlertCondition.ALWAYS - - if alert_condition == 'filter count changed': - return AlertCondition.FILTER_COUNT_CHANGED - - if alert_condition == 'filter count at least': - return AlertCondition.FILTER_COUNT_AT_LEAST - - if alert_condition == 'severity at least': - return AlertCondition.SEVERITY_AT_LEAST - - if alert_condition == 'severity changed': - return AlertCondition.SEVERITY_CHANGED - - raise InvalidArgument( - argument='alert_condition', - function=get_alert_condition_from_string.__name__, - ) - - -class AlertMethod(Enum): - """Enum for alert method type""" - - SCP = "SCP" - SEND = "Send" - SMB = "SMB" - SNMP = "SNMP" - SYSLOG = "Syslog" - EMAIL = "Email" - START_TASK = "Start Task" - HTTP_GET = "HTTP Get" - SOURCEFIRE_CONNECTOR = "Sourcefire Connector" - VERINICE_CONNECTOR = "verinice Connector" - TIPPINGPOINT = "TippingPoint SMS" - ALEMBA_VFIRE = "Alemba vFire" - - -def get_alert_method_from_string( - alert_method: Optional[str], -) -> Optional[AlertMethod]: - """Convert an alert method string into a AlertCondition instance""" - if not alert_method: - return None - - alert_method = alert_method.upper() - - if alert_method == 'START TASK': - return AlertMethod.START_TASK - - if alert_method == 'HTTP GET': - return AlertMethod.HTTP_GET - - if alert_method == 'SOURCEFIRE CONNECTOR': - return AlertMethod.SOURCEFIRE_CONNECTOR - - if alert_method == 'VERINICE CONNECTOR': - return AlertMethod.VERINICE_CONNECTOR - - if alert_method == 'TIPPINGPOINT SMS': - return AlertMethod.TIPPINGPOINT - - if alert_method == 'ALEMBA VFIRE': - return AlertMethod.ALEMBA_VFIRE - - try: - return AlertMethod[alert_method] - except KeyError: - raise InvalidArgument( - argument='alert_method', - function=get_alert_method_from_string.__name__, - ) from None - - class ScannerType(Enum): """Enum for scanner type""" From 5f2022c592f38e312bb52063dac1ae4d4845b153 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaspar=20L=C3=B6chte?= Date: Thu, 13 May 2021 14:25:47 +0200 Subject: [PATCH 02/12] Add the Mixin and Types to 208 and 214 --- gvm/protocols/gmpv208/__init__.py | 10 ++++++++++ gvm/protocols/gmpv214/__init__.py | 10 ++++++++++ gvm/protocols/gmpv214/types.py | 12 ------------ 3 files changed, 20 insertions(+), 12 deletions(-) diff --git a/gvm/protocols/gmpv208/__init__.py b/gvm/protocols/gmpv208/__init__.py index f0d54e0c2..645da2899 100644 --- a/gvm/protocols/gmpv208/__init__.py +++ b/gvm/protocols/gmpv208/__init__.py @@ -28,6 +28,15 @@ from typing import Any, Callable, Optional from gvm.protocols.gmpv208.gmpv208 import GmpV208Mixin +from gvm.protocols.gmpv208.entities.alerts import ( + AlertCondition, + AlertEvent, + AlertMethod, + AlertsMixin, + get_alert_condition_from_string, + get_alert_event_from_string, + get_alert_method_from_string, +) from gvm.protocols.gmpv208.entities.port_lists import ( get_port_range_type_from_string, PortListMixin, @@ -67,6 +76,7 @@ class Gmp( GmpV208Mixin, + AlertsMixin, NotesMixin, OverridesMixin, PortListMixin, diff --git a/gvm/protocols/gmpv214/__init__.py b/gvm/protocols/gmpv214/__init__.py index ec9e4f88f..5024627d0 100644 --- a/gvm/protocols/gmpv214/__init__.py +++ b/gvm/protocols/gmpv214/__init__.py @@ -28,6 +28,15 @@ from typing import Any, Callable, Optional +from gvm.protocols.gmpv208.entities.alerts import ( + AlertCondition, + AlertEvent, + AlertMethod, + AlertsMixin, + get_alert_condition_from_string, + get_alert_event_from_string, + get_alert_method_from_string, +) from gvm.protocols.gmpv208.entities.port_lists import ( PortListMixin, PortRangeType, @@ -71,6 +80,7 @@ class Gmp( GmpV214Mixin, GmpV208Mixin, + AlertsMixin, PortListMixin, NotesMixin, OverridesMixin, diff --git a/gvm/protocols/gmpv214/types.py b/gvm/protocols/gmpv214/types.py index d200eff67..1463dae3e 100644 --- a/gvm/protocols/gmpv214/types.py +++ b/gvm/protocols/gmpv214/types.py @@ -23,9 +23,6 @@ from gvm.protocols.gmpv208.types import ( AggregateStatistic, - AlertCondition, - AlertEvent, - AlertMethod, AssetType, CredentialFormat, CredentialType, @@ -41,9 +38,6 @@ TimeUnit, UserAuthType, get_aggregate_statistic_from_string, - get_alert_condition_from_string, - get_alert_event_from_string, - get_alert_method_from_string, get_asset_type_from_string, get_credential_format_from_string, get_credential_type_from_string, @@ -63,9 +57,6 @@ __all__ = [ "AggregateStatistic", - "AlertCondition", - "AlertEvent", - "AlertMethod", "AssetType", "CredentialFormat", "CredentialType", @@ -83,9 +74,6 @@ "TimeUnit", "UserAuthType", "get_aggregate_statistic_from_string", - "get_alert_condition_from_string", - "get_alert_event_from_string", - "get_alert_method_from_string", "get_asset_type_from_string", "get_credential_format_from_string", "get_credential_type_from_string", From 42ae16ab74a73e2cc31c521345bf0a03fbdb5b48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaspar=20L=C3=B6chte?= Date: Fri, 14 May 2021 09:42:13 +0200 Subject: [PATCH 03/12] Moved alert tests to dir --- .../gmpv208/entities/alerts/__init__.py | 26 +++++++++++++++++++ .../alerts}/test_clone_alert.py | 2 +- .../alerts}/test_create_alert.py | 2 +- .../alerts}/test_delete_alert.py | 2 +- .../alerts}/test_get_alert.py | 2 +- .../alerts}/test_get_alerts.py | 2 +- .../alerts}/test_modify_alert.py | 2 +- .../alerts}/test_test_alert.py | 2 +- .../alerts}/test_trigger_alert.py | 2 +- tests/protocols/gmpv208/testcmds/__init__.py | 8 ------ 10 files changed, 34 insertions(+), 16 deletions(-) create mode 100644 tests/protocols/gmpv208/entities/alerts/__init__.py rename tests/protocols/gmpv208/{testcmds => entities/alerts}/test_clone_alert.py (97%) rename tests/protocols/gmpv208/{testcmds => entities/alerts}/test_create_alert.py (99%) rename tests/protocols/gmpv208/{testcmds => entities/alerts}/test_delete_alert.py (97%) rename tests/protocols/gmpv208/{testcmds => entities/alerts}/test_get_alert.py (98%) rename tests/protocols/gmpv208/{testcmds => entities/alerts}/test_get_alerts.py (98%) rename tests/protocols/gmpv208/{testcmds => entities/alerts}/test_modify_alert.py (99%) rename tests/protocols/gmpv208/{testcmds => entities/alerts}/test_test_alert.py (97%) rename tests/protocols/gmpv208/{testcmds => entities/alerts}/test_trigger_alert.py (99%) diff --git a/tests/protocols/gmpv208/entities/alerts/__init__.py b/tests/protocols/gmpv208/entities/alerts/__init__.py new file mode 100644 index 000000000..0fceedee8 --- /dev/null +++ b/tests/protocols/gmpv208/entities/alerts/__init__.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- +# Copyright (C) 2021 Greenbone Networks GmbH +# +# SPDX-License-Identifier: GPL-3.0-or-later +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +from .test_clone_alert import GmpCloneAlertTestMixin +from .test_create_alert import GmpCreateAlertTestMixin +from .test_delete_alert import GmpDeleteAlertTestMixin +from .test_get_alert import GmpGetAlertTestMixin +from .test_get_alerts import GmpGetAlertsTestMixin +from .test_modify_alert import GmpModifyAlertTestMixin +from .test_test_alert import GmpTestAlertTestMixin +from .test_trigger_alert import GmpTriggerAlertTestMixin diff --git a/tests/protocols/gmpv208/testcmds/test_clone_alert.py b/tests/protocols/gmpv208/entities/alerts/test_clone_alert.py similarity index 97% rename from tests/protocols/gmpv208/testcmds/test_clone_alert.py rename to tests/protocols/gmpv208/entities/alerts/test_clone_alert.py index 51faff593..97aa64296 100644 --- a/tests/protocols/gmpv208/testcmds/test_clone_alert.py +++ b/tests/protocols/gmpv208/entities/alerts/test_clone_alert.py @@ -19,7 +19,7 @@ from gvm.errors import RequiredArgument -class GmpCloneAlertTestCase: +class GmpCloneAlertTestMixin: def test_clone(self): self.gmp.clone_alert('a1') diff --git a/tests/protocols/gmpv208/testcmds/test_create_alert.py b/tests/protocols/gmpv208/entities/alerts/test_create_alert.py similarity index 99% rename from tests/protocols/gmpv208/testcmds/test_create_alert.py rename to tests/protocols/gmpv208/entities/alerts/test_create_alert.py index 97a79f871..66ee6eaec 100644 --- a/tests/protocols/gmpv208/testcmds/test_create_alert.py +++ b/tests/protocols/gmpv208/entities/alerts/test_create_alert.py @@ -21,7 +21,7 @@ from gvm.protocols.gmpv208 import AlertCondition, AlertEvent, AlertMethod -class GmpCreateAlertTestCase: +class GmpCreateAlertTestMixin: def test_missing_name(self): with self.assertRaises(RequiredArgument): self.gmp.create_alert( diff --git a/tests/protocols/gmpv208/testcmds/test_delete_alert.py b/tests/protocols/gmpv208/entities/alerts/test_delete_alert.py similarity index 97% rename from tests/protocols/gmpv208/testcmds/test_delete_alert.py rename to tests/protocols/gmpv208/entities/alerts/test_delete_alert.py index 7d8320c32..494d02194 100644 --- a/tests/protocols/gmpv208/testcmds/test_delete_alert.py +++ b/tests/protocols/gmpv208/entities/alerts/test_delete_alert.py @@ -19,7 +19,7 @@ from gvm.errors import RequiredArgument -class GmpDeleteAlertTestCase: +class GmpDeleteAlertTestMixin: def test_delete(self): self.gmp.delete_alert('a1') diff --git a/tests/protocols/gmpv208/testcmds/test_get_alert.py b/tests/protocols/gmpv208/entities/alerts/test_get_alert.py similarity index 98% rename from tests/protocols/gmpv208/testcmds/test_get_alert.py rename to tests/protocols/gmpv208/entities/alerts/test_get_alert.py index 98bd8211b..1103f88f5 100644 --- a/tests/protocols/gmpv208/testcmds/test_get_alert.py +++ b/tests/protocols/gmpv208/entities/alerts/test_get_alert.py @@ -19,7 +19,7 @@ from gvm.errors import RequiredArgument -class GmpGetAlertTestCase: +class GmpGetAlertTestMixin: def test_get_alert(self): self.gmp.get_alert('a1') diff --git a/tests/protocols/gmpv208/testcmds/test_get_alerts.py b/tests/protocols/gmpv208/entities/alerts/test_get_alerts.py similarity index 98% rename from tests/protocols/gmpv208/testcmds/test_get_alerts.py rename to tests/protocols/gmpv208/entities/alerts/test_get_alerts.py index 3ff0937ff..cbe31f14a 100644 --- a/tests/protocols/gmpv208/testcmds/test_get_alerts.py +++ b/tests/protocols/gmpv208/entities/alerts/test_get_alerts.py @@ -17,7 +17,7 @@ # along with this program. If not, see . -class GmpGetAlertsTestCase: +class GmpGetAlertsTestMixin: def test_get_alerts(self): self.gmp.get_alerts() diff --git a/tests/protocols/gmpv208/testcmds/test_modify_alert.py b/tests/protocols/gmpv208/entities/alerts/test_modify_alert.py similarity index 99% rename from tests/protocols/gmpv208/testcmds/test_modify_alert.py rename to tests/protocols/gmpv208/entities/alerts/test_modify_alert.py index 2c8033277..e2f639f2e 100644 --- a/tests/protocols/gmpv208/testcmds/test_modify_alert.py +++ b/tests/protocols/gmpv208/entities/alerts/test_modify_alert.py @@ -21,7 +21,7 @@ from gvm.protocols.gmpv208 import AlertCondition, AlertEvent, AlertMethod -class GmpModifyAlertTestCase: +class GmpModifyAlertTestMixin: def test_modify_alert(self): self.gmp.modify_alert(alert_id='a1') diff --git a/tests/protocols/gmpv208/testcmds/test_test_alert.py b/tests/protocols/gmpv208/entities/alerts/test_test_alert.py similarity index 97% rename from tests/protocols/gmpv208/testcmds/test_test_alert.py rename to tests/protocols/gmpv208/entities/alerts/test_test_alert.py index 6cdca50ef..8ec1b8bc3 100644 --- a/tests/protocols/gmpv208/testcmds/test_test_alert.py +++ b/tests/protocols/gmpv208/entities/alerts/test_test_alert.py @@ -19,7 +19,7 @@ from gvm.errors import GvmError -class GmpTestAlertTestCase: +class GmpTestAlertTestMixin: def test_test_alert(self): self.gmp.test_alert('a1') diff --git a/tests/protocols/gmpv208/testcmds/test_trigger_alert.py b/tests/protocols/gmpv208/entities/alerts/test_trigger_alert.py similarity index 99% rename from tests/protocols/gmpv208/testcmds/test_trigger_alert.py rename to tests/protocols/gmpv208/entities/alerts/test_trigger_alert.py index 2053bab9a..f1022db66 100644 --- a/tests/protocols/gmpv208/testcmds/test_trigger_alert.py +++ b/tests/protocols/gmpv208/entities/alerts/test_trigger_alert.py @@ -23,7 +23,7 @@ ) -class GmpTriggerAlertTestCase: +class GmpTriggerAlertTestMixin: def test_trigger_alert_without_alert_id(self): with self.assertRaises(RequiredArgument): self.gmp.trigger_alert(alert_id=None, report_id='r1') diff --git a/tests/protocols/gmpv208/testcmds/__init__.py b/tests/protocols/gmpv208/testcmds/__init__.py index ca5fdfa98..6540ab784 100644 --- a/tests/protocols/gmpv208/testcmds/__init__.py +++ b/tests/protocols/gmpv208/testcmds/__init__.py @@ -32,7 +32,6 @@ from .test_clone_policy import GmpClonePolicyTestCase from .test_clone_tls_certificate import GmpCloneTLSCertificateTestCase from .test_create_audit import GmpCreateAuditCommandTestCase -from .test_create_alert import GmpCreateAlertTestCase from .test_create_config import GmpCreateConfigTestCase from .test_create_config_from_osp_scanner import ( GmpCreateConfigFromOSPScannerTestCase, @@ -54,7 +53,6 @@ from .test_get_tls_certificate import GmpGetTlsCertificateTestCase from .test_get_tls_certificates import GmpGetTLSCertificatesTestCase from .test_modify_credential import GmpModifyCredentialTestCase -from .test_modify_alert import GmpModifyAlertTestCase from .test_modify_audit import GmpModifyAuditCommandTestCase from .test_modify_policy_set_comment import GmpModifyPolicySetCommentTestCase from .test_modify_policy_set_family_selection import ( @@ -87,7 +85,6 @@ from .test_modify_schedule import GmpModifyScheduleTestCase from .test_protocol_version import GmpProtocolVersionTestCase from .test_authenticate import GmpAuthenticateTestCase -from .test_clone_alert import GmpCloneAlertTestCase from .test_clone_report_format import GmpCloneReportFormatTestCase from .test_clone_credential import GmpCloneCredentialTestCase from .test_clone_filter import GmpCloneFilterTestCase @@ -102,7 +99,6 @@ from .test_create_host import GmpCreateHostTestCase from .test_create_role import GmpCreateRoleTestCase from .test_create_user import GmpCreateUserTestCase -from .test_delete_alert import GmpDeleteAlertTestCase from .test_delete_asset import GmpDeleteAssetTestCase from .test_delete_credential import GmpDeleteCredentialTestCase from .test_delete_filter import GmpDeleteFilterTestCase @@ -116,8 +112,6 @@ from .test_delete_user import GmpDeleteUserTestCase from .test_describe_auth import GmpDescribeAuthCommandTestCase from .test_empty_trashcan import GmpEmptyTrashcanCommandTestCase -from .test_get_alert import GmpGetAlertTestCase -from .test_get_alerts import GmpGetAlertsTestCase from .test_get_asset import GmpGetAssetTestCase from .test_get_assets import GmpGetAssetsTestCase from .test_get_credential import GmpGetCredentialTestCase @@ -176,8 +170,6 @@ from .test_sync_config import GmpSyncConfigCommandTestCase from .test_sync_feed import GmpSyncFeedCommandTestCase from .test_sync_scap import GmpSyncScapCommandTestCase -from .test_test_alert import GmpTestAlertTestCase -from .test_trigger_alert import GmpTriggerAlertTestCase from .test_verify_report_format import GmpVerifyReportFormatTestCase from .test_verify_scanner import GmpVerifyScannerTestCase from .test_with_statement import GmpWithStatementTestCase From b9b32af115fb8e9f81bb527ebbd98a6c71acc26a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaspar=20L=C3=B6chte?= Date: Fri, 14 May 2021 09:42:38 +0200 Subject: [PATCH 04/12] Add the new test cases --- .../protocols/gmpv208/entities/test_alerts.py | 61 +++++++++++++++++++ .../protocols/gmpv214/entities/test_alerts.py | 61 +++++++++++++++++++ 2 files changed, 122 insertions(+) create mode 100644 tests/protocols/gmpv208/entities/test_alerts.py create mode 100644 tests/protocols/gmpv214/entities/test_alerts.py diff --git a/tests/protocols/gmpv208/entities/test_alerts.py b/tests/protocols/gmpv208/entities/test_alerts.py new file mode 100644 index 000000000..48cfcbb6e --- /dev/null +++ b/tests/protocols/gmpv208/entities/test_alerts.py @@ -0,0 +1,61 @@ +# -*- coding: utf-8 -*- +# Copyright (C) 2021 Greenbone Networks GmbH +# +# SPDX-License-Identifier: GPL-3.0-or-later +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +from ...gmpv208 import Gmpv208TestCase +from .alerts import ( + GmpCloneAlertTestMixin, + GmpCreateAlertTestMixin, + GmpDeleteAlertTestMixin, + GmpGetAlertsTestMixin, + GmpGetAlertTestMixin, + GmpModifyAlertTestMixin, + GmpTestAlertTestMixin, + GmpTriggerAlertTestMixin, +) + + +class Gmpv208CloneAlertTestCase(GmpCloneAlertTestMixin, Gmpv208TestCase): + pass + + +class Gmpv208CreateAlertTestCase(GmpCreateAlertTestMixin, Gmpv208TestCase): + pass + + +class Gmpv208DeleteAlertTestCase(GmpDeleteAlertTestMixin, Gmpv208TestCase): + pass + + +class Gmpv208GetAlertTestCase(GmpGetAlertTestMixin, Gmpv208TestCase): + pass + + +class Gmpv208GetAlertsTestCase(GmpGetAlertsTestMixin, Gmpv208TestCase): + pass + + +class Gmpv208ModifyAlertTestCase(GmpModifyAlertTestMixin, Gmpv208TestCase): + pass + + +class Gmpv208TestAlertTestCase(GmpTestAlertTestMixin, Gmpv208TestCase): + pass + + +class Gmpv208TriggerAlertTestCase(GmpTriggerAlertTestMixin, Gmpv208TestCase): + pass diff --git a/tests/protocols/gmpv214/entities/test_alerts.py b/tests/protocols/gmpv214/entities/test_alerts.py new file mode 100644 index 000000000..db4291697 --- /dev/null +++ b/tests/protocols/gmpv214/entities/test_alerts.py @@ -0,0 +1,61 @@ +# -*- coding: utf-8 -*- +# Copyright (C) 2021 Greenbone Networks GmbH +# +# SPDX-License-Identifier: GPL-3.0-or-later +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +from ...gmpv214 import Gmpv214TestCase +from ...gmpv208.entities.alerts import ( + GmpCloneAlertTestMixin, + GmpCreateAlertTestMixin, + GmpDeleteAlertTestMixin, + GmpGetAlertsTestMixin, + GmpGetAlertTestMixin, + GmpModifyAlertTestMixin, + GmpTestAlertTestMixin, + GmpTriggerAlertTestMixin, +) + + +class Gmpv214CloneAlertTestCase(GmpCloneAlertTestMixin, Gmpv214TestCase): + pass + + +class Gmpv214CreateAlertTestCase(GmpCreateAlertTestMixin, Gmpv214TestCase): + pass + + +class Gmpv214DeleteAlertTestCase(GmpDeleteAlertTestMixin, Gmpv214TestCase): + pass + + +class Gmpv214GetAlertTestCase(GmpGetAlertTestMixin, Gmpv214TestCase): + pass + + +class Gmpv214GetAlertsTestCase(GmpGetAlertsTestMixin, Gmpv214TestCase): + pass + + +class Gmpv214ModifyAlertTestCase(GmpModifyAlertTestMixin, Gmpv214TestCase): + pass + + +class Gmpv214TestAlertTestCase(GmpTestAlertTestMixin, Gmpv214TestCase): + pass + + +class Gmpv214TriggerAlertTestCase(GmpTriggerAlertTestMixin, Gmpv214TestCase): + pass From 81277d151296aa2fb052fcfa4ed4938b34adfc4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaspar=20L=C3=B6chte?= Date: Fri, 14 May 2021 09:43:00 +0200 Subject: [PATCH 05/12] Remove the alert test cases from old structure --- tests/protocols/gmpv208/test_new_gmpv208.py | 33 ------------------- .../gmpv214/test_v208_from_gmpv214.py | 33 ------------------- 2 files changed, 66 deletions(-) diff --git a/tests/protocols/gmpv208/test_new_gmpv208.py b/tests/protocols/gmpv208/test_new_gmpv208.py index 5bf30897b..1022a51c9 100644 --- a/tests/protocols/gmpv208/test_new_gmpv208.py +++ b/tests/protocols/gmpv208/test_new_gmpv208.py @@ -107,14 +107,6 @@ class Gmpv208CreatePolicyTestCase(GmpCreatePolicyTestCase, Gmpv208TestCase): pass -class Gmpv208ModifyAlertTestCase(GmpModifyAlertTestCase, Gmpv208TestCase): - pass - - -class Gmpv208CreateAlertTestCase(GmpCreateAlertTestCase, Gmpv208TestCase): - pass - - class Gmpv208CreateTLSCertificateTestCase( GmpCreateTLSCertificateTestCase, Gmpv208TestCase ): @@ -297,11 +289,6 @@ class Gmpv208AuthenticateTestCase(GmpAuthenticateTestCase, Gmpv208TestCase): pass -class Gmpv208CloneAlertTestCase(GmpCloneAlertTestCase, Gmpv208TestCase): - - pass - - class Gmpv208CloneReportFormatTestCase( GmpCloneReportFormatTestCase, Gmpv208TestCase ): @@ -369,10 +356,6 @@ class Gmpv208CreateUserTestCase(GmpCreateUserTestCase, Gmpv208TestCase): pass -class Gmpv208DeleteAlertTestCase(GmpDeleteAlertTestCase, Gmpv208TestCase): - pass - - class Gmpv208DeleteAssetTestCase(GmpDeleteAssetTestCase, Gmpv208TestCase): pass @@ -435,14 +418,6 @@ class Gmpv208EmptyTrashcanCommandTestCase( pass -class Gmpv208GetAlertTestCase(GmpGetAlertTestCase, Gmpv208TestCase): - pass - - -class Gmpv208GetAlertsTestCase(GmpGetAlertsTestCase, Gmpv208TestCase): - pass - - class Gmpv208GetAssetTestCase(GmpGetAssetTestCase, Gmpv208TestCase): pass @@ -663,14 +638,6 @@ class Gmpv208SyncScapCommandTestCase( pass -class Gmpv208TestAlertTestCase(GmpTestAlertTestCase, Gmpv208TestCase): - pass - - -class Gmpv208TriggerAlertTestCase(GmpTriggerAlertTestCase, Gmpv208TestCase): - pass - - class Gmpv208VerifyReportFormatTestCase( GmpVerifyReportFormatTestCase, Gmpv208TestCase ): diff --git a/tests/protocols/gmpv214/test_v208_from_gmpv214.py b/tests/protocols/gmpv214/test_v208_from_gmpv214.py index 60e3421a3..8989bfe87 100644 --- a/tests/protocols/gmpv214/test_v208_from_gmpv214.py +++ b/tests/protocols/gmpv214/test_v208_from_gmpv214.py @@ -107,14 +107,6 @@ class Gmpv214CreatePolicyTestCase(GmpCreatePolicyTestCase, Gmpv214TestCase): pass -class Gmpv214ModifyAlertTestCase(GmpModifyAlertTestCase, Gmpv214TestCase): - pass - - -class Gmpv214CreateAlertTestCase(GmpCreateAlertTestCase, Gmpv214TestCase): - pass - - class Gmpv214CreateTLSCertificateTestCase( GmpCreateTLSCertificateTestCase, Gmpv214TestCase ): @@ -289,11 +281,6 @@ class Gmpv214AuthenticateTestCase(GmpAuthenticateTestCase, Gmpv214TestCase): pass -class Gmpv214CloneAlertTestCase(GmpCloneAlertTestCase, Gmpv214TestCase): - - pass - - class Gmpv214CloneReportFormatTestCase( GmpCloneReportFormatTestCase, Gmpv214TestCase ): @@ -361,10 +348,6 @@ class Gmpv214CreateUserTestCase(GmpCreateUserTestCase, Gmpv214TestCase): pass -class Gmpv214DeleteAlertTestCase(GmpDeleteAlertTestCase, Gmpv214TestCase): - pass - - class Gmpv214DeleteAssetTestCase(GmpDeleteAssetTestCase, Gmpv214TestCase): pass @@ -427,14 +410,6 @@ class Gmpv214EmptyTrashcanCommandTestCase( pass -class Gmpv214GetAlertTestCase(GmpGetAlertTestCase, Gmpv214TestCase): - pass - - -class Gmpv214GetAlertsTestCase(GmpGetAlertsTestCase, Gmpv214TestCase): - pass - - class Gmpv214GetAssetTestCase(GmpGetAssetTestCase, Gmpv214TestCase): pass @@ -651,14 +626,6 @@ class Gmpv214SyncScapCommandTestCase( pass -class Gmpv214TestAlertTestCase(GmpTestAlertTestCase, Gmpv214TestCase): - pass - - -class Gmpv214TriggerAlertTestCase(GmpTriggerAlertTestCase, Gmpv214TestCase): - pass - - class Gmpv214VerifyReportFormatTestCase( GmpVerifyReportFormatTestCase, Gmpv214TestCase ): From e615a367b7aab1eb3cd926f2a4abaddaf935d59d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaspar=20L=C3=B6chte?= Date: Fri, 14 May 2021 11:15:39 +0200 Subject: [PATCH 06/12] Improve get_from_string alert methods, so its easier to extend the corrosponding Types --- gvm/protocols/gmpv208/entities/alerts.py | 87 +++++------------------- 1 file changed, 17 insertions(+), 70 deletions(-) diff --git a/gvm/protocols/gmpv208/entities/alerts.py b/gvm/protocols/gmpv208/entities/alerts.py index 15c489be9..d370a4a7b 100644 --- a/gvm/protocols/gmpv208/entities/alerts.py +++ b/gvm/protocols/gmpv208/entities/alerts.py @@ -48,29 +48,13 @@ def get_alert_event_from_string( if not alert_event: return None - alert_event = alert_event.lower() - - if alert_event == 'task run status changed': - return AlertEvent.TASK_RUN_STATUS_CHANGED - - if alert_event == 'updated secinfo arrived': - return AlertEvent.UPDATED_SECINFO_ARRIVED - - if alert_event == 'new secinfo arrived': - return AlertEvent.NEW_SECINFO_ARRIVED - - if alert_event == 'ticket received': - return AlertEvent.TICKET_RECEIVED - - if alert_event == 'assigned ticket changed': - return AlertEvent.ASSIGNED_TICKET_CHANGED - - if alert_event == 'owned ticket changed': - return AlertEvent.OWNED_TICKET_CHANGED - - raise InvalidArgument( - argument='alert_event', function=get_alert_event_from_string.__name__ - ) + try: + return AlertEvent[alert_event.replace(' ', '_').upper()] + except KeyError: + raise InvalidArgument( + argument='alert_event', + function=get_alert_event_from_string.__name__, + ) from KeyError class AlertCondition(Enum): @@ -91,30 +75,13 @@ def get_alert_condition_from_string( if not alert_condition: return None - alert_condition = alert_condition.lower() - - if alert_condition == 'error': - return AlertCondition.ERROR - - if alert_condition == 'always': - return AlertCondition.ALWAYS - - if alert_condition == 'filter count changed': - return AlertCondition.FILTER_COUNT_CHANGED - - if alert_condition == 'filter count at least': - return AlertCondition.FILTER_COUNT_AT_LEAST - - if alert_condition == 'severity at least': - return AlertCondition.SEVERITY_AT_LEAST - - if alert_condition == 'severity changed': - return AlertCondition.SEVERITY_CHANGED - - raise InvalidArgument( - argument='alert_condition', - function=get_alert_condition_from_string.__name__, - ) + try: + return AlertCondition[alert_condition.replace(' ', '_').upper()] + except KeyError: + raise InvalidArgument( + argument='alert_condition', + function=get_alert_condition_from_string.__name__, + ) from KeyError class AlertMethod(Enum): @@ -130,7 +97,7 @@ class AlertMethod(Enum): HTTP_GET = "HTTP Get" SOURCEFIRE_CONNECTOR = "Sourcefire Connector" VERINICE_CONNECTOR = "verinice Connector" - TIPPINGPOINT = "TippingPoint SMS" + TIPPINGPOINT_SMS = "TippingPoint SMS" ALEMBA_VFIRE = "Alemba vFire" @@ -141,33 +108,13 @@ def get_alert_method_from_string( if not alert_method: return None - alert_method = alert_method.upper() - - if alert_method == 'START TASK': - return AlertMethod.START_TASK - - if alert_method == 'HTTP GET': - return AlertMethod.HTTP_GET - - if alert_method == 'SOURCEFIRE CONNECTOR': - return AlertMethod.SOURCEFIRE_CONNECTOR - - if alert_method == 'VERINICE CONNECTOR': - return AlertMethod.VERINICE_CONNECTOR - - if alert_method == 'TIPPINGPOINT SMS': - return AlertMethod.TIPPINGPOINT - - if alert_method == 'ALEMBA VFIRE': - return AlertMethod.ALEMBA_VFIRE - try: - return AlertMethod[alert_method] + return AlertMethod[alert_method.replace(' ', '_').upper()] except KeyError: raise InvalidArgument( argument='alert_method', function=get_alert_method_from_string.__name__, - ) from None + ) from KeyError def _check_event( From dcfd15b49475919e8f1a1e040e3e8f8846d295fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaspar=20L=C3=B6chte?= Date: Fri, 14 May 2021 11:16:00 +0200 Subject: [PATCH 07/12] We don't need to lower that, cause we upper it afterwards --- gvm/protocols/gmpv208/entities/report_formats.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/gvm/protocols/gmpv208/entities/report_formats.py b/gvm/protocols/gmpv208/entities/report_formats.py index cfec66b4a..f8ff53207 100644 --- a/gvm/protocols/gmpv208/entities/report_formats.py +++ b/gvm/protocols/gmpv208/entities/report_formats.py @@ -53,12 +53,10 @@ def get_report_format_id_from_string( if not report_format: return None - report_format = report_format.lower() - try: return ReportFormatType[report_format.replace(' ', '_').upper()] except KeyError: raise InvalidArgument( argument='report_format', function=get_report_format_id_from_string.__name__, - ) from None + ) from KeyError From d0b0860c1a8c0ef4d5dc900e39a9266a749bb1a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaspar=20L=C3=B6chte?= Date: Fri, 14 May 2021 11:16:24 +0200 Subject: [PATCH 08/12] Adjust alert method tippingpoint sms, to fit the Type --- tests/protocols/gmpv208/testtypes/test_alert_method.py | 2 +- tests/protocols/gmpv214/testtypes/test_alert_method.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/protocols/gmpv208/testtypes/test_alert_method.py b/tests/protocols/gmpv208/testtypes/test_alert_method.py index dd7336f28..60918888a 100644 --- a/tests/protocols/gmpv208/testtypes/test_alert_method.py +++ b/tests/protocols/gmpv208/testtypes/test_alert_method.py @@ -75,7 +75,7 @@ def test_verinice_connector(self): def test_tippingpoint_sms(self): ct = get_alert_method_from_string('Tippingpoint SMS') - self.assertEqual(ct, AlertMethod.TIPPINGPOINT) + self.assertEqual(ct, AlertMethod.TIPPINGPOINT_SMS) def test_alemba_vfire(self): ct = get_alert_method_from_string('Alemba vFire') diff --git a/tests/protocols/gmpv214/testtypes/test_alert_method.py b/tests/protocols/gmpv214/testtypes/test_alert_method.py index 826d61245..fee239763 100644 --- a/tests/protocols/gmpv214/testtypes/test_alert_method.py +++ b/tests/protocols/gmpv214/testtypes/test_alert_method.py @@ -75,7 +75,7 @@ def test_verinice_connector(self): def test_tippingpoint_sms(self): ct = get_alert_method_from_string('Tippingpoint SMS') - self.assertEqual(ct, AlertMethod.TIPPINGPOINT) + self.assertEqual(ct, AlertMethod.TIPPINGPOINT_SMS) def test_alemba_vfire(self): ct = get_alert_method_from_string('Alemba vFire') From 75b4904615641cc869f2264f639d11f401bc36a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaspar=20L=C3=B6chte?= Date: Fri, 14 May 2021 11:17:50 +0200 Subject: [PATCH 09/12] Added CHANGELOG entry --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b0049111d..4c1c27f01 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ and this project adheres to [Calendar Versioning](https://calver.org)html). * Introduced new explicit API calls for SecInfo: `get_nvt()`, `get_nvt_list()`, `get_cpe()`, `get_cpe_list()`, `get_cve()`, `get_cve_list()`, `get_cert_bund_advisory()`, `get_cert_bund_advisory_list()`, `get_dnf_cert_advisory()`, `get_dnf_cert_advisory_list()`, `get_oval_definition()`, `get_oval_definition_list()`. [#456](https://github.com/greenbone/python-gvm/pull/456) ### Changed +* Detached the Alerts API calls from the GMP class into a new `AlertsMixin`. [#458](https://github.com/greenbone/python-gvm/pull/458) * Changed the API calls `get_nvt()` and `get_nvts()` to `get_scan_config_nvt()` and `get_scan_config_nvts()`. [#456](https://github.com/greenbone/python-gvm/pull/456) * Detached the `InfoType` from the GMP types class. [#456](https://github.com/greenbone/python-gvm/pull/456) * Detached the SecInfo (CPE, CVE, NVT, CERT-BUND, DNF-CERT, OVAL Definitions) calls from CMP class into new `SecInfoMixin`. [#456](https://github.com/greenbone/python-gvm/pull/456) From 9761fe900657569da04b553e9e94e05d563ce7c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaspar=20L=C3=B6chte?= Date: Mon, 17 May 2021 11:15:55 +0200 Subject: [PATCH 10/12] The else case cannot be accessed over the modify or create_alert commands --- gvm/protocols/gmpv208/entities/alerts.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/gvm/protocols/gmpv208/entities/alerts.py b/gvm/protocols/gmpv208/entities/alerts.py index d370a4a7b..8714dac4d 100644 --- a/gvm/protocols/gmpv208/entities/alerts.py +++ b/gvm/protocols/gmpv208/entities/alerts.py @@ -202,8 +202,6 @@ def _check_event( raise InvalidArgument( "Invalid method {} for event {}".format(method.name, event.name) ) - elif event is not None: - raise InvalidArgument('Invalid event "{}"'.format(event.name)) class AlertsMixin: From 2826ed44cf6a16438e0fa2d8dfbcb00ca3f29287 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaspar=20L=C3=B6chte?= Date: Mon, 17 May 2021 11:16:10 +0200 Subject: [PATCH 11/12] Increase coverage of alerts --- .../entities/alerts/test_modify_alert.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/tests/protocols/gmpv208/entities/alerts/test_modify_alert.py b/tests/protocols/gmpv208/entities/alerts/test_modify_alert.py index e2f639f2e..c6b4c4a79 100644 --- a/tests/protocols/gmpv208/entities/alerts/test_modify_alert.py +++ b/tests/protocols/gmpv208/entities/alerts/test_modify_alert.py @@ -202,3 +202,21 @@ def test_modify_alert_with_method_data(self): 'Task run status changed' '' ) + + def test_modify_missing_method_for_ticket_received(self): + with self.assertRaises(RequiredArgument): + self.gmp.modify_alert( + alert_id='a1', + condition=AlertCondition.ALWAYS, + event=AlertEvent.TICKET_RECEIVED, + method=None, + ) + + def test_modify_missing_condition_for_ticket_received(self): + with self.assertRaises(RequiredArgument): + self.gmp.modify_alert( + alert_id='a1', + condition=None, + event=AlertEvent.TICKET_RECEIVED, + method=AlertMethod.EMAIL, + ) From 070d884a129b75a23e10bbce9f22de3415c1da98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaspar=20L=C3=B6chte?= Date: Mon, 17 May 2021 11:19:39 +0200 Subject: [PATCH 12/12] Test missing types correctly --- .../gmpv208/entities/alerts/test_modify_alert.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/tests/protocols/gmpv208/entities/alerts/test_modify_alert.py b/tests/protocols/gmpv208/entities/alerts/test_modify_alert.py index c6b4c4a79..e9c24c684 100644 --- a/tests/protocols/gmpv208/entities/alerts/test_modify_alert.py +++ b/tests/protocols/gmpv208/entities/alerts/test_modify_alert.py @@ -69,22 +69,25 @@ def test_modify_alert_invalid_condition(self): self.gmp.modify_alert( alert_id='a1', condition='bar', - event='Task run status changed', - method='Email', + event=AlertEvent.TASK_RUN_STATUS_CHANGED, + method=AlertMethod.SCP, ) def test_modify_alert_invalid_event(self): with self.assertRaises(InvalidArgumentType): self.gmp.modify_alert( - alert_id='a1', condition='Always', event='lorem', method='Email' + alert_id='a1', + condition=AlertCondition.ALWAYS, + event='lorem', + method=AlertMethod.SCP, ) def test_modify_alert_invalid_method(self): with self.assertRaises(InvalidArgumentType): self.gmp.modify_alert( alert_id='a1', - condition='Always', - event='Task run status changed', + condition=AlertCondition.ALWAYS, + event=AlertEvent.TASK_RUN_STATUS_CHANGED, method='ipsum', )