Conversation
Add image mode support for the ansible prepare plugin. When running on a bootc guest, the plugin: 1. Flushes any pending containerfile directives from prior phases 2. Ensures ansible-playbook is available on the guest 3. Starts a container from the current bootc image 4. Runs ansible-playbook with the containers.podman.podman connection plugin targeting the container 5. Commits the container to a new image 6. Switches via bootc switch and reboots This enables running Ansible playbooks (e.g. system roles) against image mode guests where /usr is read-only and changes must be baked into the container image. Closes #4511 Assisted-by Claude Code
There was a problem hiding this comment.
Code Review
This pull request adds support for the Ansible prepare step in image mode (bootc), including a new integration test. However, a high-severity Path Traversal vulnerability and several instances of potential Command Injection were identified due to improper handling of user-supplied paths and command arguments, which could allow an attacker to read arbitrary files or execute unintended commands. It is recommended to use existing path sanitization helpers and switch from shell-based command execution to structured command objects.
| if lowercased.startswith('file://'): | ||
| rel_path = Path(raw_playbook[7:]) | ||
| else: | ||
| rel_path = Path(raw_playbook) | ||
|
|
||
| local_path = self.step.plan.anchor_path / rel_path |
There was a problem hiding this comment.
A high-severity Path Traversal vulnerability exists in the _resolve_playbook_for_guest method. It resolves local playbook paths by concatenating the plan's anchor path with a user-supplied path without proper validation, potentially allowing an attacker to read arbitrary files. The method fails to use the unrooted() helper or verify that the resulting path is within the anchor path. Additionally, consider refactoring the duplicated playbook resolution logic to improve maintainability.
| if lowercased.startswith('file://'): | |
| rel_path = Path(raw_playbook[7:]) | |
| else: | |
| rel_path = Path(raw_playbook) | |
| local_path = self.step.plan.anchor_path / rel_path | |
| if lowercased.startswith('file://'): | |
| rel_path = Path(raw_playbook[7:]) | |
| else: | |
| rel_path = Path(raw_playbook) | |
| local_path = self.step.plan.anchor_path / rel_path.unrooted() | |
| if not local_path.is_relative_to(self.step.plan.anchor_path): | |
| raise PrepareError(f"Playbook path '{raw_playbook}' is outside the plan directory.") |
| f'{guest.facts.sudo_prefix} podman run -d' | ||
| f' --name {container_name}' | ||
| f' -v {guest.run_workdir}:{guest.run_workdir}:Z' | ||
| f' {current_image}' | ||
| f' sleep infinity' | ||
| ) | ||
| ) |
There was a problem hiding this comment.
The podman run command is constructed using an f-string and executed via ShellScript. Variables such as guest.run_workdir and current_image are included without proper shell quoting. While paths internally generated and controlled by the application, like guest.run_workdir, do not strictly require quoting for security against command injection, lack of quoting can still cause the command to fail if paths contain spaces. For current_image, if it's user-provided, this poses a command injection risk. Using the Command class is preferred as it handles argument quoting safely for all variables and improves robustness.
# Start a container from the current bootc image
logger.info('ansible', f'starting container {container_name}', 'green')
podman_run_cmd = Command('podman', 'run', '-d')
if guest.facts.sudo_prefix:
podman_run_cmd = Command(guest.facts.sudo_prefix) + podman_run_cmd
podman_run_cmd += Command('--name', container_name)
podman_run_cmd += Command('-v', f'{guest.run_workdir}:{guest.run_workdir}:Z')
podman_run_cmd += Command(current_image, 'sleep', 'infinity')
guest.execute(podman_run_cmd)References
- Paths that are internally generated and controlled by the application do not need to be quoted in shell commands, as they are not considered user-provided input.
| ansible_cmd = ( | ||
| f'{guest.facts.sudo_prefix} ansible-playbook' | ||
| f' -c containers.podman.podman' | ||
| f" -i '{container_name},'" | ||
| f' {guest_playbook}' | ||
| ) | ||
|
|
||
| if self.data.extra_args: | ||
| ansible_cmd += f' {self.data.extra_args}' | ||
|
|
||
| return guest.execute(ShellScript(ansible_cmd)) |
There was a problem hiding this comment.
The ansible-playbook command is constructed using an f-string and executed via ShellScript. Variables such as container_name, guest_playbook, and self.data.extra_args are included without proper shell quoting. While paths internally generated and controlled by the application, like container_name, do not strictly require quoting for security against command injection, lack of quoting can still cause the command to fail if paths contain spaces. For guest_playbook and especially self.data.extra_args (which is user-provided), this poses a significant command injection risk. Structured Command objects should be used instead of raw shell strings to handle argument quoting safely.
# Build the ansible-playbook command to run on the guest
ansible_cmd = Command('ansible-playbook')
if guest.facts.sudo_prefix:
ansible_cmd = Command(guest.facts.sudo_prefix) + ansible_cmd
ansible_cmd += Command('-c', 'containers.podman.podman', '-i', f'{container_name},', guest_playbook)
if self.data.extra_args:
import shlex
ansible_cmd += Command(*shlex.split(self.data.extra_args))
return guest.execute(ansible_cmd)References
- Paths that are internally generated and controlled by the application do not need to be quoted in shell commands, as they are not considered user-provided input.
Fixes #4606 Get rid of the standalone `tests/prepare/bootc/` and user rather the existing per-plugin prepare step test suites (`prepare/install`, `prepare/shell`, `prepare/recommend`). Extend them with image mode coverage on both CentOS Stream 10 and Fedora 44 bootc qcow2 images. All image mode tests verify that prepared state (installed packages, enabled repos, excluded packages) persists after a reboot, which is critical for image mode where changes are applied via Containerfile rebuild + `bootc switch` + reboot. Implements three missing methods in `Bootc` package manager (`tmt/package_managers/bootc.py`) that enable `prepare/install` with COPR and `prepare/artifact` on image mode guests: - `enable_copr()` — delegates to the underlying `Dnf`/`Dnf5` package manager via `bootc_builder`. The copr plugin install and `dnf copr enable` write to `/etc` which persists in image mode. - `create_repository()` — delegates to `aux_engine` to run `createrepo` on the live system. - `install_repository()` — delegates to `aux_engine` to write `.repo` file to `/etc/yum.repos.d/` and refresh the package cache on the live system without triggering a container rebuild. `create_repository()` and `install_repository()` are not directly tested — they are trivial one-line delegations to `aux_engine` and will be exercised once the `prepare/artifact` tests are extended for image mode in a follow-up PR. - Adds `TEST_IMAGE_MODE_IMAGES` variable and `is_image_mode*` helper functions to `tests/images.sh` - Creates `/plans/provision/virtual-image-mode` CI plan with `PROVISION_HOW=virtual-image-mode` environment. Tests can be marked to run in this plan using the tag `provision-virtual-image-mode`. - Adds corresponding Packit job `provision-virtual-image-mode` to run the tests separately The following existing tests are extended with image mode coverage (reboot persistence verification via `tmt-reboot`): | Test | Scenarios on image mode | |------|------------------------| | `prepare/install` | existing packages, downloaded packages, COPR, debuginfo, exclude, escape | | `prepare/shell` | custom script with Containerfile assertions | | `prepare/recommend` | recommended packages with missing package handling | Inner test plans gain `adjust: when: package_manager == bootc` blocks that override the execute step to verify packages/repos and reboot. | Plugin | Reason | |--------|--------| | `prepare/artifact` | Currently `provision-container` only with `distro == fedora` gate. Code fixes are in place but test infrastructure needs refactoring. | | `prepare/ansible` | Runs ansible-playbook via SSH, cannot be deferred to Containerfile. Tracked in #4636. | | `prepare/feature/epel`, `fips`, `profile` | Use Ansible playbooks internally. To be covered with #4636 or follow-up. | | `prepare/distgit` | Existing test needs refactoring to support image mode provision. | | `prepare/require` | Currently `provision-container` only. | Pull Request Checklist * [x] implement the feature * [x] extend the test coverage Assisted-by: Claude Code Signed-off-by: Miroslav Vadkerti <mvadkert@redhat.com>
Fixes #4606 Get rid of the standalone `tests/prepare/bootc/` and user rather the existing per-plugin prepare step test suites (`prepare/install`, `prepare/shell`, `prepare/recommend`). Extend them with image mode coverage on both CentOS Stream 10 and Fedora 44 bootc qcow2 images. All image mode tests verify that prepared state (installed packages, enabled repos, excluded packages) persists after a reboot, which is critical for image mode where changes are applied via Containerfile rebuild + `bootc switch` + reboot. Implements three missing methods in `Bootc` package manager (`tmt/package_managers/bootc.py`) that enable `prepare/install` with COPR and `prepare/artifact` on image mode guests: - `enable_copr()` — delegates to the underlying `Dnf`/`Dnf5` package manager via `bootc_builder`. The copr plugin install and `dnf copr enable` write to `/etc` which persists in image mode. - `create_repository()` — delegates to `aux_engine` to run `createrepo` on the live system. - `install_repository()` — delegates to `aux_engine` to write `.repo` file to `/etc/yum.repos.d/` and refresh the package cache on the live system without triggering a container rebuild. `create_repository()` and `install_repository()` are not directly tested — they are trivial one-line delegations to `aux_engine` and will be exercised once the `prepare/artifact` tests are extended for image mode in a follow-up PR. - Adds `TEST_IMAGE_MODE_IMAGES` variable and `is_image_mode*` helper functions to `tests/images.sh` - Creates `/plans/provision/virtual-image-mode` CI plan with `PROVISION_HOW=virtual-image-mode` environment. Tests can be marked to run in this plan using the tag `provision-virtual-image-mode`. - Adds corresponding Packit job `provision-virtual-image-mode` to run the tests separately The following existing tests are extended with image mode coverage (reboot persistence verification via `tmt-reboot`): | Test | Scenarios on image mode | |------|------------------------| | `prepare/install` | existing packages, downloaded packages, COPR, debuginfo, exclude, escape | | `prepare/shell` | custom script with Containerfile assertions | | `prepare/recommend` | recommended packages with missing package handling | Inner test plans gain `adjust: when: package_manager == bootc` blocks that override the execute step to verify packages/repos and reboot. | Plugin | Reason | |--------|--------| | `prepare/artifact` | Currently `provision-container` only with `distro == fedora` gate. Code fixes are in place but test infrastructure needs refactoring. | | `prepare/ansible` | Runs ansible-playbook via SSH, cannot be deferred to Containerfile. Tracked in #4636. | | `prepare/feature/epel`, `fips`, `profile` | Use Ansible playbooks internally. To be covered with #4636 or follow-up. | | `prepare/distgit` | Existing test needs refactoring to support image mode provision. | | `prepare/require` | Currently `provision-container` only. | Pull Request Checklist * [x] implement the feature * [x] extend the test coverage Assisted-by: Claude Code Signed-off-by: Miroslav Vadkerti <mvadkert@redhat.com>
Fixes #4606 Remove standalone `tests/prepare/bootc/` and extend existing plugin tests (`prepare/install`, `prepare/shell`, `prepare/recommend`) with image mode coverage on CentOS Stream 10 and Fedora 44 bootc images. Implement three methods in `Bootc` package manager: - `enable_copr()` — installs copr plugin via Containerfile (since `/usr` is read-only), then runs `dnf copr enable` on the live system to write `.repo` to `/etc`. - `create_repository()`, `install_repository()` — delegate to `aux_engine` to run on the live system. Not directly tested, will be exercised when `prepare/artifact` tests are extended. Existing tests gain `IS_IMAGE_MODE` handling and run against image mode images when triggered by the new `/plans/provision/virtual/image-mode` sub-plan. Reboot persistence is verified through a dedicated `reboot-persistence` inner plan that installs packages, reboots via `tmt-reboot`, and re-verifies. A single reboot test is sufficient — all install variants (repo, local RPM, COPR, etc.) go through the same bootc mechanism (Containerfile rebuild → `bootc switch` → reboot), so if packages survive a reboot in one case, they survive in all. Not covered (follow-up): - `prepare/artifact`, `prepare/require` — `provision-container` only - `prepare/ansible`, `prepare/feature` — need #4636 - `prepare/distgit` — test refactoring needed Assisted-by: Claude Code Signed-off-by: Miroslav Vadkerti <mvadkert@redhat.com>
Remove standalone `tests/prepare/bootc/` and extend existing plugin tests (`prepare/install`, `prepare/shell`, `prepare/recommend`) with image mode coverage on CentOS Stream 10 and Fedora 44 bootc images. - `enable_copr()` — installs copr plugin via Containerfile (since `/usr` is read-only), then runs `dnf copr enable` on the live system to write `.repo` to `/etc`. - `create_repository()`, `install_repository()` — delegate to `aux_engine` to run on the live system. Not directly tested, will be exercised when `prepare/artifact` tests are extended. Existing tests gain `IS_IMAGE_MODE` handling and run against image mode images when triggered by the new `/plans/provision/virtual/image-mode` sub-plan. Reboot persistence is verified through a dedicated `reboot-persistence` inner plan that installs packages, reboots via `tmt-reboot`, and re-verifies. A single reboot test is sufficient — all install variants (repo, local RPM, COPR, etc.) go through the same bootc mechanism (Containerfile rebuild → `bootc switch` → reboot), so if packages survive a reboot in one case, they survive in all. - `prepare/artifact`, `prepare/require` — currently `provision-container` only - `prepare/ansible`, `prepare/feature/epel,fips,profile` — need Ansible support in image mode (#4636) - `prepare/distgit` — test refactoring needed Pull Request Checklist * [x] implement the feature * [x] extend the test coverage Assisted-by: Claude Code
Remove standalone `tests/prepare/bootc/` and extend existing plugin tests (`prepare/install`, `prepare/shell`, `prepare/recommend`) with image mode coverage on CentOS Stream 10 and Fedora 44 bootc images. - `enable_copr()` — installs copr plugin via Containerfile (since `/usr` is read-only), then runs `dnf copr enable` on the live system to write `.repo` to `/etc`. - `create_repository()`, `install_repository()` — delegate to `aux_engine` to run on the live system. Not directly tested, will be exercised when `prepare/artifact` tests are extended. Existing tests gain `IS_IMAGE_MODE` handling and run against image mode images when triggered by the new `/plans/provision/virtual/image-mode` sub-plan. Reboot persistence is verified through a dedicated `reboot-persistence` inner plan that installs packages, reboots via `tmt-reboot`, and re-verifies. A single reboot test is sufficient — all install variants (repo, local RPM, COPR, etc.) go through the same bootc mechanism (Containerfile rebuild → `bootc switch` → reboot), so if packages survive a reboot in one case, they survive in all. - `prepare/artifact`, `prepare/require` — currently `provision-container` only - `prepare/ansible`, `prepare/feature/epel,fips,profile` — need Ansible support in image mode (#4636) - `prepare/distgit` — test refactoring needed Pull Request Checklist * [x] implement the feature * [x] extend the test coverage Assisted-by: Claude Code Signed-off-by: Miroslav Vadkerti <mvadkert@redhat.com>
Remove standalone `tests/prepare/bootc/` and extend existing plugin tests (`prepare/install`, `prepare/shell`, `prepare/recommend`) with image mode coverage on CentOS Stream 10 and Fedora 44 bootc images. - `enable_copr()` — installs copr plugin via Containerfile (since `/usr` is read-only), then runs `dnf copr enable` on the live system to write `.repo` to `/etc`. - `create_repository()`, `install_repository()` — delegate to `aux_engine` to run on the live system. Not directly tested, will be exercised when `prepare/artifact` tests are extended. Existing tests gain `IS_IMAGE_MODE` handling and run against image mode images when triggered by the new `/plans/provision/virtual/image-mode` sub-plan. Reboot persistence is verified through a dedicated `reboot-persistence` inner plan that installs packages, reboots via `tmt-reboot`, and re-verifies. A single reboot test is sufficient — all install variants (repo, local RPM, COPR, etc.) go through the same bootc mechanism (Containerfile rebuild → `bootc switch` → reboot), so if packages survive a reboot in one case, they survive in all. - `prepare/artifact`, `prepare/require` — currently `provision-container` only - `prepare/ansible`, `prepare/feature/epel,fips,profile` — need Ansible support in image mode (#4636) - `prepare/distgit` — test refactoring needed Pull Request Checklist * [x] implement the feature * [x] extend the test coverage Assisted-by: Claude Code Signed-off-by: Miroslav Vadkerti <mvadkert@redhat.com>
Remove standalone `tests/prepare/bootc/` and extend existing plugin tests (`prepare/install`, `prepare/shell`, `prepare/recommend`) with image mode coverage on CentOS Stream 10 and Fedora 44 bootc images. - `enable_copr()` — installs copr plugin via Containerfile (since `/usr` is read-only), then runs `dnf copr enable` on the live system to write `.repo` to `/etc`. - `create_repository()`, `install_repository()` — delegate to `aux_engine` to run on the live system. Not directly tested, will be exercised when `prepare/artifact` tests are extended. Existing tests gain `IS_IMAGE_MODE` handling and run against image mode images when triggered by the new `/plans/provision/virtual/image-mode` sub-plan. Reboot persistence is verified through a dedicated `reboot-persistence` inner plan that installs packages, reboots via `tmt-reboot`, and re-verifies. A single reboot test is sufficient — all install variants (repo, local RPM, COPR, etc.) go through the same bootc mechanism (Containerfile rebuild → `bootc switch` → reboot), so if packages survive a reboot in one case, they survive in all. - `prepare/artifact`, `prepare/require` — currently `provision-container` only - `prepare/ansible`, `prepare/feature/epel,fips,profile` — need Ansible support in image mode (#4636) - `prepare/distgit` — test refactoring needed Pull Request Checklist * [x] implement the feature * [x] extend the test coverage Assisted-by: Claude Code Signed-off-by: Miroslav Vadkerti <mvadkert@redhat.com>
LecrisUT
left a comment
There was a problem hiding this comment.
I do not like this approach. Please elaborate why you went with this and what other alternatives have you considered.
| def _ensure_ansible_on_guest( | ||
| self, | ||
| guest: 'Guest', | ||
| logger: tmt.log.Logger, | ||
| ) -> None: | ||
| """ | ||
| Ensure ansible-playbook is available on the guest. | ||
|
|
||
| Checks if ansible-playbook is already installed. If not, installs | ||
| ansible-core via the bootc package manager, which triggers a | ||
| container image build, bootc switch, and reboot. | ||
| """ | ||
|
|
||
| try: | ||
| guest.execute(Command('which', 'ansible-playbook'), silent=True) | ||
| logger.debug('ansible-playbook is already available on the guest.') | ||
| except tmt.utils.RunError: | ||
| logger.info('ansible', 'installing ansible-core on the guest', 'green') | ||
| guest.package_manager.install(Package('ansible-core')) |
There was a problem hiding this comment.
Why is ansible required on the guest?
There was a problem hiding this comment.
@LecrisUT this should happen on the guest to:
-
mitigate having an external container registry in place to share the images (or find some other crazy way how to get the base image from the guest and push it to the guest). The base container image is available only on the guest
-
Be similar to a regular container rebuild, less suprises, easier to explain how it works
There was a problem hiding this comment.
mitigate having an external container registry
The local container registry of the bootc runtime should be usable right?
Be similar to a regular container rebuild, less suprises
I disagree with this creating less surprises. E.g. if the package being tested is anything inside the ansible dependency stack, and this fails at the prepare step, how would one debug this? Having a minimal dependency footprint would be the best for the "less surprises"
Before anything, I would like a better breakdown of any other alternative approaches. From what I understand of bootc it is supposed to be possible to do local builds from the current state, don't know if bootc image copy-to-storage, but there seem to be many ways of interacting with bootc and would like to have a more thorough breakdown of it
There was a problem hiding this comment.
The local container registry of the bootc runtime should be usable right?
it has nothing to do with bootc runtime, it is the guest local registry on the machine
I disagree with this creating less surprises. E.g. if the package being tested is anything inside the ansible dependency stack, and this fails at the prepare step, how would one debug this? Having a minimal dependency footprint would be the best for the "less surprises"
Not sure I follow, the failed preparation should be visible from the tmt logs?
Before anything, I would like a better breakdown of any other alternative approaches. From what I understand of bootc it is supposed to be possible to do local builds from the current state,
Local to what? guest or host?
don't know if bootc image copy-to-storage, but there seem to be many ways of interacting with bootc and would like to have a more thorough breakdown of it
I am not aware of any alternative approaches that would not require what I wrote
| ShellScript( | ||
| f'{guest.facts.sudo_prefix} /bin/bash -c "(' | ||
| f' ( podman pull {current_image}' | ||
| f' || podman pull containers-storage:{current_image} )' | ||
| f' || bootc image copy-to-storage --target {current_image}' | ||
| ')"' | ||
| ) |
| # Build the ansible-playbook command to run on the guest | ||
| ansible_cmd = ( | ||
| f'{guest.facts.sudo_prefix} ansible-playbook' | ||
| f' -c containers.podman.podman' | ||
| f" -i '{container_name},'" | ||
| f' {guest_playbook}' | ||
| ) |
There was a problem hiding this comment.
👎 to this approach. It uses both a containers connection and it also runs on the guest!?
|
It was decided we will not support Ansible for now, only fix the playbooks for feature plugins to be image-mode friendly. |
Remove standalone `tests/prepare/bootc/` and extend existing plugin tests (`prepare/install`, `prepare/shell`, `prepare/recommend`) with image mode coverage on CentOS Stream 10 and Fedora 44 bootc images. - `enable_copr()` — installs copr plugin via Containerfile (since `/usr` is read-only), then runs `dnf copr enable` on the live system to write `.repo` to `/etc`. - `create_repository()`, `install_repository()` — delegate to `aux_engine` to run on the live system. Not directly tested, will be exercised when `prepare/artifact` tests are extended. Existing tests gain `IS_IMAGE_MODE` handling and run against image mode images when triggered by the new `/plans/provision/virtual/image-mode` sub-plan. Reboot persistence is verified through a dedicated `reboot-persistence` inner plan that installs packages, reboots via `tmt-reboot`, and re-verifies. A single reboot test is sufficient — all install variants (repo, local RPM, COPR, etc.) go through the same bootc mechanism (Containerfile rebuild → `bootc switch` → reboot), so if packages survive a reboot in one case, they survive in all. - `prepare/artifact`, `prepare/require` — currently `provision-container` only - `prepare/ansible`, `prepare/feature/epel,fips,profile` — need Ansible support in image mode (#4636) - `prepare/distgit` — test refactoring needed Pull Request Checklist * [x] implement the feature * [x] extend the test coverage Assisted-by: Claude Code Signed-off-by: Miroslav Vadkerti <mvadkert@redhat.com>
|
As discussed, closing this for now, we will go with #4625 by adjusting the playbooks to not use tasks which will not work in image mode (e.g. dnf) |
Remove standalone `tests/prepare/bootc/` and extend existing plugin tests (`prepare/install`, `prepare/shell`, `prepare/recommend`) with image mode coverage on CentOS Stream 10 and Fedora 44 bootc images. - `enable_copr()` — installs copr plugin via Containerfile (since `/usr` is read-only), then runs `dnf copr enable` on the live system to write `.repo` to `/etc`. - `create_repository()`, `install_repository()` — delegate to `aux_engine` to run on the live system. Not directly tested, will be exercised when `prepare/artifact` tests are extended. Existing tests gain `IS_IMAGE_MODE` handling and run against image mode images when triggered by the new `/plans/provision/virtual/image-mode` sub-plan. Reboot persistence is verified through a dedicated `reboot-persistence` inner plan that installs packages, reboots via `tmt-reboot`, and re-verifies. A single reboot test is sufficient — all install variants (repo, local RPM, COPR, etc.) go through the same bootc mechanism (Containerfile rebuild → `bootc switch` → reboot), so if packages survive a reboot in one case, they survive in all. - `prepare/artifact`, `prepare/require` — currently `provision-container` only - `prepare/ansible`, `prepare/feature/epel,fips,profile` — need Ansible support in image mode (#4636) - `prepare/distgit` — test refactoring needed Pull Request Checklist * [x] implement the feature * [x] extend the test coverage Assisted-by: Claude Code Signed-off-by: Miroslav Vadkerti <mvadkert@redhat.com>
Remove standalone `tests/prepare/bootc/` and extend existing plugin tests (`prepare/install`, `prepare/shell`, `prepare/recommend`) with image mode coverage on CentOS Stream 10 and Fedora 44 bootc images. - `enable_copr()` — installs copr plugin via Containerfile (since `/usr` is read-only), then runs `dnf copr enable` on the live system to write `.repo` to `/etc`. - `create_repository()`, `install_repository()` — delegate to `aux_engine` to run on the live system. Not directly tested, will be exercised when `prepare/artifact` tests are extended. Existing tests gain `IS_IMAGE_MODE` handling and run against image mode images when triggered by the new `/plans/provision/virtual/image-mode` sub-plan. Reboot persistence is verified through a dedicated `reboot-persistence` inner plan that installs packages, reboots via `tmt-reboot`, and re-verifies. A single reboot test is sufficient — all install variants (repo, local RPM, COPR, etc.) go through the same bootc mechanism (Containerfile rebuild → `bootc switch` → reboot), so if packages survive a reboot in one case, they survive in all. - `prepare/artifact`, `prepare/require` — currently `provision-container` only - `prepare/ansible`, `prepare/feature/epel,fips,profile` — need Ansible support in image mode (#4636) - `prepare/distgit` — test refactoring needed Pull Request Checklist * [x] implement the feature * [x] extend the test coverage Assisted-by: Claude Code Signed-off-by: Miroslav Vadkerti <mvadkert@redhat.com>
Remove standalone `tests/prepare/bootc/` and extend existing plugin tests (`prepare/install`, `prepare/shell`, `prepare/recommend`) with image mode coverage on CentOS Stream 10 and Fedora 44 bootc images. - `enable_copr()` — installs copr plugin via Containerfile (since `/usr` is read-only), then runs `dnf copr enable` on the live system to write `.repo` to `/etc`. - `create_repository()`, `install_repository()` — delegate to `aux_engine` to run on the live system. Not directly tested, will be exercised when `prepare/artifact` tests are extended. Existing tests gain `IS_IMAGE_MODE` handling and run against image mode images when triggered by the new `/plans/provision/virtual/image-mode` sub-plan. Reboot persistence is verified through a dedicated `reboot-persistence` inner plan that installs packages, reboots via `tmt-reboot`, and re-verifies. A single reboot test is sufficient — all install variants (repo, local RPM, COPR, etc.) go through the same bootc mechanism (Containerfile rebuild → `bootc switch` → reboot), so if packages survive a reboot in one case, they survive in all. - `prepare/artifact`, `prepare/require` — currently `provision-container` only - `prepare/ansible`, `prepare/feature/epel,fips,profile` — need Ansible support in image mode (#4636) - `prepare/distgit` — test refactoring needed Pull Request Checklist * [x] implement the feature * [x] extend the test coverage Assisted-by: Claude Code Signed-off-by: Miroslav Vadkerti <mvadkert@redhat.com>
Summary
ansibleprepare pluginansible-playbookwithcontainers.podman.podmanconnection plugin, commits the result, switches viabootc switch, and rebootstests/prepare/bootc/patternDetails
On image mode guests,
/usris read-only and system changes must be baked into the container image. The existing shell and install prepare plugins handle this via Containerfile directives, but the ansible plugin had no image mode support.The implementation:
ansible-playbookis available on the guest (installsansible-coreif needed)ansible-playbook -c containers.podman.podmanbootc switch --transport containers-storageand rebootsTest plan
tests/prepare/bootc-ansible/test with an image mode guestCloses #4624