2
0
mirror of https://github.com/xcat2/xcat-dep.git synced 2026-09-30 14:55:17 +00:00

build(ipxe-xcat): package the upstream binaries for EL and Debian

ipxe-xcat installs the release tree under /tftpboot/xcat/ipxe as it
is, with its relative symlinks, and installs the source archive and the
licence texts with the documentation. It is a noarch RPM and an
Architecture: all deb.

Both builders check the archives against SHA256SUMS before the build.
After the build they unpack the RPM or deb and compare its tree with
payload.sha256, entry for entry, before the package reaches the result
directory. The spec and the Debian rules do not strip or compress the
tree, so the signed EFI files keep their signatures.

The package does not obsolete, provide or conflict with xnba-undi.
This commit is contained in:
Vinícius Ferrão
2026-09-25 13:15:50 -03:00
parent 0e8e044fa3
commit c56e943dc3
12 changed files with 618 additions and 0 deletions
+70
View File
@@ -0,0 +1,70 @@
ipxe-xcat
=========
This package installs the ipxeboot.tar.gz tree of the iPXE v2.0.0 release
under /tftpboot/xcat/ipxe, unchanged. Nothing is rebuilt. The x86_64-sb
and arm64-sb builds carry their Secure Boot signatures inside the files, and
the shim finds snponly.efi and ipxe.efi by name in its own directory, so the
package keeps every name, symlink and byte of the release tree.
Files
-----
ipxeboot-2.0.0.tar.gz
The ipxeboot.tar.gz asset of
https://github.com/ipxe/ipxe/releases/tag/v2.0.0, renamed. Its SHA-256,
01a526d4cc791fc30362259c609d6c506cc64a7bdff51b9a5eb788354e17eee1, is the
digest that GitHub publishes for the asset.
ipxe-2.0.0-source.tar.gz
The source archive of tag v2.0.0, commit
12798ec29aa8a64d8675c4378b99f5fe28447afb, from
https://github.com/ipxe/ipxe/archive/refs/tags/v2.0.0.tar.gz. Its content
equals "git archive --prefix=ipxe-2.0.0/ v2.0.0". snpnet.c and undinet.c
are GPL2_OR_LATER without the UBDL, so snponly.efi and undionly.kpxe are
GPLv2+ as a whole. The package installs this archive with the binaries.
SHA256SUMS
The SHA-256 of both archives. Both builders check it before the build.
payload.sha256
One line for each directory, file and symlink of the release tree, with
the SHA-256 of each file and the target of each symlink. After the build,
both builders unpack the RPM or deb and compare its /tftpboot/xcat/ipxe
with this list, entry for entry, with verify-payload.pl. A difference
fails the build.
licenses/
ipxe/COPYING, COPYING.GPLv2 and COPYING.UBDL are from iPXE tag v2.0.0.
shim/COPYRIGHT is from ipxe/shim tag ipxe-16.1.
shim/openssl/LICENSE is from openssl/openssl tag OpenSSL_1_0_2k, the
OpenSSL version that shim 16.1 carries in Cryptlib.
shim/gnu-efi/README.efilib is from rhboot/gnu-efi commit dc7fd96, the
gnu-efi commit that tag ipxe-16.1 pins.
The shim
--------
x86_64-sb/shimx64.efi and arm64-sb/shimaa64.efi report shim 16.1, and
shimx64.efi is signed by the Microsoft Corporation UEFI CA 2011 only. The
ipxe/shim ipxe-16.1 release assets were replaced on 2026-05-27 with a build
signed by both the UEFI CA 2011 and the UEFI CA 2023. The files in this
release tree are the earlier 16.1 build.
Update to a new release
-----------------------
1. Download ipxeboot.tar.gz from the release, and compare its SHA-256 with
the digest on the release page.
2. Download the source archive of the tag, and compare its content with
"git archive" of the tag.
3. Replace both archives, and write SHA256SUMS with sha256sum.
4. Write payload.sha256:
mkdir tree
tar -xzf ipxeboot-<version>.tar.gz --strip-components=1 -C tree
./verify-payload.pl --generate tree > payload.sha256
5. Update licenses/ when the release changes its licence texts or its shim.
6. Set the version in ipxe-xcat.spec and debian/changelog, and the ipxe-xcat
pins in packages-manifest.conf and debs-manifest.conf.
+5
View File
@@ -0,0 +1,5 @@
ipxe-xcat (2.0.0-1) unstable; urgency=medium
* Package the ipxeboot.tar.gz tree of the iPXE v2.0.0 release.
-- xCAT <xcat-user@lists.sourceforge.net> Fri, 25 Sep 2026 12:00:00 +0000
+1
View File
@@ -0,0 +1 @@
12
+16
View File
@@ -0,0 +1,16 @@
Source: ipxe-xcat
Section: admin
Priority: optional
Maintainer: xCAT <xcat-user@lists.sourceforge.net>
Build-Depends: debhelper (>= 12)
Standards-Version: 4.5.0
Homepage: https://ipxe.org/
Package: ipxe-xcat
Architecture: all
Depends: ${misc:Depends}
Description: iPXE network boot binaries from the upstream release
The ipxeboot.tar.gz tree of the iPXE 2.0.0 release, installed unchanged
under /tftpboot/xcat/ipxe. It carries the signed Secure Boot builds and
their shim. The source archive of the release tag is installed with the
documentation.
+37
View File
@@ -0,0 +1,37 @@
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: iPXE
Source: https://github.com/ipxe/ipxe/releases/tag/v2.0.0
Comment: ipxeboot-2.0.0.tar.gz is the ipxeboot.tar.gz asset of the iPXE v2.0.0
release, unchanged. ipxe-2.0.0-source.tar.gz is the source archive of tag
v2.0.0, installed as /usr/share/doc/ipxe-xcat/ipxe-2.0.0-source.tar.gz.
.
The files x86_64-sb/shimx64.efi and arm64-sb/shimaa64.efi in the release tree
are shim 16.1, built by the iPXE project from ipxe/shim tag ipxe-16.1. Shim is
under the BSD licence in licenses/shim/COPYRIGHT and includes OpenSSL 1.0.2k
(licenses/shim/openssl/LICENSE) and gnu-efi (licenses/shim/gnu-efi/README.efilib).
.
The licence texts are installed in /usr/share/doc/ipxe-xcat/licenses/.
Files: *
Copyright: Michael Brown <mbrown@fensystems.co.uk> and the iPXE contributors
License: GPL-2+
iPXE files are licensed under the GNU General Public License, version 2 or
(at your option) any later version, unless the file states another licence.
Some files are licensed under version 2 only, some under BSD or MIT terms,
and most may also be used under the Unmodified Binary Distribution Licence
(licenses/ipxe/COPYING.UBDL). Each file in the source archive states its
own licence.
.
On Debian systems, the complete text of the GNU General Public License
version 2 can be found in /usr/share/common-licenses/GPL-2.
Files: debian/*
Copyright: xCAT contributors
License: GPL-2+
This packaging is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2 of the License, or (at your option)
any later version.
.
On Debian systems, the complete text of the GNU General Public License
version 2 can be found in /usr/share/common-licenses/GPL-2.
+36
View File
@@ -0,0 +1,36 @@
#!/usr/bin/make -f
# The payload is the upstream release tree, byte for byte: nothing strips it, and dh_compress and
# dh_fixperms leave /tftpboot and the licence texts alone.
VERSION := $(shell dpkg-parsechangelog -S Version | sed 's/-[^-]*$$//')
DEST := debian/ipxe-xcat
DOC := $(DEST)/usr/share/doc/ipxe-xcat
build build-arch build-indep:
clean:
dh_testdir
dh_clean
binary-arch:
binary-indep:
dh_testdir
dh_testroot
dh_prep
install -d $(DEST)/tftpboot/xcat/ipxe $(DOC)
tar -xzf ipxeboot-$(VERSION).tar.gz --no-same-owner --strip-components=1 -C $(DEST)/tftpboot/xcat/ipxe
install -m 0644 ipxe-$(VERSION)-source.tar.gz $(DOC)/
cp -R licenses $(DOC)/licenses
dh_installdocs
dh_installchangelogs
dh_compress -Xlicenses/
dh_fixperms -Xtftpboot/
dh_installdeb
dh_gencontrol
dh_md5sums
dh_builddeb
binary: binary-indep binary-arch
.PHONY: build build-arch build-indep clean binary-arch binary-indep binary
+1
View File
@@ -0,0 +1 @@
3.0 (native)
+53
View File
@@ -0,0 +1,53 @@
# The payload is the upstream release, byte for byte: signed EFI files must not be stripped or
# otherwise touched by the build-root policy scripts.
%global debug_package %{nil}
%global __os_install_post %{nil}
Name: ipxe-xcat
Version: 2.0.0
Release: 1
Summary: iPXE network boot binaries from the upstream release
License: GPL-2.0-only AND GPL-2.0-or-later AND BSD-2-Clause AND BSD-2-Clause-Patent AND BSD-3-Clause AND MIT AND OpenSSL
URL: https://ipxe.org/
BuildArch: noarch
Source0: ipxeboot-%{version}.tar.gz
Source1: ipxe-%{version}-source.tar.gz
Source2: licenses/ipxe/COPYING
Source3: licenses/ipxe/COPYING.GPLv2
Source4: licenses/ipxe/COPYING.UBDL
Source5: licenses/shim/COPYRIGHT
Source6: licenses/shim/openssl/LICENSE
Source7: licenses/shim/gnu-efi/README.efilib
%description
The ipxeboot.tar.gz tree of the iPXE %{version} release, installed unchanged
under /tftpboot/xcat/ipxe. It carries the signed Secure Boot builds and
their shim. The source archive of the release tag is installed with the
documentation.
%prep
%setup -q -c -T
install -D -m 0644 %{SOURCE2} licenses/ipxe/COPYING
install -D -m 0644 %{SOURCE3} licenses/ipxe/COPYING.GPLv2
install -D -m 0644 %{SOURCE4} licenses/ipxe/COPYING.UBDL
install -D -m 0644 %{SOURCE5} licenses/shim/COPYRIGHT
install -D -m 0644 %{SOURCE6} licenses/shim/openssl/LICENSE
install -D -m 0644 %{SOURCE7} licenses/shim/gnu-efi/README.efilib
%build
%install
mkdir -p %{buildroot}/tftpboot/xcat/ipxe
tar -xzf %{SOURCE0} --no-same-owner --strip-components=1 -C %{buildroot}/tftpboot/xcat/ipxe
install -D -m 0644 %{SOURCE1} %{buildroot}%{_pkgdocdir}/ipxe-%{version}-source.tar.gz
%files
/tftpboot/xcat/ipxe
%license licenses/ipxe licenses/shim
%dir %{_pkgdocdir}
%doc %{_pkgdocdir}/ipxe-%{version}-source.tar.gz
%changelog
* Fri Sep 25 2026 xCAT <xcat-user@lists.sourceforge.net> - 2.0.0-1
- Package the ipxeboot.tar.gz tree of the iPXE v2.0.0 release
+172
View File
@@ -0,0 +1,172 @@
#!/usr/bin/perl
# ipxe-xcat/mockbuild.pl -- build the ipxe-xcat noarch RPM with mock from the committed release
# archives. The archives are checked against SHA256SUMS before the build, and the built RPM payload
# against payload.sha256 before anything is copied to --result-dir.
use strict;
use warnings;
use Cwd qw(abs_path);
use File::Basename qw(basename);
use File::Copy qw(copy);
use File::Path qw(make_path remove_tree);
use FindBin qw($RealBin);
use Getopt::Long qw(GetOptions);
use lib "$RealBin/..", "$RealBin/../lib";
use MockBuildUtils qw(resolve_mock_cfg);
use XCAT::BuildUtils qw(capture_command digest_file print_step require_command run_command shell_quote);
my $pkg_dir = abs_path($RealBin);
my $repo_root = abs_path("$pkg_dir/..");
my $spec_file = "$pkg_dir/ipxe-xcat.spec";
my $work_dir = '/tmp/ipxe-xcat-mockbuild';
my $mock_cfg = '';
my $mock_uniqueext = '';
my $result_dir = "$repo_root/build-output/list3/ipxe-xcat";
my $log_dir = "$repo_root/build-logs/list3/ipxe-xcat";
my $build_timestamp;
GetOptions(
'work-dir=s' => \$work_dir,
'mock-cfg=s' => \$mock_cfg,
'mock-uniqueext=s' => \$mock_uniqueext,
'result-dir=s' => \$result_dir,
'log-dir=s' => \$log_dir,
'build-timestamp=i' => \$build_timestamp,
) or die usage();
die "Run as root (current uid=$>)\n" if $> != 0;
require_command($_) for qw(mock rpm rpm2cpio cpio bash sha256sum);
my ($version, @sources) = spec_sources($spec_file);
die "Could not parse Version from $spec_file\n" if !$version;
if (!$mock_cfg) {
my $os_id = capture_command('bash', '-c', 'source /etc/os-release; echo $ID');
my $arch = capture_command('uname', '-m');
$mock_cfg = resolve_mock_cfg($os_id, 10, $arch);
}
my @uniqueext = $mock_uniqueext ne '' ? ('--uniqueext', $mock_uniqueext) : ();
my $epoch = $build_timestamp;
if (!defined $epoch) {
$epoch = `git -C \Q$repo_root\E log -1 --format=%ct HEAD 2>/dev/null` // '';
chomp $epoch;
$epoch = time() if $epoch !~ /^\d+$/;
}
$ENV{SOURCE_DATE_EPOCH} = $epoch;
print_step('Configuration');
print "pkg_dir: $pkg_dir\n";
print "version: $version\n";
print "work_dir: $work_dir\n";
print "result_dir: $result_dir\n";
print "log_dir: $log_dir\n";
print "mock_cfg: $mock_cfg\n";
print_step('Check the release archives');
run_command('bash', '-c', 'cd ' . shell_quote($pkg_dir) . ' && sha256sum --check --strict SHA256SUMS');
print_step('Stage the sources');
remove_tree($work_dir) if -d $work_dir;
my $sources_dir = "$work_dir/sources";
make_path($sources_dir, $result_dir, $log_dir);
my %staged;
for my $source (@sources) {
my $name = basename($source);
die "Two Source files share the name $name\n" if $staged{$name}++;
copy("$pkg_dir/$source", "$sources_dir/$name")
or die "Failed to copy $pkg_dir/$source: $!\n";
}
run_command('bash', '-c', 'cd ' . shell_quote($sources_dir)
. ' && sha256sum --check --strict ' . shell_quote("$pkg_dir/SHA256SUMS"));
my $det_cfg = "$work_dir/mock-deterministic.cfg";
open(my $cfg_fh, '>', $det_cfg) or die "Cannot write $det_cfg: $!\n";
print {$cfg_fh} "include('/etc/mock/${mock_cfg}.cfg')\n";
print {$cfg_fh} "config_opts['environment']['SOURCE_DATE_EPOCH'] = '$epoch'\n";
close($cfg_fh) or die "Cannot write $det_cfg: $!\n";
my @defines = map { ('--define', $_) }
('use_source_date_epoch_as_buildtime 1', 'clamp_mtime_to_source_date_epoch 1', '_buildhost xcat-build');
print_step('Build the SRPM with mock');
my $srpm_out = "$work_dir/srpm";
make_path($srpm_out);
run_mock('mock', '-r', $det_cfg, @uniqueext, '--buildsrpm', '--spec', $spec_file,
'--sources', $sources_dir, '--resultdir', $srpm_out, @defines);
my @srpms = glob("$srpm_out/ipxe-xcat-*.src.rpm");
die "Expected one SRPM in $srpm_out, found " . scalar(@srpms) . "\n" if @srpms != 1;
print_step('Rebuild the RPM with mock');
my $rpm_out = "$work_dir/rpm";
make_path($rpm_out);
run_mock('mock', '-r', $det_cfg, @uniqueext, '--rebuild', $srpms[0], '--resultdir', $rpm_out, @defines);
my @rpms = glob("$rpm_out/ipxe-xcat-$version-*.noarch.rpm");
die "Expected one ipxe-xcat noarch RPM in $rpm_out, found " . scalar(@rpms) . "\n" if @rpms != 1;
my $rpm = $rpms[0];
print_step('Check the RPM payload');
my $payload = "$work_dir/payload";
make_path($payload);
run_command('bash', '-o', 'pipefail', '-c', 'cd ' . shell_quote($payload)
. ' && rpm2cpio ' . shell_quote($rpm) . ' | cpio -idm --quiet');
run_command('perl', "$pkg_dir/verify-payload.pl", "$payload/tftpboot/xcat/ipxe",
"$pkg_dir/payload.sha256");
check_installed("$payload/usr/share/doc/ipxe-xcat/ipxe-$version-source.tar.gz",
"$pkg_dir/ipxe-$version-source.tar.gz");
for my $licence (grep { m{^licenses/} } @sources) {
(my $installed = $licence) =~ s{^licenses/}{};
check_installed("$payload/usr/share/licenses/ipxe-xcat/$installed", "$pkg_dir/$licence");
}
print_step('Collect the results');
for my $file ($rpm, $srpms[0]) {
copy($file, $result_dir) or die "Failed to copy $file to $result_dir: $!\n";
print "Copied: $result_dir/" . basename($file) . "\n";
}
for my $log (qw(build.log root.log state.log)) {
copy("$rpm_out/$log", "$log_dir/$log") if -f "$rpm_out/$log";
copy("$srpm_out/$log", "$log_dir/srpm-$log") if -f "$srpm_out/$log";
}
print_step('Completed');
exit 0;
sub usage {
return <<"USAGE";
Usage: $0 [options]
--work-dir PATH Temporary work directory (default: $work_dir)
--mock-cfg NAME Mock config (default: the EL10 config of this host)
--mock-uniqueext TEXT mock --uniqueext suffix for concurrent builds
--result-dir PATH Output directory for the RPM and SRPM
--log-dir PATH Output directory for the mock logs
--build-timestamp EPOCH SOURCE_DATE_EPOCH for a reproducible build
USAGE
}
sub spec_sources {
my ($path) = @_;
open(my $fh, '<', $path) or die "Cannot read $path: $!\n";
my ($version, @sources) = ('');
while (my $line = <$fh>) {
$version = $1 if $line =~ /^Version:\s*(\S+)/;
push @sources, $1 if $line =~ /^Source\d*:\s*(\S+)/;
}
close($fh);
s/%\{version\}/$version/g for @sources;
return ($version, @sources);
}
sub check_installed {
my ($installed, $committed) = @_;
die "Missing from the RPM payload: $installed\n" if !-f $installed || -l $installed;
die "The RPM payload changed $installed\n" if digest_file($installed) ne digest_file($committed);
}
# mock exits 30 when its package manager failed, most often a transient mirror error: retry once.
sub run_mock {
my (@command) = @_;
my $ok = eval { run_command(@command) };
return 1 if $ok;
die $@ if $@ !~ /\(rc=30\)/;
print "mock failed with rc=30 (package manager); retrying once\n";
return run_command(@command);
}
+54
View File
@@ -0,0 +1,54 @@
# ipxe-xcat payload manifest, written by verify-payload.pl --generate
dir - arm32
file 2a8d50db2b3b5f02302302b3161931c1142301f42d52c64c0005974b602b7092 arm32/ipxe-legacy.efi
file fa58061710e6fab23fc27c6d200d510453c3f14f3bc0715fa6804111f1e5fc74 arm32/ipxe.efi
file 206310f30306569ed2c6e0ef015b3ad24230b303a1ad1171e19c117c914a65d6 arm32/snponly.efi
dir - arm64
dir - arm64-sb
link shimaa64.efi arm64-sb/ipxe-shim.efi
file 01b2438e6dc354c343590c308f1d4f000bc098be4d2237540432023abdbddcb8 arm64-sb/ipxe.efi
file 8c13ca9078279c4012dc26dbd095bbebd54553db88af0b67a76b1641cf7b1a87 arm64-sb/shimaa64.efi
link shimaa64.efi arm64-sb/snponly-shim.efi
file bed8da8639b45eeec55d41627349863efa5085a2113bb1193838b8a463e5f49e arm64-sb/snponly.efi
file cff2abf51b7b491d7c5e2ef68c45003a0b4c5e866cb5b20f162569746d53390d arm64/ipxe-legacy.efi
file a9cb6df506a68f3afa4bb94cf6cb8e3862a5a2ff3bf1d8027fea83f7e1d49217 arm64/ipxe.efi
file 03665b4184e4a0b8b9a889de0c7fb833fc48b02385e3fa40a4460db1122f1b36 arm64/snponly.efi
dir - i386
file 9dc4aee199f582fb8f55cf8bfb4622998c5e71c2dde149d5bbdfe33121c925d8 i386/ipxe-legacy.efi
file df9bab29487d20af3fe9dda46afc775009ba1c089d2216098b9a6e82d906939b i386/ipxe-legacy.pxe
file ea63c6d3745e751e8db4f9c8d4c97efa883fb6d0fc57c697b3d13ad98c1bfe0c i386/ipxe.efi
file a0f144a5f7e10e567d189606c6c2320c1f43a228f9fb6148e7e52f5009fd789f i386/ipxe.pxe
file 81a086995758b889fba7f13d7c5255dc7eb87ed38350b8c03112b9f56556de98 i386/snponly.efi
file ef6ff013f988c52feb3e543dccf0bdc50cd1d68b8a4ab84b8975cef33f64e848 i386/undionly.kpxe
link x86_64/ipxe-legacy.efi ipxe-legacy.efi
link x86_64/ipxe-legacy.pxe ipxe-legacy.pxe
link x86_64/ipxe.efi ipxe.efi
link x86_64/ipxe.pxe ipxe.pxe
dir - loong64
file 03b078b2ba00e97427b5d99b14035bdb7abdb48631aba8759cf95c24a2620b7e loong64/ipxe-legacy.efi
file c326c8bf54d8fc40fa6730907ee07cb44e8151ecc1397e1ddd2c0edef7cb2872 loong64/ipxe.efi
file fd7cb2df195ad5cc3a09f41fab23713afa23624ff664f83de0e7ca0fd5776fb7 loong64/snponly.efi
dir - riscv32
file 41f76da3efc3293887a701f35cac389c04a3a8110743673e37451e3c6e24e507 riscv32/ipxe-legacy.efi
file 4afd51329213e50a4aaf24b397e8aba67910ca1e94ea3a6fab0e089d91ac69b8 riscv32/ipxe.efi
file 0a901453bde1392051e53bb1e75584a4eb7cc9c75a27a2b34d7b26ad21734f8f riscv32/snponly.efi
dir - riscv64
file a72923e2ff600bd94628ef5f97a7ddd5c23fabdc9736fdaa2c22cfb7f0fe908d riscv64/ipxe-legacy.efi
file 53c926c45043c1f2ad03aa70aa22921accc3202865c791cc6023fa17d92f8f24 riscv64/ipxe.efi
file 95b9f6466e0d88fafe642c46d3d6024e4107cac24d2197664b62610f21a48585 riscv64/snponly.efi
link x86_64-sb sb
link x86_64/snponly.efi snponly.efi
link x86_64/undionly.kpxe undionly.kpxe
dir - x86_64
dir - x86_64-sb
link shimx64.efi x86_64-sb/ipxe-shim.efi
file 6558e37887516b246d6a97122e8d18bedfe4197b7ba7f67bf1bf102a16678d33 x86_64-sb/ipxe.efi
file 83ad71c7d4f2cf328b75b653d09bf3bea5f29bee2e67ca058f37d83c07133885 x86_64-sb/shimx64.efi
link shimx64.efi x86_64-sb/snponly-shim.efi
file b1e67c3e4a1e8708ddfd0079ad4505e3a02245acb55ee9a95437ab3c507be82a x86_64-sb/snponly.efi
file 1d567f2e89a3c0cf0a184549918a3e799a47dc542df385c56e6b464e4765fae2 x86_64/ipxe-legacy.efi
file fc37ef1e4a4bd5d22f8db3c84e1718ac8b03fe20156cf2fc4b9e2ae5e4a348db x86_64/ipxe-legacy.pxe
file 868aa34057ff416ebf2fdfb5781de035e2c540477c04039198a9f8a9c6130034 x86_64/ipxe.efi
file 0fb21c695c82fd70d4f89732ddcd285063776e2bbd71de9a2c39e9cfe4b180b8 x86_64/ipxe.pxe
file f61c2ce34e05d7d857633df2e512d547df75b6aa18b2da152a7c9af222cfe28f x86_64/snponly.efi
file 4186562d21ff54e970d905751c9f36d628e73a51a94afe4a6a42f925b0df448c x86_64/undionly.kpxe
+55
View File
@@ -0,0 +1,55 @@
#!/usr/bin/env perl
# ipxe-xcat/sbuild.pl -- per-package Ubuntu/Debian builder for ipxe-xcat, the apt analogue of
# ipxe-xcat/mockbuild.pl. Invoked by sbuild-all.pl per (codename,arch); also runnable standalone.
# The build runs on a copy of the package tree inside the <codename>-<arch>-sbuild chroot, and it
# checks the archives before dpkg-buildpackage and the built payload after it, so a deb that
# differs from the release never reaches --result-dir.
use strict;
use warnings;
use Cwd qw(abs_path);
use File::Basename qw(basename);
use Getopt::Long qw(GetOptions);
use FindBin qw($RealBin);
use lib "$RealBin/..";
use BuildUtils qw(chroot_name build_deb_in_chroot);
my $pkg_dir = abs_path($RealBin);
my $pkg = basename($pkg_dir);
my ($codename, $arch, $chroot, $result_dir, $log_dir) = ('', '', '', '', '');
my ($build_timestamp, $build_number, $skip_install) = (undef, undef, 0);
# --log-dir, --build-number and --skip-install keep the command line sbuild-all.pl passes to every
# builder; this package has no use for them.
GetOptions(
'codename=s' => \$codename, 'arch=s' => \$arch, 'chroot=s' => \$chroot,
'result-dir=s' => \$result_dir, 'log-dir=s' => \$log_dir,
'build-timestamp=i' => \$build_timestamp, 'build-number=i' => \$build_number,
'skip-install!' => \$skip_install,
) or die "bad options\n";
$arch ||= `dpkg --print-architecture 2>/dev/null`; chomp $arch; $arch ||= 'amd64';
die "FATAL: --codename required\n" unless $codename;
$chroot ||= chroot_name($codename, $arch);
$result_dir ||= "$pkg_dir/../build-output/sbuild/$codename/$arch";
$build_timestamp = time() unless defined $build_timestamp;
# ipxe-xcat is Architecture:all and is built once on amd64 (see debs-manifest.conf).
my $build = <<'BUILD';
set -e
sha256sum --check --strict SHA256SUMS
dpkg-buildpackage -uc -us -b
version=$(dpkg-parsechangelog -S Version)
payload=$(mktemp -d)
dpkg-deb -x "../ipxe-xcat_${version}_all.deb" "$payload"
perl ./verify-payload.pl "$payload/tftpboot/xcat/ipxe" payload.sha256
source_archive="ipxe-${version%-*}-source.tar.gz"
grep -F " $source_archive" SHA256SUMS \
| (cd "$payload/usr/share/doc/ipxe-xcat" && sha256sum --check --strict -)
for licence in $(cd licenses && find . -type f); do
cmp "licenses/$licence" "$payload/usr/share/doc/ipxe-xcat/licenses/$licence"
done
rm -rf "$payload"
BUILD
build_deb_in_chroot(
pkg => $pkg, chroot => $chroot, pkg_dir => $pkg_dir, result_dir => $result_dir,
build_timestamp => $build_timestamp, build => $build,
);
+118
View File
@@ -0,0 +1,118 @@
#!/usr/bin/perl
# verify-payload.pl -- compare an unpacked ipxe-xcat tree with payload.sha256.
#
# verify-payload.pl --generate <tree> > payload.sha256
# verify-payload.pl <tree> <payload.sha256>
#
# Each manifest line is "<type>\t<value>\t<path>", sorted by path: "file" with the SHA-256 of the
# content, "link" with the symlink target, "dir" with "-". Paths are relative to <tree>, and
# symlinks are never followed. The check exits 0 when the tree matches the manifest entry for
# entry, 1 when it differs, and 2 on a usage or read error.
use strict;
use warnings;
use Digest::SHA ();
use File::Find ();
use Getopt::Long qw(GetOptions);
my $generate = 0;
GetOptions('generate' => \$generate) or usage();
if ($generate) {
usage() if @ARGV != 1;
my $tree = scan_tree($ARGV[0]);
print "# ipxe-xcat payload manifest, written by verify-payload.pl --generate\n";
for my $path (sort keys %{$tree}) {
print join("\t", @{ $tree->{$path} }, $path), "\n";
}
exit 0;
}
usage() if @ARGV != 2;
my ($root, $manifest_file) = @ARGV;
my $expected = read_manifest($manifest_file);
my $found = scan_tree($root);
my @problems;
for my $path (sort keys %{$expected}) {
my ($type, $value) = @{ $expected->{$path} };
if (!exists $found->{$path}) {
push @problems, "missing: $path";
next;
}
my ($found_type, $found_value) = @{ $found->{$path} };
if ($found_type ne $type) {
push @problems, "type changed: $path (expected $type, found $found_type)";
} elsif ($type eq 'file' && $found_value ne $value) {
push @problems, "content changed: $path";
} elsif ($type eq 'link' && $found_value ne $value) {
push @problems, "link target changed: $path (expected $value, found $found_value)";
}
}
push @problems, map { "unexpected: $_" } grep { !exists $expected->{$_} } sort keys %{$found};
if (@problems) {
print STDERR "$_\n" for @problems;
print STDERR "payload does not match $manifest_file: " . scalar(@problems) . " difference(s)\n";
exit 1;
}
print "payload matches $manifest_file: " . scalar(keys %{$expected}) . " entries\n";
exit 0;
sub usage {
print STDERR "Usage: $0 --generate <tree>\n $0 <tree> <payload.sha256>\n";
exit 2;
}
sub fail {
my ($message) = @_;
print STDERR "$0: $message\n";
exit 2;
}
sub scan_tree {
my ($dir) = @_;
$dir =~ s{/+\z}{} if $dir ne '/';
fail("not a directory: $dir") if -l $dir || !-d $dir;
my %entries;
File::Find::find({
no_chdir => 1,
wanted => sub {
my $path = $File::Find::name;
return if $path eq $dir;
my $relative = substr($path, length($dir) + 1);
lstat($path) or fail("cannot stat $path: $!");
if (-l _) {
my $target = readlink($path);
fail("cannot read link $path: $!") if !defined $target;
$entries{$relative} = ['link', $target];
} elsif (-d _) {
$entries{$relative} = ['dir', '-'];
} elsif (-f _) {
my $sha = Digest::SHA->new(256);
eval { $sha->addfile($path, 'b'); 1 } or fail("cannot read $path: $@");
$entries{$relative} = ['file', $sha->hexdigest];
} else {
$entries{$relative} = ['other', '-'];
}
},
}, $dir);
return \%entries;
}
sub read_manifest {
my ($file) = @_;
open(my $fh, '<', $file) or fail("cannot read $file: $!");
my %entries;
while (my $line = <$fh>) {
chomp $line;
next if $line =~ /^\s*(?:#|$)/;
my ($type, $value, $path) = split(/\t/, $line, 3);
fail("$file line $.: malformed entry")
if !defined $path || $path eq '' || $type !~ /^(?:file|link|dir)$/
|| ($type eq 'file' && $value !~ /^[0-9a-f]{64}$/);
fail("$file line $.: duplicate path $path") if exists $entries{$path};
$entries{$path} = [$type, $value];
}
close($fh);
return \%entries;
}