pytest: parameterize test_payerkey and test_exposesecret.
What changed, and why it matters
This commit only changes test code. It expands two existing tests so they run against both the old and new styles of HSM secret generation, verifying that expected cryptographic output values remain stable. There is no change to production code, no bug fix, and no security vulnerability.
No security action needed. Treat as normal test-maintenance commit.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The commit parameterizes pytest test cases test_payerkey and test_exposesecret with an old_hsmsecret boolean. It adds expected keys/secrets for the new HSM secret style while preserving the old expectations. The production implementation of payer key derivation and secret exposure is untouched; this is purely regression-test hardening to catch accidental output changes across releases.
Changed components
tests/test_pay.pytests/test_plugin.pyInspect captured patch +57 / −26
diff --git a/tests/test_pay.py b/tests/test_pay.py
index 7ed8652e..8e290b17 100644
--- a/tests/test_pay.py
+++ b/tests/test_pay.py
@@ -5350,18 +5350,28 @@ def test_pay_middle_fail(node_factory, bitcoind, executor):
@unittest.skipIf(TEST_NETWORK != 'regtest', "Invoice is network specific")
+@pytest.mark.parametrize("old_hsmsecret", [True, False])
@pytest.mark.slow_test
-def test_payerkey(node_factory):
+def test_payerkey(node_factory, old_hsmsecret):
"""payerkey calculation should not change across releases!"""
- nodes = node_factory.get_nodes(7)
-
- expected_keys = ["035e43e4ec029ee6cc0e320ebefdf863bc0f284ec0208275f780837d17e21bba32",
- "02411811b24f4940de49ad460ee14ecb96810e29ca49cdd3600a985da2eda06b87",
- "036a19f00424ff244af1841715e89f3716c08f1f62a8e5d9bd0f69a21aa96a7b8d",
- "026d8b82fe6039fe16f8ef376174b630247e821331b90620315a1e9c3db8384056",
- "0393fb950e04916c063a585aa644df3d72642c16de4eb44ccf5dbede194836140f",
- "030b68257230f7057e694222bbd54d9d108decced6b647a90da6f578360af53f7d",
- "02f402bd7374a1304b07c7236d9c683b83f81072517195ddede8ab328026d53157"]
+ nodes = node_factory.get_nodes(7, opts={'old_hsmsecret': old_hsmsecret})
+
+ if old_hsmsecret:
+ expected_keys = ["035e43e4ec029ee6cc0e320ebefdf863bc0f284ec0208275f780837d17e21bba32",
+ "02411811b24f4940de49ad460ee14ecb96810e29ca49cdd3600a985da2eda06b87",
+ "036a19f00424ff244af1841715e89f3716c08f1f62a8e5d9bd0f69a21aa96a7b8d",
+ "026d8b82fe6039fe16f8ef376174b630247e821331b90620315a1e9c3db8384056",
+ "0393fb950e04916c063a585aa644df3d72642c16de4eb44ccf5dbede194836140f",
+ "030b68257230f7057e694222bbd54d9d108decced6b647a90da6f578360af53f7d",
+ "02f402bd7374a1304b07c7236d9c683b83f81072517195ddede8ab328026d53157"]
+ else:
+ expected_keys = ["027c4ec2cf63aeb101109d6d16b9a97e74cd9a149860c16a9fd6ddddf18d337193",
+ "028cd5b653ba55558095e66c0c42c43dd1077598a8d08a097387383dece4c2a325",
+ "02bf5fe9675aed4728c7ed6afb3dab02143cbb693d2c49f62d4c28704d9877fbd0",
+ "037b07ee0335a92f47e803d6ce5500dca721b43a1a9bc4a6ea6b75db4508c7b7de",
+ "02484674b6acc7f3ddb4c5b13ef14ab0b018e748f4f3bffc55ab36dc57fdff6ec5",
+ "024d11164cfd85c0f9383dd78703d3ad533e5af57bc5a09c1c1dae595f212941ae",
+ "0369fb4a73973a31f7d357f4ec39fcc5663f9abae8b5fd47d1a3ada04ee4ae5656"]
bolt12tool = os.path.join(os.path.dirname(__file__), "..", "devtools", "bolt12-cli")
diff --git a/tests/test_plugin.py b/tests/test_plugin.py
index b50a3479..3f862c2c 100644
--- a/tests/test_plugin.py
+++ b/tests/test_plugin.py
@@ -4402,8 +4402,9 @@ def test_important_plugin_shutdown(node_factory):
@unittest.skipIf(VALGRIND, "It does not play well with prompt and key derivation.")
-def test_exposesecret(node_factory):
- l1, l2 = node_factory.get_nodes(2, opts=[{'exposesecret-passphrase': "test_exposesecret"}, {}])
+@pytest.mark.parametrize("old_hsmsecret", [True, False])
+def test_exposesecret(node_factory, old_hsmsecret):
+ l1, l2 = node_factory.get_nodes(2, opts=[{'exposesecret-passphrase': "test_exposesecret", 'old_hsmsecret': old_hsmsecret}, {}])
# listconfigs will conceal the value for us, even if we ask directly.
l1.rpc.listconfigs()['configs']['exposesecret-passphrase']['value_str'] == '...'
@@ -4436,26 +4437,46 @@ def test_exposesecret(node_factory):
with pytest.raises(RpcError, match="must be valid bech32 string"):
l1.rpc.exposesecret(passphrase='test_exposesecret', identifier=invalid)
- # As given by lightning-hsmtool:
- # $ ./tools/lightning-hsmtool getcodexsecret /tmp/ltests-10uyxcnw/test_exposesecret_1/lightning-1/regtest/hsm_secret junr
- # cl10junrsd35kw6r5de5kueedxyqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqj00m675kxffh
- # $ ./tools/lightning-hsmtool getcodexsecret /tmp/ltests-10uyxcnw/test_exposesecret_1/lightning-1/regtest/hsm_secret junx
- # cl10junxsd35kw6r5de5kueedxyqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq6mdtn5lql6p8m
- # $ ./tools/lightning-hsmtool getcodexsecret /tmp/ltests-10uyxcnw/test_exposesecret_1/lightning-1/regtest/hsm_secret cln2
- # cl10cln2sd35kw6r5de5kueedxyqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq2v3y60yxxn4mq
- assert l1.rpc.exposesecret(passphrase='test_exposesecret') == {'codex32': 'cl10junrsd35kw6r5de5kueedxyqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqj00m675kxffh',
- 'identifier': 'junr'}
-
- assert l1.rpc.exposesecret(passphrase='test_exposesecret', identifier='cln2') == {'codex32': 'cl10cln2sd35kw6r5de5kueedxyqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq2v3y60yxxn4mq',
- 'identifier': 'cln2'}
+ if old_hsmsecret:
+ # As given by lightning-hsmtool:
+ # $ ./tools/lightning-hsmtool getcodexsecret /tmp/ltests-10uyxcnw/test_exposesecret_1/lightning-1/regtest/hsm_secret junr
+ # cl10junrsd35kw6r5de5kueedxyqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqj00m675kxffh
+ # $ ./tools/lightning-hsmtool getcodexsecret /tmp/ltests-10uyxcnw/test_exposesecret_1/lightning-1/regtest/hsm_secret junx
+ # cl10junxsd35kw6r5de5kueedxyqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq6mdtn5lql6p8m
+ # $ ./tools/lightning-hsmtool getcodexsecret /tmp/ltests-10uyxcnw/test_exposesecret_1/lightning-1/regtest/hsm_secret cln2
+ # cl10cln2sd35kw6r5de5kueedxyqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq2v3y60yxxn4mq
+ assert l1.rpc.exposesecret(passphrase='test_exposesecret') == {'codex32': 'cl10junrsd35kw6r5de5kueedxyqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqj00m675kxffh',
+ 'identifier': 'junr'}
+
+ assert l1.rpc.exposesecret(passphrase='test_exposesecret', identifier='cln2') == {'codex32': 'cl10cln2sd35kw6r5de5kueedxyqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq2v3y60yxxn4mq',
+ 'identifier': 'cln2'}
+ else:
+ # As given by lightning-hsmtool:
+ # $ ./tools/lightning-hsmtool getcodexsecret /tmp/ltests-2xbjux9b/test_exposesecret_1/lightning-1/regtest/hsm_secret stra
+ # cl10strasmms5axpgnml3svm0urkrvv2cuvxmz0xyd3dlfhaljvcy5wuu2gts07pad39rz85w6
+ # $ ./tools/lightning-hsmtool getcodexsecret /tmp/ltests-2xbjux9b/test_exposesecret_1/lightning-1/regtest/hsm_secret junx
+ # cl10junxsmms5axpgnml3svm0urkrvv2cuvxmz0xyd3dlfhaljvcy5wuu2gtsfcrlankxlxmaa
+ # $ ./tools/lightning-hsmtool getcodexsecret /tmp/ltests-2xbjux9b/test_exposesecret_1/lightning-1/regtest/hsm_secret cln2
+ # cl10cln2smms5axpgnml3svm0urkrvv2cuvxmz0xyd3dlfhaljvcy5wuu2gtse0ls5gdqx00px
+ assert l1.rpc.exposesecret(passphrase='test_exposesecret') == {'codex32': 'cl10strasmms5axpgnml3svm0urkrvv2cuvxmz0xyd3dlfhaljvcy5wuu2gts07pad39rz85w6',
+ 'identifier': 'stra',
+ 'mnemonic': 'hockey enroll sure trip track rescue original plate abandon abandon abandon account'}
+ assert l1.rpc.exposesecret(passphrase='test_exposesecret', identifier='cln2') == {'codex32': 'cl10cln2smms5axpgnml3svm0urkrvv2cuvxmz0xyd3dlfhaljvcy5wuu2gtse0ls5gdqx00px',
+ 'identifier': 'cln2',
+ 'mnemonic': 'hockey enroll sure trip track rescue original plate abandon abandon abandon account'}
# FIXME: runtime config for alias!!
l1.stop()
l1.daemon.opts["alias"] = 'J1U1IOBiobN'
l1.start()
- assert l1.rpc.exposesecret(passphrase='test_exposesecret') == {'codex32': 'cl10junxsd35kw6r5de5kueedxyqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq6mdtn5lql6p8m',
- 'identifier': 'junx'}
+ if old_hsmsecret:
+ assert l1.rpc.exposesecret(passphrase='test_exposesecret') == {'codex32': 'cl10junxsd35kw6r5de5kueedxyqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq6mdtn5lql6p8m',
+ 'identifier': 'junx'}
+ else:
+ assert l1.rpc.exposesecret(passphrase='test_exposesecret') == {'codex32': 'cl10junxsmms5axpgnml3svm0urkrvv2cuvxmz0xyd3dlfhaljvcy5wuu2gtsfcrlankxlxmaa',
+ 'identifier': 'junx',
+ 'mnemonic': 'hockey enroll sure trip track rescue original plate abandon abandon abandon account'}
@unittest.skipIf(VALGRIND, "It does not play well with prompt and key derivation.")
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.