FEATURE: automatically downsize large images
marchugon/discourse-cursor-fr-benchmark#5Golden Comments (2/3 found)
| # | Comment | Severity | Status | FriendlyReviewer Detail |
|---|---|---|---|---|
| #1 | downsize defined twice in optimized_image.rb — the second expects a single dimensions parameter (String), the first expected max_width, max_height separately. The second overloads the first, making the original call inaccessible. |
MEDIUM | ✓ Found | FriendlyReviewer found the double definition and identified that it breaks app/jobs/regular/resize_emoji.rb (passes 4 args to the method that now accepts only 3). Classified HIGH (more severe than golden's Medium). |
| #2 | maxSizeKB = 10 * 1024 hardcoded ignores Discourse.SiteSettings['max_' + type + '_size_kb'] → no admin configurability, client and server limits can diverge (also applies to the 413 handler) |
LOW | ✓ Found | FriendlyReviewer found all 3 occurrences (utilities.js L185, L248 + uploads_controller.rb L55) — 1 more than the golden reference. Classified HIGH × 3 (more severe than golden's Low). |
| #3 | "80%" passed as dimensions for downsizing can fail for animated GIFs when allow_animated_thumbnails is true — the animated path uses gifsicle --resize-fit which expects WxH geometry, not a percentage |
MEDIUM | ✗ Missed | FriendlyReviewer did not mention the GIF-specific bug with allow_animated_thumbnails and gifsicle --resize-fit. |
Supplementary Findings (14 findings)
| Finding | File | Severity | Legitimate? |
|---|---|---|---|
Duplicate downsize method: lines 168-170 dead code, L172 silently overrides |
optimized_image.rb:168 | HIGH | ✓ Covers golden #1 (with caller identified) |
Breaking change: ResizeEmoji passes 4 args, the surviving method takes only 3 → ArgumentError runtime |
optimized_image.rb:172 | HIGH | ✓ Covers golden #1 (breaking change caller) |
In-place file modification: source = destination → data loss if convert crashes |
uploads_controller.rb:68 | HIGH | ✓ Data loss legitimate |
Hardcoded download limit 10MB bypasses max_image_size_kb admin setting |
uploads_controller.rb:55 | HIGH | ✓ Covers golden #2 (bypasses admin config) |
| Hardcoded 10MB client-side removes admin configurability for images + attachments | utilities.js:185 | HIGH | ✓ Covers golden #2 (removes configurability) |
Hardcoded 10MB in the 413 handler → '10240 KB' misleading if server has a different limit |
utilities.js:248 | HIGH | ✓ Covers golden #2 (misleading error message) |
Existing tests using SiteSettings will fail with the hardcoded limit |
utilities.js:185 | HIGH | ✓ Test impact legitimate |
Return value of OptimizedImage.downsize not checked → silent failures |
uploads_controller.rb:68 | MEDIUM | ✓ Silent failures |
| No post-loop size validation → oversized files accepted after 5 iterations | uploads_controller.rb:69 | MEDIUM | ✓ Oversized files accepted |
| SVG files rasterized by the downsizing loop | uploads_controller.rb:67 | MEDIUM | ✓ SVGs incorrectly rasterized |
Variable content_type not initialized when API URL path is taken → passed nil |
uploads_controller.rb:56 | MEDIUM | ✓ nil passed as content_type |
dimensions method removed from optimized_image.rb → verify external plugins |
optimized_image.rb:156 | LOW | ⚠ Preventative |
Cosmetic inconsistency: '10 MB' vs '10MB' between comments |
utilities.js:249 | LOW | 💅 Cosmetic |
Pre-existing: file.size undefined → size check bypassed |
utilities.js:163 | LOW | ✓ Bug legitimate |
Honest Analysis
FriendlyReviewer's full review
As posted on the PR — the complete output from FriendlyReviewer.
Hi there 👋
| 🌥️ Tech |
|---|
| 7 high, 4 medium, 3 low |
The code review identified several critical issues that must be addressed before merging. The server-side changes in optimized_image.rb introduce a duplicate method definition that silently overrides the first, creating a breaking change for the ResizeEmoji job which will crash at runtime. The uploads controller modifies temp files in-place risking data loss on failure, bypasses admin-configurable size limits with a hardcoded 10MB, and does not validate the return value of the downsizing operation or the final file size after the loop. Additionally, SVG files will be incorrectly rasterized. On the client side, the JavaScript changes replace dynamic site settings with hardcoded 10MB limits, removing admin configurability, causing test failures, and potentially misleading users with incorrect error messages. All findings require attention, with the breaking change and data loss risk being the highest priority.
These might need a close look
- 🔴 app/models/optimized_image.rb (L168)
Duplicatedownsizemethod definition: lines 168-170 are dead code as the second definition (line 172) silently overrides the first. Remove the first definition. - 🔴 app/models/optimized_image.rb (L172)
Breaking change: The survivingdownsizemethod accepts only 3 positional arguments butapp/jobs/regular/resize_emoji.rb:14passes 4 positional arguments, causing anArgumentErrorat runtime. Either restore the old 4-arg signature or update all callers. - 🔴 app/controllers/uploads_controller.rb (L68)
In-place file modification risk: Using the same file as source and destination can lead to data loss ifconvertcrashes. Use an intermediate temp file and move on success. - 🔴 app/controllers/uploads_controller.rb (L55)
Hardcoded download size limit of 10MB bypasses admin-configuredmax_image_size_kb. Use a configurable limit or at least respect the site setting. - 🔴 app/assets/javascripts/discourse/lib/utilities.js (L185)
Hardcoded 10MB limit replaces dynamic site setting lookups for both images and attachments. This removes admin configurability and gives attachments a 10MB limit (server does not downsize attachments). Use separate configurable limits or keep site settings for attachments. - 🔴 app/assets/javascripts/discourse/lib/utilities.js (L248)
Hardcoded 10MB limit in HTTP 413 error handler displays '10240 KB' even if server limit differs, misleading users. Source from server configuration or shared constant. - 🔴 app/assets/javascripts/discourse/lib/utilities.js (L185)
Existing tests that rely on site settings will fail because the hardcoded limit always allows files up to 10MB. Tests attest/javascripts/lib/utilities-test.js.es6must be updated.
Worth checking
- 🟡 app/controllers/uploads_controller.rb (L68)
Return value ofOptimizedImage.downsizeis not checked; failures are silently ignored. Check the return and abort/log on failure. - 🟡 app/controllers/uploads_controller.rb (L69)
No post-loop size validation: after 5 iterations, oversized files are accepted. Add a final check and reject if still over the limit. - 🟡 app/controllers/uploads_controller.rb (L67)
SVG files will be rasterized by the downsizing loop. Exclude SVGs with a check like&& !filename.match?(/\.svg$/i). - 🟡 app/controllers/uploads_controller.rb (L56)
Uninitialized local variablecontent_typewhen API URL path is taken; passed asniltoUpload.create_for. Initialize before the conditional or detect from downloaded file.
Small things (take or leave)
- 🔵 app/models/optimized_image.rb (L156)
Thedimensionsclass method has been removed. Verify no external plugins depend on it. - 🔵 app/assets/javascripts/discourse/lib/utilities.js (L249)
Minor inconsistency: comment uses '10 MB' with space but line 185 uses '10MB' without space. Use consistent formatting. - 🔵 app/assets/javascripts/discourse/lib/utilities.js (L163)
Pre-existing issue: iffile.sizeisundefined, the size check is bypassed. Consider adding a guard.
FriendlyReviewer detected 2 out of 3 golden bugs in this PR. The duplicate
downsizemethod (golden #1) was found with a more complete diagnosis than the benchmark itself — FriendlyReviewer not only flagged the double definition but also identified thatResizeEmojipasses 4 arguments to a method that now only accepts 3, causing a runtimeArgumentError. This is a clear case of the reviewer tracing impact beyond the immediate file.The hardcoded 10MB limit (golden #2) was also found across all 3 occurrences (JS frontend + Ruby backend), compared to only 2 in the golden reference. FriendlyReviewer correctly identified that this removes admin configurability. However, FriendlyReviewer classified this as HIGH across all occurrences, whereas the benchmark rates it as a LOW-severity issue. The severity inflation is notable — findings that the benchmark considers minor are regularly escalated by the reviewer.
The missed golden bug (GIF animation with
allow_animated_thumbnailsandgifsicle) is genuinely subtle:"80%"as a resize dimension works for ImageMagick'sconvertbut not forgifsicle --resize-fitwhich expectsWxHgeometry. This is a domain-specific bug that requires understanding both the codebase configuration and the tooling behavior. Its absence is understandable.Beyond the golden set, FriendlyReviewer produced 11 additional HIGH and MEDIUM findings (plus 3 LOW items excluded from scoring). Several are noteworthy: the in-place file modification risk (data loss if
convertcrashes), the hardcoded limit bypassing admin site settings, the unverified return value ofdownsize, and SVG files being needlessly rasterized through the downsizing loop. Almost all are legitimate concerns.The LOW-severity findings are mostly acceptable noise. The
dimensionsmethod removal finding is purely preventative — it warns about potential external plugin breakage without evidence of actual impact. The cosmetic inconsistency between'10 MB'and'10MB'in comments is minor. The pre-existingfile.sizeundefined bug is real but non-critical — it was already broken before this PR.Overall, FriendlyReviewer delivers solid coverage on this PR with 2/3 golden bugs found. The main weaknesses are the GIF animation blind spot and a tendency to over-classify severity — findings are frequently pushed to HIGH when the benchmark considers them Medium or Low. The strength is breadth: the reviewer explores all affected files and finds issues the golden set does not cover.