Some people want to use container build tools, but for compatibility
with older systems export a tar format of the OS state e.g.
Anaconda liveimg expects this.
Basically this is only *slightly* more than just `tar cf`; we need
to handle SELinux labeling and move the kernel.
Ref: #1957
Assisted-by: OpenCode (Sonnet 4.5)
Signed-off-by: Colin Walters <walters@verbum.org>
Add a new subcommand that builds a Unified Kernel Image (UKI) by
computing the necessary arguments from a container image and invoking
ukify. This simplifies the sealed image build workflow by having bootc
internally compute:
- The composefs digest (via existing compute-composefs-digest logic)
- Kernel arguments from /usr/lib/bootc/kargs.d/*.toml files
- Paths to kernel, initrd, and os-release
Any additional arguments are passed through to ukify unchanged, allowing
full control over signing, output paths, and other ukify options.
The seal-uki script is updated to use this new command instead of
manually computing these values and invoking ukify directly.
Also adds kargs.d configuration files for the sealed UKI workflow:
- 10-rootfs-rw.toml: Mount root filesystem read-write
- 21-console-hvc0.toml: Console configuration for QEMU/virtio
Closes: #1955
Assisted-by: OpenCode (Opus 4.5)
Signed-off-by: John Eckersberg <jeckersb@redhat.com>
The composefs backend implementation has largely landed. Consolidate
tracking of known issues into the docs, categorized by severity:
- Deployment blockers: GC, SELinux enforcing=0, OCI registry install
- Important: Sealed image build UX, kargs.d support
- Long-term: Unified storage, UKI/systemd-boot improvements
This allows closing the original tracking issue #1190.
Assisted-by: OpenCode (Claude Sonnet 4)
Signed-off-by: Colin Walters <walters@verbum.org>
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>
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>
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>
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>
When cargo-binstall fetches pre-built binaries from GitHub, it can hit
API rate limits (403 Forbidden) when unauthenticated. This causes it to
fall back to building from source, which fails for mdbook-linkcheck
because the devenv container lacks openssl-devel and the perl modules
needed to build OpenSSL from source.
Pass the GitHub Actions token through to the container build as a secret,
allowing cargo-binstall to make authenticated requests with higher rate
limits.
Assisted-by: OpenCode (claude-sonnet-4-20250514)
Signed-off-by: Colin Walters <walters@verbum.org>
These external git dependencies don't have docs on docs.rs, so include
them in the internal documentation alongside our workspace crates.
Assisted-by: OpenCode (Opus 4.5)
Signed-off-by: Colin Walters <walters@verbum.org>
The docs workflow now also generates rustdoc for all workspace crates
and publishes them as a subdirectory of the main documentation site.
This makes internal API documentation available at
bootc-dev.github.io/bootc/internals.html with links to each crate.
Note this required switching the docs container to CentOS Stream 10 for newer Rust (1.91).
Assisted-by: OpenCode (Opus 4.5)
Signed-off-by: Colin Walters <walters@verbum.org>
The container inspect command previously only supported JSON output.
This extends it to support human-readable output (now the default)
and YAML, matching the output format options available in other
bootc commands like status.
The --json flag provides backward compatibility for scripts that
expect JSON output, while --format allows explicit selection of
any supported format.
Assisted-by: OpenCode (Sonnet 4)
Signed-off-by: Colin Walters <walters@verbum.org>
The container-inspect command previously only reported kernel arguments.
Extend it to also report kernel information, including whether the image
contains a traditional kernel or a Unified Kernel Image (UKI).
This consolidates UKI detection logic previously in bootc_composefs::boot
into a new kernel module that can find kernels via either the traditional
/usr/lib/modules/<version>/vmlinuz path or UKI files in /boot/EFI/Linux/.
The ContainerInspect output now includes a "kernel" field with version
and unified (boolean) properties, enabling tooling to determine the
boot method before installation.
Assisted-by: OpenCode (Claude Opus 4.5)
Signed-off-by: Colin Walters <walters@verbum.org>
systemd-boot has support for automatically enrolling keys
for Secure Boot, this adds support for copying these keys
as embedded in the input container image into the location
where systemd-boot can perform automatic enrollment on them.
Commit-message-written-by: Colin Walters <walters@verbum.org>
Signed-off-by: Gareth Widlansky <gareth.widlansky@proton.me>
Add a new --from-downloaded flag to bootc upgrade that allows users to
unlock a staged deployment created with --download-only without fetching
updates from the container image source.
This provides a way to apply already-downloaded updates without triggering
a fetch operation, which is useful for scheduled maintenance workflows where
the update was downloaded earlier and should now be applied at a scheduled
time.
Usage:
# Download update without applying
bootc upgrade --download-only
# Later: Apply the staged update (without fetching from image source)
bootc upgrade --from-downloaded
# Or: Apply staged update and reboot immediately
bootc upgrade --from-downloaded --apply
The flag conflicts with --check and --download-only as those operations
have different purposes. It can be combined with --apply to immediately
reboot after unlocking the staged deployment.
This commit also updates the documentation (upgrades.md) to describe all
three ways to apply a download-only update, and updates the download-only
test case (test-25) to use --from-downloaded instead of plain
'bootc upgrade' when clearing the download-only flag.
Assisted-by: Claude Code (Sonnet 4.5)
Signed-off-by: Wei Shi <wshi@redhat.com>
Add support for downloading and staging updates without automatic
application on reboot. This allows users to prepare updates and apply
them at a controlled time.
User-facing changes:
- Add --download-only flag to bootc upgrade command
- bootc upgrade --download-only: stages deployment in download-only mode
- bootc upgrade (no flags): clears download-only mode if present
- bootc upgrade --apply: clears download-only mode and immediately reboots
- bootc upgrade --check: read-only, doesn't change download-only state
- bootc status shows "Download-only: yes/no" for staged deployments in verbose mode
- Garbage collection automatically cleans up unreferenced images after staging
Implementation details:
- Internally uses OSTree finalization locking APIs
- Sets opts.locked in SysrootDeployTreeOpts when staging deployments
- Added change_finalization() method to SysrootLock wrapper
- Tracks lock state changes separately from image digest changes
- Field name in BootEntry is download_only (Rust), downloadOnly (JSON)
- Verbose status display uses "Download-only" label (matches Soft-reboot pattern)
- Uses deployment.is_finalization_locked() API (OSTree v2023.8+)
- Always emits downloadOnly field in JSON output for consistency
Testing and documentation:
- New dedicated test: test-25-download-only-upgrade.nu (4-boot workflow)
- Test verifies: switch → upgrade --download-only → reboot (stays old) →
re-stage → upgrade (clear) → reboot (applies)
- Updated docs/src/upgrades.md with comprehensive workflow examples
- Includes notes about reboot behavior and image switching
- Generated man pages and JSON schemas updated
- All test fixtures updated with downloadOnly field
The download-only flag is only available for upgrade, not switch.
The implementation is designed to support future composefs backend.
Assisted-by: Claude Code (Sonnet 4.5)
Signed-off-by: Wei Shi <wshi@redhat.com>
We need to run most of our tests in a separate provisioned machine,
which means it needs an individual plan. And then we need a test
for that plan. And then we need the *actual test code*.
This "triplication" is a huge annoying pain.
TMT is soooo complicated, yet as far as I can tell it doesn't offer
us any tools to solve this. So we'll do it here, cut over to
generating the TMT stuff from metadata defined in the test file.
Hence adding a test is just:
- Write a new tests/booted/foo.nu
- `cargo xtask update-generated`
Signed-off-by: Colin Walters <walters@verbum.org>
Users doing `bootc install to-existing-root` previously had no easy
way to find the ostree deployment before rebooting in order to inject
configuration files. This addresses that gap.
Key changes:
- Document using `ostree admin --print-current-dir` to find the newly
created deployment path before rebooting
- Clarify the two distinct scenarios: injecting new configuration
before reboot vs. migrating old data after reboot
- Add examples for both file-based configuration and kernel arguments
(via `systemd.mount-extra`)
- Cross-link documentation between general install docs and the
to-existing-root man page
- Fix typo in path structure documentation
Related: https://github.com/bootc-dev/bootc/issues/531
Assisted-by: Claude Code (Sonnet 4.5)
Signed-off-by: Colin Walters <walters@verbum.org>
This fixes bootc's use of the Discoverable Partition Specification (DPS)
to properly support systemd-gpt-auto-generator. Previously, bootc was
incorrectly setting filesystem UUIDs to the DPS partition type UUID value,
which caused UUID collisions and prevented proper DPS functionality.
It's still a TODO on our side to support systemd-repart in this flow.
Note we go back to using random filesystem UUIDs with this, but
per above we should likely reinitialize them on boot via repart.
Note we remove root= parameter from kernel cmdline for composefs sealed images,
allowing systemd-gpt-auto-generator to auto-discover the root partition
and we test this.
Fixes: #1771
Assisted-by: Claude Code (Sonnet 4.5)
Signed-off-by: Colin Walters <walters@verbum.org>
While composefs is still experimental, after looking at this
I think the feature gating we're doing has a pretty high "pain:gain"
ratio - in other words, the risk we're mitigating by having it
off is very low.
Since composefs is a focus of development, let's just remove
the feature gate. We have good CI coverage for the non-composefs
case.
Assisted-by: Claude Code (Sonnet 4.5)
Signed-off-by: Colin Walters <walters@verbum.org>
Claude pointed this out while I was working on something else
completely unrelated. But it looks like somewhere along the way
114800 snuck its way in and probably got copy/pasted into a few
places. The maximum baud rate is 115200[1], and that is the more
typical usage.
[1] https://www.kernel.org/doc/html/latest/admin-guide/serial-console.html
Signed-off-by: John Eckersberg <jeckersb@redhat.com>
- Change the install logic to detect UKIs and automatically
enable composefs
- Change the install logic to detect absence of bootupd
and default to installing systemd-boot
- Move sealing bits to the toplevel
- Add Justfile entrypoints
- Add basic end-to-end CI coverage (install + run) using
our integration tests
- Change lints to ignore `/boot/EFI`
Signed-off-by: Colin Walters <walters@verbum.org>
This drains nontrivial logic out GHA and into something
isolated via containers and driven via `Justfile` and
easily replicable locally too.
Signed-off-by: Colin Walters <walters@verbum.org>
- Remove duplicated logic between xtask and makefile
for converting markdown; it needs to be in xtask
as we handle the version substitution there and
some other tweaks
- Really just make the developer entrypoint `just update-generated`
in general
- Fix the rendering of booleans
- Remove unnecessary emoji from prints
Signed-off-by: Colin Walters <walters@verbum.org>
See the updates to `Justfile` for how to use this.
Closes: #1428
Assisted-By: Claude Code (opus + sonnet)
Signed-off-by: Colin Walters <walters@verbum.org>