fix: restore Python 3.10/3.11 support and report MCP version
Testing / test (3.10) (push) Successful in 48s
Testing / test (3.12) (push) Successful in 47s
Testing / test (3.14) (push) Successful in 1m7s
Testing / remote-protocol-compat (0.15.0) (push) Successful in 6m59s
Testing / remote-protocol-compat (0.16.0) (push) Successful in 6m47s
Testing / test (3.15) (push) Successful in 6m20s

- Drop backslash from f-string expression in markdown/html.py
- That syntax needs 3.12+ (PEP 701) and broke import on 3.10/3.11
- Add Python matrix 3.10/3.12/3.14/3.15 to the Gitea testing workflow
- Pass project_version() to MCPServer; serverInfo.version was empty
- Cover the reported version with an in-memory MCP client test
- Swap deprecated click.get_text_stream for sys.stdin.isatty()
- Add explicit encoding to native host shim and manifest writes
- Add explicit encoding to the registry lock file open
- Add explicit encoding to every read_text/write_text call in tests
- Bump version to 0.16.10 in pyproject.toml and extension/manifest.json
- Move .python-version to 3.15 and refresh uv.lock

Extension code is unchanged; only the manifest version string moved.

Verified with 778 tests on 3.10 through 3.15, plus a strict run using -X warn_default_encoding with EncodingWarning and DeprecationWarning as errors.
This commit is contained in:
2026-10-20 12:41:25 +02:00
parent 7cb034dfc2
commit 69387c1054
19 changed files with 155 additions and 88 deletions
+10 -10
View File
@@ -74,7 +74,7 @@ class TestChallenge:
monkeypatch.setattr("browser_cli.auth.pq_kex_server_keypair", lambda: ("fake-private", b"fake-public"))
path = tmp_path / "authorized_keys"
_, pub = generate_keypair()
path.write_text(pub + "\n")
path.write_text(pub + "\n", encoding="utf-8")
client, server = _pair()
t = _spawn(server, path)
@@ -106,7 +106,7 @@ class TestRejection:
def test_missing_pubkey_sig_rejected(self, tmp_path):
path = tmp_path / "authorized_keys"
_, pub = generate_keypair()
path.write_text(pub + "\n")
path.write_text(pub + "\n", encoding="utf-8")
client, t, _ = self._connect(path)
msg = {"id": "x", "command": "tabs.list", "args": {}, "user_agent": FAKE_UA}
_send_framed(client, json.dumps(msg).encode())
@@ -119,7 +119,7 @@ class TestRejection:
def test_untrusted_pubkey_rejected(self, tmp_path):
path = tmp_path / "authorized_keys"
_, trusted_pub = generate_keypair()
path.write_text(trusted_pub + "\n")
path.write_text(trusted_pub + "\n", encoding="utf-8")
pem, untrusted_pub = generate_keypair()
key_path = tmp_path / "other.pem"
@@ -140,7 +140,7 @@ class TestRejection:
def test_bad_signature_rejected(self, tmp_path):
path = tmp_path / "authorized_keys"
_, pub = generate_keypair()
path.write_text(pub + "\n")
path.write_text(pub + "\n", encoding="utf-8")
client, t, _ = self._connect(path)
msg = {"id": "x", "command": "tabs.list", "args": {}, "user_agent": FAKE_UA, "pubkey": pub, "sig": "00" * 64}
_send_framed(client, json.dumps(msg).encode())
@@ -154,7 +154,7 @@ class TestRejection:
monkeypatch.setattr("browser_cli.auth.pq_kex_server_keypair", lambda: ("fake-private", b"fake-public"))
path = tmp_path / "authorized_keys"
pem, pub = generate_keypair()
path.write_text(pub + "\n")
path.write_text(pub + "\n", encoding="utf-8")
priv_path = tmp_path / "client.pem"
priv_path.write_bytes(pem)
priv = load_private_key(priv_path)
@@ -200,7 +200,7 @@ class TestAuthSuccess:
"""Correct signature → error must be 'browser not connected', not 'unauthorized'."""
path = tmp_path / "authorized_keys"
pem, pub = generate_keypair()
path.write_text(pub + "\n")
path.write_text(pub + "\n", encoding="utf-8")
key_path = tmp_path / "client.key.pem"
key_path.write_bytes(pem)
priv = load_private_key(key_path)
@@ -236,7 +236,7 @@ class TestAuthSuccess:
path = tmp_path / "authorized_keys"
pem, pub = generate_keypair()
path.write_text(pub + "\n")
path.write_text(pub + "\n", encoding="utf-8")
key_path = tmp_path / "client.key.pem"
key_path.write_bytes(pem)
priv = load_private_key(key_path)
@@ -276,7 +276,7 @@ class TestAuthSuccess:
path = tmp_path / "authorized_keys"
pem, pub = generate_keypair()
path.write_text(pub + "\n")
path.write_text(pub + "\n", encoding="utf-8")
key_path = tmp_path / "client.key.pem"
key_path.write_bytes(pem)
priv = load_private_key(key_path)
@@ -411,7 +411,7 @@ class TestPerKeyPolicy:
monkeypatch.setattr("browser_cli.client.targets.resolve_socket", _mock_no_browser)
path = tmp_path / "authorized_keys"
pem, pub = generate_keypair()
path.write_text(pub + "\n")
path.write_text(pub + "\n", encoding="utf-8")
key_path = tmp_path / "client.key.pem"
key_path.write_bytes(pem)
priv = load_private_key(key_path)
@@ -441,7 +441,7 @@ class TestPerKeyPolicy:
path = tmp_path / "authorized_keys"
pem, pub = generate_keypair()
path.write_text(pub + " mykey\n")
path.write_text(pub + " mykey\n", encoding="utf-8")
key_path = tmp_path / "client.key.pem"
key_path.write_bytes(pem)
priv = load_private_key(key_path)