Skip to content

ci(distro): add Rocky 10 package test + update to v0.75.0 artifacts #314

ci(distro): add Rocky 10 package test + update to v0.75.0 artifacts

ci(distro): add Rocky 10 package test + update to v0.75.0 artifacts #314

Workflow file for this run

name: Linux CI
on:
push:
branches: [main, 'sid/**']
paths:
- 'flake.nix'
- 'flake.lock'
- 'nix/**'
- 'vendor/**'
- 'cmuxd/**'
- 'cmux-linux/**'
- 'dist/linux/**'
- 'ghostty'
- '.github/workflows/linux-ci.yml'
pull_request:
branches: [main]
workflow_dispatch:
concurrency:
group: linux-ci-${{ github.ref }}
cancel-in-progress: true
jobs:
# ── Nix Flake: dev shell + checks ──────────────────────────────────
nix-flake:
name: Nix flake check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Strip non-version tags from ghostty
run: git -C ghostty tag -l 'xcframework-*' | xargs git -C ghostty tag -d 2>/dev/null || true
- uses: DeterminateSystems/nix-installer-action@main
with:
# relaxed sandbox allows __noChroot derivations (needed for
# libghostty: Zig build-time tools require /lib64 dynamic linker)
extra-conf: "sandbox = relaxed"
- uses: DeterminateSystems/magic-nix-cache-action@main
- name: Verify dev shell
run: |
nix develop --command bash -c '
echo "=== Dev Shell Verification ==="
echo "Zig: $(zig version)"
echo "pkg-config: $(pkg-config --version)"
echo "GTK4: $(pkg-config --modversion gtk4 2>/dev/null || echo "not available on CI runner")"
echo "Shell OK"
'
- name: Run headless flake checks (required)
run: |
nix build .#checks.x86_64-linux.basic-version-check --print-build-logs
nix build .#checks.x86_64-linux.cmux-linux-build-check --print-build-logs
nix build .#checks.x86_64-linux.gtk4-version-check --print-build-logs
- name: Run socket test suite check (best-effort)
continue-on-error: true
timeout-minutes: 45
run: nix build .#checks.x86_64-linux.socket-test-suite --print-build-logs
- name: Run graphical flake check (best-effort)
continue-on-error: true
timeout-minutes: 30
run: nix build .#checks.x86_64-linux.basic-window-check-gnome --print-build-logs
# ── Zig vendor libraries on Linux ──────────────────────────────────
zig-libs-linux:
name: Zig vendor libs (Linux)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Strip non-version tags from ghostty
run: git -C ghostty tag -l 'xcframework-*' | xargs git -C ghostty tag -d 2>/dev/null || true
- name: Install Zig
uses: mlugg/setup-zig@v2
with:
version: 0.15.2
use-cache: false
- name: Install Linux dependencies
run: |
sudo apt-get update
sudo apt-get install -y \
libsecret-1-dev libnotify-dev pkg-config \
libgtk-4-dev libadwaita-1-dev \
libwebkitgtk-6.0-dev \
libfreetype-dev libharfbuzz-dev libfontconfig-dev \
libpng-dev libonig-dev libgl-dev \
glslang-tools spirv-cross
- name: Build + test zig-ctap2
run: |
cd vendor/ctap2
zig build -Doptimize=ReleaseFast
zig build test 2>&1 || echo "Note: ctap2 tests may skip on Linux (USB HID is platform-specific)"
echo "libctap2.a: $(ls -lh zig-out/lib/libctap2.a)"
- name: Build + test zig-crypto
run: |
cd vendor/zig-crypto
zig build -Doptimize=ReleaseFast
zig build test
echo "libzig-crypto.a: $(ls -lh zig-out/lib/libzig-crypto.a)"
- name: Build + test zig-keychain
run: |
cd vendor/zig-keychain
zig build -Doptimize=ReleaseFast
zig build test
echo "libzig-keychain.a: $(ls -lh zig-out/lib/libzig-keychain.a)"
- name: Build cmuxd
run: |
if [ -d cmuxd ]; then
cd cmuxd
zig build -Doptimize=ReleaseFast
echo "cmuxd: $(ls -lh zig-out/bin/cmuxd)"
else
echo "cmuxd directory not found, skipping"
fi
- name: Build libghostty
run: |
cd ghostty
zig build -Dapp-runtime=none -Drenderer=opengl -Doptimize=ReleaseFast
echo "libghostty.a: $(ls -lh zig-out/lib/libghostty.a)"
echo "ghostty.h: $(ls -lh zig-out/include/ghostty.h)"
- name: Build cmux-linux
run: |
cd cmux-linux
zig build -Doptimize=ReleaseFast
echo "cmux: $(ls -lh zig-out/bin/cmux)"
- name: Test cmux-linux (config parser)
run: |
cd cmux-linux
zig build test
- name: Tier 0 — Validate desktop + metainfo files
run: |
sudo apt-get install -y desktop-file-utils appstream
echo "=== Desktop entry validation ==="
desktop-file-validate dist/linux/com.jesssullivan.cmux.desktop
echo "=== AppStream metainfo validation ==="
appstreamcli validate --no-net dist/linux/com.jesssullivan.cmux.metainfo.xml
echo "=== Icon format checks ==="
for icon in dist/linux/icons/*.png; do
info=$(file "$icon")
echo " $info"
echo "$info" | grep -q "PNG image data" || { echo "FAIL: $icon is not a valid PNG"; exit 1; }
done
echo "Tier 0 validation passed"
- name: Tier 1 — Static binary checks
run: |
BINARY="cmux-linux/zig-out/bin/cmux"
export LD_LIBRARY_PATH="$PWD/ghostty/zig-out/lib:${LD_LIBRARY_PATH:-}"
echo "=== ELF magic check ==="
file "$BINARY" | grep -q "ELF 64-bit" || { echo "FAIL: not a 64-bit ELF"; exit 1; }
echo "=== Executable bit ==="
[ -x "$BINARY" ] || { echo "FAIL: not executable"; exit 1; }
echo "=== Shared library dependencies ==="
ldd "$BINARY"
ldd "$BINARY" | grep -q "libgtk-4" || { echo "FAIL: libgtk-4 not linked"; exit 1; }
ldd "$BINARY" | grep -q "libadwaita" || { echo "FAIL: libadwaita not linked"; exit 1; }
echo "Static binary checks passed"
- name: Tier 1 — Headless smoke test (Xvfb)
continue-on-error: true
run: |
sudo apt-get install -y xvfb socat mesa-utils libgl1-mesa-dri
# Start virtual framebuffer
export DISPLAY=:99
Xvfb :99 -screen 0 800x600x24 &
XVFB_PID=$!
sleep 1
# Set up XDG runtime
export XDG_RUNTIME_DIR=/tmp/xdg-runtime-smoke
mkdir -p "$XDG_RUNTIME_DIR"
chmod 700 "$XDG_RUNTIME_DIR"
BINARY="cmux-linux/zig-out/bin/cmux"
# libghostty.so is in ghostty/zig-out/lib
export LD_LIBRARY_PATH="$PWD/ghostty/zig-out/lib:${LD_LIBRARY_PATH:-}"
# Force software OpenGL (Xvfb has no GPU)
# Ghostty requires GL 4.3; llvmpipe supports it but reports 3.3 by default
export LIBGL_ALWAYS_SOFTWARE=1
export MESA_GL_VERSION_OVERRIDE=4.6COMPAT
export MESA_GLSL_VERSION_OVERRIDE=460
echo "=== OpenGL info ==="
glxinfo 2>/dev/null | grep -E "OpenGL version|OpenGL renderer|direct rendering" || echo "glxinfo not available"
echo "=== Starting cmux-linux under Xvfb ==="
timeout 8 "$BINARY" 2>/tmp/cmux-smoke-stderr.log &
BINARY_PID=$!
# Wait for socket creation (up to 5 seconds)
SOCKET_FOUND=false
for i in $(seq 1 10); do
if [ -S "$XDG_RUNTIME_DIR/cmux.sock" ]; then
SOCKET_FOUND=true
echo "Socket created after ${i}x0.5s"
break
fi
sleep 0.5
done
if [ "$SOCKET_FOUND" = true ]; then
echo "=== Socket permissions ==="
ls -la "$XDG_RUNTIME_DIR/cmux.sock"
echo "=== JSON-RPC ping test ==="
RESPONSE=$(echo '{"id":1,"method":"system.ping","params":{}}' | \
socat -t2 - UNIX-CONNECT:"$XDG_RUNTIME_DIR/cmux.sock" 2>/dev/null || true)
echo "Response: $RESPONSE"
if echo "$RESPONSE" | grep -q "pong"; then
echo "Socket ping: PASS"
else
echo "Socket ping: SKIP (method may not be wired yet)"
fi
else
echo "Socket not created (expected — socket server may not be wired to GTK lifecycle yet)"
fi
echo "=== Clean shutdown test ==="
if kill -0 $BINARY_PID 2>/dev/null; then
kill -TERM $BINARY_PID 2>/dev/null || true
# Wait up to 3 seconds for clean exit
for i in $(seq 1 6); do
kill -0 $BINARY_PID 2>/dev/null || break
sleep 0.5
done
if kill -0 $BINARY_PID 2>/dev/null; then
echo "WARN: Process did not exit on SIGTERM, sending SIGKILL"
kill -9 $BINARY_PID 2>/dev/null || true
else
echo "Clean shutdown: PASS"
fi
else
echo "Process already exited before shutdown test"
# Don't call wait — the PID may belong to timeout wrapper
fi
# Show any stderr from the binary
if [ -f /tmp/cmux-smoke-stderr.log ]; then
echo "=== Binary stderr ==="
cat /tmp/cmux-smoke-stderr.log || true
fi
# Cleanup
kill -9 $XVFB_PID 2>/dev/null || true
rm -rf "$XDG_RUNTIME_DIR"
echo "Headless smoke test completed"
# ── Fedora 42 container: GTK4 4.18 ────────────────────────────────
fedora:
name: Fedora 42 (GTK4 4.18)
runs-on: ubuntu-latest
container: fedora:42
steps:
- name: Install git and dependencies
run: |
dnf install -y \
git \
gcc gcc-c++ \
pkg-config \
gtk4-devel \
libadwaita-devel \
webkitgtk6.0-devel \
libsecret-devel \
libnotify-devel \
wayland-devel \
wayland-protocols-devel \
freetype-devel harfbuzz-devel fontconfig-devel \
libpng-devel oniguruma-devel mesa-libGL-devel
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Strip non-version tags from ghostty
run: git -C ghostty tag -l 'xcframework-*' | xargs git -C ghostty tag -d 2>/dev/null || true
- name: Verify GTK4 version
run: |
GTK_VER=$(pkg-config --modversion gtk4)
echo "GTK4 version: $GTK_VER"
ADWAITA_VER=$(pkg-config --modversion libadwaita-1)
echo "libadwaita version: $ADWAITA_VER"
WEBKIT_VER=$(pkg-config --modversion webkitgtk-6.0)
echo "WebKitGTK version: $WEBKIT_VER"
- name: Install Zig
uses: mlugg/setup-zig@v2
with:
version: 0.15.2
use-cache: false
- name: Build zig-ctap2
run: |
cd vendor/ctap2
zig build -Doptimize=ReleaseFast
- name: Build zig-crypto
run: |
cd vendor/zig-crypto
zig build -Doptimize=ReleaseFast
- name: Build zig-keychain
run: |
cd vendor/zig-keychain
zig build -Doptimize=ReleaseFast
- name: Build libghostty
run: |
cd ghostty
zig build -Dapp-runtime=none -Drenderer=opengl -Doptimize=ReleaseFast
- name: Build cmux-linux (Fedora)
run: |
cd cmux-linux
zig build -Doptimize=ReleaseFast
- name: Tier 0 — Validate desktop + metainfo (Fedora)
run: |
dnf install -y desktop-file-utils appstream
desktop-file-validate dist/linux/com.jesssullivan.cmux.desktop
appstreamcli validate --no-net dist/linux/com.jesssullivan.cmux.metainfo.xml
echo "Tier 0 (Fedora) passed"
# ── Arch Linux container: bleeding edge ────────────────────────────
arch:
name: Arch Linux (bleeding edge)
runs-on: ubuntu-latest
container: archlinux:latest
steps:
- name: Install dependencies
run: |
pacman -Syu --noconfirm \
base-devel \
git \
pkg-config \
gtk4 \
libadwaita \
webkitgtk-6.0 \
libsecret \
libnotify \
wayland \
wayland-protocols \
freetype2 harfbuzz fontconfig \
libpng oniguruma mesa
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Strip non-version tags from ghostty
run: git -C ghostty tag -l 'xcframework-*' | xargs git -C ghostty tag -d 2>/dev/null || true
- name: Verify GTK4 version
run: |
GTK_VER=$(pkg-config --modversion gtk4)
echo "GTK4 version: $GTK_VER"
ADWAITA_VER=$(pkg-config --modversion libadwaita-1)
echo "libadwaita version: $ADWAITA_VER"
- name: Install Zig
uses: mlugg/setup-zig@v2
with:
version: 0.15.2
use-cache: false
- name: Build zig-ctap2
run: |
cd vendor/ctap2
zig build -Doptimize=ReleaseFast
- name: Build zig-crypto
run: |
cd vendor/zig-crypto
zig build -Doptimize=ReleaseFast
- name: Build zig-keychain
run: |
cd vendor/zig-keychain
zig build -Doptimize=ReleaseFast
- name: Build libghostty
run: |
cd ghostty
zig build -Dapp-runtime=none -Drenderer=opengl -Doptimize=ReleaseFast
- name: Build cmux-linux (Arch)
run: |
cd cmux-linux
zig build -Doptimize=ReleaseFast
- name: Tier 0 — Validate desktop + metainfo (Arch)
run: |
pacman -S --noconfirm desktop-file-utils appstream
desktop-file-validate dist/linux/com.jesssullivan.cmux.desktop
appstreamcli validate --no-net dist/linux/com.jesssullivan.cmux.metainfo.xml
echo "Tier 0 (Arch) passed"