Skip to content

Commit 99c0b20

Browse files
committed
fix: stop exposing internal error details in API responses
Replace f-string error details with generic messages in HTTP exceptions to avoid leaking stack traces and internal state to clients. Errors are still logged server-side with exc_info=True. Signed-off-by: Amit Oren <amoren@redhat.com>
1 parent 6883fe2 commit 99c0b20

2 files changed

Lines changed: 23 additions & 19 deletions

File tree

src/neuralnav/api/routes/configuration.py

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -104,10 +104,10 @@ async def deploy_model(request: DeploymentRequest):
104104
yaml_validator.validate_all(result["files"])
105105
logger.info(f"All YAML files validated for deployment: {result['deployment_id']}")
106106
except Exception as e:
107-
logger.error(f"YAML validation failed: {e}")
107+
logger.error(f"YAML validation failed: {e}", exc_info=True)
108108
raise HTTPException(
109109
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
110-
detail=f"Generated YAML validation failed: {str(e)}",
110+
detail="Generated YAML validation failed",
111111
) from e
112112

113113
return DeploymentResponse(
@@ -118,11 +118,13 @@ async def deploy_model(request: DeploymentRequest):
118118
message=f"Deployment files generated successfully for {result['deployment_id']}",
119119
)
120120

121+
except HTTPException:
122+
raise
121123
except Exception as e:
122124
logger.error(f"Failed to generate deployment: {e}", exc_info=True)
123125
raise HTTPException(
124126
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
125-
detail=f"Failed to generate deployment: {str(e)}",
127+
detail="Failed to generate deployment",
126128
) from e
127129

128130

@@ -249,10 +251,10 @@ async def deploy_to_cluster(request: DeploymentRequest):
249251
yaml_validator.validate_all(files)
250252
logger.info(f"YAML validation passed for: {deployment_id}")
251253
except Exception as e:
252-
logger.error(f"YAML validation failed: {e}")
254+
logger.error(f"YAML validation failed: {e}", exc_info=True)
253255
raise HTTPException(
254256
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
255-
detail=f"Generated YAML validation failed: {str(e)}",
257+
detail="Generated YAML validation failed",
256258
) from e
257259

258260
# Step 3: Deploy to cluster
@@ -264,7 +266,7 @@ async def deploy_to_cluster(request: DeploymentRequest):
264266
logger.error(f"Deployment failed: {deployment_result['errors']}")
265267
raise HTTPException(
266268
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
267-
detail=f"Deployment failed: {deployment_result['errors']}",
269+
detail="Deployment to cluster failed",
268270
)
269271

270272
logger.info(f"Successfully deployed {deployment_id} to cluster")
@@ -284,7 +286,7 @@ async def deploy_to_cluster(request: DeploymentRequest):
284286
logger.error(f"Failed to deploy to cluster: {e}", exc_info=True)
285287
raise HTTPException(
286288
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
287-
detail=f"Failed to deploy to cluster: {str(e)}",
289+
detail="Failed to deploy to cluster",
288290
) from e
289291

290292

@@ -309,7 +311,7 @@ async def get_cluster_status():
309311
}
310312
except Exception as e:
311313
logger.error(f"Failed to query cluster status: {e}")
312-
return {"accessible": False, "error": str(e)}
314+
return {"accessible": False, "error": "Failed to connect to cluster"}
313315

314316

315317
@router.get("/deployments/{deployment_id}/k8s-status")
@@ -343,7 +345,7 @@ async def get_k8s_deployment_status(deployment_id: str):
343345
logger.error(f"Failed to get K8s deployment status: {e}", exc_info=True)
344346
raise HTTPException(
345347
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
346-
detail=f"Failed to get deployment status: {str(e)}",
348+
detail="Failed to get deployment status",
347349
) from e
348350

349351

@@ -384,7 +386,7 @@ async def get_deployment_yaml(deployment_id: str):
384386
logger.error(f"Failed to retrieve YAML files: {e}", exc_info=True)
385387
raise HTTPException(
386388
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
387-
detail=f"Failed to retrieve YAML files: {str(e)}",
389+
detail="Failed to retrieve YAML files",
388390
) from e
389391

390392

@@ -408,9 +410,10 @@ async def delete_deployment(deployment_id: str):
408410
result = manager.delete_inferenceservice(deployment_id)
409411

410412
if not result["success"]:
413+
logger.error(f"Failed to delete deployment: {result.get('error', 'Unknown error')}")
411414
raise HTTPException(
412415
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
413-
detail=f"Failed to delete deployment: {result.get('error', 'Unknown error')}",
416+
detail="Failed to delete deployment",
414417
)
415418

416419
return result
@@ -421,7 +424,7 @@ async def delete_deployment(deployment_id: str):
421424
logger.error(f"Failed to delete deployment: {e}", exc_info=True)
422425
raise HTTPException(
423426
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
424-
detail=f"Failed to delete deployment: {str(e)}",
427+
detail="Failed to delete deployment",
425428
) from e
426429

427430

@@ -459,5 +462,5 @@ async def list_all_deployments():
459462
logger.error(f"Failed to list deployments: {e}", exc_info=True)
460463
raise HTTPException(
461464
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
462-
detail=f"Failed to list deployments: {str(e)}",
465+
detail="Failed to list deployments",
463466
) from e

src/neuralnav/api/routes/database.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,10 @@ async def db_status():
4141
finally:
4242
conn.close()
4343
except Exception as e:
44-
logger.error(f"Failed to get DB status: {e}")
44+
logger.error(f"Failed to get DB status: {e}", exc_info=True)
4545
raise HTTPException(
46-
status_code=status.HTTP_503_SERVICE_UNAVAILABLE, detail=f"Database not accessible: {e}"
46+
status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
47+
detail="Database not accessible",
4748
) from e
4849

4950

@@ -95,10 +96,10 @@ async def upload_benchmarks(file: UploadFile = File(...)):
9596
finally:
9697
conn.close()
9798
except Exception as e:
98-
logger.error(f"Failed to load benchmarks: {e}")
99+
logger.error(f"Failed to load benchmarks: {e}", exc_info=True)
99100
raise HTTPException(
100101
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
101-
detail=f"Failed to load benchmarks: {e}",
102+
detail="Failed to load benchmarks",
102103
) from e
103104

104105

@@ -126,8 +127,8 @@ async def reset_database():
126127
finally:
127128
conn.close()
128129
except Exception as e:
129-
logger.error(f"Failed to reset database: {e}")
130+
logger.error(f"Failed to reset database: {e}", exc_info=True)
130131
raise HTTPException(
131132
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
132-
detail=f"Failed to reset database: {e}",
133+
detail="Failed to reset database",
133134
) from e

0 commit comments

Comments
 (0)