fix(office-ui): serve attachments saved under any project - #37
Open
CatJuly wants to merge 1 commit into
Open
Conversation
Images uploaded in chat render as broken thumbnails whenever the active
project is not the one the server started with. Uploads are saved by the
per-project engine under projects/{pid}/attachments/{id}/, but the
/api/attachments HTTP handler only looked in the root engine's active
attachment store, so every request for a file stored under another
project returned 404.
Resolve attachments across all project attachment directories: try the
active store first, then projects/*/attachments/{id}/{filename}.
Attachment ids are 16-hex uuid4 prefixes, unique across projects, so the
scan cannot serve the wrong file. Both path components are validated
(no separators, no '..') before touching the filesystem, keeping the
existing traversal guard intact.
Verified with a new test (opc/plugins/office_ui/tests/
test_attachment_http_handler.py) that reproduces the cross-project 404
before the fix and passes after; office_ui suite shows no regressions
vs the origin/main baseline (same 6 pre-existing event_adapter
failures).
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.
Summary
Images uploaded in the office-UI chat render as broken thumbnails (
404on/api/attachments/...) whenever the message was sent while a project other than the server's startup project was active.Root cause
Uploads are processed by the per-project engine resolved via
_engine_for_request, andAttachmentStorewrites files to{opc_home}/projects/{project_id}/attachments/{id}/{filename}. The HTTP download handler built by_make_attachment_handler(engine)inopc/plugins/office_ui/server.py, however, only resolves paths against the root engine's active attachment store. Any attachment saved under a different project's directory is reported as404 Not found, so<img>tags in the chat show broken images.Reproduce: start
opc ui, switch to (or create) a non-default project, paste an image into the chat, send. The stored file lands inprojects/<that-project>/attachments/...while the handler looks inprojects/default/attachments/....Fix
_make_attachment_handlernow resolves the attachment across all project attachment directories: the active store is tried first (fast path), thenprojects/*/attachments/{attachment_id}/{filename}. Attachment ids are 16-hexuuid4prefixes and unique across projects, so the scan cannot serve a wrong file. Both URL path components are rejected up front if they contain path separators or.., and the existing_is_under_pathtraversal guard is kept per candidate.Testing
opc/plugins/office_ui/tests/test_attachment_http_handler.py:../ separator components inattachment_idandfilename.uv run pytest opc/plugins/office_ui/tests/ tests/test_attachment_multimodal_routing.py: failure list identical to the origin/main baseline (6 pre-existingtest_event_adapter.pyfailures on both sides), so no regressions.200 image/png; traversal attempts never reach the filesystem.Scope
Backend only (
server.py+ new test). No frontend orfrontend_distchanges.