refactor: split compat into package, harden serve proxy (v0.9.3)
Testing / test (push) Failing after 10m21s

- compat.py → compat/ package: auth.py (auth-field normalizers),
  commands.py (command-format shims), __init__.py (re-exports)
- Add _auth_0_9_3 transformer: normalizes pubkey to lowercase before auth
  so clients < 0.9.3 sending uppercase hex are accepted
- adapt_auth() now called before auth check in serve.py; command extracted
  after adapt_auth so future transformers can rename commands safely
- serve.py: deduplicate _recv_exact (import from client), unify
  resp/resp_payload across Windows/Unix branches, require lowercase hex
  pubkey (re.fullmatch), reorganize imports, drop unused os import
- client.py: move payload/framed construction inside branches (remote path
  no longer serializes JSON it never uses); fix _is_valid_key_spec
  operator precedence; import MAX_MSG_BYTES from version_manager
- auth.py: narrow except clause (ValueError instead of bare Exception)
- Bump version 0.9.2 → 0.9.3

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-03 10:12:55 +02:00
parent c1a5ef9dd7
commit 0d5c49c19a
26 changed files with 630 additions and 352 deletions
+28 -28
View File
@@ -262,12 +262,12 @@ def test_tabs_list_multi_browser_shows_browser_column():
return [{"id": 1 if profile == "default" else 2, "windowId": 1, "active": True, "title": profile, "url": "https://example.com"}]
with patch(
"browser_cli.commands.tabs.active_browser_targets",
"browser_cli.commands.active_browser_targets",
return_value=[
BrowserTarget("default", "550e8400-e29b-41d4-a716-446655440000", "/tmp/default.sock"),
BrowserTarget("work", "work", "/tmp/work.sock"),
],
), patch("browser_cli.commands.tabs.send_command", side_effect=fake_send_command):
), patch("browser_cli.commands.send_command", side_effect=fake_send_command):
result = CliRunner().invoke(main, ["tabs", "list"])
assert result.exit_code == 0
@@ -278,13 +278,13 @@ def test_tabs_list_multi_browser_shows_browser_column():
def test_tabs_list_with_remote_uses_only_remote_targets():
with patch(
"browser_cli.commands.tabs.active_browser_targets",
"browser_cli.commands.active_browser_targets",
side_effect=AssertionError("local targets should not be used for explicit remote"),
), patch(
"browser_cli.commands.tabs.remote_browser_targets",
"browser_cli.commands.remote_browser_targets",
return_value=[BrowserTarget("work", "remote-host:work", "", remote="remote-host:8765")],
), patch(
"browser_cli.commands.tabs.send_command",
"browser_cli.commands.send_command",
return_value=[{"id": 1, "windowId": 1, "active": True, "title": "Remote", "url": "https://example.com"}],
) as send_command:
result = CliRunner().invoke(main, ["--remote", "remote-host:8765", "tabs", "list"])
@@ -297,13 +297,13 @@ def test_tabs_list_with_remote_uses_only_remote_targets():
def test_tabs_list_with_explicit_browser_does_not_show_browser_column():
with patch(
"browser_cli.commands.tabs.active_browser_targets",
"browser_cli.commands.active_browser_targets",
return_value=[
BrowserTarget("default", "uuid-1", "/tmp/default.sock"),
BrowserTarget("work", "work", "/tmp/work.sock"),
],
), patch(
"browser_cli.commands.tabs.send_command",
"browser_cli.commands.send_command",
return_value=[{"id": 1, "windowId": 1, "active": True, "title": "Example", "url": "https://example.com"}],
) as send_command:
result = CliRunner().invoke(main, ["--browser", "work", "tabs", "list"])
@@ -322,12 +322,12 @@ def test_tabs_count_multi_browser_shows_total():
return counts[profile]
with patch(
"browser_cli.commands.tabs.active_browser_targets",
"browser_cli.commands.active_browser_targets",
return_value=[
BrowserTarget("default", "uuid-1", "/tmp/default.sock"),
BrowserTarget("work", "work", "/tmp/work.sock"),
],
), patch("browser_cli.commands.tabs.send_command", side_effect=fake_send_command):
), patch("browser_cli.commands.send_command", side_effect=fake_send_command):
result = CliRunner().invoke(main, ["tabs", "count", "github"])
assert result.exit_code == 0
@@ -344,12 +344,12 @@ def test_group_count_multi_browser_shows_total():
return counts[profile]
with patch(
"browser_cli.commands.groups.active_browser_targets",
"browser_cli.commands.active_browser_targets",
return_value=[
BrowserTarget("default", "uuid-1", "/tmp/default.sock"),
BrowserTarget("work", "work", "/tmp/work.sock"),
],
), patch("browser_cli.commands.groups.send_command", side_effect=fake_send_command):
), patch("browser_cli.commands.send_command", side_effect=fake_send_command):
result = CliRunner().invoke(main, ["groups", "count"])
assert result.exit_code == 0
@@ -360,7 +360,7 @@ def test_group_count_multi_browser_shows_total():
def test_group_list_leaves_unnamed_group_cell_empty():
with patch(
"browser_cli.commands.groups.send_command",
"browser_cli.commands.send_command",
return_value=[{"id": 42, "title": "", "color": "grey", "collapsed": False, "tabCount": 1}],
):
result = CliRunner().invoke(main, ["groups", "list"])
@@ -372,7 +372,7 @@ def test_group_list_leaves_unnamed_group_cell_empty():
def test_tabs_move_accepts_right_short_alias():
with patch("browser_cli.commands.tabs.send_command") as send_command:
with patch("browser_cli.commands.send_command") as send_command:
result = CliRunner().invoke(main, ["tabs", "move", "12", "-r"])
assert result.exit_code == 0
@@ -384,7 +384,7 @@ def test_tabs_move_accepts_right_short_alias():
def test_groups_move_accepts_left_short_alias():
with patch("browser_cli.commands.groups.send_command") as send_command:
with patch("browser_cli.commands.send_command") as send_command:
result = CliRunner().invoke(main, ["groups", "move", "research", "-l"])
assert result.exit_code == 0
@@ -399,12 +399,12 @@ def test_windows_list_multi_browser_shows_browser_column():
return [{"id": 1, "alias": profile, "focused": True, "tabCount": 2, "state": "normal"}]
with patch(
"browser_cli.commands.windows.active_browser_targets",
"browser_cli.commands.active_browser_targets",
return_value=[
BrowserTarget("default", "uuid-1", "/tmp/default.sock"),
BrowserTarget("work", "work", "/tmp/work.sock"),
],
), patch("browser_cli.commands.windows.send_command", side_effect=fake_send_command):
), patch("browser_cli.commands.send_command", side_effect=fake_send_command):
result = CliRunner().invoke(main, ["windows", "list"])
assert result.exit_code == 0
@@ -420,12 +420,12 @@ def test_session_list_multi_browser_shows_browser_column():
return [{"name": f"{profile}-session", "tabs": 2, "savedAt": 1712707200000}]
with patch(
"browser_cli.commands.session.active_browser_targets",
"browser_cli.commands.active_browser_targets",
return_value=[
BrowserTarget("default", "uuid-1", "/tmp/default.sock"),
BrowserTarget("work", "work", "/tmp/work.sock"),
],
), patch("browser_cli.commands.session.send_command", side_effect=fake_send_command):
), patch("browser_cli.commands.send_command", side_effect=fake_send_command):
result = CliRunner().invoke(main, ["session", "list"])
assert result.exit_code == 0
@@ -438,13 +438,13 @@ def test_session_list_multi_browser_shows_browser_column():
def test_session_list_with_explicit_browser_does_not_show_browser_column():
with patch(
"browser_cli.commands.session.active_browser_targets",
"browser_cli.commands.active_browser_targets",
return_value=[
BrowserTarget("default", "uuid-1", "/tmp/default.sock"),
BrowserTarget("work", "work", "/tmp/work.sock"),
],
), patch(
"browser_cli.commands.session.send_command",
"browser_cli.commands.send_command",
return_value=[{"name": "work-session", "tabs": 2, "savedAt": 1712707200000}],
) as send_command:
result = CliRunner().invoke(main, ["--browser", "work", "session", "list"])
@@ -455,7 +455,7 @@ def test_session_list_with_explicit_browser_does_not_show_browser_column():
def test_windows_open_passes_url():
with patch("browser_cli.commands.windows.send_command", return_value={"id": 7}) as send_command:
with patch("browser_cli.commands.send_command", return_value={"id": 7}) as send_command:
result = CliRunner().invoke(main, ["windows", "open", "https://example.com"])
assert result.exit_code == 0
@@ -463,20 +463,20 @@ def test_windows_open_passes_url():
send_command.assert_called_once_with("windows.open", {"url": "https://example.com"}, profile=None)
def test_extract_markdown_command():
with patch("browser_cli.commands.extract.send_command", return_value="# Title") as send_command:
with patch("browser_cli.commands.send_command", return_value="# Title") as send_command:
result = CliRunner().invoke(main, ["extract", "markdown"])
assert result.exit_code == 0
assert result.output == "# Title\n"
send_command.assert_called_once_with("extract.markdown", {"selector": None})
send_command.assert_called_once_with("extract.markdown", {"selector": None}, profile=None)
def test_extract_markdown_command_with_selector():
with patch("browser_cli.commands.extract.send_command", return_value="## Post") as send_command:
with patch("browser_cli.commands.send_command", return_value="## Post") as send_command:
result = CliRunner().invoke(main, ["extract", "markdown", "--selector", "article"])
assert result.exit_code == 0
assert result.output == "## Post\n"
send_command.assert_called_once_with("extract.markdown", {"selector": "article"})
send_command.assert_called_once_with("extract.markdown", {"selector": "article"}, profile=None)
def test_clean_markdown_output_removes_escaped_underscores_and_dashes():
@@ -561,7 +561,7 @@ def test_extract_markdown_command_repairs_malformed_tables_and_code_blocks():
"Golden Set │ ▼Promptfoo(Testausführung) │ ▼Plattformen├ Omnifact└ Le Chat\n"
"```"
)
with patch("browser_cli.commands.extract.send_command", return_value=raw):
with patch("browser_cli.commands.send_command", return_value=raw):
result = CliRunner().invoke(main, ["extract", "markdown"])
assert result.exit_code == 0
@@ -639,8 +639,8 @@ def test_tabs_list_multi_browser_queries_remote_target():
remote=endpoint,
)
with patch("browser_cli.commands.tabs.active_browser_targets", return_value=[remote_target, BrowserTarget("local", "local", "/tmp/local.sock")]), patch(
"browser_cli.commands.tabs.send_command",
with patch("browser_cli.commands.active_browser_targets", return_value=[remote_target, BrowserTarget("local", "local", "/tmp/local.sock")]), patch(
"browser_cli.commands.send_command",
return_value=[{"id": 1, "windowId": 1, "active": True, "title": "Remote", "url": "https://example.com"}],
) as send_command:
result = CliRunner().invoke(main, ["tabs", "list"])