Let a wiki's owner decide whether API, widget and public-link runs edit it

A run from an agent's API key or widget acts as the agent's owner, so it
could rewrite any wiki the owner can edit. A new per-wiki setting,
wiki_outside_edits (off by default), decides whether such runs, and runs
from the agent's public link, get the wiki's edit actions. While it is off
they are offered only wiki_view, and the tool refuses writes itself after
reading the live setting. The owner changes it through the owner-only
/api/sources/<id>/wiki/settings route; tokens can read it but not change it.
This commit is contained in:
arc53-machine committed 2026-09-29 16:07:57 +01:00
1 parent 33a73bc442
commit 3b44b6851d
13 files changed
+560 -6

No files matched your search

@@ -27,6 +27,7 @@ from docsgpt.core.model_utils import (
get_provider_from_model_id,
validate_model_id,
)
from docsgpt.agents.tools.wiki import outside_edits_allowed
from docsgpt.core.settings import settings
from docsgpt.guardrails.config import AgentConfig
from sqlalchemy import text as sql_text
@@ -1259,10 +1260,22 @@ class StreamProcessor:
writable wiki source; the first match wins and the scan stops there so
this runs at most one owner+source lookup per chat on the hot path.
Returns None when no writable wiki source is present.
An API-key, widget or public-link run (``outside_caller``) gets the
edit actions only when the wiki's owner turned on
``wiki_outside_edits``; otherwise ``writes_allowed`` is False and the
tool offers only ``wiki_view``.
"""
caller = self.decoded_token.get("sub") if self.decoded_token else None
if not caller:
return None
# Processors built without __init__ (tests, resume helpers) lack these.
run_config = getattr(self, "agent_config", None) or {}
outside_caller = bool(
run_config.get("external_api_caller")
or run_config.get("public_link_caller")
or getattr(self, "external_caller", False)
)
wiki_config: Optional[Dict[str, Any]] = None
try:
@@ -1286,6 +1299,8 @@ class StreamProcessor:
"source_owner_id": owner,
"decoded_token": self.decoded_token,
"user": caller,
"outside_caller": outside_caller,
"writes_allowed": not outside_caller or outside_edits_allowed(source_doc),
}
break
except Exception: