2
0
mirror of https://github.com/xcat2/xcat-dep.git synced 2026-10-20 14:45:43 +00:00

fix(genesis): harden staged release publication

This commit is contained in:
Vinícius Ferrão
2026-08-22 02:39:38 -03:00
parent 1b21fdb827
commit 17bd87c53c
5 changed files with 55 additions and 34 deletions
+5 -12
View File
@@ -120,12 +120,11 @@ command -v gpg >/dev/null 2>&1 \
|| die "gpg not found. Install: sudo apt-get install gnupg"
command -v cmp >/dev/null 2>&1 \
|| die "cmp not found. Install: sudo apt-get install diffutils"
command -v dpkg-deb >/dev/null 2>&1 \
|| die "dpkg-deb not found. Install: sudo apt-get install dpkg"
command -v sha256sum >/dev/null 2>&1 \
|| die "sha256sum not found. Install: sudo apt-get install coreutils"
if [[ -n "$GENESIS_RELEASE" ]]; then
command -v dpkg-deb >/dev/null 2>&1 \
|| die "dpkg-deb not found. Install: sudo apt-get install dpkg"
command -v sha256sum >/dev/null 2>&1 \
|| die "sha256sum not found. Install: sudo apt-get install coreutils"
GENESIS_CHECKSUMS=$(mktemp "${TMPDIR:-/tmp}/xcat-genesis-checksums.XXXXXX")
cp -- "$GENESIS_RELEASE/SHA256SUMS" "$GENESIS_CHECKSUMS"
"$GENESIS_VERIFIER" --complete --format deb "$GENESIS_RELEASE"
@@ -198,12 +197,7 @@ copy_genesis_deb() {
name=$(basename "$source")
destination="$directory/$name"
relative="deb/$name"
if [[ -e "$destination" ]]; then
cmp -s "$source" "$destination" \
|| die "Package collision with different content: $destination"
else
cp -- "$source" "$destination"
fi
cp -- "$source" "$destination"
expected=$(awk -v path="$relative" '$2 == path { print $1 }' "$GENESIS_CHECKSUMS")
[[ -n "$expected" ]] || die "Missing verified checksum for $relative"
actual=$(sha256sum "$destination")
@@ -225,7 +219,6 @@ for ver in "${SELECTED_VERS[@]}"; do
copy_deb "$deb" "$dst"
done
if [[ -n "$GENESIS_RELEASE" ]]; then
rm -f -- "$dst"/xcat-genesis-openembedded-*.deb
for deb in "$GENESIS_RELEASE"/deb/*.deb; do
copy_genesis_deb "$deb" "$dst"
done
+1 -1
View File
@@ -112,7 +112,7 @@ sub _build_rpm {
my $archive = "$rpm_top/SOURCES/$source_name.tar.gz";
_run(
'tar', '--sort=name', '--owner=0', '--group=0',
'tar', '--sort=name', '--owner=0', '--group=0', '--numeric-owner',
"--mtime=\@$source_date_epoch", '--use-compress-program=gzip -n',
'-cf', $archive, '-C', dirname($source_root), basename($source_root),
);
@@ -3,7 +3,6 @@
Name: xCAT-genesis-openembedded-%{genesis_arch}
Version: %{?version}%{!?version:0}
Release: %{?release}%{!?release:1}
Epoch: 1
Summary: xCAT OpenEmbedded Genesis netboot image
License: Various
URL: https://xcat.org/
@@ -24,6 +23,7 @@ service actions before a node boots its installed operating system.
rm -rf %{buildroot}
install -d -m 0755 %{buildroot}/opt/xcat/share/xcat/netboot/genesis-openembedded/%{genesis_arch}
install -m 0644 image/* %{buildroot}/opt/xcat/share/xcat/netboot/genesis-openembedded/%{genesis_arch}/
# Keep this path stable across RPM build hosts. %%{_docdir} differs on SUSE.
install -d -m 0755 %{buildroot}/usr/share/doc/%{name}
install -m 0644 xcat-core-revision %{buildroot}/usr/share/doc/%{name}/
+12 -3
View File
@@ -61,14 +61,23 @@ sub _verify_rpm {
my ($path, $expected_arch, $expected_source) = @{$package};
my $metadata = _capture(
'rpm', '-qp', '--qf',
"%{NAME}\t%{VERSION}\t%{RELEASE}\t%{ARCH}\t%{EPOCHNUM}\t%{SOURCERPM}\n",
"%{NAME}\t%{VERSION}\t%{RELEASE}\t%{ARCH}\t%{EPOCHNUM}\t%{SOURCERPM}"
. "\t%{BUILDHOST}\t%{BUILDTIME}\n",
$path,
);
my $expected = join(
"\t", $name, $manifest->{xcat_version}, $manifest->{xcat_release},
$expected_arch, '1', $expected_source,
$expected_arch, '0', $expected_source, 'xcat-release',
$manifest->{source_date_epoch},
);
die "Unexpected RPM identity for $path: $metadata\n" unless $metadata eq $expected;
for my $relationship (qw(conflicts obsoletes)) {
my $value = _capture('rpm', '-qp', "--$relationship", $path);
die "Unexpected RPM $relationship for $path: $value\n" if $value ne '';
}
my $provides = _capture('rpm', '-qp', '--provides', $path);
die "Legacy RPM relationship in $path: $provides\n"
if $provides =~ /xCAT-genesis-base/;
}
}
@@ -87,7 +96,7 @@ sub _verify_deb {
'all',
);
die "Unexpected DEB identity for $path: $metadata\n" unless $metadata eq $expected;
for my $field (qw(Conflicts Replaces)) {
for my $field (qw(Breaks Conflicts Provides Replaces)) {
my $value = _capture('dpkg-deb', '-f', $path, $field);
die "Unexpected DEB $field for $path: $value\n" if $value ne '';
}
+36 -17
View File
@@ -466,7 +466,6 @@ push @collect_roots, @extra_collect_dirs;
my @srpm_collect_roots = (!$skip_xcat)
? uniq(@collect_roots, $xcat_srpms_dir)
: uniq(@collect_roots);
@srpm_collect_roots = uniq(@srpm_collect_roots);
if ($genesis_release && !$dry_run) {
remove_genesis_packages($repo_dir, 0);
@@ -609,11 +608,21 @@ sub deploy_target {
print_step("Deploy $tgt -> $dest");
return if $dry_run;
make_path($dest);
remove_genesis_packages($dest, 0) if $genesis_release;
for my $rpm (bsd_glob("$src/*.rpm")) {
next if $rpm =~ /\.src\.rpm$/;
copy($rpm, "$dest/" . basename($rpm))
or die "Failed to copy $rpm -> $dest: $!\n";
my $destination = "$dest/" . basename($rpm);
my $temporary = "$destination.$$.new";
die "Deployment staging file already exists: $temporary\n"
if -e $temporary || -l $temporary;
copy($rpm, $temporary)
or die "Failed to stage $rpm -> $temporary: $!\n";
rename($temporary, $destination)
or die "Failed to publish $temporary -> $destination: $!\n";
}
if ($genesis_release) {
my @keep = map { basename($_) } genesis_release_files('rpm');
remove_genesis_packages($dest, 0, \@keep);
verify_genesis_release_packages('rpm', $dest);
}
assert_required_deps($dest);
sign_and_index_repo($dest);
@@ -935,12 +944,14 @@ sub assert_required_deps {
}
sub remove_genesis_packages {
my ($directory, $source) = @_;
my ($directory, $source, $keep_names) = @_;
return unless -d $directory;
my %keep = map { $_ => 1 } @{ $keep_names // [] };
opendir(my $dh, $directory) or die "Cannot read $directory: $!\n";
my @names = grep { /^xCAT-genesis-openembedded-.*\.rpm\z/ } readdir($dh);
closedir($dh) or die "Cannot close $directory: $!\n";
for my $name (@names) {
next if $keep{$name};
my $path = "$directory/$name";
next if $source && $path !~ /\.src\.rpm\z/;
next if !$source && $path =~ /\.src\.rpm\z/;
@@ -953,11 +964,7 @@ sub install_genesis_release_packages {
remove_genesis_packages($destination_root, $prefix eq 'srpm');
my $copied = 0;
for my $relative (
sort grep { /^\Q$prefix\E\/xCAT-genesis-openembedded-[^\/]+\.rpm\z/ }
keys %{$genesis_release_checksums}
)
{
for my $relative (genesis_release_files($prefix)) {
my $source = "$genesis_release/$relative";
my $destination = "$destination_root/" . basename($relative);
copy($source, $destination)
@@ -969,6 +976,24 @@ sub install_genesis_release_packages {
return $copied;
}
sub genesis_release_files {
my ($prefix) = @_;
return sort grep {
/^\Q$prefix\E\/xCAT-genesis-openembedded-[^\/]+\.rpm\z/
} keys %{$genesis_release_checksums};
}
sub verify_genesis_release_packages {
my ($prefix, $destination_root) = @_;
my @files = genesis_release_files($prefix);
die "Genesis release has no $prefix packages\n" unless @files;
for my $relative (@files) {
my $destination = "$destination_root/" . basename($relative);
verify_release_file($genesis_release_checksums, $relative, $destination);
}
return scalar(@files);
}
sub assert_genesis_release_copied {
my ($binary_directory, $source_directory) = @_;
for my $entry (
@@ -976,13 +1001,7 @@ sub assert_genesis_release_copied {
[ 'srpm', $source_directory ],
) {
my ($prefix, $destination_root) = @{$entry};
for my $relative (
sort grep { /^\Q$prefix\E\/[^\/]+\.rpm\z/ } keys %{$genesis_release_checksums}
)
{
my $destination = "$destination_root/" . basename($relative);
verify_release_file($genesis_release_checksums, $relative, $destination);
}
verify_genesis_release_packages($prefix, $destination_root);
}
}