diff --git a/apps/api/src/api/tool_instances.py b/apps/api/src/api/tool_instances.py index 579eaa4..4dd95f2 100644 --- a/apps/api/src/api/tool_instances.py +++ b/apps/api/src/api/tool_instances.py @@ -258,6 +258,21 @@ async def create_instance( else: repo_path = repo.path + # Verify cloned repo has files + if data.clone_mode == "clone" and repo_path: + try: + repo_contents = os.listdir(repo_path) + if not repo_contents or (len(repo_contents) == 1 and repo_contents[0] == ".git"): + logger.error("Cloned repository at %s appears empty", repo_path) + raise RuntimeError("Cloned repository is empty") + logger.info("Verified cloned repo at %s has %d items", repo_path, len(repo_contents)) + except Exception as exc: + logger.exception("Failed to verify cloned repository: %s", exc) + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail=f"Cloned repository verification failed: {exc}" + ) + # Create new local branch if requested if data.clone_mode == "clone" and data.new_branch: try: @@ -325,6 +340,37 @@ services: "PROJECT_ID": str(project_id), } compose_content = render_compose_template(tool_type.compose_template, variables) + + # Safety check: for clone mode, ensure repo is mounted in compose file + if data.clone_mode == "clone" and repo_path: + import yaml + compose_data = yaml.safe_load(compose_content) + repo_mounted = False + if compose_data and "services" in compose_data: + for svc in compose_data["services"].values(): + volumes = svc.get("volumes", []) + for vol in volumes: + vol_str = str(vol) + if repo_path in vol_str: + repo_mounted = True + break + if repo_mounted: + break + + if not repo_mounted: + logger.warning( + "Compose template for tool type %s does not mount repo path; adding default mount", + tool_type.name, + ) + # Add default mount to first service + if compose_data and "services" in compose_data: + for svc in compose_data["services"].values(): + if "volumes" not in svc: + svc["volumes"] = [] + svc["volumes"].append(f"{repo_path}:/workspace") + break + compose_content = yaml.dump(compose_data, default_flow_style=False) + write_compose_file(instance_dir, compose_content) # Create database record