fix(image): preserve installer kernel and verified update contracts
This commit is contained in:
@@ -142,6 +142,8 @@ def kernel_image(root):
|
|||||||
candidates = [root_path(root, 'boot/' + prefix + version)
|
candidates = [root_path(root, 'boot/' + prefix + version)
|
||||||
for prefix in ('kernel-', 'vmlinuz-')]
|
for prefix in ('kernel-', 'vmlinuz-')]
|
||||||
images = [path for path in candidates if path.is_file()]
|
images = [path for path in candidates if path.is_file()]
|
||||||
|
if len(images) == 2 and images[0].samefile(images[1]):
|
||||||
|
return images[1] # Stable installer/GRUB vmlinuz alias for Gentoo kernel-bin.
|
||||||
if len(images) != 1:
|
if len(images) != 1:
|
||||||
raise ImageError('Installed modules require exactly one matching boot kernel image')
|
raise ImageError('Installed modules require exactly one matching boot kernel image')
|
||||||
return images[0]
|
return images[0]
|
||||||
@@ -256,6 +258,10 @@ def configure_rootfs(root, source):
|
|||||||
if not (source / name).is_file():
|
if not (source / name).is_file():
|
||||||
raise ImageError(f'Required committed runtime/installer asset is missing: {name}')
|
raise ImageError(f'Required committed runtime/installer asset is missing: {name}')
|
||||||
version = kernel_version(root)
|
version = kernel_version(root)
|
||||||
|
kernel = kernel_image(root)
|
||||||
|
alias = root_path(root, 'boot/vmlinuz-' + version)
|
||||||
|
if not alias.exists():
|
||||||
|
alias.symlink_to(kernel.name)
|
||||||
sanitize_rootfs(root)
|
sanitize_rootfs(root)
|
||||||
copy_overlay(root, source / 'image/rootfs')
|
copy_overlay(root, source / 'image/rootfs')
|
||||||
write(root, 'etc/hydra/live-mode/dracut.conf', (source / 'image/dracut.conf').read_text())
|
write(root, 'etc/hydra/live-mode/dracut.conf', (source / 'image/dracut.conf').read_text())
|
||||||
|
|||||||
+11
-2
@@ -8,6 +8,8 @@ scripts/hydra-build fetch
|
|||||||
scripts/hydra-build prepare
|
scripts/hydra-build prepare
|
||||||
scripts/hydra-build packages --pretend
|
scripts/hydra-build packages --pretend
|
||||||
scripts/hydra-build packages
|
scripts/hydra-build packages
|
||||||
|
scripts/hydra-build rootfs
|
||||||
|
scripts/hydra-build iso
|
||||||
scripts/hydra-build status
|
scripts/hydra-build status
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -34,5 +36,12 @@ for installed-system updates. Rolling binhost contents can change; resulting
|
|||||||
versions/USE are recorded without claiming bit-identical output. The pinned
|
versions/USE are recorded without claiming bit-identical output. The pinned
|
||||||
service-keyring hash may need deliberate review when Gentoo rotates keys.
|
service-keyring hash may need deliberate review when Gentoo rotates keys.
|
||||||
|
|
||||||
`rootfs` and `iso` are reserved assembly commands and currently return an
|
`rootfs` exports the dedicated builder into a private intermediate and assembles
|
||||||
explicit error until the live-image assembly implementation is integrated.
|
an isolated sanitized payload, generic live initramfs and squashfs. `iso` checks
|
||||||
|
those artifacts and emits the UEFI `HYDRA_OS` ISO, SHA256 and build manifest in
|
||||||
|
`build/artifacts/`. The working builder is retained for package retries. The
|
||||||
|
installed Gentoo repository uses the standard rsync backend with signed
|
||||||
|
metamanifest verification; the builder continues to use its pinned snapshot.
|
||||||
|
QEMU and remote-viewer retain local patches and are excluded from upstream
|
||||||
|
binary packages on installed updates. Disposable boot/install validation is
|
||||||
|
required before treating an emitted ISO as release ready.
|
||||||
|
|||||||
@@ -6,6 +6,11 @@ if [[ $# != 1 || "$1" != /hydra-output/rootfs ]]; then
|
|||||||
fi
|
fi
|
||||||
root=$1
|
root=$1
|
||||||
python3 /hydra-source/hydra/image.py configure "$root" --source /hydra-source
|
python3 /hydra-source/hydra/image.py configure "$root" --source /hydra-source
|
||||||
|
# This is a separate rootfs inside the assembly container, never the host root.
|
||||||
|
mount --bind /dev "$root/dev"
|
||||||
|
mount -t proc proc "$root/proc"
|
||||||
|
mount --bind /sys "$root/sys"
|
||||||
|
trap 'umount "$root/sys" "$root/proc" "$root/dev"' EXIT
|
||||||
for group in wheel kvm video render audio; do
|
for group in wheel kvm video render audio; do
|
||||||
chroot "$root" getent group "$group" >/dev/null || chroot "$root" groupadd -r "$group"
|
chroot "$root" getent group "$group" >/dev/null || chroot "$root" groupadd -r "$group"
|
||||||
done
|
done
|
||||||
@@ -24,10 +29,5 @@ chroot "$root" chmod 0750 /usr/libexec/qemu-bridge-helper
|
|||||||
chroot "$root" visudo --check
|
chroot "$root" visudo --check
|
||||||
systemctl --root="$root" enable NetworkManager.service greetd.service hydra-network.service hydra-dnsmasq.service hydra-bridge-permissions.service getty@tty2.service serial-getty@ttyS0.service
|
systemctl --root="$root" enable NetworkManager.service greetd.service hydra-network.service hydra-dnsmasq.service hydra-bridge-permissions.service getty@tty2.service serial-getty@ttyS0.service
|
||||||
systemctl --root="$root" set-default graphical.target
|
systemctl --root="$root" set-default graphical.target
|
||||||
# This is a separate rootfs inside the assembly container, never the host root.
|
|
||||||
mount --bind /dev "$root/dev"
|
|
||||||
mount -t proc proc "$root/proc"
|
|
||||||
mount --bind /sys "$root/sys"
|
|
||||||
trap 'umount "$root/sys" "$root/proc" "$root/dev"' EXIT
|
|
||||||
kernel=$(python3 /hydra-source/hydra/image.py kernel "$root")
|
kernel=$(python3 /hydra-source/hydra/image.py kernel "$root")
|
||||||
chroot "$root" dracut --force --no-hostonly --no-hostonly-cmdline --conf /etc/hydra/live-mode/dracut.conf --confdir /etc/hydra/live-mode/dracut.conf.d --add dmsquash-live /boot/initramfs-live.img "$kernel"
|
chroot "$root" dracut --force --no-hostonly --no-hostonly-cmdline --conf /etc/hydra/live-mode/dracut.conf --confdir /etc/hydra/live-mode/dracut.conf.d --add dmsquash-live /boot/initramfs-live.img "$kernel"
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
[gentoo]
|
||||||
|
location = /var/db/repos/gentoo
|
||||||
|
sync-type = rsync
|
||||||
|
sync-uri = rsync://rsync.gentoo.org/gentoo-portage
|
||||||
|
auto-sync = yes
|
||||||
|
sync-rsync-verify-metamanifest = yes
|
||||||
|
sync-rsync-verify-max-age = 3
|
||||||
|
sync-openpgp-key-package = sec-keys/openpgp-keys-gentoo-release
|
||||||
|
sync-openpgp-key-path = /usr/share/openpgp-keys/gentoo-release.asc
|
||||||
|
sync-openpgp-keyserver = hkps://keys.gentoo.org
|
||||||
|
sync-webrsync-verify-signature = yes
|
||||||
@@ -46,6 +46,37 @@ class ImageTests(unittest.TestCase):
|
|||||||
self.assertEqual(image.kernel_version(self.root), version)
|
self.assertEqual(image.kernel_version(self.root), version)
|
||||||
self.assertEqual(image.kernel_image(self.root), kernel)
|
self.assertEqual(image.kernel_image(self.root), kernel)
|
||||||
|
|
||||||
|
def test_configured_real_kernel_layout_is_accepted_by_installer(self):
|
||||||
|
from hydra.installer import select_kernel
|
||||||
|
version = '6.18.54-gentoo-dist-bin'
|
||||||
|
(self.root / 'lib/modules' / version).mkdir(parents=True)
|
||||||
|
kernel = self.file('boot/kernel-' + version, 'real Gentoo kernel')
|
||||||
|
image.configure_rootfs(self.root, Path(__file__).resolve().parents[1])
|
||||||
|
self.assertEqual(select_kernel(self.root, None), version)
|
||||||
|
alias = self.root / ('boot/vmlinuz-' + version)
|
||||||
|
self.assertTrue(alias.samefile(kernel))
|
||||||
|
self.assertEqual(image.kernel_image(self.root), alias)
|
||||||
|
|
||||||
|
def test_exported_repository_sync_works_with_extracted_tree(self):
|
||||||
|
import configparser
|
||||||
|
self.kernel()
|
||||||
|
self.file('etc/portage/repos.conf/gentoo.conf',
|
||||||
|
'[gentoo]\nlocation=/var/db/repos/gentoo\nsync-type=git\nauto-sync=no\n')
|
||||||
|
self.file('var/db/repos/gentoo/profiles/repo_name', 'gentoo')
|
||||||
|
image.configure_rootfs(self.root, Path(__file__).resolve().parents[1])
|
||||||
|
config = configparser.ConfigParser()
|
||||||
|
config.read(self.root / 'etc/portage/repos.conf/gentoo.conf')
|
||||||
|
repo = config['gentoo']
|
||||||
|
self.assertEqual(repo['sync-type'], 'rsync')
|
||||||
|
self.assertEqual(repo['sync-uri'], 'rsync://rsync.gentoo.org/gentoo-portage')
|
||||||
|
self.assertEqual(repo['auto-sync'], 'yes')
|
||||||
|
self.assertEqual(repo['sync-rsync-verify-metamanifest'], 'yes')
|
||||||
|
self.assertEqual(repo['sync-openpgp-key-path'], '/usr/share/openpgp-keys/gentoo-release.asc')
|
||||||
|
self.assertFalse((self.root / 'var/db/repos/gentoo/.git').exists())
|
||||||
|
source = Path(__file__).resolve().parents[1]
|
||||||
|
builder_config = (source / 'image/portage/repos.conf/gentoo.conf').read_text()
|
||||||
|
self.assertIn('auto-sync = no', builder_config)
|
||||||
|
|
||||||
def test_conflicting_kernel_images_refused(self):
|
def test_conflicting_kernel_images_refused(self):
|
||||||
version = self.kernel()
|
version = self.kernel()
|
||||||
self.file('boot/kernel-' + version, 'different kernel')
|
self.file('boot/kernel-' + version, 'different kernel')
|
||||||
|
|||||||
Reference in New Issue
Block a user