From faeec6eff1e80be893916d16fb6bd3cd8f0246c9 Mon Sep 17 00:00:00 2001 From: wang-guangge Date: Wed, 31 May 2023 18:06:22 +0800 Subject: [PATCH] fix hotpatch updateinfo for search hotpatch information MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hotpatch/baseclass.py | 14 ++-- hotpatch/hot-updateinfo.py | 118 +++++++++----------------------- hotpatch/hotpatch.py | 13 ++-- hotpatch/hotpatch_updateinfo.py | 58 ++++++++++------ 4 files changed, 83 insertions(+), 120 deletions(-) diff --git a/hotpatch/baseclass.py b/hotpatch/baseclass.py index d88ef40..2542a03 100644 --- a/hotpatch/baseclass.py +++ b/hotpatch/baseclass.py @@ -115,7 +115,7 @@ class Hotpatch(object): class Cve(object): - __slots__ = ['_cve_id', '_hotpatch'] + __slots__ = ['_cve_id', '_hotpatches'] def __init__(self, id, @@ -124,15 +124,14 @@ class Cve(object): id: str """ self._cve_id = id - self._hotpatch = None + self._hotpatches = [] @property - def hotpatch(self): - return self._hotpatch + def hotpatches(self): + return self._hotpatches - @hotpatch.setter - def hotpatch(self, hotpatch: Hotpatch): - self._hotpatch = hotpatch + def add_hotpatch(self, hotpatch: Hotpatch): + self._hotpatches.append(hotpatch) @property def cve_id(self): @@ -206,3 +205,4 @@ class Advisory(object): def add_hotpatch(self, hotpatch: Hotpatch): self._hotpatches.append(hotpatch) + diff --git a/hotpatch/hot-updateinfo.py b/hotpatch/hot-updateinfo.py index 779337b..d1e6d58 100644 --- a/hotpatch/hot-updateinfo.py +++ b/hotpatch/hot-updateinfo.py @@ -4,46 +4,6 @@ from dnf.cli.commands.updateinfo import UpdateInfoCommand import hawkey from .hotpatch_updateinfo import HotpatchUpdateInfo - -class Versions: - """ - Version number processing - """ - - separator = (".", "-") - _connector = "&" - - def _order(self, version, separator=None): - """ - Version of the cutting - Args: - version: version - separator: separator - - Returns: - - """ - if not separator: - separator = self._connector - return tuple([int(v) for v in version.split(separator) if v.isdigit()]) - - def lgt(self, version, compare_version): - """ - Returns true if the size of the compared version is greater - than that of the compared version, or false otherwise - - """ - for separator in self.separator: - version = self._connector.join( - [v for v in version.split(separator)]) - compare_version = self._connector.join( - [v for v in compare_version.split(separator)] - ) - version = self._order(version) - compare_version = self._order(compare_version) - return version >= compare_version - - @dnf.plugin.register_command class HotUpdateinfoCommand(dnf.cli.Command): aliases = ['hot-updateinfo'] @@ -118,26 +78,13 @@ class HotUpdateinfoCommand(dnf.cli.Command): return mapping_nevra_cve - def _filter_and_format_list_output(self, echo_lines: list, fixed_cve_id: set, fixed_coldpatches: set): + def _filter_and_format_list_output(self, echo_lines: list, fixed_cve_id: set): """ Only show specified cve information that have not been fixed, and format output """ - def is_patch_fixed(coldpatch, fixed_coldpatches): - """ - Check whether the coldpatch is fixed - """ - for fixed_coldpatch in fixed_coldpatches: - pkg_name, pkg_evr, _ = coldpatch - fixed_pkg_name, fixed_pkg_evr, _ = fixed_coldpatch - if pkg_name != fixed_pkg_name: - continue - if version.lgt(fixed_pkg_evr, pkg_evr): - return True - return False idw = tiw = ciw = 0 format_lines = set() - version = Versions() for echo_line in echo_lines: cve_id, adv_type, coldpatch, hotpatch = echo_line[0], echo_line[1], echo_line[2], echo_line[3] if self.filter_cves is not None and cve_id not in self.filter_cves: @@ -145,11 +92,8 @@ class HotUpdateinfoCommand(dnf.cli.Command): if cve_id in fixed_cve_id: continue if not isinstance(coldpatch, str): - if is_patch_fixed(coldpatch, fixed_coldpatches): - continue - else: - pkg_name, pkg_evr, pkg_arch = coldpatch - coldpatch = '%s-%s.%s' % (pkg_name, pkg_evr, pkg_arch) + pkg_name, pkg_evr, pkg_arch = coldpatch + coldpatch = '%s-%s.%s' % (pkg_name, pkg_evr, pkg_arch) idw = max(idw, len(cve_id)) tiw = max(tiw, len(adv_type)) @@ -178,41 +122,43 @@ class HotUpdateinfoCommand(dnf.cli.Command): mapping_nevra_cve = self.get_mapping_nevra_cve() echo_lines = [] fixed_cve_id = set() - fixed_coldpatches = set() iterated_cve_id = set() for ((nevra), aupdated), id2type in sorted(mapping_nevra_cve.items(), key=lambda x: x[0]): pkg_name, pkg_evr, pkg_arch = nevra for cve_id, atypesev in id2type.items(): iterated_cve_id.add(cve_id) - label = type2label(self.updateinfo, *atypesev) - echo_line = [cve_id, label, nevra, '-'] - echo_lines.append(echo_line) - if cve_id not in self.hp_hawkey.hotpatch_cves: + label = type2label(self.updateinfo, *atypesev) + if cve_id not in self.hp_hawkey.hotpatch_cves or not self.hp_hawkey.hotpatch_cves[cve_id].hotpatches: + echo_line = [cve_id, label, nevra, '-'] + echo_lines.append(echo_line) continue - hotpatch = self.hp_hawkey.hotpatch_cves[cve_id].hotpatch - if hotpatch is None or hotpatch.src_pkg_nevre[0] != pkg_name: - continue - if hotpatch.state == self.hp_hawkey.INSTALLED: - # record the fixed cves - for cve_id in hotpatch.cves: - fixed_cve_id.add(cve_id) - # record the fixed coldpatch to filter the cves of the corresponding coldpatch with the lower version - fixed_coldpatches.add((nevra)) - echo_lines.pop() - elif hotpatch.state == self.hp_hawkey.INSTALLABLE: - echo_lines[-1][3] = hotpatch.nevra + + for hotpatch in self.hp_hawkey.hotpatch_cves[cve_id].hotpatches: + echo_line = [cve_id, label, nevra, '-'] + echo_lines.append(echo_line) + if hotpatch.src_pkg_nevre[0] != pkg_name: + continue + if hotpatch.state == self.hp_hawkey.INSTALLED: + # record the fixed cves + for cve_id in hotpatch.cves: + fixed_cve_id.add(cve_id) + echo_lines.pop() + elif hotpatch.state == self.hp_hawkey.INSTALLABLE: + echo_lines[-1][3] = hotpatch.nevra + hp_cve_list = list(set(self.hp_hawkey.hotpatch_cves.keys()).difference(iterated_cve_id)) for cve_id in hp_cve_list: - hotpatch = self.hp_hawkey.hotpatch_cves[cve_id].hotpatch - if hotpatch is None: - continue - echo_line = [cve_id, hotpatch.advisory.severity + '/Sec.', '-', '-'] - if hotpatch.state == self.hp_hawkey.INSTALLED: - continue - elif hotpatch.state == self.hp_hawkey.INSTALLABLE: - echo_line = [cve_id, hotpatch.advisory.severity + '/Sec.', '-', hotpatch.nevra] - echo_lines.append(echo_line) + for hotpatch in self.hp_hawkey.hotpatch_cves[cve_id].hotpatches: + echo_line = [cve_id, hotpatch.advisory.severity + '/Sec.', '-', '-'] + if hotpatch.state == self.hp_hawkey.INSTALLED: + # record the fixed cves + fixed_cve_id.add(cve_id) + continue + elif hotpatch.state == self.hp_hawkey.INSTALLABLE: + echo_line = [cve_id, hotpatch.advisory.severity + '/Sec.', '-', hotpatch.nevra] + echo_lines.append(echo_line) self._filter_and_format_list_output( - echo_lines, fixed_cve_id, fixed_coldpatches) + echo_lines, fixed_cve_id) + diff --git a/hotpatch/hotpatch.py b/hotpatch/hotpatch.py index 0704a08..ccef636 100644 --- a/hotpatch/hotpatch.py +++ b/hotpatch/hotpatch.py @@ -102,12 +102,12 @@ class HotpatchCommand(dnf.cli.Command): hotpatch_cves = self.hp_hawkey.hotpatch_cves echo_lines = [] for cve_id in hotpatch_cves.keys(): - hotpatch = hotpatch_cves[cve_id].hotpatch - status = self.hp_hawkey._get_hotpatch_status_in_syscare(hotpatch) - if status == '': - continue - echo_line = [cve_id, hotpatch.syscare_name, status] - echo_lines.append(echo_line) + for hotpatch in hotpatch_cves[cve_id].hotpatches: + status = self.hp_hawkey._get_hotpatch_status_in_syscare(hotpatch) + if status == '': + continue + echo_line = [cve_id, hotpatch.syscare_name, status] + echo_lines.append(echo_line) self._filter_and_format_list_output(echo_lines) @@ -133,3 +133,4 @@ class HotpatchCommand(dnf.cli.Command): else: logger.info(_("%s hot patch '%s' succeed"), operate, self.base.output.term.bold(target_patch)) + diff --git a/hotpatch/hotpatch_updateinfo.py b/hotpatch/hotpatch_updateinfo.py index 6689553..399e05c 100644 --- a/hotpatch/hotpatch_updateinfo.py +++ b/hotpatch/hotpatch_updateinfo.py @@ -67,7 +67,7 @@ class HotpatchUpdateInfo(object): """ Initialize hotpatch information from repos """ - # get xxx-hotpatch.xml.gz file paths by traversing the system_cachedir(/var/cache/dnf) + # get xxx-updateinfo.xml.gz file paths by traversing the system_cachedir(/var/cache/dnf) system_cachedir = self.cli.base.conf.system_cachedir all_repos = self.cli.base.repos map_repo_updateinfoxml = {} @@ -80,9 +80,9 @@ class HotpatchUpdateInfo(object): continue for xml_file in os.listdir(repodata_path): - # the hotpatch relevant updateinfo is recorded in xxx-hotpatch.xml.gz - if "hotpatch" in xml_file: - repo_name = file.split("-")[0] + # the hotpatch relevant updateinfo is recorded in xxx-updateinfo.xml.gz + if "updateinfo" in xml_file: + repo_name = file.rsplit("-")[0] cache_updateinfo_xml_path = os.path.join( repodata_path, xml_file) map_repo_updateinfoxml[repo_name] = cache_updateinfo_xml_path @@ -99,7 +99,7 @@ class HotpatchUpdateInfo(object): Parse the pkglist information, filter the hotpatches with different arches """ hotpatches = [] - hot_patch_collection = pkglist.find('collection') + hot_patch_collection = pkglist.find('hot_patch_collection') arches = self.base.sack.list_arches() if not hot_patch_collection: return hotpatches @@ -171,14 +171,19 @@ class HotpatchUpdateInfo(object): advisory.cves = advisory_cves for hotpatch_kwargs in advisory_hotpatches: + # parse the id string of the package to list + # e.g. parse the id of "CVE-2021-2023,CVE-2021-2024" to ["CVE-2021-2023", "CVE-2021-2024"] + hotpatch_ref_id = hotpatch_kwargs.pop('id') + hotpatch_ref_id = hotpatch_ref_id.split(',') + hotpatch = Hotpatch(**hotpatch_kwargs) hotpatch.advisory = advisory - hotpatch.cves = advisory_cves.keys() + hotpatch.cves = hotpatch_ref_id advisory.add_hotpatch(hotpatch) - - for cve in advisory_cves.values(): - cve.hotpatch = hotpatch + + for ref_id in hotpatch_ref_id: + advisory_cves[ref_id].add_hotpatch(hotpatch) self._hotpatch_advisories[advisory_kwargs['id']] = advisory @@ -213,9 +218,9 @@ class HotpatchUpdateInfo(object): def _parse_and_store_from_xml(self, updateinfoxml): """ - Parse and store hotpatch update information from xxx-hotpatch.xml.gz + Parse and store hotpatch update information from xxx-updateinfo.xml.gz - xxx-hotpatch.xml.gz e.g. + xxx-updateinfo.xml.gz e.g. @@ -226,19 +231,26 @@ class HotpatchUpdateInfo(object): openEuler - + + patch-redis-6.2.5-1-HP001.(CVE-2022-24048) - + openEuler - - patch-redis-6.2.5-1-HP001-0-1.aarch64.rpm + + patch-redis-6.2.5-1-HP001-1-1.aarch64.rpm + + + patch-redis-6.2.5-1-HP001-1-1.x86_64.rpm + + + patch-redis-6.2.5-1-HP002-1-1.aarch64.rpm - - patch-redis-6.2.5-1-HP001-0-1.x86_64.rpm + + patch-redis-6.2.5-1-HP002-1-1.x86_64.rpm - + ... @@ -248,6 +260,9 @@ class HotpatchUpdateInfo(object): tree = ET.parse(content) root = tree.getroot() for update in root.iter('update'): + # check whether the hotpatch relevant package information is in each advisory + if not update.find('pkglist/hot_patch_collection'): + continue advisory = self._parse_advisory(update) self._store_advisory_info(advisory) @@ -288,9 +303,9 @@ class HotpatchUpdateInfo(object): mapping_cve_hotpatches[cve_id] = [] if cve_id not in self.hotpatch_cves: continue - hotpatch = self.hotpatch_cves[cve_id].hotpatch - if hotpatch is not None and hotpatch.state == self.INSTALLABLE: - mapping_cve_hotpatches[cve_id].append(hotpatch.nevra) + for hotpatch in self.hotpatch_cves[cve_id].hotpatches: + if hotpatch.state == self.INSTALLABLE: + mapping_cve_hotpatches[cve_id].append(hotpatch.nevra) return mapping_cve_hotpatches def get_hotpatches_from_advisories(self, advisories: list[str]) -> dict(): @@ -317,3 +332,4 @@ class HotpatchUpdateInfo(object): mapping_advisory_hotpatches[advisory_id].append( hotpatch.nevra) return mapping_advisory_hotpatches + -- Gitee