From e5ceff876b2455d34d33457c5cec60429fba5291 Mon Sep 17 00:00:00 2001 From: Daniel Hilst <392820+dhilst@users.noreply.github.com> Date: Thu, 1 Oct 2026 21:38:34 -0300 Subject: [PATCH] test(xcat-dep): the openEuler native overlays enable a plugin the host cannot run Every openEuler ppc64le native prerequisite after procenv itself fails before rpmbuild starts: FileNotFoundError: [Errno 2] No such file or directory: '/usr/bin/procenv' raised from mock's procenv plugin prebuild hook. The plugin runs ["/usr/bin/procenv"] through mockbuild.util.do with no chroot prefix, so it executes the BUILD HOST's copy, and xcat-master-ppc has none. The plugin also appends procenv to the buildroot's preexisting_deps itself, so the chroot already gets the package: a run that installed it, with "Installing : procenv-0.60-1.ppc64le" in root.log, failed on the same line. mock ships procenv_enable False. The overlays turn it on, which makes every native build depend on a host package that neither repository declares, for a procenv.log that nothing reads. The overlay text was built inline in native_overlay, so there was nothing a unit test could call. native_overlay_text in XCAT::NativeInputs now renders one overlay and reproduces today's values exactly, and native_overlay writes what it returns. openeuler_native_procenv_plugin.t asserts the plugin is left at its default in all three overlays, that the prerequisite repository and the bind mount survive, and that the uid split does not move. Two of its eleven checks fail on this commit, which is the defect. Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com> --- .github/workflows/genesis-openembedded.yml | 1 + lib/XCAT/NativeInputs.pm | 38 ++++++++++++++++++- mockbuild-all.pl | 14 +------ t/openeuler_native_procenv_plugin.t | 43 ++++++++++++++++++++++ 4 files changed, 82 insertions(+), 14 deletions(-) create mode 100644 t/openeuler_native_procenv_plugin.t diff --git a/.github/workflows/genesis-openembedded.yml b/.github/workflows/genesis-openembedded.yml index 9a008c5..d419823 100644 --- a/.github/workflows/genesis-openembedded.yml +++ b/.github/workflows/genesis-openembedded.yml @@ -79,6 +79,7 @@ jobs: prove -v t/openeuler.t prove -v t/openeuler_mock_template_include.t prove -v t/openeuler_native_result_permissions.t + prove -v -Ilib t/openeuler_native_procenv_plugin.t prove -v -Ilib t/openeuler_native_trust_dbpath.t prove -v -Ilib t/openeuler_native_cpio_scan.t bats t/verify-xcatsn-install.bats diff --git a/lib/XCAT/NativeInputs.pm b/lib/XCAT/NativeInputs.pm index 065c136..2dacb62 100644 --- a/lib/XCAT/NativeInputs.pm +++ b/lib/XCAT/NativeInputs.pm @@ -14,7 +14,7 @@ use File::Temp qw(tempdir); use JSON::PP; our @EXPORT_OK = qw(load_inputs stage_inputs verify_input rpm_identity validate_outputs publisher_trust - trust_dbpath scan_cpio_for_elf); + trust_dbpath scan_cpio_for_elf native_overlay_text); sub read_file { my ($path) = @_; @@ -300,4 +300,40 @@ sub validate_outputs { return \%seen; } +#------------------------------------------------------------------------------- + +=head3 native_overlay_text + + Descriptions: Render one native mock overlay configuration. + + Arguments: + $purpose - 1000, 0 or 'procenv'. 'procenv' is the overlay that builds + procenv itself. + $base - path of the snapshotted base mock configuration to include. + $prereqs - path of the local repository holding the built prerequisites. + + Returns: the overlay file content. + +=cut + +#------------------------------------------------------------------------------- +sub native_overlay_text { + my ($purpose, $base, $prereqs) = @_; + my $bootstrap = $purpose eq 'procenv'; + my $uid = $bootstrap ? 1000 : $purpose; + my $url = $prereqs; + $url =~ s{([^A-Za-z0-9_./~-])}{sprintf('%%%02X', ord($1))}ge; + my $repo = "\n[xcat-native-inputs]\nname=xCAT native build prerequisites\nbaseurl=file://$url\n" + . "gpgkey=file://$url/repodata/repomd.xml.key\ngpgcheck=1\nrepo_gpgcheck=1\n" + . "enabled=1\nskip_if_unavailable=0\n"; + my $out = 'include(' . JSON::PP->new->encode($base) . ")\n"; + $out .= "config_opts['chrootuid'] = $uid\nconfig_opts['chrootgid'] = 1000\n"; + $out .= "config_opts['dnf.conf'] += \"\"\"$repo\"\"\"\n"; + $out .= "config_opts['plugin_conf']['bind_mount_enable'] = True\n"; + $out .= "config_opts['plugin_conf']['procenv_enable'] = " . ($bootstrap ? 'False' : 'True') . "\n"; + $out .= "config_opts['plugin_conf']['bind_mount_opts']['dirs'].append(" + . '(' . JSON::PP->new->encode($prereqs) . ', ' . JSON::PP->new->encode($prereqs) . "))\n"; + return $out; +} + 1; diff --git a/mockbuild-all.pl b/mockbuild-all.pl index 28914a3..8ae2150 100755 --- a/mockbuild-all.pl +++ b/mockbuild-all.pl @@ -1289,21 +1289,9 @@ sub native_overlay { return if $dry_run; my $base = "$work/native-base.cfg"; copy("/etc/mock/$target.cfg", $base) or die "Cannot snapshot native mock configuration: $!\n"; - my $url = $prereqs; - $url =~ s{([^A-Za-z0-9_./~-])}{sprintf('%%%02X', ord($1))}ge; - my $repo = "\n[xcat-native-inputs]\nname=xCAT native build prerequisites\nbaseurl=file://$url\n" - . "gpgkey=file://$url/repodata/repomd.xml.key\ngpgcheck=1\nrepo_gpgcheck=1\n" - . "enabled=1\nskip_if_unavailable=0\n"; for my $key (1000, 0, 'procenv') { - my $uid = $key eq 'procenv' ? 1000 : $key; open my $fh, '>', $plan->{overlays}{$key} or die "Cannot write native overlay: $!\n"; - print {$fh} 'include(' . JSON::PP->new->encode($base) . ")\n"; - print {$fh} "config_opts['chrootuid'] = $uid\nconfig_opts['chrootgid'] = 1000\n"; - print {$fh} "config_opts['dnf.conf'] += \"\"\"$repo\"\"\"\n"; - print {$fh} "config_opts['plugin_conf']['bind_mount_enable'] = True\n"; - print {$fh} "config_opts['plugin_conf']['procenv_enable'] = " . ($key eq 'procenv' ? 'False' : 'True') . "\n"; - print {$fh} "config_opts['plugin_conf']['bind_mount_opts']['dirs'].append(" - . '(' . JSON::PP->new->encode($prereqs) . ', ' . JSON::PP->new->encode($prereqs) . "))\n"; + print {$fh} XCAT::NativeInputs::native_overlay_text($key, $base, $prereqs); close $fh or die "Cannot close native overlay: $!\n"; } open my $ledger, '>', "$work/native-overlays.json" or die "Cannot record native overlays: $!\n"; diff --git a/t/openeuler_native_procenv_plugin.t b/t/openeuler_native_procenv_plugin.t new file mode 100644 index 0000000..256906e --- /dev/null +++ b/t/openeuler_native_procenv_plugin.t @@ -0,0 +1,43 @@ +#!/usr/bin/perl +# Every openEuler ppc64le native prerequisite after procenv itself fails before rpmbuild starts: +# +# FileNotFoundError: [Errno 2] No such file or directory: '/usr/bin/procenv' +# +# raised from mock's procenv plugin prebuild hook. The plugin runs ["/usr/bin/procenv"] through +# mockbuild.util.do with no chroot prefix, so it executes the BUILD HOST's copy, and +# xcat-master-ppc has none. Installing procenv in the chroot does not help: mock already appends it +# to preexisting_deps itself, and the run that did so still failed with the same line while +# root.log recorded "Installing : procenv-0.60-1.ppc64le". +# +# mock ships procenv_enable False. The overlays turned it on, which made every native build depend +# on a host package that neither repository declares, for a procenv.log nothing reads. They now +# leave it at the default. +# +# native_overlay_text is pure, so this runs no mock. +use strict; +use warnings; +use Test::More; +use FindBin qw($RealBin); +use lib "$RealBin/../lib"; +use XCAT::NativeInputs qw(native_overlay_text); + +my $base = '/opt/xcat-ci-shared/builds/oe264/work/native-base.cfg'; +my $prereqs = '/opt/xcat-ci-shared/builds/oe264/work/native-prerequisites'; + +for my $purpose (1000, 0, 'procenv') { + my $text = native_overlay_text($purpose, $base, $prereqs); + unlike($text, qr/procenv_enable'\]\s*=\s*True/, + "overlay $purpose does not enable the procenv plugin, which needs a host binary"); + # The overlay must still carry what the native build does depend on. + like($text, qr/\[xcat-native-inputs\]/, "overlay $purpose still declares the prerequisite repository"); + like($text, qr/bind_mount_enable'\]\s*=\s*True/, "overlay $purpose still binds the prerequisite tree"); +} + +# The uid split is declared in the inputs and must not move: genesis builds as root, the rest as +# 1000, and the procenv overlay runs as 1000 too. +is((native_overlay_text(1000, $base, $prereqs) =~ /chrootuid'\]\s*=\s*(\d+)/)[0], 1000, + 'the unprivileged overlay still runs as uid 1000'); +is((native_overlay_text(0, $base, $prereqs) =~ /chrootuid'\]\s*=\s*(\d+)/)[0], 0, + 'the genesis overlay still runs as root'); + +done_testing();