diff --git a/bayesian/api/api_v2.py b/bayesian/api/api_v2.py index 58856fe3..f183da4e 100644 --- a/bayesian/api/api_v2.py +++ b/bayesian/api/api_v2.py @@ -91,6 +91,7 @@ def vulnerability_analysis_post(): """ input_json: Dict = request.get_json() ecosystem: str = input_json.get('ecosystem') + ignore_vulnerabilities: Dict = input_json.get('ignore', {}) try: # Step1: Gather and clean Request @@ -98,7 +99,7 @@ def vulnerability_analysis_post(): # Step2: Get aggregated CA data from Query GraphDB, graph_response = get_vulnerability_data(ecosystem, packages_list) # Step3: Build Unknown packages and Generates Stack Recommendation. - stack_recommendation = get_known_pkgs(graph_response, packages_list) + stack_recommendation = get_known_pkgs(graph_response, packages_list, ignore_vulnerabilities) except BadRequest as br: logger.error(br) raise HTTPError(400, str(br)) from br diff --git a/bayesian/utility/v2/component_analyses.py b/bayesian/utility/v2/component_analyses.py index 7044b197..4bb85168 100644 --- a/bayesian/utility/v2/component_analyses.py +++ b/bayesian/utility/v2/component_analyses.py @@ -78,6 +78,12 @@ def validate_input(input_json: Dict, ecosystem: str) -> List[Dict]: error_msg: str = "package_versions is missing" raise BadRequest(error_msg) + ignore_package_vulns = input_json.get('ignore', {}) + if not isinstance(ignore_package_vulns, dict): + error_msg = "Expected a dictionary 'ignore' consisting of package names as key" \ + ", and list of vulnerabilities to ignore for that package as value" + raise BadRequest(error_msg) + packages_list = [] for pkg in input_json.get('package_versions'): package = pkg.get("package") @@ -305,14 +311,31 @@ def clean_package_list(package_details_dict: Dict): return packages_list -def get_known_pkgs(graph_response: Dict, packages_list: Dict) -> List[Dict]: +def get_known_pkgs(graph_response: Dict, packages_list: Dict, ignore_vulnerabilities: Dict) \ + -> List[Dict]: """Analyse Known Packages.""" package_details_dict = {} + for temp in packages_list: temp["vulnerabilities"] = [] package_details_dict[temp["name"]] = temp for vulnerability in graph_response.get('result', {}).get('data'): package_details = package_details_dict.get(vulnerability["package_name"][0]) + vulns_to_ignore = ignore_vulnerabilities.get(vulnerability["package_name"][0], []) + if not isinstance(vulns_to_ignore, list): + error_msg = "Expected list of vulnerabilities to ignore in the 'ignore' " \ + "dictionary as values, where the package name is the key" + raise BadRequest(error_msg) + # if package is in the 'ignore' dict and list of vulnerabilities to + # ignore is empty, ignore the vulnerability + if vulnerability["package_name"][0] in ignore_vulnerabilities and len(vulns_to_ignore) == 0: + continue + # if package is in the 'ignore' dict and list of vulnerabilities + # to ignore is not empty, ignore vulnerability + # if the vulnerability is in the list of vulnerabilities to ignore for that package + if vulnerability["package_name"][0] in ignore_vulnerabilities \ + and vulnerability["snyk_vuln_id"][0] in vulns_to_ignore: + continue if(check_vulnerable_package(package_details["version"], vulnerability['vulnerable_versions'][0])): package_details["vulnerabilities"].append( diff --git a/tests/utility/v2/test_component_analyses.py b/tests/utility/v2/test_component_analyses.py index b65b2e29..e37e524a 100644 --- a/tests/utility/v2/test_component_analyses.py +++ b/tests/utility/v2/test_component_analyses.py @@ -70,28 +70,42 @@ def test_get_known_pkgs_no_cve(self): """Test Known Pkgs, No Cve.""" input_pkgs = [{"name": "markdown2", "version": "2.3.2"}] gremlin_batch_data_no_cve = {"result": {"data": []}} - - stack_recommendation = get_known_pkgs(gremlin_batch_data_no_cve, input_pkgs) + ignore = {} + stack_recommendation = get_known_pkgs(gremlin_batch_data_no_cve, input_pkgs, ignore) ideal_output = [{'name': 'markdown2', 'version': '2.3.2', 'vulnerabilities': []}] self.assertListEqual(stack_recommendation, ideal_output) - def test_get_known_pkgs_with_cve(self): + def test_get_known_pkgs_with_cve_with_ignore(self): """Test Known Pkgs with Cve(VA).""" input_pkgs = [{"name": "st", "version": "0.2.5"}] batch_data_cve = os.path.join('tests/data/gremlin/va.json') with open(batch_data_cve) as f: gremlin_batch_data_cve = json.load(f) + ignore = {"st": ["SNYK-JS-ST-10820"]} + stack_recommendation = get_known_pkgs(gremlin_batch_data_cve, input_pkgs, ignore) + ideal_output = [{'name': 'st', + 'version': '0.2.5', + 'vulnerabilities': [] + }] + self.assertListEqual(stack_recommendation, ideal_output) - stack_recommendation = get_known_pkgs(gremlin_batch_data_cve, input_pkgs) + def test_get_known_pkgs_with_cve(self): + """Test Known Pkgs with Cve(VA).""" + input_pkgs = [{"name": "st", "version": "0.2.5"}] + batch_data_cve = os.path.join('tests/data/gremlin/va.json') + with open(batch_data_cve) as f: + gremlin_batch_data_cve = json.load(f) + ignore = {} + stack_recommendation = get_known_pkgs(gremlin_batch_data_cve, input_pkgs, ignore) ideal_output = [{'name': 'st', 'version': '0.2.5', 'vulnerabilities': [{ "fixed_in": [ - "1.2.2", - "1.2.3", - "1.2.4" + "1.2.2", + "1.2.3", + "1.2.4" ], "id": "SNYK-JS-ST-10820", "severity": "medium",