What changed, and why it matters
This commit hides the 'Allow Notes' option from a security feature called SSSP on older COLDCARD devices (mk4) that lack a qwerty keyboard. It is a UI cleanup, not a security fix. The change prevents users from seeing a setting that does not apply to their hardware, but does not alter how notes are actually protected.
No security action required. Treat as normal feature/maintenance commit.
Security signals we found
No access-control or cryptographic logic changed
UI-only predicate added to hide an inapplicable menu item
Tests adjusted to reflect hardware-specific menu visibility
Evidence from the diff
The patch adds a predicate version.has_qwerty to the SSSPCheckedMenuItem for ‘Allow Notes’ in shared/ccc.py, so the menu item only appears on Q1 (qwerty) models. Tests are updated to expect the item absent on non-qwerty devices and to assert the test device is q1 before exercising notes-related SSSP setup. There is no change to access-control logic, secure-note storage, or policy enforcement.
Changed components
shared/ccc.py (SSSP configuration menu)testing/test_hobble.pytesting/test_sssp.pyInspect captured patch +14 / −5
diff --git a/shared/ccc.py b/shared/ccc.py
index 8b5f8c9..28248ca 100644
--- a/shared/ccc.py
+++ b/shared/ccc.py
@@ -1195,7 +1195,7 @@ class SSSPConfigMenu(MenuSystem):
MenuItem('Edit Policy...',
menu=lambda *a: SpendingPolicyMenu.be_a_submenu(SSSPFeature.get_policy())),
SSSPCheckedMenuItem('Word Check', 'words', 'To change Spending Policy, in addition to special PIN, you must provide the first and last seed words.'),
- SSSPCheckedMenuItem('Allow Notes', 'notes', 'Allow (read-only) access to secure notes and passwords? Otherwise, they are inaccessible.'),
+ SSSPCheckedMenuItem('Allow Notes', 'notes', 'Allow (read-only) access to secure notes and passwords? Otherwise, they are inaccessible.', predicate=version.has_qwerty),
SSSPCheckedMenuItem('Related Keys', 'okeys', 'Allow access to BIP-39 passphrase wallets based on master seed, and Seed Vault (read-only). Single Spending Policy applies to all.'),
#MenuItem('Test Word Challenge', f=sssp_word_challenge), # XXX test only?
]
diff --git a/testing/test_hobble.py b/testing/test_hobble.py
index 554c422..9120b76 100644
--- a/testing/test_hobble.py
+++ b/testing/test_hobble.py
@@ -138,7 +138,7 @@ def test_menu_contents(set_hobble, pick_menu_item, cap_menu, en_okeys, en_notes,
def test_h_notes(only_q1, set_hobble, pick_menu_item, cap_menu, settings_set, need_some_notes,
- is_q1, sim_exec, settings_remove):
+ sim_exec, settings_remove):
'''
* load a secure note/pw; check readonly once hobbled
* cannot export
@@ -168,7 +168,7 @@ def test_h_notes(only_q1, set_hobble, pick_menu_item, cap_menu, settings_set, ne
assert 'Secure Notes & Passwords' not in m
def test_kt_limits(only_q1, set_hobble, pick_menu_item, cap_menu, settings_set, need_some_notes,
- is_q1, sim_exec, settings_remove):
+ sim_exec, settings_remove):
'''
- key teleport
* check KT only offered if MS wallet setup
@@ -181,7 +181,7 @@ def test_kt_limits(only_q1, set_hobble, pick_menu_item, cap_menu, settings_set,
# converse already tested in test_menu_contents
@pytest.mark.parametrize('sv_empty', [ True, False] )
-def test_h_seedvault(sv_empty, set_hobble, pick_menu_item, cap_menu, settings_set, is_q1, sim_exec,
+def test_h_seedvault(sv_empty, set_hobble, pick_menu_item, cap_menu, settings_set, sim_exec,
settings_remove, restore_main_seed, settings_get, press_cancel, press_select,
cap_story):
'''
diff --git a/testing/test_sssp.py b/testing/test_sssp.py
index ffb9798..422efa3 100644
--- a/testing/test_sssp.py
+++ b/testing/test_sssp.py
@@ -64,7 +64,7 @@ def setup_sssp(goto_sssp_menu, pick_menu_item, cap_story, press_select, pass_wor
assert "last Violation" not in m
assert "Word Check" in m
- assert "Allow Notes" in m
+ assert ("Allow Notes" in m) or not is_q1
assert "Related Keys" in m
assert "Remove Policy" in m
assert "Test Drive" in m
@@ -189,6 +189,7 @@ def setup_sssp(goto_sssp_menu, pick_menu_item, cap_story, press_select, pass_wor
if word_check:
assert "Enable?" in story
press_select() # confirm action
+ time.sleep(.1)
assert settings_get("sssp")["words"]
else:
assert "Disable?" in story
@@ -197,6 +198,7 @@ def setup_sssp(goto_sssp_menu, pick_menu_item, cap_story, press_select, pass_wor
assert not pol["words"]
if notes_and_pws is not None:
+ assert is_q1
pick_menu_item("Allow Notes")
time.sleep(.1)
title, story = cap_story()
@@ -699,5 +701,12 @@ def test_sssp_enforce_tmp_seed(setup_sssp, bitcoind, settings_set, settings_get,
_, story = cap_story()
assert "Spending Policy violation" in story
press_select()
+
+def test_sssp_notes_enable(only_q1, setup_sssp):
+ # just test menu item works
+ setup_sssp("11-11", mag=2, vel='6 blocks (hour)', notes_and_pws=True)
+def test_sssp_word_check(setup_sssp):
+ # just test menu item works
+ setup_sssp("11-11", mag=2, vel='6 blocks (hour)', word_check=True)
# EOF
Why this scored 18/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.