feat: publish Hermes Nextcloud calendar MCP under AGPL-3.0
This commit is contained in:
126
tests/test_wallet_protection.py
Normal file
126
tests/test_wallet_protection.py
Normal file
@@ -0,0 +1,126 @@
|
||||
import os
|
||||
|
||||
import pytest
|
||||
|
||||
from hermes_caldav_mcp import wallet_protection as protection
|
||||
from hermes_caldav_mcp.types import SafeError
|
||||
from hermes_caldav_mcp.wallets import WalletChoice
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def no_native_windows(monkeypatch):
|
||||
monkeypatch.setattr(protection, "open_manager", lambda _: False)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"header,state",
|
||||
[
|
||||
(b"GnomeKeyring\n\r\0\n\0\0\0\0", "protected"),
|
||||
(b"[keyring]\n", "unprotected"),
|
||||
(b"unknown format", "unknown"),
|
||||
(b"GnomeKeyring\n\r\0\n\1\0\0\0", "unknown"),
|
||||
],
|
||||
)
|
||||
def test_gnome_checks_exact_collection_header_only(tmp_path, header, state):
|
||||
root = tmp_path / "keyrings"
|
||||
root.mkdir()
|
||||
(root / "login.keyring").write_bytes(header + b"synthetic secret payload")
|
||||
result = protection.inspect_file("gnome", "login", tmp_path)
|
||||
assert result.state == state
|
||||
assert "synthetic" not in repr(result)
|
||||
|
||||
|
||||
def test_other_wallet_file_does_not_prove_selected_wallet(tmp_path):
|
||||
root = tmp_path / "keyrings"
|
||||
root.mkdir()
|
||||
(root / "other.keyring").write_bytes(b"GnomeKeyring\n\r\0\n\0\0\0\0")
|
||||
assert protection.inspect_file("gnome", "login", tmp_path).state == "unknown"
|
||||
assert protection.inspect_file("gnome", "../other", tmp_path).state == "unknown"
|
||||
|
||||
|
||||
def test_kwallet_encrypted_header_does_not_prove_nonempty_password(tmp_path):
|
||||
root = tmp_path / "kwalletd"
|
||||
root.mkdir()
|
||||
(root / "kdewallet.kwl").write_bytes(b"KWALLET\n\r\0\r\n\0\1\0\0" + b"x" * 80)
|
||||
result = protection.inspect_file("kde", "kdewallet", tmp_path)
|
||||
assert result.state == "unknown"
|
||||
assert result.encrypted_format
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"version,recognized",
|
||||
[
|
||||
(bytes([0, 0, 0, 0]), True),
|
||||
(bytes([0, 1, 3, 2]), True),
|
||||
(bytes([0, 1, 2, 0]), True),
|
||||
(bytes([0, 1, 1, 0]), False),
|
||||
(bytes([9, 1, 3, 2]), False),
|
||||
(bytes([0, 1, 3, 99]), False),
|
||||
],
|
||||
)
|
||||
def test_kwallet_known_ciphers_are_recognized_without_claiming_password_protection(
|
||||
tmp_path, version, recognized
|
||||
):
|
||||
root = tmp_path / "kwalletd"
|
||||
root.mkdir()
|
||||
(root / "kdewallet.kwl").write_bytes(b"KWALLET\n\r\0\r\n" + version + b"x" * 80)
|
||||
result = protection.inspect_file("kde", "kdewallet", tmp_path)
|
||||
assert result.state == "unknown"
|
||||
assert result.encrypted_format is recognized
|
||||
|
||||
|
||||
def test_symlink_and_fifo_are_not_read_as_wallets(tmp_path):
|
||||
root = tmp_path / "keyrings"
|
||||
root.mkdir()
|
||||
target = tmp_path / "other"
|
||||
target.write_bytes(b"GnomeKeyring\n\r\0\n\0\0\0\0")
|
||||
path = root / "login.keyring"
|
||||
path.symlink_to(target)
|
||||
assert protection.inspect_file("gnome", "login", tmp_path).state == "unknown"
|
||||
path.unlink()
|
||||
os.mkfifo(path)
|
||||
assert protection.inspect_file("gnome", "login", tmp_path).state == "unknown"
|
||||
|
||||
|
||||
@pytest.mark.parametrize("state", ["unknown", "unprotected"])
|
||||
def test_override_requires_explicit_nondefault_choice(monkeypatch, state):
|
||||
replies = iter(["", "3"])
|
||||
monkeypatch.setattr("builtins.input", lambda _: next(replies))
|
||||
monkeypatch.setattr(
|
||||
protection, "inspect_storage", lambda _: protection.StorageStatus(state)
|
||||
)
|
||||
with pytest.raises(SafeError):
|
||||
protection.ensure_storage(WalletChoice("kde"))
|
||||
|
||||
|
||||
def test_unprotected_override_is_distinct_from_verified_storage(monkeypatch):
|
||||
replies = iter(["2"])
|
||||
monkeypatch.setattr("builtins.input", lambda _: next(replies))
|
||||
monkeypatch.setattr(
|
||||
protection, "inspect_storage", lambda _: protection.StorageStatus("unprotected")
|
||||
)
|
||||
assert protection.ensure_storage(WalletChoice("gnome")) is False
|
||||
|
||||
|
||||
def test_protected_storage_needs_no_confirmation(monkeypatch):
|
||||
monkeypatch.setattr(
|
||||
protection,
|
||||
"inspect_storage",
|
||||
lambda _: protection.StorageStatus("protected", True),
|
||||
)
|
||||
monkeypatch.setattr("builtins.input", lambda _: pytest.fail("Unnecessary prompt"))
|
||||
assert protection.ensure_storage(WalletChoice("gnome")) is True
|
||||
|
||||
|
||||
def test_guided_password_setup_rechecks_before_accepting(monkeypatch):
|
||||
replies = iter(["", "1"])
|
||||
states = iter(
|
||||
[
|
||||
protection.StorageStatus("unknown"),
|
||||
protection.StorageStatus("protected", True),
|
||||
]
|
||||
)
|
||||
monkeypatch.setattr("builtins.input", lambda _: next(replies))
|
||||
monkeypatch.setattr(protection, "inspect_storage", lambda _: next(states))
|
||||
monkeypatch.setattr(protection, "open_manager", lambda _: True)
|
||||
assert protection.ensure_storage(WalletChoice("gnome")) is True
|
||||
Reference in New Issue
Block a user