owasp-depscan 5.4.8__py3-none-any.whl → 6.0.0a2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of owasp-depscan might be problematic. Click here for more details.

Files changed (34) hide show
  1. depscan/__init__.py +8 -0
  2. depscan/cli.py +719 -827
  3. depscan/cli_options.py +302 -0
  4. depscan/lib/audit.py +3 -1
  5. depscan/lib/bom.py +390 -288
  6. depscan/lib/config.py +86 -337
  7. depscan/lib/explainer.py +363 -98
  8. depscan/lib/license.py +11 -10
  9. depscan/lib/logger.py +65 -17
  10. depscan/lib/package_query/__init__.py +0 -0
  11. depscan/lib/package_query/cargo_pkg.py +124 -0
  12. depscan/lib/package_query/metadata.py +170 -0
  13. depscan/lib/package_query/npm_pkg.py +345 -0
  14. depscan/lib/package_query/pkg_query.py +195 -0
  15. depscan/lib/package_query/pypi_pkg.py +113 -0
  16. depscan/lib/tomlparse.py +116 -0
  17. depscan/lib/utils.py +34 -188
  18. owasp_depscan-6.0.0a2.dist-info/METADATA +390 -0
  19. {owasp_depscan-5.4.8.dist-info → owasp_depscan-6.0.0a2.dist-info}/RECORD +28 -25
  20. {owasp_depscan-5.4.8.dist-info → owasp_depscan-6.0.0a2.dist-info}/WHEEL +1 -1
  21. vendor/choosealicense.com/_licenses/cern-ohl-p-2.0.txt +1 -1
  22. vendor/choosealicense.com/_licenses/cern-ohl-s-2.0.txt +1 -1
  23. vendor/choosealicense.com/_licenses/cern-ohl-w-2.0.txt +2 -2
  24. vendor/choosealicense.com/_licenses/mit-0.txt +1 -1
  25. vendor/spdx/json/licenses.json +904 -677
  26. depscan/lib/analysis.py +0 -1550
  27. depscan/lib/csaf.py +0 -1860
  28. depscan/lib/normalize.py +0 -312
  29. depscan/lib/orasclient.py +0 -142
  30. depscan/lib/pkg_query.py +0 -532
  31. owasp_depscan-5.4.8.dist-info/METADATA +0 -580
  32. {owasp_depscan-5.4.8.dist-info → owasp_depscan-6.0.0a2.dist-info}/entry_points.txt +0 -0
  33. {owasp_depscan-5.4.8.dist-info → owasp_depscan-6.0.0a2.dist-info/licenses}/LICENSE +0 -0
  34. {owasp_depscan-5.4.8.dist-info → owasp_depscan-6.0.0a2.dist-info}/top_level.txt +0 -0
depscan/lib/normalize.py DELETED
@@ -1,312 +0,0 @@
1
- from vdb.lib import KNOWN_PKG_TYPES
2
- from vdb.lib.config import placeholder_exclude_version
3
- from vdb.lib.utils import parse_purl
4
-
5
- from depscan.lib import config
6
-
7
- # Common package suffixes
8
- COMMON_SUFFIXES = [
9
- "-core",
10
- ".core",
11
- "-client-core",
12
- "-classic",
13
- "-api",
14
- "-complete",
15
- "-full",
16
- "-all",
17
- "-ex",
18
- "-server",
19
- ".js",
20
- "-handler",
21
- "apache-",
22
- "-web",
23
- "-broker",
24
- "-netty",
25
- "-plugin",
26
- "-web-console",
27
- "-main",
28
- "-war",
29
- ]
30
-
31
-
32
- def create_pkg_variations(pkg_dict):
33
- """
34
- Method to create variations of the given package by considering vendor
35
- and package aliases
36
-
37
- :param pkg_dict: Dict containing package vendor, name and version
38
- :return: List of possible variations to the package
39
- """
40
- pkg_list = [{**pkg_dict}]
41
- vendor_aliases = set()
42
- name_aliases = set()
43
- vendor = pkg_dict.get("vendor") or ""
44
- name = pkg_dict.get("name") or ""
45
- purl = pkg_dict.get("purl") or ""
46
- pkg_type = ""
47
- name_aliases.add(name)
48
- name_aliases.add(name.lower())
49
- name_aliases.add(name.replace("-", "_"))
50
- os_distro = None
51
- if purl:
52
- try:
53
- purl_obj = parse_purl(purl)
54
- if purl_obj:
55
- pkg_type = purl_obj.get("type")
56
- qualifiers = purl_obj.get("qualifiers", {})
57
- # Issue #320. Mandate version number for generic packages to reduce FPs
58
- if pkg_type in ("generic",) and not purl_obj.get("version"):
59
- return None
60
- if pkg_type in ("npm",):
61
- # vendorless package could have npm as the vendor name from sources such as osv
62
- # So we need 1 more alias
63
- if not purl_obj.get("namespace") and not vendor:
64
- pkg_list.append(
65
- {
66
- "vendor": "npm",
67
- "name": pkg_dict.get("name"),
68
- "version": pkg_dict.get("version"),
69
- }
70
- )
71
- return pkg_list
72
- # For Rubygems, version string could include the plaform.
73
- # So we create an alias without the platform to improve the results
74
- if pkg_type in ("gem",):
75
- for plaform_marker in config.RUBY_PLATFORM_MARKERS:
76
- if pkg_dict.get("version") and plaform_marker in pkg_dict["version"]:
77
- pkg_list.append(
78
- {
79
- "vendor": vendor,
80
- "name": pkg_dict.get("name"),
81
- "version": pkg_dict["version"].split(plaform_marker)[0],
82
- }
83
- )
84
- break
85
- if qualifiers and qualifiers.get("distro_name"):
86
- os_distro_name = qualifiers.get("distro_name")
87
- name_aliases.add(f"""{os_distro_name}/{name}""")
88
- if qualifiers and qualifiers.get("distro"):
89
- os_distro = qualifiers.get("distro")
90
- name_aliases.add(f"""{os_distro}/{name}""")
91
- # almalinux-9.2 becomes almalinux-9
92
- if "-" in os_distro and "." in os_distro:
93
- name_aliases.add(
94
- f"""{os_distro.rsplit(".", 1)[0]}/{name}"""
95
- )
96
- except Exception:
97
- tmp_parts = purl.split(":")
98
- if tmp_parts and len(tmp_parts) > 1:
99
- vendor_aliases.add(tmp_parts[1])
100
- if vendor:
101
- vendor_aliases.add(vendor)
102
- vendor_aliases.add(vendor.lower())
103
- vendor_aliases.add(vendor.lstrip("@"))
104
- # Add some common vendor aliases
105
- if purl.startswith("pkg:golang") and not name.startswith("go"):
106
- vendor_aliases.add("go")
107
- # Ignore third party alternatives for builtins
108
- if "golang" not in vendor and name not in [
109
- "net",
110
- "crypto",
111
- "http",
112
- "text",
113
- ]:
114
- vendor_aliases.add("golang")
115
- if pkg_type not in config.OS_PKG_TYPES:
116
- if not vendor and purl.startswith("pkg:composer"):
117
- vendor_aliases.add("get" + name)
118
- vendor_aliases.add(name + "_project")
119
- for k, v in config.vendor_alias.items():
120
- if vendor and (vendor.startswith(k) or k.startswith(vendor)):
121
- vendor_aliases.add(k)
122
- vendor_aliases.add(v)
123
- elif name == k:
124
- vendor_aliases.add(v)
125
- elif name.startswith(v):
126
- vendor_aliases.add(k)
127
- # This will add false positives to ubuntu
128
- if "/" in name and os_distro and "ubuntu" not in os_distro:
129
- name_aliases.add(name.split("/")[-1])
130
- # Pypi specific vendor aliases
131
- if purl.startswith("pkg:pypi"):
132
- if not name.startswith("python-"):
133
- name_aliases.add("python-" + name)
134
- name_aliases.add("python-" + name + "_project")
135
- # Eg: numpy:numpy
136
- vendor_aliases.add(name)
137
- # Issue #262
138
- # Eg: cpe:2.3:a:microsoft:azure_storage_blobs:*:*:*:*:*:python:*:*
139
- # pypi name is pkg:pypi/azure-storage-blob@12.8.0
140
- # Issue #341 - do not change colorama to coloramas
141
- if not name.endswith("s") and "-" in name:
142
- name_aliases.add(name.replace("-", "_") + "s")
143
- vendor_aliases.add("pip")
144
- vendor_aliases.add("pypi")
145
- vendor_aliases.add("python")
146
- vendor_aliases.add("python-" + name)
147
- elif purl.startswith("pkg:npm"):
148
- # pg-promise CVE is filed as pg
149
- if name.endswith("-promise"):
150
- name_aliases.add(name.replace("-promise", ""))
151
- elif purl.startswith("pkg:crates") and not name.startswith("rust-"):
152
- name_aliases.add("rust-" + name)
153
- elif purl.startswith("pkg:composer") and not name.startswith("php-"):
154
- name_aliases.add("php-" + name)
155
- elif purl.startswith("pkg:nuget"):
156
- vendor_aliases.add("nuget")
157
- name_parts = name.split(".")
158
- vendor_aliases.add(name_parts[0])
159
- vendor_aliases.add(name_parts[0].lower())
160
- # We don't want this to match Microsoft Windows
161
- if "windows" not in name_parts[-1].lower():
162
- name_aliases.add(name_parts[-1])
163
- name_aliases.add(name_parts[-1].lower())
164
- if name.lower().startswith("system"):
165
- vendor_aliases.add("microsoft")
166
- elif purl.startswith("pkg:gem") or purl.startswith("pkg:rubygems"):
167
- vendor_aliases.add("gem")
168
- vendor_aliases.add("rubygems")
169
- vendor_aliases.add("rubyonrails")
170
- elif purl.startswith("pkg:hex") or purl.startswith("pkg:elixir"):
171
- vendor_aliases.add("hex")
172
- vendor_aliases.add("elixir")
173
- elif purl.startswith("pkg:pub") or purl.startswith("pkg:dart"):
174
- vendor_aliases.add("pub")
175
- vendor_aliases.add("dart")
176
- elif purl.startswith("pkg:github"):
177
- vendor_aliases.add("github actions")
178
- name_aliases.add(f"{vendor}/{name}")
179
- if pkg_type not in config.OS_PKG_TYPES:
180
- for suffix in COMMON_SUFFIXES:
181
- if name.endswith(suffix):
182
- name_aliases.add(name.replace(suffix, ""))
183
- # The below aliasing is resulting in several false positives for npm
184
- if pkg_type not in ("npm",):
185
- for k, v in config.package_alias.items():
186
- if (
187
- name.startswith(k)
188
- or k.startswith(name)
189
- or v.startswith(name)
190
- ):
191
- name_aliases.add(k)
192
- name_aliases.add(v)
193
- if pkg_type in config.OS_PKG_TYPES:
194
- if "lib" in name:
195
- name_aliases.add(name.replace("lib", ""))
196
- elif "lib" not in name:
197
- name_aliases.add("lib" + name)
198
- if "-bin" not in name:
199
- name_aliases.add(name + "-bin")
200
- else:
201
- # Filter vendor aliases that are also name aliases
202
- # This is needed for numpy which has the vendor name numpy
203
- # Also needed for nuget. Eg: selenium:selenium
204
- if not purl.startswith("pkg:nuget"):
205
- vendor_aliases = [
206
- x for x in vendor_aliases if x not in name_aliases or x == vendor or config.package_alias.get(x) is not None
207
- ]
208
- if len(vendor_aliases) > 1:
209
- for vvar in list(vendor_aliases):
210
- for nvar in list(name_aliases):
211
- pkg_list.append(
212
- {
213
- "vendor": vvar,
214
- "name": nvar,
215
- "version": pkg_dict.get("version", ""),
216
- }
217
- )
218
- elif len(name_aliases) > 1:
219
- for nvar in list(name_aliases):
220
- # vendor could be none which is fine
221
- pkg_list.append(
222
- {
223
- "vendor": pkg_dict.get("vendor"),
224
- "name": nvar,
225
- "version": pkg_dict.get("version", ""),
226
- }
227
- )
228
- return pkg_list
229
-
230
-
231
- def dealias_packages(pkg_list, pkg_aliases, purl_aliases):
232
- """
233
- Method to dealias package names by looking up vendor and name information
234
- in the aliases list
235
-
236
- :param pkg_list: List of packages to dealias
237
- :param pkg_aliases: A dictionary of package aliases
238
- :param purl_aliases: A dictionary of package URL aliases
239
- :return: Dictionary of dealiased package names and their aliases
240
- """
241
- if not pkg_aliases:
242
- return {}
243
- dealias_dict = {}
244
- for res in pkg_list:
245
- version = None
246
- if res.matched_by:
247
- version = res.matched_by.split("|")[-1]
248
- package_issue = res.package_issue
249
- full_pkg = package_issue.affected_location.package
250
- if package_issue.affected_location.vendor:
251
- full_pkg = (
252
- f"{package_issue.affected_location.vendor}:"
253
- f"{package_issue.affected_location.package}"
254
- )
255
- if version:
256
- full_pkg = full_pkg + ":" + version
257
- if purl_aliases.get(full_pkg):
258
- dealias_dict[full_pkg] = purl_aliases.get(full_pkg)
259
- elif purl_aliases.get(full_pkg.lower()):
260
- dealias_dict[full_pkg] = purl_aliases.get(full_pkg.lower())
261
- else:
262
- for k, v in pkg_aliases.items():
263
- if (
264
- full_pkg in v
265
- or (":" + package_issue.affected_location.package) in v
266
- ) and full_pkg != k:
267
- dealias_dict[full_pkg] = k
268
- break
269
- return dealias_dict
270
-
271
-
272
- def dedup(project_type, pkg_list):
273
- """Method to trim duplicates in the results based on the id. The logic
274
- should ideally be based on package alias but is kept simple for now.
275
-
276
- :param project_type: Project type
277
- :param pkg_list: List of packages to dedup
278
- :return: List of packages with duplicates removed
279
- """
280
- dedup_dict = {}
281
- ret_list = []
282
- for res in pkg_list:
283
- vid = res.id
284
- vuln_occ_dict = res.to_dict()
285
- package_type = vuln_occ_dict.get("type")
286
- package_issue = res.package_issue
287
- fixed_location = package_issue.fixed_location
288
- version = None
289
- if res.matched_by:
290
- version = res.matched_by.split("|")[-1]
291
- full_pkg = package_issue.affected_location.package
292
- if package_issue.affected_location.vendor:
293
- full_pkg = (
294
- f"{package_issue.affected_location.vendor}:"
295
- f"{package_issue.affected_location.package}"
296
- )
297
- if version:
298
- full_pkg = full_pkg + ":" + version
299
- full_pkg = vid + ":" + full_pkg
300
- # Ignore any result with the exclude fix location
301
- # Required for debian
302
- if fixed_location == placeholder_exclude_version:
303
- dedup_dict[full_pkg] = True
304
- continue
305
- allowed_type = config.LANG_PKG_TYPES.get(project_type)
306
- if package_type and package_type in KNOWN_PKG_TYPES and allowed_type:
307
- if allowed_type != package_type:
308
- dedup_dict[full_pkg] = True
309
- if full_pkg not in dedup_dict:
310
- ret_list.append(res)
311
- dedup_dict[full_pkg] = True
312
- return ret_list
depscan/lib/orasclient.py DELETED
@@ -1,142 +0,0 @@
1
- import os
2
- import shutil
3
- import subprocess
4
- import tarfile
5
- import tempfile
6
-
7
- import oras.client
8
- import oras.provider
9
- from oras.logger import setup_logger
10
- from vdb.lib.config import data_dir
11
-
12
- from depscan.lib.config import vdb_database_url, vdb_rafs_database_url
13
- from depscan.lib.logger import LOG
14
-
15
- setup_logger(quiet=True, debug=False)
16
-
17
-
18
- class VdbDistributionRegistry(oras.provider.Registry):
19
- """
20
- We override the default registry to make things compatible with ghcr. Without this, the below error is thrown.
21
-
22
- jsonschema.exceptions.ValidationError: Additional properties are not allowed ('artifactType' was unexpected)
23
- """
24
-
25
- def get_manifest(self, container, allowed_media_type=None, refresh_headers=True):
26
- """
27
- Retrieve a manifest for a package.
28
-
29
- :param container: parsed container URI
30
- :type container: oras.container.Container or str
31
- :param allowed_media_type: one or more allowed media types
32
- :type allowed_media_type: str
33
- """
34
- if not allowed_media_type:
35
- allowed_media_type = [oras.defaults.default_manifest_media_type]
36
- headers = {"Accept": ";".join(allowed_media_type)}
37
-
38
- get_manifest = f"{self.prefix}://{container.manifest_url()}" # type: ignore
39
- response = self.do_request(get_manifest, "GET", headers=headers)
40
- self._check_200_response(response)
41
- manifest = response.json()
42
- return manifest
43
-
44
-
45
- def download_rafs_based_image():
46
- """
47
- Method to download RAFS based vdb files from a oci registry
48
- """
49
- rafs_image_downloaded, paths_list = False, None
50
- nydus_image_command = shutil.which("nydus-image", mode=os.X_OK)
51
- if nydus_image_command is not None:
52
- LOG.info(
53
- "About to download the vulnerability database from %s. This might take a while ...",
54
- vdb_rafs_database_url,
55
- )
56
-
57
- try:
58
- oras_client = oras.client.OrasClient(
59
- registry=VdbDistributionRegistry()
60
- )
61
- rafs_data_dir = tempfile.TemporaryDirectory()
62
- paths_list = oras_client.pull(
63
- target=vdb_rafs_database_url,
64
- outdir=rafs_data_dir.name,
65
- allowed_media_type=[],
66
- overwrite=True,
67
- )
68
-
69
- if (
70
- paths_list
71
- and os.path.exists(
72
- os.path.join(rafs_data_dir.name, "data.rafs")
73
- )
74
- and os.path.exists(
75
- os.path.join(rafs_data_dir.name, "meta.rafs")
76
- )
77
- ):
78
- nydus_download_command = [
79
- f"{nydus_image_command}",
80
- "unpack",
81
- "--blob",
82
- os.path.join(rafs_data_dir.name, "data.rafs"),
83
- "--output",
84
- os.path.join(data_dir, "vdb.tar"),
85
- "--bootstrap",
86
- os.path.join(rafs_data_dir.name, "meta.rafs"),
87
- ]
88
- _ = subprocess.run(
89
- nydus_download_command,
90
- check=True,
91
- stdout=subprocess.DEVNULL,
92
- stderr=subprocess.DEVNULL,
93
- )
94
- if os.path.exists(os.path.join(data_dir, "vdb.tar")):
95
- rafs_image_downloaded = True
96
- with tarfile.open(
97
- os.path.join(data_dir, "vdb.tar"), "r"
98
- ) as tarf:
99
- tarf.extractall(path=data_dir)
100
- os.remove(os.path.join(data_dir, "vdb.tar"))
101
- else:
102
- raise FileNotFoundError("vdb.tar not found")
103
- else:
104
- raise FileNotFoundError("data.rafs or meta.rafs not found")
105
-
106
- except Exception:
107
- LOG.info(
108
- "Unable to pull the vulnerability database (rafs image) from %s. Trying to pull the non-rafs-based VDB image.",
109
- vdb_rafs_database_url,
110
- )
111
- rafs_image_downloaded = False
112
-
113
- return rafs_image_downloaded, data_dir
114
-
115
-
116
- def download_image():
117
- """
118
- Method to download vdb files from a oci registry
119
- """
120
- rafs_image_downloaded, paths_list = download_rafs_based_image()
121
- if rafs_image_downloaded:
122
- return paths_list
123
- LOG.info(
124
- "About to download the vulnerability database from %s. This might take a while ...",
125
- vdb_database_url,
126
- )
127
- oras_client = oras.client.OrasClient(registry=VdbDistributionRegistry())
128
- paths_list = oras_client.pull(
129
- target=vdb_database_url,
130
- outdir=data_dir,
131
- allowed_media_type=[],
132
- overwrite=True,
133
- )
134
- for apath in paths_list:
135
- if apath.endswith(".tar.gz"):
136
- with tarfile.open(apath, "r") as tarf:
137
- tarf.extractall(path=data_dir)
138
- try:
139
- os.remove(apath)
140
- except OSError:
141
- pass
142
- return paths_list