Skip to content

Commit

Permalink
Merge pull request #174 from LedgerHQ/integration/flex
Browse files Browse the repository at this point in the history
Flex integration
  • Loading branch information
lpascal-ledger authored Apr 12, 2024
2 parents 2904123 + c206c1f commit 928ce2b
Show file tree
Hide file tree
Showing 40 changed files with 718 additions and 448 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build_and_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ jobs:
echo """[app]
build_directory = \"./\"
sdk = \"C\"
devices = [\"nanos\", \"nanos+\", \"nanox\", \"stax\"]""" > ledger_app.toml
devices = [\"nanos\", \"nanos+\", \"nanox\", \"stax\", \"flex\"]""" > ledger_app.toml
- name: Check the downloaded files
run: tree .
Expand Down
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,19 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [1.18.0] - 2024-04-12

### Added
- Flex firmware & navigation

### Changed
- firmware: 'stax' module is renamed 'touch', as it is no longer specific to the Stax device
- navigator: 'StaxNavigator' class is renamed 'TouchNavigator', as it is no longer specific to the
Stax device

### Removed
- firmware: deprecated properties `Firmware.has_bal` and `has_nbgl`

## [1.17.0] - 2024-04-11

### Added
Expand Down
2 changes: 0 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,6 @@ You can also install it from sources. At the root of the `git` repository, run:
pip install '.[all_backends]'
```

The extra index is important, as it brings the latest version of Speculos.

### Extras

Sometimes we just need some function embedded in the library, or just one backend. It can be
Expand Down
9 changes: 5 additions & 4 deletions doc/glossary.rst
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,6 @@ Glossary
integrated into the C SDK managing the UI of the NanoS, NanoX and NanoS+
devices. It is embedded into the :term:`SDK`

Its equivalent for :term:`Stax` device is :term:`NBGL`.

BOLOS
**BOLOS** is `the operating system running on all Ledger hardware wallets
<https://www.ledger.com/introducing-bolos-blockchain-open-ledger-operating-system>`_.
Expand Down Expand Up @@ -85,6 +83,9 @@ Glossary
:term:`BAGL` for more recent devices such as :term:`Stax`. It is embedded
into the :term:`SDK`.

It has also been back-ported to older devices such as NanoS+ and NanoX (but
not NanoS) to ease interface flow development.

Page
In the :term:`Stax` SDK, a **Page** refers to a specific displayed Stax
screen.A welcome page, a setting page are example of Pages. This name is
Expand Down Expand Up @@ -131,8 +132,8 @@ Glossary
allowing to easily control and communicate with said emulator.

Stax
**Stax** is the latest Ledger device which, in a programmatic point of
view, mostly differs from previous devices by its richer UI and a touch
**Stax** is the most premium Ledger device which, in a programmatic point
of view, mostly differs from previous devices by its richer UI and a touch
screen, justifying the usage of the new graphic library, :term:`NBGL`.

Use Case
Expand Down
2 changes: 1 addition & 1 deletion doc/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ The Ragger framework

``Ragger`` is a Python framework which aims at simplifying the test and overall
automatic manipulation of applications running on Ledger devices: NanoS, NanoS+,
NanoX and Stax (sometimes referred as Fatstacks in the sources).
NanoX, Stax and Flex.

It is composed of a tiny wrapper around other Ledger's libraries which abstract
and/or provide access to Ledger's cold wallet, and higher-level classes allowing
Expand Down
26 changes: 13 additions & 13 deletions doc/rationale.rst
Original file line number Diff line number Diff line change
Expand Up @@ -96,24 +96,24 @@ it helps a lot to write code which on the first hand manipulate high-level
concept as validating a transaction, and on the other hand deal with low-level
details such as crafting an :term:`APDU` and click on a button at the right time.

Stax screen management
----------------------
Touch screen management
-----------------------

Dealing with UI and user interaction is never simple. Nano devices has only two
user physical inputs, through the two buttons, which already allows some
elaborate combinations that could be challenging to test automatically.

With the Stax device and its touchable screen, the number of possibilities
With the touchable screens of Stax or Flex devices, the number of possibilities
drastically increases.

``Ragger`` embeds tools allowing to ease the development and the maintenance of
UI clients. this tools mainly consist of 3 components:

- the :py:class:`layout classes <ragger.firmware.stax.layouts>`, representing
- the :py:class:`layout classes <ragger.firmware.touch.layouts>`, representing
the layouts proposed in the NBGL section of the C SDK,
- the :py:class:`use cases classes <ragger.firmware.stax.use_cases>`,
- the :py:class:`use cases classes <ragger.firmware.touch.use_cases>`,
representing the use cases proposed in the NBGL section of the C SDK,
- the :py:mod:`screen module <ragger.firmware.stax.screen>`, allowing to nest
- the :py:mod:`screen module <ragger.firmware.touch.screen>`, allowing to nest
the previous components in a single, centralized object.

.. note::
Expand All @@ -127,7 +127,7 @@ These components bring multiple benefits:

- these abstractions prevent to directly use ``(X, Y)`` coordinates to interact
with the screen and propose higher-level methods (for instance, when using the
:py:class:`UseCaseHome <ragger.firmware.stax.use_cases.UseCaseHome>` use case,
:py:class:`UseCaseHome <ragger.firmware.touch.use_cases.UseCaseHome>` use case,
going to the settings is triggered with the method ``UseCaseHome.settings()``
instead of touching the screen at ``(342, 55)``). The client's code is
meaningful.
Expand All @@ -137,14 +137,14 @@ These components bring multiple benefits:
- the :term:`layouts <Layout>` and :term:`use cases <Use Case>` mimic the
:term:`NBGL` capabilities, so that the ``Ragger`` client screen architecture
is close to the application one.
- the :py:class:`FullScreen <ragger.firmware.stax.screen.FullScreen>` class
embeds every existing :py:class:`layout <ragger.firmware.stax.layouts>` and
:py:class:`use case <ragger.firmware.stax.use_cases>` in a single class,
- the :py:class:`FullScreen <ragger.firmware.touch.screen.FullScreen>` class
embeds every existing :py:class:`layout <ragger.firmware.touch.layouts>` and
:py:class:`use case <ragger.firmware.touch.use_cases>` in a single class,
providing a fast way of testing an interface without any other configuration.
- the :py:class:`MetaScreen <ragger.firmware.stax.screen.MetaScreen>` metaclass
- the :py:class:`MetaScreen <ragger.firmware.touch.screen.MetaScreen>` metaclass
allows to build custom screen classes nesting the
:py:class:`layouts <ragger.firmware.stax.layouts>` and the
:py:class:`use cases <ragger.firmware.stax.use_cases>` of your choosing,
:py:class:`layouts <ragger.firmware.touch.layouts>` and the
:py:class:`use cases <ragger.firmware.touch.use_cases>` of your choosing,
creating a convenient and meaningful screen object where all UI interactions
are centralized.

Expand Down
16 changes: 9 additions & 7 deletions doc/source.rst
Original file line number Diff line number Diff line change
Expand Up @@ -72,27 +72,29 @@ should expect. This is declared with this class:

.. autoattribute:: STAX

.. autoattribute:: FLEX

``ragger.firmware.stax``

``ragger.firmware.touch``
++++++++++++++++++++++++

``ragger.firmware.stax.screen``
``ragger.firmware.touch.screen``
'''''''''''''''''''''''''''''''

.. automodule:: ragger.firmware.stax.screen
.. automodule:: ragger.firmware.touch.screen
:members:

``ragger.firmware.stax.layouts``
``ragger.firmware.touch.layouts``
'''''''''''''''''''''''''''''''''

.. automodule:: ragger.firmware.stax.layouts
.. automodule:: ragger.firmware.touch.layouts
:members:
:undoc-members:

``ragger.firmware.stax.use_cases``
``ragger.firmware.touch.use_cases``
''''''''''''''''''''''''''''''''''

.. automodule:: ragger.firmware.stax.use_cases
.. automodule:: ragger.firmware.touch.use_cases
:members:
:undoc-members:

Expand Down
30 changes: 15 additions & 15 deletions doc/tutorial_screen.rst
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
.. _tutorial_screen:

Complex UI management - Stax
============================
Complex UI management - Flex / Stax
===================================

Interacting programmatically with an application tends to be a non-trivial
thing, as complex processes (like performing a complete transaction) have to be
Expand All @@ -16,8 +16,8 @@ specifically about the UI, we saw :ref:`previously
to cope with simple physical interactions (like on the Nano devices: only two
buttons). But what to do with more complex interfaces?

In particular, interacting with the Stax screen can be bothersome. It is hard to
track of button positions, pages layouts and such.
In particular, interacting with the touch screen devices (Stax or Flex) can be
bothersome. It is hard to track of button positions, pages layouts and such.

Study case
----------
Expand Down Expand Up @@ -66,26 +66,26 @@ to change some button position, or if higher-level graphic objects (such as
the "info" button to the top left -, all this code becomes deprecated.


That's why ``Ragger`` mimics the Stax SDK graphics library and provides
That's why ``Ragger`` mimics the Flex/Stax SDK graphics library and provides
:term:`Layout` and :term:`Use Case` (:term:`Page` will also come soon) classes
that keep track of every interactive screen elements and expose meaningful
methods to interact with them.

Layouts
'''''''

``Ragger``'s :mod:`Layouts <ragger.firmware.stax.layouts>` and
:mod:`UseCases <ragger.firmware.stax.use_cases>` allows to quickly describe an
``Ragger``'s :mod:`Layouts <ragger.firmware.touch.layouts>` and
:mod:`UseCases <ragger.firmware.touch.use_cases>` allows to quickly describe an
application screens and its attached behavior in a purely declarative way,
thanks to the :class:`MetaScreen <ragger.firmware.stax.screen.MetaScreen>`
thanks to the :class:`MetaScreen <ragger.firmware.touch.screen.MetaScreen>`
metaclass. For instance, with the previously described application:

.. code-block:: python
:linenos:
from ragger.firmware.stax.screen import MetaScreen
from ragger.firmware.stax.layouts import CancelFooter, ExitFooter, InfoHeader
from ragger.firmware.touch.screen import MetaScreen
from ragger.firmware.touch.layouts import CancelFooter, ExitFooter, InfoHeader
class RecoveryAppScreen(metaclass=MetaScreen)
layout_quit = ExitFooter
Expand Down Expand Up @@ -131,7 +131,7 @@ way than if positions were still necessary:
First of all, the buttons may be at the same place, but they don't carry the
same purpose, and it is a good idea to reflect that on the code.

Second, if in a future version the Stax design changes and one of these
Second, if in a future version the Flex/Stax design changes and one of these
button moves somewhere else on the screen's footer, **the layouts will be
updated accordingly** in ``Ragger``, and the ``CancelFooter`` or ``ExitFooter``
will still be valid, hence all code using this class remains valid too.
Expand Down Expand Up @@ -163,8 +163,8 @@ and start with ``use_case_``:
.. code-block:: python
:linenos:
from ragger.firmware.stax.screen import MetaScreen
from ragger.firmware.stax.use_case import UseCaseHome, UseCaseSettings
from ragger.firmware.touch.screen import MetaScreen
from ragger.firmware.touch.use_case import UseCaseHome, UseCaseSettings
class RecoveryAppScreen(metaclass=MetaScreen)
use_case_welcome = UseCaseHome
Expand Down Expand Up @@ -198,7 +198,7 @@ All-in-one solution: the ``FullScreen``
All these classes helps you tailoring a fairly elegant and straight-forward
client with meaningful and easy to write screen controls. However if you don't
feel like crafting you own screen representation, ``Ragger`` comes with a
:class:`FullScreen <ragger.firmware.stax.screen.FullScreen>` class
:class:`FullScreen <ragger.firmware.touch.screen.FullScreen>` class
which embeds every existing :term:`Layout` and :term:`Use Case`.

It can be used to quickly instantiate a screen which could work with any
Expand All @@ -209,7 +209,7 @@ application screen, as declared button can be totally fictional.
.. code-block:: python
:linenos:
from ragger.firmware.stax.screen import FullScreen
from ragger.firmware.touch.screen import FullScreen
screen = FullScreen(backend, firmware)
Expand Down
7 changes: 4 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ requires-python = ">=3.8"
dependencies = [
"bip_utils>=2.4.0",
"py-sr25519-bindings>=0.2.0,<0.3.0",
"ledgered>=0.5.0",
"ledgered>=0.6.3",
]
dynamic = ["version"]

Expand All @@ -47,6 +47,7 @@ checkers = [
"flake8",
"flake8-pyproject",
"mypy",
"types-toml",
"bandit",
"pyqt5-stubs",
]
Expand All @@ -62,7 +63,7 @@ doc = [
"docutils==0.16",
]
speculos = [
"speculos>=0.5.1",
"speculos>=0.8.5",
"mnemonic",
]
ledgercomm = [
Expand Down Expand Up @@ -113,4 +114,4 @@ exclude_lines = [
]

[tool.flake8]
max-line-length = 120
max-line-length = 120
2 changes: 1 addition & 1 deletion src/ragger/backend/speculos.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ def _retrieve_client_screen_content(self) -> dict:
raw_content = self._client.get_current_screen_content()
# Keep only text events
# This removes events such as: {'text': ' ', 'x': 0, 'y': 464}
# They probably comes from long press progress bar on Stax
# They probably comes from long press progress bar on Stax/Flex
# and if not removed they falsely make wait_for_screen_change
# consider screen as changed when screen text didn't and that's
# what we want here.
Expand Down
9 changes: 5 additions & 4 deletions src/ragger/conftest/base_conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from ledgered.manifest import Manifest
from ragger.firmware import Firmware
from ragger.backend import SpeculosBackend, LedgerCommBackend, LedgerWalletBackend
from ragger.navigator import NanoNavigator, StaxNavigator, NavigateWithScenario
from ragger.navigator import NanoNavigator, TouchNavigator, NavigateWithScenario
from ragger.utils import find_project_root_dir, find_library_application, find_application
from ragger.utils.misc import get_current_app_name_and_version, exit_current_app, open_app_from_dashboard
from ragger.logger import get_default_logger
Expand All @@ -14,13 +14,14 @@

BACKENDS = ["speculos", "ledgercomm", "ledgerwallet"]

DEVICES = ["nanos", "nanox", "nanosp", "stax", "all", "all_nano"]
DEVICES = ["nanos", "nanox", "nanosp", "stax", "flex", "all", "all_nano"]

FIRMWARES = [
Firmware.NANOS,
Firmware.NANOSP,
Firmware.NANOX,
Firmware.STAX,
Firmware.FLEX,
]


Expand Down Expand Up @@ -218,8 +219,8 @@ def navigator(backend, firmware, golden_run):
return NanoNavigator(backend, firmware, golden_run)
else:
# `firmware` fixture is generated by `pytest_generate_tests`, which controls it against the
# `FIRMWARES` list. So by design, if the firmware is not a Nano, it is a Stax
return StaxNavigator(backend, firmware, golden_run)
# `FIRMWARES` list. So by design, if the firmware is not a Nano, it is either Stax or Flex
return TouchNavigator(backend, firmware, golden_run)


@pytest.fixture(scope="function")
Expand Down
Loading

0 comments on commit 928ce2b

Please sign in to comment.