Skip to content

v5.3.0 - Run as the calling user, plural aliases, pointer fixes#14

Merged
AdrianCurtin merged 2 commits into
mainfrom
dev
Jun 5, 2026
Merged

v5.3.0 - Run as the calling user, plural aliases, pointer fixes#14
AdrianCurtin merged 2 commits into
mainfrom
dev

Conversation

@AdrianCurtin
Copy link
Copy Markdown
Contributor

@AdrianCurtin AdrianCurtin commented Jun 5, 2026

v5.3.0

Three things this release: webhook handlers and clients can run as the calling
user
, plural model-constant aliases, and property … as: pointer associations
now serialize correctly (breaking for one narrow case).

Breaking Changes

  • BREAKING: a field declared with property … as: now serializes as a
    Pointer ({__type: "Pointer", …}) instead of a String. Previously as: was a
    silent no-op and the field defaulted to :string. If a deployed app used
    property … as: and saved records, Parse Server pinned that column as
    String, and a Pointer write is now rejected with error 111 (schema type
    mismatch) — drop or migrate that column to a Pointer type before deploying.
    Apps that never used property … as: are unaffected.

Run webhook handlers (and clients) as the calling user

Parse Server includes the caller's live session token in every trigger/function
webhook fired by a logged-in user. A handler — or any client-side caller — can
opt into acting on the server as that user, with full ACL / CLP /
protectedFields enforcement, instead of the application master key.

  • NEW: Parse::Webhooks::Payload#session_token / #session_token? — the
    caller's token, captured before credential scrubbing; nil for master-key
    requests; never present in as_json, inspect, or the request log.
  • NEW: Parse::Webhooks::Payload#user_agent — a non-master, client-mode
    Parse::Agent scoped to the caller (ACL/CLP enforced).
  • NEW: Parse::Webhooks::Payload#user_client — a non-master Parse::Client
    with the caller's token bound, so even raw REST calls authorize as the user.
  • NEW: Parse::Client.new(session_token:) binds a token to a client,
    applied as the lowest-priority auth fallback (explicit per-call
    session_token:, Parse.with_session, and use_master_key: true all win).
  • NEW: Parse::Client#become(session_token) derives a non-master client
    mirroring the receiver's connection; Parse::Client#anonymous derives the
    same with no token (unauthenticated REST).
  • NEW: Parse::User#session_client — a user-scoped client straight from a
    logged-in user (Parse::User.login(u, p).session_client).
  • NEW: Parse::Client#with_session { ... } runs a block with the client's
    bound token as the ambient session, scoping REST-routed operations
    (find/get/count/save) as the user (the client-receiver flavor of
    Parse.with_session / Parse::User#with_session). Mongo-direct queries stay
    explicitly scoped.
  • NEW: rake client:console opens an interactive console whose default
    client is bound to a user (session token, login, or anonymous), so every query
    runs with that user's ACL/CLP rather than the master key.
  • FIXED: Parse::Client#inspect and Parse::Webhooks::Payload#inspect
    redact the master key and session token (and the payload's pre-scrub raw
    credentials) instead of printing them in cleartext.
  • FIXED: an explicit master_key: nil no longer re-inherits the process
    master key from the environment, and a whitespace-only session_token: is
    treated as no token — so a client built for user scoping stays non-master.

Pluralized class-name aliases

  • NEW: referencing the plural of a model constant resolves to that class, so
    the plural reads as a query entry point — Posts.where(...).count works for a
    class Post. The alias is lazy and the same class object as the singular
    (Posts.equal?(Post)), so it adds no descendants entry and registers no
    separate Parse schema class.
  • NEW: pluralized_alias! macro for an explicit/custom plural (or a
    namespaced model), and Parse.pluralized_aliases configuration (default on;
    opt out with Parse.pluralized_aliases = false / PARSE_PLURALIZED_ALIASES=false).

Pointer associations declared with property … as:

  • FIXED: property <name>, as: <class> and property <name>, :pointer now
    declare a pointer association identical to the equivalent belongs_to — same
    field type, remote column, target-class reference, dirty tracking, and
    {__type: "Pointer", …} wire form (see Breaking Changes above).
  • NEW: belongs_to / property … as: raise ArgumentError at declaration
    when as: names a scalar type such as as: :string.
  • NEW: Parse.validate_associations! verifies every belongs_to /
    property … as: pointer target and has_many … through: :relation target
    resolves to a known Parse class, for a once-after-load (boot/CI) check.
  • IMPROVED: belongs_to (and property … as:) now retain _description: /
    _enum: agent metadata that previously only property kept.

Introduce run_test_files! helper that runs each test file in its own Ruby process, prints PASS/FAIL + duration per file, and appends progress to a tail-able log. Add environment knobs: TEST_PATTERN to filter files and CONTINUE_ON_FAILURE to stop on first failure. Wire this helper into test:integration and test:unit (replacing their inline loops), create per-suite logs under tmp/, and ensure the task exits non-zero when any file fails. Task descriptions were updated to document the knobs.
Copilot AI review requested due to automatic review settings June 5, 2026 13:53
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR introduces first-class support for “run webhook handlers as the calling user” by capturing the caller’s live session token from Parse Server trigger payloads, exposing safe opt-in handles (user_client / user_agent), and locking in the non-leak/scrub invariants with both unit and Docker integration coverage.

Changes:

  • Add Parse::Webhooks::Payload#session_token, #session_token?, #user_client, and #user_agent, capturing user.sessionToken before credential scrubbing.
  • Add unit + end-to-end integration tests to ensure ACL/CLP enforcement under session-token scope and to prevent token leakage into handler-visible objects/serialization/log surfaces.
  • Improve test rake tasks with per-file process isolation, progress logging, and filtering knobs; bump version/docs/changelog to 5.2.2.

Reviewed changes

Copilot reviewed 8 out of 9 changed files in this pull request and generated no comments.

Show a summary per file
File Description
lib/parse/webhooks/payload.rb Captures and exposes caller session token safely; provides user-scoped client/agent helpers.
lib/parse/client.rb Adds session_token: option to bind a token to a client and apply it as lowest-priority auth fallback per request.
test/lib/parse/webhook_session_token_capture_test.rb Unit regression tests to ensure token capture works and token never leaks into payload serialization/objects.
test/lib/parse/webhook_session_token_as_user_integration_test.rb Docker integration tests proving scoped reads enforce ACL vs master contrast across route/DSL/MCP-style agent cases.
Rakefile Adds shared per-test-file runner with progress logs and filtering knobs; updates test:unit / test:integration tasks to use it.
docs/mcp_guide.md Documents webhook client-mode usage via captured session token (v5.2.2).
CHANGELOG.md Changelog entry describing the new webhook caller-scoped capability and client binding.
lib/parse/stack/version.rb Bumps gem version to 5.2.2.
Gemfile.lock Updates locked gem version to 5.2.2.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@AdrianCurtin AdrianCurtin changed the title Dev v5.3.0 - Run webhooks and clients as the calling user Jun 5, 2026
@AdrianCurtin AdrianCurtin requested a review from Copilot June 5, 2026 14:48
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 22 out of 23 changed files in this pull request and generated 3 comments.

Comment on lines +175 to +181
def self.extract_session_token(user_hash)
return nil unless user_hash.is_a?(Hash)
token = user_hash["sessionToken"] || user_hash[:sessionToken] ||
user_hash["session_token"] || user_hash[:session_token]
token = token.to_s
token.empty? ? nil : token
end
Comment thread lib/parse/client.rb
Comment on lines +409 to +412
def with_session(&block)
raise ArgumentError, "Parse::Client#with_session requires a client with a bound session_token" if @session_token.nil?
Parse.with_session(@session_token, &block)
end
Comment thread lib/parse/client.rb
Comment on lines 1131 to 1135
if token.nil? && !(explicit_master && opts[:use_master_key] == true)
ambient = Parse.current_session_token
token = ambient if ambient.is_a?(String) && !ambient.empty?
token = @session_token if (token.nil? || token.to_s.empty?) && @session_token
end
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 23 out of 24 changed files in this pull request and generated 1 comment.

Comment thread Rakefile Outdated
Comment on lines +38 to +42
# Resolve the identity for `rake client:console`. Returns a session-token String,
# or nil to mean "anonymous" (no token, no master). Order: PARSE_SESSION_TOKEN,
# PARSE_CLIENT_ANONYMOUS=true, PARSE_LOGIN_USER (+PARSE_LOGIN_PASSWORD), else
# prompt for login / token / anon. +client+ is the master client used to log in.
def client_console_token!(client)
@AdrianCurtin AdrianCurtin changed the title v5.3.0 - Run webhooks and clients as the calling user v5.3.0 - Run as the calling user, plural aliases, pointer fixes Jun 5, 2026
@AdrianCurtin AdrianCurtin force-pushed the dev branch 5 times, most recently from 063a307 to 92dab08 Compare June 5, 2026 17:13
Add support for binding a session token to clients and running operations as a user: Parse::Client gains a session_token option, become/anonymous helpers, with_session block scoping, and redacted inspect; request token resolution prefers ambient session, then bound token. Webhook payloads expose session_token, user_agent and user_client so handlers can opt in to acting as the calling user. Add Parse::User#session_client and client console (rake client:console) to open an IRB with a non-master user-scoped default client. Delegate pointer-style property declarations to belongs_to and enforce declaration-time guards: reject scalar `as:` usages, surface pointer metadata, and honor strict_property_redefinition to avoid silent type changes. Introduce pluralized class-name aliases (automatic const_missing hook + pluralized_alias! macro) so plurals like Posts resolve to Post. Update docs, changelog and add tests/snapshots covering associations, webhooks, pluralized aliases and property pointer behavior.
@AdrianCurtin AdrianCurtin merged commit d803262 into main Jun 5, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants