SFT-7945: test suite working in devshell, removed unused translation
What changed, and why it matters
This commit is a routine cleanup and test-infrastructure change. It removes an unused translation system (translation files, imports, and a test), updates linting rules to no longer exclude the now-removed translation folder, and fixes the test runner path and simulator fixture reliability. There is no security-relevant behavior change in the firmware itself.
No security action required. Treat as normal maintenance.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The diff deletes the translations package (init.py, en.py, tags.py), removes all from translations import t, T imports from flow modules, drops the translation freeze entry from manifest.py, removes the translation test, and adjusts pycodestyle exclusions. It also updates Justfile test command pathing and improves simulator.py socket connection error handling with a 10-second timeout and process-exit detection. No cryptographic, authentication, or sensitive-data-handling code is modified.
Changed components
Build/test infrastructureLinting configurationSimulator test fixtureTranslation subsystem (removed)Inspect captured patch +25 / −214
### .github/workflows/lint.yaml
@@ -55,7 +55,7 @@ jobs:
steps:
- uses: actions/checkout@v6
- run: sudo apt-get install -y pycodestyle
- - run: pycodestyle --statistics --exclude translations ports/stm32/boards/Passport
+ - run: pycodestyle --statistics ports/stm32/boards/Passport
is-foundation-header-up-to-date:
name: Is foundation.h header file up to date?
### Justfile
@@ -72,7 +72,7 @@ sim screen="mono" ext="":
# Run unit tests.
test:
just simulator/build color
- cd ports/stm32/boards/Passport/modules/tests; python3 -m pytest . --simulatordir=$(pwd)/simulator
+ cd ports/stm32/boards/Passport/modules/tests && python3 -m pytest . --simulatordir=$(pwd)/../../../../../../simulator
# Lint the codebase.
lint: (run-in-docker "just ports/stm32/lint") (run-in-docker "just extmod/foundation-rust/lint")
### flake.nix
@@ -125,9 +125,15 @@
openssl
pkg-config
python3
+ python3Packages.autopep8
+ python3Packages.imageio
+ python3Packages.opencv4
python3Packages.pip
+ python3Packages.pillow
+ python3Packages.pytest
+ python3Packages.pysdl2
python3Packages.virtualenv
- python3Packages.autopep8
+ SDL2
reuse
rust-cbindgen
xterm
@@ -145,7 +151,6 @@
fontmiscmisc
minicom
openocd
- SDL2
]);
### ports/stm32/Justfile
@@ -48,7 +48,7 @@ init-openocd:
# Lint only the python code of the project
lint-py:
- pycodestyle --exclude trezor-firmware,unused_modules,graphics.py,translations --statistics boards/Passport
+ pycodestyle --exclude trezor-firmware,unused_modules,graphics.py --statistics boards/Passport
# Lint only the C code of the project
lint-c:
### ports/stm32/boards/Passport/manifest.py
@@ -290,12 +290,6 @@
'tasks/verify_backup_task.py',
'tasks/verify_firmware_signature_task.py'))
-# Translations
-freeze('$(MPY_DIR)/ports/stm32/boards/Passport/modules',
- ('translations/__init__.py',
- 'translations/en.py',
- 'translations/tags.py'))
-
# UI
freeze('$(MPY_DIR)/ports/stm32/boards/Passport/modules',
('ui/__init__.py',
### ports/stm32/boards/Passport/modules/flows/change_pin_flow.py
@@ -7,7 +7,6 @@
from pages import PINEntryPage, ErrorPage, SuccessPage
from tasks import change_pin_task
from utils import spinner_task
-from translations import t, T
import microns
from common import settings
from serializations import sha256
### ports/stm32/boards/Passport/modules/flows/delete_account_flow.py
@@ -8,7 +8,6 @@
from pages import ErrorPage, SuccessPage, QuestionPage, ErrorPage
from tasks import delete_account_task
from utils import spinner_task
-from translations import t, T
class DeleteAccountFlow(Flow):
### ports/stm32/boards/Passport/modules/flows/delete_multisig_flow.py
@@ -4,7 +4,6 @@
# delete_multisig_flow.py - Delete the specified multisig config
from flows import Flow
-from translations import t, T
class DeleteMultisigFlow(Flow):
### ports/stm32/boards/Passport/modules/flows/erase_passport_flow.py
@@ -9,7 +9,6 @@
from pages import SuccessPage, QuestionPage, LongQuestionPage
from tasks import erase_passport_task
from utils import spinner_task
-from translations import t, T
import microns
import passport
### ports/stm32/boards/Passport/modules/flows/new_account_flow.py
@@ -9,7 +9,6 @@
from pages import ErrorPage, SuccessPage, TextInputPage, ErrorPage
from tasks import save_new_account_task
from utils import get_account_by_name, get_account_by_number, get_accounts_by_xfp, spinner_task
-from translations import t, T
from wallets.utils import get_next_account_num
from common import settings
### ports/stm32/boards/Passport/modules/flows/new_seed_flow.py
@@ -7,7 +7,6 @@
from pages import ErrorPage, QuestionPage, SuccessPage, YesNoChooserPage
from tasks import new_seed_task, save_seed_task
from utils import has_secrets, spinner_task
-from translations import t, T
import lvgl as lv
import microns
### ports/stm32/boards/Passport/modules/flows/rename_account_flow.py
@@ -9,7 +9,6 @@
from pages import ErrorPage, SuccessPage, TextInputPage, ErrorPage
from tasks import rename_account_task
from utils import get_account_by_name, spinner_task
-from translations import t, T
class RenameAccountFlow(Flow):
### ports/stm32/boards/Passport/modules/flows/rename_multisig_flow.py
@@ -5,7 +5,6 @@
from flows import Flow
import microns
-from translations import t, T
class RenameMultisigFlow(Flow):
### ports/stm32/boards/Passport/modules/main.py
@@ -15,7 +15,6 @@
import gc
from utils import mem_info
-# from translations import T, t, set_active_language
mem_info(label='Start main.py:')
### ports/stm32/boards/Passport/modules/tests/fixtures/simulator.py
@@ -4,6 +4,8 @@
import pytest
import os
+import signal
+import time
class SimulatorSocket:
@@ -26,12 +28,21 @@ def _connect(self):
import tempfile
self.pipe = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
+ deadline = time.monotonic() + 10
while True:
try:
self.pipe.connect(self.UNIX_SOCKET_PATH)
break
- except Exception:
- continue
+ except OSError:
+ if self.process.poll() is not None:
+ raise RuntimeError(
+ 'Simulator exited before opening its socket '
+ f'(exit code {self.process.returncode})'
+ )
+ if time.monotonic() >= deadline:
+ os.killpg(os.getpgid(self.process.pid), signal.SIGTERM)
+ raise TimeoutError('Simulator did not open its socket within 10 seconds')
+ time.sleep(0.01)
while True:
try:
@@ -46,8 +57,6 @@ def _connect(self):
# Close the connection and kill the simulator process.
def close(self):
- import signal
-
self.pipe.close()
os.killpg(os.getpgid(self.process.pid), signal.SIGTERM)
### ports/stm32/boards/Passport/modules/tests/test_translations.py
@@ -1,51 +0,0 @@
-# SPDX-FileCopyrightText: © 2021 Foundation Devices, Inc. <hello@foundation.xyz>
-#
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-# Test that the translation module works.
-
-import sys
-import os
-
-sys.path.insert(1, os.path.join(sys.path[0], '..'))
-
-
-def test_change_active_language():
- from translations import t, T, set_active_language, get_active_language
-
- assert set_active_language('en')
- assert get_active_language() == 'en'
-
- # The value of these messages will be always these so we can reliably test
- # here if a basic Yes/No is translated.
- #
- # NOTE: If these values are changed on the translations please update this
- # test!
- assert t(T.DEFAULT_YES_BUTTON_LABEL) == "Yes"
- assert t(T.DEFAULT_NO_BUTTON_LABEL) == "No"
-
- assert set_active_language('es')
- assert get_active_language() == 'es'
-
- assert t(T.DEFAULT_YES_BUTTON_LABEL) == "Sí"
- assert t(T.DEFAULT_NO_BUTTON_LABEL) == "No"
-
- # Restore it.
- assert set_active_language('en')
-
-
-def test_fallback_works():
- from translations import t, T, set_active_language
-
- # Verify that messages that don't need to be translated for some languages
- # correctly fall back to the original english translation (this avoid duplicate
- # strings).
- #
- # NOTE: If ever FOUNDATION_CO is translated to spanish update this test.
- assert set_active_language('es')
- foundation_co_es = t(T.FOUNDATION_CO)
-
- assert set_active_language('en')
- foundation_co_en = t(T.FOUNDATION_CO)
-
- assert foundation_co_es == foundation_co_en
### ports/stm32/boards/Passport/modules/tests/unit/foundation.py
@@ -22,8 +22,8 @@ def should_fail(f):
should_fail(lambda: foundation.qr.init())
-should_fail(lambda: foundation.qr.init(None, None, None))
-foundation.qr.init(HOR_RES, VER_RES, bytearray(HOR_RES * VER_RES))
+should_fail(lambda: foundation.qr.init(None, None))
+foundation.qr.init(HOR_RES, VER_RES)
should_fail(lambda: foundation.convert_rgb565_to_grayscale())
should_fail(lambda: foundation.convert_rgb565_to_grayscale(None, None, None, None))
### ports/stm32/boards/Passport/modules/translations/__init__.py
@@ -1,53 +0,0 @@
-# SPDX-FileCopyrightText: © 2021 Foundation Devices, Inc. <hello@foundation.xyz>
-#
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-# translations.py
-#
-# Multi-language text utility functions
-#
-
-from .tags import T as _T
-from .en import EN_TRANSLATIONS
-
-ACTIVE_LANGUAGE = 'en'
-TRANSLATIONS = {
- 'en': EN_TRANSLATIONS,
-}
-
-
-def t(tag, **kwargs):
- translations = TRANSLATIONS[ACTIVE_LANGUAGE]
- if tag in translations:
- str = translations[tag]
- elif tag in EN_TRANSLATIONS:
- str = EN_TRANSLATIONS[tag]
- else:
- # Error
- return '<UNKNOWN TEXT>'
-
- if kwargs is not None:
- return str.format(**kwargs)
- else:
- return str
-
-
-# Get the global active language.
-def get_active_language():
- return ACTIVE_LANGUAGE
-
-
-# Set the global active language.
-def set_active_language(language):
- global ACTIVE_LANGUAGE
-
- # Verify that the requsted language is supported
- if language in TRANSLATIONS.keys():
- ACTIVE_LANGUAGE = language
- return True
-
- return False
-
-
-# Re-export the tags
-T = _T
### ports/stm32/boards/Passport/modules/translations/en.py
@@ -1,42 +0,0 @@
-# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. <hello@foundation.xyz>
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-# en.py - String translations for EN language code
-#
-# AUTOGENERATED FILE! DO NOT EDIT MANUALLY!
-#
-
-from .tags import T
-
-EN_TRANSLATIONS = {
- T.import_pp_intro_card1_heading: '''Pair Passport with Envoy''',
- T.import_pp_intro_card1_subheading: '''On Passport, select Pair Wallet > Envoy''',
- T.import_pp_intro_card2_subheading: '''If you want to use Envoy for firmware updates only, feel free to skip this step.''',
- T.import_pp_intro_cta: '''Get Started''',
- T.import_pp_intro_os_clock: '''9:41''',
- T.import_pp_intro_right_action: '''Skip''',
- T.import_pp_scan_cta: '''Continue''',
- T.import_pp_scan_heading: '''Scan the QR code that Passport generates''',
- T.import_pp_scan_os_clock: '''9:41''',
- T.import_pp_scan_right_action: '''Skip''',
- T.import_pp_scan_subheading: '''This QR code contains the information required for Envoy to interact securley with Passport.''',
- T.wallet_address_verify_confirm_cta: '''Continue''',
- T.wallet_address_verify_confirm_cta1: '''Contact support''',
- T.wallet_address_verify_confirm_heading: '''Address Validated?''',
- T.wallet_address_verify_confirm_os_clock: '''9:41''',
- T.wallet_address_verify_confirm_right_action: '''Skip''',
- T.wallet_address_verify_confirm_subheading: '''If you get a success message on Passport, your setup is now complete.
-
-If Passport could not verify the address, please try again or contact support.''',
- T.wallet_address_verify_cta: '''Continue''',
- T.wallet_address_verify_heading: '''Scan this QR code with Passport to validate''',
- T.wallet_address_verify_os_clock: '''9:41''',
- T.wallet_address_verify_right_action: '''Skip''',
- T.wallet_address_verify_subheading: '''This is the first receive address controlled by your Passport.''',
- T.wallet_pair_success_cta: '''Validate Receiving address''',
- T.wallet_pair_success_cta1: '''Continue to home screen''',
- T.wallet_pair_success_heading: '''Connection successful''',
- T.wallet_pair_success_os_clock: '''9:41''',
- T.wallet_pair_success_right_action: '''Skip''',
- T.wallet_pair_success_subheading: '''Envoy has the information required to generate addresses and construct transactions for Passport. You can validate this on the following screen or skip straight to home''',
-}
### ports/stm32/boards/Passport/modules/translations/tags.py
@@ -1,42 +0,0 @@
-# SPDX-FileCopyrightText: © 2022 Foundation Devices, Inc. <hello@foundation.xyz>
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-# tags.py
-#
-# Text tag names used in all translation files.
-#
-# AUTOGENERATED FILE! DO NOT EDIT MANUALLY!
-#
-
-from Enum import enum
-
-T = enum(
- 'import_pp_intro_card1_heading',
- 'import_pp_intro_card1_subheading',
- 'import_pp_intro_card2_subheading',
- 'import_pp_intro_cta',
- 'import_pp_intro_os_clock',
- 'import_pp_intro_right_action',
- 'import_pp_scan_cta',
- 'import_pp_scan_heading',
- 'import_pp_scan_os_clock',
- 'import_pp_scan_right_action',
- 'import_pp_scan_subheading',
- 'wallet_address_verify_confirm_cta',
- 'wallet_address_verify_confirm_cta1',
- 'wallet_address_verify_confirm_heading',
- 'wallet_address_verify_confirm_os_clock',
- 'wallet_address_verify_confirm_right_action',
- 'wallet_address_verify_confirm_subheading',
- 'wallet_address_verify_cta',
- 'wallet_address_verify_heading',
- 'wallet_address_verify_os_clock',
- 'wallet_address_verify_right_action',
- 'wallet_address_verify_subheading',
- 'wallet_pair_success_cta',
- 'wallet_pair_success_cta1',
- 'wallet_pair_success_heading',
- 'wallet_pair_success_os_clock',
- 'wallet_pair_success_right_action',
- 'wallet_pair_success_subheading',
-)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.