#!/usr/bin/env bash # Launch the real desktop binary in an isolated X11 session, prove its window # renders, capture evidence, request a normal window close, and require a clean # process exit so SiteStandaloneApp::drop runs its bounded writer drain. set -euo pipefail binary=${1:-target/debug/nigig-site} evidence_dir=${2:-/tmp/nigig-site-ci} [[ -x "$binary" ]] || { echo "ERROR: runtime binary is not executable: $binary" >&2 exit 1 } for command in xvfb-run xdotool import identify timeout; do command -v "$command" >/dev/null || { echo "ERROR: required runtime-smoke tool is missing: $command" >&2 exit 1 } done mkdir -p "$evidence_dir" runtime_root=$(mktemp -d) cleanup() { rm -rf "$runtime_root" } trap cleanup EXIT mkdir -p "$runtime_root/home" "$runtime_root/data" "$runtime_root/cache" export HOME="$runtime_root/home" export XDG_DATA_HOME="$runtime_root/data" export XDG_CACHE_HOME="$runtime_root/cache" export NIGIG_SITE_RUNTIME_BINARY="$binary" export NIGIG_SITE_RUNTIME_ROOT="$runtime_root" export NIGIG_SITE_RUNTIME_EVIDENCE="$evidence_dir" timeout --signal=TERM --kill-after=5s 30s xvfb-run -a bash -c ' set -euo pipefail "$NIGIG_SITE_RUNTIME_BINARY" >"$NIGIG_SITE_RUNTIME_EVIDENCE/runtime-app.log" 2>&1 & pid=$! cleanup_child() { if [[ -n "${pid:-}" ]] && kill -0 "$pid" 2>/dev/null; then kill "$pid" 2>/dev/null || true wait "$pid" 2>/dev/null || true fi } trap cleanup_child EXIT window="" for _ in $(seq 1 200); do window=$(xdotool search --pid "$pid" --name "^nigig-site$" 2>/dev/null | head -n 1 || true) [[ -n "$window" ]] && break if ! kill -0 "$pid" 2>/dev/null; then cat "$NIGIG_SITE_RUNTIME_EVIDENCE/runtime-app.log" >&2 wait "$pid" exit 1 fi sleep 0.1 done [[ -n "$window" ]] || { echo "ERROR: nigig-site did not create its desktop window" >&2 cat "$NIGIG_SITE_RUNTIME_EVIDENCE/runtime-app.log" >&2 kill "$pid" 2>/dev/null || true exit 1 } [[ $(xdotool getwindowname "$window") == nigig-site ]] # Wait for the first GL present; finding a mapped-but-unpainted black window # is not runtime UI evidence. sleep 2 import -window "$window" "$NIGIG_SITE_RUNTIME_EVIDENCE/runtime-ui.png" identify "$NIGIG_SITE_RUNTIME_EVIDENCE/runtime-ui.png" \ >"$NIGIG_SITE_RUNTIME_EVIDENCE/runtime-ui-image.txt" mean=$(identify -format "%[fx:mean]" "$NIGIG_SITE_RUNTIME_EVIDENCE/runtime-ui.png") awk -v mean="$mean" "BEGIN { exit !(mean > 0.05) }" || { echo "ERROR: runtime window remained effectively black after first paint" >&2 exit 1 } # WM_DELETE_WINDOW follows the normal Makepad close path. A forced signal # would not prove the Rust Drop implementation and is therefore forbidden. xdotool windowclose "$window" for _ in $(seq 1 200); do ! kill -0 "$pid" 2>/dev/null && break sleep 0.1 done if kill -0 "$pid" 2>/dev/null; then echo "ERROR: nigig-site ignored a normal window-close request" >&2 kill "$pid" 2>/dev/null || true exit 1 fi wait "$pid" pid="" ' # An absent repository must stay absent: startup is open-only and setup is # security-review locked. Cache/shader output is outside XDG_DATA_HOME. if find "$runtime_root/data" -type f -print -quit | grep -q .; then echo "ERROR: runtime startup created repository data without setup consent" >&2 find "$runtime_root/data" -type f -print >&2 exit 1 fi if grep -Eiq 'panicked|fatal|segmentation fault|graceful persistence drain failed' \ "$evidence_dir/runtime-app.log"; then echo "ERROR: runtime log contains a fatal or shutdown failure" >&2 cat "$evidence_dir/runtime-app.log" >&2 exit 1 fi [[ -s "$evidence_dir/runtime-ui.png" ]] [[ -s "$evidence_dir/runtime-ui-image.txt" ]] echo "runtime smoke passed: isolated startup, rendered window, normal close, no repository creation"