test(core): test backup cancellation during `ResetDevice`
What changed, and why it matters
This commit only adds new automated tests that simulate a user cancelling the backup step during device setup (ResetDevice). It does not change the actual Trezor firmware code, wallet logic, or fix any bug. It is a testing improvement with no direct security impact on shipped devices.
No action required; this is a test-only change. Review the new test coverage as part of normal QA if desired.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The diff extends three existing Python test suites for BIP-39 and SLIP-39 reset/recovery flows. It parameterises tests with two flow adapters: a normal flow and a try_to_cancel adapter that attempts to cancel at specific UI states (setup_device, confirm_setup_device, backup_device, success_backup). No production firmware, bootloader, or communication code is modified.
Changed components
tests/device_tests/reset_recovery/test_reset_bip39_t2.pytests/device_tests/reset_recovery/test_reset_slip39_advanced.pytests/device_tests/reset_recovery/test_reset_slip39_basic.pyInspect captured patch +59 / −18
diff --git a/tests/device_tests/reset_recovery/test_reset_bip39_t2.py b/tests/device_tests/reset_recovery/test_reset_bip39_t2.py
index 4c87900b..0ed1c583 100644
--- a/tests/device_tests/reset_recovery/test_reset_bip39_t2.py
+++ b/tests/device_tests/reset_recovery/test_reset_bip39_t2.py
@@ -25,19 +25,34 @@ from trezorlib.exceptions import TrezorFailure
from ...common import EXTERNAL_ENTROPY, MNEMONIC12, MOCK_GET_ENTROPY, generate_entropy
from ...input_flows import (
+ FlowAdapter,
InputFlowBip39ResetBackup,
InputFlowBip39ResetFailedCheck,
InputFlowBip39ResetPIN,
+ normal,
+ try_to_cancel,
)
pytestmark = pytest.mark.models("core")
+FLOW_ADAPTERS = [
+ normal,
+ try_to_cancel(
+ {
+ "setup_device",
+ "confirm_setup_device",
+ "backup_device",
+ "success_backup",
+ }
+ ),
+]
-def reset_device(session: Session, strength: int):
+
+def reset_device(session: Session, strength: int, adapt_flow: FlowAdapter):
debug = session.debug
with session.test_ctx as client:
IF = InputFlowBip39ResetBackup(session)
- client.set_input_flow(IF.get())
+ client.set_input_flow(adapt_flow(session, IF.get()))
# No PIN, no passphrase, don't display random
device.setup(
@@ -76,13 +91,15 @@ def reset_device(session: Session, strength: int):
@pytest.mark.setup_client(uninitialized=True)
-def test_reset_device(session: Session):
- reset_device(session, 128) # 12 words
+@pytest.mark.parametrize("adapt_flow", FLOW_ADAPTERS, ids=lambda f: f.__name__)
+def test_reset_device(session: Session, adapt_flow: FlowAdapter):
+ reset_device(session, 128, adapt_flow) # 12 words
@pytest.mark.setup_client(uninitialized=True)
-def test_reset_device_192(session: Session):
- reset_device(session, 192) # 18 words
+@pytest.mark.parametrize("adapt_flow", FLOW_ADAPTERS, ids=lambda f: f.__name__)
+def test_reset_device_192(session: Session, adapt_flow: FlowAdapter):
+ reset_device(session, 192, adapt_flow) # 18 words
@pytest.mark.setup_client(uninitialized=True)
diff --git a/tests/device_tests/reset_recovery/test_reset_slip39_advanced.py b/tests/device_tests/reset_recovery/test_reset_slip39_advanced.py
index c997cd4a..ca658073 100644
--- a/tests/device_tests/reset_recovery/test_reset_slip39_advanced.py
+++ b/tests/device_tests/reset_recovery/test_reset_slip39_advanced.py
@@ -23,21 +23,32 @@ from trezorlib.exceptions import TrezorFailure
from trezorlib.messages import BackupAvailability, BackupType
from ...common import EXTERNAL_ENTROPY, MOCK_GET_ENTROPY, generate_entropy
-from ...input_flows import InputFlowSlip39AdvancedResetRecovery
+from ...input_flows import (
+ FlowAdapter,
+ InputFlowSlip39AdvancedResetRecovery,
+ normal,
+ try_to_cancel,
+)
pytestmark = pytest.mark.models("core")
+FLOW_ADAPTERS = [
+ normal,
+ try_to_cancel({"backup_device", "setup_device", "success_backup"}),
+]
+
# TODO: test with different options
@pytest.mark.setup_client(uninitialized=True)
-def test_reset_device_slip39_advanced(client: Client):
+@pytest.mark.parametrize("adapt_flow", FLOW_ADAPTERS, ids=lambda f: f.__name__)
+def test_reset_device_slip39_advanced(client: Client, adapt_flow: FlowAdapter):
strength = 128
member_threshold = 3
session = client.get_seedless_session()
with session.test_ctx as client:
IF = InputFlowSlip39AdvancedResetRecovery(client, False)
- client.set_input_flow(IF.get())
+ client.set_input_flow(adapt_flow(session, IF.get()))
# No PIN, no passphrase, don't display random
device.setup(
session,
diff --git a/tests/device_tests/reset_recovery/test_reset_slip39_basic.py b/tests/device_tests/reset_recovery/test_reset_slip39_basic.py
index efe02911..f9b72c59 100644
--- a/tests/device_tests/reset_recovery/test_reset_slip39_basic.py
+++ b/tests/device_tests/reset_recovery/test_reset_slip39_basic.py
@@ -26,17 +26,27 @@ from trezorlib.exceptions import TrezorFailure
from trezorlib.messages import BackupAvailability, BackupType
from ...common import EXTERNAL_ENTROPY, MOCK_GET_ENTROPY, generate_entropy
-from ...input_flows import InputFlowSlip39BasicResetRecovery
+from ...input_flows import (
+ FlowAdapter,
+ InputFlowSlip39BasicResetRecovery,
+ normal,
+ try_to_cancel,
+)
pytestmark = pytest.mark.models("core")
+FLOW_ADAPTERS = [
+ normal,
+ try_to_cancel({"backup_device", "setup_device", "success_backup"}),
+]
-def reset_device(session: Session, strength: int):
+
+def reset_device(session: Session, strength: int, adapt_flow: FlowAdapter):
member_threshold = 3
with session.test_ctx as client:
IF = InputFlowSlip39BasicResetRecovery(session)
- client.set_input_flow(IF.get())
+ client.set_input_flow(adapt_flow(session, IF.get()))
# No PIN, no passphrase, don't display random
device.setup(
@@ -71,24 +81,27 @@ def reset_device(session: Session, strength: int):
@pytest.mark.setup_client(uninitialized=True)
-def test_reset_device_slip39_basic(session: Session):
- reset_device(session, 128)
+@pytest.mark.parametrize("adapt_flow", FLOW_ADAPTERS, ids=lambda f: f.__name__)
+def test_reset_device_slip39_basic(session: Session, adapt_flow: FlowAdapter):
+ reset_device(session, 128, adapt_flow)
+@pytest.mark.parametrize("adapt_flow", FLOW_ADAPTERS, ids=lambda f: f.__name__)
@pytest.mark.setup_client(uninitialized=True)
-def test_reset_device_slip39_basic_256(session: Session):
- reset_device(session, 256)
+def test_reset_device_slip39_basic_256(session: Session, adapt_flow: FlowAdapter):
+ reset_device(session, 256, adapt_flow)
@pytest.mark.setup_client(uninitialized=True)
-def test_reset_entropy_check(session: Session):
+@pytest.mark.parametrize("adapt_flow", FLOW_ADAPTERS, ids=lambda f: f.__name__)
+def test_reset_entropy_check(session: Session, adapt_flow: FlowAdapter):
member_threshold = 3
strength = 128 # 20 words
with session.test_ctx as client:
IF = InputFlowSlip39BasicResetRecovery(session)
- client.set_input_flow(IF.get())
+ client.set_input_flow(adapt_flow(session, IF.get()))
# No PIN, no passphrase.
path_xpubs = device.setup(
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.