diff --git a/bayesian/utils.py b/bayesian/utils.py index 3ace1792..f702b429 100644 --- a/bayesian/utils.py +++ b/bayesian/utils.py @@ -12,6 +12,7 @@ import shutil import hashlib import zipfile +import logging from io import BytesIO from functools import lru_cache @@ -38,6 +39,8 @@ from github import Github, BadCredentialsException, GithubException, RateLimitExceededException from git import Repo, Actor +logger = logging.getLogger(__file__) + # TODO remove hardcoded gremlin_url when moving to Production This is just # a stop-gap measure for demo @@ -349,47 +352,52 @@ def get_analyses_from_graph(ecosystem, package, version): if graph_req is not None: resp = graph_req.json() + result_data = resp['result'].get('data') - if not (resp['result'].get('data') and len(resp['result'].get('data')) > 0): + if not (result_data and len(result_data) > 0): # trigger unknown component flow in API for missing package return None clubbed_data.append({ - "epv": resp['result']['data'] + "epv": result_data }) - if "cve" in resp['result'].get('data')[0]: - script2 = """\ -g.V().has('pecosystem', ecosystem).has('pname', name).has('version', version)\ -.in('has_version').out('has_version').not(out('has_cve')).values('version').dedup();\ -""" - payload = { - 'gremlin': script2, - 'bindings': { - 'ecosystem': ecosystem, - 'name': package, - 'version': version - } - } - - graph_req2 = post(gremlin_url, data=json.dumps(payload)) - if graph_req2 is not None: - resp2 = graph_req2.json() + if "cve" in result_data[0]: + if "latest_non_cve_version" in result_data[0]['package']: clubbed_data.append({ - "recommended_versions": resp2['result']['data'] + "recommended_versions": result_data[0]['package']['latest_non_cve_version'] }) + else: + script2 = "g.V().has('pecosystem', ecosystem).has('pname', name)" \ + ".has('version', version).in('has_version')" \ + ".out('has_version').not(out('has_cve')).values('version').dedup();" + payload = { + 'gremlin': script2, + 'bindings': { + 'ecosystem': ecosystem, + 'name': package, + 'version': version + } + } + + graph_req2 = post(gremlin_url, data=json.dumps(payload)) + if graph_req2 is not None: + resp2 = graph_req2.json() + clubbed_data.append({ + "recommended_versions": resp2['result']['data'] + }) else: clubbed_data.append({ "recommended_versions": [] }) except Exception as e: - current_app.logger.debug(' '.join([type(e), ':', str(e)])) + logger.debug(' '.join([type(e), ':', str(e)])) return None finally: elapsed_seconds = (datetime.datetime.now() - start).total_seconds() epv = "{e}/{p}/{v}".format(e=ecosystem, p=package, v=version) - current_app.logger.debug("Gremlin request {p} took {t} seconds.".format(p=epv, - t=elapsed_seconds)) + logger.debug("Gremlin request {p} took {t} seconds.".format(p=epv, + t=elapsed_seconds)) resp = generate_recommendation(clubbed_data, package, version) return resp diff --git a/tests/test_utils.py b/tests/test_utils.py index 09c25bdf..74deccb5 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -21,7 +21,8 @@ CveByDateEcosystemUtils, resolved_files_exist, get_ecosystem_from_manifest, - check_for_accepted_ecosystem + check_for_accepted_ecosystem, + get_analyses_from_graph ) from f8a_worker.enums import EcosystemBackend from f8a_worker.models import Analysis, Ecosystem, Package, Version, WorkerResult @@ -61,6 +62,33 @@ } } +non_cve_input = { + "result": { + "data": [ + { + "cve": { + "ecosystem": ["npm"], + "cve_id": ["CVE-2018-0001"], + "cvss_v2": [10.0], + "nvd_status": ["Awaiting Analyses"], + "description": ["Some description here updated just now."], + "modified_date": ["20180911"] + }, + "version": { + "pname": ["lodash"], + "version": ["4.17.4"], + "pecosystem": ["npm"] + }, + "package": { + "name": ["lodash"], + "latest_non_cve_version": ["4.17.11"], + "pecosystem": ["npm"] + } + } + ] + } +} + @pytest.fixture def analyses(app): @@ -445,3 +473,12 @@ def test_check_for_accepted_ecosystem(): resp = check_for_accepted_ecosystem("abcd") assert not resp + + +@patch("bayesian.utils.post") +def test_get_analyses_from_graph(mocker): + """Test the get_analyses_from_graph function.""" + mocker.return_value = mock_response = Mock() + mock_response.json.return_value = non_cve_input + resp = get_analyses_from_graph("npm", "lodash", "4.17.4") + assert resp['result']['recommendation']['change_to'] == "4.17.11"