fix(settings): harden PATCH/redeploy per code review
- Add infisicalsdk dependency - Narrow update→create fallback to NotFound errors only (no silent swallow) - Truncate Coolify error response text to 200 chars - Add 60s cooldown to redeploy endpoint - Move httpx to top-level import
This commit is contained in:
47
web/app.py
47
web/app.py
@@ -26,6 +26,7 @@ from typing import Any
|
||||
from pydantic import BaseModel
|
||||
|
||||
import asyncpg
|
||||
import httpx
|
||||
|
||||
from legal_mcp import config
|
||||
from legal_mcp.services import chunker, db, embeddings, extractor, git_sync, processor, proofreader, research_md
|
||||
@@ -2552,6 +2553,12 @@ async def api_post_agent_comment(case_number: str, req: AgentCommentRequest):
|
||||
|
||||
# ── Settings: MCP Server Configuration ────────────────────────────
|
||||
|
||||
# Module-level guard: minimum interval between redeploys (60 seconds).
|
||||
# Prevents accidental double-clicks or automated retry loops from queueing
|
||||
# multiple redundant Coolify builds.
|
||||
_LAST_REDEPLOY_AT: float = 0.0
|
||||
_REDEPLOY_MIN_INTERVAL_SEC: float = 60.0
|
||||
|
||||
|
||||
def _infisical_client():
|
||||
"""Build Infisical SDK client, or return None if not configured."""
|
||||
@@ -2699,10 +2706,12 @@ async def api_mcp_env_update(key: str, req: McpEnvUpdateRequest):
|
||||
"false" if coerced is False else str(coerced)
|
||||
)
|
||||
try:
|
||||
# SDK pattern: try update, fall back to create if missing.
|
||||
# NOTE: exact method may vary by infisical-python version. The
|
||||
# canonical method is `update_secret_by_name`; if your version
|
||||
# uses `secrets.update`, replace accordingly.
|
||||
# SDK pattern: try update, fall back to create if the secret doesn't exist.
|
||||
# The Infisical SDK's specific NotFound exception class isn't stable across
|
||||
# versions, so we inspect the error string. Network/auth errors (which DON'T
|
||||
# contain 'not found' / 404 / 'does not exist') are re-raised immediately
|
||||
# so they reach the outer handler and surface as 502 with the real error,
|
||||
# rather than being silently retried as a create-call.
|
||||
try:
|
||||
client.update_secret_by_name(
|
||||
project_id=project_id,
|
||||
@@ -2711,7 +2720,22 @@ async def api_mcp_env_update(key: str, req: McpEnvUpdateRequest):
|
||||
secret_name=key,
|
||||
secret_value=str_value,
|
||||
)
|
||||
except Exception:
|
||||
except Exception as update_err:
|
||||
err_text = str(update_err).lower()
|
||||
looks_like_missing = (
|
||||
"not found" in err_text
|
||||
or "does not exist" in err_text
|
||||
or "404" in err_text
|
||||
)
|
||||
if not looks_like_missing:
|
||||
logger.warning(
|
||||
"infisical_update_failed key=%s err=%s — not retrying as create",
|
||||
key, update_err,
|
||||
)
|
||||
raise
|
||||
logger.info(
|
||||
"infisical_secret_missing key=%s — falling back to create", key,
|
||||
)
|
||||
client.create_secret_by_name(
|
||||
project_id=project_id,
|
||||
environment_slug=env,
|
||||
@@ -2740,7 +2764,14 @@ async def api_mcp_env_update(key: str, req: McpEnvUpdateRequest):
|
||||
@app.post("/api/settings/mcp/env/redeploy")
|
||||
async def api_mcp_env_redeploy():
|
||||
"""Trigger Coolify redeploy of the legal-ai app."""
|
||||
import httpx
|
||||
global _LAST_REDEPLOY_AT
|
||||
now = time.time()
|
||||
elapsed = now - _LAST_REDEPLOY_AT
|
||||
if elapsed < _REDEPLOY_MIN_INTERVAL_SEC:
|
||||
wait = int(_REDEPLOY_MIN_INTERVAL_SEC - elapsed)
|
||||
raise HTTPException(
|
||||
429, f"Redeploy בהמתנה: נסה שוב בעוד {wait} שניות."
|
||||
)
|
||||
coolify_url = os.environ.get("COOLIFY_URL", "http://158.178.131.193:8000")
|
||||
coolify_token = os.environ.get("COOLIFY_API_TOKEN", "")
|
||||
app_uuid = os.environ.get("COOLIFY_APP_UUID", "gyjo0mtw2c42ej3xxvbz8zio")
|
||||
@@ -2757,8 +2788,9 @@ async def api_mcp_env_redeploy():
|
||||
except Exception as e:
|
||||
raise HTTPException(502, f"Coolify unreachable: {e}")
|
||||
if resp.status_code >= 400:
|
||||
body_preview = (resp.text or "")[:200]
|
||||
raise HTTPException(
|
||||
502, f"Coolify deploy failed: {resp.status_code} {resp.text}"
|
||||
502, f"Coolify deploy failed: {resp.status_code} — {body_preview}"
|
||||
)
|
||||
data = resp.json() if resp.content else {}
|
||||
deployment_uuid = (
|
||||
@@ -2766,6 +2798,7 @@ async def api_mcp_env_redeploy():
|
||||
or (data.get("deployments") or [{}])[0].get("deployment_uuid")
|
||||
)
|
||||
logger.info("mcp_env_redeploy triggered uuid=%s", deployment_uuid)
|
||||
_LAST_REDEPLOY_AT = now
|
||||
return {
|
||||
"ok": True,
|
||||
"deployment_uuid": deployment_uuid,
|
||||
|
||||
Reference in New Issue
Block a user