Skip to content

Commit 2903edc

Browse files
authored
Merge pull request #1058 from TG1999/migrate/istio
Migrate istio importer #1059
2 parents c939ffb + a785ed6 commit 2903edc

File tree

8 files changed

+178
-320
lines changed

8 files changed

+178
-320
lines changed

CHANGELOG.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ Next release
77

88
- We re-enabled support for the mozilla vulnerabilities advisories importer.
99
- We re-enabled support for the gentoo vulnerabilities advisories importer.
10+
- We re-enabled support for the istio vulnerabilities advisories importer.
1011

1112

1213
Version v31.1.1

vulnerabilities/importers/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
from vulnerabilities.importers import gentoo
1616
from vulnerabilities.importers import github
1717
from vulnerabilities.importers import gitlab
18+
from vulnerabilities.importers import istio
1819
from vulnerabilities.importers import mozilla
1920
from vulnerabilities.importers import nginx
2021
from vulnerabilities.importers import npm
@@ -47,6 +48,7 @@
4748
apache_httpd.ApacheHTTPDImporter,
4849
mozilla.MozillaImporter,
4950
gentoo.GentooImporter,
51+
istio.IstioImporter,
5052
]
5153

5254
IMPORTERS_REGISTRY = {x.qualified_name: x for x in IMPORTERS_REGISTRY}

vulnerabilities/importers/istio.py

Lines changed: 89 additions & 125 deletions
Original file line numberDiff line numberDiff line change
@@ -6,165 +6,129 @@
66
# See https://github.com/nexB/vulnerablecode for support or download.
77
# See https://aboutcode.org for more information about nexB OSS projects.
88
#
9-
import asyncio
109
import re
10+
from pathlib import Path
1111
from typing import Set
1212

1313
import pytz
1414
import saneyaml
1515
from dateutil import parser
1616
from packageurl import PackageURL
17-
from univers.version_range import VersionRange
17+
from univers.version_constraint import VersionConstraint
18+
from univers.version_range import GitHubVersionRange
19+
from univers.version_range import GolangVersionRange
1820
from univers.versions import SemverVersion
1921

2022
from vulnerabilities.importer import AdvisoryData
21-
from vulnerabilities.importer import GitImporter
23+
from vulnerabilities.importer import AffectedPackage
24+
from vulnerabilities.importer import Importer
2225
from vulnerabilities.importer import Reference
23-
from vulnerabilities.package_managers import GitHubTagsAPI
24-
from vulnerabilities.utils import nearest_patched_package
2526
from vulnerabilities.utils import split_markdown_front_matter
2627

2728
is_release = re.compile(r"^[\d.]+$", re.IGNORECASE).match
2829

2930

30-
class IstioImporter(GitImporter):
31-
def __enter__(self):
32-
super(IstioImporter, self).__enter__()
31+
class IstioImporter(Importer):
32+
spdx_license_expression = "Apache-2.0"
33+
license_url = "https://github.com/istio/istio.io/blob/master/LICENSE"
34+
repo_url = "git+https://github.com/istio/istio.io/"
3335

34-
if not getattr(self, "_added_files", None):
35-
self._added_files, self._updated_files = self.file_changes(
36-
recursive=True, file_ext="md", subdir="./content/en/news/security"
37-
)
38-
self.version_api = GitHubTagsAPI()
39-
self.set_api()
40-
41-
def set_api(self):
42-
asyncio.run(self.version_api.load_api(["istio/istio"]))
43-
44-
def updated_advisories(self) -> Set[AdvisoryData]:
45-
files = self._added_files.union(self._updated_files)
46-
advisories = []
47-
for f in files:
36+
def advisory_data(self) -> Set[AdvisoryData]:
37+
self.clone(self.repo_url)
38+
path = Path(self.vcs_response.dest_dir)
39+
vuln = path / "content/en/news/security/"
40+
for file in vuln.glob("**/*.md"):
4841
# Istio website has files with name starting with underscore, these contain metadata
4942
# required for rendering the website. We're not interested in these.
5043
# See also https://github.com/nexB/vulnerablecode/issues/563
51-
if f.endswith("_index.md"):
44+
file = str(file)
45+
if file.endswith("_index.md"):
5246
continue
53-
processed_data = self.process_file(f)
54-
if processed_data:
55-
advisories.extend(processed_data)
56-
return self.batch_advisories(advisories)
57-
58-
def get_pkg_versions_from_ranges(self, version_range_list, release_date):
59-
"""Takes a list of version ranges(affected) of a package
60-
as parameter and returns a tuple of safe package versions and
61-
vulnerable package versions"""
62-
all_version = self.version_api.get("istio/istio", release_date).valid_versions
63-
safe_pkg_versions = []
64-
vuln_pkg_versions = []
65-
version_ranges = [
66-
VersionRange.from_scheme_version_spec_string("semver", r) for r in version_range_list
67-
]
68-
for version in all_version:
69-
version_obj = SemverVersion(version)
70-
if any([version_obj in v for v in version_ranges]):
71-
vuln_pkg_versions.append(version)
72-
73-
safe_pkg_versions = set(all_version) - set(vuln_pkg_versions)
74-
return safe_pkg_versions, vuln_pkg_versions
47+
yield from self.process_file(file)
7548

7649
def process_file(self, path):
7750

78-
advisories = []
79-
8051
data = self.get_data_from_md(path)
81-
release_date = parser.parse(data["publishdate"]).replace(tzinfo=pytz.UTC)
82-
83-
releases = []
84-
if data.get("releases"):
85-
for release in data["releases"]:
86-
# If it is of form "All releases prior to x"
87-
if "All releases prior" in release:
88-
release = release.strip()
89-
release = release.split(" ")
90-
releases.append("<" + release[4])
91-
92-
# Eg. 'All releases 1.5 and later'
93-
elif "All releases" in release and "and later" in release:
94-
release = release.split()[2].strip()
95-
releases.append(f">={release}")
96-
97-
elif "to" in release:
98-
release = release.strip()
99-
release = release.split(" ")
100-
lbound = ">=" + release[0]
101-
ubound = "<=" + release[2]
102-
releases.append(lbound + "," + ubound)
103-
# If it is a single release
104-
elif is_release(release):
105-
releases.append(release)
106-
107-
data["release_ranges"] = releases
108-
109-
if not data.get("cves"):
110-
data["cves"] = [""]
111-
112-
for cve_id in data["cves"]:
52+
published_date = data.get("publishdate")
53+
release_date = None
54+
if published_date:
55+
release_date = parser.parse(published_date).replace(tzinfo=pytz.UTC)
56+
57+
constraints = []
58+
59+
for release in data.get("releases") or []:
60+
# If it is of form "All releases prior to x"
61+
if "All releases prior" in release:
62+
_, _, release = release.strip().rpartition(" ")
63+
constraints.append(
64+
VersionConstraint(version=SemverVersion(release), comparator="<")
65+
)
11366

114-
if not cve_id.startswith("CVE"):
115-
cve_id = ""
67+
# Eg. 'All releases 1.5 and later'
68+
elif "All releases" in release and "and later" in release:
69+
# remove All releases from string
70+
release = release.replace("All releases", "").strip()
71+
# remove and later from string
72+
release = release.replace("and later", "").strip()
73+
if not is_release(release):
74+
continue
75+
constraints.append(
76+
VersionConstraint(version=SemverVersion(release), comparator=">=")
77+
)
11678

117-
safe_pkg_versions = []
118-
vuln_pkg_versions = []
79+
# Eg. 1.5 to 2.0
80+
elif "to" in release:
81+
lower, _, upper = release.strip().partition("to")
82+
constraints.append(VersionConstraint(version=SemverVersion(lower), comparator=">="))
83+
constraints.append(VersionConstraint(version=SemverVersion(upper), comparator="<="))
11984

120-
if not data.get("release_ranges"):
121-
data["release_ranges"] = []
85+
# If it is a single release
86+
elif is_release(release):
87+
constraints.append(
88+
VersionConstraint(version=SemverVersion(release), comparator="=")
89+
)
12290

123-
safe_pkg_versions, vuln_pkg_versions = self.get_pkg_versions_from_ranges(
124-
data["release_ranges"], release_date
125-
)
91+
for cve_id in data.get("cves") or []:
92+
93+
if not cve_id.startswith("CVE"):
94+
continue
12695

12796
affected_packages = []
12897

129-
safe_purls_golang = [
130-
PackageURL(type="golang", name="istio", version=version)
131-
for version in safe_pkg_versions
132-
]
133-
134-
vuln_purls_golang = [
135-
PackageURL(type="golang", name="istio", version=version)
136-
for version in vuln_pkg_versions
137-
]
138-
139-
affected_packages.extend(nearest_patched_package(vuln_purls_golang, safe_purls_golang))
140-
141-
safe_purls_github = [
142-
PackageURL(type="github", name="istio", version=version)
143-
for version in safe_pkg_versions
144-
]
145-
146-
vuln_purls_github = [
147-
PackageURL(type="github", name="istio", version=version)
148-
for version in vuln_pkg_versions
149-
]
150-
151-
affected_packages.extend(nearest_patched_package(vuln_purls_github, safe_purls_github))
152-
153-
advisories.append(
154-
AdvisoryData(
155-
vulnerability_id=cve_id,
156-
summary=data["description"],
157-
affected_packages=affected_packages,
158-
references=[
159-
Reference(
160-
reference_id=data["title"],
161-
url=f"https://istio.io/latest/news/security/{data['title']}/",
162-
)
163-
],
98+
if constraints:
99+
affected_packages.append(
100+
AffectedPackage(
101+
package=PackageURL(type="golang", namespace="istio.io", name="istio"),
102+
affected_version_range=GolangVersionRange(constraints=constraints),
103+
)
104+
)
105+
106+
affected_packages.append(
107+
AffectedPackage(
108+
package=PackageURL(type="github", namespace="istio", name="istio"),
109+
affected_version_range=GitHubVersionRange(constraints=constraints),
110+
)
164111
)
165-
)
166112

167-
return advisories
113+
title = data.get("title") or ""
114+
references = []
115+
if title:
116+
references.append(
117+
Reference(
118+
reference_id=title,
119+
url=f"https://istio.io/latest/news/security/{title}/",
120+
)
121+
)
122+
123+
summary = data.get("description") or ""
124+
125+
yield AdvisoryData(
126+
aliases=[cve_id],
127+
summary=summary,
128+
affected_packages=affected_packages,
129+
references=references,
130+
date_published=release_date,
131+
)
168132

169133
def get_data_from_md(self, path):
170134
"""Return a mapping of vulnerability data extracted from an advisory."""

vulnerabilities/improvers/default.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,15 +46,25 @@ def get_inferences(self, advisory_data: AdvisoryData) -> Iterable[Inference]:
4646
for affected_package in advisory_data.affected_packages:
4747
# To deal with multiple fixed versions in a single affected package
4848
affected_purls, fixed_purls = get_exact_purls(affected_package)
49-
for fixed_purl in fixed_purls:
49+
if not fixed_purls:
5050
yield Inference(
5151
aliases=advisory_data.aliases,
5252
confidence=MAX_CONFIDENCE,
5353
summary=advisory_data.summary,
5454
affected_purls=affected_purls,
55-
fixed_purl=fixed_purl,
55+
fixed_purl=None,
5656
references=advisory_data.references,
5757
)
58+
else:
59+
for fixed_purl in fixed_purls or []:
60+
yield Inference(
61+
aliases=advisory_data.aliases,
62+
confidence=MAX_CONFIDENCE,
63+
summary=advisory_data.summary,
64+
affected_purls=affected_purls,
65+
fixed_purl=fixed_purl,
66+
references=advisory_data.references,
67+
)
5868

5969
else:
6070
yield Inference.from_advisory_data(

vulnerabilities/tests/conftest.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ def no_rmtree(monkeypatch):
2929
"test_apache_tomcat.py",
3030
"test_api.py",
3131
"test_elixir_security.py",
32-
"test_istio.py",
3332
"test_models.py",
3433
"test_msr2019.py",
3534
"test_package_managers.py",
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
[
2+
{
3+
"aliases": [
4+
"CVE-2019-12243"
5+
],
6+
"summary": "Incorrect access control.",
7+
"affected_packages": [
8+
{
9+
"package": {
10+
"type": "golang",
11+
"namespace": "istio.io",
12+
"name": "istio",
13+
"version": null,
14+
"qualifiers": null,
15+
"subpath": null
16+
},
17+
"affected_version_range": "vers:golang/<0.0.9|>=1.1.0|<=1.1.15|>=1.3.0|<=1.3.1|>=1.5.0",
18+
"fixed_version": null
19+
},
20+
{
21+
"package": {
22+
"type": "github",
23+
"namespace": "istio",
24+
"name": "istio",
25+
"version": null,
26+
"qualifiers": null,
27+
"subpath": null
28+
},
29+
"affected_version_range": "vers:github/<0.0.9|>=1.1.0|<=1.1.15|>=1.3.0|<=1.3.1|>=1.5.0",
30+
"fixed_version": null
31+
}
32+
],
33+
"references": [
34+
{
35+
"reference_id": "ISTIO-SECURITY-2019-001",
36+
"url": "https://istio.io/latest/news/security/ISTIO-SECURITY-2019-001/",
37+
"severities": []
38+
}
39+
],
40+
"date_published": "2019-05-28T00:00:00+00:00"
41+
}
42+
]

vulnerabilities/tests/test_data/istio/test_file.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ description: Incorrect access control.
55
cves: [CVE-2019-12243]
66
cvss: "8.9"
77
vector: "CVSS:3.0/AV:A/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:N/E:H/RL:O/RC:C"
8-
releases: ["1.1 to 1.1.15", "1.2 to 1.2.6", "1.3 to 1.3.1"]
8+
releases: ["All releases prior to 0.0.9","1.1 to 1.1.15","1.3 to 1.3.1", "All releases 1.5.0 and later"]
99
publishdate: 2019-05-28
1010

1111
---

0 commit comments

Comments
 (0)