Conversation
The marker upload lands in storage under the uploader's own filename before generate_marker_variants renames it to markers/<pk>/original.<ext> and deletes the original. That delete sat in a bare `except Exception: pass`, so a storage failure left the user-named object in public storage with nothing recording it. Narrows the except to OSError and SuspiciousFileOperation and logs the exception with the path left behind. The upload still succeeds either way. Closes #989 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HXUw7kyELDu8ycGQxtaFbb
This branch has not been deployed
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.
Description
A marker upload first lands in storage under the uploader's own filename, because
Marker.sourcehasupload_to="markers/".generate_marker_variantsthen renames it tomarkers/<pk>/original.<ext>and deletes the original — but that delete was wrapped in a bareexcept Exception: passlabelled "non-critical cleanup".It isn't non-critical. If the delete fails, the object stays publicly reachable under a name the uploader chose, and nothing anywhere records it: no log, no metric, no retry. That's the same privacy exposure @pablodiegoss described on #699 — it just happens on the failure path instead of the happy one.
Resolves (Issues)
Closes #989
General tasks performed
exceptfrom bareExceptiontoOSErrorandSuspiciousFileOperation.passwithlog.exception(...), naming the path left behind and the marker id, so it reaches Sentry.src/core/tests/test_marker_cleanup_logging.py— the happy path renames away from the user's filename; a failingstorage.deleteis logged and the upload still succeeds; a successful cleanup logs nothing.Something the test surfaced
Django's
get_valid_namesanitises but does not anonymise. An upload namedMinha imagem #1.pngreaches storage asmarkers/Minha_imagem_1.png— spaces become underscores and#is dropped, yet it is still recognisably the uploader's chosen name. The test asserts on the sanitised form, and there's a comment explaining why, so the next reader doesn't assume Django already solved this.Deliberately unchanged: the failure still doesn't fail the upload, and there's no retry or sweeper. Making it visible is the fix this issue asks for; deciding whether to retry or queue the path for a later sweep is a design call for the maintainers.
Verification: full suite
pytest src/core src/users src/blogpasses — 275 passed.ruff format --diff src/clean, zeroI001, andruff checkactually drops from 93 findings ondevelopto 92 here, because removing the bareexceptalso removes itsBLE001andS110.Have you confirmed the application builds locally without error? See here.
🤖 Generated with Claude Code
https://claude.ai/code/session_01HXUw7kyELDu8ycGQxtaFbb
Generated by Claude Code