The install-tests CI job was failing because running `cargo xtask`
as root (via sudojust) modified ~/.cargo files with root ownership,
causing later cargo commands to fail with permission errors.
This change builds container images as the regular user and copies
them to root's podman storage using `podman save | sudo podman load`.
This avoids cargo cache permission issues while still making images
available for privileged tests.
Add two new Justfile recipes:
- copy-to-rootful: Copy a single image from user to root storage
- copy-lbi-to-rootful: Copy all bound images (LBI) to root storage
Assisted-by: OpenCode (Opus 4.5)
Signed-off-by: Colin Walters <walters@verbum.org>
bootc images have /home as a symlink to /var/home, but /var/home
may not exist in the base container image. When local-rust-deps
outputs bind mount arguments for paths under /home/..., crun fails
to create the mount destination because it can't create /var/home.
Fix by mapping /home/... paths to /var/home/... for the container
destination. Cargo inside the container can still access the files
via /home/... since the symlink works once /var/home exists.
Assisted-by: OpenCode (Claude Sonnet 4)
Signed-off-by: Colin Walters <walters@verbum.org>
This allows registries to distinguish "image pulls for bootc client
runs" from other skopeo/containers-image users. The user agent will
be in the format "bootc/<version> skopeo/<version>".
All places in bootc that create ImageProxyConfig now use a new helper
function that sets the user_agent_prefix field.
Closes: https://github.com/bootc-dev/bootc/issues/1686
Assisted-by: OpenCode (Sonnet 4)
Signed-off-by: Colin Walters <walters@verbum.org>
Add `cargo xtask local-rust-deps` which uses `cargo metadata` to find
local path dependencies outside the workspace (e.g., from [patch] sections)
and outputs podman bind mount arguments.
This enables a cleaner workflow for local development against modified
dependencies like composefs-rs:
1. Add a [patch] section to Cargo.toml with real local paths
2. Run `just build` - the Justfile auto-detects and bind-mounts them
Benefits over the previous BOOTC_extra_src approach:
- No manual env var needed
- Paths work for both local `cargo build` and container builds
- No /run/extra-src indirection or Cargo.toml path munging required
- Auto-detection means it Just Works™
The Justfile's build target now calls `cargo xtask local-rust-deps` to
get bind mount args, falling back gracefully if there are no external deps.
The old BOOTC_extra_src mechanism is still supported for backwards compat.
Assisted-by: OpenCode (Opus 4.5)
Signed-off-by: Colin Walters <walters@verbum.org>
I want to be able to write build rules in Rust that may be
invoked from outside of a container build, but in the default
GHA runners Rust is installed via `rustup` which lives just in
the `runner` user's homedir.
When using `sudo` it resets `$PATH` so we lose access to it.
Fix this by passing `$PATH` in.
Assisted-by: OpenCode (claude-sonnet-4-20250514)
Signed-off-by: Colin Walters <walters@verbum.org>
Until now while checking if a deployment is capable of being soft
rebooted, we were not taking into account any differences in SELinux
policies between the two deployments. This commit adds such a check
We only check for policy diff if SELinux is enabled
Signed-off-by: Pragyan Poudyal <pragyanpoudyal41999@gmail.com>
composefs: Refactor
Add doc comments for StagedDeployment struct
Use `serde_json::to_writer` to prevent intermediate string allocation
Signed-off-by: Pragyan Poudyal <pragyanpoudyal41999@gmail.com>
composefs/selinux: More refactor
Move SELinux realted oprations to a separate module
Minor refactoring and add some comments
Signed-off-by: Pragyan Poudyal <pragyanpoudyal41999@gmail.com>
When `--download-only` is passed, only download the image into the
composefs repository but don't finalize it.
Conver the /run/composefs/staged-deployment to a JSON file and Add a
finalization_locked field depending upon which the finalize service will
either finalize the staged deployment or leave it as is for garbage
collection (even though GC is not fully implemented right now).
Signed-off-by: Pragyan Poudyal <pragyanpoudyal41999@gmail.com>
After bootc/commit/49d753f996747a9b1f531abf35ba4e207cf4f020,
composefs-rs saves config in the format `oci-config-sha256:`.
Update to match the same
Signed-off-by: Pragyan Poudyal <pragyanpoudyal41999@gmail.com>
Aligning with ostree API, now we only initiate soft-reboot if `--apply`
is passed to `bootc update`, `bootc switch`, else we only prepare the
soft reboot
Signed-off-by: Pragyan Poudyal <pragyanpoudyal41999@gmail.com>
Allow configuring the root and boot filesystem mount
specs via the install configuration file under [install].
As for other options, CLI arguments take precedence.
For the to-existing-root flow, mount specs from config are ignored.
Example configuration:
```
[install]
root-mount-spec = "LABEL=rootfs"
boot-mount-spec = "UUID=abcd-1234"
```
Fixes https://github.com/bootc-dev/bootc/issues/1939
Assisted-by: Opencode (Claude Opus 4.5)
Signed-off-by: jbtrystram <jbtrystram@redhat.com>
Support for configuring the stateroot name through the install
configuration file under `[install.ostree]`.
The CLI flag will override config file values, as for other options.
Partial fix for https://github.com/bootc-dev/bootc/issues/1939
Assisted-by: Opencode (Claude Opus 4.5)
Signed-off-by: jbtrystram <jbtrystram@redhat.com>
This is useful when debugging issues with stale cached layers,
such as package version skew between base images and repos.
Signed-off-by: Colin Walters <walters@verbum.org>
Justfile changes:
- Organize targets into groups (core, testing, docs, debugging, maintenance)
- Add `list-variants` target to show available build variants
- Simplify comments to be concise single-line descriptions
- Move composefs targets (build-sealed, test-composefs) into core group
CONTRIBUTING.md changes:
- Reference `just --list` and `just list-variants` instead of duplicating
- Remove tables that duplicate Justfile information
- Fix broken link to cli.rs
The Justfile is now self-documenting via `just --list` (grouped targets)
and `just list-variants` (build configuration options).
Assisted-by: OpenCode (Claude Sonnet 4)
Signed-off-by: Colin Walters <walters@verbum.org>
Add comprehensive documentation for building sealed bootc images,
focusing on the core concepts and the key command:
`bootc container compute-composefs-digest`.
Key additions:
- Document how sealed images work (UKI + composefs digest + Secure Boot)
- Explain the build workflow abstractly without distribution-specific details
- Document the compute-composefs-digest command and its options
- Add section on generating/signing UKIs with ukify
- Document developer testing commands (just variant=composefs-sealeduki-sdboot)
- Add validation tooling documentation
This provides the foundation for distribution-specific documentation
to build upon with concrete Containerfile examples.
Assisted-by: OpenCode (Claude Sonnet 4)
Signed-off-by: Colin Walters <walters@verbum.org>
We changed how composefs digests are computed to ensure that
mounted filesystem via --mount=type=image and install-time view
(OCI tar layer processing from containers-storage) match.
There were various problems like differing metadata for `/`
among other things.
Signed-off-by: Colin Walters <walters@verbum.org>
The composefs-rs PR 209 has been merged to main. This updates
bootc to use the containers/composefs-rs repository at the
merge commit.
Key API changes:
- Directory::default() -> Directory::new(Stat::uninitialized())
- read_filesystem() no longer takes stat_root parameter
- New read_container_root() for OCI containers (propagates /usr metadata to root)
- stat_root CLI flag renamed to no_propagate_usr_to_root with inverted logic
See https://github.com/containers/composefs-rs/pull/209
Signed-off-by: Colin Walters <walters@verbum.org>
Add support for bind-mounting an extra source directory into container
builds, primarily for developing against a local composefs-rs checkout.
Usage:
BOOTC_extra_src=$HOME/src/composefs-rs just build
The directory is mounted at /run/extra-src inside the container. When
using this, also patch Cargo.toml to use path dependencies pointing to
/run/extra-src/crates/....
Signed-off-by: Colin Walters <walters@verbum.org>
Assisted-by: OpenCode (Opus 4.5)
Signed-off-by: Colin Walters <walters@verbum.org>
Now that we're doing a "from scratch" build we don't
have the mtime issue, and so we can change our build system
to do everything in a single step.
Assisted-by: OpenCode (Opus 4.5)
Signed-off-by: Colin Walters <walters@verbum.org>
Add a TMT test that exercises the mount point check fix from PR #1904.
The test builds a container image with an embedded disk.yaml that creates
a partition layout WITHOUT a separate /boot partition - just root (/)
with /boot/efi as a separate mount point.
This partition layout triggers the bug from issue #1907 where bootc's
empty rootfs verification would fail with:
"Found entry in boot: efi"
The issue was that when /boot is a directory on the root filesystem
(not a separate partition), but /boot/efi IS a mount point on a different
device, the old code incorrectly saw "efi" as a regular directory entry
rather than recognizing it was a mount point boundary.
Verified that temporarily reverting the fix from PR #1904 causes this
test to fail with the expected error message.
This was already fixed by ab65078675
but we didn't realize at the time the scope.
Closes: https://github.com/bootc-dev/bootc/issues/1907
Signed-off-by: Colin Walters <walters@verbum.org>
Document the bootc-destructive-cleanup.service systemd unit that runs
on first boot after an alongside installation with --cleanup. The man
page explains how the service is enabled via the systemd generator,
what the Fedora cleanup script does, and how distributions can
customize the cleanup behavior.
Resolves: https://issues.redhat.com/browse/RHEL-131317
Assisted-by: OpenCode (Claude Sonnet 4)
Signed-off-by: Colin Walters <walters@verbum.org>
install-to-filesystem-var-mount test requires packages which should
be built into image for Packit provision (system-reinstall-bootc on
package mode testing farm runner)
Signed-off-by: Xiaofeng Wang <henrywangxf@me.com>
When rpm -qa returns no packages, xargs would still invoke
rpm -e with no arguments, causing failure with "no packages
given for erase" (exit code 123).
Add -r flag to xargs to skip execution when input is empty.
Signed-off-by: Xiaofeng Wang <henrywangxf@me.com>
If a directory is modified/added in the current etc, but deleted in the
new etc, we'd want it in the new etc. This case prior to this commit
resulted in a panic as we were not taking it into account
Fixes: https://github.com/bootc-dev/bootc/issues/1924
Signed-off-by: Pragyan Poudyal <pragyanpoudyal41999@gmail.com>
In C9S there's something leaking files in `/tmp` so let's just
enforce use of tmpfs for `/run` at build time too.
But fix `RUN bootc container lint` to *not* have those mounts
becuase otherwise we don't actually see the leaked content.
Assisted-by: Cursor (Opus 4.5)
Signed-off-by: Colin Walters <walters@verbum.org>
Use copy-to-storage to add the booted container to podman storage
instead of pulling a remote image. This matches the pattern used
by other TMT tests and ensures we test the actual bootc under test.
Changes:
- Use localhost/bootc from copy-to-storage instead of remote image
- Disable LBIs via bind mount of /usr/share/empty
- Remove unnecessary host modifications (usr-overlay, dnf install, etc.)
- Use 100%FREE for root LV to ensure sufficient space for deployment
Assisted-by: OpenCode (Opus 4.5)
Signed-off-by: ckyrouac <ckyrouac@redhat.com>
Signed-off-by: Colin Walters <walters@verbum.org>
The base image may be built from a compose that has newer packages
than what's available on the public mirrors. This causes version skew
where packages like bootupd have different versions between the base
image and our built image.
For example, bootupd 0.2.32 changed the EFI file layout from
/usr/lib/bootupd/updates/EFI/ to /usr/lib/efi/, and if we build
with an older bootupd from mirrors while the target image has
the newer layout, bootloader installation fails.
Enable the CentOS Stream compose repos with higher priority to ensure
we get matching versions.
xref https://gitlab.com/redhat/centos-stream/containers/bootc/-/issues/1174
Signed-off-by: Colin Walters <walters@verbum.org>
Assisted-by: OpenCode (Opus 4.5)
Signed-off-by: Colin Walters <walters@verbum.org>
Add a helper function that returns WalkConfiguration with noxdev()
enabled by default. This ensures consistent behavior across all
filesystem walks in the linting code.
The doc comment clarifies that noxdev skips directory mount points
(to avoid descending into bind mounts, tmpfs, etc.) but non-directory
mount points like bind-mounted regular files will still be visited.
Assisted-by: OpenCode (Opus 4.5)
Signed-off-by: Colin Walters <walters@verbum.org>
Add a lint that warns when /run or /tmp contain any content. These
directories are tmpfs at runtime and should be empty in container images.
Common causes of content in these directories include:
- podman/buildah's RUN --mount leaving directory stubs
- Build tools leaving temporary files
This is particularly important for bootc with composefs because content
in these directories can cause digest mismatches between build-time
(mounted filesystem) and install-time (OCI tar layers) views, leading
to sealed boot failures.
The lint uses the walk API with noxdev() to automatically skip mount
points, and filters out content injected by container runtimes
(.containerenv, secrets, packages).
Assisted-by: OpenCode (Opus 4.5)
Signed-off-by: Colin Walters <walters@verbum.org>
When using --mount=type=bind,target=/run/foo, podman/buildah creates
the mount point directory in the image layer even though the mounted
content is not committed. These empty directory stubs pollute /run
in the final image.
Fix by using --mount=type=tmpfs,target=/run with bind mounts nested
inside. This ensures /run remains empty in the committed layer.
Also move the lint invocation in Dockerfile.cfsuki to a separate RUN
command so it runs after the bind mount is released.
Assisted-by: OpenCode (Opus 4.5)
Signed-off-by: Colin Walters <walters@verbum.org>
Due to https://bugzilla.redhat.com/show_bug.cgi?id=2429501
This reverts the prior change to make the test non gating
because the problem is we'd consistently fail to do a bootc install
*for each test* which dramatically slowed down that job.
We could fix that but it's easier to just disable the job.
Signed-off-by: Colin Walters <walters@verbum.org>
When G_MESSAGES_DEBUG is set (e.g., 'all'), GLib and OSTree emit debug
messages to stdout instead of stderr. This corrupts the commit hash
that we parse from the ostree commit subprocess output, causing derived
layer content to be silently lost during container imports.
The issue manifests as packages installed via 'dnf install' in a
Containerfile not appearing in the deployed system's rpmdb after
a rebase/upgrade operation.
Fixes: https://issues.redhat.com/browse/OCPBUGS-64692
Assisted-by: OpenCode (Claude Opus 4.5)
Signed-off-by: Joseph Marrero Corchado <jmarrero@redhat.com>
The "install to-filesystem with separate /var mount" test was causing
disk space issues on GitHub Actions runners due to its large disk
image requirements (12GB for partitions with LVM). Moving it to a TMT
test allows it to run in a dedicated VM where disk space is not as
constrained.
The test verifies that bootc install to-filesystem correctly handles
scenarios where /var is on a separate filesystem, which is a common
production setup.
Changes:
- Remove the test from Rust integration tests (install.rs)
- Add new TMT test: test-32-install-to-filesystem-var-mount.sh
- Add package requirements (parted, lvm2, dosfstools, e2fsprogs)
- Update tests.fmf and integration.fmf with new test entry
Assisted-by: Claude Code (Opus 4.5)
Signed-off-by: ckyrouac <ckyrouac@redhat.com>