{p}
@@ -381,27 +371,6 @@ async def save_notifications(
return HTMLResponse(_notifications_page(username, back_persona, success="Notification settings saved."))
-@router.post("/settings/tool-policy", include_in_schema=False)
-async def save_tool_policy_route(
- request: Request,
- allow_list: str = Form(""),
- deny_list: str = Form(""),
-):
- username = _get_session_user(request)
- if not username:
- return RedirectResponse("/login", status_code=302)
-
- personas = list_user_personas(username)
- back_persona = _preferred_persona(request, username)
-
- allow_tools = [ln.strip() for ln in allow_list.splitlines() if ln.strip()]
- deny_tools = [ln.strip() for ln in deny_list.splitlines() if ln.strip()]
- save_tool_policy(username, {"allow": allow_tools, "deny": deny_tools})
- logger.info("tool policy updated for %s (allow=%d deny=%d)", username, len(allow_tools), len(deny_tools))
- return HTMLResponse(_settings_page(username, personas, back_persona,
- success="Tool permission policy saved."))
-
-
@router.post("/settings/email-allowlist", include_in_schema=False)
async def save_email_allowlist(
request: Request,
diff --git a/cortex/routers/tools_settings.py b/cortex/routers/tools_settings.py
index 847599e..77e65e0 100644
--- a/cortex/routers/tools_settings.py
+++ b/cortex/routers/tools_settings.py
@@ -17,7 +17,7 @@ from fastapi.responses import HTMLResponse, RedirectResponse
from auth_utils import COOKIE_NAME, decode_token, get_tool_policy, save_tool_policy
from persona import list_user_personas
-from tools import TOOL_CATEGORIES, TOOL_RISK
+from tools import TOOL_CATEGORIES, TOOL_RISK, CONFIRM_REQUIRED
logger = logging.getLogger(__name__)
router = APIRouter()
@@ -124,6 +124,9 @@ def _tools_page(
html = html.replace("{{ tool_table_html }}", _build_tool_table(policy))
html = html.replace("{{ tool_risk_json }}", json.dumps(TOOL_RISK))
+ html = html.replace("{{ confirm_required_tools }}", _html.escape(", ".join(sorted(CONFIRM_REQUIRED))))
+ html = html.replace("{{ tool_allow }}", _html.escape("\n".join(policy.get("allow") or [])))
+ html = html.replace("{{ tool_deny }}", _html.escape("\n".join(policy.get("deny") or [])))
html = html.replace("{{ back_href }}", f"/{username}/{back_persona}" if back_persona else "/")
html = html.replace("{{ help_href }}", f"/help?persona={back_persona}" if back_persona else "/help")
@@ -167,7 +170,9 @@ async def save_tools(request: Request):
elif val == "blacklist":
blacklist.append(tool)
- # Merge into existing policy (preserve allow/deny confirmation-gate fields)
+ allow_tools = [ln.strip() for ln in (form.get("allow_list") or "").splitlines() if ln.strip()]
+ deny_tools = [ln.strip() for ln in (form.get("deny_list") or "").splitlines() if ln.strip()]
+
policy = get_tool_policy(username)
if max_risk:
policy["max_risk"] = max_risk
@@ -176,11 +181,13 @@ async def save_tools(request: Request):
policy["whitelist"] = whitelist
policy["blacklist"] = blacklist
+ policy["allow"] = allow_tools
+ policy["deny"] = deny_tools
save_tool_policy(username, policy)
logger.info(
- "tool policy saved for %s: max_risk=%s whitelist=%d blacklist=%d",
- username, max_risk or "none", len(whitelist), len(blacklist),
+ "tool policy saved for %s: max_risk=%s whitelist=%d blacklist=%d allow=%d deny=%d",
+ username, max_risk or "none", len(whitelist), len(blacklist), len(allow_tools), len(deny_tools),
)
return HTMLResponse(_tools_page(
username, back_persona,
diff --git a/cortex/static/settings.html b/cortex/static/settings.html
index b2ac1ed..88de91e 100644
--- a/cortex/static/settings.html
+++ b/cortex/static/settings.html
@@ -379,33 +379,18 @@
-
+
Tool Permissions
-
- Override the default confirmation gate for orchestrator tools.
- Allow list — tools that run without asking for confirmation.
- Deny list — tools that are always blocked for your account.
- One tool name per line.
+
+ Configure tool access, risk policy, and confirmation gate overrides on the Tools page.
-
- Tools requiring confirmation by default: {{ confirm_required_tools }}
-