Files
browser-cli/tests/test_known_hosts.py
daniel156161 6270d8c956
Testing / remote-protocol-compat (0.16.0) (push) Successful in 1m1s
Testing / remote-protocol-compat (0.15.0) (push) Successful in 1m3s
Testing / test (push) Failing after 1m15s
Build & Publish Package / publish (push) Successful in 51s
Package Extension / package-extension (push) Successful in 1m6s
feat: add remote trust and server identity pinning
- Add SSH-style server identity keys and known-host verification for remote serve endpoints.
- Add remote add/list/remove commands for explicit endpoint persistence.
- Fix remote clients listing to fan out through target discovery instead of ambiguous auto-routing.
- Add URL glob matching for tabs filter and count with extension tests.
- Add n8n credential pinning for server public keys or SHA256 fingerprints.
- Remove obsolete compat shim behavior while keeping empty compat seams for future protocol changes.
- Bump browser-cli to 0.16.4 and n8n node to 0.3.1.
- Cover known-hosts, remote registry, compat seams, n8n protocol verification, and URL matching with tests.
2026-06-26 08:53:21 +02:00

65 lines
2.4 KiB
Python

import json
import pytest
from browser_cli.auth.server_identity import load_or_create_server_identity, public_key_hex, sign_challenge, verify_challenge_signature
from browser_cli.errors import BrowserNotConnected
from browser_cli.remote import known_hosts
def _challenge(tmp_path):
key = load_or_create_server_identity(tmp_path / "server.pem")
msg = {
"type": "challenge",
"nonce": "00" * 32,
"server_version": "0.16.4",
"min_client_version": "0.9.0",
"server_pubkey": public_key_hex(key),
}
msg["server_sig"] = sign_challenge(msg, key)
return msg
def test_challenge_signature_verifies(tmp_path):
challenge = _challenge(tmp_path)
assert verify_challenge_signature(challenge) is True
challenge["nonce"] = "11" * 32
assert verify_challenge_signature(challenge) is False
def test_known_host_mismatch_is_rejected(monkeypatch, tmp_path):
path = tmp_path / "known_hosts.json"
challenge = _challenge(tmp_path)
monkeypatch.setattr(known_hosts, "KNOWN_HOSTS_PATH", path)
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text(json.dumps({"browser-host.example": "00" * 32}), encoding="utf-8")
with pytest.raises(BrowserNotConnected, match="REMOTE SERVER IDENTITY CHANGED"):
known_hosts.verify_known_host("browser-host.example", challenge)
def test_unknown_non_interactive_host_is_rejected(monkeypatch, tmp_path):
path = tmp_path / "known_hosts.json"
challenge = _challenge(tmp_path)
monkeypatch.setattr(known_hosts, "KNOWN_HOSTS_PATH", path)
monkeypatch.setattr("sys.stdin.isatty", lambda: False)
with pytest.raises(BrowserNotConnected, match="Unknown remote server identity"):
known_hosts.verify_known_host("browser-host.example", challenge)
def test_loopback_unknown_host_is_allowed(monkeypatch, tmp_path):
path = tmp_path / "known_hosts.json"
challenge = _challenge(tmp_path)
monkeypatch.setattr(known_hosts, "KNOWN_HOSTS_PATH", path)
monkeypatch.setattr("sys.stdin.isatty", lambda: False)
known_hosts.verify_known_host("127.0.0.1:8765", challenge)
assert not path.exists()
def test_save_and_remove_known_host(tmp_path):
path = tmp_path / "known_hosts.json"
known_hosts.save_known_host("browser-host.example:443", "11" * 32, path)
assert json.loads(path.read_text(encoding="utf-8")) == {"browser-host.example": "11" * 32}
assert known_hosts.remove_known_host("browser-host.example", path) is True
assert known_hosts.load_known_hosts(path) == {}