feat(webui): add project workspaces and access controls (#4007)
* feat(webui): add project workspaces and access controls * feat(webui): add project workspaces and access controls * refactor(tools): centralize workspace access resolution * refactor(webui): remove unused workspace host state * fix(webui): hide estimated file edit label * fix(webui): clarify file edit deletion feedback * fix(webui): label deleted file activity * fix(webui): flatten file edit activity rows * fix(core): remove path-only patch deletion * fix(core): keep apply patch non-destructive * refactor(webui): trim workspace host plumbing * fix(tools): register exec with tools config
This commit is contained in:
@@ -49,7 +49,7 @@ def test_rejects_missing_domain():
|
||||
])
|
||||
def test_blocks_private_ipv4(ip: str, label: str):
|
||||
with patch("nanobot.security.network.socket.getaddrinfo", _fake_resolve("evil.com", [ip])):
|
||||
ok, err = validate_url_target(f"http://evil.com/path")
|
||||
ok, err = validate_url_target("http://evil.com/path")
|
||||
assert not ok, f"Should block {label} ({ip})"
|
||||
assert "private" in err.lower() or "blocked" in err.lower()
|
||||
|
||||
@@ -92,6 +92,21 @@ def test_detects_wget_localhost():
|
||||
assert contains_internal_url("wget http://localhost:8080/secret")
|
||||
|
||||
|
||||
def test_loopback_exception_allows_literal_localhost_only():
|
||||
with patch("nanobot.security.network.socket.getaddrinfo", _fake_resolve("localhost", ["127.0.0.1"])):
|
||||
assert not contains_internal_url("curl http://localhost:8765/", allow_loopback=True)
|
||||
|
||||
|
||||
def test_loopback_exception_rejects_public_name_resolving_to_loopback():
|
||||
with patch("nanobot.security.network.socket.getaddrinfo", _fake_resolve("example.com", ["127.0.0.1"])):
|
||||
assert contains_internal_url("curl http://example.com:8765/", allow_loopback=True)
|
||||
|
||||
|
||||
def test_loopback_exception_rejects_metadata():
|
||||
with patch("nanobot.security.network.socket.getaddrinfo", _fake_resolve("169.254.169.254", ["169.254.169.254"])):
|
||||
assert contains_internal_url("curl http://169.254.169.254/latest/meta-data/", allow_loopback=True)
|
||||
|
||||
|
||||
def test_allows_normal_curl():
|
||||
with patch("nanobot.security.network.socket.getaddrinfo", _fake_resolve("example.com", ["93.184.216.34"])):
|
||||
assert not contains_internal_url("curl https://example.com/api/data")
|
||||
|
||||
Reference in New Issue
Block a user