From 8bc6d1724a037db9f7e71f00288219648153946e Mon Sep 17 00:00:00 2001 From: Steven McGrath Date: Thu, 6 Feb 2025 11:18:24 -0600 Subject: [PATCH] Corrected the now incorrect behavior for max scan time #863 (#873) --- tenable/sc/scans.py | 304 ++++++++------- tests/sc/test_scans.py | 846 +++++++++++++++++++++-------------------- 2 files changed, 601 insertions(+), 549 deletions(-) diff --git a/tenable/sc/scans.py b/tenable/sc/scans.py index 85b16458b..b32955ab2 100644 --- a/tenable/sc/scans.py +++ b/tenable/sc/scans.py @@ -1,4 +1,4 @@ -''' +""" Scans ===== @@ -14,173 +14,203 @@ .. rst-class:: hide-signature .. autoclass:: ScanAPI :members: -''' -from .base import SCEndpoint -from tenable.utils import dict_merge +""" + from tenable.errors import UnexpectedValueError +from tenable.utils import dict_merge + +from .base import SCEndpoint + class ScanAPI(SCEndpoint): def _constructor(self, **kw): - ''' + """ Handles parsing the keywords and returns a scan definition document - ''' - if 'inactivity_timeout' in kw: - kw['inactivityTimeout'] = str(self._check( - 'inactivity_timeout', kw['inactivity_timeout'], int, default=3600)) - del (kw['inactivity_timeout']) - - if 'name' in kw: + """ + if "inactivity_timeout" in kw: + kw["inactivityTimeout"] = str( + self._check( + "inactivity_timeout", kw["inactivity_timeout"], int, default=3600 + ) + ) + del kw["inactivity_timeout"] + + if "name" in kw: # simply verify that the name attribute is a string. - self._check('name', kw['name'], str) + self._check("name", kw["name"], str) - if 'type' in kw: + if "type" in kw: # If the scan type is manually specified, then we will want to make # sure that its a valid input. - self._check('type', kw['type'], str, choices=['plugin', 'policy']) + self._check("type", kw["type"], str, choices=["plugin", "policy"]) - if 'description' in kw: + if "description" in kw: # The description should always be a string value. - self._check('description', kw['description'], str) + self._check("description", kw["description"], str) - if 'repo' in kw: + if "repo" in kw: # as we accept input as a integer, we need to expand the repository # attribute to be a dictionary item with just the ID (per API docs) - kw['repository'] = {'id': self._check( - 'repo', kw['repo'], int)} - del(kw['repo']) + kw["repository"] = {"id": self._check("repo", kw["repo"], int)} + del kw["repo"] - if 'scan_zone' in kw: + if "scan_zone" in kw: # similarly to the repository, the API expects the zone to be # defined as a sub-dictionary with just the id field. - kw['zone'] = {'id': self._check( - 'scan_zone', kw['scan_zone'], int, default=0)} - del(kw['scan_zone']) + kw["zone"] = { + "id": self._check("scan_zone", kw["scan_zone"], int, default=0) + } + del kw["scan_zone"] - if 'email_complete' in kw: + if "email_complete" in kw: # As emailOnFinish is effectively a string interpretation of a bool # value, if the snake case equivalent is used, we will convert it # into the expected parameter and remove the snake cased version. - kw['emailOnFinish'] = str(self._check( - 'email_complete', kw['email_complete'], bool, default=False)).lower() - del(kw['email_complete']) + kw["emailOnFinish"] = str( + self._check("email_complete", kw["email_complete"], bool, default=False) + ).lower() + del kw["email_complete"] - if 'email_launch' in kw: + if "email_launch" in kw: # As emailOnLaunch is effectively a string interpretation of a bool # value, if the snake case equivalent is used, we will convert it # into the expected parameter and remove the snake cased version. - kw['emailOnLaunch'] = str(self._check( - 'email_launch', kw['email_launch'], bool, default=False)).lower() - del(kw['email_launch']) + kw["emailOnLaunch"] = str( + self._check("email_launch", kw["email_launch"], bool, default=False) + ).lower() + del kw["email_launch"] - if 'host_tracking' in kw: + if "host_tracking" in kw: # As host_tracking is effectively a string interpretation of a bool # value, if the snake case equivalent is used, we will convert it # into the expected parameter and remove the snake cased version. - kw['dhcpTracking'] = str(self._check( - 'host_tracking', kw['host_tracking'], bool, default=False)).lower() - del(kw['host_tracking']) + kw["dhcpTracking"] = str( + self._check("host_tracking", kw["host_tracking"], bool, default=False) + ).lower() + del kw["host_tracking"] - if 'timeout' in kw: + if "timeout" in kw: # timeout is the checked version of timeoutAction. If timeout is # specified, we will check to make sure that the action is a valid # one, put the result into timeoutAction, and remove timeout. - kw['timeoutAction'] = self._check('timeout', kw['timeout'], str, - choices=['discard', 'import', 'rollover'], default='import') - del(kw['timeout']) - - if 'vhosts' in kw: + kw["timeoutAction"] = self._check( + "timeout", + kw["timeout"], + str, + choices=["discard", "import", "rollover"], + default="import", + ) + del kw["timeout"] + + if "vhosts" in kw: # As scanningVirtualHosts is effectively a string interpretation of # a bool value, if the snake case equivalent is used, we will # convert it into the expected parameter and remove the snake cased # version. - kw['scanningVirtualHosts'] = str(self._check( - 'vhosts', kw['vhosts'], bool, default=False)).lower() - del(kw['vhosts']) + kw["scanningVirtualHosts"] = str( + self._check("vhosts", kw["vhosts"], bool, default=False) + ).lower() + del kw["vhosts"] - if 'rollover' in kw: + if "rollover" in kw: # The scan rolloverType parameter simply shortened to better conform # to pythonic naming convention. - kw['rolloverType'] = self._check('rollover', kw['rollover'], str, - choices=['nextDay', 'template'], default='template') - del(kw['rollover']) - - if 'targets' in kw: + kw["rolloverType"] = self._check( + "rollover", + kw["rollover"], + str, + choices=["nextDay", "template"], + default="template", + ) + del kw["rollover"] + + if "targets" in kw: # targets is list representation of a comma-separated string of # values for the ipList attribute. By handling as a list instead of # the raw string variant the API expects, we can ensure that there # isn't any oddities, such as extra spaces, between the commas. - kw['ipList'] = ','.join([self._check('target', i.strip(), str) - for i in self._check('targets', kw['targets'], list)]) - del(kw['targets']) - - if 'max_time' in kw: + kw["ipList"] = ",".join( + [ + self._check("target", i.strip(), str) + for i in self._check("targets", kw["targets"], list) + ] + ) + del kw["targets"] + + if "max_time" in kw: # maxScanTime is a integer encased in a string value. the snake # cased version of that expects an integer and converts it into the # string equivalent. - kw['maxScanTime'] = self._check('max_time', kw['max_time'], int) - if kw['maxScanTime'] <= 0: - kw['maxScanTime'] = 'unlimited'; - else: - kw['maxScanTime'] = str(kw['maxScanTime']) - del(kw['max_time']) - - if 'auto_mitigation' in kw: + max_time = int(kw.pop("max_time", None)) + kw["maxScanTime"] = str(max_time) + + if "auto_mitigation" in kw: # As classifyMitigatedAge is effectively a string interpretation of # an int value, if the snake case equivalent is used, we will # convert it into the expected parameter and remove the snake cased # version. - kw['classifyMitigatedAge'] = str(self._check( - 'auto_mitigation', kw['auto_mitigation'], int, default=0)).lower() - del(kw['auto_mitigation']) + kw["classifyMitigatedAge"] = str( + self._check("auto_mitigation", kw["auto_mitigation"], int, default=0) + ).lower() + del kw["auto_mitigation"] # hand off the building the schedule sub-document to the schedule # document builder. - if 'schedule' in kw: - kw['schedule'] = self._schedule_constructor(kw['schedule']) + if "schedule" in kw: + kw["schedule"] = self._schedule_constructor(kw["schedule"]) - if 'reports' in kw: + if "reports" in kw: # as the reports list should already be in a format that the API # expects, we will simply verify that everything looks like it should. - for item in self._check('reports', kw['reports'], list): - self._check('report:id', item['id'], int), - self._check('reportSource', item['reportSource'], str, choices=[ - 'cumulative', - 'patched', - 'individual', - 'lce', - 'archive', - 'mobile' - ]) - - if 'asset_lists' in kw: + for item in self._check("reports", kw["reports"], list): + (self._check("report:id", item["id"], int),) + self._check( + "reportSource", + item["reportSource"], + str, + choices=[ + "cumulative", + "patched", + "individual", + "lce", + "archive", + "mobile", + ], + ) + + if "asset_lists" in kw: # asset_lists is the collapsed list of id documents that the API # expects to see. We will check each item in the list to make sure # its in the right type and then expand it into a sub-document. - kw['assets'] = [{'id': self._check('asset_list:id', i, int)} - for i in self._check('assets_lists', kw['asset_lists'], list)] - del(kw['asset_lists']) + kw["assets"] = [ + {"id": self._check("asset_list:id", i, int)} + for i in self._check("assets_lists", kw["asset_lists"], list) + ] + del kw["asset_lists"] - if 'creds' in kw: + if "creds" in kw: # creds is the collapsed list of id documents that the API expects # to see. We will check each item in the list to make sure its in # the right type and then expand it into a sub-document. - kw['credentials'] = [{'id': self._check('cred:id', i, int)} - for i in self._check('creds', kw['creds'], list)] - del(kw['creds']) + kw["credentials"] = [ + {"id": self._check("cred:id", i, int)} + for i in self._check("creds", kw["creds"], list) + ] + del kw["creds"] - if 'policy_id' in kw: + if "policy_id" in kw: # If just the policy_id is specified, then we are safe to assume # that this is a policy-based scan. set the policy id attribute # within the policy document as the API would expect and remove the # snake cased variant that was inputted. - kw['type'] = 'policy' - kw['policy'] = {'id': self._check('policy_id', kw['policy_id'], int)} - del(kw['policy_id']) + kw["type"] = "policy" + kw["policy"] = {"id": self._check("policy_id", kw["policy_id"], int)} + del kw["policy_id"] return kw def list(self, fields=None): - ''' + """ Retrieves the list of scan definitions. :sc-api:`scan: list ` @@ -196,16 +226,15 @@ def list(self, fields=None): Examples: >>> for scan in sc.scans.list(): ... pprint(scan) - ''' + """ params = dict() if fields: - params['fields'] = ','.join([self._check('field', f, str) - for f in fields]) + params["fields"] = ",".join([self._check("field", f, str) for f in fields]) - return self._api.get('scan', params=params).json()['response'] + return self._api.get("scan", params=params).json()["response"] def create(self, name, repo, **kw): - ''' + """ Creates a scan definition. :sc-api:`scan: create ` @@ -276,21 +305,21 @@ def create(self, name, repo, **kw): >>> sc.scans.create('Example scan', 1, policy_id=1001, ... targets=['127.0.0.1']) - ''' - kw['name'] = name - kw['repo'] = repo + """ + kw["name"] = name + kw["repo"] = repo # If the policy_id or plugin_id is set (as one or the other generally # should be) then we will automatically set the scan type based on # which of the values is defined. - if 'policy_id' in kw: - kw['type'] = 'policy' + if "policy_id" in kw: + kw["type"] = "policy" scan = self._constructor(**kw) - return self._api.post('scan', json=scan).json()['response'] + return self._api.post("scan", json=scan).json()["response"] def details(self, id, fields=None): - ''' + """ Returns the details for a specific scan. :sc-api:`scan: details ` @@ -306,16 +335,17 @@ def details(self, id, fields=None): Examples: >>> scan = sc.scans.detail(1) >>> pprint(scan) - ''' + """ params = dict() if fields: - params['fields'] = ','.join([self._check('field', f, str) for f in fields]) + params["fields"] = ",".join([self._check("field", f, str) for f in fields]) - return self._api.get('scan/{}'.format(self._check('id', id, int)), - params=params).json()['response'] + return self._api.get( + "scan/{}".format(self._check("id", id, int)), params=params + ).json()["response"] def edit(self, id, **kw): - ''' + """ Edits an existing scan definition. :sc-api:`scan: update ` @@ -379,13 +409,14 @@ def edit(self, id, **kw): Editing an existing scan's name: >>> sc.scans.edit(1, name='Example scan') - ''' + """ scan = self._constructor(**kw) - return self._api.patch('scan/{}'.format(self._check('id', id, int)), - json=scan).json()['response'] + return self._api.patch( + "scan/{}".format(self._check("id", id, int)), json=scan + ).json()["response"] def delete(self, id): - ''' + """ Removes the specified scan from SecurityCenter. :sc-api:`scan: delete ` @@ -399,12 +430,13 @@ def delete(self, id): Examples: >>> sc.scans.delete(1) - ''' - return self._api.delete('scan/{}'.format(self._check('id', id, int)) - ).json()['response'] + """ + return self._api.delete("scan/{}".format(self._check("id", id, int))).json()[ + "response" + ] def copy(self, id, name, user_id): - ''' + """ Copies an existing scan definition. :sc-api:`scan: copy ` @@ -421,17 +453,18 @@ def copy(self, id, name, user_id): Examples: >>> sc.scans.copy(1, name='Cloned Scan') - ''' + """ payload = { - 'name': self._check('name', name, str), - 'targetUser': {'id': self._check('user_id', user_id, int)} + "name": self._check("name", name, str), + "targetUser": {"id": self._check("user_id", user_id, int)}, } - return self._api.post('scan/{}/copy'.format( - self._check('id', id, int)), json=payload).json()['response']['scan'] + return self._api.post( + "scan/{}/copy".format(self._check("id", id, int)), json=payload + ).json()["response"]["scan"] def launch(self, id, diagnostic_target=None, diagnostic_password=None): - ''' + """ Launches a scan definition. :sc-api:`scan: launch ` @@ -455,13 +488,16 @@ def launch(self, id, diagnostic_target=None, diagnostic_password=None): >>> running = sc.scans.launch(1) >>> print('The Scan Result ID is {}'.format( ... running['scanResult']['id'])) - ''' + """ payload = dict() if diagnostic_target and diagnostic_password: - payload['diagnosticTarget'] = self._check( - 'diagnostic_target', diagnostic_target, str) - payload['diagnosticPassword'] = self._check( - 'diagnostic_password', diagnostic_password, str) - - return self._api.post('scan/{}/launch'.format( - self._check('id', id, int)), json=payload).json()['response'] + payload["diagnosticTarget"] = self._check( + "diagnostic_target", diagnostic_target, str + ) + payload["diagnosticPassword"] = self._check( + "diagnostic_password", diagnostic_password, str + ) + + return self._api.post( + "scan/{}/launch".format(self._check("id", id, int)), json=payload + ).json()["response"] diff --git a/tests/sc/test_scans.py b/tests/sc/test_scans.py index ecdae5873..df4a02aa5 100644 --- a/tests/sc/test_scans.py +++ b/tests/sc/test_scans.py @@ -1,158 +1,160 @@ -''' +""" test file for testing various scenarios in security center's scans functionality -''' +""" + import pytest from tenable.errors import APIError, UnexpectedValueError from tests.pytenable_log_handler import log_exception + from ..checker import check def test_schedule_constructor_type_typeerror(security_center): - ''' + """ test schedule constructor for 'type' type error - ''' + """ with pytest.raises(TypeError): - security_center.scans._schedule_constructor({'type': 1}) + security_center.scans._schedule_constructor({"type": 1}) def test_schedule_constructor_type_unexpected_value(security_center): - ''' + """ test schedule constructor for 'type' unexpected value error - ''' + """ with pytest.raises(UnexpectedValueError): - security_center.scans._schedule_constructor({'type': 'nothing here'}) + security_center.scans._schedule_constructor({"type": "nothing here"}) def test_schedule_constructor_start_typeerror(security_center): - ''' + """ test schedule constructor for 'start' type error - ''' + """ with pytest.raises(TypeError): security_center.scans._schedule_constructor( - {'type': 'ical', 'start': 1, 'repeatRule': ''}) + {"type": "ical", "start": 1, "repeatRule": ""} + ) def test_schedule_constructor_rrule_typeerror(security_center): - ''' + """ test schedule constructor for 'repeat rule' type error - ''' + """ with pytest.raises(TypeError): security_center.scans._schedule_constructor( - {'type': 'ical', 'start': '', 'repeatRule': 1}) + {"type": "ical", "start": "", "repeatRule": 1} + ) def test_scans_constructor_name_typeerror(security_center): - ''' + """ test scans constructor for 'name' type error - ''' + """ with pytest.raises(TypeError): security_center.scans._constructor(name=1) def test_scans_constructor_type_typeerror(security_center): - ''' + """ test scans constructor for 'type' type error - ''' + """ with pytest.raises(TypeError): security_center.scans._constructor(type=1) def test_scans_constructor_type_unexpectedvalueerror(security_center): - ''' + """ test scans constructor for 'type' unexpected value error - ''' + """ with pytest.raises(UnexpectedValueError): - security_center.scans._constructor(type='something') + security_center.scans._constructor(type="something") def test_scans_constructor_description_typeerror(security_center): - ''' + """ test scans constructor for 'description' type error - ''' + """ with pytest.raises(TypeError): security_center.scans._constructor(description=1) def test_scans_constructor_repo_typeerror(security_center): - ''' + """ test scans constructor for 'repo' type error - ''' + """ with pytest.raises(TypeError): - security_center.scans._constructor(repo='nope') + security_center.scans._constructor(repo="nope") def test_scans_constructor_repo_success(security_center): - ''' + """ test scans constructor for 'repo' success - ''' + """ resp = security_center.scans._constructor(repo=1) - assert resp == {'repository': {'id': 1}} + assert resp == {"repository": {"id": 1}} def test_scans_constructor_scan_zone_typeerror(security_center): - ''' + """ test scans constructor for 'scan_zone' type error - ''' + """ with pytest.raises(TypeError): - security_center.scans._constructor(scan_zone='nope') + security_center.scans._constructor(scan_zone="nope") def test_scans_constructor_scan_zone_success(security_center): - ''' + """ test scans constructor for 'scan_zone' success - ''' + """ resp = security_center.scans._constructor(scan_zone=1) - assert resp == {'zone': {'id': 1}} + assert resp == {"zone": {"id": 1}} def test_scans_constructor_email_complete_typeerror(security_center): - ''' + """ test scans constructor for 'email complete' type error - ''' + """ with pytest.raises(TypeError): - security_center.scans._constructor(email_complete='nope') + security_center.scans._constructor(email_complete="nope") def test_scans_constructor_email_complete_success(security_center): - ''' + """ test scans constructor for 'email complete' success - ''' + """ resp = security_center.scans._constructor(email_complete=True) - assert resp == {'emailOnFinish': 'true'} + assert resp == {"emailOnFinish": "true"} def test_scans_constructor_email_launch_typeerror(security_center): - ''' + """ test scans constructor for 'email launch' type error - ''' + """ with pytest.raises(TypeError): - security_center.scans._constructor(email_launch='nope') + security_center.scans._constructor(email_launch="nope") def test_scans_constructor_email_launch_success(security_center): - ''' + """ test scans constructor for 'email launch' success - ''' + """ resp = security_center.scans._constructor(email_launch=True) - assert resp == {'emailOnLaunch': 'true'} + assert resp == {"emailOnLaunch": "true"} def test_scans_constructor_timeout_typeerror(security_center): - ''' + """ test scans constructor for 'timeout' type error - ''' + """ with pytest.raises(TypeError): security_center.scans._constructor(timeout=1) + def test_scans_constructor_inactivity_timeout(security_center): """ Tests inactivity_timeout is mapped correctly in the constructor. """ - scan_params = { - "inactivity_timeout": 3600, - "policy_id": 1000001 - } + scan_params = {"inactivity_timeout": 3600, "policy_id": 1000001} scan = security_center.scans._constructor(**scan_params) @@ -161,274 +163,282 @@ def test_scans_constructor_inactivity_timeout(security_center): def test_scans_constructor_timeout_unexpectedvalueerror(security_center): - ''' + """ test scans constructor for 'timeout' unexpected value error - ''' + """ with pytest.raises(UnexpectedValueError): - security_center.scans._constructor(timeout='something') + security_center.scans._constructor(timeout="something") def test_scans_constructor_timeout_success(security_center): - ''' + """ test scans constructor for 'timeout' success - ''' - resp = security_center.scans._constructor(timeout='rollover') - assert resp == {'timeoutAction': 'rollover'} + """ + resp = security_center.scans._constructor(timeout="rollover") + assert resp == {"timeoutAction": "rollover"} def test_scans_constructor_host_tracking_typeerror(security_center): - ''' + """ test scans constructor for 'host tracking' type error - ''' + """ with pytest.raises(TypeError): - security_center.scans._constructor(host_tracking='something') + security_center.scans._constructor(host_tracking="something") def test_scans_constructor_host_tracking_success(security_center): - ''' + """ test scans constructor for 'host tracking' success - ''' - assert {'dhcpTracking': 'true'} == security_center.scans._constructor(host_tracking=True) + """ + assert {"dhcpTracking": "true"} == security_center.scans._constructor( + host_tracking=True + ) def test_scans_constructor_vhosts_typeerror(security_center): - ''' + """ test scans constructor for 'vhosts' type error - ''' + """ with pytest.raises(TypeError): - security_center.scans._constructor(vhosts='nope') + security_center.scans._constructor(vhosts="nope") def test_scans_constructor_vhosts_success(security_center): - ''' + """ test scans constructor for 'vhosts' success - ''' + """ resp = security_center.scans._constructor(vhosts=True) - assert resp == {'scanningVirtualHosts': 'true'} + assert resp == {"scanningVirtualHosts": "true"} def test_scans_constructor_rollover_typeerror(security_center): - ''' + """ test scans constructor for 'rollover' type error - ''' + """ with pytest.raises(TypeError): security_center.scans._constructor(rollover=1) def test_scans_constructor_rollover_unexpectedvalueerror(security_center): - ''' + """ test scans constructor for 'rollover' unexpected value error - ''' + """ with pytest.raises(UnexpectedValueError): - security_center.scans._constructor(rollover='something') + security_center.scans._constructor(rollover="something") def test_scans_constructor_rollover_success(security_center): - ''' + """ test scans constructor for 'rollover' success - ''' - assert {'rolloverType': 'nextDay'} == security_center.scans._constructor(rollover='nextDay') + """ + assert {"rolloverType": "nextDay"} == security_center.scans._constructor( + rollover="nextDay" + ) def test_scans_constructor_targets_typeerror(security_center): - ''' + """ test scans constructor for 'targets' type error - ''' + """ with pytest.raises(TypeError): - security_center.scans._constructor(targets='something') + security_center.scans._constructor(targets="something") def test_scans_constructor_targets_success(security_center): - ''' + """ test scans constructor for 'targets' success - ''' - resp = security_center.scans._constructor(targets=['127.0.0.1', '127.0.0.2']) - assert resp == {'ipList': '127.0.0.1,127.0.0.2'} + """ + resp = security_center.scans._constructor(targets=["127.0.0.1", "127.0.0.2"]) + assert resp == {"ipList": "127.0.0.1,127.0.0.2"} def test_scans_constructor_max_time_typeerror(security_center): - ''' + """ test scans constructor for 'max time' type error - ''' - with pytest.raises(TypeError): - security_center.scans._constructor(max_time='nope') + """ + with pytest.raises(ValueError): + security_center.scans._constructor(max_time="nope") def test_scans_constructor_max_time_success(security_center): - ''' + """ test scans constructor for 'max time' success - ''' + """ resp = security_center.scans._constructor(max_time=3600) - assert resp == {'maxScanTime': '3600'} + assert resp == {"maxScanTime": "3600"} def test_scans_constructor_max_time_zero(security_center): - ''' + """ test scans constructor for 'max time' zero - ''' + """ resp = security_center.scans._constructor(max_time=0) - assert resp == {'maxScanTime': 'unlimited'} + assert resp == {"maxScanTime": "0"} def test_scans_constructor_schedule_success(security_center): - ''' + """ test scans constructor for 'schedule' success - ''' - scan = security_center.scans._constructor(schedule={'type': 'ical', 'start': ''}) - assert {'schedule': {'type': 'ical', 'start': ''}} == scan + """ + scan = security_center.scans._constructor(schedule={"type": "ical", "start": ""}) + assert {"schedule": {"type": "ical", "start": ""}} == scan def test_scans_constructor_auto_mitigation_typeerror(security_center): - ''' + """ test scans constructor for 'auto mitigation' type error - ''' + """ with pytest.raises(TypeError): - security_center.scans._constructor(auto_mitigation='nope') + security_center.scans._constructor(auto_mitigation="nope") def test_scans_constructor_auto_mitigation_success(security_center): - ''' + """ test scans constructor for 'auto mitigation' success - ''' + """ resp = security_center.scans._constructor(auto_mitigation=True) - assert resp == {'classifyMitigatedAge': 'true'} + assert resp == {"classifyMitigatedAge": "true"} def test_scans_constructor_reports_typeerror_base(security_center): - ''' + """ test scans constructor for 'reports' type error - ''' + """ with pytest.raises(TypeError): - security_center.scans._constructor(reports='nope') + security_center.scans._constructor(reports="nope") def test_scans_constructor_reports_typeerror_id(security_center): - ''' + """ test scans constructor reports for 'id' type error - ''' + """ with pytest.raises(TypeError): - security_center.scans._constructor(reports=[ - {'id': 'nope', 'reportSource': 'cumulative'}]) + security_center.scans._constructor( + reports=[{"id": "nope", "reportSource": "cumulative"}] + ) def test_scans_constructor_reports_typeerror_report_source(security_center): - ''' + """ test scans constructor reports for 'report source' type error - ''' + """ with pytest.raises(TypeError): - security_center.scans._constructor(reports=[ - {'id': 1, 'reportSource': 1}]) + security_center.scans._constructor(reports=[{"id": 1, "reportSource": 1}]) def test_scans_constructor_reports_unexpectedvalueerror_reportsource(security_center): - ''' + """ test scans constructor reports for 'report source' unexpected value error - ''' + """ with pytest.raises(UnexpectedValueError): - security_center.scans._constructor(reports=[ - {'id': 1, 'reportSource': 'something'}]) + security_center.scans._constructor( + reports=[{"id": 1, "reportSource": "something"}] + ) def test_scans_constructor_reports_success(security_center): - ''' + """ test scans constructor reports for success - ''' - resp = security_center.scans._constructor(reports=[ - {'id': 1, 'reportSource': 'cumulative'}]) - assert resp == {'reports': [{'id': 1, 'reportSource': 'cumulative'}]} + """ + resp = security_center.scans._constructor( + reports=[{"id": 1, "reportSource": "cumulative"}] + ) + assert resp == {"reports": [{"id": 1, "reportSource": "cumulative"}]} def test_scans_constructor_asset_lists_typeerror(security_center): - ''' + """ test scans constructor for 'asset lists' type error - ''' + """ with pytest.raises(TypeError): security_center.scans._constructor(asset_lists=1) def test_scans_constructor_asset_list_id_typeerror(security_center): - ''' + """ test scans constructor for 'asset list id' type error - ''' + """ with pytest.raises(TypeError): - security_center.scans._constructor(asset_lists=['nope', ]) + security_center.scans._constructor( + asset_lists=[ + "nope", + ] + ) def test_scans_constructor_asset_lists_success(security_center): - ''' + """ test scans constructor for 'asset lists' success - ''' + """ resp = security_center.scans._constructor(asset_lists=[1, 2]) - assert resp == {'assets': [{'id': 1}, {'id': 2}]} + assert resp == {"assets": [{"id": 1}, {"id": 2}]} def test_scans_constructor_creds_typeerror(security_center): - ''' + """ test scans constructor for 'creds' type error - ''' + """ with pytest.raises(TypeError): security_center.scans._constructor(creds=1) def test_scans_constructor_creds_id_typeerror(security_center): - ''' + """ test scans constructor for 'creds id' type error - ''' + """ with pytest.raises(TypeError): - security_center.scans._constructor(creds=['nope']) + security_center.scans._constructor(creds=["nope"]) def test_scans_constructor_creds_success(security_center): - ''' + """ test scans constructor for creds success - ''' + """ resp = security_center.scans._constructor(creds=[1, 2]) - assert resp == {'credentials': [{'id': 1}, {'id': 2}]} + assert resp == {"credentials": [{"id": 1}, {"id": 2}]} def test_scans_constructor_plugin_id_success(security_center): - ''' + """ test scans constructor for plugin id success - ''' + """ resp = security_center.scans._constructor(policy_id=19506) - assert resp == { - 'type': 'policy', - 'policy': { - 'id': 19506 - } - } + assert resp == {"type": "policy", "policy": {"id": 19506}} def test_scans_constructor_policy_id_typeerror(security_center): - ''' + """ test scans constructor for 'policy id' type error - ''' + """ with pytest.raises(TypeError): - security_center.scans._constructor(policy_id='nope') + security_center.scans._constructor(policy_id="nope") def test_scans_constructor_policy_id_success(security_center): - ''' + """ test scans constructor for 'policy id' success - ''' + """ resp = security_center.scans._constructor(policy_id=1) - assert resp == {'type': 'policy', 'policy': {'id': 1}} + assert resp == {"type": "policy", "policy": {"id": 1}} @pytest.fixture def scan(request, security_center, vcr): - ''' + """ test fixture for scan - ''' - with vcr.use_cassette('sc_scans_create'): - scan = security_center.scans.create('Example Scan', 1, - schedule_type='template', - targets=['127.0.0.1'], - policy_id=1000001) + """ + with vcr.use_cassette("sc_scans_create"): + scan = security_center.scans.create( + "Example Scan", + 1, + schedule_type="template", + targets=["127.0.0.1"], + policy_id=1000001, + ) def teardown(): try: - security_center.scans.delete(int(scan['id'])) + security_center.scans.delete(int(scan["id"])) except APIError as error: log_exception(error) @@ -438,309 +448,315 @@ def teardown(): @pytest.mark.vcr() def test_scans_list(security_center): - ''' + """ test scans list for success - ''' + """ scans = security_center.scans.list() - for scan in scans['usable']: + for scan in scans["usable"]: assert isinstance(scan, dict) - check(scan, 'id', str) - check(scan, 'name', str) - check(scan, 'description', str) - check(scan, 'status', str) + check(scan, "id", str) + check(scan, "name", str) + check(scan, "description", str) + check(scan, "status", str) @pytest.mark.vcr() def test_scans_list_for_fields(security_center): - ''' + """ test scans list success for fields - ''' - scans = security_center.scans.list(fields=['id', 'name']) - for scan in scans['usable']: + """ + scans = security_center.scans.list(fields=["id", "name"]) + for scan in scans["usable"]: assert isinstance(scan, dict) - check(scan, 'id', str) - check(scan, 'name', str) + check(scan, "id", str) + check(scan, "name", str) @pytest.mark.vcr() def test_scans_details(security_center, scan): - ''' + """ test scans details for success - ''' - scan = security_center.scans.details(int(scan['id'])) + """ + scan = security_center.scans.details(int(scan["id"])) assert isinstance(scan, dict) - check(scan, 'id', str) - check(scan, 'name', str) - check(scan, 'description', str) - check(scan, 'ipList', str) - check(scan, 'type', str) - check(scan, 'dhcpTracking', str) - check(scan, 'classifyMitigatedAge', str) - check(scan, 'emailOnLaunch', str) - check(scan, 'emailOnFinish', str) - check(scan, 'timeoutAction', str) - check(scan, 'scanningVirtualHosts', str) - check(scan, 'rolloverType', str) - check(scan, 'status', str) - check(scan, 'createdTime', str) - check(scan, 'modifiedTime', str) - check(scan, 'reports', list) - check(scan, 'assets', list) - check(scan, 'numDependents', str) - check(scan, 'schedule', dict) - check(scan['schedule'], 'id', str) - check(scan['schedule'], 'type', str) - check(scan['schedule'], 'start', str) - check(scan['schedule'], 'repeatRule', str) - check(scan['schedule'], 'nextRun', int) - check(scan, 'policy', dict) - check(scan['policy'], 'id', str) - check(scan['policy'], 'name', str) - check(scan['policy'], 'description', str) - check(scan, 'policyPrefs', list) - check(scan, 'repository', dict) - check(scan['repository'], 'id', str) - check(scan['repository'], 'name', str) - check(scan['repository'], 'description', str) - check(scan, 'ownerGroup', dict) - check(scan['ownerGroup'], 'id', str) - check(scan['ownerGroup'], 'name', str) - check(scan['ownerGroup'], 'description', str) - check(scan, 'creator', dict) - check(scan['creator'], 'id', str) - check(scan['creator'], 'username', str) - check(scan['creator'], 'firstname', str) - check(scan['creator'], 'lastname', str) - check(scan, 'owner', dict) - check(scan['owner'], 'id', str) - check(scan['owner'], 'username', str) - check(scan['owner'], 'firstname', str) - check(scan['owner'], 'lastname', str) + check(scan, "id", str) + check(scan, "name", str) + check(scan, "description", str) + check(scan, "ipList", str) + check(scan, "type", str) + check(scan, "dhcpTracking", str) + check(scan, "classifyMitigatedAge", str) + check(scan, "emailOnLaunch", str) + check(scan, "emailOnFinish", str) + check(scan, "timeoutAction", str) + check(scan, "scanningVirtualHosts", str) + check(scan, "rolloverType", str) + check(scan, "status", str) + check(scan, "createdTime", str) + check(scan, "modifiedTime", str) + check(scan, "reports", list) + check(scan, "assets", list) + check(scan, "numDependents", str) + check(scan, "schedule", dict) + check(scan["schedule"], "id", str) + check(scan["schedule"], "type", str) + check(scan["schedule"], "start", str) + check(scan["schedule"], "repeatRule", str) + check(scan["schedule"], "nextRun", int) + check(scan, "policy", dict) + check(scan["policy"], "id", str) + check(scan["policy"], "name", str) + check(scan["policy"], "description", str) + check(scan, "policyPrefs", list) + check(scan, "repository", dict) + check(scan["repository"], "id", str) + check(scan["repository"], "name", str) + check(scan["repository"], "description", str) + check(scan, "ownerGroup", dict) + check(scan["ownerGroup"], "id", str) + check(scan["ownerGroup"], "name", str) + check(scan["ownerGroup"], "description", str) + check(scan, "creator", dict) + check(scan["creator"], "id", str) + check(scan["creator"], "username", str) + check(scan["creator"], "firstname", str) + check(scan["creator"], "lastname", str) + check(scan, "owner", dict) + check(scan["owner"], "id", str) + check(scan["owner"], "username", str) + check(scan["owner"], "firstname", str) + check(scan["owner"], "lastname", str) @pytest.mark.vcr() def test_scans_details_for_fields(security_center, scan): - ''' + """ test scans details success for fields - ''' - scan_details = security_center.scans.details(int(scan['id']), fields=['id', 'name', 'description']) + """ + scan_details = security_center.scans.details( + int(scan["id"]), fields=["id", "name", "description"] + ) assert isinstance(scan_details, dict) - check(scan_details, 'id', str) - check(scan_details, 'name', str) - check(scan_details, 'description', str) + check(scan_details, "id", str) + check(scan_details, "name", str) + check(scan_details, "description", str) @pytest.mark.vcr() def test_scans_create(scan): - ''' + """ test scans create for success - ''' + """ assert isinstance(scan, dict) - check(scan, 'id', str) - check(scan, 'name', str) - check(scan, 'description', str) - check(scan, 'ipList', str) - check(scan, 'type', str) - check(scan, 'dhcpTracking', str) - check(scan, 'classifyMitigatedAge', str) - check(scan, 'emailOnLaunch', str) - check(scan, 'emailOnFinish', str) - check(scan, 'timeoutAction', str) - check(scan, 'scanningVirtualHosts', str) - check(scan, 'rolloverType', str) - check(scan, 'status', str) - check(scan, 'createdTime', str) - check(scan, 'modifiedTime', str) - check(scan, 'reports', list) - check(scan, 'assets', list) - check(scan, 'numDependents', str) - check(scan, 'schedule', dict) - check(scan['schedule'], 'id', str) - check(scan['schedule'], 'type', str) - check(scan['schedule'], 'start', str) - check(scan['schedule'], 'repeatRule', str) - check(scan['schedule'], 'nextRun', int) - check(scan, 'policy', dict) - check(scan['policy'], 'id', str) - check(scan['policy'], 'name', str) - check(scan['policy'], 'description', str) - check(scan, 'policyPrefs', list) - check(scan, 'repository', dict) - check(scan['repository'], 'id', str) - check(scan['repository'], 'name', str) - check(scan['repository'], 'description', str) - check(scan, 'ownerGroup', dict) - check(scan['ownerGroup'], 'id', str) - check(scan['ownerGroup'], 'name', str) - check(scan['ownerGroup'], 'description', str) - check(scan, 'creator', dict) - check(scan['creator'], 'id', str) - check(scan['creator'], 'username', str) - check(scan['creator'], 'firstname', str) - check(scan['creator'], 'lastname', str) - check(scan, 'owner', dict) - check(scan['owner'], 'id', str) - check(scan['owner'], 'username', str) - check(scan['owner'], 'firstname', str) - check(scan['owner'], 'lastname', str) + check(scan, "id", str) + check(scan, "name", str) + check(scan, "description", str) + check(scan, "ipList", str) + check(scan, "type", str) + check(scan, "dhcpTracking", str) + check(scan, "classifyMitigatedAge", str) + check(scan, "emailOnLaunch", str) + check(scan, "emailOnFinish", str) + check(scan, "timeoutAction", str) + check(scan, "scanningVirtualHosts", str) + check(scan, "rolloverType", str) + check(scan, "status", str) + check(scan, "createdTime", str) + check(scan, "modifiedTime", str) + check(scan, "reports", list) + check(scan, "assets", list) + check(scan, "numDependents", str) + check(scan, "schedule", dict) + check(scan["schedule"], "id", str) + check(scan["schedule"], "type", str) + check(scan["schedule"], "start", str) + check(scan["schedule"], "repeatRule", str) + check(scan["schedule"], "nextRun", int) + check(scan, "policy", dict) + check(scan["policy"], "id", str) + check(scan["policy"], "name", str) + check(scan["policy"], "description", str) + check(scan, "policyPrefs", list) + check(scan, "repository", dict) + check(scan["repository"], "id", str) + check(scan["repository"], "name", str) + check(scan["repository"], "description", str) + check(scan, "ownerGroup", dict) + check(scan["ownerGroup"], "id", str) + check(scan["ownerGroup"], "name", str) + check(scan["ownerGroup"], "description", str) + check(scan, "creator", dict) + check(scan["creator"], "id", str) + check(scan["creator"], "username", str) + check(scan["creator"], "firstname", str) + check(scan["creator"], "lastname", str) + check(scan, "owner", dict) + check(scan["owner"], "id", str) + check(scan["owner"], "username", str) + check(scan["owner"], "firstname", str) + check(scan["owner"], "lastname", str) @pytest.mark.vcr() def test_scans_create_plugin(security_center): - ''' + """ test scans create plugin for success - ''' - scan = security_center.scans.create('Example Scan 9', 9, - schedule_type='template', - targets=['127.0.0.1'], - plugin_id=1000001) + """ + scan = security_center.scans.create( + "Example Scan 9", + 9, + schedule_type="template", + targets=["127.0.0.1"], + plugin_id=1000001, + ) assert isinstance(scan, dict) - check(scan, 'id', str) - check(scan, 'name', str) - check(scan, 'description', str) - security_center.scans.delete(int(scan['id'])) + check(scan, "id", str) + check(scan, "name", str) + check(scan, "description", str) + security_center.scans.delete(int(scan["id"])) @pytest.mark.vcr() def test_scans_edit(security_center, scan): - ''' + """ test scans edit for success - ''' - scan = security_center.scans.edit(int(scan['id']), name='Edited Example Scan') + """ + scan = security_center.scans.edit(int(scan["id"]), name="Edited Example Scan") assert isinstance(scan, dict) - check(scan, 'id', str) - check(scan, 'name', str) - check(scan, 'description', str) - check(scan, 'ipList', str) - check(scan, 'type', str) - check(scan, 'dhcpTracking', str) - check(scan, 'classifyMitigatedAge', str) - check(scan, 'emailOnLaunch', str) - check(scan, 'emailOnFinish', str) - check(scan, 'timeoutAction', str) - check(scan, 'scanningVirtualHosts', str) - check(scan, 'rolloverType', str) - check(scan, 'status', str) - check(scan, 'createdTime', str) - check(scan, 'modifiedTime', str) - check(scan, 'reports', list) - check(scan, 'assets', list) - check(scan, 'numDependents', str) - check(scan, 'schedule', dict) - check(scan['schedule'], 'id', str) - check(scan['schedule'], 'type', str) - check(scan['schedule'], 'start', str) - check(scan['schedule'], 'repeatRule', str) - check(scan['schedule'], 'nextRun', int) - check(scan, 'policy', dict) - check(scan['policy'], 'id', str) - check(scan['policy'], 'name', str) - check(scan['policy'], 'description', str) - check(scan, 'policyPrefs', list) - check(scan, 'repository', dict) - check(scan['repository'], 'id', str) - check(scan['repository'], 'name', str) - check(scan['repository'], 'description', str) - check(scan, 'ownerGroup', dict) - check(scan['ownerGroup'], 'id', str) - check(scan['ownerGroup'], 'name', str) - check(scan['ownerGroup'], 'description', str) - check(scan, 'creator', dict) - check(scan['creator'], 'id', str) - check(scan['creator'], 'username', str) - check(scan['creator'], 'firstname', str) - check(scan['creator'], 'lastname', str) - check(scan, 'owner', dict) - check(scan['owner'], 'id', str) - check(scan['owner'], 'username', str) - check(scan['owner'], 'firstname', str) - check(scan['owner'], 'lastname', str) + check(scan, "id", str) + check(scan, "name", str) + check(scan, "description", str) + check(scan, "ipList", str) + check(scan, "type", str) + check(scan, "dhcpTracking", str) + check(scan, "classifyMitigatedAge", str) + check(scan, "emailOnLaunch", str) + check(scan, "emailOnFinish", str) + check(scan, "timeoutAction", str) + check(scan, "scanningVirtualHosts", str) + check(scan, "rolloverType", str) + check(scan, "status", str) + check(scan, "createdTime", str) + check(scan, "modifiedTime", str) + check(scan, "reports", list) + check(scan, "assets", list) + check(scan, "numDependents", str) + check(scan, "schedule", dict) + check(scan["schedule"], "id", str) + check(scan["schedule"], "type", str) + check(scan["schedule"], "start", str) + check(scan["schedule"], "repeatRule", str) + check(scan["schedule"], "nextRun", int) + check(scan, "policy", dict) + check(scan["policy"], "id", str) + check(scan["policy"], "name", str) + check(scan["policy"], "description", str) + check(scan, "policyPrefs", list) + check(scan, "repository", dict) + check(scan["repository"], "id", str) + check(scan["repository"], "name", str) + check(scan["repository"], "description", str) + check(scan, "ownerGroup", dict) + check(scan["ownerGroup"], "id", str) + check(scan["ownerGroup"], "name", str) + check(scan["ownerGroup"], "description", str) + check(scan, "creator", dict) + check(scan["creator"], "id", str) + check(scan["creator"], "username", str) + check(scan["creator"], "firstname", str) + check(scan["creator"], "lastname", str) + check(scan, "owner", dict) + check(scan["owner"], "id", str) + check(scan["owner"], "username", str) + check(scan["owner"], "firstname", str) + check(scan["owner"], "lastname", str) @pytest.mark.vcr() def test_scans_delete(scan, security_center): - ''' + """ test scans delete for success - ''' - security_center.scans.delete(int(scan['id'])) + """ + security_center.scans.delete(int(scan["id"])) @pytest.mark.vcr() def test_scans_copy(scan, security_center): - ''' + """ test scans copy for success - ''' - scan = security_center.scans.copy(int(scan['id']), 'scan_copy', 1) - security_center.scans.delete(int(scan['id'])) + """ + scan = security_center.scans.copy(int(scan["id"]), "scan_copy", 1) + security_center.scans.delete(int(scan["id"])) assert isinstance(scan, dict) - check(scan, 'id', str) - check(scan, 'name', str) - check(scan, 'description', str) - check(scan, 'ipList', str) - check(scan, 'type', str) - check(scan, 'dhcpTracking', str) - check(scan, 'classifyMitigatedAge', str) - check(scan, 'emailOnLaunch', str) - check(scan, 'emailOnFinish', str) - check(scan, 'timeoutAction', str) - check(scan, 'scanningVirtualHosts', str) - check(scan, 'rolloverType', str) - check(scan, 'status', str) - check(scan, 'createdTime', str) - check(scan, 'modifiedTime', str) - check(scan, 'reports', list) - check(scan, 'assets', list) - check(scan, 'numDependents', str) - check(scan, 'schedule', dict) - check(scan['schedule'], 'id', str) - check(scan['schedule'], 'type', str) - check(scan['schedule'], 'start', str) - check(scan['schedule'], 'repeatRule', str) - check(scan['schedule'], 'nextRun', int) - check(scan, 'policy', dict) - check(scan['policy'], 'id', str) - check(scan['policy'], 'name', str) - check(scan['policy'], 'description', str) - check(scan, 'policyPrefs', list) - check(scan, 'repository', dict) - check(scan['repository'], 'id', str) - check(scan['repository'], 'name', str) - check(scan['repository'], 'description', str) - check(scan, 'ownerGroup', dict) - check(scan['ownerGroup'], 'id', str) - check(scan['ownerGroup'], 'name', str) - check(scan['ownerGroup'], 'description', str) - check(scan, 'creator', dict) - check(scan['creator'], 'id', str) - check(scan['creator'], 'username', str) - check(scan['creator'], 'firstname', str) - check(scan['creator'], 'lastname', str) - check(scan, 'owner', dict) - check(scan['owner'], 'id', str) - check(scan['owner'], 'username', str) - check(scan['owner'], 'firstname', str) - check(scan['owner'], 'lastname', str) + check(scan, "id", str) + check(scan, "name", str) + check(scan, "description", str) + check(scan, "ipList", str) + check(scan, "type", str) + check(scan, "dhcpTracking", str) + check(scan, "classifyMitigatedAge", str) + check(scan, "emailOnLaunch", str) + check(scan, "emailOnFinish", str) + check(scan, "timeoutAction", str) + check(scan, "scanningVirtualHosts", str) + check(scan, "rolloverType", str) + check(scan, "status", str) + check(scan, "createdTime", str) + check(scan, "modifiedTime", str) + check(scan, "reports", list) + check(scan, "assets", list) + check(scan, "numDependents", str) + check(scan, "schedule", dict) + check(scan["schedule"], "id", str) + check(scan["schedule"], "type", str) + check(scan["schedule"], "start", str) + check(scan["schedule"], "repeatRule", str) + check(scan["schedule"], "nextRun", int) + check(scan, "policy", dict) + check(scan["policy"], "id", str) + check(scan["policy"], "name", str) + check(scan["policy"], "description", str) + check(scan, "policyPrefs", list) + check(scan, "repository", dict) + check(scan["repository"], "id", str) + check(scan["repository"], "name", str) + check(scan["repository"], "description", str) + check(scan, "ownerGroup", dict) + check(scan["ownerGroup"], "id", str) + check(scan["ownerGroup"], "name", str) + check(scan["ownerGroup"], "description", str) + check(scan, "creator", dict) + check(scan["creator"], "id", str) + check(scan["creator"], "username", str) + check(scan["creator"], "firstname", str) + check(scan["creator"], "lastname", str) + check(scan, "owner", dict) + check(scan["owner"], "id", str) + check(scan["owner"], "username", str) + check(scan["owner"], "firstname", str) + check(scan["owner"], "lastname", str) @pytest.mark.vcr() def test_scans_launch(security_center, scan): - ''' + """ test scans launch for success - ''' - launch = security_center.scans.launch(int(scan['id']), diagnostic_target='target', - diagnostic_password='password') + """ + launch = security_center.scans.launch( + int(scan["id"]), diagnostic_target="target", diagnostic_password="password" + ) assert isinstance(launch, dict) - check(launch, 'scanID', str) - check(launch, 'scanResult', dict) - check(launch['scanResult'], 'initiatorID', str) - check(launch['scanResult'], 'ownerID', str) - check(launch['scanResult'], 'scanID', str) - check(launch['scanResult'], 'repositoryID', str) - check(launch['scanResult'], 'jobID', str) - check(launch['scanResult'], 'name', str) - check(launch['scanResult'], 'description', str, allow_none=True) - check(launch['scanResult'], 'details', str) - check(launch['scanResult'], 'status', str) - check(launch['scanResult'], 'downloadFormat', str) - check(launch['scanResult'], 'dataFormat', str) - check(launch['scanResult'], 'id', str) + check(launch, "scanID", str) + check(launch, "scanResult", dict) + check(launch["scanResult"], "initiatorID", str) + check(launch["scanResult"], "ownerID", str) + check(launch["scanResult"], "scanID", str) + check(launch["scanResult"], "repositoryID", str) + check(launch["scanResult"], "jobID", str) + check(launch["scanResult"], "name", str) + check(launch["scanResult"], "description", str, allow_none=True) + check(launch["scanResult"], "details", str) + check(launch["scanResult"], "status", str) + check(launch["scanResult"], "downloadFormat", str) + check(launch["scanResult"], "dataFormat", str) + check(launch["scanResult"], "id", str)