clawdie-ai/scripts/browser-jail-clone-validation/run-validation.sh
Operator & Codex 3ea26f231d Validate browser clone cookie injection
---
Build: pass | Tests: pass — 2383 passed (175 files)
2026-05-11 16:19:12 +02:00

148 lines
5.3 KiB
Bash
Executable file

#!/usr/bin/env bash
set -euo pipefail
REPO_DIR="$(cd "$(dirname "$0")/../.." && pwd)"
TEMPLATE="${TEMPLATE:-browser}"
SNAPSHOT="${SNAPSHOT:-}"
DATASET_BASE="${DATASET_BASE:-zroot/clawdie-runtime/jails}"
JAILS_DIR="${JAILS_DIR:-/usr/local/bastille/jails}"
CYCLES="${CYCLES:-3}"
COOKIE="${VALIDATION_COOKIE:-phase06-cookie}"
RESULT_DIR="${RESULT_DIR:-${REPO_DIR}/tmp/browser-jail-clone-validation}"
RESULT_JSONL="${RESULT_JSONL:-${RESULT_DIR}/results.jsonl}"
if [ -z "$SNAPSHOT" ]; then
echo "SNAPSHOT is required, e.g. SNAPSHOT=pre-injection-11.maj.2026-1430" >&2
exit 2
fi
mkdir -p "$RESULT_DIR"
: > "$RESULT_JSONL"
now_ms() {
python3 -c 'import time; print(int(time.time() * 1000))'
}
json_escape() {
python3 -c 'import json,sys; print(json.dumps(sys.stdin.read())[1:-1])'
}
emit_json() {
local cycle="$1"
local clone="$2"
local ip="$3"
local clone_ms="$4"
local start_ms="$5"
local chrome_ms="$6"
local smoke_ms="$7"
local destroy_ms="$8"
local status="$9"
local note="${10:-}"
local escaped_note
escaped_note="$(printf '%s' "$note" | json_escape)"
printf '{"cycle":%s,"clone":"%s","ip":"%s","clone_ms":%s,"start_ms":%s,"chrome_ready_ms":%s,"smoke_ms":%s,"destroy_ms":%s,"status":"%s","note":"%s"}\n' \
"$cycle" "$clone" "$ip" "$clone_ms" "$start_ms" "$chrome_ms" "$smoke_ms" "$destroy_ms" "$status" "$escaped_note" >> "$RESULT_JSONL"
}
patch_clone_config() {
local clone="$1"
local suffix="$2"
local ip="$3"
python3 - "$clone" "$suffix" "$ip" "$JAILS_DIR" "$TEMPLATE" <<'PY'
from pathlib import Path
import sys
clone, suffix, ip, jails_dir, template = sys.argv[1:]
base = Path(jails_dir) / clone
jail_conf = base / 'jail.conf'
text = jail_conf.read_text()
text = text.replace(f'{template} {{', f'{clone} {{')
text = text.replace(f'/var/log/bastille/{template}_console.log', f'/var/log/bastille/{clone}_console.log')
text = text.replace(f'{jails_dir}/{template}/fstab', f'{jails_dir}/{clone}/fstab')
text = text.replace(f'{jails_dir}/{template}/root', f'{jails_dir}/{clone}/root')
text = text.replace(f'e0b_{template}', f'e0b_{suffix}')
text = text.replace(f'e0a_{template}', f'e0a_{suffix}')
text = text.replace(f'jail {template}', f'jail {clone}')
jail_conf.write_text(text)
fstab = base / 'fstab'
fstab_text = fstab.read_text().replace(f'{jails_dir}/{template}/', f'{jails_dir}/{clone}/')
fstab.write_text(fstab_text)
rc = base / 'root/etc/rc.conf'
rc_text = rc.read_text()
rc_text = rc_text.replace(f'ifconfig_e0b_{template}_name', f'ifconfig_e0b_{suffix}_name')
rc_text = rc_text.replace('inet 192.168.72.6/24', f'inet {ip}/24')
rc.write_text(rc_text)
PY
}
cleanup_clone() {
local clone="$1"
local suffix="$2"
bastille cmd "$clone" sh -c 'if [ -f /var/run/browser-validation-chromium.pid ]; then kill -TERM "$(cat /var/run/browser-validation-chromium.pid)" 2>/dev/null || true; fi' >/dev/null 2>&1 || true
bastille stop "$clone" >/dev/null 2>&1 || true
ifconfig "e0a_${suffix}" destroy >/dev/null 2>&1 || true
zfs destroy -r "${DATASET_BASE}/${clone}" >/dev/null 2>&1 || true
}
wait_for_cdp() {
local clone="$1"
local attempt
for attempt in $(seq 1 30); do
if bastille cmd "$clone" fetch -qo - http://127.0.0.1:9222/json/version >/dev/null 2>&1; then
return 0
fi
sleep 1
done
return 1
}
for cycle in $(seq 1 "$CYCLES"); do
clone="browsertask$(printf '%03d' "$cycle")"
suffix="bt$(printf '%03d' "$cycle")"
ip="192.168.72.$((159 + cycle))"
clone_ms=0
start_ms=0
chrome_ms=0
smoke_ms=0
destroy_ms=0
status="ok"
note=""
cleanup_clone "$clone" "$suffix"
start=$(now_ms)
zfs clone -o mountpoint="${JAILS_DIR}/${clone}" "${DATASET_BASE}/${TEMPLATE}@${SNAPSHOT}" "${DATASET_BASE}/${clone}"
zfs clone -o mountpoint="${JAILS_DIR}/${clone}/root" "${DATASET_BASE}/${TEMPLATE}/root@${SNAPSHOT}" "${DATASET_BASE}/${clone}/root"
patch_clone_config "$clone" "$suffix" "$ip"
end=$(now_ms)
clone_ms=$((end - start))
start=$(now_ms)
bastille start "$clone"
end=$(now_ms)
start_ms=$((end - start))
start=$(now_ms)
bastille cmd "$clone" sh -c 'nohup /usr/local/bin/chrome --headless=new --no-sandbox --disable-gpu --password-store=basic --remote-debugging-address=127.0.0.1 --remote-debugging-port=9222 --user-data-dir=/var/db/browser-profile-basic about:blank >/var/log/browser-validation-chromium.log 2>&1 & echo $! >/var/run/browser-validation-chromium.pid'
wait_for_cdp "$clone"
end=$(now_ms)
chrome_ms=$((end - start))
start=$(now_ms)
bastille cmd "$clone" sh -c "cd /opt/browser-validation && VALIDATION_COOKIE=${COOKIE} SCREENSHOT_PATH=/var/tmp/${clone}-smoke.png node clone-smoke.mjs"
end=$(now_ms)
smoke_ms=$((end - start))
start=$(now_ms)
bastille cmd "$clone" sh -c 'if [ -f /var/run/browser-validation-chromium.pid ]; then kill -TERM "$(cat /var/run/browser-validation-chromium.pid)" 2>/dev/null || true; fi; for i in 1 2 3 4 5; do pgrep chrome >/dev/null 2>&1 || exit 0; sleep 1; done; if [ -f /var/run/browser-validation-chromium.pid ]; then kill -KILL "$(cat /var/run/browser-validation-chromium.pid)" 2>/dev/null || true; fi' >/dev/null 2>&1 || true
bastille stop "$clone"
ifconfig "e0a_${suffix}" destroy >/dev/null 2>&1 || true
zfs destroy -r "${DATASET_BASE}/${clone}"
end=$(now_ms)
destroy_ms=$((end - start))
emit_json "$cycle" "$clone" "$ip" "$clone_ms" "$start_ms" "$chrome_ms" "$smoke_ms" "$destroy_ms" "$status" "$note"
done
printf 'results=%s\n' "$RESULT_JSONL"