fix: add defensive checks for time ranges, pointer queries, and entity fields#1889
fix: add defensive checks for time ranges, pointer queries, and entity fields#1889LautaroPetaccio wants to merge 3 commits into
Conversation
decentraland-bot
left a comment
There was a problem hiding this comment.
Review: fix: add defensive checks for time ranges, pointer queries, and entity fields
PR: #1889
Files changed: 5 (+43 -4)
Findings Summary
- P1 CRITICAL: 1 — blocks merge
- P2 IMPORTANT: 2 — should fix
- P3 NICE-TO-HAVE: 2 — enhancements
P1 — Critical (Blocks Merge)
- [CI]
validationscheck is failing — prettier formatting error- File:
content/src/controller/handlers/get-entities-handler.ts:48 - The chained
.filter()makes the line too long for prettier. The lint step wants the chain broken across multiple lines:enumFields = fields .split(',') .map((f) => (<any>EntityField)[f.toUpperCase().trim()]) .filter((f) => f !== undefined)
- File:
P2 — Important
-
[Correctness] Empty
enumFieldsarray when all field names are invalid- File:
content/src/controller/handlers/get-entities-handler.ts:48 - If a client sends
?fields=BOGUS, the filter producesenumFields = [](empty array). Previously this would have been[undefined]. Verify how downstream code (maskEntity) handles an empty array vsundefined— if[]means "return no fields" rather than "return all fields", this silently changes the API behavior for typo'd requests. Consider either returning a 400 for unrecognized field names, or treating[]the same asundefined.
- File:
-
[Testing] Missing test coverage for 3 of the 4 fixes
- The time-range fix has good tests ✅
- No test for
checker.ts— should assertresult.get(item) === falsewhencontractAddressis missing - No test for
pointers-queries.ts— should verify early return on empty arrays without hitting the DB - No test for
get-entities-handler.ts— should verify invalid field names are filtered and check the empty-array edge case
P3 — Nice-to-Have
-
[Type Safety]
<any>EntityFieldbracket-notation lookup with user input- File:
content/src/controller/handlers/get-entities-handler.ts:48 - Pre-existing, but worth improving alongside this change. Prototype keys like
__proto__,constructor,toStringare notundefinedand will survive the filter. A whitelist approach is safer:const VALID_FIELDS = new Set(Object.values(EntityField)) enumFields = fields .split(',') .map((f) => (<any>EntityField)[f.toUpperCase().trim()]) .filter((f): f is EntityField => VALID_FIELDS.has(f))
- File:
-
[Clarity]
time-range.tsloop redundantly processessorted[0]- The first iteration compares
sorted[0].initTimestamp > sorted[0].endTimestamp(always false for valid ranges) and theMath.maxis a no-op. Starting from index 1 would be slightly cleaner but not functionally necessary.
- The first iteration compares
Security
No new vulnerabilities introduced. The changes are net-positive for security — the empty-array SQL guards prevent malformed queries, and the undefined filter prevents unexpected downstream behavior. The pre-existing <any> enum lookup is flagged above as a P3 improvement.
Verdict
Request changes — the CI formatting failure must be fixed before merge, and the empty enumFields array edge case should be verified.
Requested by Lautaro Petaccio via Slack
Summary
Three defensive-coding fixes across different modules:
isTimeRangeCoveredByassumed sorted input (logic/time-range.ts): The sweep-line algorithm checked for gaps by comparing each range's start against the running max. If input ranges were unsorted, it could falsely detect a gap and trigger unnecessary snapshot regeneration. Now sorts a copy of the input byinitTimestampbefore sweeping.Empty pointers array produces invalid SQL (
pointers-queries.ts):updateActiveDeploymentsandremoveActiveDeploymentsbuilt SQLINSERT ... VALUESorDELETE ... IN ()clauses from the pointers array without guarding against empty input. While callers currently validate this upstream, the functions themselves now return early on empty arrays.Invalid field names silently become undefined (
get-entities-handler.ts): The?fields=query param mapped field names toEntityFieldenum values via(<any>EntityField)[f.toUpperCase()]. Unrecognized names producedundefinedentries in the array, which were passed through tomaskEntity(). Now filters out undefined values after mapping.Also adds
result.set(item, false)inchecker.tsfor items without acontractAddress, making the rejection explicit instead of relying on the|| falsefallback at the call site.Test plan
cd content && npx jest test/unit/ --no-coverage