mirror of
https://github.com/tiennm99/DocsGPT.git
synced 2026-10-13 22:15:10 +00:00
Hold resumed turns and public-link visitors to the right wiki rules
A paused turn is found by the agent owner's id, so anyone holding one of the owner's agent keys could resume the owner's own chat with its saved wiki edit rights. A resume now counts as an API or widget caller when either the saved state or the resuming request is one, cuts the wiki tool to wiki_view unless the wiki allows outside edits, and gives the tool executor the same flags. A request that names an agent, by key or id, may only resume that agent's turn; otherwise the claim is released and the request refused. Public-link visitors run as themselves and reach only wikis they may edit, so the wiki switch no longer applies to them. Instead every wiki write in a public-link run waits for the visitor's approval, so the agent owner's prompt or sources can't steer an edit to the visitor's wiki unasked.
This commit is contained in:
1 parent
91e70d2f0c
commit
051452c438
10 files changed
+405
-64
No files matched your search
@@ -685,7 +685,7 @@ class TestOutsideCallerWrites:
|
||||
tool = _outside_tool(monkeypatch, False)
|
||||
for action, kwargs in _WRITES:
|
||||
result = tool.execute_action(action, **kwargs)
|
||||
assert "API, widget or public-link" in result, action
|
||||
assert "API or widget" in result, action
|
||||
reembed_mock.assert_not_called()
|
||||
assert _FakeWikiRepo().get_by_path("src-1", "/a.md")["content"] == "one"
|
||||
# Reading stays open to them.
|
||||
@@ -706,7 +706,7 @@ class TestOutsideCallerWrites:
|
||||
return None
|
||||
|
||||
monkeypatch.setattr("docsgpt.agents.tools.wiki.SourcesRepository", _Gone)
|
||||
assert "API, widget or public-link" in tool.execute_action("create", path="/b.md", content="x")
|
||||
assert "API or widget" in tool.execute_action("create", path="/b.md", content="x")
|
||||
|
||||
def test_owner_and_team_runs_skip_the_setting(self, wiki_tool, monkeypatch):
|
||||
class _Boom:
|
||||
@@ -737,6 +737,12 @@ class TestReadOnlyEntry:
|
||||
assert {"wiki_view", "wiki_create", "wiki_str_replace", "wiki_delete"} <= names
|
||||
assert entry["config"]["outside_caller"] is True
|
||||
|
||||
def test_approval_required_gates_writes_only(self):
|
||||
entry = self._entry(approval_required=True)
|
||||
for action in entry["actions"]:
|
||||
assert bool(action.get("require_approval")) is (action["name"] != "wiki_view"), action["name"]
|
||||
assert entry["config"]["outside_caller"] is False
|
||||
|
||||
def test_in_app_config_keeps_every_action(self):
|
||||
entry = self._entry()
|
||||
assert len(entry["actions"]) == 6
|
||||
@@ -767,18 +773,26 @@ class TestBuildConfigOutsideCallers:
|
||||
proc.agent_config = agent_config
|
||||
return proc._build_wiki_config()
|
||||
|
||||
@pytest.mark.parametrize("flag", ["external_api_caller", "public_link_caller"])
|
||||
def test_outside_caller_gets_read_only_while_off(self, monkeypatch, flag):
|
||||
cfg = self._cfg(monkeypatch, {flag: True})
|
||||
def test_api_key_caller_gets_read_only_while_off(self, monkeypatch):
|
||||
cfg = self._cfg(monkeypatch, {"external_api_caller": True})
|
||||
assert cfg["outside_caller"] is True
|
||||
assert cfg["writes_allowed"] is False
|
||||
assert cfg["approval_required"] is False
|
||||
|
||||
@pytest.mark.parametrize("flag", ["external_api_caller", "public_link_caller"])
|
||||
def test_outside_caller_may_write_when_on(self, monkeypatch, flag):
|
||||
cfg = self._cfg(monkeypatch, {flag: True}, allowed=True)
|
||||
def test_api_key_caller_may_write_when_on(self, monkeypatch):
|
||||
cfg = self._cfg(monkeypatch, {"external_api_caller": True}, allowed=True)
|
||||
assert cfg["outside_caller"] is True
|
||||
assert cfg["writes_allowed"] is True
|
||||
|
||||
@pytest.mark.parametrize("allowed", [False, True])
|
||||
def test_public_link_visitor_is_asked_whatever_the_switch(self, monkeypatch, allowed):
|
||||
# A visitor runs as themselves, so only wikis they can edit get here;
|
||||
# the switch doesn't apply, but every edit waits for their approval.
|
||||
cfg = self._cfg(monkeypatch, {"public_link_caller": True}, allowed=allowed)
|
||||
assert cfg["outside_caller"] is False
|
||||
assert cfg["writes_allowed"] is True
|
||||
assert cfg["approval_required"] is True
|
||||
|
||||
def test_v1_key_holder_gets_read_only(self, monkeypatch):
|
||||
from docsgpt.api.answer.services.stream_processor import StreamProcessor
|
||||
|
||||
@@ -791,3 +805,4 @@ class TestBuildConfigOutsideCallers:
|
||||
cfg = self._cfg(monkeypatch, agent_config)
|
||||
assert cfg["outside_caller"] is False
|
||||
assert cfg["writes_allowed"] is True
|
||||
assert cfg["approval_required"] is False
|
||||
Reference in new issue
Block a user