Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package mkosi for openSUSE:Factory checked in at 2026-10-07 19:34:58 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/mkosi (Old) and /work/SRC/openSUSE:Factory/.mkosi.new.3698736 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "mkosi" Wed Oct 7 19:34:58 2026 rev:35 rq:1382954 version:27.1 Changes: -------- --- /work/SRC/openSUSE:Factory/mkosi/mkosi.changes 2026-09-10 11:52:21.816037286 +0200 +++ /work/SRC/openSUSE:Factory/.mkosi.new.3698736/mkosi.changes 2026-10-07 19:35:50.204766747 +0200 @@ -1,0 +2,29 @@ +Mon Oct 5 14:46:35 UTC 2026 - Antonio Feijoo <[email protected]> + +- Update to 27.1: + * Fix tests failing in restricted build environments. + * SignInitrdPCRs= can be used with SplitArtifacts=pcrs, fixing initrd-specific + PCR policies with systemd v262. + * Don't fail creating initrds when there are directories mixed in with + microcode files. + * Fix builds when using unsigned local repositories with opensuse. + * Only use repositories and variables from the sandbox tree when using DNF. + * The mkosi-obs no longer sets MakeScriptsExecutable=, except for the main + image, so it can be included again. + * The security and debug repositories are switched back to deb.debian.org and + are no longer set by the Repositories= setting. + * Add an environment variable MKOSI_FORCE_USERNS_FALLBACK that when set to a + value that parses as a truthy bool, skips using systemd-nsresourced. + * A new setting DelegateRanges= is added that defaults to 0 when mkosi is run + as the root user. This fixes builds run as the root user. + +- Remove 0003-mkosi-obs-Only-configure-MakeScriptsExecutable-in-th.patch, merged + in version 27.1. + +- Remove 0002-opensuse-tolerate-missing-RPM-keyring.patch, merged + in version 27.1. + +- Remove 0001-tests-skip-test_fork_and_wait-if-on-rc-1.patch, merged + in version 27.1. + +------------------------------------------------------------------- Old: ---- 0001-tests-skip-test_fork_and_wait-if-on-rc-1.patch 0002-opensuse-tolerate-missing-RPM-keyring.patch 0003-mkosi-obs-Only-configure-MakeScriptsExecutable-in-th.patch mkosi-27.tar.gz New: ---- mkosi-27.1.tar.gz ----------(Old B)---------- Old: - Remove 0001-tests-skip-test_fork_and_wait-if-on-rc-1.patch, merged in version 27.1. Old: - Remove 0002-opensuse-tolerate-missing-RPM-keyring.patch, merged in version 27.1. Old: - Remove 0003-mkosi-obs-Only-configure-MakeScriptsExecutable-in-th.patch, merged in version 27.1. ----------(Old E)---------- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ mkosi.spec ++++++ --- /var/tmp/diff_new_pack.gG87Fx/_old 2026-10-07 19:35:51.012800529 +0200 +++ /var/tmp/diff_new_pack.gG87Fx/_new 2026-10-07 19:35:51.018800780 +0200 @@ -28,7 +28,7 @@ %endif Name: mkosi -Version: 27 +Version: 27.1 Release: 0 Summary: Build bespoke OS Images License: LGPL-2.1-or-later @@ -36,12 +36,6 @@ URL: https://github.com/systemd/mkosi Source0: https://github.com/systemd/mkosi/archive/v%{version}.tar.gz#/%{name}-%{version}.tar.gz Source1: mkosi-initrd.conf -# PATCH-FIX-UPSTREAM https://github.com/systemd/mkosi/pull/4432 -Patch0: 0001-tests-skip-test_fork_and_wait-if-on-rc-1.patch -# PATCH-FIX-UPSTREAM https://github.com/systemd/mkosi/pull/4442 -Patch1: 0002-opensuse-tolerate-missing-RPM-keyring.patch -# PATCH-FIX-UPSTREAM https://github.com/systemd/mkosi/pull/4453 -Patch2: 0003-mkosi-obs-Only-configure-MakeScriptsExecutable-in-th.patch BuildRequires: %{python_module pip} BuildRequires: %{python_module pytest} BuildRequires: %{python_module wheel} ++++++ mkosi-27.tar.gz -> mkosi-27.1.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mkosi-27/action.yaml new/mkosi-27.1/action.yaml --- old/mkosi-27/action.yaml 2026-08-27 16:30:58.000000000 +0200 +++ new/mkosi-27.1/action.yaml 2026-09-28 15:32:03.000000000 +0200 @@ -118,8 +118,8 @@ run: | set +e APK_TOOLS_API="https://gitlab.alpinelinux.org/api/v4/projects/5" - APK_FALLBACK_VERSION='v3.0.7' - APK_FALLBACK_SHA256='c07bf5356eacc9dd7a8c56bc537f46702f007170287403299d52a04264e74b3c' + APK_FALLBACK_VERSION='v3.0.8' + APK_FALLBACK_SHA256='11758d76de3699c7606152357f415f55879743ccf0e3d8942d5ba98cf29a3c86' APK_VERSION=$(curl -fsSL --retry 5 --retry-all-errors --retry-max-time 30 "${APK_TOOLS_API}/repository/tags" | jq -r '.[].name' | grep -v '_rc' | sort -V | tail -1) if [[ -n "$APK_VERSION" && "$APK_VERSION" != "$APK_FALLBACK_VERSION" ]] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mkosi-27/docs/root-verity.md new/mkosi-27.1/docs/root-verity.md --- old/mkosi-27/docs/root-verity.md 2026-08-27 16:30:58.000000000 +0200 +++ new/mkosi-27.1/docs/root-verity.md 2026-09-28 15:32:03.000000000 +0200 @@ -144,7 +144,7 @@ whose contents will depend on how updates are deployed: ```ini -# /usr/lib/sysupdate.d/10-root-verity-sig.conf +# /usr/lib/sysupdate.d/10-root-verity-sig.transfer [Transfer] ProtectVersion=%A @@ -156,7 +156,7 @@ PartitionFlags=0 ReadOnly=1 -# /usr/lib/sysupdate.d/11-root-verity.conf +# /usr/lib/sysupdate.d/11-root-verity.transfer [Transfer] ProtectVersion=%A @@ -168,7 +168,7 @@ PartitionFlags=0 ReadOnly=1 -# /usr/lib/sysupdate.d/12-root.conf +# /usr/lib/sysupdate.d/12-root.transfer [Transfer] ProtectVersion=%A @@ -180,7 +180,7 @@ PartitionFlags=0 ReadOnly=1 -# /usr/lib/sysupdate.d/20-uki.conf +# /usr/lib/sysupdate.d/20-uki.transfer [Transfer] ProtectVersion=%A diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mkosi-27/mkosi/__init__.py new/mkosi-27.1/mkosi/__init__.py --- old/mkosi-27/mkosi/__init__.py 2026-08-27 16:30:58.000000000 +0200 +++ new/mkosi-27.1/mkosi/__init__.py 2026-09-28 15:32:03.000000000 +0200 @@ -1504,11 +1504,18 @@ if amd.exists(): with (destdir / "AuthenticAMD.bin").open("wb") as f: for p in amd.iterdir(): + if not p.is_file(): + continue f.write(p.read_bytes()) if intel.exists(): with (destdir / "GenuineIntel.bin").open("wb") as f: for p in intel.iterdir(): + # On some distributions the Intel ucode directory may contain directories like + # intel-ucode-with-caveats, that contain microcode that needs special patches in the + # kernel or other manual interventions, so we ignore these. + if not p.is_file(): + continue f.write(p.read_bytes()) # Normalize timestamps for reproducible builds before creating cpio @@ -1721,6 +1728,7 @@ die("Could not find ukify") json_out = False + ukify_version = systemd_tool_version(python_binary(context.config), ukify, sandbox=context.sandbox) arguments: list[PathString] = [ "--os-release", f"@{workdir(context.root / 'usr/lib/os-release')}", @@ -1776,15 +1784,13 @@ "--pcr-banks", "sha256", ] # fmt: skip - ukify_version = systemd_tool_version(python_binary(context.config), ukify, sandbox=context.sandbox) - if ukify_version >= "258": cert_parameter = "--pcr-certificate" else: cert_parameter = "--pcr-public-key" if context.config.sign_initrd_pcrs == ConfigFeature.enabled or ( - context.config.sign_initrd_pcrs == ConfigFeature.auto and ukify_version >= "261.999" + context.config.sign_initrd_pcrs == ConfigFeature.auto and ukify_version >= "262~" ): arguments += ["--sign-initrd-pcrs"] @@ -1830,6 +1836,10 @@ "--pcr-banks", "sha256", "--pcr-certificate", workdir(context.config.sign_expected_pcr_certificate), ] # fmt: skip + if context.config.sign_initrd_pcrs == ConfigFeature.enabled or ( + context.config.sign_initrd_pcrs == ConfigFeature.auto and ukify_version >= "262~" + ): + arguments += ["--sign-initrd-pcrs"] options += [ "--ro-bind", context.config.sign_expected_pcr_certificate, workdir(context.config.sign_expected_pcr_certificate), # noqa: E501 ] # fmt: skip @@ -2754,8 +2764,10 @@ hint="Run mkosi genkey to generate a key/certificate pair", ) - if config.sign_initrd_pcrs == ConfigFeature.enabled and not want_signed_pcrs(config): - die("SignInitrdPCRs= is enabled but PCR signing is not enabled") + if config.sign_initrd_pcrs == ConfigFeature.enabled and not ( + want_signed_pcrs(config) or ArtifactOutput.pcrs in config.split_artifacts + ): + die("SignInitrdPCRs= is enabled but neither PCR signing nor SplitArtifacts=pcrs are enabled") if config.secure_boot_key_source != config.sign_expected_pcr_key_source: die("Secure boot key source and expected PCR signatures key source have to be the same") @@ -2909,7 +2921,7 @@ if config.sign_initrd_pcrs == ConfigFeature.enabled and want_signed_pcrs(config): check_ukify( config, - version="261.999", + version="262~", reason="sign a PCR policy for the initrd", ) @@ -5097,9 +5109,17 @@ return try: + if parse_boolean(os.getenv("MKOSI_FORCE_USERNS_FALLBACK") or "0"): + raise ConnectionRefusedError("Forced fallback to unpriv userns.") + # Try to get a user namespace with some delegated ranges and the foreign UID range via - # systemd-nsresourced if we can. - acquire_privileges(foreign=True, delegate=3) + # systemd-nsresourced if we can, unless we're running as root, then + # - Only use the foreign UID range if it was explicitly requested + # - Only use delegated ranges if they were requested + acquire_privileges( + foreign=last.foreign_uid_range if (os.getuid() == 0 and os.getgid() == 0) else True, + delegate_ranges=last.delegate_ranges, + ) # Don't fail if systemd-nsresourced is too old, not installed or refuses to provision a user namespace # for us unless the foreign UID range was explicitly requested, use a regular unpriv user namespace # instead. @@ -5114,7 +5134,7 @@ if last.foreign_uid_range: die(f"Could not provision user namespace via systemd-nsresourced ({e})") - logging.debug( + logging.info( f"Could not provision user namespace via systemd-nsresourced ({e}), falling back to " "unprivileged user namespace via unshare(CLONE_NEWUSER) and writing /proc/self/uid_map directly", ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mkosi-27/mkosi/config.py new/mkosi-27.1/mkosi/config.py --- old/mkosi-27/mkosi/config.py 2026-08-27 16:30:58.000000000 +0200 +++ new/mkosi-27.1/mkosi/config.py 2026-09-28 15:32:03.000000000 +0200 @@ -908,6 +908,18 @@ return parse_boolean(value) +def config_parse_int(value: Optional[str], old: Optional[int]) -> Optional[int]: + if value is None: + return None + + try: + num = int(value) + except ValueError: + die(f"{value!r} is not a valid integer") + + return num + + def parse_feature(value: str) -> ConfigFeature: try: return ConfigFeature(value) @@ -2245,6 +2257,7 @@ proxy_client_key: Optional[Path] make_scripts_executable: bool foreign_uid_range: bool + delegate_ranges: int nspawn_settings: Optional[Path] ephemeral: bool @@ -4194,6 +4207,15 @@ help="Use the foreign UID range", scope=SettingScope.main, ), + ConfigSetting( + dest="delegate_ranges", + name="DelegateRanges", + section="Build", + default=0 if (os.getuid() == 0 and os.getgid() == 0) else 3, + parse=config_parse_int, + help="Delegate this number of UID ranges in the foreign UID range", + scope=SettingScope.main, + ), # Runtime section ConfigSetting( dest="nspawn_settings", @@ -6011,6 +6033,9 @@ Tools Tree: {config.tools_tree} Tools Tree Certificates: {yes_no(config.tools_tree_certificates)} + Use the Foreign UID Range: {yes_no(config.foreign_uid_range)} + Number of Delegated Ranges: {config.delegate_ranges} + Extra Search Paths: {line_join_list(config.extra_search_paths)} Incremental: {config.incremental} Use Only Package Cache: {config.cacheonly} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mkosi-27/mkosi/distribution/debian.py new/mkosi-27.1/mkosi/distribution/debian.py --- old/mkosi-27/mkosi/distribution/debian.py 2026-08-27 16:30:58.000000000 +0200 +++ new/mkosi-27.1/mkosi/distribution/debian.py 2026-09-28 15:32:03.000000000 +0200 @@ -81,7 +81,7 @@ if snapshot: url = join_mirror(mirror, f"archive/debian-debug/{snapshot}") else: - url = join_mirror(mirror, "debian-debug") + url = "http://deb.debian.org/debian-debug" yield AptRepository( types=types, @@ -107,7 +107,7 @@ if snapshot: url = join_mirror(mirror, f"archive/debian-security/{snapshot}") else: - url = join_mirror(mirror, "debian-security") + url = "http://deb.debian.org/debian-security" yield AptRepository( types=types, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mkosi-27/mkosi/distribution/opensuse.py new/mkosi-27.1/mkosi/distribution/opensuse.py --- old/mkosi-27/mkosi/distribution/opensuse.py 2026-08-27 16:30:58.000000000 +0200 +++ new/mkosi-27.1/mkosi/distribution/opensuse.py 2026-09-28 15:32:03.000000000 +0200 @@ -1,6 +1,7 @@ # SPDX-License-Identifier: LGPL-2.1-or-later import os +import subprocess import tempfile from collections.abc import Iterable, Sequence from pathlib import Path @@ -57,7 +58,7 @@ options = context.rootoptions() gpgkeys: Sequence[PathString] = [] - if (p := context.keyring_dir / "opensuse.gpg").exists(): + if (p := context.keyring_dir / "opensuse.gpg").exists() and p.stat().st_size > 0: gpgkeys = [workdir(p)] options += ["--bind", os.fspath(p), workdir(p)] else: @@ -76,14 +77,29 @@ return context.keyring_dir.mkdir(parents=True, exist_ok=True) + keyring = context.keyring_dir / "opensuse.gpg" - with (context.keyring_dir / "opensuse.gpg").open("wb") as f: - run( - # TODO: Switch to rpmkeys --export once we can rely on rpm 6.0.0 or newer. - ["rpm", "--root=/buildroot", "-q", "gpg-pubkey", "--qf", "%{PUBKEYS:armor}\n"], - stdout=f, - sandbox=context.sandbox(options=context.rootoptions()), - ) + result = run( + # TODO: Switch to rpmkeys --export once we can rely on rpm 6.0.0 or newer. + ["rpm", "--root=/buildroot", "-q", "gpg-pubkey", "--qf", "%{PUBKEYS:armor}\n"], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + sandbox=context.sandbox(options=context.rootoptions()), + success_exit_status=(0, 1), + ) + + if result.returncode == 1: + expected = "package gpg-pubkey is not installed" + if expected not in result.stdout and expected not in result.stderr: + raise subprocess.CalledProcessError( + result.returncode, + result.args, + output=result.stdout, + stderr=result.stderr, + ) + keyring.unlink(missing_ok=True) + else: + keyring.write_text(result.stdout) @classmethod def install(cls, context: Context) -> None: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mkosi-27/mkosi/installer/dnf.py new/mkosi-27.1/mkosi/installer/dnf.py --- old/mkosi-27/mkosi/installer/dnf.py 2026-08-27 16:30:58.000000000 +0200 +++ new/mkosi-27.1/mkosi/installer/dnf.py 2026-09-28 15:32:03.000000000 +0200 @@ -217,11 +217,15 @@ if dnf == "dnf5": cmdline += ["--use-host-config"] else: - cmdline += [ - "--config=/etc/dnf/dnf.conf", - "--setopt=reposdir=/etc/yum.repos.d", - "--setopt=varsdir=/etc/dnf/vars", - ] + cmdline += ["--config=/etc/dnf/dnf.conf"] + + # By default, dnf5 also reads repository definitions and variables from /usr/share/dnf5 which comes + # from the tools tree when using one (e.g. Fedora rawhide's fedora-repos ships its repositories there + # now), so make sure we only ever use the ones from the sandbox tree. + cmdline += [ + "--setopt=reposdir=/etc/yum.repos.d", + "--setopt=varsdir=/etc/dnf/vars", + ] if context.config.proxy_url: cmdline += [f"--setopt=proxy={context.config.proxy_url}"] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mkosi-27/mkosi/resources/man/mkosi.1.md new/mkosi-27.1/mkosi/resources/man/mkosi.1.md --- old/mkosi-27/mkosi/resources/man/mkosi.1.md 2026-08-27 16:30:58.000000000 +0200 +++ new/mkosi-27.1/mkosi/resources/man/mkosi.1.md 2026-09-28 15:32:03.000000000 +0200 @@ -1458,11 +1458,18 @@ : Path to the X.509 file containing the certificate for signing the expected PCR signatures. `SignInitrdPCRs=`, `--sign-initrd-pcrs=` -: Whether to generate signed PCR policies that can only be satisfied from the - initrd. This is required for initialization of NvPCRs. This takes a boolean value - or the special value `auto`, which is the default and is equivalent to a true value - if PCR signing is enabled (see `SignExpectedPcr=`) and the version of **ukify** is - at least v262. Signing is performed with the key that is supplied to `SignExpectedPcrKey=`. +: Whether to generate PCR policies that can only be satisfied from the initrd. + This is required for initialization of NvPCRs. This takes a boolean value or + the special value `auto`, which is the default and is equivalent to a true + value if the version of **ukify** is at least v262 and either PCR signing is + enabled (see `SignExpectedPcr=`) or `pcrs` is selected in `SplitArtifacts=`. + If enabled explicitly, either PCR signing or `SplitArtifacts=pcrs` must be + enabled as well. + + When PCR signing is enabled, the policies are signed with the key supplied to + `SignExpectedPcrKey=` and embedded in the UKI. If `SplitArtifacts=pcrs` is + enabled and PCR signing is disabled, the policy digests are written unsigned to + the split PCR JSON artifact for offline signing. `SecureBootKeySource=`, `--secure-boot-key-source=`, `VerityKeySource=`, `--verity-key-source=`, `SignExpectedPcrKeySource=`, `--sign-expected-key-source=` : The source of the corresponding private key, to support OpenSSL engines and providers, @@ -1636,7 +1643,8 @@ it will use the configuration files from their canonical locations in `/usr` or `/etc` in the sandbox trees. For example, it will look for `/etc/dnf/dnf.conf` in the sandbox trees if **dnf** is used to - install packages. + install packages. See **PACKAGE MANAGER-SPECIFIC BEHAVIOUR** for + further details. `WorkspaceDirectory=`, `--workspace-directory=` : Path to a directory where to store data required temporarily while @@ -1853,6 +1861,10 @@ systemd-nsresourced and systemd-mountfsd v260 or newer are required on the host to make use of this option. +`DelegateRanges=`, `--delegate-ranges=` +: Set the number of delegated ranges in the foreign UID range. Defaults to 3 for regular users and 0 for + root. + ### [Runtime] Section (previously known as the [Host] section) `NSpawnSettings=`, `--settings=` @@ -2504,8 +2516,9 @@ 1. Parse CLI options 1. Parse configuration files 1. Run configure scripts (`mkosi.configure`) -1. If we're not running as root, unshare the user namespace and map the - subuid range configured in `/etc/subuid` and `/etc/subgid` into it. +1. If we're not running as root, unshare the user namespace and map the the current user to root in it. If + available this uses systemd-nsresourced to acquire a delegated range in the foreign UID range, otherwise + an unprivileged user namespace is set up by mkosi. 1. Unshare the mount namespace 1. Remount the following directories read-only if they exist: - `/usr` @@ -3115,6 +3128,28 @@ | `zstd` | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | | `zypper` | ✓ | | ✓ | ✓ | ✓ | ✓ | ✓ | | +# PACKAGE MANAGER-SPECIFC BEHAVIOUR + +## Arch and other pacman-based distributions + +mkosi generates a `pacman.conf` in the sanbox tree if one doesn't exist. If one exists, a `DownloadUser` +setting is always removed. The generated config will always include all files with the `.conf` extension from +`/etc/pacman.d` in the sandbox tree. + +## Debian and other deb-based distributions + +mkosi generates `/etc/apt/sources.list.d/mkosi.sources` in the sandbox tree if it does not exist. +The configured `Mirror=` is used for everything except for the security and debug repositories, which always +use http://deb.debian.org. + +## Fedora and other distributions using DNF + +mkosi generates `/etc/yum.repos.d/mkosi.repo` in the sandbox tree if it does not exist. + +## Opensuse and other distributions using Zypper + +mkosi generates `/etc/zypp/repos.d/mkosi.repo` in the sandbox tree if it does not exist. + # BUILDING MULTIPLE IMAGES If the `mkosi.images/` directory exists, **mkosi** will load individual @@ -3492,6 +3527,11 @@ You can set `PORTABLE_PREFIXES=` by setting `Environment=PORTABLE_PREFIXES=XXX` in your mkosi config. +- `BaseTrees=`/`Overlay=` do not work with nsresourced? + + This is expected and need upstream kernel changes expected to land in Linux 7.3. You can skip the usage of + nsresourced by setting the environment variable `MKOSI_FORCE_USERNS_FALLBACK` to a true value. + # REFERENCES * [Primary mkosi git repository on GitHub](https://github.com/systemd/mkosi/) * [mkosi — A Tool for Generating OS Images](https://0pointer.net/blog/mkosi-a-tool-for-generating-os-images.html) introductory blog post by Lennart Poettering diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mkosi-27/mkosi/resources/man/mkosi.news.7.md new/mkosi-27.1/mkosi/resources/man/mkosi.news.7.md --- old/mkosi-27/mkosi/resources/man/mkosi.news.7.md 2026-08-27 16:30:58.000000000 +0200 +++ new/mkosi-27.1/mkosi/resources/man/mkosi.news.7.md 2026-09-28 15:32:03.000000000 +0200 @@ -4,6 +4,23 @@ # mkosi Changelog +## v27.1 + +- Fix tests failing in restricted build environments +- `SignInitrdPCRs=` can be used with `SplitArtifacts=pcrs`, fixing initrd-specific PCR policies with systemd + v262. +- Don't fail creating initrds when there are directories mixed in with microcode files. +- Fix builds when using unsigned local repositories with opensuse. +- Only use repositories and variables from the sandbox tree when using DNF. +- The mkosi-obs no longer sets `MakeScriptsExecutable=`, except for the main image, so it can be included + again. +- The security and debug repositories are switched back to deb.debian.org and are no longer set by the + `Repositories=` setting. +- Add an environment variable `MKOSI_FORCE_USERNS_FALLBACK` that when set to a value that parses as a truthy + bool, skips using systemd-nsresourced. +- A new setting `DelegateRanges=` is added that defaults to 0 when mkosi is run as the root user. This fixes + builds run as the root user. + ## v27 - Debug output (with `--debug`) will now show the duration of all steps. @@ -29,7 +46,7 @@ images unprivileged without a sufficiently new systemd-nsresourced is still supported. - If a `mkosi/` directory exists and no output location is configured, the `.mkosi-private` will be put there. - `LocalMirror=` can now be set for tools trees. -- A new setting `DriveType=` has been added to configures the disk type to use for the root disk when booting +- A new setting `DiskType=` has been added to configures the disk type to use for the root disk when booting a virtual machine. - Four new settings `ElTorito=`, `ElToritoSystem=`, `ElToritoVolume=`, and `ElToritoPublisher=` for use with systemd-repart's El Torito support have been added. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mkosi-27/mkosi/resources/mkosi-obs/mkosi.build new/mkosi-27.1/mkosi/resources/mkosi-obs/mkosi.build --- old/mkosi-27/mkosi/resources/mkosi-obs/mkosi.build 2026-08-27 16:30:58.000000000 +0200 +++ new/mkosi-27.1/mkosi/resources/mkosi-obs/mkosi.build 2026-09-28 15:32:03.000000000 +0200 @@ -140,14 +140,14 @@ while read -r SIG; do uki="$OUTPUTDIR/$(basename "$(dirname "${SIG%.sig}")")" pcrs="${uki%.efi}.pcrs" - pol="$(basename "${SIG%.sig}")" + tbs="$(basename "${SIG%.sig}")" test -f "${pcrs}" - jq -c --arg pol "$pol" --arg sig "$(base64 -w0 <"$SIG")" ' + jq -c --arg tbs "$tbs" --arg sig "$(base64 -w0 <"$SIG")" ' to_entries | map( .value |= map( - if .pol == $pol then + if (.tbs // .pol) == $tbs then .sig = $sig else . diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mkosi-27/mkosi/resources/mkosi-obs/mkosi.conf new/mkosi-27.1/mkosi/resources/mkosi-obs/mkosi.conf --- old/mkosi-27/mkosi/resources/mkosi-obs/mkosi.conf 2026-08-27 16:30:58.000000000 +0200 +++ new/mkosi-27.1/mkosi/resources/mkosi-obs/mkosi.conf 2026-09-28 15:32:03.000000000 +0200 @@ -8,6 +8,3 @@ SignExpectedPcr=no Verity=defer Checksum=yes - -[Build] -MakeScriptsExecutable=yes diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mkosi-27/mkosi/resources/mkosi-obs/mkosi.conf.d/main.conf new/mkosi-27.1/mkosi/resources/mkosi-obs/mkosi.conf.d/main.conf --- old/mkosi-27/mkosi/resources/mkosi-obs/mkosi.conf.d/main.conf 2026-08-27 16:30:58.000000000 +0200 +++ new/mkosi-27.1/mkosi/resources/mkosi-obs/mkosi.conf.d/main.conf 2026-09-28 15:32:03.000000000 +0200 @@ -11,6 +11,7 @@ CacheDirectory= Incremental=no WithNetwork=never +MakeScriptsExecutable=yes [Distribution] RepositoryKeyCheck=no diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mkosi-27/mkosi/resources/mkosi-obs/mkosi.postoutput new/mkosi-27.1/mkosi/resources/mkosi-obs/mkosi.postoutput --- old/mkosi-27/mkosi/resources/mkosi-obs/mkosi.postoutput 2026-08-27 16:30:58.000000000 +0200 +++ new/mkosi-27.1/mkosi/resources/mkosi-obs/mkosi.postoutput 2026-09-28 15:32:03.000000000 +0200 @@ -41,9 +41,9 @@ test -f "${OUTPUTDIR}/${f}" || continue if [ -f "${OUTPUTDIR}/${f%.efi}.pcrs" ]; then mkdir -p "hashes/pcrs/$f" - while read -r pol; do - echo -n "$pol" | tr '[:lower:]' '[:upper:]' | basenc --base16 --decode >"hashes/pcrs/${f}/${pol}" - done < <(jq -r 'to_entries[] | .value[].pol' <"${OUTPUTDIR}/${f%.efi}.pcrs") + while read -r tbs; do + echo -n "$tbs" | tr '[:lower:]' '[:upper:]' | basenc --base16 --decode >"hashes/pcrs/${f}/${tbs}" + done < <(jq -r 'to_entries[] | .value[] | .tbs // .pol' <"${OUTPUTDIR}/${f%.efi}.pcrs") else mkdir -p "$(dirname "hashes/ukis/$f")" pesign --force -n sql:"$nss_db" -i "${OUTPUTDIR}/${f}" -E "hashes/ukis/$f" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mkosi-27/mkosi/sandbox.py new/mkosi-27.1/mkosi/sandbox.py --- old/mkosi-27/mkosi/sandbox.py 2026-08-27 16:30:58.000000000 +0200 +++ new/mkosi-27.1/mkosi/sandbox.py 2026-09-28 15:32:03.000000000 +0200 @@ -13,7 +13,7 @@ import sys import warnings # noqa: F401 (loaded lazily by os.execvp() which happens too late) -__version__ = "27" +__version__ = "27.1" # The following constants are taken from the Linux kernel headers. AT_EMPTY_PATH = 0x1000 @@ -745,7 +745,7 @@ userns: FD, type: str = "managed", foreign: bool = False, - delegate: int = 0, + delegate_ranges: int = 0, become_root: bool = False, ) -> None: import uuid @@ -760,7 +760,7 @@ "type": type, **({"target": 0} if become_root or type != "self" else {}), "mapForeign": foreign, - "delegateContainerRanges": delegate, + "delegateContainerRanges": delegate_ranges, }, fds=(userns,), ) @@ -857,7 +857,7 @@ *, identity: bool = True, foreign: bool = False, - delegate: int = 0, + delegate_ranges: int = 0, become_root: bool = False, network: bool = False, ) -> bool: @@ -865,12 +865,12 @@ have_effective_cap(CAP_SYS_ADMIN) and identity and (not foreign or have_effective_cap(CAP_CHOWN)) - and not delegate + and (delegate_ranges == 0) and (not become_root or (os.getuid() == 0 and os.getgid() == 0)) ): return False - if not identity or (foreign and not have_effective_cap(CAP_CHOWN)) or delegate: + if not identity or (foreign and not have_effective_cap(CAP_CHOWN)) or delegate_ranges: # nsresource_allocate_user_range() might fail for various reasons and we don't want to leave # the process in an empty user namespace if that's the case. Hence we don't unshare our own # user namespace but get ourselves a child user namespace which we pass to nsresourced. We only @@ -880,7 +880,7 @@ userns_fd, "self" if identity else "managed", foreign, - delegate, + delegate_ranges, become_root, ) setns(userns_fd, CLONE_NEWUSER) @@ -1595,7 +1595,7 @@ userns = acquire_privileges( identity=True, foreign=map_foreign, - delegate=(map_delegate + int(foreign)), + delegate_ranges=(map_delegate + int(foreign)), become_root=(not foreign and become_root), network=unshare_net, ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mkosi-27/mkosi/user.py new/mkosi-27.1/mkosi/user.py --- old/mkosi-27/mkosi/user.py 2026-08-27 16:30:58.000000000 +0200 +++ new/mkosi-27.1/mkosi/user.py 2026-09-28 15:32:03.000000000 +0200 @@ -5,8 +5,6 @@ from mkosi.run import find_binary from mkosi.util import parents_below -SUBRANGE = 65536 - class INVOKING_USER: @classmethod diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mkosi-27/pyproject.toml new/mkosi-27.1/pyproject.toml --- old/mkosi-27/pyproject.toml 2026-08-27 16:30:58.000000000 +0200 +++ new/mkosi-27.1/pyproject.toml 2026-09-28 15:32:03.000000000 +0200 @@ -7,7 +7,7 @@ authors = [ {name = "mkosi contributors", email = "[email protected]"}, ] -version = "27" +version = "27.1" description = "Build Bespoke OS Images" readme = "README.md" requires-python = ">=3.9" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mkosi-27/tests/test_json.py new/mkosi-27.1/tests/test_json.py --- old/mkosi-27/tests/test_json.py 2026-08-27 16:30:58.000000000 +0200 +++ new/mkosi-27.1/tests/test_json.py 2026-09-28 15:32:03.000000000 +0200 @@ -161,6 +161,7 @@ "Value": null } ], + "DelegateRanges": 3, "Dependencies": [ "dep1" ], @@ -487,6 +488,7 @@ Credential(name="credkey", value="credval"), Credential(name="pathcred", path=Path("/secret/file")), ], + delegate_ranges=3, dependencies=["dep1"], distribution=Distribution.fedora, disk_type=QemuDiskType.virtio_blk, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mkosi-27/tests/test_run.py new/mkosi-27.1/tests/test_run.py --- old/mkosi-27/tests/test_run.py 2026-08-27 16:30:58.000000000 +0200 +++ new/mkosi-27.1/tests/test_run.py 2026-09-28 15:32:03.000000000 +0200 @@ -8,6 +8,7 @@ import pytest from mkosi.run import fork_and_wait +from mkosi.sandbox import EPERM def test_fork_and_wait_returns_value() -> None: @@ -60,5 +61,10 @@ def exists() -> bool: return Path("/abc").exists() - result = fork_and_wait(exists, sandbox=contextlib.nullcontext(["--bind", os.fspath(tmp_path), "/"])) + try: + result = fork_and_wait(exists, sandbox=contextlib.nullcontext(["--bind", os.fspath(tmp_path), "/"])) + except subprocess.CalledProcessError as e: + if e.returncode == EPERM or e.returncode == 28: + pytest.skip("CLONE_NEWUSER is not allowed in the test environment") + raise assert result
