From 8e340f0ce8b158d9aab2e5619c08cc4934c6be4e Mon Sep 17 00:00:00 2001 From: YueGuobin Date: Tue, 9 Jun 2026 23:33:35 +0800 Subject: [PATCH] Add descriptive detail to 403 errors in compute file endpoints Both is_safe_path rejection and PermissionError were returning 403 without a detail message, making them indistinguishable in logs. Add specific detail strings to each: - is_safe_path: 'Path is outside the project directory' - PermissionError (write): 'Permission denied writing to ...' - PermissionError (delete): 'Permission denied deleting ...' --- gns3server/api/routes/compute/projects.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/gns3server/api/routes/compute/projects.py b/gns3server/api/routes/compute/projects.py index f56094b07..71245dfe7 100644 --- a/gns3server/api/routes/compute/projects.py +++ b/gns3server/api/routes/compute/projects.py @@ -188,7 +188,7 @@ async def write_compute_project_file( # Raise error if user try to escape if not is_safe_path(path, project.path): - raise HTTPException(status_code=status.HTTP_403_FORBIDDEN) + raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Path is outside the project directory") path = os.path.join(project.path, path) try: @@ -201,7 +201,7 @@ async def write_compute_project_file( except FileNotFoundError: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND) except PermissionError: - raise HTTPException(status_code=status.HTTP_403_FORBIDDEN) + raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail=f"Permission denied writing to '{path}'") except OSError as e: log.error(f"Error writing file '{path}': {e}") raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e)) @@ -217,7 +217,7 @@ async def delete_compute_project_file( path = os.path.normpath(file_path) if not is_safe_path(path, project.path): - raise HTTPException(status_code=status.HTTP_403_FORBIDDEN) + raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Path is outside the project directory") path = os.path.join(project.path, path) if not os.path.exists(path): @@ -231,6 +231,6 @@ async def delete_compute_project_file( except FileNotFoundError: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND) except PermissionError: - raise HTTPException(status_code=status.HTTP_403_FORBIDDEN) + raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail=f"Permission denied deleting '{path}'") except OSError as e: raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e))