What changed, and why it matters
This commit adds test helper code for reading and interacting with vertical menus on Trezor hardware wallet screens. It only touches the Python test/debugging library and does not change any firmware security logic, cryptography, or user-facing behavior. There is no security issue here.
No security action needed. Treat as routine test infrastructure.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The diff extends trezorlib/debuglink.py with new test-only helpers: LayoutContent.vertical_menu_content() reads on-screen text from a ‘VerticalMenu’ component, DebugUI.navigate_to_menu_item() swipes and clicks during automated tests, and ButtonActions._vertical_menu_items() returns screen coordinates for menu items on Delizia and Eckhart layouts. All additions are inside the debug/test automation path and are not compiled into device firmware.
Changed components
python/src/trezorlib/debuglink.pyInspect captured patch +42 / −0
diff --git a/python/src/trezorlib/debuglink.py b/python/src/trezorlib/debuglink.py
index 86f973201..24545f8e5 100644
--- a/python/src/trezorlib/debuglink.py
+++ b/python/src/trezorlib/debuglink.py
@@ -356,6 +356,16 @@ class LayoutContent(UnstructuredJSONReader):
return [get_button_content(btn_key) for btn_key in button_keys]
+ def vertical_menu_content(self) -> list[str]:
+ """Get the content of the vertical menu."""
+
+ vertical_menu = self.find_unique_object_with_key_and_value(
+ "component", "VerticalMenu"
+ )
+ assert isinstance(vertical_menu, dict)
+
+ return [btn_obj["text"] for btn_obj in vertical_menu["buttons"]]
+
def seed_words(self) -> list[str]:
"""Get all the seed words on the screen in order.
@@ -989,6 +999,19 @@ class DebugUI:
else:
self._paginate_and_confirm(br.pages)
+ def navigate_to_menu_item(self, idx: int) -> None:
+ layout = self.debuglink.read_layout()
+ if self.buttons.layout_type is LayoutType.Eckhart:
+ assert "VerticalMenu" in layout.all_components()
+
+ # swipe n-1 times to get the nth item to the top
+ for _ in range(idx - 1):
+ self.debug.swipe_up()
+ (self._mid(), self._grid(self._height(), 5, 1))
+ self.debug.click(self.buttons.vertical_menu_items()[0])
+ else:
+ raise ValueError("Wrong layout type")
+
def _visit_menu_items(self) -> LayoutContent:
layout = self.debuglink.read_layout()
if not layout.has_menu() or not self.debuglink.allow_interactions:
@@ -2140,3 +2163,22 @@ class ButtonActions:
)
click_amount = BUTTON_LETTERS_BIP39[idx].index(letter) + 1
return self.buttons.mnemonic_from_index(idx), click_amount
+
+ # vertical menu buttons
+ def _vertical_menu_items(self) -> list[Coords]:
+ if self.layout_type is LayoutType.Delizia:
+ sb = ScreenButtons(self.layout_type)
+ return [
+ (sb._mid(), sb._grid(sb._height(), 4, 1)),
+ (sb._mid(), sb._grid(sb._height(), 4, 2)),
+ (sb._mid(), sb._grid(sb._height(), 4, 3)),
+ ]
+ elif self.layout_type is LayoutType.Eckhart:
+ sb = ScreenButtons(self.layout_type)
+ return [
+ (sb._mid(), sb._grid(sb._height(), 5, 1)),
+ (sb._mid(), sb._grid(sb._height(), 5, 2)),
+ (sb._mid(), sb._grid(sb._height(), 5, 3)),
+ ]
+ else:
+ raise ValueError("Wrong layout type")
Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.