Skip to content
Merged
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
56 changes: 38 additions & 18 deletions bootc-build/setup-runner/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ inputs:
description: "Storage backend: 'btrfs' (remove-software + BTRFS loopback for /var/lib/containers) or 'remove-software' (remove-software only)"
default: "btrfs"
update-podman:
description: "Install podman/buildah/crun/skopeo from Ubuntu resolute (25.04)"
description: "Upgrade podman/buildah/crun/skopeo from Ubuntu resolute (26.04) on runner images that ship an older stack; no-op on ubuntu-26.04 runners"
default: "true"
native-overlay:
description: "Use native rootful overlay storage instead of fuse-overlayfs; resets rootful Podman storage"
Expand Down Expand Up @@ -52,31 +52,51 @@ runs:
mount-opts: compress-force=zstd:2
loopback-free: "1"

- name: Add Ubuntu resolute apt source
- name: Select podman source
if: inputs.update-podman == 'true'
id: podman-source
shell: bash
run: |
set -eux
# TODO: remove when Ubuntu 26.04 runners ship a new-enough podman
# Old podman (Ubuntu 24.04) does not push layer annotations (ostree.components)
# needed by the rpm-ostree rechunker and does not support zstd:chunked push.
IDV=$(. /usr/lib/os-release && echo ${ID}-${VERSION_ID})
test "${IDV}" = "ubuntu-24.04"
if [ "$(dpkg --print-architecture)" = "amd64" ]; then
mirror="http://azure.archive.ubuntu.com/ubuntu"
else
mirror="http://ports.ubuntu.com/ubuntu-ports"
fi
echo "deb ${mirror} resolute universe main" | sudo tee /etc/apt/sources.list.d/resolute.list
set -euo pipefail
IDV=$(. /usr/lib/os-release && echo "${ID}-${VERSION_ID}")
case "${IDV}" in
ubuntu-24.04)
# Ubuntu 24.04's podman (4.9.x) does not push layer annotations
# (ostree.components) needed by the rpm-ostree rechunker and does not
# support zstd:chunked push. The resolute (26.04) packages install on
# noble, so pull the whole stack from there.
if [ "$(dpkg --print-architecture)" = "amd64" ]; then
mirror="http://azure.archive.ubuntu.com/ubuntu"
else
mirror="http://ports.ubuntu.com/ubuntu-ports"
fi
echo "deb ${mirror} resolute universe main" | sudo tee /etc/apt/sources.list.d/resolute.list
echo "install-from-resolute=true" >> "$GITHUB_OUTPUT"
;;
ubuntu-26.04)
# resolute *is* 26.04: verify the runner's podman is 5.x or newer
PODMAN_VERSION=$(podman --version 2>/dev/null | awk '{print $3}' || echo "unknown")
if [[ ! "${PODMAN_VERSION}" =~ ^([0-9]+)\. ]] || (( BASH_REMATCH[1] < 5 )); then
echo "::error::ubuntu-26.04 runner image has podman '${PODMAN_VERSION}', but version 5.x or newer is required for layer annotations and zstd:chunked push."
exit 1
fi
echo "::notice::${IDV} ships podman ${PODMAN_VERSION}; skipping the resolute apt source."
echo "install-from-resolute=false" >> "$GITHUB_OUTPUT"
;;
*)
echo "::error::setup-runner supports ubuntu-24.04 and ubuntu-26.04 runner images; found '${IDV}'. Set update-podman: 'false' to skip the podman upgrade."
exit 1
;;
esac

- name: Compute apt cache key (weekly rotation)
if: inputs.update-podman == 'true'
if: steps.podman-source.outputs.install-from-resolute == 'true'
id: apt-cache-key
shell: bash
run: echo "week=$(date +%Y-W%V)" >> "$GITHUB_OUTPUT"

- name: Restore apt package cache
if: inputs.update-podman == 'true'
if: steps.podman-source.outputs.install-from-resolute == 'true'
id: apt-cache-restore
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
Expand All @@ -86,7 +106,7 @@ runs:
apt-resolute-podman-${{ runner.os }}-${{ runner.arch }}-

- name: Install podman stack from Ubuntu resolute
if: inputs.update-podman == 'true'
if: steps.podman-source.outputs.install-from-resolute == 'true'
shell: bash
run: |
set -eux
Expand All @@ -103,7 +123,7 @@ runs:
sudo rm -f /etc/needrestart/conf.d/99-no-restarts.conf

- name: Save apt package cache
if: inputs.update-podman == 'true' && steps.apt-cache-restore.outputs.cache-hit != 'true'
if: steps.podman-source.outputs.install-from-resolute == 'true' && steps.apt-cache-restore.outputs.cache-hit != 'true'
uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: /var/cache/apt/archives
Expand Down
2 changes: 1 addition & 1 deletion docs/skills/composite-actions.md
Original file line number Diff line number Diff line change
Expand Up @@ -457,7 +457,7 @@ jobs:
Always add `workflow_dispatch` alongside `workflow_run` so the workflow can be triggered manually without waiting for the upstream workflow to run.
| `chmod 777` before cache save | `dnf-cache` | [actions/cache#1533](https://github.com/actions/cache/issues/1533) - root-owned files break cache agent |
| `chown ~/.sigstore` before cosign | `sign-and-publish` | Runner sigstore cache created with wrong ownership |
| podman upgraded from Ubuntu resolute | `setup-runner` | Ubuntu 24.04 podman too old for `ostree.components` annotations + `zstd:chunked` push |
| podman upgraded from Ubuntu resolute | `setup-runner` | Ubuntu 24.04 podman too old for `ostree.components` annotations + `zstd:chunked` push (skipped on 26.04 runners after verifying Podman >= 5) |
| `-v $(pwd):/run/src` + `--security-opt=label=disable` | `chunka` | buildah < v1.44 drops bind-mounts without these; needed for the OCI output dir (`out/`) to survive to the final stage |
| `sudo rm -rf out` | `chunka` | Containerfile.splitter leaves `out/` dir in CWD (v0.6.0+; was `out.ociarchive` in v0.5.0); stale dir breaks re-runs |
| `sudo podman save \| podman load` | `chunka` | buildah (root) and podman (user) use separate container stores |
Expand Down
11 changes: 6 additions & 5 deletions docs/skills/composite-actions/action-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ Sets up a GitHub Actions runner for bootc image building. Two storage backends:
- `btrfs` (default): mounts a BTRFS volume at `/var/lib/containers` via `ublue-os/container-storage-action`
- `remove-software`: frees disk by nuking Android/Haskell/dotnet toolchains

Upgrades podman from Ubuntu **resolute** (25.04) because older Ubuntu 24.04 runner images ship a version too old to support layer annotations (`ostree.components`) and `zstd:chunked` push.
Upgrades podman from Ubuntu **resolute** (26.04) on `ubuntu-24.04` runner images because stock noble ships Podman 4.9.x, which is too old to support layer annotations (`ostree.components`) and `zstd:chunked` push. On `ubuntu-26.04` runner images, setup-runner verifies the runner already ships Podman 5.x or newer and skips the resolute apt source. Any other runner image fails fast with an actionable error.

Installs optional tools (`just`, `cosign`, `oras`, `syft`) via `install-tools` JSON array input.

Expand Down Expand Up @@ -65,11 +65,12 @@ Native-overlay mode is opt-in and destructive to existing **rootful** Podman sta

Combine it with `update-podman: "true"` when the consumer requires Podman 5 on every hosted
runner. Runner images that predate the static Podman bundle ship apt Podman 4.9.3, which fails
the version gate unless Resolute packages are installed. Images that include the bundle keep
`/usr/local/bin/podman` ahead of the Resolute packages on `PATH` (including sudo's
`secure_path`); normalizing that mixed stack is a separate concern from this mode. Use
the version gate unless Resolute packages are installed. On `ubuntu-26.04` runners, `update-podman: "true"`
verifies the runner's Podman is already version 5 or newer and skips the Resolute apt source as a no-op.
Images that include the bundle keep `/usr/local/bin/podman` ahead of the Resolute packages on `PATH`
(including sudo's `secure_path`); normalizing that mixed stack is a separate concern from this mode. Use
`update-podman: "false"` only when the caller can rely on the runner-provided Podman already
being version 5 or newer.
being version 5 or newer on any runner image.

Do not merely delete `mount_program` from the runner configuration: the FUSE-only `fsync=0` mount
option and containers/storage's persistent mount-program marker must be removed too.
Expand Down
2 changes: 1 addition & 1 deletion docs/skills/testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ Coverage gate: `--cov-fail-under=75`
| `detect-changes` image_flavors shell logic | `tests/bats/test_detect_changes.bats` (8 tests) |
| `push-image` push/retry/alias shell logic | `tests/bats/test_push_image.bats` (16 tests) |
| `sign-and-publish` keyless/key validation + SBOM attach/cache/path guards | `tests/bats/test_sign_and_publish.bats` (19 tests) |
| `setup-runner` native-overlay setup | `tests/bats/test_setup_runner.bats` (9 tests) |
| `setup-runner` native-overlay setup & podman source selection | `tests/bats/test_setup_runner.bats` (16 tests) |
| `chunka` config temp-file creation + `fs.protected_regular` drift guard | `tests/bats/test_chunka.bats` (4 tests) |
| `reusable-renovate-automerge.yml` check-rollup classification | `tests/bats/test_renovate_automerge_checks.bats` (8 tests) |
| `reusable-renovate-automerge.yml` PR-lookup / qualification matcher | `tests/bats/test_renovate_automerge_find_pr.bats` (10 tests) |
Expand Down
161 changes: 159 additions & 2 deletions tests/bats/test_setup_runner.bats
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#!/usr/bin/env bats
# Tests for bootc-build/setup-runner native-overlay validation and storage setup.
# Tests for bootc-build/setup-runner native-overlay validation, storage setup,
# and podman source selection.
#
# The shell logic lives inline in bootc-build/setup-runner/action.yml. Keep these
# snippets verbatim so action changes must update their regression tests.
Expand All @@ -15,6 +16,44 @@ case "${NATIVE_OVERLAY}" in
esac
EOF
)
# Verbatim from bootc-build/setup-runner/action.yml ("Select podman source" step)
# Note: only the os-release source file is substituted via MOCK_OS_RELEASE.
PODMAN_SOURCE_LOGIC=$(cat <<'EOF'
set -euo pipefail
IDV=$(. "${MOCK_OS_RELEASE:-/usr/lib/os-release}" && echo "${ID}-${VERSION_ID}")
case "${IDV}" in
ubuntu-24.04)
# Ubuntu 24.04's podman (4.9.x) does not push layer annotations
# (ostree.components) needed by the rpm-ostree rechunker and does not
# support zstd:chunked push. The resolute (26.04) packages install on
# noble, so pull the whole stack from there.
if [ "$(dpkg --print-architecture)" = "amd64" ]; then
mirror="http://azure.archive.ubuntu.com/ubuntu"
else
mirror="http://ports.ubuntu.com/ubuntu-ports"
fi
echo "deb ${mirror} resolute universe main" | sudo tee /etc/apt/sources.list.d/resolute.list
echo "install-from-resolute=true" >> "$GITHUB_OUTPUT"
;;
ubuntu-26.04)
# resolute *is* 26.04: verify the runner's podman is 5.x or newer
# before skipping the apt source.
PODMAN_VERSION=$(podman --version 2>/dev/null | awk '{print $3}' || echo "unknown")
if [[ ! "${PODMAN_VERSION}" =~ ^([0-9]+)\. ]] || (( BASH_REMATCH[1] < 5 )); then
echo "::error::ubuntu-26.04 runner image has podman '${PODMAN_VERSION}', but version 5.x or newer is required for layer annotations and zstd:chunked push."
exit 1
fi
echo "::notice::${IDV} ships podman ${PODMAN_VERSION}; skipping the resolute apt source."
echo "install-from-resolute=false" >> "$GITHUB_OUTPUT"
;;
*)
echo "::error::setup-runner supports ubuntu-24.04 and ubuntu-26.04 runner images; found '${IDV}'. Set update-podman: 'false' to skip the podman upgrade."
exit 1
;;
esac
EOF
)


NATIVE_OVERLAY_LOGIC=$(cat <<'NATIVE_LOGIC_EOF'
set -euo pipefail
Expand Down Expand Up @@ -95,6 +134,8 @@ setup() {
mkdir -p "${MOCK_DIR}"
touch "${CALL_LOG}"
export PATH="${MOCK_DIR}:${PATH}"
export GITHUB_OUTPUT="${TEST_TMP}/github_output"
touch "${GITHUB_OUTPUT}"

cat > "${MOCK_DIR}/sudo" <<'EOF'
#!/usr/bin/env bash
Expand All @@ -114,14 +155,30 @@ case "${1:-}" in
exit 0
;;
tee)
cat > "${MOCK_STORAGE_CONF}"
shift
if [[ "${1:-}" == "/etc/apt/sources.list.d/resolute.list" ]]; then
cat > "${MOCK_RESOLUTE_LIST}"
else
cat > "${MOCK_STORAGE_CONF}"
fi
;;
*)
exec "$@"
;;
esac
EOF
chmod +x "${MOCK_DIR}/sudo"
cat > "${MOCK_DIR}/dpkg" <<'EOF'
#!/usr/bin/env bash
set -euo pipefail
if [[ "$*" == "--print-architecture" ]]; then
echo "${MOCK_DPKG_ARCH:-amd64}"
exit 0
fi
exit 1
EOF
chmod +x "${MOCK_DIR}/dpkg"


cat > "${MOCK_DIR}/podman" <<'EOF'
#!/usr/bin/env bash
Expand All @@ -148,6 +205,7 @@ EOF
# kernels enable the overlay module's redirect_dir); make the default
# mock match that observation.
export MOCK_PODMAN_INFO_JSON='{"store":{"graphDriverName":"overlay","graphStatus":{"Native Overlay Diff":"false"},"graphOptions":{}}}'
export MOCK_RESOLUTE_LIST="${TEST_TMP}/resolute.list"
}

teardown() {
Expand Down Expand Up @@ -239,3 +297,102 @@ teardown() {
[ "${status}" -ne 0 ]
[[ "${output}" == *"still reports a mount_program"* ]]
}

@test "podman source selection configures resolute apt repo on ubuntu-24.04 amd64" {
export MOCK_OS_RELEASE="${TEST_TMP}/os-release"
cat <<'EOF' > "${MOCK_OS_RELEASE}"
ID=ubuntu
VERSION_ID=24.04
EOF
export MOCK_DPKG_ARCH="amd64"

run bash -c "${PODMAN_SOURCE_LOGIC}"

[ "${status}" -eq 0 ]
grep -q "^install-from-resolute=true$" "${GITHUB_OUTPUT}"
grep -q "deb http://azure.archive.ubuntu.com/ubuntu resolute universe main" "${MOCK_RESOLUTE_LIST}"
}

@test "podman source selection configures resolute ports repo on ubuntu-24.04 arm64" {
export MOCK_OS_RELEASE="${TEST_TMP}/os-release"
cat <<'EOF' > "${MOCK_OS_RELEASE}"
ID=ubuntu
VERSION_ID=24.04
EOF
export MOCK_DPKG_ARCH="arm64"

run bash -c "${PODMAN_SOURCE_LOGIC}"

[ "${status}" -eq 0 ]
grep -q "^install-from-resolute=true$" "${GITHUB_OUTPUT}"
grep -q "deb http://ports.ubuntu.com/ubuntu-ports resolute universe main" "${MOCK_RESOLUTE_LIST}"
}

@test "podman source selection skips apt repo on ubuntu-26.04 when podman >= 5" {
export MOCK_OS_RELEASE="${TEST_TMP}/os-release"
cat <<'EOF' > "${MOCK_OS_RELEASE}"
ID=ubuntu
VERSION_ID=26.04
EOF
export MOCK_PODMAN_VERSION="5.7.0"

run bash -c "${PODMAN_SOURCE_LOGIC}"

[ "${status}" -eq 0 ]
grep -q "^install-from-resolute=false$" "${GITHUB_OUTPUT}"
[[ "${output}" == *"ships podman 5.7.0; skipping the resolute apt source"* ]]
[ ! -f "${MOCK_RESOLUTE_LIST}" ]
}

@test "podman source selection rejects ubuntu-26.04 if podman is older than 5" {
export MOCK_OS_RELEASE="${TEST_TMP}/os-release"
cat <<'EOF' > "${MOCK_OS_RELEASE}"
ID=ubuntu
VERSION_ID=26.04
EOF
export MOCK_PODMAN_VERSION="4.9.3"

run bash -c "${PODMAN_SOURCE_LOGIC}"

[ "${status}" -ne 0 ]
[[ "${output}" == *"ubuntu-26.04 runner image has podman '4.9.3', but version 5.x or newer is required"* ]]
[ ! -f "${MOCK_RESOLUTE_LIST}" ]
}

@test "podman source selection fails fast on unsupported runner image" {
export MOCK_OS_RELEASE="${TEST_TMP}/os-release"
cat <<'EOF' > "${MOCK_OS_RELEASE}"
ID=ubuntu
VERSION_ID=22.04
EOF

run bash -c "${PODMAN_SOURCE_LOGIC}"

[ "${status}" -ne 0 ]
[[ "${output}" == *"supports ubuntu-24.04 and ubuntu-26.04 runner images; found 'ubuntu-22.04'"* ]]
}

@test "podman source selection fails fast on non-ubuntu runner image" {
export MOCK_OS_RELEASE="${TEST_TMP}/os-release"
cat <<'EOF' > "${MOCK_OS_RELEASE}"
ID=fedora
VERSION_ID=42
EOF

run bash -c "${PODMAN_SOURCE_LOGIC}"

[ "${status}" -ne 0 ]
[[ "${output}" == *"supports ubuntu-24.04 and ubuntu-26.04 runner images; found 'fedora-42'"* ]]
}

@test "setup-runner action.yml contains the verbatim podman source selection logic" {
ACTION_FILE="${BATS_TEST_DIRNAME}/../../bootc-build/setup-runner/action.yml"
# Ensure the action.yml contains the expected branch structures and outputs
grep -q 'case "${IDV}" in' "${ACTION_FILE}"
grep -q 'ubuntu-24.04)' "${ACTION_FILE}"
grep -q 'ubuntu-26.04)' "${ACTION_FILE}"
grep -q 'echo "deb \${mirror} resolute universe main" | sudo tee /etc/apt/sources.list.d/resolute.list' "${ACTION_FILE}"
grep -q 'install-from-resolute=true' "${ACTION_FILE}"
grep -q 'install-from-resolute=false' "${ACTION_FILE}"
grep -q "supports ubuntu-24.04 and ubuntu-26.04 runner images" "${ACTION_FILE}"
}
Loading