diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index dfadee6..1e56da0 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,11 +1,11 @@ repos: - repo: https://github.com/phantomcyber/dev-cicd-tools - rev: v1.16 + rev: v1.23 hooks: - id: org-hook - id: package-app-dependencies - repo: https://github.com/Yelp/detect-secrets - rev: v1.4.0 + rev: v1.5.0 hooks: - id: detect-secrets args: ['--no-verify', '--exclude-files', '^awsinspector.json$'] diff --git a/LICENSE b/LICENSE index 94b040f..64cc283 100644 --- a/LICENSE +++ b/LICENSE @@ -198,4 +198,4 @@ distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file + limitations under the License. diff --git a/README.md b/README.md index 2074bac..2cab158 100644 --- a/README.md +++ b/README.md @@ -6,12 +6,12 @@ Connector Version: 2.2.11 Product Vendor: AWS Product Name: Inspector Product Version Supported (regex): ".\*" -Minimum Product Version: 5.2.0 +Minimum Product Version: 6.3.0 This app integrates with AWS Inspector to perform security assessment actions [comment]: # " File: README.md" -[comment]: # " Copyright (c) 2019-2022 Splunk Inc." +[comment]: # " Copyright (c) 2019-2024 Splunk Inc." [comment]: # "" [comment]: # "Licensed under the Apache License, Version 2.0 (the 'License');" [comment]: # "you may not use this file except in compliance with the License." diff --git a/awsinspector.json b/awsinspector.json index 49996cd..9e0d528 100644 --- a/awsinspector.json +++ b/awsinspector.json @@ -9,50 +9,18 @@ "product_name": "Inspector", "product_version_regex": ".*", "publisher": "Splunk", - "license": "Copyright (c) 2019-2023 Splunk Inc.", + "license": "Copyright (c) 2019-2024 Splunk Inc.", "app_version": "2.2.11", "utctime_updated": "2022-01-07T21:56:46.000000Z", "package_name": "phantom_awsinspector", "main_module": "awsinspector_connector.py", - "min_phantom_version": "5.2.0", + "min_phantom_version": "6.3.0", "fips_compliant": true, "latest_tested_versions": [ "Cloud tested on July 29th, 2021" ], "python_version": "3", "app_wizard_version": "1.0.0", - "pip_dependencies": { - "wheel": [ - { - "module": "boto3", - "input_file": "wheels/shared/boto3-1.17.30-py2.py3-none-any.whl" - }, - { - "module": "botocore", - "input_file": "wheels/shared/botocore-1.20.30-py2.py3-none-any.whl" - }, - { - "module": "jmespath", - "input_file": "wheels/shared/jmespath-0.10.0-py2.py3-none-any.whl" - }, - { - "module": "python_dateutil", - "input_file": "wheels/shared/python_dateutil-2.8.1-py2.py3-none-any.whl" - }, - { - "module": "s3transfer", - "input_file": "wheels/shared/s3transfer-0.3.7-py2.py3-none-any.whl" - }, - { - "module": "six", - "input_file": "wheels/shared/six-1.16.0-py2.py3-none-any.whl" - }, - { - "module": "urllib3", - "input_file": "wheels/shared/urllib3-1.26.18-py2.py3-none-any.whl" - } - ] - }, "configuration": { "access_key": { "description": "Access Key", @@ -1270,5 +1238,25 @@ }, "versions": "EQ(*)" } - ] + ], + "pip_dependencies": { + "wheel": [ + { + "module": "boto3", + "input_file": "wheels/shared/boto3-1.17.30-py2.py3-none-any.whl" + }, + { + "module": "botocore", + "input_file": "wheels/shared/botocore-1.20.30-py2.py3-none-any.whl" + }, + { + "module": "jmespath", + "input_file": "wheels/shared/jmespath-0.10.0-py2.py3-none-any.whl" + }, + { + "module": "s3transfer", + "input_file": "wheels/shared/s3transfer-0.3.7-py2.py3-none-any.whl" + } + ] + } } diff --git a/awsinspector_connector.py b/awsinspector_connector.py index 8e119fc..69ae78e 100644 --- a/awsinspector_connector.py +++ b/awsinspector_connector.py @@ -21,6 +21,7 @@ import sys import phantom.app as phantom + # Usage of the consts file is recommended import requests from boto3 import Session, client @@ -60,7 +61,7 @@ def __init__(self): self._base_url = None def initialize(self): - """ This is an optional function that can be implemented by the AppConnector derived class. Since the + """This is an optional function that can be implemented by the AppConnector derived class. Since the configuration dictionary is already validated by the time this function is called, it's a good place to do any extra initialization of any internal modules. This function MUST return a value of either phantom.APP_SUCCESS. """ @@ -72,13 +73,13 @@ def initialize(self): self._region = AWSINSPECTOR_REGION_DICT.get(config[AWSINSPECTOR_JSON_REGION]) self._proxy = {} - env_vars = config.get('_reserved_environment_variables', {}) - if 'HTTP_PROXY' in env_vars: - self._proxy['http'] = env_vars['HTTP_PROXY']['value'] - if 'HTTPS_PROXY' in env_vars: - self._proxy['https'] = env_vars['HTTPS_PROXY']['value'] + env_vars = config.get("_reserved_environment_variables", {}) + if "HTTP_PROXY" in env_vars: + self._proxy["http"] = env_vars["HTTP_PROXY"]["value"] + if "HTTPS_PROXY" in env_vars: + self._proxy["https"] = env_vars["HTTPS_PROXY"]["value"] - if config.get('use_role'): + if config.get("use_role"): credentials = self._handle_get_ec2_role() if not credentials: return self.set_status(phantom.APP_ERROR, AWSINSPECTOR_ROLE_CREDENTIALS_FAILURE_MSG) @@ -88,8 +89,8 @@ def initialize(self): return phantom.APP_SUCCESS - self._access_key = config.get('access_key') - self._secret_key = config.get('secret_key') + self._access_key = config.get("access_key") + self._secret_key = config.get("secret_key") if not (self._access_key and self._secret_key): return self.set_status(phantom.APP_ERROR, AWSINSPECTOR_BAD_ASSET_CONFIG_MSG) @@ -97,7 +98,7 @@ def initialize(self): return phantom.APP_SUCCESS def finalize(self): - """ This function gets called once all the param dictionary elements are looped over and no more handle_action + """This function gets called once all the param dictionary elements are looped over and no more handle_action calls are left to be made. It gives the AppConnector a chance to loop through all the results that were accumulated by multiple handle_action function calls and create any summary if required. Another usage is cleanup, disconnect from remote devices etc. @@ -127,12 +128,12 @@ def _create_client(self, action_result, param=None): # Try getting and using temporary assume role credentials from parameters temp_credentials = dict() - if param and 'credentials' in param: + if param and "credentials" in param: try: - temp_credentials = ast.literal_eval(param['credentials']) - self._access_key = temp_credentials.get('AccessKeyId', '') - self._secret_key = temp_credentials.get('SecretAccessKey', '') - self._session_token = temp_credentials.get('SessionToken', '') + temp_credentials = ast.literal_eval(param["credentials"]) + self._access_key = temp_credentials.get("AccessKeyId", "") + self._secret_key = temp_credentials.get("SecretAccessKey", "") + self._session_token = temp_credentials.get("SessionToken", "") self.save_progress("Using temporary assume role credentials for action") except Exception as e: @@ -143,18 +144,16 @@ def _create_client(self, action_result, param=None): self.debug_print("Creating boto3 client with API keys") self._client = client( - 'inspector', - region_name=self._region, - aws_access_key_id=self._access_key, - aws_secret_access_key=self._secret_key, - aws_session_token=self._session_token, - config=boto_config) + "inspector", + region_name=self._region, + aws_access_key_id=self._access_key, + aws_secret_access_key=self._secret_key, + aws_session_token=self._session_token, + config=boto_config, + ) else: self.debug_print("Creating boto3 client without API keys") - self._client = client( - 'inspector', - region_name=self._region, - config=boto_config) + self._client = client("inspector", region_name=self._region, config=boto_config) except Exception as e: return action_result.set_status(phantom.APP_ERROR, "Could not create boto3 client: {0}".format(e)) @@ -177,12 +176,12 @@ def _make_boto_call(self, action_result, method, **kwargs): try: resp_json = boto_func(**kwargs) except Exception as e: - return RetVal(action_result.set_status(phantom.APP_ERROR, 'boto3 call to Inspector failed', e), None) + return RetVal(action_result.set_status(phantom.APP_ERROR, "boto3 call to Inspector failed", e), None) return phantom.APP_SUCCESS, resp_json def _handle_test_connectivity(self, param): - """ This function is used to handle the test connectivity action. + """This function is used to handle the test connectivity action. :param param: Dictionary of input parameters :return: Status(phantom.APP_SUCCESS/phantom.APP_ERROR) @@ -194,7 +193,7 @@ def _handle_test_connectivity(self, param): if phantom.is_fail(self._create_client(action_result, param)): return action_result.get_status() - ret_val, response = self._make_boto_call(action_result, 'list_assessment_targets', maxResults=1) + ret_val, response = self._make_boto_call(action_result, "list_assessment_targets", maxResults=1) if phantom.is_fail(ret_val): self.save_progress("Test Connectivity Failed") @@ -204,7 +203,7 @@ def _handle_test_connectivity(self, param): return action_result.set_status(phantom.APP_SUCCESS) def _handle_list_targets(self, param): - """ This function is used to fetch targets of specific AWS account. + """This function is used to fetch targets of specific AWS account. :param param: Dictionary of input parameters :return: list of targets and their info for the specific AWS account @@ -217,40 +216,42 @@ def _handle_list_targets(self, param): if phantom.is_fail(self._create_client(action_result, param)): return action_result.get_status() - target_name = param.get('target_name') - limit = param.get('limit') + target_name = param.get("target_name") + limit = param.get("limit") if (limit and not str(limit).isdigit()) or limit == 0: return action_result.set_status(phantom.APP_ERROR, AWSINSPECTOR_INVALID_LIMIT) filter = {} if target_name: - filter['assessmentTargetNamePattern'] = target_name + filter["assessmentTargetNamePattern"] = target_name kwargs = {} - kwargs['filter'] = filter + kwargs["filter"] = filter - list_targets = self._paginator('list_assessment_targets', limit, action_result, **kwargs) + list_targets = self._paginator("list_assessment_targets", limit, action_result, **kwargs) if list_targets is None: - return action_result.get_status() + return action_result.get_status() tz = tzlocal() self.debug_print(tz) for target in list_targets: - ret_val, res = self._make_boto_call(action_result, 'describe_assessment_targets', assessmentTargetArns=[target]) + ret_val, res = self._make_boto_call(action_result, "describe_assessment_targets", assessmentTargetArns=[target]) if phantom.is_fail(ret_val): return action_result.get_status() - if res.get('assessmentTargets'): - assessment_target = res.get('assessmentTargets')[0] + if res.get("assessmentTargets"): + assessment_target = res.get("assessmentTargets")[0] else: - failure_code = res.get('failedItems', {}).get(target, {}).get('failureCode') - error_message = failure_code if failure_code else 'Unknown error' - return action_result.set_status(phantom.APP_ERROR, - 'Error occurred while fetching the details of the assessment target: {0}. Error: {1}'.format(target, error_message)) + failure_code = res.get("failedItems", {}).get(target, {}).get("failureCode") + error_message = failure_code if failure_code else "Unknown error" + return action_result.set_status( + phantom.APP_ERROR, + "Error occurred while fetching the details of the assessment target: {0}. Error: {1}".format(target, error_message), + ) for key, value in list(assessment_target.items()): if isinstance(value, datetime.datetime): @@ -259,12 +260,12 @@ def _handle_list_targets(self, param): action_result.add_data(assessment_target) summary = action_result.update_summary({}) - summary['total_targets'] = action_result.get_data_size() + summary["total_targets"] = action_result.get_data_size() return action_result.set_status(phantom.APP_SUCCESS) def _handle_list_templates(self, param): - """ This function is used to fetch templates that correspond to the assessment targets. + """This function is used to fetch templates that correspond to the assessment targets. :param param: Dictionary of input parameters :return: list of templates and their info for the specific AWS account @@ -277,13 +278,13 @@ def _handle_list_templates(self, param): if phantom.is_fail(self._create_client(action_result, param)): return action_result.get_status() - target_arns = param.get('target_arns') - if param.get('target_arns'): - target_arns = [target_arn.strip() for target_arn in target_arns.split(',')] - target_arns = ' '.join(target_arns).split() + target_arns = param.get("target_arns") + if param.get("target_arns"): + target_arns = [target_arn.strip() for target_arn in target_arns.split(",")] + target_arns = " ".join(target_arns).split() - template_name = param.get('template_name') - limit = param.get('limit') + template_name = param.get("template_name") + limit = param.get("limit") if (limit and not str(limit).isdigit()) or limit == 0: return action_result.set_status(phantom.APP_ERROR, AWSINSPECTOR_INVALID_LIMIT) @@ -292,27 +293,29 @@ def _handle_list_templates(self, param): kwargs = {} if target_arns: - kwargs['assessmentTargetArns'] = target_arns + kwargs["assessmentTargetArns"] = target_arns if template_name: - filter['namePattern'] = template_name - kwargs['filter'] = filter + filter["namePattern"] = template_name + kwargs["filter"] = filter - list_templates = self._paginator('list_assessment_templates', limit, action_result, **kwargs) + list_templates = self._paginator("list_assessment_templates", limit, action_result, **kwargs) if list_templates is None: - return action_result.get_status() + return action_result.get_status() for template in list_templates: - ret_val, res = self._make_boto_call(action_result, 'describe_assessment_templates', assessmentTemplateArns=[template]) + ret_val, res = self._make_boto_call(action_result, "describe_assessment_templates", assessmentTemplateArns=[template]) - if res.get('assessmentTemplates'): - assessment_template = res.get('assessmentTemplates')[0] + if res.get("assessmentTemplates"): + assessment_template = res.get("assessmentTemplates")[0] else: - failure_code = res.get('failedItems', {}).get(template, {}).get('failureCode') - error_message = failure_code if failure_code else 'Unknown error' - return action_result.set_status(phantom.APP_ERROR, - 'Error occurred while fetching the details of the assessment template: {0}. Error: {1}'.format(template, error_message)) + failure_code = res.get("failedItems", {}).get(template, {}).get("failureCode") + error_message = failure_code if failure_code else "Unknown error" + return action_result.set_status( + phantom.APP_ERROR, + "Error occurred while fetching the details of the assessment template: {0}. Error: {1}".format(template, error_message), + ) for key, value in list(assessment_template.items()): if isinstance(value, datetime.datetime): @@ -324,13 +327,13 @@ def _handle_list_templates(self, param): action_result.add_data(assessment_template) summary = action_result.update_summary({}) - summary['total_templates'] = action_result.get_data_size() + summary["total_templates"] = action_result.get_data_size() self.save_progress("Handle list templates succeeded") return action_result.set_status(phantom.APP_SUCCESS) def _handle_add_target(self, param): - """ This function is used to create a new assessment target to the specific AWS account. + """This function is used to create a new assessment target to the specific AWS account. :param param: Dictionary of input parameters :return: ARN of the assessment target that is created by this action. @@ -343,35 +346,35 @@ def _handle_add_target(self, param): if phantom.is_fail(self._create_client(action_result, param)): return action_result.get_status() - target_name = param['target_name'] - resource_group_arn = param.get('resource_group_arn') + target_name = param["target_name"] + resource_group_arn = param.get("resource_group_arn") kwargs = {} - kwargs['assessmentTargetName'] = target_name + kwargs["assessmentTargetName"] = target_name - if param.get('resource_group_arn'): - kwargs['resourceGroupArn'] = resource_group_arn + if param.get("resource_group_arn"): + kwargs["resourceGroupArn"] = resource_group_arn - ret_val, response = self._make_boto_call(action_result, 'create_assessment_target', **kwargs) + ret_val, response = self._make_boto_call(action_result, "create_assessment_target", **kwargs) if phantom.is_fail(ret_val): return action_result.get_status() try: - del response['ResponseMetadata'] + del response["ResponseMetadata"] except: pass action_result.add_data(response) summary = action_result.update_summary({}) - summary['total_target_arn'] = action_result.get_data_size() + summary["total_target_arn"] = action_result.get_data_size() self.save_progress("Handle add target succeeded") return action_result.set_status(phantom.APP_SUCCESS, "Target successfully added") def _handle_run_assessment(self, param): - """ This function is used to start the assessment run specified by the ARN of the assessment template. + """This function is used to start the assessment run specified by the ARN of the assessment template. :param param: Dictionary of input parameters :return: ARN of the assessment run and their information @@ -384,37 +387,39 @@ def _handle_run_assessment(self, param): if phantom.is_fail(self._create_client(action_result, param)): return action_result.get_status() - template_arn = param['template_arn'] - assessment_run_name = param.get('assessment_run_name') + template_arn = param["template_arn"] + assessment_run_name = param.get("assessment_run_name") kwargs = {} - kwargs['assessmentTemplateArn'] = template_arn + kwargs["assessmentTemplateArn"] = template_arn - if param.get('assessment_run_name'): - kwargs['assessmentRunName'] = assessment_run_name + if param.get("assessment_run_name"): + kwargs["assessmentRunName"] = assessment_run_name - ret, assessment_run = self._make_boto_call(action_result, 'start_assessment_run', **kwargs) + ret, assessment_run = self._make_boto_call(action_result, "start_assessment_run", **kwargs) if phantom.is_fail(ret): return action_result.get_status() - assessment_run_arn = assessment_run.get('assessmentRunArn') + assessment_run_arn = assessment_run.get("assessmentRunArn") if not assessment_run_arn: - return action_result.get_status() + return action_result.get_status() # for arn in assessment_run_arns: - ret_val, res = self._make_boto_call(action_result, 'describe_assessment_runs', assessmentRunArns=[assessment_run_arn]) + ret_val, res = self._make_boto_call(action_result, "describe_assessment_runs", assessmentRunArns=[assessment_run_arn]) if phantom.is_fail(ret_val): return action_result.get_status() - if res.get('assessmentRuns'): - assessment_run = res.get('assessmentRuns')[0] + if res.get("assessmentRuns"): + assessment_run = res.get("assessmentRuns")[0] else: - failure_code = res.get('failedItems', {}).get(assessment_run_arn, {}).get('failureCode') - error_message = failure_code if failure_code else 'Unknown error' - return action_result.set_status(phantom.APP_ERROR, - 'Error occurred while fetching the details of the assessment run: {0}. Error: {1}'.format(assessment_run_arn, error_message)) + failure_code = res.get("failedItems", {}).get(assessment_run_arn, {}).get("failureCode") + error_message = failure_code if failure_code else "Unknown error" + return action_result.set_status( + phantom.APP_ERROR, + "Error occurred while fetching the details of the assessment run: {0}. Error: {1}".format(assessment_run_arn, error_message), + ) for key, value in list(assessment_run.items()): if isinstance(value, datetime.datetime): @@ -427,20 +432,20 @@ def _handle_run_assessment(self, param): val[k1] = str(v1) try: - del res['ResponseMetadata'] + del res["ResponseMetadata"] except: pass action_result.add_data(assessment_run) summary = action_result.update_summary({}) - summary['assessment_run_arn'] = assessment_run_arn + summary["assessment_run_arn"] = assessment_run_arn self.save_progress("Handle run assessment succeeded") return action_result.set_status(phantom.APP_SUCCESS) def _handle_get_findings(self, param): - """ This function is used to fetch findings that are generated by the assessment runs. + """This function is used to fetch findings that are generated by the assessment runs. :param param: Dictionary of input parameters :return: list of findings and their information @@ -455,64 +460,64 @@ def _handle_get_findings(self, param): filter = {} - assessment_run_arns = param.get('assessment_run_arns') + assessment_run_arns = param.get("assessment_run_arns") - if param.get('assessment_run_arns'): - assessment_run_arns = [assessment_run_arn.strip() for assessment_run_arn in assessment_run_arns.split(',')] - assessment_run_arns = ' '.join(assessment_run_arns).split() + if param.get("assessment_run_arns"): + assessment_run_arns = [assessment_run_arn.strip() for assessment_run_arn in assessment_run_arns.split(",")] + assessment_run_arns = " ".join(assessment_run_arns).split() - severities = param.get('severities') - if param.get('severities'): - severities = [severity.strip() for severity in severities.split(',')] - severities = ' '.join(severities).split() - filter.update({ - 'severities': severities - }) + severities = param.get("severities") + if param.get("severities"): + severities = [severity.strip() for severity in severities.split(",")] + severities = " ".join(severities).split() + filter.update({"severities": severities}) - limit = param.get('limit') + limit = param.get("limit") if (limit and not str(limit).isdigit()) or limit == 0: return action_result.set_status(phantom.APP_ERROR, AWSINSPECTOR_INVALID_LIMIT) kwargs = {} - if param.get('assessment_run_arns'): - kwargs['assessmentRunArns'] = assessment_run_arns - kwargs['filter'] = filter + if param.get("assessment_run_arns"): + kwargs["assessmentRunArns"] = assessment_run_arns + kwargs["filter"] = filter - list_findings = self._paginator('list_findings', limit, action_result, **kwargs) + list_findings = self._paginator("list_findings", limit, action_result, **kwargs) if list_findings is None: - return action_result.get_status() + return action_result.get_status() while list_findings: - ret_val, res = self._make_boto_call(action_result, 'describe_findings', findingArns=list_findings[:min(10, len(list_findings))]) + ret_val, res = self._make_boto_call(action_result, "describe_findings", findingArns=list_findings[: min(10, len(list_findings))]) if phantom.is_fail(ret_val): return action_result.get_status() - findings = res.get('findings') + findings = res.get("findings") if findings: for finding in findings: for key, value in list(finding.items()): if isinstance(value, datetime.datetime): finding[key] = str(value) else: - return action_result.set_status(phantom.APP_ERROR, - 'Error occurred while fetching the details of the findings: {0}'.format(str(list_findings[:min(10, len(list_findings))]))) + return action_result.set_status( + phantom.APP_ERROR, + "Error occurred while fetching the details of the findings: {0}".format(str(list_findings[: min(10, len(list_findings))])), + ) for finding_detail in findings: action_result.add_data(finding_detail) - del list_findings[:min(10, len(list_findings))] + del list_findings[: min(10, len(list_findings))] summary = action_result.update_summary({}) - summary['total_findings'] = action_result.get_data_size() + summary["total_findings"] = action_result.get_data_size() self.save_progress("Handle get findings succeeded") return action_result.set_status(phantom.APP_SUCCESS) def _handle_delete_target(self, param): - """ This function is used to delete the existing assessment target from the specific AWS account. + """This function is used to delete the existing assessment target from the specific AWS account. :param param: Dictionary of input parameters :return: Status (phantom.APP_ERROR/phantom.APP_SUCCESS), target is deleted successfully @@ -525,18 +530,18 @@ def _handle_delete_target(self, param): if phantom.is_fail(self._create_client(action_result, param)): return action_result.get_status() - target_arn = param['target_arn'] + target_arn = param["target_arn"] kwargs = {} - kwargs['assessmentTargetArn'] = target_arn + kwargs["assessmentTargetArn"] = target_arn - ret_val, response = self._make_boto_call(action_result, 'delete_assessment_target', **kwargs) + ret_val, response = self._make_boto_call(action_result, "delete_assessment_target", **kwargs) if phantom.is_fail(ret_val): return action_result.get_status() try: - del response['ResponseMetadata'] + del response["ResponseMetadata"] except: pass @@ -557,21 +562,19 @@ def _paginator(self, method_name, limit, action_result, **kwargs): list_items = list() next_token = None dic_map = { - 'list_targets': 'assessmentTargetArns', - 'list_templates': 'assessmentTemplateArns', - 'get_findings': 'findingArns', - 'delete_target': 'assessmentTargetArns' + "list_targets": "assessmentTargetArns", + "list_templates": "assessmentTemplateArns", + "get_findings": "findingArns", + "delete_target": "assessmentTargetArns", } set_name = dic_map.get(self.get_action_identifier()) while True: if next_token: - ret_val, response = self._make_boto_call(action_result, - method_name, - nextToken=next_token, - maxResults=AWSINSPECTOR_MAX_PER_PAGE_LIMIT, - **kwargs) + ret_val, response = self._make_boto_call( + action_result, method_name, nextToken=next_token, maxResults=AWSINSPECTOR_MAX_PER_PAGE_LIMIT, **kwargs + ) else: ret_val, response = self._make_boto_call(action_result, method_name, maxResults=AWSINSPECTOR_MAX_PER_PAGE_LIMIT, **kwargs) @@ -584,14 +587,14 @@ def _paginator(self, method_name, limit, action_result, **kwargs): if limit and len(list_items) >= limit: return list_items[:limit] - next_token = response.get('nextToken') + next_token = response.get("nextToken") if not next_token: break return list_items def handle_action(self, param): - """ This function gets current action identifier and calls member function of its own to handle the action. + """This function gets current action identifier and calls member function of its own to handle the action. :param param: Dictionary which contains information about the actions to be executed :return: Status(phantom.APP_SUCCESS/phantom.APP_ERROR) @@ -599,13 +602,13 @@ def handle_action(self, param): self.debug_print("action_id", self.get_action_identifier()) # Dictionary mapping each action with its corresponding actions action_mapping = { - 'test_connectivity': self._handle_test_connectivity, - 'list_targets': self._handle_list_targets, - 'list_templates': self._handle_list_templates, - 'add_target': self._handle_add_target, - 'delete_target': self._handle_delete_target, - 'run_assessment': self._handle_run_assessment, - 'get_findings': self._handle_get_findings + "test_connectivity": self._handle_test_connectivity, + "list_targets": self._handle_list_targets, + "list_templates": self._handle_list_templates, + "add_target": self._handle_add_target, + "delete_target": self._handle_delete_target, + "run_assessment": self._handle_run_assessment, + "get_findings": self._handle_get_findings, } action = self.get_action_identifier() @@ -618,7 +621,7 @@ def handle_action(self, param): return action_execution_status -if __name__ == '__main__': +if __name__ == "__main__": import argparse @@ -628,10 +631,10 @@ def handle_action(self, param): argparser = argparse.ArgumentParser() - argparser.add_argument('input_test_json', help='Input Test JSON file') - argparser.add_argument('-u', '--username', help='username', required=False) - argparser.add_argument('-p', '--password', help='password', required=False) - argparser.add_argument('-v', '--verify', action='store_true', help='verify', required=False, default=False) + argparser.add_argument("input_test_json", help="Input Test JSON file") + argparser.add_argument("-u", "--username", help="username", required=False) + argparser.add_argument("-p", "--password", help="password", required=False) + argparser.add_argument("-v", "--verify", action="store_true", help="verify", required=False, default=False) args = argparser.parse_args() session_id = None @@ -640,31 +643,32 @@ def handle_action(self, param): password = args.password verify = args.verify - if (username is not None and password is None): + if username is not None and password is None: # User specified a username but not a password, so ask import getpass + password = getpass.getpass("Password: ") - if (username and password): + if username and password: login_url = BaseConnector._get_phantom_base_url() + "login" try: print("Accessing the Login page") response = requests.get(login_url, verify=verify, timeout=AWSINSPECTOR_DEFAULT_TIMEOUT) - csrftoken = response.cookies['csrftoken'] + csrftoken = response.cookies["csrftoken"] data = dict() - data['username'] = username - data['password'] = password - data['csrfmiddlewaretoken'] = csrftoken + data["username"] = username + data["password"] = password + data["csrfmiddlewaretoken"] = csrftoken headers = dict() - headers['Cookie'] = 'csrftoken={0}'.format(csrftoken) - headers['Referer'] = login_url + headers["Cookie"] = "csrftoken={0}".format(csrftoken) + headers["Referer"] = login_url print("Logging into Platform to get the session id") r2 = requests.post(login_url, verify=verify, data=data, headers=headers, timeout=AWSINSPECTOR_DEFAULT_TIMEOUT) - session_id = r2.cookies['sessionid'] + session_id = r2.cookies["sessionid"] except Exception as e: print("Unable to get session id from the platform. Error: {0}".format(str(e))) sys.exit(1) @@ -677,9 +681,9 @@ def handle_action(self, param): connector = AwsInspectorConnector() connector.print_progress_message = True - if (session_id is not None): - in_json['user_session_token'] = session_id - connector._set_csrf_info(csrftoken, headers['Referer']) + if session_id is not None: + in_json["user_session_token"] = session_id + connector._set_csrf_info(csrftoken, headers["Referer"]) ret_val = connector._handle_action(json.dumps(in_json), None) print(json.dumps(json.loads(ret_val), indent=4)) diff --git a/awsinspector_consts.py b/awsinspector_consts.py index 6dc0022..126aa72 100644 --- a/awsinspector_consts.py +++ b/awsinspector_consts.py @@ -15,23 +15,23 @@ # # # Define your constants here -AWSINSPECTOR_INVALID_LIMIT = 'Please provide non-zero positive integer in limit' +AWSINSPECTOR_INVALID_LIMIT = "Please provide non-zero positive integer in limit" AWSINSPECTOR_MAX_PER_PAGE_LIMIT = 500 AWSINSPECTOR_JSON_REGION = "region" AWSINSPECTOR_REGION_DICT = { - "US East (N. Virginia)": "us-east-1", - "US East (Ohio)": "us-east-2", - "US West (N. California)": "us-west-1", - "US West (Oregon)": "us-west-2", - "Asia Pacific (Mumbai)": "ap-south-1", - "Asia Pacific (Seoul)": "ap-northeast-2", - "Asia Pacific (Singapore)": "ap-southeast-1", - "Asia Pacific (Sydney)": "ap-southeast-2", - "Asia Pacific (Tokyo)": "ap-northeast-1", - "EU (Frankfurt)": "eu-central-1", - "EU (Ireland)": "eu-west-1", - "EU (London)": "eu-west-2", - } -AWSINSPECTOR_BAD_ASSET_CONFIG_MSG = 'Please provide access keys or select assume role check box in asset configuration' -AWSINSPECTOR_ROLE_CREDENTIALS_FAILURE_MSG = 'Failed to retrieve EC2 role credentials from instance' + "US East (N. Virginia)": "us-east-1", + "US East (Ohio)": "us-east-2", + "US West (N. California)": "us-west-1", + "US West (Oregon)": "us-west-2", + "Asia Pacific (Mumbai)": "ap-south-1", + "Asia Pacific (Seoul)": "ap-northeast-2", + "Asia Pacific (Singapore)": "ap-southeast-1", + "Asia Pacific (Sydney)": "ap-southeast-2", + "Asia Pacific (Tokyo)": "ap-northeast-1", + "EU (Frankfurt)": "eu-central-1", + "EU (Ireland)": "eu-west-1", + "EU (London)": "eu-west-2", +} +AWSINSPECTOR_BAD_ASSET_CONFIG_MSG = "Please provide access keys or select assume role check box in asset configuration" +AWSINSPECTOR_ROLE_CREDENTIALS_FAILURE_MSG = "Failed to retrieve EC2 role credentials from instance" AWSINSPECTOR_DEFAULT_TIMEOUT = 30 diff --git a/awsinspector_view.py b/awsinspector_view.py index 40db4c7..15a2c81 100644 --- a/awsinspector_view.py +++ b/awsinspector_view.py @@ -13,7 +13,7 @@ # either express or implied. See the License for the specific language governing permissions # and limitations under the License. def get_ctx_result(provides, result): - """ Function that parses data. + """Function that parses data. :param result: result :param provides: action name @@ -26,22 +26,22 @@ def get_ctx_result(provides, result): summary = result.get_summary() data = result.get_data() - ctx_result['param'] = param + ctx_result["param"] = param if summary: - ctx_result['summary'] = summary - ctx_result['action'] = provides + ctx_result["summary"] = summary + ctx_result["action"] = provides if not data: - ctx_result['data'] = {} + ctx_result["data"] = {} return ctx_result - ctx_result['data'] = data + ctx_result["data"] = data return ctx_result def display_view(provides, all_app_runs, context): - """ Function that displays view. + """Function that displays view. :param provides: action name :param context: context @@ -49,7 +49,7 @@ def display_view(provides, all_app_runs, context): :return: html page """ - context['results'] = results = [] + context["results"] = results = [] for summary, action_results in all_app_runs: for result in action_results: @@ -59,7 +59,7 @@ def display_view(provides, all_app_runs, context): results.append(ctx_result) if provides == "run assessment": - return_page = "awsinspector_run_assessment.html" + return_page = "awsinspector_run_assessment.html" elif provides == "list templates": return_page = "awsinspector_list_templates.html" elif provides == "get findings": diff --git a/manual_readme_content.md b/manual_readme_content.md index 552f7a7..a10d230 100644 --- a/manual_readme_content.md +++ b/manual_readme_content.md @@ -1,5 +1,5 @@ [comment]: # " File: README.md" -[comment]: # " Copyright (c) 2019-2022 Splunk Inc." +[comment]: # " Copyright (c) 2019-2024 Splunk Inc." [comment]: # "" [comment]: # "Licensed under the Apache License, Version 2.0 (the 'License');" [comment]: # "you may not use this file except in compliance with the License." diff --git a/release_notes/unreleased.md b/release_notes/unreleased.md index fbcb2fd..3fdbd0f 100644 --- a/release_notes/unreleased.md +++ b/release_notes/unreleased.md @@ -1 +1,3 @@ **Unreleased** + +* Update urllib3 library due to vulnerability, pre-commit updates [PAPP-34886] \ No newline at end of file diff --git a/tox.ini b/tox.ini index c4644ad..720a141 100644 --- a/tox.ini +++ b/tox.ini @@ -1,7 +1,4 @@ [flake8] max-line-length = 145 max-complexity = 28 -extend-ignore = F403,E128,E126,E111,E121,E127,E731,E201,E202,F405,E722,D,W292 - -[isort] -line_length = 145 +extend-ignore = F403,E128,E126,E121,E127,E731,E201,E202,E203,E701,F405,E722,D,W503 diff --git a/wheels/shared/urllib3-1.26.18-py2.py3-none-any.whl b/wheels/shared/urllib3-1.26.18-py2.py3-none-any.whl deleted file mode 100644 index c7337c7..0000000 Binary files a/wheels/shared/urllib3-1.26.18-py2.py3-none-any.whl and /dev/null differ