Sync upstream (0.8.7)#371
Open
3rdIteration wants to merge 294 commits into
Open
Conversation
Update instances of 0.8.5 to 0.8.6
[Enhancement] Add support for BBQr PSBT decoding
Update encode_qr.py - Adds comments to code (Fixes SeedSigner#582)
Resolves issue 678 - Clean up else condition to catch ALL remaining possibilities
…r-docs [Documentation] Clarify that SeedQR uses English BIP39 wordlist
[CI Fix] Modify CI to run test checks on all commits
…ng-software-docs [Documentation] Mention `--ignore-missing` flag issue on older macOS versions
…ing-spinner [Feature] Added 'Calculating...' spinner while generating seed from Image Entropy
Use PyPI version for urtypes lib
[l10n] Move Italian to the "Fully supported languages" list
[l10n] Remove libraqm workarounds and enforce libraqm dependency
Co-authored-by: notTanveer <101289209+notTanveer@users.noreply.github.com>
Disables the screensaver entirely while the SeedQR transcription routine is active. Any view can be configured to allow or disallow screensaver activation.
…to is_screensaver_start_allowed
…s when the current view is SeedTranscribeSeedQRZoomedInView
…ranslations-submodule Update seedsigner-translations submodule to latest dev (708961)
[Bugfix] Back Navigation in Seed Entry Views
Add pythonpath=["src"] to pyproject.toml and remove redundant pip install . from CI workflow. Rework view imports and exports so internal helpers (including underscore-prefixed symbols and shared TextQR/BIP85 helpers) are explicitly re-exported from tools_views for backward compatibility. Propagate shared helpers across gpg_views, password_generator_views, and smartcard_views (also fix a logging call and add hmac, seedkeeper utils, and seed-related imports). Update tests to patch the appropriate modules (smartcard_views and password_generator_views) so monkeypatches target the modules that actually import the helpers.
Add a Testing guidance section to AGENTS.md describing how to run pytest, expected platform-dependent failures, a star-import caveat for underscore-prefixed names, and guidance for adding tests. Re-export _check_future_key_creation from gpg_views in tools_views.py for backward compatibility with tests and callers. Update tests/test_gpg_message.py: improve _msys2_path to detect the installed gpg via shutil.which and only convert Windows paths to MSYS2 style when the GPG binary is from Git-for-Windows/MSYS2, leaving native Gpg4win paths unchanged to avoid writable keyring errors.
Define a MIN_RSA_KEY_BITS = 2048 constant in gpg_views.py (used by bip85_rsa_from_root) to enforce a minimum RSA key size. Update AGENTS.md to refresh the test table (clarify satochip test entry) and adjust the baseline test counts to 716 passing, 134 skipped, 7 failing, noting satochip tests require physical hardware.
Add missing imports and helpers to smartcard_views: binascii (hexlify/unhexlify), embit.descriptor.Descriptor, and embit_utils plus XprvSeed from models. Also reorder/clean imports and expose SeedExportXpubVerifyAddressView. Update unit test to patch HDKey in the smartcard_views module instead of tools_views to match the refactor. These changes prepare the smartcard view code for using embit utilities and the Xprv-backed seed model.
Refactor tests/test_bip85_gpg.py to import and reference seedsigner.views.gpg_views rather than the older tools_views alias. Update monkeypatch.setattr targets, class instantiations, and BIP85_DATA assertions to use gpg_views. Add seed_bytes attribute to test SeedObj classes and make a few related minor adjustments (imports and subprocess/microsd references) to ensure tests target the correct module.
Add multiple .cap applet binaries under javacard-cap/ to ship built applets. Refactor smartcard views: move the GlobalPlatform presence check into the BUILD_APPLETS path and show a clear warning when DIY tools are not available. Rewrite ToolsDIYInstallAppletView to gather .cap files from both the internal repo and the MicroSD javacard-cap directory, merge results, prefix duplicate names with (Internal)/(MicroSD) to disambiguate, and handle missing/unreadable MicroSD gracefully. Also add a docstring and improve selection logging.
Add a new javacard-cap/javacard-cap.sha256 manifest containing SHA256 sums for various CAP files. Update smartcard_views.py to detect the DIY toolchain by checking for the ANT executable path (ant/bin/ant) instead of looking for gp.jar, with host-specific path locations adjusted accordingly and the existence check updated to use the ant path.
Extracts the internal javacard-cap path into a module-level _get_internal_cap_dir() function and updates ToolsDIYInstallAppletView to use it. Tests updated to monkeypatch this helper (and adjust the logger target) so the test suite can isolate from the real filesystem. No behavioral change beyond making the internal cap directory retrieval testable.
# Conflicts: # .github/workflows/telegram.yml
Add robust validation and normalization for Settings QR parsing and multiselect handling (reject empty values, validate against selection_options, support free-text fields, handle legacy formats and restore-default cases). Add new XPUB QR format setting entry. Introduce optional import for pivideostream on platforms where it's available. Add a BaseDisplayDriver and small cleanup in ST7789 driver docstrings. Fix restart logic to call subprocess.call (and import subprocess). Make descriptor views handle single-sig descriptors (show "Single sig" instead of multisig policy). Update tests to flush deferred settings saves to disk before asserting file contents.
There was a problem hiding this comment.
Pull request overview
This PR syncs the SeedSigner codebase to upstream release 0.8.7, including substantial UI wording/i18n updates, new/updated QR and settings behaviors, expanded flow tests, and several infrastructure/documentation changes.
Changes:
- Adds/extends QR handling (e.g., BBQR PSBT support) and updates xpub-export QR format behavior/settings.
- Introduces/updates UI flows and screens (e.g., MicroSD removal blocking flow, screensaver gating, refined PSBT/transaction wording).
- Updates tests, CI/config, and documentation/templates to match upstream structure and conventions.
Reviewed changes
Copilot reviewed 73 out of 89 changed files in this pull request and generated 14 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/test_settingsqr_decoder.py | Refactors SettingsQR decoder test to reuse a shared SettingsQR base. |
| tests/test_settings.py | Adds tests for defaults, persistence load, and multiselect empty handling; introduces SettingsQRBase. |
| tests/test_settings_definition.py | Adjusts imports for updated test needs. |
| tests/test_seedqr.py | Sets ambiguous-QR preference during CompactSeedQR decode tests. |
| tests/test_seedkeeper_install.py | Updates monkeypatching targets after view/module splits. |
| tests/test_password_generator_views.py | Patches split module import site for dice entropy screen. |
| tests/test_javacard_mnemonic_tools.py | Patches both tools_views and smartcard_views after module split. |
| tests/test_gpg_message.py | Improves Windows GNUPG path handling for MSYS2 vs native GPG. |
| tests/test_flows.py | Adds RemoveMicroSDWarning flow test and updates imports/wording. |
| tests/test_flows_view.py | Updates flow tests for camera error view and import changes. |
| tests/test_flows_settings.py | Updates multiselect flow behavior and SettingsQR constants. |
| tests/test_flows_seed.py | Updates seed flows for xpub QR format selection and adds additional navigation tests. |
| tests/test_encodepsbtqr.py | Updates encoder class name for Specter legacy xpub QR encoding. |
| tests/test_embit_utils.py | Adds tests for multisig policy extraction and improves wording. |
| tests/test_controller.py | Updates SettingsConstants import location and default assertions. |
| tests/test_bip85_gpg.py | Updates patch targets to gpg_views and related module splits. |
| tests/screenshot_generator/utils.py | Adds screenshot-generator renderer flags and mock context manager support. |
| tests/base.py | Updates test environment mocking to accommodate new modules/features. |
| src/seedsigner/views/view.py | Adds camera-specific error view and MicroSD removal warning view; UI wording tweaks. |
| src/seedsigner/views/settings_views.py | Adds blocking/unblocking navigation logic for setting selection flow. |
| src/seedsigner/views/seed_views.py | Large set of flow/UI changes including xpub export flow changes and screensaver gating. |
| src/seedsigner/views/screensaver.py | Switches splash animation behavior based on screenshot-generator detection. |
| src/seedsigner/views/scan_views.py | Updates PSBT scan wording and unknown QR exit button wording. |
| src/seedsigner/views/psbt_views.py | Renames PSBT terminology to “transaction” across flow and screen strings; minor grammar fixes. |
| src/seedsigner/models/settings.py | Tightens SettingsQR parsing/validation and multiselect normalization; persistence behaviors. |
| src/seedsigner/models/settings_definition.py | Reworks constants/settings entries (xpub QR format setting, MicroSD toast timer, locale detection changes). |
| src/seedsigner/models/qr_type.py | Adds BBQR PSBT QR type. |
| src/seedsigner/models/psbt_parser.py | Adds missing fingerprint fill logic and minor refactors. |
| src/seedsigner/models/encode_qr.py | Renames Specter xpub encoder to legacy and adds alias for compatibility; comments added. |
| src/seedsigner/models/decode_qr.py | Adds BBQR PSBT decoder and segment-type detection; adds debug logging. |
| src/seedsigner/helpers/embit_utils.py | Adds multisig policy extraction helper; minor comment cleanup. |
| src/seedsigner/hardware/displays/ST7789.py | Adds BaseDisplayDriver and documentation tweaks. |
| src/seedsigner/hardware/displays/st7789_mpy.py | Adjusts class definition/inheritance for display driver refactor. |
| src/seedsigner/hardware/displays/ili9341.py | Adjusts class definition/inheritance and renames invert arg for clarity. |
| src/seedsigner/hardware/displays/display_driver.py | Refactors display driver selection/initialization logic. |
| src/seedsigner/hardware/camera.py | Introduces CameraConnectionError and expands cross-platform camera abstraction. |
| src/seedsigner/hardware/init.py | Attempts optional import of pivideostream for platform flexibility. |
| src/seedsigner/gui/toast.py | Adjusts toast rendering behavior and default MicroSD toast duration. |
| src/seedsigner/gui/screens/tools_screens.py | Minor bbox variable name fix and descriptor text cleanup. |
| src/seedsigner/gui/screens/settings_screens.py | Adjusts selection screen behavior for screenshots and checked-selection defaults. |
| src/seedsigner/gui/screens/seed_screens.py | Removes passphrase-related UI variants and adjusts wording/translation notes. |
| src/seedsigner/gui/screens/screen.py | Adds ButtonOptionWithoutTranslation, refines keyboard title updates, and removes some unused screens/flags. |
| src/seedsigner/gui/screens/scan_screens.py | Refactors scan loop and return semantics for cancel behavior. |
| src/seedsigner/gui/screens/psbt_screens.py | Renames PSBT terminology and refines change/receive address display. |
| src/seedsigner/gui/renderer.py | Adds screenshot-generator detection property. |
| src/seedsigner/gui/keyboard.py | Removes unused key definitions/fields and simplifies keyboard input signature. |
| src/seedsigner/controller.py | Adds raqm availability warning, import timing tweaks, and screensaver gating property. |
| README.md | Updates wording and release version references for downloads/verification. |
| pyproject.toml | Bumps version to 0.8.7; updates coverage omit list and pytest pythonpath. |
| l10n/requirements-l10n.txt | Adds setuptools requirement for l10n tooling. |
| l10n/messages.pot | Updates translation template strings and copyright year. |
| javacard-cap/javacard-cap.sha256 | Adds checksums for bundled CAP files. |
| docs/usb_relay.md | Improves formatting, code fences, and wording for USB relay instructions. |
| docs/seed_qr/README.md | Clarifies SeedQR assumptions (English wordlist) and improves explanations. |
| docs/raspberry_pi_os_build_instructions.md | Updates USB/WiFi wording and static IP instructions. |
| docs/qr_formats.md | Improves formatting and wording; clarifies supported formats. |
| docs/legacy_hardware.md | Fixes typos and improves clarity. |
| docs/feature_roadmap.md | Fixes wording and formatting. |
| docs/electrum.md | Standardizes title/casing and improves clarity. |
| docs/dice_verification.md | Fixes typos and improves clarity of verification steps. |
| docs/developer_tips.md | Improves instructions formatting and clarity. |
| docs/debug_crash.md | Improves formatting and step clarity. |
| docs/code_structure.md | Improves MVC description and wording. |
| AGENTS.md | Adds explicit test-running guidance and notes on module split caveats. |
| .github/workflows/tests.yml | Adjusts CI triggers and removes pip install . step. |
| .github/workflows/telegram.yml | Removes Telegram notification workflow. |
| .github/pull_request_template.md | Replaces PR template with more structured checklist and sections. |
Comments suppressed due to low confidence (4)
src/seedsigner/controller.py:22
controller.pynow importsSettingsConstantsfrom bothseedsigner.models.settingsandseedsigner.models.settings_definition. The second import overwrites the first, making the added import redundant/confusing and easy to break during future refactors.
from seedsigner.models.settings import Settings
from seedsigner.models.settings import SettingsConstants
from seedsigner.models.singleton import Singleton
from seedsigner.models.threads import BaseThread
from seedsigner.models.settings_definition import SettingsConstants
from seedsigner.views.screensaver import ScreensaverScreen
src/seedsigner/views/seed_views.py:2362
SeedExportXpubCustomDerivationViewroutes toSeedExportXpubQRFormatView, but that class does not exist in this file (the selection view class is stillSeedExportXpubCoordinatorView). As-is, this will raiseNameErrorwhen exporting an xpub with a custom derivation path.
src/seedsigner/views/seed_views.py:2459SeedExportXpubWarningView.run()passesxpub_qr_formatinview_argswhen routing toSeedExportXpubDetailsView, butSeedExportXpubDetailsView.__init__still expectscoordinator(and will raiseTypeError: __init__ got an unexpected keyword argument 'xpub_qr_format').
src/seedsigner/views/seed_views.py:2560- When routing from
SeedExportXpubDetailsViewtoSeedExportXpubQRDisplayView, theview_argskey was changed toxpub_qr_format, butSeedExportXpubQRDisplayView.__init__still expectscoordinator. This will raiseTypeErrorand break the xpub export flow.
Comment on lines
22
to
41
| def __init__(self, display_type: str = DISPLAY_TYPE__ST7789, width: int = None, height: int = None): | ||
| if display_type not in ALL_DISPLAY_TYPES: | ||
| raise ValueError(f"Invalid display type: {display_type}") | ||
| self.display_type = display_type | ||
|
|
||
| if self.display_type == DISPLAY_TYPE__ST7789: | ||
| if display_type == DISPLAY_TYPE__ST7789: | ||
| if width not in [240, 320] or height != 240: | ||
| raise ValueError("ST7789 display only supports 240x240 or 320x240 resolutions") | ||
|
|
||
| if width == 240: | ||
| # TODO: For now the original ST7789 driver has to be used for 240x240. | ||
| # The mpy version below renders incorrectly (almost like each row of pixels | ||
| # is one pixel short, so the entire screen exhibits a diagonal skew). | ||
| from seedsigner.hardware.displays.ST7789 import ST7789 | ||
| self.display = ST7789() | ||
| from seedsigner.hardware.displays.ST7789 import ST7789 as original_ST7789 | ||
| return original_ST7789(_width=width, _height=height) | ||
|
|
||
| elif width == 320: | ||
| from seedsigner.hardware.displays.st7789_mpy import ST7789 | ||
| from seedsigner.hardware.displays.st7789_mpy import ST7789 as mpy_ST7789 | ||
| # Have to swap width and height; screen is natively 240x320 | ||
| self.display = ST7789(width=height, height=width) | ||
|
|
Comment on lines
48
to
+52
| elif self.display_type == DISPLAY_TYPE__ILI9341: | ||
| from seedsigner.hardware.displays.ili9341 import ILI9341 | ||
| self.display = ILI9341() | ||
| self.display.begin() | ||
| display = ILI9341(_width=width, _height=height) | ||
| display.begin() | ||
| return display |
Comment on lines
+235
to
238
| @dataclass | ||
| class ST7789(BaseDisplayDriver): | ||
| """ | ||
| ST7789 driver class |
Comment on lines
+138
to
140
| @dataclass | ||
| class ILI9341(BaseDisplayDriver): | ||
| """Representation of an ILI9341 TFT LCD.""" |
Comment on lines
12
to
+18
| sys.modules['seedsigner.hardware.buttons'] = MagicMock() | ||
| sys.modules['seedsigner.hardware.camera'] = MagicMock() | ||
| sys.modules['seedsigner.hardware.camera.Camera'] = MagicMock() | ||
| # Only mock pivideostream if the real module is unavailable (it's needed for luckfox camera tests) | ||
| try: | ||
| __import__("seedsigner.hardware.pivideostream") | ||
| except ImportError: | ||
| sys.modules['seedsigner.hardware.pivideostream'] = MagicMock() |
Comment on lines
2567
to
2593
| class SeedExportXpubQRDisplayView(View): | ||
| def __init__(self, seed_num: int, coordinator: str, derivation_path: str, sig_type: str = SettingsConstants.SINGLE_SIG, script_type: str = SettingsConstants.NATIVE_SEGWIT, coordinator_label: str = ""): | ||
| super().__init__() | ||
| self.seed = self.controller.get_seed(seed_num) | ||
| self.seed_num = seed_num | ||
| self.script_type = script_type | ||
| self.sig_type = sig_type | ||
| self.derivation_path = derivation_path | ||
| self.coordinator_label = coordinator_label | ||
|
|
||
| encoder_args = dict( | ||
| seed=self.seed, | ||
| derivation=derivation_path, | ||
| network=self.settings.get_value(SettingsConstants.SETTING__NETWORK), | ||
| qr_density=self.settings.get_value(SettingsConstants.SETTING__QR_DENSITY), | ||
| sig_type=sig_type | ||
| ) | ||
|
|
||
| if coordinator == SettingsConstants.COORDINATOR__SPECTER_DESKTOP: | ||
| self.qr_encoder = SpecterXPubQrEncoder(**encoder_args) | ||
|
|
||
| elif coordinator in [SettingsConstants.COORDINATOR__BLUE_WALLET, | ||
| SettingsConstants.COORDINATOR__KEEPER]: | ||
| if xpub_qr_format == SettingsConstants.XPUB_QR_FORMAT__STATIC: | ||
| self.qr_encoder = StaticXpubQrEncoder(**encoder_args) | ||
|
|
||
| elif xpub_qr_format == SettingsConstants.XPUB_QR_FORMAT__SPECTER_LEGACY: | ||
| self.qr_encoder = SpecterLegacyXPubQrEncoder(**encoder_args) | ||
|
|
||
| else: | ||
| # Default: UR crypto-address | ||
| self.qr_encoder = UrXpubQrEncoder(**encoder_args) |
Comment on lines
+384
to
+392
| # If this selection view was opened from a blocking flow (e.g. RemoveMicroSDWarningView), | ||
| # prevent navigation away until the setting actually changes. If it hasn't changed, | ||
| # return to the blocking view so it can re-evaluate the state. | ||
| if self.blocking_view: | ||
| current_value = self.settings.get_value(self.settings_entry.attr_name) | ||
| if current_value == initial_value: | ||
| return Destination(self.blocking_view, clear_history=True) | ||
| elif self.unblocking_view: | ||
| return Destination(self.unblocking_view, clear_history=True) |
Comment on lines
+545
to
+553
| elif button_data[selected_menu_num] == self.SETTINGS: | ||
| from seedsigner.views.settings_views import SettingsEntryUpdateSelectionView | ||
| return Destination( | ||
| SettingsEntryUpdateSelectionView, | ||
| view_args=dict( | ||
| attr_name=SettingsConstants.SETTING__MICROSD_TOAST_TIMER, | ||
| blocking_view=RemoveMicroSDWarningView, | ||
| unblocking_view=MainMenuView | ||
| ) |
Comment on lines
+440
to
+446
| # Treat empty/invalid multiselect values as "restore defaults" | ||
| current_val = new_settings[entry.attr_name] | ||
| if isinstance(current_val, list): | ||
| # Filter out empty strings and whitespace-only entries | ||
| cleaned = [v for v in current_val if isinstance(v, str) is False or v.strip()] | ||
| if len(cleaned) == 0: | ||
| new_settings[entry.attr_name] = entry.default_value |
Comment on lines
+296
to
+301
| # Validate that the value is a recognized option for this setting | ||
| if settings_entry.type != SettingsConstants.TYPE__MULTISELECT: | ||
| if isinstance(value, list): | ||
| raise InvalidSettingsQRData(f"Setting {settings_entry.attr_name} does not accept multiple values") | ||
| if value not in valid_values: | ||
| raise InvalidSettingsQRData(f"Unrecognized option '{value}' for setting {settings_entry.attr_name}") |
Add `from embit.psbt import PSBT` to src/seedsigner/models/encode_qr.py and src/seedsigner/views/smartcard_views.py to enable PSBT handling in QR encoding and smartcard view code paths. Prepares these modules to work with PSBT objects for transaction-related functionality.
Rename and centralize XPUB QR format handling into a "coordinator" concept across seed and smartcard views. seed_views: replace xpub_qr_format variables with coordinator, switch to SETTINGS__XPUB_QR_FORMAT/ALL_XPUB_QR_FORMATS, and use SpecterXPubQrEncoder for the Specter format; adjust QR display and navigation arguments accordingly. smartcard_views: iterate ALL_XPUB_QR_FORMATS and check SETTING__XPUB_QR_FORMAT. settings_views: add a guard to keep the settings menu on-screen for invalid selections and add blocking_view/unblocking_view attributes to SettingsEntryUpdateSelectionView. Update tests to reflect the view and setting renames and the changed behavior. These changes unify naming, prevent invalid selection crashes, and update encoders for the new coordinator model.
Validate comma-separated multiselect values from Settings QR data: accept non-empty strings, split on commas, and verify each option against allowed values (conversion to list happens later in TYPE__MULTISELECT handling). Also extend SettingsEntryUpdateSelectionView to accept and persist blocking_view/unblocking_view parameters, return to the blocking view on BACK, and propagate these parameters when reinvoking the view so blocking flows are preserved.
- Restore special case for persistent_settings=E when only D is allowed (SD card removed), silently coercing to DISABLED instead of raising. - Add screen mocks and fix redirect flags in SeedQR transcribe flow tests.
…seScreen._run() The _run() loop always started with the lowercase letter keyboard regardless of which keyboard was rendered initially, causing arrow key navigation to operate on a hidden letter overlay instead of the visible digits keyboard. Also pass initial_keyboard='123' to all PIN/PUK entry screens so they start on digits.
…PassphraseScreen._run()" This reverts commit 7367617.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Describe the change simply. Provide a reason for the change.
Include screenshots of any new or modified screens (or at least explain why they were omitted)
This pull request is categorized as a:
Checklist
pytestand made sure all unit tests pass before sumbitting the PRIf you modified or added functionality/workflow, did you add new unit tests?
I have tested this PR on the following platforms/os:
Note: Keep your changes limited in scope; if you uncover other issues or improvements along the way, ideally submit those as a separate PR. The more complicated the PR the harder to review, test, and merge.