|
1 | 1 | import itertools |
2 | 2 | import saneyaml |
| 3 | +from schema import Regex, Or, Schema |
3 | 4 | from urllib.request import urlopen |
4 | 5 | from io import BytesIO |
5 | 6 | from zipfile import ZipFile |
6 | 7 |
|
7 | | -ALPINE_DB_URL = 'https://gitlab.alpinelinux.org/alpine/infra/alpine-secdb/-/\ |
8 | | -archive/master/alpine-secdb-master.zip' |
| 8 | +ALPINE_DB_URL = "https://gitlab.alpinelinux.org/alpine/infra/alpine-secdb/-/\ |
| 9 | +archive/master/alpine-secdb-master.zip" |
9 | 10 |
|
10 | 11 |
|
11 | 12 | def alpine_advisories(url): |
12 | 13 | with urlopen(url) as response: |
13 | 14 | with ZipFile(BytesIO(response.read())) as zf: |
14 | 15 | for path in zf.namelist(): |
15 | | - if path.endswith('main.yaml'): |
| 16 | + if path.endswith("main.yaml"): |
16 | 17 | yield saneyaml.load(zf.open(path)) |
17 | 18 |
|
18 | 19 |
|
| 20 | +def validate_schema(advisory_dict): |
| 21 | + scheme = { |
| 22 | + "distroversion": Regex(r"v\d.\d*"), |
| 23 | + "reponame": "main", |
| 24 | + "archs": list, |
| 25 | + "packages": [ |
| 26 | + { |
| 27 | + "pkg": { |
| 28 | + "name": str, |
| 29 | + "secfixes": { |
| 30 | + str: Or( |
| 31 | + [ |
| 32 | + Or( |
| 33 | + Regex(r"CVE.\d+-\d+"), |
| 34 | + Regex(r"XSA-\d{3}"), |
| 35 | + Regex(r"ZBX-\d{4}"), |
| 36 | + Regex(r"wnpa-sec-\d{4}-\d{2}"), |
| 37 | + ) |
| 38 | + ], |
| 39 | + "", |
| 40 | + ), |
| 41 | + }, |
| 42 | + } |
| 43 | + } |
| 44 | + ], |
| 45 | + object: object, |
| 46 | + } |
| 47 | + Schema(scheme).validate(advisory_dict) |
| 48 | + |
| 49 | + |
19 | 50 | def import_vulnerabilities(): |
20 | 51 | vulnerability_package_dicts = [] |
21 | 52 | for vulnerability in alpine_advisories(ALPINE_DB_URL): |
22 | | - for pkg_details in vulnerability['packages']: |
23 | | - package_name = pkg_details['pkg']['name'] |
24 | | - for version, fixed_cves in pkg_details['pkg']['secfixes'].items(): |
| 53 | + validate_schema(vulnerability) |
| 54 | + for pkg_details in vulnerability["packages"]: |
| 55 | + package_name = pkg_details["pkg"]["name"] |
| 56 | + for version, fixed_cves in pkg_details["pkg"]["secfixes"].items(): |
25 | 57 | # ['CVE-2016-9932 XSA-200', 'CVE-2016-9815','CVE-????-?????'] after mapping |
26 | 58 | # the split function to above list |
27 | 59 | all_cves = list(map(lambda x: x.split(), fixed_cves)) |
28 | 60 | # it becomes [['CVE-2016-9932','XSA-200'], ['CVE-2016-9815'],['CVE-????-?????']] |
29 | 61 | for index, vuln_grp in enumerate(all_cves): |
30 | 62 | all_cves[index] = list( |
31 | | - filter(lambda x: 'CVE-????-?????' not in x, vuln_grp)) |
| 63 | + filter(lambda x: "CVE-????-?????" not in x, vuln_grp) |
| 64 | + ) |
32 | 65 | all_cves = [i for i in all_cves if i and len(i) <= 2] |
33 | 66 | # this data consists lots of 'CVE-????-?????' to denote vulnerabilities |
34 | 67 | # with unassigned CVE ids , we filter out these as well as other garbage data |
35 | 68 | vulnerability_package_dicts.append( |
36 | 69 | { |
37 | | - 'package_name': package_name, |
38 | | - 'vuln_ids': all_cves, |
39 | | - 'fixed_version': version, |
| 70 | + "package_name": package_name, |
| 71 | + "vuln_ids": all_cves, |
| 72 | + "fixed_version": version, |
40 | 73 | } |
41 | 74 | ) |
42 | 75 | return vulnerability_package_dicts |
0 commit comments