chore: big refactoring of the basic structure#223
Conversation
| except Exception as exc: | ||
| logger.exception("Health check failed") | ||
| REQUEST_COUNT.labels(method="GET", endpoint="/health", status="500").inc() | ||
| return jsonify({"error": str(exc)}), 500 |
Check warning
Code scanning / CodeQL
Information exposure through an exception Medium
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 5 months ago
Generally, to fix this issue you should avoid returning raw exception messages (or stack traces) to the client. Instead, log the full exception on the server (which is already done with logger.exception(...)) and return a generic, user-safe error message with the same HTTP status code.
Concretely in app/api/routes.py:
- In the
/healthendpoint, replacereturn jsonify({"error": str(exc)}), 500with a generic message such asreturn jsonify({"error": "Internal server error"}), 500(or similar wording). - In the
/transformendpoint, likewise replacereturn jsonify({"error": str(exc)}), 500with the same generic message. - No new imports are needed; we continue using
jsonifyand the existing logging. Functionality is preserved in terms of status codes and metrics; only the exposed error body is made generic, while detailed information remains in server logs.
| @@ -30,7 +30,7 @@ | ||
| except Exception as exc: | ||
| logger.exception("Health check failed") | ||
| REQUEST_COUNT.labels(method="GET", endpoint="/health", status="500").inc() | ||
| return jsonify({"error": str(exc)}), 500 | ||
| return jsonify({"error": "Internal server error"}), 500 | ||
| finally: | ||
| REQUEST_LATENCY.labels(method="GET", endpoint="/health").observe( | ||
| time.time() - start_time | ||
| @@ -52,7 +52,7 @@ | ||
| except Exception as exc: | ||
| logger.exception("Transform request failed") | ||
| REQUEST_COUNT.labels(method="POST", endpoint="/transform", status="500").inc() | ||
| return jsonify({"error": str(exc)}), 500 | ||
| return jsonify({"error": "Internal server error"}), 500 | ||
| finally: | ||
| REQUEST_LATENCY.labels(method="POST", endpoint="/transform").observe( | ||
| time.time() - start_time |
| TRANSFORM_DURATION.observe(time.time() - transform_start_time) | ||
|
|
||
| REQUEST_COUNT.labels(method="POST", endpoint="/transform", status="200").inc() | ||
| return result |
Check warning
Code scanning / CodeQL
Information exposure through an exception Medium
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 5 months ago
In general, to fix information exposure through exceptions, stop returning raw exception details (messages, stack traces) to the client. Log the exception (including stack trace) on the server, and send back a generic or otherwise pre-reviewed, non-sensitive error message and status code.
For this codebase, the minimal, behavior-preserving fix that addresses the CodeQL findings is confined to app/transform/main.py in post_transform:
- Keep the existing logging with
exc_info=Trueso developers still get stack traces. - Change the return values for:
KnownExceptionto return a JSON error response containingstr(e)(since it is explicitly for end users) but in a well-defined structure, not a bare string. This makes the taint less ambiguous to CodeQL and keeps behavior similar for clients that expect a message, but if you want stricter hardening you could also replace this with a generic string.PrivateInternalExceptionto return a generic error message (e.g.,"An internal error has occurred.") instead ofstr(e), aligning with the comment that it should be “generic” to the end user.
- Also return consistent JSON for the unexpected exception path, which already uses a generic
UnexpectedErrormessage.
Concretely:
- In
post_transform:- Replace
return str(e), 400in theKnownExceptionhandler withreturn jsonify({"error": str(e)}), 400. - Replace
return str(e), 400in thePrivateInternalExceptionhandler withreturn jsonify({"error": "An internal error has occurred."}), 500(or stick with 400 if that’s required, but 500 better reflects an internal error). - Replace
return str(UnexpectedError()), 400withreturn jsonify({"error": str(UnexpectedError())}), 500(or the appropriate status used elsewhere for generic unexpected errors).
- Replace
- No changes are needed in
app/api/routes.pybecause it already returns generic error JSON for its own exceptions, and it simply forwards whateverpost_transformreturns.
These changes require no new methods or external dependencies beyond what is already imported (jsonify is already imported in app/transform/main.py).
| @@ -71,15 +71,18 @@ | ||
| except KnownException as e: | ||
| # Exception with description for the end user. | ||
| logger.warning("Known exception during transform", exc_info=True) | ||
| return str(e), 400 | ||
| # Return a controlled error message for the client while keeping full details in logs. | ||
| return jsonify({"error": str(e)}), 400 | ||
| except PrivateInternalException as e: | ||
| # Internal exception with a generic description to the end user. | ||
| logger.error("Internal exception during transform", exc_info=True) | ||
| return str(e), 400 | ||
| # Do not expose internal exception details to the client. | ||
| return jsonify({"error": "An internal error has occurred."}), 500 | ||
| except Exception as e: | ||
| # Not handled exception should be handled in the future. | ||
| logger.exception("Unexpected exception during transform") | ||
| return str(UnexpectedError()), 400 | ||
| # Return a generic unexpected error message without exposing the original exception. | ||
| return jsonify({"error": str(UnexpectedError())}), 500 | ||
|
|
||
|
|
||
| def handle_transformation(request: flask.Request): |
| except Exception as exc: | ||
| logger.exception("Transform request failed") | ||
| REQUEST_COUNT.labels(method="POST", endpoint="/transform", status="500").inc() | ||
| return jsonify({"error": str(exc)}), 500 |
Check warning
Code scanning / CodeQL
Information exposure through an exception Medium
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 5 months ago
In general, to fix this kind of problem you should avoid returning raw exception messages or stack traces to users. Instead, log detailed errors internally and send clients a generic, non-sensitive message (optionally with a non-identifying error code) along with the appropriate HTTP status.
For this specific file, the best fix without changing observable behavior beyond the error text is:
- Keep the
logger.exception(...)calls so full details (including stack trace) are logged on the server. - Replace
jsonify({"error": str(exc)})with a generic, non-revealing message such asjsonify({"error": "Internal server error"})(or slightly endpoint-specific wording if desired). - Apply this change to both the
/healthhandler (line 33) and the/transformhandler (line 55) to ensure consistent behavior.
No new imports or helper methods are required; jsonify is already imported and used. The modifications are confined to app/api/routes.py in the except blocks of health and transform.
| @@ -30,7 +30,7 @@ | ||
| except Exception as exc: | ||
| logger.exception("Health check failed") | ||
| REQUEST_COUNT.labels(method="GET", endpoint="/health", status="500").inc() | ||
| return jsonify({"error": str(exc)}), 500 | ||
| return jsonify({"error": "Internal server error"}), 500 | ||
| finally: | ||
| REQUEST_LATENCY.labels(method="GET", endpoint="/health").observe( | ||
| time.time() - start_time | ||
| @@ -52,7 +52,7 @@ | ||
| except Exception as exc: | ||
| logger.exception("Transform request failed") | ||
| REQUEST_COUNT.labels(method="POST", endpoint="/transform", status="500").inc() | ||
| return jsonify({"error": str(exc)}), 500 | ||
| return jsonify({"error": "Internal server error"}), 500 | ||
| finally: | ||
| REQUEST_LATENCY.labels(method="POST", endpoint="/transform").observe( | ||
| time.time() - start_time |
…sformation request
…and service task naming
… multiple test files
… and adjust documentation
Description
Please describe the changes you made.
Checklist
Additional Notes
Is there anything the reviewers should pay attention to?