Gunnar

nordisk/heimdall

scripts/ci.sh

#!/bin/sh
# SPDX-License-Identifier: AGPL-3.0-only
# Heimdall CI. Heimdall is a defensive sandbox; this script builds and tests
# only Heimdall itself. Run it inside the toolchain container, from the repo
# root, e.g.:
#   podman run --rm -v "$PWD":/src -w /src localhost/nordisk-cargo-toolchain:<tag> scripts/ci.sh
# Steps: fmt, clippy -D warnings, tests, cargo deny (when deny.toml and
# cargo-deny are both present), fuzz smoke runs (when cargo-fuzz and a nightly
# toolchain are present; HEIMDALL_CI_FUZZ_RUNS sets the run count, 0 skips).
set -eu
cd "$(dirname "$0")/.."

step() { printf '\n== %s\n' "$*"; }

step "cargo fmt --check"
cargo fmt --all -- --check

step "cargo clippy -D warnings"
cargo clippy --workspace --all-targets --locked -- -D warnings

step "cargo test"
cargo test --workspace --locked

# heimdall-plain's shim links libseccomp (feature `youki`, off by default).
if pkg-config --exists libseccomp 2>/dev/null; then
  step "heimdall-plain --features youki: clippy + build the shim"
  cargo clippy -p nordisk-heimdall-plain --features youki --all-targets --locked -- -D warnings
  cargo build -p nordisk-heimdall-plain --features youki --bins --locked
else
  echo "libseccomp-dev not installed: heimdall-plain's youki shim not built" >&2
fi
echo "heimdall-plain container tests: scripts/plain-tests.sh (needs privileges)"

# The wasm guests are their own workspaces (built for wasm32, not host members).
for g in guests/*/Cargo.toml; do
  [ -f "$g" ] || continue
  d=$(dirname "$g")
  step "$d: fmt, clippy, tests (incl. the guest in the real wasm host), wasm32 build"
  (cd "$d" && cargo fmt -- --check \
    && cargo clippy --all-targets --release --locked -- -D warnings \
    && cargo test --release --locked \
    && cargo build --release --lib --locked --target wasm32-unknown-unknown)
done

if [ -f deny.toml ]; then
  if cargo deny --version >/dev/null 2>&1; then
    step "cargo deny check"
    cargo deny check
  else
    echo "deny.toml present but cargo-deny is not installed: skipped" >&2
  fi
fi

runs=${HEIMDALL_CI_FUZZ_RUNS:-2000}
if [ -d fuzz ] && [ "$runs" -gt 0 ]; then
  if cargo fuzz --version >/dev/null 2>&1 && rustup run nightly rustc --version >/dev/null 2>&1; then
    for t in $(cargo +nightly fuzz list --fuzz-dir fuzz); do
      step "cargo fuzz run $t ($runs runs)"
      # The checked-in seeds start the corpus; new finds stay in the
      # ignored fuzz/corpus, never in fuzz/seeds.
      mkdir -p "fuzz/corpus/$t"
      [ -d "fuzz/seeds/$t" ] && cp -n "fuzz/seeds/$t"/* "fuzz/corpus/$t"/ 2>/dev/null || true
      cargo +nightly fuzz run --fuzz-dir fuzz "$t" -- -runs="$runs" -max_len=65536
    done
  else
    step "fuzz targets: build check only (no cargo-fuzz or nightly)"
    cargo check --manifest-path fuzz/Cargo.toml --bins
  fi
fi

step "CI green"