def yaml_file_to_advisory(yaml_path): impacted_packages = [] resolved_packages = [] references = [] data = load_yaml(yaml_path) vuln_id = data["vulnerability_id"] summary = "\n".join([note["text"] for note in data["notes"]]) for entry in data.get("artifacts", []): package = PackageURL.from_string(entry["id"]) if entry["affected"]: impacted_packages.append(package) else: resolved_packages.append(package) for fix in data.get("fixes", []): for commit in fix["commits"]: references.append( Reference(url=f"{commit['repository']}/{commit['id']}")) return Advisory( vulnerability_id=vuln_id, summary=summary, impacted_package_urls=impacted_packages, resolved_package_urls=resolved_packages, references=references, )
def collect_packages(self): packages = set() files = self._updated_files.union(self._added_files) for f in files: data = load_yaml(f) if data.get("package"): packages.add(data["package"]) return packages
def process_file(self, path) -> List[Advisory]: record = load_yaml(path) package_name = record.get("gem") if not package_name: return if "cve" in record: cve_id = "CVE-{}".format(record["cve"]) else: return safe_version_ranges = record.get("patched_versions", []) # this case happens when the advisory contain only 'patched_versions' field # and it has value None(i.e it is empty :( ). if not safe_version_ranges: safe_version_ranges = [] safe_version_ranges += record.get("unaffected_versions", []) safe_version_ranges = [i for i in safe_version_ranges if i] if not getattr(self, "pkg_manager_api", None): self.pkg_manager_api = RubyVersionAPI() all_vers = self.pkg_manager_api.get(package_name) safe_versions, affected_versions = self.categorize_versions( all_vers, safe_version_ranges) impacted_purls = { PackageURL( name=package_name, type="gem", version=version, ) for version in affected_versions } resolved_purls = { PackageURL( name=package_name, type="gem", version=version, ) for version in safe_versions } references = [] if record.get("url"): references.append(Reference(url=record.get("url"))) return Advisory( summary=record.get("description", ""), impacted_package_urls=impacted_purls, resolved_package_urls=resolved_purls, references=references, vulnerability_id=cve_id, )
def process_file(self, path): yaml_file = load_yaml(path) pkg_name = yaml_file["package"] safe_pkg_versions = [] vuln_pkg_versions = [] if not yaml_file.get("patched_versions"): yaml_file["patched_versions"] = [] if not yaml_file.get("unaffected_versions"): yaml_file["unaffected_versions"] = [] safe_pkg_versions, vuln_pkg_versions = self.get_versions_for_pkg_from_range_list( yaml_file["patched_versions"] + yaml_file["unaffected_versions"], pkg_name, ) if yaml_file.get("cve"): cve_id = "CVE-" + yaml_file["cve"] else: cve_id = "" safe_purls = [] vuln_purls = [] safe_purls = [ PackageURL(name=pkg_name, type="hex", version=version) for version in safe_pkg_versions ] vuln_purls = [ PackageURL(name=pkg_name, type="hex", version=version) for version in vuln_pkg_versions ] references = [ Reference( reference_id=yaml_file["id"], ), Reference( url=yaml_file["link"], ), ] return Advisory( summary=yaml_file["description"], affected_packages=nearest_patched_package(vuln_purls, safe_purls), vulnerability_id=cve_id, references=references, )
def test_to_advisory(self): raw_data = load_yaml(TEST_DATA) expected_data = [ Advisory( summary="", references=[ Reference( reference_id="", url= "https://ftp.suse.com/pub/projects/security/yaml/suse-cvss-scores.yaml", severities=[ VulnerabilitySeverity( system=ScoringSystem( identifier="cvssv2", name="CVSSv2 Base Score", url="https://www.first.org/cvss/v2/", notes="cvssv2 base score", ), value="4.3", ), VulnerabilitySeverity( system=ScoringSystem( identifier="cvssv2_vector", name="CVSSv2 Vector", url="https://www.first.org/cvss/v2/", notes= "cvssv2 vector, used to get additional info about nature and severity of vulnerability", # nopep8 ), value="AV:N/AC:M/Au:N/C:N/I:N/A:P", ), VulnerabilitySeverity( system=ScoringSystem( identifier="cvssv3.1", name="CVSSv3.1 Base Score", url="https://www.first.org/cvss/v3-1/", notes="cvssv3.1 base score", ), value="3.7", ), VulnerabilitySeverity( system=ScoringSystem( identifier="cvssv3.1_vector", name="CVSSv3.1 Vector", url="https://www.first.org/cvss/v3-1/", notes= "cvssv3.1 vector, used to get additional info about nature and severity of vulnerability", # nopep8 ), value= "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:L", ), ], ) ], vulnerability_id="CVE-2004-0230", ), Advisory( summary="", references=[ Reference( reference_id="", url= "https://ftp.suse.com/pub/projects/security/yaml/suse-cvss-scores.yaml", severities=[ VulnerabilitySeverity( system=ScoringSystem( identifier="cvssv3", name="CVSSv3 Base Score", url="https://www.first.org/cvss/v3-0/", notes="cvssv3 base score", ), value="8.6", ), VulnerabilitySeverity( system=ScoringSystem( identifier="cvssv3_vector", name="CVSSv3 Vector", url="https://www.first.org/cvss/v3-0/", notes= "cvssv3 vector, used to get additional info about nature and severity of vulnerability", # nopep8 ), value= "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:N/A:N", ), ], ) ], vulnerability_id="CVE-2003-1605", ), ] found_data = SUSESeverityScoreDataSource.to_advisory(raw_data) found_advisories = list(map(Advisory.normalized, found_data)) expected_advisories = list(map(Advisory.normalized, expected_data)) assert sorted(found_advisories) == sorted(expected_advisories)