#!/usr/bin/env bash # Pre-commit / pre-push gate. Commit or push only after this exits 0. # check.sh toolchain check, secret scan, JS tests, positive controls, # contract unit tests, wasm type-check # The release wasm build (cargo near build) is not part of this gate. set -euo pipefail cd "$(dirname "$0")/.." ROOT=$PWD export CARGO_TARGET_DIR="${CARGO_TARGET_DIR:-$ROOT/../tmp/target}" # Local builds use the toolchain already installed; versions are compared below. export RUSTUP_TOOLCHAIN="${RUSTUP_TOOLCHAIN:-1.99.0}" MAX_TARGET_MB="${MAX_TARGET_MB:-2500}" MIN_FREE_GB="${MIN_FREE_GB:-3}" # Always remove the build directory, including when a build is stopped or fails. cleanup() { [ "${KEEP_TARGET:-}" = "1" ] || rm -rf -- "$CARGO_TARGET_DIR"; } trap cleanup EXIT free_gb() { df --output=avail -BG / | tail -1 | tr -dc 0-9; } if [ "$(free_gb)" -lt "$MIN_FREE_GB" ]; then echo "check: only $(free_gb) GB free, need $MIN_FREE_GB. Not building."; exit 2 fi echo "== toolchain matches what the locked dependencies need" cargo metadata --locked --format-version 1 | python3 -I -c ' import json, re, sys channel = re.search(r"channel = \"([0-9.]+)\"", open("rust-toolchain.toml").read()).group(1) ver = lambda s: tuple(int(x) for x in s.split("."))[:2] need = [(p["rust_version"], p["name"]) for p in json.load(sys.stdin)["packages"] if p.get("rust_version")] top = max(need, key=lambda x: ver(x[0])) print(f"toolchain {channel}, highest requirement {top[0]} ({top[1]})") sys.exit(0 if ver(top[0]) <= ver(channel) else 1)' cfg=$(sed -n 's/^channel = "\(.*\)"$/\1/p' rust-toolchain.toml); [ -n "$cfg" ] || { echo "check: CI cannot read the channel"; exit 1; } echo "== secret scan"; scripts/secret-scan.sh echo "== js tests" node --test test/*.test.mjs >"$CARGO_TARGET_DIR.js-tests.log" 2>&1 || { tail -40 "$CARGO_TARGET_DIR.js-tests.log"; exit 1; } grep -E '^# (tests|pass|fail) ' "$CARGO_TARGET_DIR.js-tests.log" || true rm -f -- "$CARGO_TARGET_DIR.js-tests.log" echo "== positive controls"; scripts/positive-controls.sh guarded() { # Stop a build that outgrows the size cap or eats the shared disk. "$@" & local pid=$! ( while kill -0 "$pid" 2>/dev/null; do sleep 15 mb=$(du -sm "$CARGO_TARGET_DIR" 2>/dev/null | cut -f1 || echo 0) if [ "${mb:-0}" -gt "$MAX_TARGET_MB" ] || [ "$(free_gb)" -lt 2 ]; then echo "check: stopping build (target ${mb} MB, $(free_gb) GB free)"; kill "$pid" 2>/dev/null; exit fi done ) & local dog=$! local rc=0; wait "$pid" || rc=$? kill "$dog" 2>/dev/null || true return "$rc" } echo "== contract unit tests" guarded cargo test --locked -j 3 -p duly-contract echo "== wasm type-check (contract, test token)" guarded cargo check --locked -j 2 --target wasm32-unknown-unknown -p duly-contract -p duly-mock-usdc echo "check: PASSED"