Skip to content

Commit

Permalink
Complete first round of major-version vetting #1228
Browse files Browse the repository at this point in the history
Reference: #1228

Signed-off-by: John M. Horan <johnmhoran@gmail.com>
  • Loading branch information
johnmhoran committed Sep 6, 2023
1 parent 1a26613 commit b626762
Show file tree
Hide file tree
Showing 2 changed files with 186 additions and 132 deletions.
295 changes: 169 additions & 126 deletions vulnerabilities/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -686,18 +686,73 @@ def fixed_package_details(self):
if sib.is_vulnerable is False:
non_vuln_sibs.append(sib)

# Add the greater-than versions to a new list.
univers_version = RANGE_CLASS_BY_SCHEMES[self.type].version_class
print("\nunivers_version = {}".format(univers_version))
# Get the univers version_class for the purl, i.e., the Package the user has searched for.
univers_version_class = RANGE_CLASS_BY_SCHEMES[self.type].version_class
# print("\nunivers_version_class = {}".format(univers_version_class))

# =======================================================
# Get the univers version for the purl.
purl_univers_version = univers_version_class(PackageURL.from_string(self.purl).version)
# print("\n>>> purl_univers_version = {}\n".format(purl_univers_version))
# 2023-09-04 Monday 18:23:51. Is the version just a string I can split?
# print("\n>>> type(purl_univers_version) = {}\n".format(type(purl_univers_version)))
# print(
# "\n>>> type(purl_univers_version.__str__()) = {}\n".format(
# type(purl_univers_version.__str__())
# )
# )
# print(
# "\n>>> purl_univers_version.__str__().split('.')[0] = {}\n".format(
# purl_univers_version.__str__().split(".")[0]
# )
# )

# Convert the univers version for the purl to a string, split the string at each '.', grab the first of these, and convert it to an int -- this is the major version.
purl_univers_version_major_int = int(purl_univers_version.__str__().split(".")[0])
# print("\n>>> purl_univers_version_major_int = {}\n".format(purl_univers_version_major_int))
# print(
# "\n>>> type(purl_univers_version_major_int) = {}\n".format(
# type(purl_univers_version_major_int)
# )
# )

# Create a list for the later non-vuln siblings.
later_non_vuln_sibs = []
# Each non_vuln_sib is a Package.
for non_vuln_sib in non_vuln_sibs:
if univers_version(non_vuln_sib.version) > univers_version(self.version):

# print("\n### type(non_vuln_sib) = {}\n".format(type(non_vuln_sib)))

# Get the univers version for the non_vuln_sib.
non_vuln_sib_univers_version = univers_version_class(
PackageURL.from_string(non_vuln_sib.purl).version
)

# print("\n### non_vuln_sib_univers_version = {}\n".format(non_vuln_sib_univers_version))

# Convert the univers version for the purl to a string, split the string at each '.', grab the first of these, and convert it to an int -- this is the major version.
non_vuln_sib_univers_version_major_int = int(
non_vuln_sib_univers_version.__str__().split(".")[0]
)

# print(
# "\n### non_vuln_sib_univers_version_major_int = {}\n".format(
# non_vuln_sib_univers_version_major_int
# )
# )

# Add it to the 'later_non_vuln_sibs' list if the major versions are the same.
# if univers_version_class(non_vuln_sib.version) > univers_version_class(self.version):
if (
univers_version_class(non_vuln_sib.version) > univers_version_class(self.version)
and purl_univers_version_major_int == non_vuln_sib_univers_version_major_int
):
later_non_vuln_sibs.append(non_vuln_sib)

# Take the list of vulnerabilities affecting the current package, retrieve a list of the fixed
# packages for each, and assign the result to a custom attribute, 'matching_fixed_packages'.
# Ex: qs[0].matching_fixed_packages returns the fixed package(s) for the 1st vulnerability
# for this affected package (i.e., self).
# packages for each (self.get_fixed_packages()), and assign the result to a custom attribute, 'matching_fixed_packages'.
# Ex: qs[0].matching_fixed_packages returns the fixed package(s) for the 1st vulnerability.

qs = qs.prefetch_related(
Prefetch(
"packages",
Expand All @@ -708,170 +763,158 @@ def fixed_package_details(self):

purl_dict = {}
# Pass a PackageURL object to the Jinja2 template via the context dictionary.
# purl_dict["test_purl"] = PackageURL.from_string(self.purl)
# purl_dict.update({"test_vulnerabilities": []})
purl_dict["purl"] = PackageURL.from_string(self.purl)
print("\npurl = {}".format(purl_dict["purl"]))
# print("\npurl = {}".format(purl_dict["purl"]))

purl_univers_version = univers_version(purl_dict["purl"].version)
print("\npurl_univers_version = {}".format(purl_univers_version))
closest_non_vulnerable_sib = ""
latest_non_vulnerable_sib = ""

# ALERT: This throws an error: AttributeError: 'MavenVersion' object has no attribute 'major'
# How do we compare major versions?
# purl_univers_version_major = purl_univers_version.major
# closest_non_vulnerable_sib_non_breaking = ""
# latest_non_vulnerable_sib_non_breaking = ""

# purl_semver_version = versions.SemverVersion(purl_dict["purl"].version)
# print("\npurl_semver_version = {}".format(purl_semver_version))
# We've already filled later_non_vuln_sibs with all non_vuln sibs with the same major
# version as the purl the user is searching for (i.e., self) -- but this could be an empty list.
if len(later_non_vuln_sibs) > 0:
closest_non_vulnerable_sib = self.sort_by_version(later_non_vuln_sibs)[0]
latest_non_vulnerable_sib = self.sort_by_version(later_non_vuln_sibs)[-1]

# purl_semver_version_major = purl_semver_version.major
# print("\npurl_semver_version_major = {}".format(purl_semver_version_major))
purl_dict["closest_non_vulnerable"] = PackageURL.from_string(
closest_non_vulnerable_sib.purl
)
purl_dict["latest_non_vulnerable"] = PackageURL.from_string(
latest_non_vulnerable_sib.purl
)

purl_semver_version_major = versions.SemverVersion(purl_dict["purl"].version).major
print("\npurl_semver_version_major = {}\n".format(purl_semver_version_major))
# print("\nlater_non_vuln_sibs = {}\n".format(later_non_vuln_sibs))

# later_non_vuln_sibs_non_breaking = []
# for non_vuln_sib in later_non_vuln_sibs:
# print("\nnon_vuln_sib = {}\n".format(non_vuln_sib))
# print("\ntype(non_vuln_sib) = {}\n".format(type(non_vuln_sib)))

else:
# closest_non_vulnerable_sib = ""
# latest_non_vulnerable_sib = ""

purl_dict["closest_non_vulnerable"] = None
purl_dict["latest_non_vulnerable"] = None
# ========================================================
# if len(later_non_vuln_sibs) > 0:
# purl_dict["closest_non_vulnerable"] = PackageURL.from_string(
# closest_non_vulnerable_sib.purl
# )
# purl_dict["latest_non_vulnerable"] = PackageURL.from_string(
# latest_non_vulnerable_sib.purl
# )
# else:
# purl_dict["closest_non_vulnerable"] = None
# purl_dict["latest_non_vulnerable"] = None
# ========================================================

# No longer need this.
# purl_univers_version_test = univers_version_class(purl_dict["purl"].version)
# print("\npurl_univers_version_test = {}".format(purl_univers_version_test))

purl_dict.update({"vulnerabilities": []})

# For each vulnerability affecting the current Package...
for vuln in qs:
later_matching_fixed_packages = []
# Pass a Vulnerability object.
# purl_dict["test_vulnerabilities"].append({"test_vulnerability": vuln})
purl_dict["vulnerabilities"].append({"vulnerability": vuln})

# Using the qs prefetch, get a <class 'list'> of all the matching fixed packages for this vulnerability, all major versions to start with.
vuln_matching_fixed_packages = vuln.matching_fixed_packages
# print(
# "\n??? type(vuln_matching_fixed_packages) = {}\n".format(
# type(vuln_matching_fixed_packages)
# )
# )
closest_fixed_package = ""

# ALERT: 2023-09-05 Tuesday 17:42:58. When refreshing a Package details page, I got an error: local variable 'sort_fixed_by_packages_by_version' referenced before assignment (referring to the definition of closest_fixed_package below)
# ALERT: Do I need to define it here?
sort_fixed_by_packages_by_version = []

if len(vuln_matching_fixed_packages) > 0:
for fixed_pkg in vuln_matching_fixed_packages:
if fixed_pkg in matching_fixed_packages and univers_version(
fixed_pkg.version
) > univers_version(self.version):
# fixed_pkg is a 'vulnerabilities.models.Package'
# print("\n!!! type(fixed_pkg) = {}\n".format(type(fixed_pkg)))

# Get the univers version for the fixed_pkg.
fixed_pkg_univers_version = univers_version_class(
PackageURL.from_string(fixed_pkg.purl).version
)

# Convert the univers version for the fixed_pkg to a string, split the string at each '.', grab the first of these, and convert it to an int -- this is the major version.
fixed_pkg_univers_version_major_int = int(
fixed_pkg_univers_version.__str__().split(".")[0]
)

# Add it to the 'later_non_vuln_sibs' list if the major versions are the same.
if (
fixed_pkg in matching_fixed_packages
and univers_version_class(fixed_pkg.version)
> univers_version_class(self.version)
and purl_univers_version_major_int == fixed_pkg_univers_version_major_int
):
later_matching_fixed_packages.append(fixed_pkg)

# We already identified a closest fixed package and are looking for a later fixed package.
if later_matching_fixed_packages:
sort_fixed_by_packages_by_version = self.sort_by_version(
later_matching_fixed_packages
)
print(
"\nsort_fixed_by_packages_by_version = {}\n".format(
sort_fixed_by_packages_by_version
)
)
for fixed_by_pkg in sort_fixed_by_packages_by_version:
print("\nfixed_by_pkg.version = {}\n".format(fixed_by_pkg.version))
purl_from_fixed_by_pkg = PackageURL.from_string(fixed_by_pkg.purl)
print("\npurl_from_fixed_by_pkg = {}\n".format(purl_from_fixed_by_pkg))

print("\nfixed_by_pkg = {}\n".format(fixed_by_pkg))

# purl_semver_version_major = versions.SemverVersion(purl_dict["purl"].version).major
# print("\npurl_semver_version_major = {}\n".format(purl_semver_version_major))

fixed_by_pkg_semver_version_major = versions.SemverVersion(
fixed_by_pkg.version
).major
print(
"\nfixed_by_pkg_semver_version_major = {}\n".format(
fixed_by_pkg_semver_version_major
)
)
# print(
# "\nsort_fixed_by_packages_by_version = {}\n".format(
# sort_fixed_by_packages_by_version
# )
# )

closest_fixed_package = sort_fixed_by_packages_by_version[0]
# ALERT: 2023-09-05 Tuesday 17:53:54. I think these 2 lines need to be indented to be inside the if condition above.
closest_fixed_package = sort_fixed_by_packages_by_version[0]
closest_fixed_package_vulns = closest_fixed_package.affected_by

closest_fixed_package_vulns = closest_fixed_package.affected_by
# closest_fixed_package = sort_fixed_by_packages_by_version[0]
# closest_fixed_package_vulns = closest_fixed_package.affected_by

else:
closest_fixed_package = "There are no reported fixed packages."
# ALERT: 2023-09-05 Tuesday 18:03:46. I don't think we want this string but rather something like None, for the if condition below.
# closest_fixed_package = "There are no reported fixed packages."
closest_fixed_package = None

# for dict_vuln in purl_dict["test_vulnerabilities"]:
for dict_vuln in purl_dict["vulnerabilities"]:
closest_non_vulnerable_sib = ""
# if len(later_non_vuln_sibs) > 0:
# closest_non_vulnerable_sib = self.sort_by_version(later_non_vuln_sibs)[0]
# else:
# closest_non_vulnerable_sib = ""

latest_non_vulnerable_sib = ""
# if len(later_non_vuln_sibs) > 0:
# latest_non_vulnerable_sib = self.sort_by_version(later_non_vuln_sibs)[-1]
# else:
# latest_non_vulnerable_sib = ""

closest_non_vulnerable_sib_non_breaking = ""
latest_non_vulnerable_sib_non_breaking = ""

if len(later_non_vuln_sibs) > 0:
closest_non_vulnerable_sib = self.sort_by_version(later_non_vuln_sibs)[0]
latest_non_vulnerable_sib = self.sort_by_version(later_non_vuln_sibs)[-1]

print("\nlater_non_vuln_sibs = {}\n".format(later_non_vuln_sibs))

later_non_vuln_sibs_non_breaking = []
for non_vuln_sib in later_non_vuln_sibs:
print("\nnon_vuln_sib = {}\n".format(non_vuln_sib))
print("\ntype(non_vuln_sib) = {}\n".format(type(non_vuln_sib)))

# 2023-08-28 Monday 19:19:03. I need to resume here and populate the list later_non_vuln_sibs_non_breaking, then see whether there are any non-breaking versions and in anmy event add 2 more dict entries for the closest non-breaking and latest non-breaking versions.
else:
closest_non_vulnerable_sib = ""
latest_non_vulnerable_sib = ""
# FIXME: 2023-08-30 Wednesday 11:18:43. Got an error when clicking from the Vulnerability details page Fixed by packages tab -- 'str' object has no attribute 'purl'. I think the if condition below needs to be changed from if len(vuln_matching_fixed_packages) > 0: to if len(later_non_vuln_sibs) > 0:. Yes that fixes the error!
# TODO: With the fix above, we also need to consolidate this if with the if below -- both start with "if len(later_non_vuln_sibs) > 0:"

# if dict_vuln["test_vulnerability"] == vuln:
if dict_vuln["vulnerability"] == vuln:

if len(vuln_matching_fixed_packages) > 0:

# dict_vuln["test_fixed_by_purl"] = PackageURL.from_string(
# closest_fixed_package.purl
# )

# dict_vuln["test_fixed_by_purl_vulnerabilities"] = [
# fixed_pkg_vuln for fixed_pkg_vuln in closest_fixed_package_vulns
# ]

# ALERT: 2023-09-05 Tuesday 17:58:24. This is not the correct test because vuln_matching_fixed_packages might contain no major version identical to the purl major version! Instead we want to check whether the closest_fixed_package exists, which we defined above as closest_fixed_package = sort_fixed_by_packages_by_version[0]
# if len(vuln_matching_fixed_packages) > 0:
if closest_fixed_package:
dict_vuln["fixed_by_purl"] = PackageURL.from_string(
closest_fixed_package.purl
)

# ALERT: 2023-09-05 Tuesday 18:00:09. I expect we'll also see an error here and will need to define closest_fixed_package_vulns higher above than where it is currently defined.
dict_vuln["fixed_by_purl_vulnerabilities"] = [
fixed_pkg_vuln for fixed_pkg_vuln in closest_fixed_package_vulns
]
else:

# dict_vuln["test_fixed_by_purl"] = None
# dict_vuln["test_fixed_by_purl_vulnerabilities"] = []

dict_vuln["fixed_by_purl"] = None
dict_vuln["fixed_by_purl_vulnerabilities"] = []

# FIXME: 2023-08-30 Wednesday 11:29:34. Will this handle the error when clicking from the Vulnerability details page Fixed by packages tab -- 'str' object has no attribute 'purl'? Yes!
# TODO: Having fixed this, we also need to conslidate this if with the similar if above.
# if len(vuln_matching_fixed_packages) > 0:
if len(later_non_vuln_sibs) > 0:

# purl_dict["TEST_test_closest_non_vulnerable"] = PackageURL.from_string(
# closest_non_vulnerable_sib.purl
# )
# purl_dict["TEST_test_latest_non_vulnerable"] = PackageURL.from_string(
# latest_non_vulnerable_sib.purl
# )

purl_dict["closest_non_vulnerable"] = PackageURL.from_string(
closest_non_vulnerable_sib.purl
)
purl_dict["latest_non_vulnerable"] = PackageURL.from_string(
latest_non_vulnerable_sib.purl
)

else:

# purl_dict["TEST_test_closest_non_vulnerable"] = None
# purl_dict["TEST_test_latest_non_vulnerable"] = None

purl_dict["closest_non_vulnerable"] = None
purl_dict["latest_non_vulnerable"] = None
# 2023-09-05 Tuesday 15:26:59. Move this chunk up to just under the start of the dict.
# # 2023-08-30 Wednesday 11:29:34. Will this handle the error when clicking from the Vulnerability details page Fixed by packages tab -- 'str' object has no attribute 'purl'? Yes!
# # Having fixed this, we also need to consolidate this if with the similar if above.

# if len(later_non_vuln_sibs) > 0:
# purl_dict["closest_non_vulnerable"] = PackageURL.from_string(
# closest_non_vulnerable_sib.purl
# )
# purl_dict["latest_non_vulnerable"] = PackageURL.from_string(
# latest_non_vulnerable_sib.purl
# )
# else:
# purl_dict["closest_non_vulnerable"] = None
# purl_dict["latest_non_vulnerable"] = None

# Temporary print output during dev/testing.
from pprint import pprint
Expand Down
Loading

0 comments on commit b626762

Please sign in to comment.