mirror of
https://github.com/kuhyx/screen-locker.git
synced 2026-11-10 19:07:16 +01:00
Pin gatelock 0.2.1, and stop the popup check passing when it cannot run
The lock-popup-safety job failed on its first CI run for two reasons, and only one of them was the obvious one. The obvious one: the script imports screen_locker directly rather than through pytest, which would have put the rootdir on sys.path for it. CI now installs the package. The one worth having found: CI installs gatelock from the pinned tag, which predated `holds_grab`, so every hostile tick died on an AttributeError -- inside a Tk `after` callback, where exceptions are swallowed and logged rather than raised. The harness sailed past, printed OK and exited 0 while doing no grab re-assertion whatsoever. A verification script that passes when it is broken is worse than not having it. So it now fails closed twice over: an explicit check that the installed gatelock has the predicate at all, with a message naming the fix, and a count of ticks that actually completed -- incremented after the work, so a raising tick does not count. Fewer completed ticks than asked for is reported as "the harness itself is broken, so this result proves nothing", not as a pass. The pin moves to gatelock-v0.2.1, which carries both of yesterday's fixes: the grab predicate that no longer steals the grab off our own posted menus, and the recovery loop that no longer stops forever when a tick raises. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
c0aae7d05b
commit
c11e27f123
3
.github/workflows/python-tests.yml
vendored
3
.github/workflows/python-tests.yml
vendored
@ -45,6 +45,9 @@ jobs:
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y xvfb python3-tk
|
||||
pip install -r requirements.txt
|
||||
# The script imports screen_locker directly rather than through
|
||||
# pytest, which would put the rootdir on sys.path for it.
|
||||
pip install -e . --no-deps
|
||||
|
||||
- name: Sport selector survives gatelock's recovery tick
|
||||
run: python3 scripts/verify_lock_popup_safety.py
|
||||
|
||||
@ -7,7 +7,7 @@ requires-python = ">=3.10"
|
||||
# crdt-sync: shared CRDT merge scheme + GitHub-Contents-API sync transport,
|
||||
# also used by diet_guard; here for phone-workout GitHub sync (Workstream C)
|
||||
dependencies = [
|
||||
"gatelock @ git+https://github.com/kuhyx/utils@gatelock-v0.2.0#subdirectory=gatelock",
|
||||
"gatelock @ git+https://github.com/kuhyx/utils@gatelock-v0.2.1#subdirectory=gatelock",
|
||||
"crdt-sync @ git+https://github.com/kuhyx/utils@crdt-sync-v0.1.0#subdirectory=crdt-sync",
|
||||
]
|
||||
|
||||
|
||||
@ -4,7 +4,7 @@ bandit>=1.7.0
|
||||
codespell>=2.2.0
|
||||
coverage>=7.4.0
|
||||
crdt-sync @ git+https://github.com/kuhyx/utils@crdt-sync-v0.1.0#subdirectory=crdt-sync
|
||||
gatelock @ git+https://github.com/kuhyx/utils@gatelock-v0.2.0#subdirectory=gatelock
|
||||
gatelock @ git+https://github.com/kuhyx/utils@gatelock-v0.2.1#subdirectory=gatelock
|
||||
mcp>=1.9
|
||||
mypy>=1.8.0
|
||||
pre-commit>=3.6.0
|
||||
|
||||
@ -97,10 +97,13 @@ class HostileLock:
|
||||
|
||||
def _tick(self) -> None:
|
||||
"""Lift the surface and re-take the grab, exactly as gatelock does."""
|
||||
self.ticks += 1
|
||||
self.root.lift()
|
||||
if not self._loop.holds_grab():
|
||||
self.root.grab_set_global()
|
||||
# Counted only after the work, so a raising tick does not count. Tk
|
||||
# swallows exceptions from `after` callbacks, and this harness once
|
||||
# reported OK while every tick was dying on an AttributeError.
|
||||
self.ticks += 1
|
||||
self.root.after(TICK_MS, self._tick)
|
||||
|
||||
|
||||
@ -120,13 +123,21 @@ def run_ticks(
|
||||
nonlocal verdict
|
||||
verdict = judge()
|
||||
|
||||
HostileLock(root)
|
||||
lock = HostileLock(root)
|
||||
if setup is not None:
|
||||
root.after(200, setup)
|
||||
root.after(TICK_MS * TICKS + 400, decide)
|
||||
root.after(TICK_MS * TICKS + 600, root.quit)
|
||||
root.mainloop()
|
||||
root.destroy()
|
||||
if lock.ticks < TICKS:
|
||||
_logger.error(
|
||||
" only %d of %d hostile ticks completed -- the harness itself is "
|
||||
"broken, so this result proves nothing",
|
||||
lock.ticks,
|
||||
TICKS,
|
||||
)
|
||||
return False
|
||||
return verdict
|
||||
|
||||
|
||||
@ -269,6 +280,14 @@ def main() -> int:
|
||||
if os.environ.get(INNER_ENV) != "1":
|
||||
return reexec_under_xvfb()
|
||||
|
||||
if not hasattr(RecoveryLoop, "holds_grab"):
|
||||
_logger.error(
|
||||
"The installed gatelock has no RecoveryLoop.holds_grab, so this "
|
||||
"check cannot replay the real grab predicate. Bump the gatelock "
|
||||
"pin in requirements.txt to a version that has it."
|
||||
)
|
||||
return 1
|
||||
|
||||
_logger.info("The mechanism (a popup on a lock surface):")
|
||||
mechanism_reproduced = check_optionmenu_still_fails()
|
||||
_logger.info("The fix (radio buttons in the production form):")
|
||||
|
||||
Loading…
Reference in New Issue
Block a user