#!/usr/bin/env bash
# SPDX-FileCopyrightText: 2026-present Xquik <support@xquik.com>
#
# SPDX-License-Identifier: Apache-2.0
#
# Fuzzes the response helpers for 180 seconds with Atheris and AddressSanitizer.
# Usage: scripts/fuzz
# Atheris needs Linux x86_64. Elsewhere, set XQUIK_FUZZ_HOST to an authorized
# Linux SSH runner, and the script copies the source there and runs on it.
set -euo pipefail
cd "$(dirname "$0")/.."

harness=".clusterfuzzlite/fuzz_response_helpers.py"

if [[ -n "${XQUIK_FUZZ_HOST:-}" ]]; then
  [[ "$XQUIK_FUZZ_HOST" =~ ^[a-zA-Z0-9][a-zA-Z0-9@._-]*$ ]] || {
    echo "Invalid SSH host. Set XQUIK_FUZZ_HOST to a host name or user@host." >&2
    exit 2
  }
  tar --exclude='__pycache__' -czf - src scripts/fuzz "$harness" |
    ssh -- "$XQUIK_FUZZ_HOST" 'set -eu; umask 077; work=$(mktemp -d); echo "Remote fuzz source is $work" >&2; tar -xzf - -C "$work"; cd "$work"; unset XQUIK_FUZZ_HOST; bash scripts/fuzz'
  exit
fi

[[ "$(uname -s) $(uname -m)" == "Linux x86_64" ]] || {
  echo "Use Linux x86_64 or set XQUIK_FUZZ_HOST to an authorized Linux SSH runner." >&2
  exit 1
}
export PATH="$HOME/.local/bin:$PATH"
evidence="$(mktemp -d)"
mkdir "$evidence/corpus"
echo "Fuzz evidence is in $evidence"
# The sanitizer runtime is preloaded into Python alone. Preloaded into uv, it can
# crash uv before Python starts, so the interpreter comes from an environment made first.
uv venv --quiet --python 3.13 "$evidence/venv"
uv pip install --quiet --python "$evidence/venv" atheris==3.1.0
fuzz_python="$evidence/venv/bin/python"
sanitizer="$("$fuzz_python" -c 'import atheris, pathlib; print(pathlib.Path(atheris.path()) / "asan_with_fuzzer.so")')"
[[ -f "$sanitizer" ]] || {
  echo "Atheris AddressSanitizer runtime is missing. Check the atheris install, then rerun." >&2
  exit 1
}
# A crashing sanitizer can print without end, so the log stops at 10 MB and the run fails.
log_limit=10485760
LD_PRELOAD="$sanitizer" ASAN_OPTIONS=detect_leaks=0:symbolize=1 PYTHONPATH="$PWD/src" \
  "$fuzz_python" "$harness" "$evidence/corpus" \
  -max_total_time=180 -max_len=4096 -rss_limit_mb=2048 -timeout=60 "-artifact_prefix=$evidence/" 2>&1 |
  head -c "$log_limit" | tee "$evidence/run.log"
