Files
boco/example/test.sh
T
marvin de59e84d73
CI / build (pull_request) Successful in 13s
Respect USER directive from OCI image config
Add support for the Dockerfile USER directive so that the container's
CMD/ENTRYPOINT runs as the configured user instead of root.

Changes:
- inject.rs: Add user field to Config struct, write /slim/user at
  build time
- build.rs: Pass config.user through to inject()
- slim-init.sh: Read /slim/user and drop privileges via su before
  executing the command. Numeric uids are resolved to usernames via
  /etc/passwd (BusyBox su does not accept numeric args). When dropping
  privileges, run as a child (not exec) so PID 1 stays root and can
  poweroff after the command exits.
- test.sh: Add test_user verifying build-time CMD and --cmd override
  both run as the configured user

Closes #7
2026-09-10 00:00:42 +02:00

214 lines
6.5 KiB
Bash
Executable File

#!/bin/bash
# Test script for slim - boots containers and verifies CMD inference/override.
# Requires: podman, qemu-system-x86_64, KVM, curl, and a kernel at
# $XDG_DATA_HOME/slim-rs/registry/vmlinuz.
set -u
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
TARGET_DIR="${CARGO_TARGET_DIR:-$SCRIPT_DIR/../target}"
SLIM_BIN="$TARGET_DIR/debug/slim"
TIMEOUT=120
pass=0
fail=0
report() {
if [ "$1" = "pass" ]; then
echo " PASS: $2"
pass=$((pass + 1))
else
echo " FAIL: $2"
fail=$((fail + 1))
fi
}
check_output() {
output="$1"
marker="$2"
label="$3"
if echo "$output" | grep -q "$marker"; then
report pass "$label"
else
report fail "$label (expected marker: $marker)"
fi
}
cleanup() {
"$SLIM_BIN" image rm "$1" >/dev/null 2>&1 || true
podman image rm "$2" >/dev/null 2>&1 || true
}
test_distro() {
distro="$1"
from="$2"
extra_setup="$3"
echo "=== Testing $distro ==="
work="$(mktemp -d)"
# === Test 1: CMD-inferred ===
echo "-- Test 1: CMD-inferred"
cat > "$work/Containerfile.infer" <<EOF
FROM $from
$extra_setup
CMD ["/bin/sh", "-c", "echo CMD_INFERRED_OK; wget -q -O /dev/null http://1.1.1.1 2>/dev/null && echo CONN_OK; wget -q -O /dev/null http://example.org 2>/dev/null && echo DNS_OK; poweroff -f"]
EOF
img="slim-test-$distro-infer"
if podman build -t "$img" -f "$work/Containerfile.infer" >/dev/null 2>&1; then
"$SLIM_BIN" build qcow2 "$img" >/dev/null 2>&1
output=$(timeout "$TIMEOUT" "$SLIM_BIN" run "$img" 2>&1 || true)
check_output "$output" "CMD_INFERRED_OK" "$distro CMD-inferred"
check_output "$output" "CONN_OK" "$distro connect to 1.1.1.1"
check_output "$output" "DNS_OK" "$distro DNS lookup"
else
report fail "$distro CMD-inferred (podman build failed)"
fi
cleanup "$img" "$img"
# === Test 2: slim run --cmd override ===
echo "-- Test 2: slim run --cmd override"
cat > "$work/Containerfile.run" <<EOF
FROM $from
$extra_setup
CMD ["/bin/sh", "-c", "echo SHOULD_NOT_APPEAR; poweroff -f"]
EOF
img="slim-test-$distro-run"
if podman build -t "$img" -f "$work/Containerfile.run" >/dev/null 2>&1; then
"$SLIM_BIN" build qcow2 "$img" >/dev/null 2>&1
output=$(timeout "$TIMEOUT" "$SLIM_BIN" run "$img" --cmd 'echo RUN_OVERRIDE_OK; poweroff -f' 2>&1 || true)
check_output "$output" "RUN_OVERRIDE_OK" "$distro run --cmd override"
else
report fail "$distro run --cmd override (podman build failed)"
fi
cleanup "$img" "$img"
# === Test 3: slim build --cmd override ===
echo "-- Test 3: slim build --cmd override"
cat > "$work/Containerfile.build" <<EOF
FROM $from
$extra_setup
CMD ["/bin/sh", "-c", "echo SHOULD_NOT_APPEAR; poweroff -f"]
EOF
img="slim-test-$distro-build"
if podman build -t "$img" -f "$work/Containerfile.build" >/dev/null 2>&1; then
"$SLIM_BIN" build qcow2 "$img" --cmd 'echo BUILD_OVERRIDE_OK; poweroff -f' >/dev/null 2>&1
output=$(timeout "$TIMEOUT" "$SLIM_BIN" run "$img" 2>&1 || true)
check_output "$output" "BUILD_OVERRIDE_OK" "$distro build --cmd override"
else
report fail "$distro build --cmd override (podman build failed)"
fi
cleanup "$img" "$img"
rm -rf "$work"
}
test_user() {
echo "=== Testing USER directive ==="
work="$(mktemp -d)"
img="slim-test-user"
cat > "$work/Containerfile" <<'EOF'
FROM alpine:latest
RUN adduser -D -u 1500 testuser
USER testuser
CMD ["/bin/sh", "-c", "echo USER_BUILD_OK:$(id -u):$(whoami); poweroff -f"]
EOF
echo "-- Building container image with USER directive..."
if ! podman build --network=none -t "$img" -f "$work/Containerfile" >/dev/null 2>&1; then
report fail "USER directive (podman build failed)"
rm -rf "$work"
return
fi
echo "-- Test 1: build-time CMD runs as USER"
"$SLIM_BIN" build qcow2 "$img" >/dev/null 2>&1
output=$(timeout "$TIMEOUT" "$SLIM_BIN" run "$img" 2>&1 || true)
check_output "$output" "USER_BUILD_OK:1500:testuser" "USER build-time CMD runs as testuser"
echo "-- Test 2: run --cmd override runs as USER"
output=$(timeout "$TIMEOUT" "$SLIM_BIN" run "$img" --cmd 'echo USER_RUN_OK:$(id -u):$(whoami); poweroff -f' 2>&1 || true)
check_output "$output" "USER_RUN_OK:1500:testuser" "USER run --cmd override runs as testuser"
cleanup "$img" "$img"
rm -rf "$work"
}
test_service() {
echo "=== Testing nextcloud service ==="
img="slim-test-nextcloud"
host_port=18080
work="$(mktemp -d)"
cat > "$work/Containerfile" <<'EOF'
FROM docker.io/library/nextcloud:32-apache
RUN apt-get update && apt-get install -y --no-install-recommends iproute2 && rm -rf /var/lib/apt/lists/*
EOF
echo "-- Building nextcloud container image..."
if ! podman build -t "$img" -f "$work/Containerfile" >/dev/null 2>&1; then
report fail "nextcloud service (podman build failed)"
rm -rf "$work"
return
fi
echo "-- Building slim VM..."
if ! "$SLIM_BIN" build qcow2 "$img" >/dev/null 2>&1; then
report fail "nextcloud service (slim build failed)"
cleanup "$img" "$img"
rm -rf "$work"
return
fi
echo "-- Booting VM with port forward (host :${host_port} -> guest :80)..."
setsid timeout 300 "$SLIM_BIN" run "$img" \
--forward "tcp:0.0.0.0:${host_port}-:80" \
--memory 2048M >/dev/null 2>&1 &
vm_pid=$!
echo "-- Waiting for Nextcloud to start..."
up=0
for _ in $(seq 1 60); do
if curl -s -o /dev/null -m 2 "http://localhost:${host_port}/" 2>/dev/null; then
up=1
break
fi
sleep 3
done
if [ "$up" = "1" ]; then
response=$(curl -s -L -m 10 "http://localhost:${host_port}/" 2>/dev/null || true)
if echo "$response" | grep -qi "nextcloud"; then
report pass "nextcloud service (port forward + content)"
else
report fail "nextcloud service (port reachable but no 'nextcloud' in response)"
fi
else
report fail "nextcloud service (port not reachable within timeout)"
fi
pkill -f "qemu-system-x86_64.*$img" 2>/dev/null || true
kill "$vm_pid" 2>/dev/null || true
wait "$vm_pid" 2>/dev/null || true
cleanup "$img" "$img"
rm -rf "$work"
}
echo "Building slim..."
cargo build 2>&1
test_distro "alpine" "alpine:latest" ""
test_distro "archlinux" "archlinux:latest" "RUN pacman -Sy --noconfirm iproute2 wget; pacman -Sc --noconfirm"
test_user
test_service
echo ""
echo "=== Results: $pass passed, $fail failed ==="
[ "$fail" -eq 0 ]