Add Nostr sync reset/fresh namespace workflow and docs

This commit is contained in:
thePR0M3TH3AN committed 2026-03-01 01:24:33 -05:00
1 parent 24aa3f12a2
commit b9d6c0d49d
10 files changed
+328 -3

No files matched your search

+20
View File
@@ -24,3 +24,23 @@ def test_start_background_sync_offline(monkeypatch):
pm.sync_index_from_nostr = lambda: called.__setitem__("sync", True)
PasswordManager.start_background_sync(pm)
assert called["sync"] is False
def test_sync_vault_sets_last_error_on_exception():
pm = PasswordManager.__new__(PasswordManager)
pm.offline_mode = False
pm.get_encrypted_data = lambda: b"data"
pm.state_manager = None
async def boom(_data):
raise RuntimeError("relay write failed")
pm.nostr_client = SimpleNamespace(
publish_snapshot=boom,
get_delta_events=lambda: [],
last_error=None,
)
result = PasswordManager.sync_vault(pm)
assert result is None
assert pm.nostr_client.last_error == "relay write failed"
+10
View File
@@ -31,6 +31,16 @@ def test_handle_post_failure(capsys):
assert "❌ Sync failed…" in out
def test_handle_post_failure_shows_nostr_error(capsys):
pm = SimpleNamespace(
sync_vault=lambda alt_summary=None: None,
nostr_client=SimpleNamespace(last_error="Manifest out of date"),
)
main.handle_post_to_nostr(pm)
out = capsys.readouterr().out
assert "❌ Sync failed… Manifest out of date" in out
def test_handle_post_prints_all_ids(capsys):
pm = SimpleNamespace(
sync_vault=lambda alt_summary=None: {
+95
View File
@@ -17,6 +17,7 @@ import main
from nostr.client import DEFAULT_RELAYS
from seedpass.core.config_manager import ConfigManager
from seedpass.core.manager import Notification, PasswordManager
from seedpass.core.state_manager import StateManager
from seedpass.core.vault import Vault
from seedpass.core.errors import SeedPassError
from utils.fingerprint_manager import FingerprintManager
@@ -263,3 +264,97 @@ def test_settings_import_missing_path_message(monkeypatch, capsys):
out = capsys.readouterr().out
assert "Import failed: file 'missing.json.enc' not found." in out
def test_reset_nostr_sync_state(monkeypatch):
with TemporaryDirectory() as tmpdir:
tmp_path = Path(tmpdir)
pm, _, _ = setup_pm(tmp_path, monkeypatch)
fp_dir = tmp_path / ".seedpass" / "fp"
state_mgr = StateManager(fp_dir)
state_mgr.update_state(
manifest_id="manifest-old",
delta_since=123,
last_sync_ts=456,
nostr_account_idx=2,
)
pm.state_manager = state_mgr
pm.fingerprint_dir = fp_dir
pm.current_fingerprint = "fp"
pm.manifest_id = "manifest-old"
pm.delta_since = 123
pm.last_sync_ts = 456
monkeypatch.setattr(main, "confirm_action", lambda *_: True)
monkeypatch.setattr(main, "pause", lambda: None)
main.handle_reset_nostr_sync_state(pm)
state = state_mgr.state
assert state["manifest_id"] is None
assert state["delta_since"] == 0
assert state["last_sync_ts"] == 0
assert state["nostr_account_idx"] == 2
assert pm.manifest_id is None
assert pm.delta_since == 0
assert pm.last_sync_ts == 0
assert pm.nostr_account_idx == 2
def test_start_fresh_nostr_namespace(monkeypatch):
with TemporaryDirectory() as tmpdir:
tmp_path = Path(tmpdir)
pm, _, _ = setup_pm(tmp_path, monkeypatch)
fp_dir = tmp_path / ".seedpass" / "fp"
state_mgr = StateManager(fp_dir)
state_mgr.update_state(
manifest_id="manifest-old",
delta_since=123,
last_sync_ts=456,
nostr_account_idx=2,
)
pm.state_manager = state_mgr
pm.fingerprint_dir = fp_dir
pm.current_fingerprint = "fp"
pm.manifest_id = "manifest-old"
pm.delta_since = 123
pm.last_sync_ts = 456
called = {"reinit": 0}
pm._initialize_nostr_client = lambda: called.__setitem__(
"reinit", called["reinit"] + 1
)
monkeypatch.setattr(main, "confirm_action", lambda *_: True)
monkeypatch.setattr(main, "pause", lambda: None)
main.handle_start_fresh_nostr_namespace(pm)
state = state_mgr.state
assert state["manifest_id"] is None
assert state["delta_since"] == 0
assert state["last_sync_ts"] == 0
assert state["nostr_account_idx"] == 3
assert pm.nostr_account_idx == 3
assert called["reinit"] == 1
def test_nostr_menu_dispatches_reset_sync_state(monkeypatch):
with TemporaryDirectory() as tmpdir:
tmp_path = Path(tmpdir)
pm, _, _ = setup_pm(tmp_path, monkeypatch)
pm.update_activity = lambda: None
inputs = iter(["8", ""])
with patch("main.handle_reset_nostr_sync_state") as handler:
with patch("builtins.input", side_effect=lambda *_: next(inputs)):
main.handle_nostr_menu(pm)
handler.assert_called_once_with(pm)
def test_nostr_menu_dispatches_fresh_namespace(monkeypatch):
with TemporaryDirectory() as tmpdir:
tmp_path = Path(tmpdir)
pm, _, _ = setup_pm(tmp_path, monkeypatch)
pm.update_activity = lambda: None
inputs = iter(["9", ""])
with patch("main.handle_start_fresh_nostr_namespace") as handler:
with patch("builtins.input", side_effect=lambda *_: next(inputs)):
main.handle_nostr_menu(pm)
handler.assert_called_once_with(pm)