Hi there 👋
| 🌥️ Tech |
🌤️ Feat |
| 2 high, 3 medium, 1 low |
1 mitigated |
This MR introduces a website_name attribute to UserSerializer intended to expose the site's host (plus path when it matches the instance domain) as a UX improvement. While the three added specs pass for the exercised branches, the implementation contains critical defects that block merging: the include_website_name guard is misnamed (missing ?) so it never runs and website_name is always serialized for every user; the attribute is not registered under untrusted_attributes, leaking the host to anonymous/TL0 viewers even when the underlying website field is masked; and the domain-matching logic is asymmetric and can fail for subdomain-of-instance cases. Spec coverage also omits the middle subdomain branch, the no-path case, and the TL0 masking path. These issues must be fixed and covered before the change is ready.
These might need a close look
- 🔴 app/serializers/user_serializer.rb (L153)
include_website_name is missing the trailing ?, so AMS does not recognize it as an inclusion guard and website_name is unconditionally serialized for every user (including users with no website). The intended website.present? check is dead code. Rename to include_website_name? and route through the project's conditional-exposure macros.
- 🔴 app/serializers/user_serializer.rb (L109)
website_name is not registered under untrusted_attributes, so its host value (e.g. example.com) is exposed to anonymous/TL0 viewers even when the source website field is masked by restrict_user_fields?. This trust-level masking bypass must be fixed by registering website_name as untrusted.
Worth checking
- 🟡 spec/serializers/user_serializer_spec.rb (L11)
The TL0 anonymous context only asserts the absence of existing attributes and uses a blank website fixture, so the website_name leak is invisible. Add a case where a TL0 user has a website and assert json does not include website_name, and extend the untrusted_attributes list with :website_name.
- 🟡 app/serializers/user_serializer.rb (L137)
The label-count string comparison is asymmetric and error-prone: when the website is a subdomain of the instance (e.g. www.example.com vs example.com), the path is not shown, while the reverse direction is treated as matching. The else branch can false-positive on single-label hosts, and URI(...).host strips the port, treating same host on different ports as identical. Use a proper suffix/public-suffix comparison and guard label counts; also parse URI(website.to_s) once instead of three times.
- 🟡 app/serializers/user_serializer.rb (L138)
website_name returns nil for scheme-less websites (e.g. bare example.com/user from import scripts) because URI("example.com/user").host is nil, while the (once-corrected) include_website_name? would still return true, yielding a key with a nil value. The broad rescue nil also hides parse failures. Guard on website.present? and handle scheme-less input before parsing.
Small things (take or leave)
- 🔵 spec/serializers/user_serializer_spec.rb (L77)
The spec covers only the exact-match and website-parent-of-instance branches; it omits the middle subdomain branch (e.g. www.example.com vs forum.example.com, same label count) and any case where the website has no path. Add coverage for these to lock in the intended contract.
✅ Feature-level checklist
Partially covered
- ⚠️ UX: show complete URL path if website domain is same as instance domain
The implementation attempts to expose the full host+path when the website domain matches the instance, and works for exact matches and the website-parent-of-instance direction. However, the guard is dead code causing unconditional serialization, the domain-matching logic is asymmetric (fails for subdomain-of-instance cases), and the feature leaks the host to untrusted users. Additionally, the no-path and middle-branch cases are untested. The core requirement is only partially satisfied.
The single golden is two-part: the missing
?oninclude_website_nameand the'.' << website_hostconcatenation that mutates string literals. FriendlyReviewer covers the first half thoroughly — the guard is never recognized by AMS, sowebsite_nameis serialized unconditionally for every user and thewebsite.present?check is dead code — and pins it to user_serializer.rb L153, the exact line. The second half is absent from the review: no finding mentions the string-literal mutation. The 1/1 recall therefore flatters the result; this is a partial hit, and the Found status is kept only because the dominant defect was caught.The best supplementary finding is the L109 trust-level leak:
website_namenot registered underuntrusted_attributesexposes the host to anonymous/TL0 viewers even when the source field is masked — arguably more severe than the golden itself. The two spec findings (L11, L77) are coherent: the test suite structurally cannot see either defect. The L137/L138 domain-matching findings are concrete (asymmetric subdomain comparison, port stripping, nil for scheme-less input) and correctly tied to the same serializer.The weak points are honest to state. The review certifies "critical defects that block merging" partly on a Rails/AMS convention (the
include_?suffix) — correct per the golden — but the L109 leak is asserted without showing the masking path it depends on. And the golden's second defect never surfaced: a reviewer who read the diff closely enough to flag dead code at L153 should have seen'.' << website_hosta few lines above. Strong on the guard, blind on the second issue — a partial hit that the recall badge alone would overstate.