[medium] fix: return a structured error when the remote event fetch fails - #391
Merged
Merged
Conversation
The exception handler guarding the remote event fetch in push_event_by_uuid read response.status_code and response.json(), but response is bound only by the call inside the try that can raise. Any transport-layer failure (DNS, connection refused, TLS, timeout) left it unbound, so the handler raised UnboundLocalError and the structured error dict was never returned: the Celery push task died with a traceback pointing at the handler and the real cause was lost. Even when response was bound, response.json() could raise again on a non-JSON body. Return a fixed 502 with the exception text instead, matching the sibling handler in the same function, and log with logger.exception so the traceback is kept. The stray positional argument to logger.warning, which logging reported as a formatting error rather than logging the exception, goes away with it. The dropped "response" key has no consumer: the router returns the dict verbatim, the Celery task discards it and the frontend reads only "message". Add a fixture-free regression test that makes the remote request raise and asserts the error dict is returned. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #391 +/- ##
==========================================
+ Coverage 84.33% 84.40% +0.06%
==========================================
Files 208 208
Lines 19391 19402 +11
==========================================
+ Hits 16354 16376 +22
+ Misses 3037 3026 -11 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Collaborator
|
Makes sense, thanks! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
BLUF
push_event_by_uuidcrashed withUnboundLocalErrorwhenever the remote MISP server was unreachable, instead of returning its error dict.exceptblock dereferencedresponse, which is only bound by the very call that raised.502plus the exception text, and log withlogger.exception.app/tests/repositories/test_servers.py.What was wrong
In
api/app/repositories/servers.py, the handler guarding the remote event fetch readresponse.status_codeandresponse.json():responseis bound only byremote_misp._prepare_request(...)inside thetry— the call that can raise. Three defects in those lines:requestsinside_prepare_request) leavesresponseunbound, so the handler itself raisesUnboundLocalError.responseis bound —_check_json_responseorMISPEvent.loadraising on a 200 —response.json()can raise a second time on a non-JSON body.logger.warning(msg, ex)passesexas a printf-style argument to an already-.format()-ed message, which logging reports as a formatting error rather than logging the exception; andwarningdiscards the traceback.Concrete impact
Pushing an event to an unreachable, DNS-unresolvable or bad-TLS server never returns the structured error dict. The Celery task
push_event_by_uuiddies with a misleading traceback anchored in the error handler, so the actual connection failure is lost from the logs, and the push endpoint returns a 500 rather than a readable message.What this changes
One exception handler:
Notes on the shape chosen:
responsedereference.responsekey is dropped rather than reconstructed: nothing consumes it. The router returns the dict verbatim, the Celery task discards it, and the frontend reads onlymessage(frontend/src/components/events/EventActions.vue:58)."...: %s" % exis the idiom already used in this module for remote-connection failures.logger.exceptionkeeps the traceback and removes the stray positional argument.This also removes the second latent crash (
response.json()on a non-JSON body) without a separate change.How it was verified
TestPushEventByUuid::test_unreachable_server_returns_an_errorinapi/app/tests/repositories/test_servers.py, following the existing fixture-free class pattern in that module. It patchesget_remote_misp_connectionso_prepare_requestraisesConnectionError, asserts the fetch was actually reached, then assertsstatus == 502and that the exception text reachesmessage. It errors withUnboundLocalErrorbefore this change and passes after it, and needs no database, OpenSearch or network.python3 -m compileall-equivalent syntax sweep overapi/is clean.docs/features/api/openapi.jsonis unaffected.