|
2 | 2 | # SPDX-License-Identifier: GPL-3.0-or-later
|
3 | 3 |
|
4 | 4 | import json
|
| 5 | +import re |
| 6 | +from json.decoder import JSONDecodeError |
| 7 | +from urllib.parse import urlparse |
5 | 8 |
|
6 | 9 | from cve_bin_tool.parsers import Parser
|
7 | 10 |
|
8 | 11 |
|
9 | 12 | class SwiftParser(Parser):
|
| 13 | + """ |
| 14 | + Parser implementation for Swift dependency files (Package.resolved). |
| 15 | +
|
| 16 | + This parser is designed to parse Swift dependencies files and generate Package URL (PURL) strings |
| 17 | + based on the modules and their dependencies listed in the file. |
| 18 | +
|
| 19 | + Attributes: |
| 20 | + cve_db (CVEDB): The CVE database instance used for vulnerability information. |
| 21 | + logger (Logger): The logger instance for logging messages and debugging information. |
| 22 | +
|
| 23 | + Methods: |
| 24 | + generate_purl(product, version, vendor): |
| 25 | + Generates PURL after normalizing all components. |
| 26 | + run_checker(filename): |
| 27 | + Parse the Swift dependency file and yield valid PURLs for the modules listed in the file. |
| 28 | +
|
| 29 | + """ |
| 30 | + |
10 | 31 | def __init__(self, cve_db, logger):
|
11 | 32 | super().__init__(cve_db, logger)
|
| 33 | + self.purl_pkg_type = "swift" |
| 34 | + |
| 35 | + def generate_purl(self, product, version, vendor, qualifier={}, subpath=None): |
| 36 | + """Generates PURL after normalizing all components.""" |
| 37 | + |
| 38 | + product = re.sub(r"[^a-zA-Z0-9_-]", "", product) |
| 39 | + version = re.sub(r"[^a-zA-Z0-9.+-]", "", version) |
| 40 | + |
| 41 | + if not re.match(r"[a-zA-Z0-9_-]", product): |
| 42 | + return |
| 43 | + if not vendor: |
| 44 | + vendor = "UNKNOWN" |
| 45 | + if not version: |
| 46 | + version = "UNKNOWN" |
| 47 | + |
| 48 | + purl = super().generate_purl( |
| 49 | + product, |
| 50 | + version, |
| 51 | + vendor, |
| 52 | + qualifier, |
| 53 | + subpath, |
| 54 | + ) |
| 55 | + |
| 56 | + return purl |
12 | 57 |
|
13 | 58 | def run_checker(self, filename):
|
| 59 | + """Parse the file and yield valid PURLs.""" |
14 | 60 | self.filename = filename
|
15 | 61 | with open(self.filename) as fh:
|
16 | 62 | # parse the json structure for extracting product version pairs
|
17 |
| - content = json.load(fh) |
| 63 | + try: |
| 64 | + content = json.load(fh) |
| 65 | + except JSONDecodeError as e: |
| 66 | + self.logger.debug(f"Error occurred while parsing {filename}: {e}") |
| 67 | + return |
18 | 68 | for package in content["object"]["pins"]:
|
19 | 69 | product = package["package"]
|
20 | 70 | version = package["state"]["version"]
|
21 |
| - vendor = self.find_vendor(product, version) |
22 |
| - if vendor is not None: |
23 |
| - yield from vendor |
| 71 | + repository_url = package.get("repositoryURL", None) |
| 72 | + domain = None |
| 73 | + if repository_url: |
| 74 | + parse = urlparse(repository_url) |
| 75 | + domain = parse.netloc |
| 76 | + self.logger.debug(domain) |
| 77 | + |
| 78 | + vendors = self.find_vendor(product, version) |
| 79 | + if vendors is not None: |
| 80 | + yield from vendors |
24 | 81 | self.logger.debug(f"Done scanning file: {self.filename}")
|
0 commit comments