c2f08d1a21
Extends the Phase A-tier-1 site-side rotation engine with an optional Node browser-sidecar and a deterministic self-heal tier, all proven LIVE-VM against the local lab change-password form. go-rod stays the default; the sidecar is a swap-in Driver behind the same Session/Driver/Rotator interfaces — no spine change, backup + verify-new-before-revoke-old + proof gates all apply unchanged. M-B1 sidecar parity: internal/browserrot/sidecar/ (index.js JSON-RPC over stdio, patchright real-fingerprint Chromium, playwright-core fallback) + sidecar.go Driver/Session. A shared test harness runs go-rod and the sidecar through the identical live rotation proof. M-B2 stealth: patchright removes navigator.webdriver; humanized input (Bezier mouse paths + per-key typing jitter, no ML trajectory generation per plan §5). M-B3 self-heal: Healer interface + heal-retry fill/click/text wrappers; on a rotted selector, heal.js relocates the field from DOM structure ONLY (never a value) and the engine rewrites + persists the recipe (recipes.go RecipeBook) so the next run is Tier-1 again. Deterministic heuristic is the proven Tier-2; Stagehand LLM strategy is opt-in + UNPROVEN. Leak-check asserts no secret ever reaches a heal request (redacted IPC transcript). Secret seam documented honestly: fill carries base64 secret bytes across exactly one local stdio boundary, typed and wiped, never logged/persisted/sent to a model. MFA/CAPTCHA still degrade to the human worklist (Hard Rule 5). 14 tests green, -race clean; lab/lab-provision-browserrot.sh proves both drivers. M-B4 (first REAL self-owned site) deliberately NOT started — needs per-credential authorization (safe-candidate ladder). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
93 lines
4.0 KiB
Bash
Executable File
93 lines
4.0 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# LIVE-VM proof for the Phase A-tier-1 site-side rotation ENGINE (internal/browserrot),
|
|
# inside the sandbox VM. FAKE credential only, against a throwaway in-process website —
|
|
# nothing real is touched.
|
|
#
|
|
# What this proves is the deterministic browser-drive machinery that would run against a
|
|
# real change-password page:
|
|
#
|
|
# * discover the change page via RFC 8615 /.well-known/change-password (real redirect)
|
|
# * inject the OLD + a freshly-minted NEW password into the form over CDP, with NO
|
|
# language model in the loop
|
|
# * submit and read the site's SUCCESS marker
|
|
# * VERIFY the new password authenticates by re-logging-in (hard rule 2), and confirm
|
|
# the OLD password no longer works (the rotation is real, not a no-op)
|
|
#
|
|
# The engine is exercised by the CHROME_BIN-gated integration test
|
|
# (TestIntegration_realBrowserRotation) driving a REAL headless Chromium. This is what
|
|
# earns browserrot's LIVE-VM proof level for the ENGINE; a specific real-site selector
|
|
# table stays UNPROVEN until it is run against that real site.
|
|
#
|
|
# It does NOT rotate any real account: only the user's own accounts, with explicit
|
|
# per-credential authorization, may ever be driven against a real provider.
|
|
set -euo pipefail
|
|
export PATH=/usr/local/bin:$PATH
|
|
|
|
# Locate a usable, NON-snap Chromium (snap chromium fights CDP + can't read /tmp).
|
|
find_chrome() {
|
|
for c in \
|
|
"${CHROME_BIN:-}" \
|
|
"$HOME"/.cache/ms-playwright/chromium-*/chrome-linux64/chrome \
|
|
"$HOME"/.cache/ms-playwright/chromium-*/chrome-linux/chrome \
|
|
/usr/bin/google-chrome /usr/bin/chromium /opt/google/chrome/chrome ; do
|
|
[ -n "$c" ] && [ -x "$c" ] && { echo "$c"; return 0; }
|
|
done
|
|
return 1
|
|
}
|
|
|
|
CHROME_BIN="$(find_chrome || true)"
|
|
if [ -z "${CHROME_BIN:-}" ]; then
|
|
echo "FAIL: no usable Chromium found. Install Chrome-for-Testing / google-chrome, or"
|
|
echo " set CHROME_BIN to a chromium executable (a Playwright-managed one is ideal)."
|
|
echo " hint: npx playwright install chromium"
|
|
exit 1
|
|
fi
|
|
echo "== using Chromium: $CHROME_BIN"
|
|
"$CHROME_BIN" --version 2>/dev/null | sed 's/^/ /' || true
|
|
|
|
# Run from the repo root (the dir containing go.mod).
|
|
cd "$(git -C "$(dirname "$0")" rev-parse --show-toplevel 2>/dev/null || echo "$(dirname "$0")/..")"
|
|
|
|
# The Node sidecar (patchright real-fingerprint Chromium) is an OPTIONAL swap-in Driver
|
|
# that must reach parity with go-rod. If a `node` runtime + the sidecar deps are present,
|
|
# prove BOTH drivers through the identical harness; otherwise prove go-rod only.
|
|
SIDECAR_DIR="internal/browserrot/sidecar"
|
|
have_sidecar() {
|
|
command -v node >/dev/null 2>&1 && [ -d "$SIDECAR_DIR/node_modules/playwright-core" ]
|
|
}
|
|
|
|
echo "== running the LIVE-VM browser-rotation proof (go-rod) =="
|
|
CHROME_BIN="$CHROME_BIN" go test -run TestIntegration_realBrowserRotation -v ./internal/browserrot/
|
|
|
|
if have_sidecar; then
|
|
echo
|
|
echo "== running the LIVE-VM browser-rotation proof (node-sidecar, parity) =="
|
|
node --version | sed 's/^/ node /'
|
|
CHROME_BIN="$CHROME_BIN" go test -run TestIntegration_sidecarBrowserRotation -v ./internal/browserrot/
|
|
|
|
if [ -d "$SIDECAR_DIR/node_modules/patchright" ]; then
|
|
echo
|
|
echo "== M-B2 stealth: patchright fingerprint + humanized input =="
|
|
CHROME_BIN="$CHROME_BIN" go test -run 'TestIntegration_sidecarStealth' -v ./internal/browserrot/
|
|
else
|
|
echo
|
|
echo "== M-B2 stealth SKIPPED (patchright not installed) =="
|
|
echo " to enable: (cd $SIDECAR_DIR && npm install patchright)"
|
|
fi
|
|
|
|
echo
|
|
echo "== M-B3 self-heal: rotted selector -> Tier-2 heal -> rewrite recipe (no secret to heal) =="
|
|
CHROME_BIN="$CHROME_BIN" go test -run 'TestIntegration_sidecarSelfHeal' -v ./internal/browserrot/
|
|
else
|
|
echo
|
|
echo "== node-sidecar SKIPPED (no node runtime or deps not installed) =="
|
|
echo " to enable: (cd $SIDECAR_DIR && PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1 npm install)"
|
|
fi
|
|
|
|
echo
|
|
echo "== secret-seam leak guard (browser-free) =="
|
|
go test -run TestSidecar_secretSeamBase64 -v ./internal/browserrot/
|
|
|
|
echo
|
|
echo "LIVE-VM BROWSER-ROTATION ENGINE PROOF PASSED"
|