#!/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 pipefailcd "$(dirname "$0")/.."ROOT=$PWDexport 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 EXITfree_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 2fiecho "== toolchain matches what the locked dependencies need"cargo metadata --locked --format-version 1 | python3 -I -c 'import json, re, syschannel = 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.shecho "== 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" || truerm -f -- "$CARGO_TARGET_DIR.js-tests.log"echo "== positive controls"; scripts/positive-controls.shguarded() { # 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-contractecho "== wasm type-check (contract, test token)"guarded cargo check --locked -j 2 --target wasm32-unknown-unknown -p duly-contract -p duly-mock-usdcecho "check: PASSED"