Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Version to tag interactivity #294

23 changes: 21 additions & 2 deletions prospector/client/cli/prospector_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,23 @@
core_statistics = execution_statistics.sub_collection("core")


def compute_tag_for_version(tag, version):
results = get_tag_for_version(tag, version)
if results.has_matches():
return results.get_matches()
else:
suggestions = results.get_suggestions()
return interactively_ask_user(
"Could not map supplied version to tag. Please provide mapping by using the '--tag-interval' flag or type it here. Suggestions:"
+ str(suggestions)
)


def interactively_ask_user(message):
_logger.warning(message)
return [str(input())]


# @profile
@measure_execution_time(execution_statistics, name="core")
def prospector( # noqa: C901
Expand Down Expand Up @@ -118,8 +135,10 @@ def prospector( # noqa: C901
prev_tag, following_tag = tag_interval.split(":")
elif version_interval != "":
vuln_version, fixed_version = version_interval.split(":")
prev_tag = get_tag_for_version(tags, vuln_version)[0]
following_tag = get_tag_for_version(tags, fixed_version)[0]
_logger.info("Determining vulnerable version")
prev_tag = compute_tag_for_version(tags, vuln_version)[0]
_logger.info("Determining fixed version")
following_tag = compute_tag_for_version(tags, fixed_version)[0]

since = None
until = None
Expand Down
2 changes: 1 addition & 1 deletion prospector/git/test_git.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ def test_get_tag_for_version():
repo = Git("https://github.com/apache/struts")
repo.clone()
tags = repo.get_tags()
assert get_tag_for_version(tags, "2.3.9") == ["STRUTS_2_3_9"]
assert get_tag_for_version(tags, "2.3.9").get_suggestions() == ["STRUTS_2_3_9"]


# def test_legacy_mapping_version_to_tag_1():
Expand Down
9 changes: 7 additions & 2 deletions prospector/git/test_version_to_tag.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import pytest

from .test_fixtures import tags
from .version_to_tag import get_tag_for_version, recursively_split_version_string
from .version_to_tag import (
recursively_split_version_string,
get_tag_for_version,
)

# flake8: noqa

Expand Down Expand Up @@ -35,4 +38,6 @@ def test_recursively_split_version_string_errors(input_version, error):
)
def test_get_tag_for_version(version, tag, tags):
# returns a list of tags that could be corresponding to the version
assert tag in get_tag_for_version(tags, version)
res = get_tag_for_version(tags, version)
print(res)
assert tag in res.get_matches()
48 changes: 35 additions & 13 deletions prospector/git/version_to_tag.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,32 @@
# flake8: noqa

import difflib
import logging
import log.util


# pylint: disable=singleton-comparison,unidiomatic-typecheck, dangerous-default-value
import re

from .git import Commit, Git

_logger = log.util.init_local_logger()


class ResultsWithSuggestions:
def __init__(self, matches: list = [], suggestions: list = []):
self.matches = matches # exact or high-confidence results
self.suggestions = suggestions # potantially good suggestions

def has_matches(self) -> bool:
return len(self.matches) != 0

def get_matches(self) -> list:
return self.matches

def get_suggestions(self) -> list:
return self.suggestions


def recursively_split_version_string(input_version: str, output_version: list = []):
"""
Expand Down Expand Up @@ -51,14 +71,14 @@ def recursively_split_version_string(input_version: str, output_version: list =
)


def get_tag_for_version(tags, version):
def get_tag_for_version(tags, version) -> ResultsWithSuggestions:
"""
Map a version onto an existing tag
Input:
tags (list): a list of tags to map version onto
version (str): the version
Returns:
list: list with tags that could be the version
ResultsWithSuggestions: class with tags that could be the version (both exact matches and suggestions)
@TODO: only return the most relevant tag i.e. for key 8 version 4.1 returns ['version-3.4.1', 'version-4.1', 'version-4.4.1']
"""
if isinstance(tags, tuple):
Expand Down Expand Up @@ -104,22 +124,23 @@ def get_tag_for_version(tags, version):
elif version in stripped_tags and stripped_tags.count(version) == 1:
tag = tags[stripped_tags.index(version)]
elif version in stripped_tags and stripped_tags.count(version) > 1:
return [
tags[index] for index, tag in enumerate(stripped_tags) if tag == version
]
return ResultsWithSuggestions(
[tags[index] for index, tag in enumerate(stripped_tags) if tag == version]
)
elif (
stripped_version in stripped_tags and stripped_tags.count(stripped_version) == 1
):
tag = tags[stripped_tags.index(stripped_version)]
elif (
stripped_version in stripped_tags and stripped_tags.count(stripped_version) > 1
):
return [
tags[index]
for index, tag in enumerate(stripped_tags)
if tag == stripped_version
]

return ResultsWithSuggestions(
[
tags[index]
for index, tag in enumerate(stripped_tags)
if tag == stripped_version
]
)
else:
version = re.sub("[^0-9]", "", version)
best_match = ("", 0.0)
Expand All @@ -128,8 +149,9 @@ def get_tag_for_version(tags, version):
match_score = difflib.SequenceMatcher(None, t_strip, version).ratio()
if match_score > best_match[1]:
best_match = (tag, match_score)
tag = best_match[0]
return [tag]
tag = [best_match[0]]
return ResultsWithSuggestions(suggestions=tag)
return ResultsWithSuggestions(matches=[tag])


# def get_timestamp_for_tag(tag, git_repo):
Expand Down