mirror of
https://github.com/PR0M3TH3AN/SeedPass.git
synced 2026-10-27 07:52:03 +00:00
Fix display service input hooks and clean pytest warnings
This commit is contained in:
1 parent
44a5afa99b
commit
4459dfea78
4 files changed
+66
-28
No files matched your search
+13
-6
@@ -1,11 +1,18 @@
|
||||
# Memory Update — scheduler-update-agent — 2026-02-26
|
||||
# Memory Update — codex — 2026-02-26
|
||||
|
||||
## Key findings
|
||||
- Roster json is perfectly synced with prompt directories.
|
||||
- No discrepancies found in daily or weekly rosters.
|
||||
- Full test suite now passes: `766 passed, 11 skipped`.
|
||||
- `DisplayService` had diverged from `seedpass.core.manager` interactive helpers, causing test monkeypatches to miss and resulting in flaky behavior.
|
||||
|
||||
## Bugs fixed
|
||||
- Fixed TOTP retrieve/edit regression where `test_edit_totp_period_from_retrieve` could fail in-suite because TOTP screen consumed input via unpatched `display_service.timed_input`.
|
||||
- Fixed suite hang at `test_show_seed_entry_details` caused by `display_service.confirm_action` bypassing patched `manager.confirm_action`, leading to infinite prompt loop on empty input.
|
||||
|
||||
## Patterns / reusable knowledge
|
||||
- Always verify file existence before assuming roster drift.
|
||||
- In this codebase, interactive helpers should be called through `seedpass.core.manager` symbols (`confirm_action`, `timed_input`, `copy_to_clipboard`) to keep behavior and tests consistent.
|
||||
|
||||
## Warnings / gotchas
|
||||
- Ensure correct path prefix when running in host-repo mode.
|
||||
## Follow-up (warnings cleanup)
|
||||
- Added pytest `markers` registration for `network` under `[tool.pytest.ini_options]` to remove `PytestUnknownMarkWarning`.
|
||||
- Added narrow pytest warning filters for known third-party GUI deprecation noise (`Pack.padding*`).
|
||||
- For `imghdr` deprecation triggered during `test_imghdr_stub` import, added a local `warnings.filterwarnings(...)` at top of that test module to suppress import-time warning deterministically.
|
||||
- Verified final suite status: `766 passed, 11 skipped`, no warnings.
|
||||
@@ -72,6 +72,18 @@ python_version = "3.11"
|
||||
strict = true
|
||||
mypy_path = "src"
|
||||
|
||||
[tool.pytest.ini_options]
|
||||
markers = [
|
||||
"network: tests that require network access",
|
||||
]
|
||||
filterwarnings = [
|
||||
"ignore:'imghdr' is deprecated and slated for removal in Python 3.13:DeprecationWarning:pgpy.constants",
|
||||
"ignore:'imghdr' is deprecated and will be removed in Python 3.13:DeprecationWarning:src.tests.test_imghdr_stub",
|
||||
"ignore:'imghdr' is deprecated and will be removed in Python 3.13:DeprecationWarning",
|
||||
"ignore:Pack.padding_top is deprecated. Use Pack.margin_top instead.:DeprecationWarning",
|
||||
"ignore:Pack.padding is deprecated. Use Pack.margin instead.:DeprecationWarning",
|
||||
]
|
||||
|
||||
[tool.briefcase]
|
||||
project_name = "SeedPass"
|
||||
bundle = "io.seedpass"
|
||||
|
||||
@@ -9,10 +9,7 @@ from termcolor import colored
|
||||
|
||||
from seedpass.core.entry_types import EntryType
|
||||
from seedpass.core.totp import TotpManager
|
||||
from utils.clipboard import copy_to_clipboard
|
||||
from utils.color_scheme import color_text
|
||||
from utils.input_utils import timed_input
|
||||
from utils.password_prompt import confirm_action
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from seedpass.core.manager import PasswordManager
|
||||
@@ -26,6 +23,25 @@ class DisplayService:
|
||||
def __init__(self, manager: PasswordManager) -> None:
|
||||
self.manager = manager
|
||||
|
||||
@staticmethod
|
||||
def _manager_module():
|
||||
# Route interactive helpers through seedpass.core.manager so tests
|
||||
# can monkeypatch one module surface consistently.
|
||||
from seedpass.core import manager as manager_module
|
||||
|
||||
return manager_module
|
||||
|
||||
def _confirm_action(self, prompt_message: str) -> bool:
|
||||
return self._manager_module().confirm_action(prompt_message)
|
||||
|
||||
def _copy_to_clipboard(self, value: str) -> bool:
|
||||
return self._manager_module().copy_to_clipboard(
|
||||
value, self.manager.clipboard_clear_delay
|
||||
)
|
||||
|
||||
def _timed_input(self, prompt: str, timeout: float) -> str:
|
||||
return self._manager_module().timed_input(prompt, timeout)
|
||||
|
||||
def display_sensitive_entry_info(self, entry: dict, index: int) -> None:
|
||||
"""Display information for a sensitive entry.
|
||||
|
||||
@@ -70,7 +86,7 @@ class DisplayService:
|
||||
while True:
|
||||
code = TotpManager.current_code_from_secret(secret)
|
||||
if self.manager.secret_mode_enabled:
|
||||
if copy_to_clipboard(code, self.manager.clipboard_clear_delay):
|
||||
if self._copy_to_clipboard(code):
|
||||
print(
|
||||
colored(
|
||||
f"[+] 2FA code for '{label}' copied to clipboard. Will clear in {self.manager.clipboard_clear_delay} seconds.",
|
||||
@@ -96,7 +112,7 @@ class DisplayService:
|
||||
sys.stdout.write(f"\r{bar} {remaining:2d}s")
|
||||
sys.stdout.flush()
|
||||
try:
|
||||
user_input = timed_input("", 1)
|
||||
user_input = self._timed_input("", 1)
|
||||
if (
|
||||
user_input.strip() == ""
|
||||
or user_input.strip().lower() == "b"
|
||||
@@ -121,7 +137,7 @@ class DisplayService:
|
||||
def _display_ssh(self, entry: dict, index: int) -> None:
|
||||
notes = entry.get("notes", "")
|
||||
label = entry.get("label", "")
|
||||
if not confirm_action(
|
||||
if not self._confirm_action(
|
||||
"WARNING: Displaying SSH keys reveals sensitive information. Continue? (Y/N): "
|
||||
):
|
||||
self.manager.notify("SSH key display cancelled.", level="WARNING")
|
||||
@@ -141,7 +157,7 @@ class DisplayService:
|
||||
print(colored("Public Key:", "cyan"))
|
||||
print(color_text(pub_pem, "default"))
|
||||
if self.manager.secret_mode_enabled:
|
||||
if copy_to_clipboard(priv_pem, self.manager.clipboard_clear_delay):
|
||||
if self._copy_to_clipboard(priv_pem):
|
||||
print(
|
||||
colored(
|
||||
f"[+] SSH private key copied to clipboard. Will clear in {self.manager.clipboard_clear_delay} seconds.",
|
||||
@@ -158,7 +174,7 @@ class DisplayService:
|
||||
def _display_seed(self, entry: dict, index: int) -> None:
|
||||
notes = entry.get("notes", "")
|
||||
label = entry.get("label", "")
|
||||
if not confirm_action(
|
||||
if not self._confirm_action(
|
||||
"WARNING: Displaying the seed phrase reveals sensitive information. Continue? (Y/N): "
|
||||
):
|
||||
self.manager.notify("Seed phrase display cancelled.", level="WARNING")
|
||||
@@ -177,7 +193,7 @@ class DisplayService:
|
||||
if tags:
|
||||
print(colored(f"Tags: {', '.join(tags)}", "cyan"))
|
||||
if self.manager.secret_mode_enabled:
|
||||
if copy_to_clipboard(phrase, self.manager.clipboard_clear_delay):
|
||||
if self._copy_to_clipboard(phrase):
|
||||
print(
|
||||
colored(
|
||||
f"[+] Seed phrase copied to clipboard. Will clear in {self.manager.clipboard_clear_delay} seconds.",
|
||||
@@ -186,7 +202,7 @@ class DisplayService:
|
||||
)
|
||||
else:
|
||||
print(color_text(phrase, "deterministic"))
|
||||
if confirm_action("Show derived entropy as hex? (Y/N): "):
|
||||
if self._confirm_action("Show derived entropy as hex? (Y/N): "):
|
||||
from local_bip85.bip85 import BIP85
|
||||
from bip_utils import Bip39SeedGenerator
|
||||
|
||||
@@ -208,7 +224,7 @@ class DisplayService:
|
||||
def _display_pgp(self, entry: dict, index: int) -> None:
|
||||
notes = entry.get("notes", "")
|
||||
label = entry.get("user_id", "")
|
||||
if not confirm_action(
|
||||
if not self._confirm_action(
|
||||
"WARNING: Displaying the PGP key reveals sensitive information. Continue? (Y/N): "
|
||||
):
|
||||
self.manager.notify("PGP key display cancelled.", level="WARNING")
|
||||
@@ -227,7 +243,7 @@ class DisplayService:
|
||||
print(colored(f"Tags: {', '.join(tags)}", "cyan"))
|
||||
print(colored(f"Fingerprint: {fingerprint}", "cyan"))
|
||||
if self.manager.secret_mode_enabled:
|
||||
if copy_to_clipboard(priv_key, self.manager.clipboard_clear_delay):
|
||||
if self._copy_to_clipboard(priv_key):
|
||||
print(
|
||||
colored(
|
||||
f"[+] PGP key copied to clipboard. Will clear in {self.manager.clipboard_clear_delay} seconds.",
|
||||
@@ -251,7 +267,7 @@ class DisplayService:
|
||||
print(colored(f"Label: {label}", "cyan"))
|
||||
print(colored(f"npub: {npub}", "cyan"))
|
||||
if self.manager.secret_mode_enabled:
|
||||
if copy_to_clipboard(nsec, self.manager.clipboard_clear_delay):
|
||||
if self._copy_to_clipboard(nsec):
|
||||
print(
|
||||
colored(
|
||||
f"[+] nsec copied to clipboard. Will clear in {self.manager.clipboard_clear_delay} seconds.",
|
||||
@@ -286,7 +302,7 @@ class DisplayService:
|
||||
)
|
||||
)
|
||||
if self.manager.secret_mode_enabled:
|
||||
if copy_to_clipboard(value, self.manager.clipboard_clear_delay):
|
||||
if self._copy_to_clipboard(value):
|
||||
print(
|
||||
colored(
|
||||
f"[+] Value copied to clipboard. Will clear in {self.manager.clipboard_clear_delay} seconds.",
|
||||
@@ -313,9 +329,7 @@ class DisplayService:
|
||||
if show == "y":
|
||||
for f_label, f_value in hidden_fields:
|
||||
if self.manager.secret_mode_enabled:
|
||||
if copy_to_clipboard(
|
||||
f_value, self.manager.clipboard_clear_delay
|
||||
):
|
||||
if self._copy_to_clipboard(f_value):
|
||||
print(
|
||||
colored(
|
||||
f"[+] {f_label} copied to clipboard. Will clear in {self.manager.clipboard_clear_delay} seconds.",
|
||||
@@ -355,7 +369,7 @@ class DisplayService:
|
||||
index, self.manager.parent_seed
|
||||
)
|
||||
if self.manager.secret_mode_enabled:
|
||||
if copy_to_clipboard(seed, self.manager.clipboard_clear_delay):
|
||||
if self._copy_to_clipboard(seed):
|
||||
print(
|
||||
colored(
|
||||
f"[+] Seed phrase copied to clipboard. Will clear in {self.manager.clipboard_clear_delay} seconds.",
|
||||
@@ -398,7 +412,7 @@ class DisplayService:
|
||||
|
||||
if password:
|
||||
if self.manager.secret_mode_enabled:
|
||||
if copy_to_clipboard(password, self.manager.clipboard_clear_delay):
|
||||
if self._copy_to_clipboard(password):
|
||||
print(
|
||||
colored(
|
||||
f"[+] Password for '{website_name}' copied to clipboard. Will clear in {self.manager.clipboard_clear_delay} seconds.",
|
||||
@@ -443,9 +457,7 @@ class DisplayService:
|
||||
if show == "y":
|
||||
for label, value in hidden_fields:
|
||||
if self.manager.secret_mode_enabled:
|
||||
if copy_to_clipboard(
|
||||
value, self.manager.clipboard_clear_delay
|
||||
):
|
||||
if self._copy_to_clipboard(value):
|
||||
print(
|
||||
colored(
|
||||
f"[+] {label} copied to clipboard. Will clear in {self.manager.clipboard_clear_delay} seconds.",
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
import pytest
|
||||
import io
|
||||
import warnings
|
||||
|
||||
warnings.filterwarnings(
|
||||
"ignore",
|
||||
message="'imghdr' is deprecated and will be removed in Python 3.13",
|
||||
category=DeprecationWarning,
|
||||
)
|
||||
from utils.imghdr_stub import what
|
||||
|
||||
|
||||
|
||||
Reference in new issue
Block a user