You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Make MCPRackApp return per-response header hashes (json_headers / sse_headers) instead of the frozen JSON_CONTENT_TYPE / SSE_HEADERS constants to avoid FrozenError when Rack middleware decorates response headers; add helpers and tests for header mutability. Harden parse_reference precompute: suppress autofetch during the before_create precompute callback to avoid ObjectNotFound, and gate client-generated objectId forwarding so precompute only runs with master-key authority (skip when a per-save session token is present or client.master_key is absent). Add YARD notes documenting Auth0 correlation_id normalization and server requirements/threat model for precompute, enable allowCustomObjectId in test docker/config/scripts to cover the precompute path, add tests for precompute behaviors, and bump version to 4.1.2 (Gemfile.lock, version file, changelog updated).
Copy file name to clipboardExpand all lines: CHANGELOG.md
+21Lines changed: 21 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,5 +1,26 @@
1
1
## Parse-Stack Changelog
2
2
3
+
### 4.1.2
4
+
5
+
#### Bug Fixes
6
+
7
+
-**FIXED**: `Parse::Agent::MCPRackApp` no longer returns the frozen `JSON_CONTENT_TYPE` / `SSE_HEADERS` module-level constants as the response headers hash. Every response now receives a fresh `.dup` of the template via new private `json_headers` / `sse_headers` helpers, so downstream Rack middleware that decorates response headers — Sinatra's `xss_header`, `json_csrf`, and `common_logger`, as well as `rack-deflater` and similar — can mutate the hash without raising `FrozenError`, and cross-request mutation cannot leak through the shared singleton. The constants remain as frozen templates and are still publicly readable; existing callers that read them directly are unaffected. (`lib/parse/agent/mcp_rack_app.rb`)
8
+
- **FIXED**: The built-in `export_data` tool definition's `columns:` parameter declared `type: "array"` without an `items` schema, which caused OpenAI's function-calling endpoint to reject every request that included the agent's tool list with `invalid_function_parameters`: "array schema missing items." Because OpenAI validates the entire tool list at request time, the broken schema fired even when the LLM never invoked `export_data`, effectively disabling the agent. The `columns:` items schema is now declared as a `oneOf` between a plain string (used as both field path and header) and a single-entry `{field => header}` object (used to rename a column), matching what `normalize_export_columns` already accepts at runtime. A new regression test (`test/lib/parse/agent/tools_schema_validity_test.rb`) walks every `TOOL_DEFINITIONS` entry and asserts that every array property at every nesting depth carries an `items` schema, so this bug class cannot recur silently in another tool's definition. (`lib/parse/agent/tools.rb`)
9
+
-**FIXED**: `parse_reference precompute: true` no longer aborts the create POST with `Parse::Error::ObjectNotFound` (code 101). The `before_create _precompute_<field>!` callback used to call `public_send(field_name)` to compare the current value against the canonical target; that read went through the property accessor, which observed `value.nil?` and `pointer?` (objectId just client-assigned, timestamps still blank) and fired an autofetch GET against an id Parse Server had not seen yet. The callback now suppresses autofetch for the duration of the write by toggling `disable_autofetch!` / `enable_autofetch!` around the comparison and assignment, restoring the prior autofetch state on exit. The eventual create POST is unaffected — it still includes both `objectId` and the canonical `parseReference` in a single round-trip. (`lib/parse/model/core/parse_reference.rb`)
10
+
11
+
#### Hardening
12
+
13
+
- **FIXED**: `parse_reference precompute: true` now refuses to forward a client-supplied `objectId` unless the save runs with master-key authority. The `_precompute_<field>!` callback short-circuits when an explicit per-save session token is set (`with_session` / `set_session_token`) or when no `master_key` is configured on `Parse::Client`; in those cases the legacy after-create `_assign_<field>!` flow takes over, costing one extra round-trip but staying within the requesting session's permissions and yielding a reference derived from the server-assigned id. Previously the callback would client-generate an objectId regardless of auth context, which on a server with `allowCustomObjectId: true` allowed objectId-squatting from any session whose ACL permitted creates on the class. The SDK gate protects parse-stack callers; for cross-SDK enforcement, the inline documentation on `parse_reference precompute:` shows a `beforeSave` cloud-code hook that rejects client-supplied objectIds from non-master sessions. (`lib/parse/model/core/parse_reference.rb`)
14
+
15
+
#### Testing Infrastructure
16
+
17
+
- The Dockerized test Parse Server now starts with `allowCustomObjectId: true` (`PARSE_SERVER_ALLOW_CUSTOM_OBJECT_ID=true`), enabling integration coverage for the `parse_reference precompute: true` path. The flag is scoped to the test rig — `config/parse-config.json` for the docker-compose mount and `scripts/start-parse.sh` for the standalone helper — and does not affect any consumer's production configuration. (`config/parse-config.json`, `scripts/docker/docker-compose.test.yml`, `scripts/start-parse.sh`, `test/lib/parse/parse_reference_integration_test.rb`, `test/lib/parse/parse_reference_test.rb`)
18
+
19
+
#### Documentation
20
+
21
+
- Added a `@note` on `Parse::Agent#correlation_id` clarifying that the safe-character regex (`[A-Za-z0-9._-]`) intentionally rejects the `|` character used in Auth0 `sub` values (e.g. `auth0|abc123`) as log-injection hardening. Integrators threading an Auth0 sub through as the correlation id should normalize it before assignment with `sub.gsub(/[^A-Za-z0-9._-]/, "_")`, which handles every disallowed character in one pass (necessary for federated provider subs that can also contain `:` or `/`). The note also calls out that many-to-one normalization can collide distinct subs onto the same correlation id, which is acceptable for log threading — the only intended use — but means the value must not be reused as a cache key, rate-limit bucket, or identity token. (`lib/parse/agent.rb`)
22
+
- Expanded the YARD doc-block on `parse_reference precompute:` with a new "Server requirements and threat model" section describing the `allowCustomObjectId` server flag, the SDK-side master-key gate, the cross-SDK objectId-squatting risk that remains when `allowCustomObjectId` is on, and the recommended `beforeSave` cloud-code hook for non-master enforcement across all client SDKs. (`lib/parse/model/core/parse_reference.rb`)
0 commit comments