#!/usr/bin/env bash
set -euo pipefail

ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
LOG_DIR="$ROOT/logs"
WORK_DIR="$ROOT/repro/work"
VENV_VULN="$ROOT/repro/venv_vuln"
VENV_FIXED="$ROOT/repro/venv_fixed"

mkdir -p "$LOG_DIR" "$WORK_DIR"

PIDS=()
cleanup() {
  for pid in "${PIDS[@]:-}"; do
    if kill -0 "$pid" 2>/dev/null; then
      kill "$pid" 2>/dev/null || true
    fi
  done
}
trap cleanup EXIT

rm -rf "$VENV_VULN" "$VENV_FIXED"
python -m venv "$VENV_VULN"
python -m venv "$VENV_FIXED"

"$VENV_VULN/bin/pip" install --upgrade pip >/dev/null
"$VENV_FIXED/bin/pip" install --upgrade pip >/dev/null

"$VENV_VULN/bin/pip" install mcp-server-git==2025.11.25 >"$LOG_DIR/pip_install_vuln.log" 2>&1
"$VENV_FIXED/bin/pip" install mcp-server-git==2025.12.18 >"$LOG_DIR/pip_install_fixed.log" 2>&1

rm -rf "$WORK_DIR/allowed_repo" "$WORK_DIR/other_repo"

WORK_DIR="$WORK_DIR" python - << 'PY'
from pathlib import Path
import os
import subprocess
root = Path(os.environ["WORK_DIR"])
allowed = root / "allowed_repo"
other = root / "other_repo"
for repo in [allowed, other]:
    repo.mkdir(parents=True, exist_ok=True)
    subprocess.run(["git","init"], cwd=repo, check=True, stdout=subprocess.DEVNULL)
    (repo / "file.txt").write_text(f"hello from {repo.name}")
    subprocess.run(["git","add","file.txt"], cwd=repo, check=True, stdout=subprocess.DEVNULL)
    subprocess.run(["git","-c","user.email=test@example.com","-c","user.name=Test","commit","-m","init"], cwd=repo, check=True, stdout=subprocess.DEVNULL)
print("allowed", allowed)
print("other", other)
PY

ln -sfn "$WORK_DIR/other_repo" "$WORK_DIR/allowed_repo/linked_repo"

run_tool_call() {
  local venv_bin="$1"
  local repo_path="$2"
  local log_file="$3"

  WORK_DIR="$WORK_DIR" PATH="$venv_bin:$PATH" "$venv_bin/python" - << PY >"$log_file" 2>&1
import anyio
import os
from pathlib import Path
from mcp.client.stdio import StdioServerParameters, stdio_client
from mcp.client.session import ClientSession

allowed = Path(os.environ["WORK_DIR"]) / "allowed_repo"
target = Path("$repo_path")

async def main():
    env = dict(os.environ)
    env["PATH"] = os.environ.get("PATH", "")
    server = StdioServerParameters(command="mcp-server-git", args=["--repository", str(allowed)], env=env)
    async with stdio_client(server) as (read_stream, write_stream):
        async with ClientSession(read_stream, write_stream) as session:
            await session.initialize()
            result = await session.call_tool("git_status", {"repo_path": str(target)})
            print(f"isError {result.isError}")
            for content in result.content:
                print(f"content {content.text}")

anyio.run(main)
PY
}

VULN_OK=1
FIXED_OK=1

run_tool_call "$VENV_VULN/bin" "$WORK_DIR/other_repo" "$LOG_DIR/vuln_outside_repo.log"
if ! grep -q "isError False" "$LOG_DIR/vuln_outside_repo.log"; then
  VULN_OK=0
fi

run_tool_call "$VENV_VULN/bin" "$WORK_DIR/allowed_repo/../other_repo" "$LOG_DIR/vuln_traversal_repo.log"
if ! grep -q "isError False" "$LOG_DIR/vuln_traversal_repo.log"; then
  VULN_OK=0
fi

run_tool_call "$VENV_VULN/bin" "$WORK_DIR/allowed_repo/linked_repo" "$LOG_DIR/vuln_symlink_repo.log"
if ! grep -q "isError False" "$LOG_DIR/vuln_symlink_repo.log"; then
  VULN_OK=0
fi

run_tool_call "$VENV_FIXED/bin" "$WORK_DIR/other_repo" "$LOG_DIR/fixed_outside_repo.log"
if ! grep -q "isError True" "$LOG_DIR/fixed_outside_repo.log"; then
  FIXED_OK=0
fi

run_tool_call "$VENV_FIXED/bin" "$WORK_DIR/allowed_repo/linked_repo" "$LOG_DIR/fixed_symlink_repo.log"
if ! grep -q "isError True" "$LOG_DIR/fixed_symlink_repo.log"; then
  FIXED_OK=0
fi

if [[ "$VULN_OK" -eq 1 && "$FIXED_OK" -eq 1 ]]; then
  echo "Reproduction successful."
  exit 0
fi

echo "Reproduction failed."
exit 1
