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
+11 -10
View File
@@ -64,39 +64,39 @@ def test_full_control_still_cannot_manage_keys():
def test_set_policy_updates_by_pubkey(tmp_path):
path = tmp_path / "authorized_keys"
pub = "a" * 64
path.write_text(f"{pub} laptop\n")
path.write_text(f"{pub} laptop\n", encoding="utf-8")
assert set_authorized_key_policy(path, pub, ["control"]) == (pub, "laptop")
assert load_authorized_keys_with_policies(path) == [(pub, "laptop", ["control"])]
def test_set_policy_by_name_and_remove_with_none(tmp_path):
path = tmp_path / "authorized_keys"
pub = "b" * 64
path.write_text(f"{pub} ci-bot allow:all\n")
path.write_text(f"{pub} ci-bot allow:all\n", encoding="utf-8")
assert set_authorized_key_policy(path, "ci-bot", None) == (pub, "ci-bot") # remove token
assert load_authorized_keys_with_policies(path) == [(pub, "ci-bot", None)]
def test_set_policy_safe_only_writes_empty_token(tmp_path):
path = tmp_path / "authorized_keys"
pub = "c" * 64
path.write_text(f"{pub} reader\n")
path.write_text(f"{pub} reader\n", encoding="utf-8")
set_authorized_key_policy(path, pub, [])
assert path.read_text().strip() == f"{pub} reader allow:"
assert path.read_text(encoding="utf-8").strip() == f"{pub} reader allow:"
def test_set_policy_not_found_returns_none(tmp_path):
path = tmp_path / "authorized_keys"
path.write_text(f"{'a' * 64} laptop\n")
path.write_text(f"{'a' * 64} laptop\n", encoding="utf-8")
assert set_authorized_key_policy(path, "nonexistent", ["control"]) is None
def test_set_policy_ambiguous_name_raises(tmp_path):
path = tmp_path / "authorized_keys"
path.write_text(f"{'a' * 64} dup\n{'b' * 64} dup\n")
path.write_text(f"{'a' * 64} dup\n{'b' * 64} dup\n", encoding="utf-8")
with pytest.raises(ValueError, match="ambiguous"):
set_authorized_key_policy(path, "dup", ["control"])
def test_set_policy_preserves_other_lines(tmp_path):
path = tmp_path / "authorized_keys"
a, b = "a" * 64, "b" * 64
path.write_text(f"{a} first\n{b} second allow:read-page\n")
path.write_text(f"{a} first\n{b} second allow:read-page\n", encoding="utf-8")
set_authorized_key_policy(path, a, ["control"])
assert load_authorized_keys_with_policies(path) == [
(a, "first", ["control"]),
@@ -139,7 +139,8 @@ def test_key_policies_from_authorized_keys(tmp_path):
path.write_text(
"AABBCC laptop allow:all\n"
"ddee01 ci-bot allow:read-page,control\n"
"112233 readonly\n" # no allow token → no override entry
"112233 readonly\n", # no allow token → no override entry
encoding="utf-8",
)
policies = key_policies_from_authorized_keys(path)
assert policies["aabbcc"] == CommandPolicy.unrestricted() # normalised to lowercase
@@ -151,13 +152,13 @@ def test_key_policies_none_returns_empty():
def test_key_policies_rejects_unknown_category(tmp_path):
path = tmp_path / "authorized_keys"
path.write_text("abc name allow:bogus\n")
path.write_text("abc name allow:bogus\n", encoding="utf-8")
with pytest.raises(ValueError, match="unknown command category"):
key_policies_from_authorized_keys(path)
def test_load_with_names_ignores_allow_token(tmp_path):
path = tmp_path / "authorized_keys"
path.write_text("abc my laptop allow:control\n")
path.write_text("abc my laptop allow:control\n", encoding="utf-8")
assert load_authorized_keys_with_names(path) == [("abc", "my laptop")]
assert load_authorized_keys_with_policies(path) == [("abc", "my laptop", ["control"])]