tests: fix mnemonic handling following seed changes
What changed, and why it matters
This commit only changes test code for the Blockstream Jade hardware wallet. It fixes how tests set and reset the device mnemonic/seed so tests run correctly after earlier seed-handling changes. There is no change to the actual wallet firmware or any user-facing security behavior.
No security action required; this is a test-only maintenance commit. Reviewers may verify CI passes.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The commit updates Python test fixtures and test cases. It replaces an ‘invalidatecache’ mnemonic marker with an explicit ‘reset’ marker, routes mnemonic changes through a caching wrapper, and adds missing ‘mnemonic’ fixture arguments so the reset fixture actually executes. All modifications are under tests/ and do not touch firmware, RPC protocol, or cryptographic logic.
Changed components
tests/__init__.pytests/conftest.pytests/rpc/test_address.pytests/rpc/test_descriptor.pytests/rpc/test_mnemonic.pytests/rpc/test_multisig.pytests/rpc/test_pinserver.pyInspect captured patch +32 / −37
### tests/__init__.py
@@ -27,10 +27,8 @@
# Mnemonic used in identity tests
'identity': 'alcohol woman abuse must during monitor noble \
actual mixed trade anger aisle',
- # Used to ensure the on-device cached mnemonic is changed to an
- # otherwise unused mnemonic for tests that set a custom mnemonic/seed
- 'invalidatecache': 'abandon abandon abandon abandon abandon abandon abandon \
- abandon abandon abandon abandon cactus'
+ # Ensure the on-device cached mnemonic is reset before the test
+ 'reset': 'reset'
})
# Seeds used in tests
### tests/conftest.py
@@ -57,16 +57,18 @@ def _create_api(self):
def set_mnemonic(self, mnemonic):
"""Set the current jade mnemonic (with caching)."""
- if mnemonic != self.current_mnemonic:
- # reset the jade
- rslt = self.jade.clean_reset()
- assert rslt is True
+ do_reset = mnemonic == mnemonics.reset
+ if do_reset or mnemonic != self.current_mnemonic:
# mnemonic differs from the one currently set: change and remember it
- rslt = self.jade.set_mnemonic(mnemonic)
+ rslt = self.jade.clean_reset()
assert rslt is True
- self.current_mnemonic = mnemonic
- # invalidate seed
- self.current_seed = None
+ if do_reset:
+ self.current_mnemonic = None # invalidate mnemonic
+ else:
+ rslt = self.jade.set_mnemonic(mnemonic)
+ assert rslt is True
+ self.current_mnemonic = mnemonic
+ self.current_seed = None # invalidate seed
time.sleep(1)
def set_seed(self, seed):
@@ -77,8 +79,7 @@ def set_seed(self, seed):
# set seed
rslt = self.jade.set_seed(bytes.fromhex(seed))
assert rslt is True
- # invalidate mnemonic
- self.current_mnemonic = None
+ self.current_mnemonic = None # invalidate mnemonic
time.sleep(1)
def disconnect(self):
@@ -210,8 +211,8 @@ def mnemonic(request):
@pytest.mark.mnemonic(mnemonics.singlesig)
"""
s = _get_test_seed(request.node)
- if s == '': # no seed, set mnemonic
- m = _get_test_mnemonic(request.node) or mnemonics.default
- get_jade_config().jade.set_mnemonic(m)
- else: # if there is seed ignore mnemonic and set seed
+ if s:
get_jade_config().set_seed(s)
+ else:
+ m = _get_test_mnemonic(request.node) or mnemonics.default
+ get_jade_config().set_mnemonic(m)
### tests/rpc/test_address.py
@@ -10,7 +10,7 @@ def test_get_greenaddress_receive_address(jade, test_case):
assert rslt == expected
-@pytest.mark.mnemonic(mnemonics.invalidatecache)
+@pytest.mark.mnemonic(mnemonics.reset)
@pytest.mark.seed(seeds.singlesig)
@with_test_cases('tests/rpc/data/address/single_sig_addr.json')
def test_get_singlesig_receive_address(jade, mnemonic, test_case):
### tests/rpc/test_descriptor.py
@@ -57,7 +57,7 @@ def test_miniscript_descriptor_registration(jade, test_case):
_test_miniscript_descriptor_registration(jade, test_case)
-@pytest.mark.mnemonic(mnemonics.invalidatecache)
+@pytest.mark.mnemonic(mnemonics.reset)
@pytest.mark.seed(seeds.singlesig)
@with_test_cases('tests/rpc/data/descriptor/descriptor_ss_*.json')
def test_miniscript_descriptor_registration_ss(jade, test_case):
### tests/rpc/test_mnemonic.py
@@ -108,8 +108,8 @@ def _set_wallet(jade, mnemonic=mnemonics.default, passphrase=None):
return reply['result']
-@pytest.mark.mnemonic(mnemonics.invalidatecache)
-def test_12word_mnemonic(jade):
+@pytest.mark.mnemonic(mnemonics.reset)
+def test_12word_mnemonic(jade, mnemonic):
# Short sanity-test of 12-word mnemonic
rslt = jade.set_mnemonic(TEST_MNEMONIC_12)
assert rslt is True
@@ -120,8 +120,8 @@ def test_12word_mnemonic(jade):
assert rslt == '38SBTKLCNKVvQh1jPpbkAbXa3gtRJEh9Ud'
-@pytest.mark.mnemonic(mnemonics.invalidatecache)
-def test_mnemonic_import(jade):
+@pytest.mark.mnemonic(mnemonics.reset)
+def test_mnemonic_import(jade, mnemonic):
# Check the mnemonic unique prefixes expands to the same mnemonic/wallet
# as when giving the full mnemonic words (test for qr-scanning prefixes)
# as the unambiguous prefixes are expanded to the full words. orc -> orchard
@@ -158,8 +158,8 @@ def test_mnemonic_import(jade):
assert xpub_root2 == xpub_root0
-@pytest.mark.mnemonic(mnemonics.invalidatecache)
-def test_mnemonic_import_bad(jade):
+@pytest.mark.mnemonic(mnemonics.reset)
+def test_mnemonic_import_bad(jade, mnemonic):
# Check importing invalid mnemonics
bad_mnemonics = [
# mnemonic phrase
@@ -189,8 +189,8 @@ def test_mnemonic_import_bad(jade):
assert any(m in message for m in expected), message
-@pytest.mark.mnemonic(mnemonics.invalidatecache)
-def test_passphrase(jade):
+@pytest.mark.mnemonic(mnemonics.reset)
+def test_passphrase(jade, mnemonic):
# Set mnemonic with/without a passphrase, and get root xpub
xpub0 = _set_wallet(jade.jade, passphrase=None)
xpub1 = _set_wallet(jade.jade, passphrase='Passphrase1')
### tests/rpc/test_multisig.py
@@ -340,7 +340,7 @@ def test_generic_multisig_matches_ga_signatures_liquid(jade, test_case):
_check_tx_signatures(jade, ga_msig, rslt)
-@pytest.mark.mnemonic(mnemonics.invalidatecache)
+@pytest.mark.mnemonic(mnemonics.reset)
@pytest.mark.seed(seeds.singlesig)
@with_test_cases('tests/rpc/data/multisig/multisig_reg_ss_*.json')
def test_generic_multisig_ss_signer(jade, mnemonic, test_case):
### tests/rpc/test_pinserver.py
@@ -24,16 +24,12 @@ def test_set_pinserver(jade):
assert rslt
-@pytest.mark.mnemonic(mnemonics.invalidatecache)
-def test_handshake(jade):
+@pytest.mark.mnemonic(mnemonics.reset)
+def test_handshake(jade, mnemonic):
"""
Pinserver handshake test - note this is tightly coupled to the dedicated
test handler in the hardware code (main/process/debug_handshake.c)
"""
- # Reset the jade
- rslt = jade.clean_reset()
- assert rslt is True
- get_jade_config().current_mnemonic = None
# First override the hww pinserver pubkey to match the local test key
TEST_URL = 'https://this.is.a.test.url.com'
TEST_ONION = 'http://we.dont.know.our.onion.but.this.string.is.about.the.right.size'
@@ -147,8 +143,8 @@ def test_handshake(jade):
assert reply2['result'] is True
-@pytest.mark.mnemonic(mnemonics.invalidatecache)
-def test_handshake_bad_server(jade):
+@pytest.mark.mnemonic(mnemonics.reset)
+def test_handshake_bad_server(jade, mnemonic):
"""
Pinserver handshake test - set the hww back to the default/production
authentication data - this should then fail with 'bad-sig' when we signWhy 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.