Skip to content

Conversation

EmpiDev
Copy link
Contributor

@EmpiDev EmpiDev commented May 27, 2025

Pull Request

Issue

Closes: #8693

Approach

This PR continues and supersedes #8694 by @dblythy.
Adds ability to return objects (or an empty array) from a beforeFind trigger.

Tasks

  • Add tests

Summary by CodeRabbit

  • New Features

    • find/get now support trigger-returned objects, including returning unsaved objects and get-specific behavior.
  • Bug Fixes

    • Access control enforced when triggers return objects; protected fields remain masked after re-filtering.
    • Role/security checks run before trigger processing to avoid unexpected database access.
  • Tests

    • Added extensive tests for beforeFind/afterFind flows, ACL/security, protectedFields, get-vs-find, and various query/input edge cases.
  • Refactor

    • Centralized trigger and query handling; object class names preserved when converting results.

Copy link

parse-github-assistant bot commented May 27, 2025

🚀 Thanks for opening this pull request!

Copy link

coderabbitai bot commented May 27, 2025

📝 Walkthrough

Walkthrough

Centralizes beforeFind/afterFind handling; allows beforeFind to short‑circuit find/get by returning objects/arrays; propagates isGet through trigger requests and RestQuery; refilters returned objects to enforce ACLs before afterFind; updates trigger utilities and adds tests for these behaviors.

Changes

Cohort / File(s) Change Summary
Tests
spec/CloudCode.spec.js
Added extensive tests for beforeFind short‑circuiting (single object, arrays, get, empty), ACL/protectedFields scenarios, and direct maybeRunAfterFindTrigger edge cases.
REST trigger orchestration
src/rest.js
Added internal runFindTriggers to centralize beforeFind/afterFind for find/get; supports beforeFind returning objects/arrays, performs refilter-by-ID query (with triggers disabled) to enforce ACLs, then runs afterFind; find/get now enforce role security and delegate to runFindTriggers.
Trigger utilities
src/triggers.js
toJSONwithObjects preserves className; getRequestObject(...) and maybeRun* functions accept isGet; maybeRunAfterFindTrigger coerces queries/objects into Parse.Query/Parse.Object, validates classNameQuery, normalizes inputs, improves logging, and returns JSON results.
Query layer
src/RestQuery.js
Introduced boolean isGet propagated into _UnsafeRestQuery and used instead of repeated method checks; isGet passed to trigger-related calls (e.g., maybeRunQueryTrigger, runAfterFindTrigger).

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant REST as REST Handler
    participant Triggers
    participant DB

    Client->>REST: find/get request
    REST->>Triggers: beforeFind(request { isGet, query, auth, ... })
    alt beforeFind returns objects/array
        Triggers-->>REST: objects/array
        REST->>REST: refilter by IDs (no triggers) to enforce ACLs
        REST->>Triggers: afterFind(request { isGet, query, auth, ... }, results)
        Triggers-->>REST: processedResults
        REST-->>Client: processedResults
    else
        Triggers-->>REST: (maybe modified) query/options
        REST->>DB: execute query (find/get)
        DB-->>REST: results
        REST->>Triggers: afterFind(request { isGet, query, auth, ... }, results)
        Triggers-->>REST: finalResults
        REST-->>Client: finalResults
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Assessment against linked issues

Objective Addressed Explanation
Allow beforeFind to return objects, bypassing RestQuery (#8693) beforeFind can return objects/arrays; runFindTriggers handles the short‑circuit path.
Support returning arrays or empty array from beforeFind to short‑circuit queries (#8693) Arrays and empty arrays are supported and tested.
Ensure afterFind receives objects returned from beforeFind short‑circuiting (#8693) Returned objects are re-filtered for ACLs then passed to afterFind.
Add tests covering beforeFind short‑circuiting and maybeRunAfterFindTrigger behavior (#8693) New test suites added in spec/CloudCode.spec.js.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues Check ✅ Passed The changes introduce centralized beforeFind handling that respects returned object arrays or empty arrays to bypass the default RestQuery flow, re-filters results for ACL compliance, and runs afterFind triggers as specified in issue #8693.
Out of Scope Changes Check ✅ Passed All additions and signature adjustments in rest.js, triggers.js, and RestQuery.js directly support the beforeFind short-circuit feature—including centralized runFindTriggers logic, isGet propagation, and trigger invocation changes—and there are no unrelated or extraneous modifications outside that objective.
Description Check ✅ Passed The description accurately follows the repository template by including the Pull Request header with security and licensing links, a filled-in Issue section referencing the specific linked issue, a concise Approach section summarizing the changes, and a trimmed Tasks list reflecting only the relevant test addition.
Title Check ✅ Passed The title clearly and concisely summarizes the primary change by describing the new ability to return objects from Parse.Cloud.beforeFind and bypass the database query, directly reflecting the pull request’s main feature and objectives.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🧹 Nitpick comments (1)
src/rest.js (1)

53-54: Replace French comments with English for consistency.

The codebase should maintain consistent language usage throughout.

-    // Déclencher le trigger afterFind si des objets sont retournés
+    // Trigger afterFind if objects are returned
-  // Conserver la distinction entre get et find
+  // Maintain the distinction between get and find

Also applies to: 69-69

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 40bad26 and 8de0edb.

📒 Files selected for processing (3)
  • spec/CloudCode.spec.js (1 hunks)
  • src/rest.js (2 hunks)
  • src/triggers.js (2 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
spec/CloudCode.spec.js (1)
spec/CloudCode.Validator.spec.js (16)
  • Parse (2-2)
  • obj (657-657)
  • obj (674-674)
  • obj (691-691)
  • obj (713-713)
  • obj (782-782)
  • obj (806-806)
  • obj (835-835)
  • obj (851-851)
  • obj (983-983)
  • obj (1148-1148)
  • obj (1169-1169)
  • obj (1181-1181)
  • obj (1206-1206)
  • obj (1229-1229)
  • obj (1247-1247)
🔇 Additional comments (7)
spec/CloudCode.spec.js (3)

204-216: LGTM: Well-structured test for beforeFind short-circuit functionality.

This test correctly validates that beforeFind can return a single object directly, bypassing the database query. The test properly:

  • Sets up both beforeFind and afterFind triggers
  • Validates the object properties and class name
  • Confirms the returned object can be saved

218-230: LGTM: Good test for array return from beforeFind.

This test correctly validates that beforeFind can return an array of objects. The logic is sound and follows the same pattern as the previous test.


246-257: LGTM: Proper test for empty array return.

This test correctly validates that returning an empty array from beforeFind results in no objects being found, even when objects exist in the database.

src/triggers.js (1)

475-477: LGTM! Good optimization to avoid unnecessary conversions.

This change efficiently prevents redundant JSON-to-Parse.Object conversions when the object is already a Parse.Object instance, improving performance for the short-circuit functionality.

src/rest.js (3)

26-82: Excellent refactoring! The centralized trigger handling improves maintainability.

The runFindTriggers function effectively centralizes the beforeFind/afterFind trigger logic and correctly implements the short-circuit functionality. The logic properly:

  1. Runs the beforeFind trigger first
  2. Checks for returned objects to enable short-circuiting
  3. Runs afterFind when objects are present
  4. Falls back to normal query execution when no objects are returned

The distinction between get and find operations is preserved through the isGet parameter.


85-97: Clean refactoring maintains existing functionality.

Both find and get functions are properly refactored to use the new runFindTriggers helper while preserving their original behavior through appropriate parameter passing.

Also applies to: 100-112


65-65:

✅ Verification successful

Verify _toFullJSON() compatibility with Parse.Object instances.

Ensure that calling _toFullJSON() on Parse.Object instances returned from triggers works correctly and produces the expected serialization format.


🏁 Script executed:

#!/bin/bash
# Description: Search for _toFullJSON usage and Parse.Object implementations to verify compatibility

# Search for _toFullJSON method usage across the codebase
rg -A 3 -B 3 "_toFullJSON"

# Search for Parse.Object related implementations
ast-grep --pattern 'Parse.Object.fromJSON($_)'

Length of output: 5795


🏁 Script executed:

#!/bin/bash
# Print the first 200 lines of src/rest.js to inspect the find handler
sed -n '1,200p' src/rest.js

Length of output: 5761


🏁 Script executed:

#!/bin/bash
sed -n '450,550p' src/triggers.js
echo "----"
sed -n '900,1050p' src/triggers.js

Length of output: 7099


_toFullJSON() Compatibility Confirmed
I’ve verified that any objects returned by triggers are always instances of Parse.Object—triggers wrap plain JSON via Parse.Object.fromJSON—and that parse.Object provides a _toFullJSON() method. Existing tests (e.g. ParseCloudCodePublisher.spec.js) already cover this serialization. No changes required.

@parseplatformorg
Copy link
Contributor

parseplatformorg commented May 27, 2025

Snyk checks have passed. No issues have been found so far.

Status Scanner Critical High Medium Low Total (0)
Open Source Security 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

coderabbitai[bot]
coderabbitai bot previously approved these changes May 30, 2025
@mtrezza
Copy link
Member

mtrezza commented May 30, 2025

Started CI...

coderabbitai[bot]
coderabbitai bot previously approved these changes Jun 2, 2025
@EmpiDev
Copy link
Contributor Author

EmpiDev commented Jun 6, 2025

Hi @mtrezza, just wondering if there's anything else I should do to trigger a re-run of the tests?

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (3)
src/rest.js (3)

66-69: Id-less objects short-circuit path: clarify/guard protectedFields

Comment says ACL doesn’t apply to unsaved objects, but returning them non-master also bypasses protectedFields sanitization. Either explicitly drop id-less objects for non-master or document that cloud code must sanitize them.

If you choose to guard, minimally:

-      // Objects without IDs are(normally) unsaved objects
-      // For unsaved objects, the ACL security does not apply, so no need to redo the query.
-      // For saved objects, we need to re-query to ensure proper ACL/CLP enforcement
+      // Objects without IDs are (normally) unsaved. ACL checks don’t apply,
+      // but protectedFields may; returning them non-master may leak fields.
+      // Consider sanitizing here or dropping id-less objects for non-master.

98-101: Fix crash: spreading undefined and missing where in withJSON

...restOptions throws when restOptions is undefined; also where may be undefined. Default both.

Apply:

-      new Parse.Query(className).withJSON({ where: restWhere, ...restOptions }),
+      new Parse.Query(className).withJSON({ where: restWhere || {}, ...(restOptions || {}) }),

58-106: afterFind must always receive and return arrays; enforce isGet single-object; honor count

Single-object short-circuit can pass a non-array to afterFind and return a non-array. Also, isGet can leak multiple objects and count is ignored.

Apply:

-    let objectsForAfterFind = objectsFromBeforeFind;
+    // Normalize to array for consistent semantics
+    const inputArray = Array.isArray(objectsFromBeforeFind)
+      ? objectsFromBeforeFind
+      : [objectsFromBeforeFind];
+    let objectsForAfterFind = inputArray;
@@
-      const ids = (Array.isArray(objectsFromBeforeFind) ? objectsFromBeforeFind : [objectsFromBeforeFind])
-        .map(o => (o && (o.id || o.objectId)) || null)
-        .filter(Boolean);
+      const ids = inputArray
+        .map(o => (o && (o.id || o.objectId)) || null)
+        .filter(Boolean);
@@
-        const refiltered = await refilterQuery.execute();
-        objectsForAfterFind = (refiltered && refiltered.results) || [];
+        const refiltered = await refilterQuery.execute();
+        objectsForAfterFind = (refiltered && refiltered.results) || [];
       }
     }
 
+    // isGet must not return more than one object
+    if (isGet && objectsForAfterFind.length > 1) {
+      objectsForAfterFind = objectsForAfterFind.slice(0, 1);
+    }
@@
-    return {
-      results: afterFindProcessedObjects,
-    };
+    const resultsArray = Array.isArray(afterFindProcessedObjects)
+      ? afterFindProcessedObjects
+      : [afterFindProcessedObjects];
+    const response = { results: resultsArray };
+    if (restOptions && restOptions.count) {
+      response.count = resultsArray.length;
+    }
+    return response;
🧹 Nitpick comments (1)
src/rest.js (1)

72-84: Preserve external ranking; don’t pass order/skip/limit to refilter; re-apply pagination after sanitization

Re-applying restOptions to the refilter query can change ordering/pagination relative to objects returned by beforeFind (e.g., ES ranking).

Apply:

-        const refilterQuery = await RestQuery({
+        const { order, skip, limit, ...refilterOptions } = (restOptions || {});
+        const refilterQuery = await RestQuery({
           method: isGet ? RestQuery.Method.get : RestQuery.Method.find,
           config,
           auth,
           className,
           restWhere: refilterWhere,
-          restOptions,
+          // Drop order/skip/limit during refilter; apply after sanitization
+          restOptions: refilterOptions,
           clientSDK,
           context,
           runBeforeFind: false,
           runAfterFind: false,
         });
@@
-        const refiltered = await refilterQuery.execute();
-        objectsForAfterFind = (refiltered && refiltered.results) || [];
+        const refiltered = await refilterQuery.execute();
+        const sanitized = (refiltered && refiltered.results) || [];
+        const byId = new Map(sanitized.map(o => [(o.objectId || o.id), o]));
+        objectsForAfterFind = ids.map(id => byId.get(id)).filter(Boolean);
+        if (typeof skip === 'number' || typeof limit === 'number') {
+          const s = skip || 0;
+          const l = typeof limit === 'number' ? limit : objectsForAfterFind.length;
+          objectsForAfterFind = objectsForAfterFind.slice(s, s + l);
+        }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f5acfa0 and fdd9270.

📒 Files selected for processing (1)
  • src/rest.js (1 hunks)
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: EmpiDev
PR: parse-community/parse-server#9770
File: src/triggers.js:467-477
Timestamp: 2025-08-27T12:33:06.237Z
Learning: In the Parse Server codebase, maybeRunAfterFindTrigger is called in production with Parse.Query objects constructed via withJSON(), so the plain object query handling bug only affects tests, not production code paths.
📚 Learning: 2025-08-26T14:06:31.853Z
Learnt from: EmpiDev
PR: parse-community/parse-server#9770
File: spec/CloudCode.spec.js:446-469
Timestamp: 2025-08-26T14:06:31.853Z
Learning: In the Parse Server codebase, when handling query objects in maybeRunAfterFindTrigger, objects without a where property that contain options like limit/skip should be treated as query JSON with an empty where clause using the spread pattern { where: {}, ...query }, not nested as { where: query }.

Applied to files:

  • src/rest.js
📚 Learning: 2025-08-27T12:33:06.237Z
Learnt from: EmpiDev
PR: parse-community/parse-server#9770
File: src/triggers.js:467-477
Timestamp: 2025-08-27T12:33:06.237Z
Learning: In the Parse Server codebase, maybeRunAfterFindTrigger is called in production with Parse.Query objects constructed via withJSON(), so the plain object query handling bug only affects tests, not production code paths.

Applied to files:

  • src/rest.js
🧬 Code graph analysis (1)
src/rest.js (1)
src/RestQuery.js (6)
  • className (967-967)
  • result (55-66)
  • triggers (6-6)
  • isGet (53-53)
  • query (328-337)
  • query (338-338)
🔇 Additional comments (2)
src/rest.js (2)

124-136: find wrapper centralization looks good

Role enforcement first, then delegated to runFindTriggers({ isGet: false }). Clean.


141-151: get wrapper centralization looks good

Role enforcement and isGet: true propagation are correct.

coderabbitai[bot]
coderabbitai bot previously approved these changes Sep 15, 2025
Copy link
Member

@Moumouls Moumouls left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@EmpiDev EmpiDev requested a review from mtrezza September 19, 2025 14:03
@mtrezza
Copy link
Member

mtrezza commented Sep 19, 2025

Started CI

@Moumouls
Copy link
Member

everything seems okay here @mtrezza :)

@mtrezza
Copy link
Member

mtrezza commented Sep 21, 2025

Merged alpha branch to run CI again;

@EmpiDev could you please resolve the lint issues?
@Moumouls could you please resolve any open comments - there are some hidden in the thread.

@Moumouls
Copy link
Member

@mtrezza i don't see some unresolved comments, or i can't resolve them because file are outdated or i approved the PR already

@EmpiDev
Copy link
Contributor Author

EmpiDev commented Sep 22, 2025

@mtrezza I have resolved the lint issues.

Copy link
Member

@mtrezza mtrezza left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Moumouls I have found these open comments:

#9770 (comment)

#9770 (comment)

#9770 (comment)

If you cannot resolve them because the button doesn't work, could you just confirm that they're resolved, so we can merge?

@Moumouls
Copy link
Member

thanks @mtrezza , i reviewed, there is still one open comment: #9770 (comment)

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
src/triggers.js (1)

467-477: Optional: Improve query handling for plain objects without where.

When a plain object without a where property (e.g., { limit: 5, skip: 0 }) is passed, the current code creates an empty Parse.Query without calling withJSON, which silently drops query options like limit and skip.

Based on learnings, this issue only affects test scenarios since production code always passes Parse.Query instances constructed via withJSON(). However, for completeness and to avoid confusion when writing tests, consider applying the spread pattern:

 } else if (typeof query === 'object' && query !== null) {
   const parseQueryInstance = new Parse.Query(classNameQuery);
-  if (query.where) {
-    parseQueryInstance.withJSON(query);
-  }
+  const json = query.where ? query : { where: {}, ...query };
+  parseQueryInstance.withJSON(json);
   request.query = parseQueryInstance;

This ensures that top-level options are preserved when where is absent.

Based on learnings.

spec/CloudCode.spec.js (1)

474-502: Test name doesn't match implementation.

The test is named "should handle plain object query without where clause" but actually passes a Parse.Query instance created with withJSON({ limit: 5, skip: 1 }):

const pq = new Parse.Query(className).withJSON({ limit: 5, skip: 1 });

This tests the query instanceof Parse.Query branch (line 467 in triggers.js), not the plain object branch. Consider either:

  1. Renaming the test to "should handle Parse.Query created with withJSON without explicit where"
  2. Changing the test to pass a plain object: { limit: 5, skip: 1 } (though this would expose the issue mentioned in the optional refactor for triggers.js)
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fdd9270 and 852f29f.

📒 Files selected for processing (3)
  • spec/CloudCode.spec.js (1 hunks)
  • src/rest.js (1 hunks)
  • src/triggers.js (5 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/rest.js
🧰 Additional context used
🧠 Learnings (4)
📚 Learning: 2025-08-27T12:33:06.237Z
Learnt from: EmpiDev
PR: parse-community/parse-server#9770
File: src/triggers.js:467-477
Timestamp: 2025-08-27T12:33:06.237Z
Learning: In the Parse Server codebase, maybeRunAfterFindTrigger is called in production with Parse.Query objects constructed via withJSON(), so the plain object query handling bug only affects tests, not production code paths.

Applied to files:

  • spec/CloudCode.spec.js
  • src/triggers.js
📚 Learning: 2025-08-26T14:06:31.853Z
Learnt from: EmpiDev
PR: parse-community/parse-server#9770
File: spec/CloudCode.spec.js:446-469
Timestamp: 2025-08-26T14:06:31.853Z
Learning: In the Parse Server codebase, when handling query objects in maybeRunAfterFindTrigger, objects without a where property that contain options like limit/skip should be treated as query JSON with an empty where clause using the spread pattern { where: {}, ...query }, not nested as { where: query }.

Applied to files:

  • spec/CloudCode.spec.js
  • src/triggers.js
📚 Learning: 2025-04-30T19:31:35.344Z
Learnt from: RahulLanjewar93
PR: parse-community/parse-server#9744
File: spec/ParseLiveQuery.spec.js:0-0
Timestamp: 2025-04-30T19:31:35.344Z
Learning: In the Parse Server codebase, the functions in QueryTools.js are typically tested through end-to-end behavior tests rather than direct unit tests, even though the functions are exported from the module.

Applied to files:

  • spec/CloudCode.spec.js
📚 Learning: 2025-08-27T09:08:34.252Z
Learnt from: EmpiDev
PR: parse-community/parse-server#9770
File: src/triggers.js:446-454
Timestamp: 2025-08-27T09:08:34.252Z
Learning: When analyzing function signature changes in Parse Server codebase, verify that call sites are actually incorrect before flagging them. Passing tests are a strong indicator that function calls are already properly aligned with new signatures.

Applied to files:

  • src/triggers.js
🧬 Code graph analysis (2)
spec/CloudCode.spec.js (3)
src/Config.js (1)
  • Config (35-768)
spec/helper.js (3)
  • databaseAdapter (56-56)
  • Parse (4-4)
  • reconfigureServer (171-205)
src/triggers.js (3)
  • result (1048-1048)
  • result (1086-1086)
  • maybeRunAfterFindTrigger (445-536)
src/triggers.js (2)
src/RestQuery.js (3)
  • className (967-967)
  • isGet (53-53)
  • result (55-66)
src/rest.js (2)
  • query (109-119)
  • result (39-48)
🔇 Additional comments (9)
src/triggers.js (5)

185-190: LGTM!

The change correctly preserves the original object's className when no override is provided, maintaining backward compatibility while fixing cases where className might be lost during JSON conversion.


263-277: LGTM!

The addition of the isGet parameter is straightforward and correctly propagates the flag into the request object when defined.


456-463: LGTM!

The no-trigger case correctly handles the conversion of Parse.Objects to JSON and returns an empty array for null/undefined inputs.


500-525: LGTM!

The object conversion logic correctly:

  • Preserves existing Parse.Object instances
  • Converts plain objects to Parse.Object, maintaining their original className
  • Executes the trigger with proper validator and skipWithMasterKey handling

642-654: LGTM!

The result normalization correctly:

  • Wraps single Parse.Object in an array
  • Validates that all array elements are Parse.Objects using every() (correctly updated from past feedback)
  • Returns the objects array as part of the response
spec/CloudCode.spec.js (4)

205-282: LGTM!

The test suite comprehensively verifies the beforeFind short-circuit behavior:

  • Properly uses spies to confirm no database operations occur
  • Tests single object, array of objects, get query, and empty array scenarios
  • Verifies afterFind receives the correct objects
  • Confirms that returned unsaved objects can be saved afterward

284-375: LGTM! Critical security coverage.

This test suite ensures that ACL filtering is properly applied to objects returned from beforeFind triggers:

  • Verifies unauthorized users cannot access ACL-protected objects even when beforeFind returns them
  • Confirms get() throws OBJECT_NOT_FOUND for unauthorized users
  • Tests master key bypass behavior
  • Validates that protectedFields masking is applied after ACL re-filtering

This security coverage is essential for preventing data leaks when using the beforeFind short-circuit feature.


378-447: LGTM!

The tests properly verify maybeRunAfterFindTrigger behavior for:

  • Converting Parse.Object instances to JSON when no trigger is defined
  • Handling null/undefined/empty array inputs gracefully

504-543: LGTM!

The tests correctly verify that maybeRunAfterFindTrigger creates a default Parse.Query for invalid query parameters (strings and null).

@mtrezza
Copy link
Member

mtrezza commented Oct 14, 2025

Waiting for CI...

@mtrezza mtrezza changed the title feat: Allow short circuit of beforeFind feat: Allow returning response in Parse.Cloud.beforeFind without invoking query Oct 14, 2025
@mtrezza mtrezza changed the title feat: Allow returning response in Parse.Cloud.beforeFind without invoking query feat: Allow returning objects in Parse.Cloud.beforeFind without invoking database query Oct 14, 2025
@mtrezza mtrezza merged commit 0b47407 into parse-community:alpha Oct 14, 2025
24 of 26 checks passed
parseplatformorg pushed a commit that referenced this pull request Oct 14, 2025
# [8.3.0-alpha.5](8.3.0-alpha.4...8.3.0-alpha.5) (2025-10-14)

### Features

* Allow returning objects in `Parse.Cloud.beforeFind` without invoking database query ([#9770](#9770)) ([0b47407](0b47407))
@parseplatformorg
Copy link
Contributor

🎉 This change has been released in version 8.3.0-alpha.5

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

state:released-alpha Released as alpha version

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Allow beforeFind to be short circuited

6 participants