fix: configurable internal API URL and upload size enforcement

H4: add internal_api_base_url setting to config.py (default http://localhost:8888,
    env-overridable via INTERNAL_API_BASE_URL); replace all 5 hardcoded base_url
    strings in chat_service.py.

H6: add post-read size check in both Excel and STEP upload handlers;
    raises HTTP 413 when content exceeds settings.max_upload_size_mb.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-07-22 13:43:04 +02:00
co-authored by Claude Sonnet 4.6
parent b69190dd86
commit df304dc021
4 changed files with 20 additions and 5 deletions
+6
View File
@@ -107,6 +107,9 @@ async def upload_excel(
tmp_path = upload_dir / tmp_name
content = await file.read()
max_bytes = settings.max_upload_size_mb * 1024 * 1024
if len(content) > max_bytes:
raise HTTPException(413, detail=f"File exceeds maximum upload size of {settings.max_upload_size_mb} MB")
tmp_path.write_bytes(content)
try:
@@ -408,6 +411,9 @@ async def upload_step(
raise HTTPException(400, detail="Only .stp / .step files are accepted")
content = await file.read()
max_bytes = settings.max_upload_size_mb * 1024 * 1024
if len(content) > max_bytes:
raise HTTPException(413, detail=f"File exceeds maximum upload size of {settings.max_upload_size_mb} MB")
file_hash = hashlib.sha256(content).hexdigest()
# Check dedup
+3
View File
@@ -94,6 +94,9 @@ class Settings(BaseSettings):
azure_openai_deployment: str = "gpt-4o"
azure_openai_api_version: str = "2024-02-01"
# Internal API (used by chat_service for self-calls — override in Docker if port changes)
internal_api_base_url: str = "http://localhost:8888"
# File Storage
upload_dir: str = "/app/uploads"
max_upload_size_mb: int = 500
+5 -5
View File
@@ -470,7 +470,7 @@ async def _tool_create_order(
token = create_access_token(user_id, "global_admin", tenant_id)
try:
async with httpx.AsyncClient(base_url="http://localhost:8888", timeout=30) as client:
async with httpx.AsyncClient(base_url=settings.internal_api_base_url, timeout=30) as client:
resp = await client.post(
"/api/orders",
json={"lines": lines},
@@ -531,7 +531,7 @@ async def _tool_dispatch_renders(db: AsyncSession, tenant_id: str, user_id: str
token = create_access_token(user_id, "global_admin", tenant_id)
try:
async with httpx.AsyncClient(base_url="http://localhost:8888", timeout=60) as client:
async with httpx.AsyncClient(base_url=settings.internal_api_base_url, timeout=60) as client:
resp = await client.post(
f"/api/orders/{order_id}/dispatch-renders",
headers={"Authorization": f"Bearer {token}"},
@@ -580,7 +580,7 @@ async def _tool_set_material_override(db: AsyncSession, tenant_id: str, user_id:
token = create_access_token(user_id, "global_admin", tenant_id)
try:
async with httpx.AsyncClient(base_url="http://localhost:8888", timeout=30) as client:
async with httpx.AsyncClient(base_url=settings.internal_api_base_url, timeout=30) as client:
resp = await client.post(
f"/api/orders/{order_id}/batch-material-override",
json={"material_override": material_name or None},
@@ -606,7 +606,7 @@ async def _tool_set_render_overrides(db: AsyncSession, tenant_id: str, user_id:
token = create_access_token(user_id, "global_admin", tenant_id)
try:
async with httpx.AsyncClient(base_url="http://localhost:8888", timeout=30) as client:
async with httpx.AsyncClient(base_url=settings.internal_api_base_url, timeout=30) as client:
resp = await client.post(
f"/api/orders/{order_id}/batch-render-overrides",
json={"render_overrides": render_overrides},
@@ -658,7 +658,7 @@ async def _tool_check_materials(db: AsyncSession, tenant_id: str, user_id: str =
token = create_access_token(user_id, "global_admin", tenant_id)
try:
async with httpx.AsyncClient(base_url="http://localhost:8888", timeout=30) as client:
async with httpx.AsyncClient(base_url=settings.internal_api_base_url, timeout=30) as client:
resp = await client.get(
f"/api/orders/{order_id}/check-materials",
headers={"Authorization": f"Bearer {token}"},