def __enter__(self):
        super(RubyDataSource, self).__enter__()

        if not getattr(self, "_added_files", None):
            self._added_files, self._updated_files = self.file_changes(
                recursive=True, file_ext="yml", subdir="./gems")

        self.pkg_manager_api = RubyVersionAPI()
        self.set_api(self.collect_packages())
Exemple #2
0
    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) -> 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,
                        vuln_references=references,
                        cve_id=cve_id)
Exemple #4
0
 def setUpClass(cls):
     data_source_cfg = {
         "repository_url":
         "https://github.com/rubysec/ruby-advisory-db.git",
     }
     cls.data_src = RubyDataSource(1, config=data_source_cfg)
     cls.data_src.pkg_manager_api = RubyVersionAPI()
class RubyDataSource(GitDataSource):
    def __enter__(self):
        super(RubyDataSource, self).__enter__()

        if not getattr(self, "_added_files", None):
            self._added_files, self._updated_files = self.file_changes(
                recursive=True, file_ext="yml", subdir="./gems")

        self.pkg_manager_api = RubyVersionAPI()
        self.set_api(self.collect_packages())

    def set_api(self, packages):
        asyncio.run(self.pkg_manager_api.load_api(packages))

    def updated_advisories(self) -> Set[Advisory]:
        files = self._updated_files
        advisories = []
        for f in files:
            processed_data = self.process_file(f)
            if processed_data:
                advisories.append(processed_data)
        return self.batch_advisories(advisories)

    def added_advisories(self) -> Set[Advisory]:
        files = self._added_files
        advisories = []
        for f in files:
            processed_data = self.process_file(f)
            if processed_data:
                advisories.append(processed_data)
        return self.batch_advisories(advisories)

    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("gem"):
                packages.add(data["gem"])

        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", ""),
            affected_packages=nearest_patched_package(impacted_purls,
                                                      resolved_purls),
            references=references,
            vulnerability_id=cve_id,
        )

    @staticmethod
    def categorize_versions(all_versions, unaffected_version_ranges):

        for id, elem in enumerate(unaffected_version_ranges):
            unaffected_version_ranges[
                id] = VersionSpecifier.from_scheme_version_spec_string(
                    "semver", elem)

        safe_versions = []
        vulnerable_versions = []
        for i in all_versions:
            vobj = SemverVersion(i)
            is_vulnerable = False
            for ver_rng in unaffected_version_ranges:
                if vobj in ver_rng:
                    safe_versions.append(i)
                    is_vulnerable = True
                    break

            if not is_vulnerable:
                vulnerable_versions.append(i)

        return safe_versions, vulnerable_versions
Exemple #6
0
class RubyDataSource(GitDataSource):
    def __enter__(self):
        super(RubyDataSource, self).__enter__()

        if not getattr(self, "_added_files", None):
            self._added_files, self._updated_files = self.file_changes(
                recursive=True, file_ext="yml", subdir="./gems")

        self.pkg_manager_api = RubyVersionAPI()
        self.set_api(self.collect_packages())

    def set_api(self, packages):
        asyncio.run(self.pkg_manager_api.load_api(packages))

    def updated_advisories(self) -> Set[Advisory]:
        files = self._updated_files
        advisories = []
        for f in files:
            processed_data = self.process_file(f)
            if processed_data:
                advisories.append(processed_data)
        return self.batch_advisories(advisories)

    def added_advisories(self) -> Set[Advisory]:
        files = self._added_files
        advisories = []
        for f in files:
            processed_data = self.process_file(f)
            if processed_data:
                advisories.append(processed_data)
        return self.batch_advisories(advisories)

    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("gem"):
                packages.add(data["gem"])

        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,
                        vuln_references=references,
                        vulnerability_id=cve_id)

    @staticmethod
    def categorize_versions(all_versions, unaffected_version_ranges):

        for id, elem in enumerate(unaffected_version_ranges):
            try:
                unaffected_version_ranges[id] = RangeSpecifier(
                    elem.replace(" ", ""))
            except InvalidSpecifier:
                continue

        safe_versions = set()
        for i in all_versions:
            for ver_rng in unaffected_version_ranges:

                if i in ver_rng:

                    safe_versions.add(i)

        return (safe_versions, all_versions - safe_versions)