Skip to content

Commit a0305cb

Browse files
authored
Feature/oras (#131)
* Support for downloading precompiled image using oras Signed-off-by: Prabhu Subramanian <[email protected]> --------- Signed-off-by: Prabhu Subramanian <[email protected]>
1 parent 153c9e4 commit a0305cb

File tree

7 files changed

+126
-29
lines changed

7 files changed

+126
-29
lines changed

README.md

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -39,22 +39,39 @@ Multiple upstream sources are used by vdb to improve accuracy and reduce false n
3939
## Installation
4040

4141
```shell
42-
pip install appthreat-vulnerability-db>=6.0.0
42+
pip install appthreat-vulnerability-db>=6.0.1
4343
```
4444

45-
VDB v6 is a major rewrite to use sqlite database. Current users of depscan v5 must continue using version 5.6.x
45+
To install vdb with optional dependencies such as `oras` use the `[oras]` or `[all]` dependency group.
4646

4747
```shell
48-
pip install appthreat-vulnerability-db==5.6.6
48+
pip install appthreat-vulnerability-db[all]
49+
```
50+
51+
**NOTE:** VDB v6 is a major rewrite to use sqlite database. Current users of depscan v5 must continue using version 5.6.x
52+
53+
```shell
54+
pip install appthreat-vulnerability-db==5.6.7
4955
```
5056

5157
## Usage
5258

5359
This package is ideal as a library for managing vulnerabilities. This is used by [owasp-dep-scan](http://github.com/owasp-dep-scan/dep-scan), a free open-source dependency audit tool. However, there is a limited cli capability available with few features to test this tool directly.
5460

55-
### Download pre-built database (Recommended)
61+
### Option 1: Download pre-built database (Recommended)
62+
63+
To download a pre-built sqlite database ([refreshed](https://github.com/AppThreat/vdb/actions) every 6 hours) containing all application and OS vulnerabilities. This step is recommended for all users.
64+
65+
```shell
66+
# pip install appthreat-vulnerability-db[all]
67+
vdb --download-image
68+
```
69+
70+
You can execute this command daily or when a fresh database is required.
5671

57-
Use the [ORAS cli](https://oras.land/cli/) to download a pre-built sqlite database ([refreshed](https://github.com/AppThreat/vdb/actions) every 6 hours) containing all application and OS vulnerabilities. This is recommended for all users.
72+
### Option 2: Download pre-built database (ORAS)
73+
74+
Using [ORAS cli](https://oras.land/) might be slightly faster.
5875

5976
```
6077
export VDB_HOME=$HOME/vdb
@@ -73,7 +90,7 @@ Use any sqlite browser or cli tools to load and query the two databases.
7390

7491
<img src="./docs/vdb6.png" alt="database" width="400">
7592

76-
### Manually create the vulnerability database
93+
### Option 3: Manually create the vulnerability database (ADVANCED users)
7794

7895
Cache application vulnerabilities
7996

@@ -102,7 +119,7 @@ It is possible to customize the cache behavior by increasing the historic data p
102119
- NVD_START_YEAR - Default: 2018. Supports up to 2002
103120
- GITHUB_PAGE_COUNT - Default: 2. Supports up to 20
104121

105-
## Usage
122+
## CLI Usage
106123

107124
```shell
108125
usage: vdb [-h] [--clean] [--cache] [--cache-os] [--only-osv] [--only-aqua] [--only-ghsa] [--search SEARCH] [--list-malware] [--bom BOM_FILE]
@@ -120,6 +137,7 @@ options:
120137
--search SEARCH Search for the package or CVE ID in the database. Use purl, cpe, or git http url.
121138
--list-malware List latest malwares with CVE ID beginning with MAL-.
122139
--bom BOM_FILE Search for packages in the CycloneDX BOM file.
140+
--download-image Downloaded pre-created vdb image to platform specific user_data_dir.
123141
```
124142
125143
### CLI search
@@ -158,6 +176,8 @@ vdb --bom bom.json
158176
159177
### List recent malware
160178
179+
To list malware entries with the `MAL-` prefix, use the following command.
180+
161181
```shell
162182
vdb --list-malware
163183
```

pyproject.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "appthreat-vulnerability-db"
3-
version = "6.0.0"
3+
version = "6.0.1"
44
description = "AppThreat's vulnerability database and package search library with a built-in sqlite based storage. OSV, CVE, GitHub, npm are the primary sources of vulnerabilities."
55
authors = [
66
{name = "Team AppThreat", email = "[email protected]"},
@@ -51,6 +51,8 @@ dev = [
5151
"pytest",
5252
"pytest-cov"
5353
]
54+
oras = ["oras"]
55+
all = ["oras"]
5456

5557
[tool.setuptools]
5658
packages = ["vdb", "vdb.lib", "vdb.lib.cve_model"]
@@ -61,3 +63,4 @@ addopts="--showlocals -v --cov-report=term-missing --no-cov-on-fail --cov vdb"
6163
[tool.pylint]
6264
disable = ["broad-exception-caught", "too-many-branches", "too-many-statements", "too-many-nested-blocks", "too-many-locals", "missing-function-docstring", "too-many-lines", "missing-module-docstring"]
6365
ignore-paths = ["vdb/lib/cve_model/*"]
66+
generated-member = ["orjson.loads", "orjson.dumps", "orjson.OPT_NAIVE_UTC"]

vdb/cli.py

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,14 @@
1818
from vdb.lib.gha import GitHubSource
1919
from vdb.lib.osv import OSVSource
2020

21+
ORAS_AVAILABLE = False
22+
# oras is an optional dependency
23+
try:
24+
from vdb.lib.orasclient import download_image
25+
ORAS_AVAILABLE = True
26+
except ImportError:
27+
pass
28+
2129
console = Console()
2230

2331
logging.basicConfig(
@@ -101,6 +109,13 @@ def build_args():
101109
dest="bom_file",
102110
help="Search for packages in the CycloneDX BOM file.",
103111
)
112+
parser.add_argument(
113+
"--download-image",
114+
action="store_true",
115+
default=False,
116+
dest="download_image",
117+
help="Downloaded pre-created vdb image to platform specific user_data_dir.",
118+
)
104119
return parser.parse_args()
105120

106121

@@ -159,7 +174,13 @@ def main():
159174
if args.clean:
160175
if os.path.exists(config.DATA_DIR):
161176
shutil.rmtree(config.DATA_DIR, ignore_errors=True)
162-
if args.cache or args.cache_os:
177+
if args.download_image:
178+
if ORAS_AVAILABLE:
179+
LOG.info("Downloading vdb image from %s to %s", config.VDB_DATABASE_URL, config.DATA_DIR)
180+
download_image(config.VDB_DATABASE_URL, config.DATA_DIR)
181+
else:
182+
console.print("Oras library is not available. Install using pip install appthreat-vulnerability-db[oras] and then re-run this command.")
183+
elif args.cache or args.cache_os:
163184
db_lib.get()
164185
db_lib.clear_all()
165186
if args.only_osv:

vdb/lib/aqua.py

Lines changed: 10 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -143,13 +143,10 @@ def alsa_to_vuln(cve_data):
143143
references = references.decode("utf-8", "ignore")
144144
description = cve_data.get("description", "")
145145
if not description and cve_data.get("title"):
146-
description = """# {}
147-
{}
148-
{}
149-
""".format(
150-
cve_data.get("summary"), cve_data.get("title"), cve_data.get("solution")
151-
)
152-
146+
description = f"""# {cve_data.get("summary")}
147+
{cve_data.get("title")}
148+
{cve_data.get("solution")}
149+
"""
153150
assigner = cve_data.get("fromstr", "")
154151
severity = config.THREAT_TO_SEVERITY[cve_data.get("severity").lower()]
155152
score, severity, vector_string, attack_complexity = get_default_cve_data(
@@ -689,11 +686,9 @@ def photon_to_vuln(cve_data):
689686
pkg_name = cve_data.get("pkg")
690687
cwe_id = ""
691688
references = []
692-
description = """Summary
693-
{}
694-
""".format(
695-
cve_data.get("aff_ver")
696-
)
689+
description = f"""Summary
690+
{cve_data.get("aff_ver")}
691+
"""
697692
assigner = "vmware"
698693
score = cve_data.get("cve_score")
699694
severity = convert_score_severity(score)
@@ -779,12 +774,10 @@ def debian_to_vuln(cve_data):
779774
and ann.get("Type") == "xref"
780775
and ann.get("Bugs")
781776
):
782-
aliases_block = """
777+
aliases_block = f"""
783778
## Related CVE(s)
784-
{}
785-
""".format(
786-
", ".join(ann.get("Bugs"))
787-
)
779+
{", ".join(ann.get("Bugs"))}
780+
"""
788781
description += aliases_block
789782
for bug in ann.get("Bugs"):
790783
if bug.startswith("CVE"):

vdb/lib/config.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,3 +144,6 @@
144144
"coreos",
145145
"ebuild",
146146
)
147+
148+
# URL for the pre-compiled database
149+
VDB_DATABASE_URL = os.getenv("VDB_DATABASE_URL", "ghcr.io/appthreat/vdbxz:v6")

vdb/lib/nvd.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import gzip
33
import logging
44
from collections import defaultdict
5-
from urllib.parse import parse_qs, urlparse
5+
from urllib.parse import urlparse
66

77
import httpx
88
import orjson
@@ -148,7 +148,7 @@ class NvdSource(CVESource):
148148

149149
def download_all(self):
150150
"""Download all historic cve data"""
151-
super.download_all()
151+
super().download_all()
152152
for y in range(now.year, int(start_year) - 1, -1):
153153
data = self.fetch(y)
154154
if not data:
@@ -216,7 +216,6 @@ def bulk_search(self, app_info, pkg_list):
216216
Bulk search the resource instead of downloading the information
217217
:return: Vulnerability result
218218
"""
219-
pass
220219

221220
@staticmethod
222221
def convert_vuln(vuln: dict) -> Vulnerability | None:

vdb/lib/orasclient.py

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import os
2+
import tarfile
3+
4+
import oras.client
5+
import oras.provider
6+
from oras.logger import setup_logger
7+
8+
9+
setup_logger(quiet=True, debug=False)
10+
11+
12+
class VdbDistributionRegistry(oras.provider.Registry):
13+
"""
14+
We override the default registry to make things compatible with ghcr. Without this, the below error is thrown.
15+
16+
jsonschema.exceptions.ValidationError: Additional properties are not allowed ('artifactType' was unexpected)
17+
"""
18+
19+
def get_manifest(self, container, allowed_media_type=None, refresh_headers=True):
20+
"""
21+
Retrieve a manifest for a package.
22+
23+
:param container: parsed container URI
24+
:type container: oras.container.Container or str
25+
:param allowed_media_type: one or more allowed media types
26+
:type allowed_media_type: str
27+
"""
28+
if not allowed_media_type:
29+
allowed_media_type = [oras.defaults.default_manifest_media_type]
30+
headers = {"Accept": ";".join(allowed_media_type)}
31+
32+
get_manifest = f"{self.prefix}://{container.manifest_url()}" # type: ignore
33+
response = self.do_request(get_manifest, "GET", headers=headers)
34+
self._check_200_response(response)
35+
manifest = response.json()
36+
return manifest
37+
38+
39+
def download_image(target, outdir):
40+
"""
41+
Method to download vdb files from a oci registry
42+
"""
43+
oras_client = oras.client.OrasClient(registry=VdbDistributionRegistry())
44+
paths_list = oras_client.pull(
45+
target=target,
46+
outdir=outdir,
47+
allowed_media_type=[],
48+
overwrite=True,
49+
)
50+
for apath in paths_list:
51+
if apath.endswith(".tar.gz") or apath.endswith(".tar.xz"):
52+
with tarfile.open(apath, "r") as tarf:
53+
tarf.extractall(path=outdir)
54+
try:
55+
os.remove(apath)
56+
except OSError:
57+
pass
58+
return paths_list

0 commit comments

Comments
 (0)