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
1 change: 1 addition & 0 deletions .containerignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@
!Cargo.toml
!Cargo.lock
!crates/
!contrib/
37 changes: 31 additions & 6 deletions .github/workflows/integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ on:

env:
CARGO_TERM_COLOR: always
COMPOSEFS_TEST_IMAGE: localhost/composefs-rs-test:latest

concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
Expand All @@ -18,13 +17,42 @@ permissions:
contents: read

jobs:
# Fast smoke test — catches basic breakage before spending time on
# container builds and VM boots. Runs only the unprivileged tests
# directly on the runner (no container image, no root required).
smoke:
name: Unprivileged smoke test
runs-on: ubuntu-24.04
timeout-minutes: 15
steps:
- uses: actions/checkout@v5
- uses: extractions/setup-just@v2
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- run: just integration-unprivileged

# Full integration tests: builds a bootc container image, runs all
# tests (both unprivileged and privileged). Privileged tests execute
# inside bcvk ephemeral VMs booted from the container image.
integration:
name: Integration tests
name: Integration tests (${{ matrix.name }})
needs: smoke
runs-on: ubuntu-24.04
timeout-minutes: 30
strategy:
fail-fast: false
matrix:
include:
- name: centos
base_image: quay.io/centos-bootc/centos-bootc:stream10
- name: debian
base_image: ghcr.io/bootcrew/debian-bootc:latest
env:
COMPOSEFS_BASE_IMAGE: ${{ matrix.base_image }}

steps:
- uses: actions/checkout@v5
- uses: extractions/setup-just@v2

- name: Setup
uses: bootc-dev/actions/bootc-ubuntu-setup@main
Expand All @@ -35,8 +63,5 @@ jobs:

- uses: Swatinem/rust-cache@v2

- name: Run unprivileged integration tests
run: just integration-unprivileged

- name: Run privileged integration tests (via bcvk VM)
- name: Run integration tests (unprivileged + privileged via VM)
run: just integration-container
25 changes: 14 additions & 11 deletions Containerfile
Original file line number Diff line number Diff line change
@@ -1,27 +1,29 @@
# Containerfile for composefs-rs
# Containerfile for composefs-rs integration testing
#
# Builds cfsctl and integration test binaries, then produces a bootable
# (bootc-compatible) container image suitable for privileged integration
# testing via `bcvk ephemeral run-ssh`.
#
# Build:
# podman build --tag composefs-rs-test -f Containerfile .
# podman build --tag composefs-rs-test .
# podman build --build-arg base_image=ghcr.io/bootcrew/debian-bootc:latest --tag composefs-rs-test-debian .
#
# Uses BuildKit-style cache mounts for fast incremental Rust builds.
# Note: when switching between base images locally, run
# podman system prune --volumes
# to clear stale build caches that may be incompatible across distros.

ARG base_image=quay.io/centos-bootc/centos-bootc:stream10

# -- source snapshot (keeps layer graph clean) --
FROM scratch AS src
COPY . /src

# -- build stage --
FROM quay.io/centos-bootc/centos-bootc:stream10 AS build
FROM ${base_image} AS build

RUN dnf install -y \
rust cargo clippy rustfmt \
openssl-devel \
gcc \
composefs \
&& dnf clean all
COPY --from=src /src/contrib /src/contrib
RUN /src/contrib/packaging/install-build-deps.sh

COPY --from=src /src /src
WORKDIR /src
Expand All @@ -42,9 +44,10 @@ RUN --network=none \
cp /src/target/release/cfsctl-integration-tests /usr/bin/cfsctl-integration-tests

# -- final bootable image --
FROM quay.io/centos-bootc/centos-bootc:stream10
FROM ${base_image}

RUN dnf install -y composefs openssl && dnf clean all
COPY --from=src /src/contrib /src/contrib
RUN /src/contrib/packaging/install-test-deps.sh && rm -rf /src

COPY --from=build /usr/bin/cfsctl /usr/bin/cfsctl
COPY --from=build /usr/bin/cfsctl-integration-tests /usr/bin/cfsctl-integration-tests
12 changes: 9 additions & 3 deletions Justfile
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,13 @@ fmt:
# Run all checks (clippy + fmt + test)
check: clippy fmt-check test

COMPOSEFS_TEST_IMAGE := "localhost/composefs-rs-test:latest"
# Base image for test container builds.
# Override to test on different distros:
# just base_image=ghcr.io/bootcrew/debian-bootc:latest integration-container
base_image := env("COMPOSEFS_BASE_IMAGE", "quay.io/centos-bootc/centos-bootc:stream10")

# Derive test image name from base_image
_test_image := if base_image =~ "debian" { "localhost/composefs-rs-test-debian:latest" } else { "localhost/composefs-rs-test:latest" }

# Run integration tests (builds cfsctl first); pass extra args to the harness
test-integration *ARGS: build
Expand All @@ -43,11 +49,11 @@ integration-unprivileged: build

# Build the test container image for VM-based integration tests
integration-container-build:
podman build -t {{COMPOSEFS_TEST_IMAGE}} -f Containerfile .
podman build --build-arg base_image={{base_image}} -t {{_test_image}} .

# Run all integration tests; privileged tests dispatch to a bcvk VM
integration-container: build integration-container-build
COMPOSEFS_TEST_IMAGE={{COMPOSEFS_TEST_IMAGE}} \
COMPOSEFS_TEST_IMAGE={{_test_image}} \
CFSCTL_PATH=$(pwd)/target/debug/cfsctl \
cargo run -p integration-tests

Expand Down
33 changes: 33 additions & 0 deletions contrib/packaging/install-build-deps.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#!/bin/bash
# Install build-time dependencies for composefs-rs.
#
# This script detects the OS via /etc/os-release and installs the
# appropriate compiler toolchain and development libraries needed to
# build cfsctl and the integration test binary.
set -euo pipefail

# shellcheck source=lib.sh
. "$(dirname "$0")/lib.sh"

case "${ID}" in
centos|fedora|rhel)
pkg_install \
rust cargo \
openssl-devel \
gcc
;;
debian|ubuntu)
pkg_install \
rustc cargo \
libssl-dev zlib1g-dev pkg-config \
gcc libc6-dev

# /var/roothome is needed because /root is an OSTree symlink to
# it, and cargo/rustup need a writable home directory.
mkdir -p /var/roothome
;;
*)
echo "Unsupported distro: ${ID}" >&2
exit 1
;;
esac
50 changes: 50 additions & 0 deletions contrib/packaging/install-test-deps.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#!/bin/bash
# Install runtime / test dependencies for composefs-rs integration tests.
#
# This runs in the final bootable image and installs everything needed
# for `cfsctl-integration-tests` to run, including SSH and networking
# configuration for bcvk VM-based testing.
set -euo pipefail

# shellcheck source=lib.sh
. "$(dirname "$0")/lib.sh"

case "${ID}" in
centos|fedora|rhel)
pkg_install composefs openssl
;;
debian|ubuntu)
pkg_install \
openssl e2fsprogs bubblewrap openssh-server

# OSTree symlink targets — /root, /home, /srv, etc. are symlinks
# into /var on OSTree systems, so the target directories must exist.
mkdir -p /var/roothome /var/home /var/srv /var/opt /var/mnt /var/local

# Enable systemd-networkd with DHCP so that bcvk VMs get
# network connectivity automatically.
mkdir -p /etc/systemd/network
printf '[Match]\nName=en*\n\n[Network]\nDHCP=yes\n' \
> /etc/systemd/network/80-vm-dhcp.network
systemctl enable systemd-networkd

# Configure sshd for bcvk — allow root login with keys and
# relax StrictModes (the OSTree symlink layout confuses the
# ownership checks otherwise).
mkdir -p /etc/ssh/sshd_config.d
printf 'PermitRootLogin prohibit-password\nStrictModes no\n' \
> /etc/ssh/sshd_config.d/99-bcvk.conf

# Regenerate initramfs with the systemd-creds module so that
# bcvk can import credentials into the VM at boot.
for kdir in /usr/lib/modules/*/; do
KVER=$(basename "${kdir}")
dracut --force --add "systemd-creds" \
"/usr/lib/modules/${KVER}/initramfs.img" "${KVER}"
done
;;
*)
echo "Unsupported distro: ${ID}" >&2
exit 1
;;
esac
46 changes: 46 additions & 0 deletions contrib/packaging/lib.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#!/bin/bash
# Shared helpers for composefs-rs packaging scripts.
#
# Sources /etc/os-release and provides distro-agnostic functions for
# bootstrapping APT on debian-bootc images and installing packages.

# shellcheck source=/dev/null
. /etc/os-release
export ID

# debian_apt_init — bootstrap the /var directory structure that APT and
# dpkg need to function. debian-bootc images use OSTree's /var as a
# mutable state partition, so it starts completely empty. This is
# idempotent and safe to call multiple times.
debian_apt_init() {
mkdir -p /var/lib/apt/lists/partial \
/var/lib/dpkg/info /var/lib/dpkg/updates /var/lib/dpkg/triggers \
/var/cache/apt/archives/partial \
/var/log /run/lock
touch /var/lib/dpkg/status /var/lib/dpkg/available
}

# pkg_install PACKAGE... — install packages using the system package
# manager. On Debian/Ubuntu this handles the full APT bootstrap cycle;
# on Fedora/CentOS/RHEL it uses dnf.
#
# APT::Sandbox::User=root works around setgroups(2) failures that happen
# inside rootless podman builds where the process cannot change groups.
pkg_install() {
case "${ID}" in
centos|fedora|rhel)
dnf install -y "$@"
dnf clean all
;;
debian|ubuntu)
debian_apt_init
apt-get -o APT::Sandbox::User=root update
apt-get -o APT::Sandbox::User=root install -y --no-install-recommends "$@"
rm -rf /var/lib/apt/lists/*
;;
*)
echo "Unsupported distro: ${ID}" >&2
return 1
;;
esac
}
Loading