summaryrefslogtreecommitdiffstats
path: root/packages/meshbay-node/tests
diff options
context:
space:
mode:
authorChristophe Besson <cbesson@gmail.com>2026-08-09 04:05:16 +0200
committerChristophe Besson <cbesson@gmail.com>2026-08-09 04:05:16 +0200
commit6b6b1a9d2febaa75da7609db671a82a458b40b4b (patch)
tree4865497ae89be70aed4f83e81f059d2a6f56a0e3 /packages/meshbay-node/tests
parente3af7d272bec0bdc426bdad16ad0ad2f203e8113 (diff)
downloadmeshbay-6b6b1a9d2febaa75da7609db671a82a458b40b4b.tar.gz
feat(node): add keystore module with 3 unlock modes
Argon2id + AES-256-GCM encryption at rest. Unlock via env var (MESHBAY_UNLOCK_KEY), unlock.key file (chmod 600), or interactive getpass. 10/10 tests passing. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Diffstat (limited to 'packages/meshbay-node/tests')
-rw-r--r--packages/meshbay-node/tests/test_keystore.py100
1 files changed, 100 insertions, 0 deletions
diff --git a/packages/meshbay-node/tests/test_keystore.py b/packages/meshbay-node/tests/test_keystore.py
new file mode 100644
index 0000000..b3c2b56
--- /dev/null
+++ b/packages/meshbay-node/tests/test_keystore.py
@@ -0,0 +1,100 @@
+"""Tests for meshbay_node.keystore."""
+
+import pytest
+from pathlib import Path
+from meshbay_node.keystore import (
+ NodeKeys,
+ create_keystore,
+ load_keystore,
+ save_keystore,
+ load_or_create_keystore,
+)
+from meshbay_common.crypto import generate_gek
+
+
+def test_create_and_load(tmp_path):
+ path = tmp_path / "keystore.enc"
+ keys = create_keystore(path=path, password="testpass99")
+
+ assert keys.sk_ed25519 is not None
+ assert keys.sk_x25519 is not None
+ assert keys.gek is None
+ assert len(keys.pk_ed25519_b64) == 44 # 32 bytes → 44 base64 chars
+ assert len(keys.pk_x25519_b64) == 44
+ assert path.exists()
+ assert oct(path.stat().st_mode)[-3:] == "600"
+
+ loaded = load_keystore(path=path, password="testpass99")
+ assert loaded.pk_ed25519_b64 == keys.pk_ed25519_b64
+ assert loaded.pk_x25519_b64 == keys.pk_x25519_b64
+ assert loaded.gek is None
+
+
+def test_wrong_password_rejected(tmp_path):
+ path = tmp_path / "keystore.enc"
+ create_keystore(path=path, password="correctpass")
+ with pytest.raises(ValueError, match="Wrong password"):
+ load_keystore(path=path, password="wrongpass")
+
+
+def test_create_fails_if_exists(tmp_path):
+ path = tmp_path / "keystore.enc"
+ create_keystore(path=path, password="pass12345")
+ with pytest.raises(FileExistsError):
+ create_keystore(path=path, password="pass12345")
+
+
+def test_load_fails_if_missing(tmp_path):
+ with pytest.raises(FileNotFoundError):
+ load_keystore(path=tmp_path / "nonexistent.enc", password="x")
+
+
+def test_save_with_gek(tmp_path):
+ path = tmp_path / "keystore.enc"
+ keys = create_keystore(path=path, password="testpass99")
+ gek = generate_gek()
+ keys.gek = gek
+
+ save_keystore(keys, path=path, password="testpass99")
+
+ reloaded = load_keystore(path=path, password="testpass99")
+ assert reloaded.gek == gek
+
+
+def test_load_or_create_creates(tmp_path):
+ path = tmp_path / "keystore.enc"
+ keys = load_or_create_keystore(path=path, password="testpass99")
+ assert keys.sk_ed25519 is not None
+ assert path.exists()
+
+
+def test_load_or_create_loads(tmp_path):
+ path = tmp_path / "keystore.enc"
+ k1 = load_or_create_keystore(path=path, password="testpass99")
+ k2 = load_or_create_keystore(path=path, password="testpass99")
+ assert k1.pk_ed25519_b64 == k2.pk_ed25519_b64
+
+
+def test_keys_unique_per_creation(tmp_path):
+ k1 = create_keystore(path=tmp_path / "k1.enc", password="p1234567")
+ k2 = create_keystore(path=tmp_path / "k2.enc", password="p1234567")
+ assert k1.pk_ed25519_b64 != k2.pk_ed25519_b64
+
+
+def test_env_var_unlock(tmp_path, monkeypatch):
+ path = tmp_path / "keystore.enc"
+ create_keystore(path=path, password="envpass42")
+ monkeypatch.setenv("MESHBAY_UNLOCK_KEY", "envpass42")
+ keys = load_keystore(path=path) # no password arg
+ assert keys.sk_ed25519 is not None
+
+
+def test_unlock_file(tmp_path):
+ path = tmp_path / "keystore.enc"
+ kf_path = tmp_path / "unlock.key"
+ kf_path.write_text("filepass42")
+ kf_path.chmod(0o600)
+
+ create_keystore(path=path, password="filepass42")
+ keys = load_keystore(path=path, unlock_file=kf_path) # no password arg
+ assert keys.sk_ed25519 is not None