Skip to content
Draft
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
375 changes: 375 additions & 0 deletions .github/workflows/gnu-smack-tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,375 @@
name: GNU SMACK tests (redpesk)

Check failure on line 1 in .github/workflows/gnu-smack-tests.yml

View workflow job for this annotation

GitHub Actions / Style/spelling (ubuntu-latest, feat_os_unix)

ERROR: `cspell`: Unknown word 'redpesk' (file:'.github/workflows/gnu-smack-tests.yml', line:1)

on:
push:
branches: [ main, master ]
pull_request:
branches: [ main, master ]

# End the current execution if there is a new changeset in the PR.
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}

jobs:
gnu-smack-tests:
runs-on: ubuntu-latest
timeout-minutes: 120

steps:
- name: Checkout code (uutils)
uses: actions/checkout@v6
with:
path: 'uutils'
persist-credentials: false
- name: Extract GNU version from build-gnu.sh
id: gnu-version-selinux
run: |
GNU_VERSION=$(grep '^release_tag_GNU=' uutils/util/build-gnu.sh | cut -d'"' -f2)
if [ -z "$GNU_VERSION" ]; then
echo "Error: Failed to extract GNU version from build-gnu.sh"
exit 1
fi
echo "REPO_GNU_REF=${GNU_VERSION}" >> $GITHUB_ENV
echo "Extracted GNU version: ${GNU_VERSION}"

- name: Checkout code (GNU coreutils)
uses: actions/checkout@v6
with:
repository: 'coreutils/coreutils'
path: 'gnu'
ref: ${{ env.REPO_GNU_REF }}
submodules: false
persist-credentials: false
- name: Override submodule URL and initialize submodules
# Use github instead of upstream git server
run: |
git submodule sync --recursive
git config submodule.gnulib.url https://github.com/coreutils/gnulib.git

Check failure on line 48 in .github/workflows/gnu-smack-tests.yml

View workflow job for this annotation

GitHub Actions / Style/spelling (ubuntu-latest, feat_os_unix)

ERROR: `cspell`: Unknown word 'gnulib' (file:'.github/workflows/gnu-smack-tests.yml', line:48)
git submodule update --init --recursive --depth 1
working-directory: gnu


#### Build environment setup
- name: Install dependencies
shell: bash
run: |
## Install dependencies
sudo apt-get update
## Check that build-gnu.sh works on the non SELinux system by installing libselinux only on lima
sudo apt-get install -y autopoint gperf gdb python3-pyinotify valgrind libexpect-perl libacl1-dev libattr1-dev libcap-dev attr quilt

Check failure on line 60 in .github/workflows/gnu-smack-tests.yml

View workflow job for this annotation

GitHub Actions / Style/spelling (ubuntu-latest, feat_os_unix)

ERROR: `cspell`: Unknown word 'libcap' (file:'.github/workflows/gnu-smack-tests.yml', line:60)

Check failure on line 60 in .github/workflows/gnu-smack-tests.yml

View workflow job for this annotation

GitHub Actions / Style/spelling (ubuntu-latest, feat_os_unix)

ERROR: `cspell`: Unknown word 'libattr' (file:'.github/workflows/gnu-smack-tests.yml', line:60)

Check failure on line 60 in .github/workflows/gnu-smack-tests.yml

View workflow job for this annotation

GitHub Actions / Style/spelling (ubuntu-latest, feat_os_unix)

ERROR: `cspell`: Unknown word 'libexpect' (file:'.github/workflows/gnu-smack-tests.yml', line:60)

Check failure on line 60 in .github/workflows/gnu-smack-tests.yml

View workflow job for this annotation

GitHub Actions / Style/spelling (ubuntu-latest, feat_os_unix)

ERROR: `cspell`: Unknown word 'pyinotify' (file:'.github/workflows/gnu-smack-tests.yml', line:60)

Check failure on line 60 in .github/workflows/gnu-smack-tests.yml

View workflow job for this annotation

GitHub Actions / Style/spelling (ubuntu-latest, feat_os_unix)

ERROR: `cspell`: Unknown word 'gperf' (file:'.github/workflows/gnu-smack-tests.yml', line:60)

Check failure on line 60 in .github/workflows/gnu-smack-tests.yml

View workflow job for this annotation

GitHub Actions / Style/spelling (ubuntu-latest, feat_os_unix)

ERROR: `cspell`: Unknown word 'autopoint' (file:'.github/workflows/gnu-smack-tests.yml', line:60)

- name: Install host dependencies (GNU harness + QEMU + OVMF + sshpass)

Check failure on line 62 in .github/workflows/gnu-smack-tests.yml

View workflow job for this annotation

GitHub Actions / Style/spelling (ubuntu-latest, feat_os_unix)

ERROR: `cspell`: Unknown word 'sshpass' (file:'.github/workflows/gnu-smack-tests.yml', line:62)

Check failure on line 62 in .github/workflows/gnu-smack-tests.yml

View workflow job for this annotation

GitHub Actions / Style/spelling (ubuntu-latest, feat_os_unix)

ERROR: `cspell`: Unknown word 'OVMF' (file:'.github/workflows/gnu-smack-tests.yml', line:62)
run: |
set -euo pipefail
sudo apt-get update
sudo apt-get install -y \
build-essential \
autoconf automake libtool \
gettext texinfo \
gawk bison \
pkg-config \
qemu-system-x86 \
ovmf \
sshpass

- name: Download redpesk SMACK minimal x86_64 image
working-directory: /tmp
run: |
set -euo pipefail

mkdir -p redpeskimage
cd redpeskimage

# Download a specific SMACK minimal x86_64 image (corn-3.0-update LTS)
# Directory listing shows image.raw.tar.xz and its checksum here:
# https://download.redpesk.bzh/redpesk-lts/corn-3.0-update/images/smack/minimal/x86_64/generic/
wget -q \
https://download.redpesk.bzh/redpesk-lts/corn-3.0-update/images/smack/minimal/x86_64/generic/redpesk-lts-corn-3.0-update-smack-minimal-x86_64-generic-2025_11_21_1557.tar.xz \
https://download.redpesk.bzh/redpesk-lts/corn-3.0-update/images/smack/minimal/x86_64/generic/redpesk-lts-corn-3.0-update-smack-minimal-x86_64-generic-2025_11_21_1557.tar.xz.sha256

# Verify integrity
sha256sum -c redpesk-lts-corn-3.0-update-smack-minimal-x86_64-generic-2025_11_21_1557.tar.xz.sha256

# Extract; this drops a disk image, typically named Redpesk-OS.img
tar xJf redpesk-lts-corn-3.0-update-smack-minimal-x86_64-generic-2025_11_21_1557.tar.xz

echo "Contents of redpeskimage:"
ls -lh

- name: Launch redpesk SMACK QEMU guest
working-directory: /tmp/redpeskimage
run: |
set -euo pipefail

DISK_IMAGE=$(ls Redpesk-OS*.img 2>/dev/null || ls *.img)
echo "Using disk image: $DISK_IMAGE"

OVMF="/usr/share/qemu/OVMF.fd"
PORT_SSH=3333

echo "Starting QEMU in TCG mode (no KVM)..."

qemu-system-x86_64 \
-machine accel=tcg \
-drive file="$DISK_IMAGE",if=virtio,format=raw \
-m 2048 \
-smp 2 \
-cpu Skylake-Client-v4 \
-vga virtio \
-device virtio-rng-pci \
-serial mon:stdio \
-serial null \
-net nic \
-net user,hostfwd=tcp::$PORT_SSH-:22 \
-bios "$OVMF" \
-nographic \
> /tmp/qemu-smack.log 2>&1 &

echo $! > /tmp/qemu-smack.pid
echo "QEMU started with PID $(cat /tmp/qemu-smack.pid)"

- name: Build GNU harness on host (uutils + GNU)
run: |
set -euo pipefail

# Detect repo roots on host
if [ -d "$GITHUB_WORKSPACE/uutils/util" ]; then
UU_ROOT="$GITHUB_WORKSPACE/uutils"
else
echo "Could not find uutils repo root."
ls -R "$GITHUB_WORKSPACE"
exit 1
fi

if [ -d "$GITHUB_WORKSPACE/gnu" ]; then
GNU_ROOT="$GITHUB_WORKSPACE/gnu"
else
echo "Could not find gnu coreutils directory."
ls -R "$GITHUB_WORKSPACE"
exit 1
fi

echo "Host UU_ROOT=${UU_ROOT}"
echo "Host GNU_ROOT=${GNU_ROOT}"

export path_UUTILS="$UU_ROOT"
export path_GNU="$GNU_ROOT"

# Build uutils + GNU harness once on the host
# UU_MAKE_PROFILE selects Rust profile; keep it small but realistic
UU_MAKE_PROFILE=release-small \
bash "$UU_ROOT/util/build-gnu.sh"
rm -rf "$UU_ROOT/.git
rm -rf "$UU_ROOT/target"/{debug,release}/incremental
rm -rf "$UU_ROOT/target"/{debug,release}/build
rm -rf "$UU_ROOT/target"/{debug,release}/.fingerprint
rm -rf "$UU_ROOT/target"/{debug,release}/deps
find "$UU_ROOT/target" -type f -name '*.rlib' -delete
cd "$BUILD_DIR"

# List of binaries needed for the SMACK tests
KEEP_BINS="
coreutils
id
mkdir
mknod
mkfifo
ls
cut
grep
cat
env
rm
chmod
"

# Normalize to one-line, space-separated
KEEP_BINS_ONE_LINE="$(echo $KEEP_BINS)"

for f in *; do
# Skip non-regular files (dirs, symlinks, etc.)
[ -f "$f" ] || continue

case " $KEEP_BINS_ONE_LINE " in
*" $f "*)
# keep
;;
*)
# delete everything else
rm -f -- "$f"
;;
esac
done



- name: Wait for SSH in guest
run: |
set -euo pipefail

PORT_SSH=3333
SSH_BASE="sshpass -p root ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -p $PORT_SSH root@localhost"

if [ ! -f /tmp/qemu-smack.pid ]; then
echo "ERROR: /tmp/qemu-smack.pid not found – QEMU did not start?"
exit 1
fi

QEMU_PID=$(cat /tmp/qemu-smack.pid)
echo "Waiting for SSH to become available in the redpesk guest (PID $QEMU_PID)..."

for i in $(seq 1 60); do
# If QEMU died, show why and bail out
if ! kill -0 "$QEMU_PID" 2>/dev/null; then
echo "ERROR: QEMU process $QEMU_PID is no longer running."
if [ -f /tmp/qemu-smack.log ]; then
echo "===== QEMU SMACK guest log (tail) ====="
tail -n 100 /tmp/qemu-smack.log || true
fi
exit 1
fi

if $SSH_BASE 'echo ready' >/dev/null 2>&1; then
echo "SSH is up."
exit 0
fi
# Inline QEMU log tail on each failed attempt
if [ -f /tmp/qemu-smack.log ]; then
echo "----- QEMU SMACK guest log tail (attempt $i) -----"
tail -n 80 /tmp/qemu-smack.log || true
echo "-----------------------------------------------"
fi


echo "SSH not ready yet (attempt $i)..."
sleep 5
done

echo "ERROR: SSH did not become ready in time."
if [ -f /tmp/qemu-smack.log ]; then
echo "===== QEMU SMACK guest log (tail) ====="
tail -n 100 /tmp/qemu-smack.log || true
fi

kill "$QEMU_PID" || true
exit 1


- name: Copy repo with built harness into guest
run: |
set -euo pipefail

PORT_SSH=3333
SSH_BASE="sshpass -p root ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -p $PORT_SSH root@localhost"

echo "GITHUB_WORKSPACE=$GITHUB_WORKSPACE"
echo "Host layout:"
ls -1 "$GITHUB_WORKSPACE"

if [ -d "$GITHUB_WORKSPACE/util" ]; then
UU_ROOT="$GITHUB_WORKSPACE"
elif [ -d "$GITHUB_WORKSPACE/uutils/util" ]; then
UU_ROOT="$GITHUB_WORKSPACE/uutils"
else
echo "Could not find uutils repo root (no util/)."
ls -R "$GITHUB_WORKSPACE"
exit 1
fi

if [ -d "$GITHUB_WORKSPACE/gnu" ]; then
GNU_ROOT="$GITHUB_WORKSPACE/gnu"
elif [ -d "$UU_ROOT/../gnu" ]; then
GNU_ROOT="$(readlink -fm "$UU_ROOT/../gnu")"
else
echo "Could not find gnu coreutils directory."
ls -R "$GITHUB_WORKSPACE"
exit 1
fi

echo "Host UU_ROOT=$UU_ROOT"
echo "Host GNU_ROOT=$GNU_ROOT"

echo "Copying uutils into guest at /root/uutils ..."
tar -C "$UU_ROOT" -cz . \
| $SSH_BASE 'rm -rf /root/uutils && mkdir -p /root/uutils && cd /root/uutils && tar xz'

echo "Copying GNU coreutils into guest at /root/gnu ..."
tar -C "$GNU_ROOT" -cz . \
| $SSH_BASE 'rm -rf /root/gnu && mkdir -p /root/gnu && cd /root/gnu && tar xz'


- name: Install make inside SMACK guest
run: |
set -euo pipefail

PORT_SSH=3333
SSH_BASE="sshpass -p root ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -p $PORT_SSH root@localhost"

echo "Installing make inside guest (needed for util/run-gnu-test.sh)..."
# redpesk is rpm-based and uses dnf
$SSH_BASE 'command -v dnf || { echo "dnf not found in guest"; exit 1; }'
$SSH_BASE 'dnf -y install make'

echo "make in guest:"
$SSH_BASE 'command -v make && make --version | head -n1'

- name: Prepare GNU harness inside guest
run: |
set -euo pipefail

PORT_SSH=3333
SSH_BASE="sshpass -p root ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -p $PORT_SSH root@localhost"

# 1) Install build deps + curl inside redpesk
$SSH_BASE '
set -euo pipefail
dnf -y install \
gcc make autoconf automake libtool \
gettext texinfo \
gawk bison \
pkg-config \
git \
curl
'
- name: Run SMACK GNU tests inside guest
run: |
set -euo pipefail

PORT_SSH=3333
SSH_BASE="sshpass -p root ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -p $PORT_SSH root@localhost"

echo "Checking that SMACK is active in the guest..."
$SSH_BASE 'grep smackfs /proc/filesystems || (echo "smackfs not present"; exit 1)'

echo "Running SMACK-related GNU tests (mkdir + id)..."
set +e
$SSH_BASE '
set -e
cd /root/uutils
echo "In guest, PWD: $PWD"
ls util
bash util/run-gnu-test.sh \
tests/mkdir/smack-no-root.sh \
tests/mkdir/smack-root.sh \
tests/id/smack.sh
'
RC=$?
set -e
echo "SMACK GNU tests exit code: $RC"

echo "Shutting down QEMU..."
if [ -f /tmp/qemu-smack.pid ]; then
kill "$(cat /tmp/qemu-smack.pid)" || true
fi

exit $RC
- name: Dump QEMU log on failure
if: failure()
run: |
echo "===== QEMU SMACK guest log ====="
if [ -f /tmp/qemu-smack.log ]; then
sed -n '1,400p' /tmp/qemu-smack.log || true
else
echo "No QEMU log file found."
fi
Loading