Closed bug report

ah decision on a web-control card: 'Allow 1 hr' arms the SHELL grant, web request times out, ab toast stays up

John Lauer · 2mo ago ·closed by John Lauer

Repro (AdomLapper, ab 2.1.87 insiders, ah embedded, 2026-09-09 20:02): wiki.adom.inc asked to run desktop write_file. ab raised the Web Control toast and mirrored a web-consent card to ah. John clicked Allow 1 hr in ah. Expected: the web origin gets its 1h grant, the request runs, ab's toast is dismissed (resolve_web_approval already does dismiss_toast_by_tag). Actual (startup.log): 20:02:24 web-consent id=fc66e5c4 delivered to ah; 20:02:27 'dismiss id= (granted)' = the resolve route's WINDOW branch ran apply_shell_auto_approve (a 1h SHELL auto-grant the user never asked for), the web session was never answered, 20:04:24 it timed out (request denied), and the ab toast stayed up. Root cause: /permission/resolve (and the shared resolver resolve_permission_decision_from) match allow_1h/allow_24h/bypass_while_running as a shell window grant BEFORE checking whether the id is a web-consent session or a credential-import consent; the 'web maps allow_1h to its 1h origin grant' code below it is unreachable for those decisions. Fix: route by id first (web session -> resolve_web_approval hour/once/deny; credential consent -> resolve_consent), then fall through to the shell vocabulary; make the route delegate to the one resolver so the two stop drifting. Also seen in the same log: the perm_mirror_dismiss relay fan-out echoes back to its sender (AdomLapper telling its own ah to dismiss remote:AdomLapper:...) - add the same originMachine self-guard toast_ack got in 2.1.86.

3 Replies

John Lauer · 2mo ago

Root cause confirmed from AdomLapper's startup.log (20:02:24 web-consent id=fc66e5c4 delivered to ah; 20:02:27 'dismiss id= (granted)' = the resolve route's window branch; 20:04:24 the web session timed out). Fix built as 2.1.88 (insiders, shipping now): resolve_permission_decision_from consults is_web_consent_id / cred_import::is_pending_consent BEFORE reading allow_1h / allow_24h / bypass_while_running as a shell window grant; /permission/resolve delegates to that one resolver (only not_pending is mapped back to the 1.9.191 'already_resolved' 200 for ah, and a mirrored Auto from ah now persists like every other surface); perm_mirror_dismiss got the relay self-guard. Side effect cleaned up: the unintended 1h SHELL grant this armed on AdomLapper at 20:02 was revoked (timed grant, permanent flag was false). Proof plan on winvm: raise a page prompt over ab's own loopback API with an Origin header, screenshot the toast, post allow_1h to /permission/resolve exactly as ah does, then show the page's second request passing silently, the shell grant file untouched, the toast gone.

John Lauer · 2mo ago

Shipped 2.1.88 (insiders). Fleet: winvm (canary, real embedded update path), ConfRoomROG, AdomLapper all on 2.1.88; Linux CLI 2.1.88 published (pkg latest 2.1.88, gallia relay module refreshed). Proof on AdomLapper (ah embedded, the box where it happened): (A) a page request POSTed to ab's loopback /command with Origin https://wiki.adom.inc raised web session 1bfbcba7; first image: ah's card AND the Web Control toast are up, ah shows '1 approval waiting'. (C) POST /permission/resolve {id, decision: allow_1h} exactly as ah posts it -> {applied: allow_1h, ok: true, scope: web-consent} (2.1.87 answered scope: window and armed the shell). shell_auto_approve_until.txt: empty before, empty after (no shell grant touched). (D) the page's second request: HTTP 200 in 63 ms with the real list_windows output, no prompt; /permission/state pendingByKind.web = 0. (E) startup.log 20:23:13: dismiss id=1bfbcba7 (allow_1h) delivered to ah. Second image (same second): toast gone, ah's card gone, the approval chip cleared. Cleanup from the investigation: the unintended 1h shell grant on AdomLapper was revoked at 20:12; two run_script prompts my first proof attempt raised on winvm (its standing grant had not survived the update) expired on their own. Smoke suite (62 tests via gallia) running; closing when it is green.

shot-2188-before

shot-2188-after

John Lauer · 2mo ago

Closing: 2.1.88 insiders on the whole fleet, proof above (resolve answers scope web-consent, shell grant untouched, page grant active, toast and ah card gone), smoke suite via gallia against the laptop on 2.1.88: all 60 non-lifecycle tests executed with 0 unexpected failures (T11/T12 lifecycle skipped by design, the 10 intentional refusals present).

John Lauer closed this · 2mo ago

Log in to reply.