mirror of
https://github.com/pewdiepie-archdaemon/odysseus.git
synced 2026-06-18 18:55:28 -04:00
fix: block app_api access to Cookbook host controls (#3231)
This commit is contained in:
@@ -2720,14 +2720,19 @@ _APP_API_BLOCKLIST_PREFIXES = (
|
||||
)
|
||||
|
||||
# (method, prefix) pairs to refuse specifically. Used for endpoints
|
||||
# where GET is fine but writes are destructive — saw the agent wipe
|
||||
# cookbook_state.json (presets + tasks) by POSTing {"tasks": []} to
|
||||
# /api/cookbook/state, which overwrote the whole file. Use the
|
||||
# dedicated preset/task tools instead.
|
||||
# where GET is fine but writes are destructive or host-control shaped.
|
||||
# Saw the agent wipe cookbook_state.json (presets + tasks) by POSTing
|
||||
# {"tasks": []} to /api/cookbook/state, which overwrote the whole file.
|
||||
# Use dedicated tools or UI flows instead.
|
||||
_APP_API_BLOCKLIST_METHOD_PATH = (
|
||||
("GET", "/api/email/accounts"), # owner-filtered in tool context; use list_email_accounts MCP tool
|
||||
("POST", "/api/cookbook/state"), # whole-file overwrite — agent must use serve_preset/serve_model instead
|
||||
("DELETE", "/api/cookbook/state"),
|
||||
# Host-control routes: package install, engine rebuild, and process
|
||||
# signalling should not be reachable through the generic API bridge.
|
||||
("POST", "/api/cookbook/packages/install"),
|
||||
("POST", "/api/cookbook/rebuild-engine"),
|
||||
("POST", "/api/cookbook/kill-pid"),
|
||||
# Use the named tools (download_model / serve_model) — they handle
|
||||
# host-name resolution, per-host env_prefix, AND register the task
|
||||
# in cookbook state so it shows in the UI + list_downloads. Hitting
|
||||
@@ -2766,8 +2771,8 @@ async def do_app_api(content: str, owner: Optional[str] = None) -> Dict:
|
||||
|
||||
The `endpoints` action returns the OpenAPI surface (method + path +
|
||||
summary) so the agent can discover what's reachable. A blocklist
|
||||
refuses sensitive auth/user/admin/shell paths to keep blast radius
|
||||
bounded.
|
||||
refuses sensitive auth/user/admin/shell paths and method-specific
|
||||
host-control routes to keep blast radius bounded.
|
||||
"""
|
||||
import httpx
|
||||
try:
|
||||
@@ -2835,6 +2840,12 @@ async def do_app_api(content: str, owner: Optional[str] = None) -> Dict:
|
||||
if any(method == m and path.startswith(p) for m, p in _APP_API_BLOCKLIST_METHOD_PATH):
|
||||
if "/api/email/accounts" in path:
|
||||
return {"error": "Don't use /api/email/accounts via app_api — it is owner-filtered in tool context and may return empty. Use the `list_email_accounts` email tool, then pass `account` to list_emails/read_email.", "exit_code": 1}
|
||||
if "/api/cookbook/packages/install" in path:
|
||||
return {"error": "Don't POST /api/cookbook/packages/install via app_api — package installation is host code execution. Use the dedicated Cookbook dependency UI/flow instead.", "exit_code": 1}
|
||||
if "/api/cookbook/rebuild-engine" in path:
|
||||
return {"error": "Don't POST /api/cookbook/rebuild-engine via app_api — engine rebuild mutates local or remote host state. Use the dedicated Cookbook UI/flow instead.", "exit_code": 1}
|
||||
if "/api/cookbook/kill-pid" in path:
|
||||
return {"error": "Don't POST /api/cookbook/kill-pid via app_api — process signalling is host control. Use the dedicated Cookbook stop/diagnostic flow instead.", "exit_code": 1}
|
||||
if "/api/model/download" in path:
|
||||
return {"error": "Don't POST /api/model/download directly — use the `download_model` tool (it resolves the server name, sets the venv env_prefix, and registers the task so it shows in the UI).", "exit_code": 1}
|
||||
if "/api/model/serve" in path:
|
||||
|
||||
Reference in New Issue
Block a user