fix(webapp): wiki text draws only uploaded pictures (#1138) #1161

Merged
claude-bot merged 8 commits from fix/1138-wiki-pictures-own-uploads into main 2026-10-13 05:31:16 +00:00
Collaborator

Closes #1138 (D297).

A picture in page text is drawn only when its address is one of Quest Board's own upload routes. Anything else stops being fetched by every reader's browser.

  • Rule (wiki/ownPicture.js, mirrored in image_service.is_own_picture_url): /api/campaigns/<id>/files/<id> and /api/campaigns/<id>/lore/<id>/image, anchored. An outside http(s) address becomes an ordinary link named by its alt text; anything else stays as typed text.
  • Where: extractAtoms in wikiText.js, so every WikiText user gets it; a page's own picture goes through a new Picture.jsx.
  • Editor: the picture button opens a file picker and uploads, instead of inserting ![](https://).
  • Server: a PATCH image_url that is not own or legacy is a 422; an import drops one; sanitize_markdown turns Markdown pictures into links.
  • CSP: img-src 'self' data: https: becomes img-src 'self'.

No migration, no bot contract change.

Verified

On docker-test: backend tests/wiki, tests/export, test_campaigns.py, the reference adapters and the new tests (2646 passed); ruff; changelog check; frontend-prod image built and its served CSP header read. Frontend lint clean. The full vitest run had 93 failures under a host load of about 40; every failing file passed on a two-worker rerun, but the whole suite was not rerun in one go.

Not run: the new journey e2e/j8-wiki-pictures.spec.js; no page was loaded in a browser against the new CSP (render check of the map, page pictures and the editor still to do before merging).

Found on the way, not fixed here

GET /auth/logout ends the session, so a plain link to it logs a reader out. Several other GET routes write. To be filed separately.

🤖 Generated with Claude Code

Closes #1138 (D297). A picture in page text is drawn only when its address is one of Quest Board's own upload routes. Anything else stops being fetched by every reader's browser. - **Rule** (`wiki/ownPicture.js`, mirrored in `image_service.is_own_picture_url`): `/api/campaigns/<id>/files/<id>` and `/api/campaigns/<id>/lore/<id>/image`, anchored. An outside `http(s)` address becomes an ordinary link named by its alt text; anything else stays as typed text. - **Where**: `extractAtoms` in `wikiText.js`, so every `WikiText` user gets it; a page's own picture goes through a new `Picture.jsx`. - **Editor**: the picture button opens a file picker and uploads, instead of inserting `![](https://)`. - **Server**: a `PATCH image_url` that is not own or legacy is a 422; an import drops one; `sanitize_markdown` turns Markdown pictures into links. - **CSP**: `img-src 'self' data: https:` becomes `img-src 'self'`. No migration, no bot contract change. ## Verified On `docker-test`: backend `tests/wiki`, `tests/export`, `test_campaigns.py`, the reference adapters and the new tests (2646 passed); ruff; changelog check; `frontend-prod` image built and its served CSP header read. Frontend lint clean. The full vitest run had 93 failures under a host load of about 40; every failing file passed on a two-worker rerun, but the whole suite was not rerun in one go. Not run: the new journey `e2e/j8-wiki-pictures.spec.js`; no page was loaded in a browser against the new CSP (render check of the map, page pictures and the editor still to do before merging). ## Found on the way, not fixed here `GET /auth/logout` ends the session, so a plain link to it logs a reader out. Several other GET routes write. To be filed separately. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
An outside picture is a link; one rule (ownPicture.js / image_service) for
text, stored page pictures, imports and the sanitiser. The picture button
uploads. img-src narrowed to 'self'.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
docs+e2e(webapp): D297, changelog fragment, journey for outside pictures (#1138)
Some checks failed
CI / Does this change touch the recording path? (pull_request) Successful in 18s
CI / Synthetic session harness (no GPU, no LLM) (pull_request) Has been skipped
CI / Backend lint (ruff) (pull_request) Successful in 44s
CI / Bot/backend version sync (pull_request) Successful in 54s
CI / Docker image build (pull_request) Successful in 53s
CI / Summarisation accuracy eval harness (stub provider) (pull_request) Successful in 1m28s
CI / Feedback site tests (pull_request) Successful in 1m33s
CI / Bot tests and audit (pull_request) Successful in 2m39s
CI / Frontend (shard 2/2) (pull_request) Successful in 10m30s
CI / Frontend (shard 1/2) (pull_request) Successful in 13m25s
CI / End-to-end journeys (keyboard) (pull_request) Failing after 16m51s
CI / End-to-end journeys (phone) (pull_request) Failing after 16m50s
CI / End-to-end journeys (desktop) (pull_request) Failing after 18m57s
CI / Backend migration, tests, and audit (pull_request) Has been cancelled
2d7d675035
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
fix(e2e): J8 makes its page with a valid entry_type (#1138)
Some checks failed
CI / Does this change touch the recording path? (pull_request) Successful in 26s
CI / Synthetic session harness (no GPU, no LLM) (pull_request) Has been skipped
CI / Bot/backend version sync (pull_request) Successful in 34s
CI / Backend lint (ruff) (pull_request) Successful in 38s
CI / Feedback site tests (pull_request) Successful in 58s
CI / Summarisation accuracy eval harness (stub provider) (pull_request) Successful in 1m11s
CI / Bot tests and audit (pull_request) Successful in 2m20s
CI / Docker image build (pull_request) Successful in 3m7s
CI / Frontend (shard 1/2) (pull_request) Successful in 12m0s
CI / Frontend (shard 2/2) (pull_request) Successful in 13m39s
CI / End-to-end journeys (desktop) (pull_request) Failing after 15m42s
CI / End-to-end journeys (keyboard) (pull_request) Failing after 15m44s
CI / End-to-end journeys (phone) (pull_request) Failing after 18m16s
CI / Backend migration, tests, and audit (pull_request) Successful in 39m42s
f4b847907d
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
fix(e2e): J8 uploads a valid PNG (#1138)
Some checks failed
CI / Backend lint (ruff) (pull_request) Successful in 33s
CI / Feedback site tests (pull_request) Successful in 52s
CI / Does this change touch the recording path? (pull_request) Successful in 19s
CI / Synthetic session harness (no GPU, no LLM) (pull_request) Has been skipped
CI / Bot/backend version sync (pull_request) Successful in 26s
CI / Summarisation accuracy eval harness (stub provider) (pull_request) Successful in 1m8s
CI / Bot tests and audit (pull_request) Successful in 2m9s
CI / Docker image build (pull_request) Successful in 2m39s
CI / Frontend (shard 1/2) (pull_request) Successful in 9m38s
CI / End-to-end journeys (desktop) (pull_request) Successful in 10m19s
CI / Frontend (shard 2/2) (pull_request) Successful in 15m2s
CI / End-to-end journeys (phone) (pull_request) Successful in 19m30s
CI / End-to-end journeys (keyboard) (pull_request) Successful in 21m59s
CI / Backend migration, tests, and audit (pull_request) Has been cancelled
19134847f1
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Merge main into fix/1138
Some checks failed
CI / Summarisation accuracy eval harness (stub provider) (pull_request) Successful in 1m5s
CI / Backend lint (ruff) (pull_request) Successful in 34s
CI / Bot/backend version sync (pull_request) Successful in 32s
CI / Feedback site tests (pull_request) Successful in 52s
CI / Bot tests and audit (pull_request) Successful in 2m17s
CI / Does this change touch the recording path? (pull_request) Successful in 23s
CI / Synthetic session harness (no GPU, no LLM) (pull_request) Has been skipped
CI / Frontend (shard 2/2) (pull_request) Successful in 10m8s
CI / Docker image build (pull_request) Successful in 5m56s
CI / Frontend (shard 1/2) (pull_request) Successful in 11m53s
CI / Backend migration, tests, and audit (pull_request) Failing after 12m25s
CI / End-to-end journeys (keyboard) (pull_request) Failing after 1m6s
CI / End-to-end journeys (desktop) (pull_request) Failing after 1m32s
CI / End-to-end journeys (phone) (pull_request) Has been cancelled
d1411bd552
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ci: re-run after the runner ran out of disk
All checks were successful
CI / Does this change touch the recording path? (pull_request) Successful in 29s
CI / Synthetic session harness (no GPU, no LLM) (pull_request) Has been skipped
CI / Backend lint (ruff) (pull_request) Successful in 47s
CI / Bot/backend version sync (pull_request) Successful in 56s
CI / Feedback site tests (pull_request) Successful in 1m3s
CI / Docker image build (pull_request) Successful in 1m2s
CI / Summarisation accuracy eval harness (stub provider) (pull_request) Successful in 1m26s
CI / Bot tests and audit (pull_request) Successful in 2m30s
CI / Frontend (shard 2/2) (pull_request) Successful in 9m0s
CI / Frontend (shard 1/2) (pull_request) Successful in 13m4s
CI / End-to-end journeys (desktop) (pull_request) Successful in 14m53s
CI / End-to-end journeys (keyboard) (pull_request) Successful in 14m51s
CI / End-to-end journeys (phone) (pull_request) Successful in 18m0s
CI / Backend migration, tests, and audit (pull_request) Successful in 33m56s
d43147972e
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Merge main into fix/1138
All checks were successful
CI / Does this change touch the recording path? (pull_request) Successful in 33s
CI / Synthetic session harness (no GPU, no LLM) (pull_request) Has been skipped
CI / Summarisation accuracy eval harness (stub provider) (pull_request) Successful in 1m1s
CI / Docker image build (pull_request) Successful in 1m10s
CI / Bot/backend version sync (pull_request) Successful in 1m14s
CI / Backend lint (ruff) (pull_request) Successful in 1m25s
CI / Feedback site tests (pull_request) Successful in 2m2s
CI / Bot tests and audit (pull_request) Successful in 2m10s
CI / Frontend (shard 2/2) (pull_request) Successful in 10m38s
CI / Frontend (shard 1/2) (pull_request) Successful in 12m39s
CI / End-to-end journeys (desktop) (pull_request) Successful in 14m17s
CI / End-to-end journeys (keyboard) (pull_request) Successful in 15m8s
CI / End-to-end journeys (phone) (pull_request) Successful in 22m6s
CI / Backend migration, tests, and audit (pull_request) Successful in 33m59s
8b58b7d2fd
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
claude-bot scheduled this pull request to auto merge when all checks succeed 2026-10-13 04:57:23 +00:00
claude-bot deleted branch fix/1138-wiki-pictures-own-uploads 2026-10-13 05:31:17 +00:00
Sign in to join this conversation.
No description provided.