From 5949608e209af2506ea1a8e9d4ac731b9043611a Mon Sep 17 00:00:00 2001 From: Craig Comstock Date: Wed, 18 Dec 2024 11:01:19 -0600 Subject: [PATCH 1/3] Fixed issue with yum package module regarding packages with epoch not validating Packages would be installed but the promise would fail due to the installed list not including the epoch number. The updates list generated by the module included the epoch number so validation would fail. e.g. findutils:1:4.8.0-7.el9:x86_64 would not match findutils:4.8.0-7.el9:x86_64 Fix this by including epoch in rpm_output_format and removing (none): where the package has no epoch. Ticket: ENT-12538 Changelog: title (cherry picked from commit 32110fedb1b9f903259d5273937acd21ba8bc5ea) --- modules/packages/vendored/yum.mustache | 24 +++++++++++++++++++++--- tests/unit/test_package_module_yum | 4 ++-- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/modules/packages/vendored/yum.mustache b/modules/packages/vendored/yum.mustache index c42ebb17e8..5625716b09 100755 --- a/modules/packages/vendored/yum.mustache +++ b/modules/packages/vendored/yum.mustache @@ -11,7 +11,7 @@ import re rpm_cmd = os.environ.get('CFENGINE_TEST_RPM_CMD', "/bin/rpm") rpm_quiet_option = ["--quiet"] -rpm_output_format = "Name=%{name}\nVersion=%{version}-%{release}\nArchitecture=%{arch}\n" +rpm_output_format = "Name=%{name}\nVersion=%{epoch}:%{version}-%{release}\nArchitecture=%{arch}\n" yum_cmd = os.environ.get('CFENGINE_TEST_YUM_CMD', "/usr/bin/yum") yum_options = ["--quiet", "-y"] @@ -87,7 +87,16 @@ def get_package_data(): # Absolute file. sys.stdout.write("PackageType=file\n") sys.stdout.flush() - return subprocess_call([rpm_cmd, "--qf", rpm_output_format, "-qp", pkg_string]) + process = subprocess_Popen([rpm_cmd, "--qf", rpm_output_format, "-qp", pkg_string], stdout=subprocess.PIPE) + (stdoutdata, _) = process.communicate() + + if process.returncode != 0: + return process.returncode + + for line in stdoutdata.decode("utf-8").splitlines(): + sys.stdout.write(line.replace("(none):","") + "\n") + + return 0 elif re.search("[:,]", pkg_string): # Contains an illegal symbol. sys.stdout.write(line + "ErrorMessage: Package string with illegal format\n") @@ -102,7 +111,16 @@ def list_installed(): # Ignore everything. sys.stdin.readlines() - return subprocess_call([rpm_cmd, "-qa", "--qf", rpm_output_format]) + process = subprocess_Popen([rpm_cmd, "-qa", "--qf", rpm_output_format], stdout=subprocess.PIPE) + (stdoutdata, _) = process.communicate() + + if process.returncode != 0: + return process.returncode + + for line in stdoutdata.decode("utf-8").splitlines(): + sys.stdout.write(line.replace("(none):","") + "\n") + + return 0 def list_updates(online): diff --git a/tests/unit/test_package_module_yum b/tests/unit/test_package_module_yum index a7864c4742..56902f99b4 100755 --- a/tests/unit/test_package_module_yum +++ b/tests/unit/test_package_module_yum @@ -151,11 +151,11 @@ assert check("list-updates-local", [], 18, assert check("list-installed", [], 6, ["Name=firefox\nVersion=24.5.0-1.el5.centos\nArchitecture=i386", "Name=yum\nVersion=3.2.29-43.el6_5\nArchitecture=noarch"], - 4, ["rpm -qa --qf Name=%{name}\nVersion=%{version}-%{release}\nArchitecture=%{arch}\n"]) + 4, ["rpm -qa --qf Name=%{name}\nVersion=%{epoch}:%{version}-%{release}\nArchitecture=%{arch}\n"]) assert check("get-package-data", ["File=/path/to/pkg"], 4, ["PackageType=file\nName=file_pkg\nVersion=10.0\nArchitecture=x86_64"], - 4, ["rpm --qf Name=%{name}\nVersion=%{version}-%{release}\nArchitecture=%{arch}\n -qp /path/to/pkg"]) + 4, ["rpm --qf Name=%{name}\nVersion=%{epoch}:%{version}-%{release}\nArchitecture=%{arch}\n -qp /path/to/pkg"]) assert check("get-package-data", ["File=repo_pkg"], 2, ["PackageType=repo\nName=repo_pkg"], 0, []) From 9c9174267e70d4cd3f6c0790ece53618deecc83e Mon Sep 17 00:00:00 2001 From: Craig Comstock Date: Thu, 19 Dec 2024 09:09:31 -0600 Subject: [PATCH 2/3] Black formatting for yum package module python script Ticket: ENT-12538 Changelog: none (cherry picked from commit ce1fac431b76b2be921ce13e6457b7758afd999d) --- modules/packages/vendored/yum.mustache | 65 ++++++++++++++++++-------- 1 file changed, 45 insertions(+), 20 deletions(-) diff --git a/modules/packages/vendored/yum.mustache b/modules/packages/vendored/yum.mustache index 5625716b09..2696cbe3aa 100755 --- a/modules/packages/vendored/yum.mustache +++ b/modules/packages/vendored/yum.mustache @@ -9,18 +9,21 @@ import subprocess import re -rpm_cmd = os.environ.get('CFENGINE_TEST_RPM_CMD', "/bin/rpm") +rpm_cmd = os.environ.get("CFENGINE_TEST_RPM_CMD", "/bin/rpm") rpm_quiet_option = ["--quiet"] -rpm_output_format = "Name=%{name}\nVersion=%{epoch}:%{version}-%{release}\nArchitecture=%{arch}\n" +rpm_output_format = ( + "Name=%{name}\nVersion=%{epoch}:%{version}-%{release}\nArchitecture=%{arch}\n" +) -yum_cmd = os.environ.get('CFENGINE_TEST_YUM_CMD', "/usr/bin/yum") +yum_cmd = os.environ.get("CFENGINE_TEST_YUM_CMD", "/usr/bin/yum") yum_options = ["--quiet", "-y"] -NULLFILE = open(os.devnull, 'w') +NULLFILE = open(os.devnull, "w") redirection_is_broken_cached = -1 + def redirection_is_broken(): # Older versions of Python have a bug where it is impossible to redirect # stderr using subprocess, and any attempt at redirecting *anything*, not @@ -41,7 +44,12 @@ def redirection_is_broken(): def subprocess_Popen(cmd, stdout=None, stderr=None): - if not redirection_is_broken() or (stdout is None and stderr is None) or stdout == subprocess.PIPE or stderr == subprocess.PIPE: + if ( + not redirection_is_broken() + or (stdout is None and stderr is None) + or stdout == subprocess.PIPE + or stderr == subprocess.PIPE + ): return subprocess.Popen(cmd, stdout=stdout, stderr=stderr) old_stdout_fd = -1 @@ -87,14 +95,17 @@ def get_package_data(): # Absolute file. sys.stdout.write("PackageType=file\n") sys.stdout.flush() - process = subprocess_Popen([rpm_cmd, "--qf", rpm_output_format, "-qp", pkg_string], stdout=subprocess.PIPE) + process = subprocess_Popen( + [rpm_cmd, "--qf", rpm_output_format, "-qp", pkg_string], + stdout=subprocess.PIPE, + ) (stdoutdata, _) = process.communicate() if process.returncode != 0: return process.returncode for line in stdoutdata.decode("utf-8").splitlines(): - sys.stdout.write(line.replace("(none):","") + "\n") + sys.stdout.write(line.replace("(none):", "") + "\n") return 0 elif re.search("[:,]", pkg_string): @@ -111,14 +122,16 @@ def list_installed(): # Ignore everything. sys.stdin.readlines() - process = subprocess_Popen([rpm_cmd, "-qa", "--qf", rpm_output_format], stdout=subprocess.PIPE) + process = subprocess_Popen( + [rpm_cmd, "-qa", "--qf", rpm_output_format], stdout=subprocess.PIPE + ) (stdoutdata, _) = process.communicate() if process.returncode != 0: return process.returncode for line in stdoutdata.decode("utf-8").splitlines(): - sys.stdout.write(line.replace("(none):","") + "\n") + sys.stdout.write(line.replace("(none):", "") + "\n") return 0 @@ -128,7 +141,7 @@ def list_updates(online): for line in sys.stdin: line = line.strip() if line.startswith("options="): - option = line[len("options="):] + option = line[len("options=") :] if option.startswith("-"): yum_options.append(option) elif option.startswith("enablerepo=") or option.startswith("disablerepo="): @@ -138,7 +151,9 @@ def list_updates(online): if not online: online_flag = ["-C"] - process = subprocess_Popen([yum_cmd] + yum_options + online_flag + ["check-update"], stdout=subprocess.PIPE) + process = subprocess_Popen( + [yum_cmd] + yum_options + online_flag + ["check-update"], stdout=subprocess.PIPE + ) (stdoutdata, _) = process.communicate() # analyze return code from `yum check-update`: # 0 means no updates @@ -147,7 +162,9 @@ def list_updates(online): if process.returncode == 1 and not online: # If we get an error when listing local updates, try again using the # online method, so that the cache is generated - process = subprocess_Popen([yum_cmd] + yum_options + ["check-update"], stdout=subprocess.PIPE) + process = subprocess_Popen( + [yum_cmd] + yum_options + ["check-update"], stdout=subprocess.PIPE + ) (stdoutdata, _) = process.communicate() if process.returncode != 100: # either there were no updates or error happened @@ -170,7 +187,9 @@ def list_updates(online): continue lastline = "" - match = re.match(r"^(?P\S+)\.(?P[^.\s]+)\s+(?P\S+)\s+\S+\s*$", line) + match = re.match( + r"^(?P\S+)\.(?P[^.\s]+)\s+(?P\S+)\s+\S+\s*$", line + ) if match is not None: sys.stdout.write("Name=" + match.group("name") + "\n") sys.stdout.write("Version=" + match.group("version") + "\n") @@ -192,8 +211,9 @@ def one_package_argument(name, arch, version, is_yum_install): archs.append(arch) if is_yum_install: - process = subprocess_Popen([rpm_cmd, "--qf", "%{arch}\n", - "-q", name], stdout=subprocess.PIPE) + process = subprocess_Popen( + [rpm_cmd, "--qf", "%{arch}\n", "-q", name], stdout=subprocess.PIPE + ) existing_archs = [line.decode("utf-8").rstrip() for line in process.stdout] process.wait() if process.returncode == 0 and existing_archs: @@ -236,13 +256,13 @@ def package_arguments_builder(is_yum_install): name = "" version = "" arch = "" - single_cmd_args = [] # List of arguments - multi_cmd_args = [] # List of lists of arguments + single_cmd_args = [] # List of arguments + multi_cmd_args = [] # List of lists of arguments old_name = "" for line in sys.stdin: line = line.strip() if line.startswith("options="): - option = line[len("options="):] + option = line[len("options=") :] if option.startswith("-"): yum_options.append(option) elif option.startswith("enablerepo=") or option.startswith("disablerepo="): @@ -250,7 +270,9 @@ def package_arguments_builder(is_yum_install): if line.startswith("Name="): if name: # Each new "Name=" triggers a new entry. - single_list, multi_list = one_package_argument(name, arch, version, is_yum_install) + single_list, multi_list = one_package_argument( + name, arch, version, is_yum_install + ) single_cmd_args += single_list if name == old_name: # Packages that differ only by architecture should be @@ -273,7 +295,9 @@ def package_arguments_builder(is_yum_install): arch = line.split("=", 1)[1].rstrip() if name: - single_list, multi_list = one_package_argument(name, arch, version, is_yum_install) + single_list, multi_list = one_package_argument( + name, arch, version, is_yum_install + ) single_cmd_args += single_list if name == old_name: # Packages that differ only by architecture should be @@ -454,4 +478,5 @@ def main(): sys.stderr.write("Invalid operation\n") return 2 + sys.exit(main()) From 3c825180b3d4ec43d8e69740bcaf4d9ff6935d3b Mon Sep 17 00:00:00 2001 From: Craig Comstock Date: Wed, 18 Dec 2024 11:55:33 -0600 Subject: [PATCH 3/3] Fixed valgrind github workflow needing librsync-dev package Ticket: none Changelog: none (cherry picked from commit e8c97c60147edb0c1611d7edb4253316e62cc6b8) --- .github/workflows/valgrind.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/valgrind.yml b/.github/workflows/valgrind.yml index 1ce71265d4..9e785141bc 100644 --- a/.github/workflows/valgrind.yml +++ b/.github/workflows/valgrind.yml @@ -22,7 +22,7 @@ jobs: ref: ${{steps.together.outputs.core}} submodules: recursive - name: Install dependencies - run: sudo apt-get update -y && sudo apt-get install -y libssl-dev libpam0g-dev liblmdb-dev byacc curl libyaml-dev valgrind + run: sudo apt-get update -y && sudo apt-get install -y libssl-dev libpam0g-dev liblmdb-dev byacc curl libyaml-dev valgrind librsync-dev # - name: Install CFEngine with cf-remote # run: | # pip3 install cf-remote