browser: click-path allowlist, safe tenant script upgrade, allowlist activation plan

- click/click_ref: pre-click allowlist gate on resolvable anchor href
  (same check as navigate; miss refuses before the click executes);
  click/click_ref/click_at: post-click landing URL check.
  click_at has no pre-click gate by design (coordinates name no
  element); JS-driven navigation, evaluate, meta refresh and popups
  are documented as unintercepable with the Tinyproxy 403 backstop.
- Tenant script upgrade is now safe: only proven-unmodified scripts
  (manifest match, 2a569ac known-shipped SHA-256, missing, or
  current) auto-merge; tenant-modified scripts are never overwritten,
  are reported as skipped, and get one deduped audit record. The
  manifest never learns a tenant hash (else the next upgrade would
  mistake a modified file for untouched). Idempotent reruns.
- Activation candidate = deployed Tinyproxy programming set encoded
  with leading-dot entries (plain entries would regress
  docs.python.org); npmjs.org per the deployed filter, not npmjs.com.
  Host activation itself is NOT performed this round: only the plan,
  validation tests and rollback are delivered.
Tests: 28 new (click 13, upgrade 8, activation 7), all fake/no-network;
98 browser-related tests pass including prior suites.

(cherry picked from commit e4a93f5748ec815f163d0bc096ff4dc4b8c651f5)
This commit is contained in:
host committed 2026-11-01 09:06:28 +00:00
1 parent 1141d0d0f8
commit 125b436ab3
8 files changed
+1150 -33

No files matched your search

+15 -3
View File
@@ -72,7 +72,12 @@ _TOOLS = [
"description": (
"Click an element by CSS selector or Playwright "
"selector (e.g. 'button.submit', 'text=Next'). "
"Then snapshot to see the result."
"Then snapshot to see the result. When "
"BROWSER_ALLOWED_HOSTS is set, an anchor click to "
"a non-listed host is refused BEFORE the click; a "
"click whose target cannot be resolved beforehand "
"(button, JS handler) is reported after it lands "
"on a blocked host instead."
),
"inputSchema": {
"type": "object",
@@ -120,7 +125,11 @@ _TOOLS = [
"top-left of the 1280x800 viewport). This is the tool "
"a live viewer drives: the user clicks on a screenshot "
"and the coordinates arrive here. Then snapshot to see "
"the result."
"the result. Coordinates identify no element, so "
"there is no pre-click allowlist gate here: when "
"BROWSER_ALLOWED_HOSTS is set, a landing on a "
"blocked host is reported after the click, and the "
"egress proxy 403 is the backstop that stops the load."
),
"inputSchema": {
"type": "object",
@@ -165,7 +174,10 @@ _TOOLS = [
"name": "browser_click_ref",
"description": (
"Click an element by its ref from browser_snapshot_refs. "
"More robust than a CSS selector across re-renders."
"More robust than a CSS selector across re-renders. "
"Same allowlist rule as browser_click: an anchor ref "
"to a non-listed host is refused before the click "
"when BROWSER_ALLOWED_HOSTS is set."
),
"inputSchema": {
"type": "object",