geenforce: kiosk watchdog must see a WINDOW, not just a process
Some checks failed
CI / backend (push) Failing after 8s
CI / naming (push) Successful in 2s
CI / frontend (push) Successful in 9s
CI / migrations-mysql (push) Failing after 7s

Reported from a real display: Edge closed on the desktop but still listed in
Task Manager, and the watchdog never relaunched it.

That is this watchdog's own bug. It asked only whether a --kiosk process
existed. After an Edge update the window can be gone while the process lingers,
so the check said "kiosk is up" and returned - every cycle, forever. Matching on
the command line was chosen to stop a stray renderer masking a dead kiosk; it
does not help when the orphan is the parent.

A kiosk now counts as up only when a --kiosk process still owns a visible
window (MainWindowHandle). Windowless ones are killed BEFORE relaunching:
leaving them would satisfy the next cycle's check again, and a second browser
would fight the first for the display.

Also refuses to run as SYSTEM. MainWindowHandle is session-scoped, so a SYSTEM
caller reads 0 for a perfectly healthy kiosk and would kill and relaunch it on
every cycle. The task uses an interactive Users principal so this cannot
normally happen; the guard makes a mis-registered task fail loudly instead of
thrashing a display in a hallway.

Verified on Windows this time by letting the SCHEDULED TASK do the work rather
than invoking the script by hand - which is what the first version was missing:
  - task fired unattended (rc=0) and launched the kiosk into session 1
  - the next cycle saw the healthy kiosk and did nothing, no relaunch loop
  - a windowless --kiosk process was killed and replaced
  - run as SYSTEM, it refused and the healthy kiosk survived
This commit is contained in:
cproudlock
2026-08-10 09:03:10 -04:00
parent 4d3985ce22
commit c0a7655aab
2 changed files with 70 additions and 8 deletions

View File

@@ -180,3 +180,26 @@ def test_watchdog_does_nothing_without_a_kiosk_shortcut():
script = build_watchdog_script()
assert 'ShopDB Kiosk.lnk' in script
assert 'shopdb-kiosk-lastlaunch' in script # debounce stamp
def test_watchdog_requires_a_visible_window_not_just_a_process():
"""Edge can update and leave a --kiosk process behind with no window. The
first version tested the command line alone, so it saw 'kiosk is up' and
never relaunched - observed on a real display."""
script = build_watchdog_script()
assert 'MainWindowHandle' in script
def test_watchdog_kills_windowless_kiosk_before_relaunching():
"""Leaving the orphan would satisfy the next cycle's check again, and two
browsers would fight over the display."""
script = build_watchdog_script()
assert 'Stop-Process' in script
assert 'windowless' in script
def test_watchdog_refuses_to_run_as_system():
"""MainWindowHandle is session-scoped: SYSTEM reads 0 for a healthy kiosk,
so a mis-registered task would kill and relaunch the display every cycle."""
script = build_watchdog_script()
assert 'IsSystem' in script