qr: add a qr test for set_epoch, cli support for capturing images
What changed, and why it matters
This commit adds a test helper and command-line tool for capturing camera images from a Blockstream Jade hardware wallet during testing. It also adds a new QR code test case and resets the device clock after QR scanning tests. There is no security vulnerability here—this is purely testing/debugging infrastructure.
No security action needed. This is a benign test/debug tooling commit.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The change introduces capture_image_data in jade_cli.py, which calls jade.capture_image_data() and writes the returned image bytes to a file. It only works on DEBUG firmware builds with CONFIG_RETURN_CAMERA_IMAGES enabled. A new binary test image and JSON expectation are added for set_epoch QR scanning, and test_jade.py now resets the device epoch after the QR scan test to avoid side effects on later tests. A docstring in jadepy/jade.py is tightened to say ‘custom-configured DEBUG builds’.
Changed components
jade_cli.pyjadepy/jade.pytest_jade.pytest_data/qr_qvga_set_epoch.dattest_data/qr_qvga_set_epoch.jsonInspect captured patch +27 / −1
diff --git a/jade_cli.py b/jade_cli.py
index d4596f1..474275a 100755
--- a/jade_cli.py
+++ b/jade_cli.py
@@ -188,5 +188,20 @@ def get_otp_code(jade, name, network):
click.echo(result)
+# UTILITY/DEBUG
+
+@cli.command()
+@click.argument('filename')
+@click.option('--check_qr', type=bool, default=False)
+@with_jade_client
+def capture_image_data(jade, filename, check_qr):
+ # NOTE: Requires a DEBUG firmware with CONFIG_RETURN_CAMERA_IMAGES
+ # enabled. Used for generating test case .dat image files.
+ result = jade.capture_image_data(check_qr)
+ with open(filename, 'wb') as f:
+ f.write(result)
+ click.echo(f'Image data written to {filename}')
+
+
if __name__ == "__main__":
cli()
diff --git a/jadepy/jade.py b/jadepy/jade.py
index bda8651..e766510 100644
--- a/jadepy/jade.py
+++ b/jadepy/jade.py
@@ -643,7 +643,7 @@ class JadeAPI:
RPC call to scan a passed image and return any data extracted from any qr image.
Exercises the camera image capture, but ignores result and uses passed image instead.
See also capture_image_data() above.
- NOTE: Only available in a DEBUG build of the firmware.
+ NOTE: Only available in custom-configured DEBUG builds of the firmware.
Parameters
----------
diff --git a/test_data/qr_qvga_set_epoch.dat b/test_data/qr_qvga_set_epoch.dat
new file mode 100644
index 0000000..614b77f
Binary files /dev/null and b/test_data/qr_qvga_set_epoch.dat differ
diff --git a/test_data/qr_qvga_set_epoch.json b/test_data/qr_qvga_set_epoch.json
new file mode 100644
index 0000000..52843b1
--- /dev/null
+++ b/test_data/qr_qvga_set_epoch.json
@@ -0,0 +1,8 @@
+{
+ "input": {
+ "image": "qr_qvga_set_epoch.dat"
+ },
+ "expected_output": {
+ "text": "UR:JADE-EPOCH/OTIYJNIHJYISJLIEINJKIHJYHEIHJOJLIAISIDINIEIYETEEEOENEEENIYJOHSJPHSJNJKOYIHIHJOJLIAISCYIALPWTISGELGREID"
+ }
+}
diff --git a/test_jade.py b/test_jade.py
index 2a024ed..2bb043e 100644
--- a/test_jade.py
+++ b/test_jade.py
@@ -2339,6 +2339,9 @@ def test_scan_qr(jadeapi, board_type):
else:
assert rslt == h2b(expected['hex'])
+ # Reset the epoch time for any following tests
+ jadeapi.set_epoch(int(time.time()))
+
# Pinserver handshake test - note this is tightly coupled to the dedicated
# test handler in the hardware code (main/process/debug_handshake.c)
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.