feat: add n8n serve node and harden remote access
- Add the n8n community node package with credentials, command mapping, direct serve TCP client, and browser-cli protocol crypto helpers. - Cover Ed25519 signing, canonical JSON, PQ transport encryption, request mapping, and security behavior with unit tests. - Harden serve-http with per-address rate limiting, an 8 MB request body cap, and clear warnings when binding plain HTTP beyond loopback. - Stop one-shot --key overrides from being persisted automatically; document explicit remote trust and keep key-management behind the keys policy tier. - Make HTML-to-Markdown conversion safer by bounding tree depth and dropping unsafe link/image URL schemes. - Bump package and extension release metadata to 0.16.3.
This commit is contained in:
@@ -6,6 +6,7 @@ from browser_cli.auth.keys import (
|
||||
format_authorized_line,
|
||||
load_authorized_keys_with_names,
|
||||
load_authorized_keys_with_policies,
|
||||
set_authorized_key_policy,
|
||||
)
|
||||
from browser_cli.command_security import CommandPolicy, assert_command_allowed
|
||||
from browser_cli.serve.security import (
|
||||
@@ -58,6 +59,50 @@ def test_full_control_still_cannot_manage_keys():
|
||||
with pytest.raises(PermissionError):
|
||||
assert_command_allowed("browser-cli.auth.trust", policy)
|
||||
|
||||
# ── set_authorized_key_policy ────────────────────────────────────────────────────
|
||||
|
||||
def test_set_policy_updates_by_pubkey(tmp_path):
|
||||
path = tmp_path / "authorized_keys"
|
||||
pub = "a" * 64
|
||||
path.write_text(f"{pub} laptop\n")
|
||||
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")
|
||||
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")
|
||||
set_authorized_key_policy(path, pub, [])
|
||||
assert path.read_text().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")
|
||||
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")
|
||||
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")
|
||||
set_authorized_key_policy(path, a, ["control"])
|
||||
assert load_authorized_keys_with_policies(path) == [
|
||||
(a, "first", ["control"]),
|
||||
(b, "second", ["read-page"]), # untouched
|
||||
]
|
||||
|
||||
# ── authorized_keys line parsing ─────────────────────────────────────────────────
|
||||
|
||||
def test_parse_line_pubkey_only():
|
||||
|
||||
Reference in New Issue
Block a user