mirror of
https://github.com/tiennm99/DocsGPT.git
synced 2026-10-16 12:14:44 +00:00
Gate outside writes on the owner's stored credentials, not only connections
API-key, widget and public-link callers were held to the write allowlist only on connected accounts, so they could still write through an API tool or a signed-in MCP server that carries the owner's credentials. Any write on credentials the caller doesn't hold is now refused unless the owner allowlisted it, and a scheduled run for such a caller counts as not holding any. The tool list names these writes per tool, so the allowlist can offer them, and its copy now names every route it covers.
This commit is contained in:
1 parent
656e3abbd0
commit
5c8b97b609
14 files changed
+243
-36
No files matched your search
@@ -101,3 +101,58 @@ def apply_default_permissions(tool_name: Optional[str], actions: list[dict]) ->
|
||||
updated["require_approval"] = True
|
||||
stamped.append(updated)
|
||||
return stamped
|
||||
|
||||
|
||||
def tool_actions(tool: dict) -> list[dict]:
|
||||
"""A tool row's actions, each carrying its ``name``.
|
||||
|
||||
An API tool keeps its actions under ``config["actions"]`` keyed by name;
|
||||
every other tool lists them in ``actions``.
|
||||
"""
|
||||
if tool.get("name") == "api_tool":
|
||||
stored = (tool.get("config") or {}).get("actions") or {}
|
||||
return [{**(action or {}), "name": name} for name, action in stored.items()]
|
||||
return [action for action in tool.get("actions") or [] if isinstance(action, dict)]
|
||||
|
||||
|
||||
def holds_owner_credentials(tool: dict) -> bool:
|
||||
"""Whether ``tool`` acts with credentials stored by its owner.
|
||||
|
||||
A connection's account, an API tool (its headers and query values carry
|
||||
the owner's keys), a stored secret, or an MCP server the owner signed in
|
||||
to. Anyone running it acts as the owner there, whoever they are.
|
||||
|
||||
Args:
|
||||
tool: A ``user_tools`` row.
|
||||
|
||||
Returns:
|
||||
True when the tool runs on the owner's credentials.
|
||||
"""
|
||||
if tool.get("connection_id") or tool.get("name") == "api_tool":
|
||||
return True
|
||||
config = tool.get("config") or {}
|
||||
if config.get("encrypted_credentials"):
|
||||
return True
|
||||
return tool.get("name") == "mcp_tool" and (config.get("auth_type") or "none") != "none"
|
||||
|
||||
|
||||
def owner_credential_writes(tool: dict) -> list[str]:
|
||||
"""Names of the tool's write actions that run on its owner's credentials.
|
||||
|
||||
These are what someone who can't approve for the owner (an API-key or
|
||||
widget caller, a public-link user, a webhook) may run only when the owner
|
||||
allows them in the agent's API write allowlist.
|
||||
|
||||
Args:
|
||||
tool: A ``user_tools`` row.
|
||||
|
||||
Returns:
|
||||
Action names, empty when the tool holds no owner credentials.
|
||||
"""
|
||||
if not holds_owner_credentials(tool):
|
||||
return []
|
||||
return [
|
||||
action["name"] for action in tool_actions(tool)
|
||||
if action.get("name") and action.get("active") is not False
|
||||
and action_access(tool.get("name"), action) == ACCESS_WRITE
|
||||
]
|
||||
Reference in new issue
Block a user