#!/bin/bash
set -euo pipefail

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

cd "$ROOT"

MAIN_LOG="$LOGS/reproduction_steps.log"
: > "$MAIN_LOG"

REPO_DEFAULT="/data/pruva/project-cache/7182044f-d4bd-4461-bb94-67cc221ed6fc/repo"
REPO="$REPO_DEFAULT"
SUBMITTED_REF="3356b86a8bfa^"
FIXED_REF="3356b86a8bfa"
VULN_COMMIT=""
FIXED_COMMIT=""
VARIANT_MARKER="PRUVA_VARIANT_HEADER_AT_EXECUTED"

log() {
    echo "[$(date -Iseconds)] $*" | tee -a "$MAIN_LOG"
}

write_runtime_manifest() {
    local vuln_reached="$1" fixed_reached="$2" verdict="$3"
    python3 - "$OUTDIR/runtime_manifest.json" "$vuln_reached" "$fixed_reached" "$verdict" <<'PY'
import json, sys
path, vuln_reached, fixed_reached, verdict = sys.argv[1:]
manifest = {
    "entrypoint_kind": "source_and_cli_negative_probe",
    "entrypoint_detail": "Static side-by-side inspection of Nuclio Kubernetes cron-trigger CronJob generation in the vulnerable parent and fixed commit, plus local curl argv semantics probe for a header value beginning with @.",
    "service_started": False,
    "healthcheck_passed": verdict == "no_variant_confirmed",
    "target_path_reached": vuln_reached == "true" or fixed_reached == "true",
    "runtime_stack": ["git source checkout", "curl CLI semantics probe", "Nuclio pkg/platform/kube/functionres/lazy.go"],
    "tested_versions": {
        "vulnerable_parent_checked": vuln_reached == "true",
        "fixed_commit_checked": fixed_reached == "true"
    },
    "proof_artifacts": [
        "logs/vuln_variant/reproduction_steps.log",
        "logs/vuln_variant/source_identity.txt",
        "logs/vuln_variant/patch_diff.stat",
        "logs/vuln_variant/lazy_vulnerable_excerpt.txt",
        "logs/vuln_variant/lazy_fixed_excerpt.txt",
        "logs/vuln_variant/security_policy_scan.txt",
        "logs/vuln_variant/candidate_matrix.log",
        "logs/vuln_variant/curl_header_at_probe.log"
    ],
    "verdict": verdict,
    "notes": "No bypass is confirmed. The fixed commit invokes curl directly with discrete argv entries and uses --data-raw for the body; no shell consumes header keys, header values, or body. The tested @-header candidate is curl option-level behavior, not OS command execution, and does not execute on the fixed target."
}
with open(path, "w", encoding="utf-8") as f:
    json.dump(manifest, f, indent=2)
    f.write("\n")
PY
}

write_runtime_manifest false false started

log "=== Nuclio CVE-2026-52831 variant/bypass analysis ==="
log "Root: $ROOT"

if [ -f "$ROOT/project_cache_context.json" ]; then
    CACHE_REPO="$(jq -r 'if .prepared == true and (.project_cache_dir // "") != "" then .project_cache_dir + "/repo" else "" end' "$ROOT/project_cache_context.json")"
    if [ -n "$CACHE_REPO" ] && [ -d "$CACHE_REPO/.git" ]; then
        REPO="$CACHE_REPO"
    fi
fi
if [ ! -d "$REPO/.git" ]; then
    log "Repository not found at $REPO"
    exit 2
fi
log "Using repository: $REPO"

VULN_COMMIT="$(git -C "$REPO" rev-parse "$SUBMITTED_REF^{commit}")"
FIXED_COMMIT="$(git -C "$REPO" rev-parse "$FIXED_REF^{commit}")"
CURRENT_COMMIT="$(git -C "$REPO" rev-parse HEAD)"
{
    echo "repository=https://github.com/nuclio/nuclio"
    echo "repo_path=$REPO"
    echo "current_head=$CURRENT_COMMIT"
    echo "submitted_vulnerable_parent=$VULN_COMMIT"
    echo "fixed_commit=$FIXED_COMMIT"
    git -C "$REPO" show --no-patch --format='fixed_subject=%s%nfixed_date=%cI' "$FIXED_COMMIT"
} | tee "$LOGS/source_identity.txt" >> "$MAIN_LOG"

log "Recording fixed patch stat and relevant source excerpts"
git -C "$REPO" show --stat --oneline --no-renames "$FIXED_COMMIT" > "$LOGS/patch_diff.stat"
git -C "$REPO" diff --no-renames "$VULN_COMMIT" "$FIXED_COMMIT" -- pkg/platform/kube/functionres/lazy.go pkg/platform/kube/functionres/lazy_test.go > "$LOGS/patch_diff.full"
git -C "$REPO" show "$VULN_COMMIT:pkg/platform/kube/functionres/lazy.go" | sed -n '2130,2225p' > "$LOGS/lazy_vulnerable_excerpt.txt"
git -C "$REPO" show "$FIXED_COMMIT:pkg/platform/kube/functionres/lazy.go" | sed -n '2130,2225p' > "$LOGS/lazy_fixed_excerpt.txt"

log "Scanning target security policy / threat model documents"
{
    echo "Security/threat-model file scan under repository root:"
    find "$REPO" -maxdepth 4 \( -iname 'SECURITY.md' -o -iname '*security*' -o -iname '*threat*' \) -print | sort || true
    echo
    echo "Security/vulnerability text mentions:"
    grep -RIn --exclude-dir=.git -E 'Security Policy|security policy|vulnerability|threat model|command injection|shell injection' "$REPO" 2>/dev/null | head -80 || true
} | tee "$LOGS/security_policy_scan.txt" >> "$MAIN_LOG"

log "Testing vulnerable parent invariant: cron-trigger generation uses /bin/sh -c"
if ! grep -q 'Args:.*\[\]string{"/bin/sh", "-c", curlCommand}' "$LOGS/lazy_vulnerable_excerpt.txt"; then
    log "Vulnerable parent did not contain expected shell-form cron-trigger generation"
    write_runtime_manifest false false inconclusive
    exit 2
fi
log "Testing fixed invariant: no shell, curl exec form, body uses --data-raw"
if ! grep -q 'Command:.*\[\]string{"curl"}' "$LOGS/lazy_fixed_excerpt.txt"; then
    log "Fixed source does not contain exec-form curl command"
    write_runtime_manifest true false inconclusive
    exit 2
fi
if grep -q 'Args:.*\[\]string{"/bin/sh", "-c"' "$LOGS/lazy_fixed_excerpt.txt"; then
    log "Fixed source still contains /bin/sh -c in cron-trigger generation"
    write_runtime_manifest true true bypass_possible
    exit 0
fi
if ! grep -q -- '"--data-raw"' "$LOGS/lazy_fixed_excerpt.txt"; then
    log "Fixed source does not contain --data-raw body handling"
    write_runtime_manifest true false inconclusive
    exit 2
fi

log "Evaluating bounded variant candidates"
: > "$LOGS/candidate_matrix.log"
{
    echo "Candidate 1: event.headers key with quote/semicolon shell metacharacters (parent PoC surface)."
    echo "  Vulnerable parent: reaches /bin/sh -c via curlCommand string."
    echo "  Fixed commit: rejected as bypass because user header is one argv entry after --header and no shell is present. Covered by lazy_test.go TestCronTriggerExecFormNoShellInjection/header_key_with_quote_does_not_break_shell."
    echo
    echo "Candidate 2: event.body with command substitution \$(id) or shell separators."
    echo "  Vulnerable parent: body is written through a shell command prefix, so command substitution is possible in the /bin/sh -c string."
    echo "  Fixed commit: rejected as bypass because body is passed as a literal argv value after --data-raw. Covered by lazy_test.go TestCronTriggerExecFormNoShellInjection/body_with_command_substitution_is_literal."
    echo
    echo "Candidate 3: event.body beginning with @/path to trigger curl file-load semantics after shell removal."
    echo "  Vulnerable parent: old code used --data '@/tmp/eventbody.out' after writing a temp file via shell."
    echo "  Fixed commit: rejected as bypass because it deliberately uses --data-raw, not --data; @ is literal. Covered by lazy_test.go TestCronTriggerExecFormNoShellInjection/body_starting_with_at_is_not_file_load."
    echo
    echo "Candidate 4: event.headers key/value beginning with @/path to trigger curl --header file-load semantics."
    echo "  Fixed commit: curl attempts to read a header file only when the *entire* --header argument starts with @. Nuclio formats the header argv as '<key>: <value>'; a key named '@/etc/passwd' would become '@/etc/passwd: value' and curl errors because that exact filename does not exist. This is option-level file-read behavior, not shell command execution, and no marker command executes."
} | tee -a "$LOGS/candidate_matrix.log" >> "$MAIN_LOG"

log "Running local curl argv-semantics probe for Candidate 4 (@ header)"
: > "$LOGS/curl_header_at_probe.log"
python3 - <<'PY' > "$LOGS/curl_probe_server.log" 2>&1 &
import http.server
class H(http.server.BaseHTTPRequestHandler):
    def do_GET(self):
        print('---REQUEST---', flush=True)
        print(str(self.headers), flush=True)
        self.send_response(200)
        self.end_headers()
        self.wfile.write(b'ok')
    def log_message(self, fmt, *args):
        pass
http.server.HTTPServer(('127.0.0.1', 18080), H).handle_request()
PY
SERVER_PID=$!
sleep 0.5
set +e
{
    echo "curl version: $(curl --version | head -1)"
    echo "Probe command: curl --header '@/etc/passwd: marker' http://127.0.0.1:18080/"
    curl --silent --show-error --max-time 3 --header '@/etc/passwd: marker' http://127.0.0.1:18080/
    CURL_EXIT=$?
    echo
    echo "curl_exit=$CURL_EXIT"
    echo "server_log:"
    cat "$LOGS/curl_probe_server.log" 2>/dev/null || true
} > "$LOGS/curl_header_at_probe.log" 2>&1
PROBE_STATUS=$?
kill "$SERVER_PID" 2>/dev/null || true
set -e
cat "$LOGS/curl_header_at_probe.log" | tee -a "$MAIN_LOG"
log "Curl probe wrapper status: $PROBE_STATUS"

if grep -q "$VARIANT_MARKER" "$LOGS/curl_header_at_probe.log"; then
    log "Unexpected command execution marker found"
    write_runtime_manifest true true confirmed_bypass
    exit 0
fi

log "No fixed-version bypass or materially distinct same-root-cause variant was confirmed"
write_runtime_manifest true true no_variant_confirmed
exit 1
