refactor: reorganize client transport and extension internals

- Split client, native, remote, serve, markdown, and SDK internals into focused packages with direct imports.
- Move local and remote transport framing/protocol helpers behind clearer module boundaries.
- Break up the extension injected DOM logic into a separate content dispatch bundle and dedicated content modules.
- Add explicit client handling for passive remote discovery without noisy PQ warnings.
- Keep behavior covered with updated unit, integration, and extension tests.
This commit is contained in:
2026-06-13 23:31:24 +02:00
parent fd5447cbb9
commit 076914e5b7
88 changed files with 7491 additions and 5228 deletions
+10 -17
View File
@@ -20,8 +20,7 @@ from browser_cli.auth import (
sign,
verify,
)
from browser_cli.client import _is_valid_key_spec
from browser_cli.remote.registry import is_valid_key_spec
class TestGenerateKeypair:
def test_returns_pem_and_hex(self):
@@ -34,7 +33,6 @@ class TestGenerateKeypair:
_, pub2 = generate_keypair()
assert pub1 != pub2
class TestCanonicalPayload:
def test_strips_auth_protocol_fields(self):
msg = {"command": "tabs.list", "id": "x", "pubkey": "abc", "sig": "def", "pq_kex": {"alg": "ML-KEM-768"}}
@@ -52,7 +50,6 @@ class TestCanonicalPayload:
msg = {"b": 2, "a": 1}
assert canonical_payload(msg) == canonical_payload(msg)
@pytest.fixture()
def keypair(tmp_path):
pem, pub_hex = generate_keypair()
@@ -61,7 +58,6 @@ def keypair(tmp_path):
priv = load_private_key(key_path)
return priv, pub_hex
class TestSignVerify:
def test_valid_signature_verifies(self, keypair):
priv, pub_hex = keypair
@@ -112,7 +108,6 @@ class TestSignVerify:
def test_wrong_length_pubkey_returns_false_not_exception(self):
assert verify("aabbcc", b"nonce", {}, "00" * 64) is False
class TestPostQuantumKex:
def test_mlkem_roundtrip_when_backend_supports_it(self):
keypair = pq_kex_server_keypair()
@@ -143,7 +138,6 @@ class TestPostQuantumKex:
with pytest.raises(Exception):
pq_decrypt(secret, "response", envelope)
class TestAuthorizedKeys:
def test_add_and_load(self, tmp_path):
path = tmp_path / "authorized_keys"
@@ -175,32 +169,31 @@ class TestAuthorizedKeys:
def test_returns_empty_for_missing_file(self, tmp_path):
assert load_authorized_keys(tmp_path / "nofile") == []
class TestIsValidKeySpec:
def test_agent_bare(self):
assert _is_valid_key_spec("agent") is True
assert is_valid_key_spec("agent") is True
def test_agent_with_selector(self):
assert _is_valid_key_spec("agent:cardno:000012345678") is True
assert is_valid_key_spec("agent:cardno:000012345678") is True
def test_absolute_pem_path(self):
assert _is_valid_key_spec("/home/user/.config/browser-cli/client.key.pem") is True
assert is_valid_key_spec("/home/user/.config/browser-cli/client.key.pem") is True
def test_dot_key_extension(self):
assert _is_valid_key_spec("/tmp/mykey.key") is True
assert is_valid_key_spec("/tmp/mykey.key") is True
def test_angled_bracket_pem_rejected(self):
# regression: operator precedence bug allowed "<garbage>.pem" to pass
assert _is_valid_key_spec("<garbage>.pem") is False
assert is_valid_key_spec("<garbage>.pem") is False
def test_angled_bracket_key_rejected(self):
assert _is_valid_key_spec("<garbage>.key") is False
assert is_valid_key_spec("<garbage>.key") is False
def test_serialized_object_rejected(self):
assert _is_valid_key_spec("<AgentKey(blob=b'...', comment='test')>.pem") is False
assert is_valid_key_spec("<AgentKey(blob=b'...', comment='test')>.pem") is False
def test_empty_string_rejected(self):
assert _is_valid_key_spec("") is False
assert is_valid_key_spec("") is False
def test_bare_filename_no_slash_no_ext_rejected(self):
assert _is_valid_key_spec("mykey") is False
assert is_valid_key_spec("mykey") is False