From d4e992a9e248908956c8ab0185275b8bd5e24823 Mon Sep 17 00:00:00 2001 From: Fusion Date: Wed, 20 May 2026 10:03:53 +0200 Subject: [PATCH] fix(cors): add API domain to CORS origins and improve instance error handling - Add API base URL to CORS allowed origins alongside web base URL - Add CORS origin logging on startup for debugging - Wrap instance creation in try/except with detailed error logging - Return proper error message instead of raw 500 for instance creation failures This fixes CORS errors when the frontend makes cross-origin requests and provides better diagnostics for instance creation failures. --- apps/api/src/api/tool_instances.py | 91 ++++++++++++++++-------------- apps/api/src/main.py | 8 ++- 2 files changed, 56 insertions(+), 43 deletions(-) diff --git a/apps/api/src/api/tool_instances.py b/apps/api/src/api/tool_instances.py index 769665a..a73c20a 100644 --- a/apps/api/src/api/tool_instances.py +++ b/apps/api/src/api/tool_instances.py @@ -124,53 +124,60 @@ async def create_instance( status_code=status.HTTP_404_NOT_FOUND, detail="tool type not found" ) - # Generate unique name - instance_name = f"{tool_type.name}-{repo.name}-{uuid.uuid4().hex[:8]}" - instance_display = data.display_name or f"{tool_type.display_name} - {repo.name}" + try: + # Generate unique name + instance_name = f"{tool_type.name}-{repo.name}-{uuid.uuid4().hex[:8]}" + instance_display = data.display_name or f"{tool_type.display_name} - {repo.name}" - # Create instance directory - instance_dir = ensure_instance_directory(instance_name) - compose_path = os.path.join(instance_dir, "docker-compose.yml") + # Create instance directory + instance_dir = ensure_instance_directory(instance_name) + compose_path = os.path.join(instance_dir, "docker-compose.yml") - # Find free port - tool_port = find_free_port() + # Find free port + tool_port = find_free_port() - # Render compose template - variables = { - "REPO_PATH": repo.path, - "INSTANCE_NAME": instance_name, - "INSTANCE_ID": instance_name, - "TOOL_PORT": tool_port, - "USER_ID": str(user_id), - "PROJECT_ID": str(project_id), - } - compose_content = render_compose_template(tool_type.compose_template, variables) - write_compose_file(instance_dir, compose_content) + # Render compose template + variables = { + "REPO_PATH": repo.path, + "INSTANCE_NAME": instance_name, + "INSTANCE_ID": instance_name, + "TOOL_PORT": tool_port, + "USER_ID": str(user_id), + "PROJECT_ID": str(project_id), + } + compose_content = render_compose_template(tool_type.compose_template, variables) + write_compose_file(instance_dir, compose_content) - # Create database record - instance = ToolInstance( - name=instance_name, - display_name=instance_display, - tool_type_id=tool_type_id, - repository_id=repo_id, - project_id=project_id, - owner_id=user_id, - status="pending", - compose_path=compose_path, - port=tool_port, - ) - session.add(instance) - await session.commit() - await session.refresh(instance) + # Create database record + instance = ToolInstance( + name=instance_name, + display_name=instance_display, + tool_type_id=tool_type_id, + repository_id=repo_id, + project_id=project_id, + owner_id=user_id, + status="pending", + compose_path=compose_path, + port=tool_port, + ) + session.add(instance) + await session.commit() + await session.refresh(instance) - return { - "id": str(instance.id), - "name": instance.name, - "display_name": instance.display_name, - "tool_type_id": str(instance.tool_type_id), - "status": instance.status, - "created_at": instance.created_at.isoformat(), - } + return { + "id": str(instance.id), + "name": instance.name, + "display_name": instance.display_name, + "tool_type_id": str(instance.tool_type_id), + "status": instance.status, + "created_at": instance.created_at.isoformat(), + } + except Exception as exc: + logger.exception("Failed to create instance: %s", exc) + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail=f"Failed to create instance: {exc}", + ) @router.get( diff --git a/apps/api/src/main.py b/apps/api/src/main.py index 412b36c..efd8258 100644 --- a/apps/api/src/main.py +++ b/apps/api/src/main.py @@ -38,9 +38,15 @@ settings = Settings() app = FastAPI(title="Headquarter API") # Configure CORS - must be before other middleware +# Build allowed origins list including web and api domains +cors_origins = [settings.web_base_url] +if settings.api_base_url != settings.web_base_url: + cors_origins.append(settings.api_base_url) +logger.info("CORS configured with origins: %s", cors_origins) + app.add_middleware( CORSMiddleware, - allow_origins=[settings.web_base_url], + allow_origins=cors_origins, allow_credentials=True, allow_methods=["*"], allow_headers=["*"],