fix(core): fix device locking if only SD card protection is enabled
What changed, and why it matters
This update fixes a bug in Trezor hardware wallets where the device would not properly lock itself when only SD card protection was enabled and no PIN was set. In that configuration, an attacker with brief physical access could potentially keep the device unlocked and use it without needing to enter a PIN or provide the SD card secret, bypassing the intended security protection.
Apply this patch and ensure firmware builds for SD-card-capable models (T2T1/T3T1) include it. Run the new `test_sd_protect_lock` device tests to confirm the device locks correctly with SD-protect-only configurations. Consider auditing other authorization paths that may still assume PIN presence implies lockability.
Security signals we found
Bypass of device locking/autolock when only SD-card protection is enabled
Inconsistent authorization checks across lock_device, bootscreen, and homescreen
New regression test `test_sd_protect_lock` covers both session lock and auto-lock with PIN removed
Changelog entry explicitly labeled as a security fix (`265.security`)
Fix cherry-picked from another commit, indicating backport of a security-relevant change
Evidence from the diff
The patch moves and reuses the can_lock_device() helper so that lock_device(), lock_device_if_unlocked(), the boot lockscreen path, and the homescreen lockscreen UI all treat SD-card protection (storage.sd_salt.is_enabled()) as a valid reason to lock the device, independent of whether a PIN is configured. Previously, some of these call sites only checked config.has_pin(), so a device with SD-protect enabled but no PIN would remain unlocked after auto-lock/session-lock and would not present a lockscreen, leaving secrets accessible.
Changed components
core/src/apps/common/lock_manager.pycore/src/apps/common/request_pin.pycore/src/apps/homescreen/__init__.pycore/src/boot.pytests/device_tests/test_sdcard.pyInspect captured patch +155 / −19
diff --git a/core/.changelog.d/265.security b/core/.changelog.d/265.security
new file mode 100644
index 00000000..57b3d0f2
--- /dev/null
+++ b/core/.changelog.d/265.security
@@ -0,0 +1 @@
+Fix device locking if only SD card protection is enabled.
diff --git a/core/src/apps/common/lock_manager.py b/core/src/apps/common/lock_manager.py
index 7f60dc55..d542b7cc 100644
--- a/core/src/apps/common/lock_manager.py
+++ b/core/src/apps/common/lock_manager.py
@@ -175,8 +175,18 @@ def set_homescreen() -> None:
set_default(homescreen)
+def can_lock_device() -> bool:
+ """Return True if the device has a PIN set or SD-protect enabled (when supported)."""
+ if not utils.USE_SD_CARD:
+ return config.has_pin()
+ else:
+ import storage.sd_salt
+
+ return config.has_pin() or storage.sd_salt.is_enabled()
+
+
def lock_device(interrupt_workflow: bool = True) -> None:
- if config.has_pin():
+ if can_lock_device():
config.lock()
filters.append(_pinlock_filter)
set_homescreen()
@@ -187,8 +197,6 @@ def lock_device(interrupt_workflow: bool = True) -> None:
def lock_device_if_unlocked() -> None:
- from apps.common.request_pin import can_lock_device
-
if not utils.USE_BACKLIGHT and not can_lock_device():
# on OLED devices without PIN, trigger screensaver
global _SCREENSAVER_IS_ON
diff --git a/core/src/apps/common/request_pin.py b/core/src/apps/common/request_pin.py
index 5ebd05ea..e3fdd197 100644
--- a/core/src/apps/common/request_pin.py
+++ b/core/src/apps/common/request_pin.py
@@ -29,17 +29,6 @@ async def _request_sd_salt(
raise
-def can_lock_device() -> bool:
- """Return True if the device has a PIN set or SD-protect enabled (when supported)."""
- # TR/T2B1 does not support SD card
- if not utils.USE_SD_CARD:
- return config.has_pin()
- else:
- import storage.sd_salt
-
- return config.has_pin() or storage.sd_salt.is_enabled()
-
-
async def request_pin(
prompt: str,
attempts_remaining: int | None = None,
diff --git a/core/src/apps/homescreen/__init__.py b/core/src/apps/homescreen/__init__.py
index ec834fc5..4c19e260 100644
--- a/core/src/apps/homescreen/__init__.py
+++ b/core/src/apps/homescreen/__init__.py
@@ -78,8 +78,7 @@ async def homescreen() -> None:
async def _lockscreen(screensaver: bool = False) -> None:
- from apps.common.lock_manager import unlock_device
- from apps.common.request_pin import can_lock_device
+ from apps.common.lock_manager import can_lock_device, unlock_device
# Only show the lockscreen UI if the device can in fact be locked, or if it is
# and OLED device (in which case the lockscreen is a screensaver).
diff --git a/core/src/boot.py b/core/src/boot.py
index 131dd252..8d770eba 100644
--- a/core/src/boot.py
+++ b/core/src/boot.py
@@ -19,7 +19,8 @@ from trezor.pin import (
)
from trezor.ui.layouts.homescreen import run_lockscreen
-from apps.common.request_pin import can_lock_device, verify_user_pin
+from apps.common.request_pin import verify_user_pin
+from apps.common import lock_manager
if utils.USE_OPTIGA:
from trezor.crypto import optiga
@@ -27,7 +28,6 @@ if utils.USE_OPTIGA:
if utils.USE_POWER_MANAGER:
from micropython import const
from trezor import workflow
- from apps.common import lock_manager
# have to use "==" over "in (list)" so that it can be statically replaced
# with the correct value during the build process
@@ -93,7 +93,7 @@ async def bootscreen() -> None:
while True:
try:
- if can_lock_device():
+ if lock_manager.can_lock_device():
enforce_welcome_screen_duration()
if utils.INTERNAL_MODEL == "T2T1":
ui.backlight_fade(ui.BacklightLevels.NONE)
diff --git a/tests/device_tests/test_sdcard.py b/tests/device_tests/test_sdcard.py
index 112785dd..495d14c6 100644
--- a/tests/device_tests/test_sdcard.py
+++ b/tests/device_tests/test_sdcard.py
@@ -14,6 +14,8 @@
# You should have received a copy of the License along with this library.
# If not, see <https://www.gnu.org/licenses/lgpl-3.0.html>.
+import time
+
import pytest
from trezorlib import device, messages
@@ -21,6 +23,8 @@ from trezorlib.debuglink import DebugSession as Session
from trezorlib.exceptions import TrezorFailure
from trezorlib.messages import SdProtectOperationType as Op
+B = messages.ButtonRequestType
+
from .. import translations as TR
PIN = "1234"
@@ -128,3 +132,114 @@ def test_sd_protect_unlock(session: Session):
device.change_pin(session)
assert e.value.code == messages.FailureType.ProcessError
+
+
+@pytest.mark.sd_card
+@pytest.mark.setup_client(pin=PIN)
+@pytest.mark.parametrize(
+ "autolock",
+ [pytest.param(False, id="session_lock"), pytest.param(True, id="auto_lock")],
+)
+def test_sd_protect_lock(session: Session, autolock: bool):
+ layout = session.debug.read_layout
+
+ assert "Lockscreen" in layout().all_components()
+ assert session.features.pin_protection is True
+ assert session.features.sd_protection is None
+ assert session.features.unlocked is False
+
+ with session.test_ctx as client:
+ # unlock and enable SD protection
+ client.use_pin_sequence([PIN] * 2)
+ client.set_expected_responses(
+ [
+ messages.ButtonRequest(code=B.PinEntry),
+ messages.ButtonRequest(code=B.Other),
+ messages.ButtonRequest(code=B.PinEntry),
+ messages.ButtonRequest(code=B.Success),
+ messages.Success,
+ messages.Features,
+ ]
+ )
+ device.sd_protect(session, Op.ENABLE)
+
+ if autolock:
+ device.apply_settings(session, auto_lock_delay_ms=10 * 1000)
+
+ def lock_func():
+ time.sleep(10.5)
+ session.refresh_features()
+
+ else:
+
+ def lock_func():
+ session.lock() # features are auto-refreshed
+
+ assert session.features.pin_protection is True
+ assert session.features.sd_protection is True
+ assert session.features.unlocked is True
+ lock_func()
+ assert "Lockscreen" in layout().all_components()
+ assert session.features.pin_protection is True
+ assert session.features.sd_protection is None
+ assert session.features.unlocked is False
+
+ with session.test_ctx as client:
+ # unlock and remove PIN
+ client.use_pin_sequence([PIN] * 2)
+ client.set_expected_responses(
+ [
+ messages.ButtonRequest(code=B.PinEntry),
+ messages.ButtonRequest(code=B.Other),
+ messages.ButtonRequest(code=B.PinEntry),
+ messages.ButtonRequest(code=B.Success),
+ messages.Success,
+ messages.Features,
+ ]
+ )
+ device.change_pin(session, remove=True)
+
+ assert session.features.pin_protection is False
+ assert session.features.sd_protection is True
+ assert session.features.unlocked is True
+ lock_func()
+ assert "Lockscreen" in layout().all_components()
+ assert session.features.pin_protection is False
+ assert session.features.sd_protection is None
+ assert session.features.unlocked is False
+
+ with session.test_ctx as client:
+ # setup PIN again
+ client.use_pin_sequence([PIN] * 2)
+ client.set_expected_responses(
+ [
+ messages.ButtonRequest(code=B.Other),
+ messages.ButtonRequest(code=B.PinEntry),
+ messages.ButtonRequest(code=B.PinEntry),
+ messages.ButtonRequest(code=B.Success),
+ messages.Success,
+ messages.Features,
+ ]
+ )
+ device.change_pin(session)
+
+ assert session.features.pin_protection is True
+ assert session.features.sd_protection is True
+ assert session.features.unlocked is True
+ lock_func()
+ assert "Lockscreen" in layout().all_components()
+ assert session.features.pin_protection is True
+ assert session.features.sd_protection is None
+ assert session.features.unlocked is False
+
+ with session.test_ctx as client:
+ # unlock again
+ client.use_pin_sequence([PIN])
+ client.set_expected_responses(
+ [
+ messages.ButtonRequest(code=B.PinEntry),
+ messages.PublicKey,
+ messages.Features,
+ ]
+ )
+ session.ensure_unlocked()
diff --git a/tests/ui_tests/fixtures.json b/tests/ui_tests/fixtures.json
index 05bafb77..633bb5df 100644
--- a/tests/ui_tests/fixtures.json
+++ b/tests/ui_tests/fixtures.json
@@ -2952,6 +2952,8 @@
"T2T1_cs_test_repeated_backup.py::test_repeated_backup_via_host_upgrade_single[Display]": "78655cf20dd03716679855e902a7b900b87b65ffb92158bc24cb5b818fa6b592",
"T2T1_cs_test_sdcard.py::test_sd_format": "11b1d8d8e573bb4df9819049bc30b4a6cbc1a546729d84e9f6d7da87f73992ff",
"T2T1_cs_test_sdcard.py::test_sd_no_format": "9d404b1bac13877e95e52a06a42b892a97880a719dda0bff688f795106d28f71",
+"T2T1_cs_test_sdcard.py::test_sd_protect_lock[auto_lock]": "8ee3c079714e542e095fbac320dfbd643ef943e10b43cfe9c7d2ec2d2ebd6080",
+"T2T1_cs_test_sdcard.py::test_sd_protect_lock[session_lock]": "221fc8f59b11ea6e420ec3c3998ddbb4f0ef29ae5ebd1630d504c594b2889e98",
"T2T1_cs_test_sdcard.py::test_sd_protect_unlock": "1a1f02b5f8ee6151940b3944ab7b540ce9ecdf37308e9be707361724e54fcd27",
"T2T1_cs_test_session.py::test_cannot_resume_ended_session": "f2b80196c81ce473b7f24f16f6192ac76d9d2ca23fb0b40053c00d02b53d5111",
"T2T1_cs_test_session.py::test_clear_session": "d98a618bd6836c074e36dd2e3dca4d32bba953869c2f012ee4115626e74def70",
@@ -4760,6 +4762,8 @@
"T2T1_de_test_repeated_backup.py::test_repeated_backup_via_host_upgrade_single[Display]": "f2af0e4681a735bb1a8417b8a699ef6fbe88a1bee77885e109ca2bd933cb5195",
"T2T1_de_test_sdcard.py::test_sd_format": "b2fe89f9055c90a0b4bd3e18501a2de994a6cbea28e7d402e909cce17339250b",
"T2T1_de_test_sdcard.py::test_sd_no_format": "2555fec831f83bd969b17990bdb7c26a67cbe72e8380d2454cee866c6f81f184",
+"T2T1_de_test_sdcard.py::test_sd_protect_lock[auto_lock]": "867b0ce1b888756ca0dc9c31f3f8d22dd223c22a8a339477f8fde586babd9760",
+"T2T1_de_test_sdcard.py::test_sd_protect_lock[session_lock]": "9ac0d5d053f6aa1ea2dd6507d34286f23e809f41174bee86a15c512c3fbe5e5b",
"T2T1_de_test_sdcard.py::test_sd_protect_unlock": "dd2d004e64ed201e92943970cdef76b875e613f69b99601f0f0f7f2f85f9e73c",
"T2T1_de_test_session.py::test_cannot_resume_ended_session": "efeaf51fe18b983e9b1a6947a939ad305a92e57798fe07110bb61c0f65755881",
"T2T1_de_test_session.py::test_clear_session": "2a91358489ddce8f4f2290a83dbfdb33495c32aa5f8789e6085008c503c9ad94",
@@ -6568,6 +6572,8 @@
"T2T1_en_test_repeated_backup.py::test_repeated_backup_via_host_upgrade_single[Display]": "59363f0227fe6f5d5ea20081dab40063f849c70eeae37c73fdca95d8c58b50c1",
"T2T1_en_test_sdcard.py::test_sd_format": "1def764a164375b0e54c5646ab4a6c23ebc3a9205fd8805e484df5d2863a799b",
"T2T1_en_test_sdcard.py::test_sd_no_format": "0dfbc1808203fab7694ab584e57e967a2a58b632e208d13fef6d096528a7d715",
+"T2T1_en_test_sdcard.py::test_sd_protect_lock[auto_lock]": "136227acaaef1c90cf7d1541fd406d589ed8f030f49300149c30d6dba932b09e",
+"T2T1_en_test_sdcard.py::test_sd_protect_lock[session_lock]": "298841d6282c426c62e5b559da6869426085fa66e0b2593f98a7c94d98e826d9",
"T2T1_en_test_sdcard.py::test_sd_protect_unlock": "6b58ce05cc3ddb0c5e2607959c7dcc2de1a1c9e3120ead02aa4c7943cf31179b",
"T2T1_en_test_session.py::test_cannot_resume_ended_session": "8aa7c68cd09e700e8c6903dcfc39c4a66214481c12c34dc56762829478399b79",
"T2T1_en_test_session.py::test_clear_session": "a99116a4a5a69619d7553783d3704f6a8dd38f5d06d9c6322ec26c46be9bde0d",
@@ -8394,6 +8400,8 @@
"T2T1_es_test_repeated_backup.py::test_repeated_backup_via_host_upgrade_single[Display]": "63df23206dfa5c0810c22b3caf0f0b7448a85debcee63004f7bbd6dd72b52be2",
"T2T1_es_test_sdcard.py::test_sd_format": "be08b71759eb536e7bb0d64ab3a6b5ae8d0602cf987e80db956acdcbf1284787",
"T2T1_es_test_sdcard.py::test_sd_no_format": "c888961397b7214c7e14701227178727f674b10fee37ce1dddd59aa925b539a3",
+"T2T1_es_test_sdcard.py::test_sd_protect_lock[auto_lock]": "199186a825f5beaedc887580b36fd7e39a508c085b53848a559cf76fdcebcad0",
+"T2T1_es_test_sdcard.py::test_sd_protect_lock[session_lock]": "b6c2a8ec5b7e739809bf40cdb87d775c14c1342bb54897a52d5587097bea66f4",
"T2T1_es_test_sdcard.py::test_sd_protect_unlock": "67fd963eb18e84dfe2827d23a6032f48991c17c8241a163fe7c545932ffe7e54",
"T2T1_es_test_session.py::test_cannot_resume_ended_session": "17d836396f272c01cafa175aa87b0c076aedf7698c935d1921c7d3d7e8911903",
"T2T1_es_test_session.py::test_clear_session": "d74cddef94c4b8bc7d9ffc4ff92b89bf130adfe42e105868c67ff1052678c733",
@@ -10202,6 +10210,8 @@
"T2T1_fr_test_repeated_backup.py::test_repeated_backup_via_host_upgrade_single[Display]": "63c8968d3d44175d60e6eeb7eec5d1ccf60436f5ce3800d0b6985f6cbee65aa0",
"T2T1_fr_test_sdcard.py::test_sd_format": "c13635e29dcba9f15cd300e817ec42d61bc7174680784ba60807a0fbae270e97",
"T2T1_fr_test_sdcard.py::test_sd_no_format": "777e8e73b9db5f658ac2a2bf18f7717e12fb002fc3a48c935a3c37844ccb4a82",
+"T2T1_fr_test_sdcard.py::test_sd_protect_lock[auto_lock]": "d899e674b9986ac2c2eb8a35abd3d44b7e1076db832ba99e1d967dab2111e047",
+"T2T1_fr_test_sdcard.py::test_sd_protect_lock[session_lock]": "2749fe83dd7698b2ec05a759d592d54aa50d502188e318db3c7ffd8379fd8a5c",
"T2T1_fr_test_sdcard.py::test_sd_protect_unlock": "8f227b17b6da40fe8a784f5815785aa9bca16e8c6fd873e5aa81e9ce1b02558a",
"T2T1_fr_test_session.py::test_cannot_resume_ended_session": "7e5a99a4b6aad4cdf7a9f9aecf483faa381108ee2108efaba88f261e29ac1f8a",
"T2T1_fr_test_session.py::test_clear_session": "f8bfaaec66103afab2a59e5300c8eb4cc4a281034acda5743b3a99aa15927bb5",
@@ -12010,6 +12020,8 @@
"T2T1_pt_test_repeated_backup.py::test_repeated_backup_via_host_upgrade_single[Display]": "4b423ba38401fe8c49c82476875d5e9f83eba13cb67c8af693676b0b5bfa5f86",
"T2T1_pt_test_sdcard.py::test_sd_format": "2d069cfc85fd66929415517413f39e45a564269aac273613d0b153f868b94655",
"T2T1_pt_test_sdcard.py::test_sd_no_format": "22ed9cafbe12bfd489fb1521ec6bf11fbd13008ea5212e98cd69ce9aa1c3d2a9",
+"T2T1_pt_test_sdcard.py::test_sd_protect_lock[auto_lock]": "96153a6368fbcae78b3fc1cae65b6966736bed4edda3983a0b310693516fcd78",
+"T2T1_pt_test_sdcard.py::test_sd_protect_lock[session_lock]": "5e6b9d768ed4a266b4a576286a1633453ca6eb05e15c6f3e813aad164fe346e6",
"T2T1_pt_test_sdcard.py::test_sd_protect_unlock": "bff32da777ceb00e8338a3475cd2cddd26a6dbdaa31d460828264cb1ea2ee954",
"T2T1_pt_test_session.py::test_cannot_resume_ended_session": "020b255e04b59e53d2aa87ae960038f4538d350de28df15a1ac41b376e9d04f2",
"T2T1_pt_test_session.py::test_clear_session": "1f7dda75595706fcc5e39c9218cd1f8e11f94a93152d44ff5489477cac75ca9e",
@@ -24968,6 +24980,8 @@
"T3T1_cs_test_repeated_backup.py::test_repeated_backup_via_host_upgrade_single[Display]": "7808ca43e32c21e405c03fd60626ca61421423d6bf9127a44849f6eb6be0f29c",
"T3T1_cs_test_sdcard.py::test_sd_format": "84c8b74e629555ba7a19736b6d6f0d9ea23eda1a143bdda66326ff89bed22ca2",
"T3T1_cs_test_sdcard.py::test_sd_no_format": "051854e6ef881cc7ae9f5d85de77ecc9e45f805f4a2dac12c9e51eb6e464f5e1",
+"T3T1_cs_test_sdcard.py::test_sd_protect_lock[auto_lock]": "3588a71c0558a7d47c8ebc9d41f2c9520808e8bc25aef8f4cfa0a3afdab263ac",
+"T3T1_cs_test_sdcard.py::test_sd_protect_lock[session_lock]": "2e81ff340ef18fd18effdea3ecc42ec35659f1aae17ee4ee30bbffd97395b43f",
"T3T1_cs_test_sdcard.py::test_sd_protect_unlock": "07eb6650a70d52675a0e2ae79a7febd9a7ec47b7835e7a80fe3b7a3d2a22b7bc",
"T3T1_cs_test_session.py::test_cannot_resume_ended_session": "9c20243bc5dacf2442af5a8778b66a0ab7cb978e11c02fec371f109fbc9d55f6",
"T3T1_cs_test_session.py::test_clear_session": "9934846e7d7b68fb4e9345be667ed98580f40e5b150b6453fe9a52fb9a9f21e3",
@@ -26750,6 +26764,8 @@
"T3T1_de_test_repeated_backup.py::test_repeated_backup_via_host_upgrade_single[Display]": "57b5e30e2b5389c72ae94e03e076c1b74ffcd8e091bf843c11f8f50d7de015bc",
"T3T1_de_test_sdcard.py::test_sd_format": "e26ca24b0efa359aa2dd315c73a902d3b9a43b93987107b53aa218bb8dbd8bbd",
"T3T1_de_test_sdcard.py::test_sd_no_format": "11d7e0781b5a6c0ccf48bdda86806907e94f11639827bc198912323cff1b18e6",
+"T3T1_de_test_sdcard.py::test_sd_protect_lock[auto_lock]": "5bc12dda47b4f5cc03cf63e3e36a39476034ade946e4049cb90ec561d17df5aa",
+"T3T1_de_test_sdcard.py::test_sd_protect_lock[session_lock]": "e7567bad410b3529c625ba9a21c24e13f7bf4c76818b9d85eede653f95c9b891",
"T3T1_de_test_sdcard.py::test_sd_protect_unlock": "2d146714b0dc613325447c4110e17f839272414b47e0b3f8897c2b55d37e177c",
"T3T1_de_test_session.py::test_cannot_resume_ended_session": "68c146f13417be0845fee20b1d8de4a05e0844608c2efb3cfae9f573be39f0c4",
"T3T1_de_test_session.py::test_clear_session": "6e88a00a4a6d89c0253b14af863ff88dbb27519a6aa9078e15ad9fa0b1f5cf9f",
@@ -28532,6 +28548,8 @@
"T3T1_en_test_repeated_backup.py::test_repeated_backup_via_host_upgrade_single[Display]": "85e650d18a28271ff60db5789a37d8c16588db4397af4b3143930f92b3ed02ea",
"T3T1_en_test_sdcard.py::test_sd_format": "d56a51a785b40cf9b298a54f07c2beed417b1c0ff6978cfa3a99b90ad93213bf",
"T3T1_en_test_sdcard.py::test_sd_no_format": "0edc58610ac21bb7fb8027bbd5b91ffb331363cda3f716b3f41d59a98946c1db",
+"T3T1_en_test_sdcard.py::test_sd_protect_lock[auto_lock]": "b1f2b1db197b02450ce0ceba8e142276472d6f51602ba675dcbd4c022869ccf9",
+"T3T1_en_test_sdcard.py::test_sd_protect_lock[session_lock]": "14dd73b7c29b1df02107723422da5aec8dd25daf9b513356513c4e7e427675db",
"T3T1_en_test_sdcard.py::test_sd_protect_unlock": "63dfb6dbc406519ddd6f5f88efd7e6240ee97e699e1e5360a9a15976a90ece4a",
"T3T1_en_test_session.py::test_cannot_resume_ended_session": "0064e8a52b9bff0c2a31432fa781b800afb21e8910d60f303671bdfc8d8425fc",
"T3T1_en_test_session.py::test_clear_session": "6a944fc5c3a69abaa5d73073d08dac598572a5a9633e8584f3b22d15af938831",
@@ -30314,6 +30332,8 @@
"T3T1_es_test_repeated_backup.py::test_repeated_backup_via_host_upgrade_single[Display]": "e232b0473cbe1782fe512db82b007e9b4a1057b9a7887f3ecf1f3e9d09842288",
"T3T1_es_test_sdcard.py::test_sd_format": "045536da467f3377bc616d33d41f90390a63e650b890a4d40aad2fa9bdfdc704",
"T3T1_es_test_sdcard.py::test_sd_no_format": "a2dcce6910f79e146cdd8cac69dbcf4b661fff74b50c6d80abbcd0c4b0d52b1d",
+"T3T1_es_test_sdcard.py::test_sd_protect_lock[auto_lock]": "dd6d1ca6b397b0b24a6abd0dda697b59eb71da62f3209007e980d2c0cd9605bd",
+"T3T1_es_test_sdcard.py::test_sd_protect_lock[session_lock]": "dc3fe92c050f6866722961d2bd9bbcb9dce3229e94bd7a6f6ffaad74a38b63a8",
"T3T1_es_test_sdcard.py::test_sd_protect_unlock": "c2c664ec48550854b19da2c3013cd294a504bd35e723eb2a6c9764735699b819",
"T3T1_es_test_session.py::test_cannot_resume_ended_session": "41b9c9e85d64891dcfd03d675df77c533f035a2d191b161144d00afab69a589d",
"T3T1_es_test_session.py::test_clear_session": "738d1771600c10057d4eecb17ef071c65a2e7e3c1bf9c80019abe3a3148bc5e0",
@@ -32096,6 +32116,8 @@
"T3T1_fr_test_repeated_backup.py::test_repeated_backup_via_host_upgrade_single[Display]": "c8b2547a0e883b3f869cca8f6a46d1f2a1140b1a9edd238c2abab1ca12de3578",
"T3T1_fr_test_sdcard.py::test_sd_format": "f655ef18e159778a54f5e4be50343c28969f8dea089b9d66482950bff2626748",
"T3T1_fr_test_sdcard.py::test_sd_no_format": "6ae3bfd66bf3f54137f12adc6006212df440368a1b8df9c667dad814b449a7e5",
+"T3T1_fr_test_sdcard.py::test_sd_protect_lock[auto_lock]": "bbf3d115801d3df7693d09a2f3b2cd6b0ec41071b9cbadd6467e4d5e2bd7a5a1",
+"T3T1_fr_test_sdcard.py::test_sd_protect_lock[session_lock]": "3eed0c60b5ebbd5668dbb15e119bcd808f385404f4c7eb53fd2fb510d7eb5f1e",
"T3T1_fr_test_sdcard.py::test_sd_protect_unlock": "55fa41aec8739c24aea358cd66fa30f7315d4bc590d827e2b94854b2397751cf",
"T3T1_fr_test_session.py::test_cannot_resume_ended_session": "116c64aa168d12181b7a5317677ddf135d739fdac22d38ff08571dc3301c2f47",
"T3T1_fr_test_session.py::test_clear_session": "f4ef104d30a6ef4fe8a01afafea8daf465803e498dfb0a37165bb0920a98cc21",
@@ -33878,6 +33900,8 @@
"T3T1_pt_test_repeated_backup.py::test_repeated_backup_via_host_upgrade_single[Display]": "e8ca351ad62a779fd11ee9583379cd02ec2663356d891a3fee7ef7d322aba620",
"T3T1_pt_test_sdcard.py::test_sd_format": "affbe3d33fab83e6146a70e80ca94c7533b9e5345f7ae3ff852c07f2a0b4c245",
"T3T1_pt_test_sdcard.py::test_sd_no_format": "bd8ed58679176a0996aa426b5f289407f2dce9c499f6b56668f089e908259b24",
+"T3T1_pt_test_sdcard.py::test_sd_protect_lock[auto_lock]": "4eb55bcae8fff279cbd90d05f51c6d17b4e83ab390b64e4dda57b4353894107e",
+"T3T1_pt_test_sdcard.py::test_sd_protect_lock[session_lock]": "ae72abb8bb7a76db134005dcf565be5a851ba9633cd39c82a7a3856a116eed61",
"T3T1_pt_test_sdcard.py::test_sd_protect_unlock": "6209cac525cad2484a7846f77e647b37754b9d050a00374559454aff2bd9ef9c",
"T3T1_pt_test_session.py::test_cannot_resume_ended_session": "14256cd1b801d1b67a37de1198d61a80d342f39e5c5d6fa991ec7fb526d683be",
"T3T1_pt_test_session.py::test_clear_session": "70f577f9f550da1d58b6de1df5735a594f6317cd03f5e9cff085966b7c391801",
Why this scored 57/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.