Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions tests/prepare/bootc-large-env/data/.fmf/version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
1
19 changes: 19 additions & 0 deletions tests/prepare/bootc-large-env/data/plans.fmf
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
discover:
how: fmf

provision:
how: virtual

execute:
how: tmt

/centos-stream-10:
provision+:
image: https://artifacts.dev.testing-farm.io/images/CentOS-Stream-10-image-mode-x86_64.qcow2

/large-env:
summary: "Prepare/shell with large environment on bootc guest"
prepare:
how: shell
script:
- dnf -y install tree
4 changes: 4 additions & 0 deletions tests/prepare/bootc-large-env/data/test.fmf
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
summary: Verify prepare/shell with large environment succeeded
test: |
tree --version
bootc status --booted --format humanreadable
15 changes: 15 additions & 0 deletions tests/prepare/bootc-large-env/main.fmf
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
summary: Test bootc image-mode with large plan environment
description: |
Verify that prepare/shell on bootc image-mode guests succeeds
when plan environment contains large values (e.g. base64-encoded
secrets). Without the push() fix, the generated Containerfile
was passed as a cat heredoc SSH command-line argument, exceeding
the OS ARG_MAX limit.
link:
- verifies: https://github.com/teemtee/tmt/issues/4518
tag+:
- provision-only
- provision-virtual
require:
- tmt+provision-virtual
duration: 2h
41 changes: 41 additions & 0 deletions tests/prepare/bootc-large-env/test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#!/bin/bash
. /usr/share/beakerlib/beakerlib.sh || exit 1

rlJournalStart
rlPhaseStartSetup
rlRun "pushd data"
rlRun "run=\$(mktemp -d --tmpdir=/var/tmp/tmt)" 0 "Create run directory"

# Generate a ~67KB base64 string simulating an encoded secret.
# This exceeds ARG_MAX when multiplied across Containerfile RUN
# directives (the bug), but is small enough to pass through
# individual SSH execute() calls.
rlRun "python3 -c 'import base64; print(\"LARGE_SECRET: \" + base64.b64encode(b\"x\" * 50000).decode())' > large-env.yaml"
rlRun "echo \"LARGE_SECRET size: \$(wc -c < large-env.yaml) bytes\""
rlPhaseEnd

rlPhaseStartTest "Prepare/shell with large environment on bootc guest"
rlRun -s "tmt -dddvvv run --scratch -i \$run --environment-file large-env.yaml plan --name /plans/centos-stream-10/large-env"

# Verify the prepare/shell command was collected
rlAssertGrep "Collected command for Containerfile" \$rlRun_LOG

# Verify the container image was built
rlAssertGrep "building container image" \$rlRun_LOG

# Verify bootc switch was called
rlAssertGrep "switching to new image" \$rlRun_LOG

# Verify reboot happened
rlAssertGrep "rebooting to apply new image" \$rlRun_LOG

# Verify tree --version ran successfully in the test
rlAssertGrep "tree v" \$rlRun_LOG
rlPhaseEnd

rlPhaseStartCleanup
rlRun "rm -rf \$run" 0 "Remove run directory"
rlRun "rm -f large-env.yaml" 0 "Remove generated environment file"
rlRun "popd"
rlPhaseEnd
rlJournalEnd
22 changes: 19 additions & 3 deletions tmt/package_managers/bootc.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import re
import tempfile
import uuid
from collections.abc import Iterator
from typing import Any, Optional

import tmt.utils
from tmt.container import PYDANTIC_V1, ConfigDict, MetadataContainer
from tmt.guest import TransferOptions
from tmt.package_managers import (
Installable,
Options,
Expand Down Expand Up @@ -265,9 +267,23 @@ def build_container(self) -> Optional[CommandOutput]:
')"'
)
)
self.guest.execute(
ShellScript(f'cat <<EOF > {containerfile_path!s} \n{containerfile} \nEOF')
)
# Write Containerfile via push() to avoid exceeding
# the OS ARG_MAX limit on the SSH command line.
with tempfile.NamedTemporaryFile(
mode='w',
suffix='.Containerfile',
delete=True,
) as tmp:
tmp.write(containerfile)
tmp.flush()
self.guest.push(
source=Path(tmp.name),
destination=containerfile_path,
options=TransferOptions(
recursive=False,
compress=True,
),
)

self.debug(f"containerfile content: {containerfile}")
# Build the container image
Expand Down
Loading