parse-stack-next 5.5.4 → 5.5.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +8 -6
- data/README.md +26 -13
- data/bin/parse-console +9 -1
- data/docs/TEST_SERVER.md +115 -238
- data/docs/mcp_guide.md +1 -1
- data/docs/mongodb_index_optimization_guide.md +3 -2
- data/docs/usage_guide.md +1 -1
- data/docs/yard-template/default/fulldoc/html/css/common.css +52 -9
- data/docs/yard-template/default/fulldoc/html/css/full_list.css +40 -13
- data/lib/parse/agent/constraint_translator.rb +18 -18
- data/lib/parse/agent/errors.rb +29 -7
- data/lib/parse/agent/metadata_dsl.rb +6 -6
- data/lib/parse/agent/tools.rb +250 -59
- data/lib/parse/agent.rb +42 -30
- data/lib/parse/api/aggregate.rb +3 -3
- data/lib/parse/api/cloud_functions.rb +19 -10
- data/lib/parse/api/objects.rb +8 -8
- data/lib/parse/api/users.rb +9 -9
- data/lib/parse/atlas_search/session.rb +34 -34
- data/lib/parse/atlas_search.rb +243 -110
- data/lib/parse/client/body_builder.rb +10 -10
- data/lib/parse/client/logging.rb +5 -2
- data/lib/parse/client/profiling.rb +5 -2
- data/lib/parse/client/protocol.rb +1 -1
- data/lib/parse/client/url_redaction.rb +94 -0
- data/lib/parse/client.rb +43 -28
- data/lib/parse/embeddings/image_fetch.rb +6 -1
- data/lib/parse/embeddings/voyage.rb +16 -17
- data/lib/parse/live_query/client.rb +7 -7
- data/lib/parse/live_query/subscription.rb +1 -1
- data/lib/parse/lock.rb +1 -1
- data/lib/parse/lock_backend.rb +118 -2
- data/lib/parse/model/acl.rb +24 -24
- data/lib/parse/model/classes/job_schedule.rb +8 -8
- data/lib/parse/model/classes/job_status.rb +9 -9
- data/lib/parse/model/classes/role.rb +49 -49
- data/lib/parse/model/classes/session.rb +2 -2
- data/lib/parse/model/classes/user.rb +66 -66
- data/lib/parse/model/core/builder.rb +7 -7
- data/lib/parse/model/core/create_lock.rb +1 -1
- data/lib/parse/model/core/properties.rb +4 -4
- data/lib/parse/model/file.rb +57 -16
- data/lib/parse/model/model.rb +19 -19
- data/lib/parse/model/object.rb +38 -38
- data/lib/parse/model/pointer.rb +4 -4
- data/lib/parse/model/push.rb +5 -5
- data/lib/parse/mongodb.rb +84 -26
- data/lib/parse/pipeline_security.rb +2 -2
- data/lib/parse/query/constraints.rb +38 -38
- data/lib/parse/query.rb +151 -75
- data/lib/parse/retrieval/reranker/cohere.rb +30 -0
- data/lib/parse/schema.rb +1 -1
- data/lib/parse/stack/version.rb +1 -1
- data/lib/parse/stack.rb +23 -10
- data/lib/parse/two_factor_auth/user_extension.rb +25 -25
- data/lib/parse/webhooks/payload.rb +35 -35
- data/lib/parse/webhooks/registration.rb +2 -2
- data/lib/parse/webhooks/replay_protection.rb +16 -16
- data/lib/parse/webhooks.rb +11 -11
- data/parse-stack-next.gemspec +19 -1
- metadata +2 -38
- data/.bundle/config +0 -5
- data/.env.sample +0 -138
- data/.env.test +0 -10
- data/.github/ISSUE_TEMPLATE/bug_report.yml +0 -105
- data/.github/ISSUE_TEMPLATE/feature_request.yml +0 -67
- data/.github/dependabot.yml +0 -13
- data/.github/workflows/codeql.yml +0 -44
- data/.github/workflows/docs.yml +0 -39
- data/.github/workflows/release.yml +0 -43
- data/.github/workflows/ruby.yml +0 -38
- data/.gitignore +0 -56
- data/.ruby-version +0 -1
- data/.solargraph.yml +0 -22
- data/.vscode/settings.json +0 -3
- data/.yardopts +0 -19
- data/Gemfile +0 -43
- data/Gemfile.lock +0 -198
- data/Makefile +0 -63
- data/Rakefile +0 -825
- data/config/parse-config.json +0 -12
- data/scripts/debug-ips.js +0 -35
- data/scripts/docker/Dockerfile.parse +0 -17
- data/scripts/docker/atlas-init.js +0 -284
- data/scripts/docker/docker-compose.atlas.yml +0 -80
- data/scripts/docker/docker-compose.test.yml +0 -159
- data/scripts/docker/docker-compose.verifyemail.yml +0 -4
- data/scripts/docker/mongo-init.js +0 -21
- data/scripts/docker/preflight.sh +0 -76
- data/scripts/eval_mcp_with_lm_studio.rb +0 -274
- data/scripts/start-parse.sh +0 -154
- data/scripts/start_mcp_server.rb +0 -78
- data/scripts/test_server_connection.rb +0 -82
- data/scripts/vector_prototype/create_vector_index.js +0 -105
- data/scripts/vector_prototype/fetch_embeddings.py +0 -241
- data/scripts/vector_prototype/fixture_manifest.json +0 -9
- data/scripts/vector_prototype/query_prototype.rb +0 -84
- data/scripts/vector_prototype/run.sh +0 -34
data/scripts/docker/preflight.sh
DELETED
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
#!/bin/sh
|
|
2
|
-
# Preflight guard for the integration stack — TEST STACK ONLY.
|
|
3
|
-
#
|
|
4
|
-
# The Compose defaults bind every service to loopback (127.0.0.1) and fall
|
|
5
|
-
# back to KNOWN, COMMITTED test credentials (master key psnextItMasterKey,
|
|
6
|
-
# Mongo root admin:password, Dashboard admin:admin). That combination is
|
|
7
|
-
# safe on loopback — nothing on the LAN can reach it.
|
|
8
|
-
#
|
|
9
|
-
# It is NOT safe the moment a developer overrides a `*_BIND` to a
|
|
10
|
-
# non-loopback address (e.g. MONGO_BIND=0.0.0.0 to attach a remote client):
|
|
11
|
-
# the stack is then reachable from the LAN while protected only by
|
|
12
|
-
# credentials that are published in this very repository. An admin-
|
|
13
|
-
# credentialed Mongo / Parse master key exposed to a shared network is a
|
|
14
|
-
# real footgun, and the failure is silent — `docker compose up` just works
|
|
15
|
-
# and the developer never sees it.
|
|
16
|
-
#
|
|
17
|
-
# This guard runs first (every other service gates on it via
|
|
18
|
-
# `service_completed_successfully`) and FAILS THE STACK CLOSED whenever a
|
|
19
|
-
# non-loopback bind is combined with still-default privileged credentials.
|
|
20
|
-
# It is invisible to the normal loopback run.
|
|
21
|
-
#
|
|
22
|
-
# Escape hatches (pick one):
|
|
23
|
-
# 1. Keep it loopback — unset the *_BIND override (the default).
|
|
24
|
-
# 2. Use real secrets — set PARSE_MASTER_KEY and MONGO_ROOT_PASSWORD
|
|
25
|
-
# (inject them with `op run` / `doppler run` —
|
|
26
|
-
# see the README "Secret injection" recipe).
|
|
27
|
-
# 3. Acknowledge the risk — ALLOW_INSECURE_BIND=1 on a trusted/isolated
|
|
28
|
-
# network where exposure is intentional.
|
|
29
|
-
|
|
30
|
-
set -eu
|
|
31
|
-
|
|
32
|
-
# Treat an empty value as loopback: the compose interpolation passes the
|
|
33
|
-
# resolved bind, and an unset override resolves to the 127.0.0.1 default.
|
|
34
|
-
is_loopback() {
|
|
35
|
-
case "$1" in
|
|
36
|
-
"" | 127.0.0.1 | ::1 | localhost) return 0 ;;
|
|
37
|
-
*) return 1 ;;
|
|
38
|
-
esac
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
exposed=""
|
|
42
|
-
for pair in "PARSE_BIND=${PARSE_BIND:-}" "MONGO_BIND=${MONGO_BIND:-}" \
|
|
43
|
-
"REDIS_BIND=${REDIS_BIND:-}" "DASHBOARD_BIND=${DASHBOARD_BIND:-}"; do
|
|
44
|
-
val=${pair#*=}
|
|
45
|
-
is_loopback "$val" || exposed="$exposed ${pair%%=*}=$val"
|
|
46
|
-
done
|
|
47
|
-
|
|
48
|
-
# Privileged credentials are "default" unless BOTH have been overridden.
|
|
49
|
-
# *_SET is "1" only when Compose interpolated a non-empty override
|
|
50
|
-
# (`${VAR:+1}`); empty means the committed default is in force.
|
|
51
|
-
if [ -n "${PARSE_MASTER_KEY_SET:-}" ] && [ -n "${MONGO_ROOT_PASSWORD_SET:-}" ]; then
|
|
52
|
-
default_creds=0
|
|
53
|
-
else
|
|
54
|
-
default_creds=1
|
|
55
|
-
fi
|
|
56
|
-
|
|
57
|
-
if [ -n "$exposed" ] && [ "$default_creds" = "1" ] && [ "${ALLOW_INSECURE_BIND:-}" != "1" ]; then
|
|
58
|
-
echo "[preflight] REFUSING TO START — non-loopback bind with default credentials." >&2
|
|
59
|
-
echo "[preflight]" >&2
|
|
60
|
-
echo "[preflight] Exposed (non-loopback) bind(s):$exposed" >&2
|
|
61
|
-
echo "[preflight] ...while still using the committed test credentials" >&2
|
|
62
|
-
echo "[preflight] (master key psnextItMasterKey / Mongo admin:password)." >&2
|
|
63
|
-
echo "[preflight] This publishes an admin-credentialed stack onto your LAN." >&2
|
|
64
|
-
echo "[preflight]" >&2
|
|
65
|
-
echo "[preflight] Resolve ONE of:" >&2
|
|
66
|
-
echo "[preflight] 1. Keep it loopback — unset the *_BIND override." >&2
|
|
67
|
-
echo "[preflight] 2. Set real secrets — PARSE_MASTER_KEY=... MONGO_ROOT_PASSWORD=..." >&2
|
|
68
|
-
echo "[preflight] 3. Acknowledge intent — ALLOW_INSECURE_BIND=1 (trusted network only)." >&2
|
|
69
|
-
exit 1
|
|
70
|
-
fi
|
|
71
|
-
|
|
72
|
-
if [ -n "$exposed" ]; then
|
|
73
|
-
echo "[preflight] OK — non-loopback bind(s)$exposed permitted (credentials overridden or ALLOW_INSECURE_BIND=1)."
|
|
74
|
-
else
|
|
75
|
-
echo "[preflight] OK — all services bound to loopback."
|
|
76
|
-
fi
|
|
@@ -1,274 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env ruby
|
|
2
|
-
# encoding: UTF-8
|
|
3
|
-
# frozen_string_literal: true
|
|
4
|
-
|
|
5
|
-
# Evaluate MCP Server with LM Studio
|
|
6
|
-
#
|
|
7
|
-
# This script connects LM Studio to the Parse MCP Server, allowing the
|
|
8
|
-
# LLM to query Parse data using the MCP tools.
|
|
9
|
-
#
|
|
10
|
-
# Usage:
|
|
11
|
-
# ruby scripts/eval_mcp_with_lm_studio.rb
|
|
12
|
-
#
|
|
13
|
-
# Prerequisites:
|
|
14
|
-
# - LM Studio running at http://127.0.0.1:1234
|
|
15
|
-
# - MCP Server running at http://localhost:3001
|
|
16
|
-
# - Parse Server running with test data
|
|
17
|
-
|
|
18
|
-
require "net/http"
|
|
19
|
-
require "json"
|
|
20
|
-
require "uri"
|
|
21
|
-
|
|
22
|
-
class MCPLMStudioEvaluator
|
|
23
|
-
LM_STUDIO_URL = ENV["LM_STUDIO_URL"] || "http://127.0.0.1:1234"
|
|
24
|
-
MCP_SERVER_URL = ENV["MCP_SERVER_URL"] || "http://localhost:3001"
|
|
25
|
-
|
|
26
|
-
def initialize
|
|
27
|
-
@conversation = []
|
|
28
|
-
@tool_definitions = nil
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
# Fetch tool definitions from MCP server
|
|
32
|
-
def fetch_tools
|
|
33
|
-
uri = URI("#{MCP_SERVER_URL}/tools")
|
|
34
|
-
response = Net::HTTP.get_response(uri)
|
|
35
|
-
|
|
36
|
-
unless response.is_a?(Net::HTTPSuccess)
|
|
37
|
-
raise "Failed to fetch tools: #{response.code} #{response.message}"
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
tools = JSON.parse(response.body)
|
|
41
|
-
|
|
42
|
-
# Convert MCP format to OpenAI function calling format
|
|
43
|
-
@tool_definitions = tools.map do |tool|
|
|
44
|
-
{
|
|
45
|
-
type: "function",
|
|
46
|
-
function: {
|
|
47
|
-
name: tool["name"],
|
|
48
|
-
description: tool["description"],
|
|
49
|
-
parameters: tool["inputSchema"]
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
puts "Loaded #{@tool_definitions.size} tools from MCP server"
|
|
55
|
-
@tool_definitions
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
# Call a tool via MCP server
|
|
59
|
-
def call_mcp_tool(tool_name, arguments)
|
|
60
|
-
uri = URI("#{MCP_SERVER_URL}/mcp")
|
|
61
|
-
http = Net::HTTP.new(uri.host, uri.port)
|
|
62
|
-
|
|
63
|
-
request = Net::HTTP::Post.new(uri.path)
|
|
64
|
-
request["Content-Type"] = "application/json"
|
|
65
|
-
request.body = JSON.generate({
|
|
66
|
-
jsonrpc: "2.0",
|
|
67
|
-
id: rand(10000),
|
|
68
|
-
method: "tools/call",
|
|
69
|
-
params: {
|
|
70
|
-
name: tool_name,
|
|
71
|
-
arguments: arguments
|
|
72
|
-
}
|
|
73
|
-
})
|
|
74
|
-
|
|
75
|
-
response = http.request(request)
|
|
76
|
-
result = JSON.parse(response.body)
|
|
77
|
-
|
|
78
|
-
if result["error"]
|
|
79
|
-
{ error: result["error"]["message"] }
|
|
80
|
-
else
|
|
81
|
-
result["result"]
|
|
82
|
-
end
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
# Send a message to LM Studio
|
|
86
|
-
def chat_with_lm(user_message, tools: true)
|
|
87
|
-
uri = URI("#{LM_STUDIO_URL}/v1/chat/completions")
|
|
88
|
-
http = Net::HTTP.new(uri.host, uri.port)
|
|
89
|
-
http.read_timeout = 300 # LLMs can be slow, especially larger models
|
|
90
|
-
http.open_timeout = 30
|
|
91
|
-
|
|
92
|
-
@conversation << { role: "user", content: user_message }
|
|
93
|
-
|
|
94
|
-
request_body = {
|
|
95
|
-
model: "qwen2.5-32b-instruct",
|
|
96
|
-
messages: @conversation,
|
|
97
|
-
temperature: 0.1,
|
|
98
|
-
max_tokens: 2000
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
# Add tools if available and requested
|
|
102
|
-
if tools && @tool_definitions
|
|
103
|
-
request_body[:tools] = @tool_definitions
|
|
104
|
-
request_body[:tool_choice] = "auto"
|
|
105
|
-
end
|
|
106
|
-
|
|
107
|
-
request = Net::HTTP::Post.new(uri.path)
|
|
108
|
-
request["Content-Type"] = "application/json"
|
|
109
|
-
request.body = JSON.generate(request_body)
|
|
110
|
-
|
|
111
|
-
puts "\n>>> Sending to LM Studio..."
|
|
112
|
-
response = http.request(request)
|
|
113
|
-
|
|
114
|
-
unless response.is_a?(Net::HTTPSuccess)
|
|
115
|
-
raise "LM Studio error: #{response.code} #{response.message}\n#{response.body}"
|
|
116
|
-
end
|
|
117
|
-
|
|
118
|
-
result = JSON.parse(response.body)
|
|
119
|
-
assistant_message = result["choices"][0]["message"]
|
|
120
|
-
|
|
121
|
-
@conversation << assistant_message
|
|
122
|
-
|
|
123
|
-
assistant_message
|
|
124
|
-
end
|
|
125
|
-
|
|
126
|
-
# Check if message has actual tool calls
|
|
127
|
-
def has_tool_calls?(message)
|
|
128
|
-
return false unless message
|
|
129
|
-
tool_calls = message["tool_calls"]
|
|
130
|
-
return false unless tool_calls.is_a?(Array) && !tool_calls.empty?
|
|
131
|
-
tool_calls.any? { |tc| tc["function"] && tc["function"]["name"] }
|
|
132
|
-
end
|
|
133
|
-
|
|
134
|
-
# Process tool calls from the LLM
|
|
135
|
-
def process_tool_calls(message)
|
|
136
|
-
tool_calls = message["tool_calls"]
|
|
137
|
-
return nil unless tool_calls && !tool_calls.empty?
|
|
138
|
-
|
|
139
|
-
tool_results = []
|
|
140
|
-
|
|
141
|
-
tool_calls.each do |tool_call|
|
|
142
|
-
function = tool_call["function"]
|
|
143
|
-
next unless function && function["name"]
|
|
144
|
-
|
|
145
|
-
tool_name = function["name"]
|
|
146
|
-
arguments = JSON.parse(function["arguments"] || "{}")
|
|
147
|
-
|
|
148
|
-
puts "\n🔧 LLM calling tool: #{tool_name}"
|
|
149
|
-
puts " Arguments: #{JSON.pretty_generate(arguments)}"
|
|
150
|
-
|
|
151
|
-
result = call_mcp_tool(tool_name, arguments)
|
|
152
|
-
|
|
153
|
-
puts " Result preview: #{result.to_s[0..200]}..."
|
|
154
|
-
|
|
155
|
-
tool_results << {
|
|
156
|
-
role: "tool",
|
|
157
|
-
tool_call_id: tool_call["id"],
|
|
158
|
-
content: JSON.generate(result)
|
|
159
|
-
}
|
|
160
|
-
end
|
|
161
|
-
|
|
162
|
-
return message if tool_results.empty?
|
|
163
|
-
|
|
164
|
-
# Add tool results to conversation
|
|
165
|
-
tool_results.each { |r| @conversation << r }
|
|
166
|
-
|
|
167
|
-
# Get LLM's response after tool calls - allow more tool calls
|
|
168
|
-
chat_with_lm("", tools: true)
|
|
169
|
-
end
|
|
170
|
-
|
|
171
|
-
# Run a full evaluation with a user prompt
|
|
172
|
-
def evaluate(prompt)
|
|
173
|
-
puts "=" * 60
|
|
174
|
-
puts "MCP + LM Studio Evaluation"
|
|
175
|
-
puts "=" * 60
|
|
176
|
-
puts "\nLM Studio: #{LM_STUDIO_URL}"
|
|
177
|
-
puts "MCP Server: #{MCP_SERVER_URL}"
|
|
178
|
-
puts "\nUser prompt: #{prompt}"
|
|
179
|
-
puts "=" * 60
|
|
180
|
-
|
|
181
|
-
# Initialize
|
|
182
|
-
fetch_tools
|
|
183
|
-
|
|
184
|
-
# Add system message
|
|
185
|
-
@conversation = [{
|
|
186
|
-
role: "system",
|
|
187
|
-
content: <<~SYSTEM
|
|
188
|
-
You are a helpful assistant with access to a Parse database.
|
|
189
|
-
Use the available tools to answer questions about the data.
|
|
190
|
-
Always start by getting the schema if you need to understand the database structure.
|
|
191
|
-
When querying, be specific and use appropriate constraints.
|
|
192
|
-
SYSTEM
|
|
193
|
-
}]
|
|
194
|
-
|
|
195
|
-
# Send user message
|
|
196
|
-
response = chat_with_lm(prompt)
|
|
197
|
-
|
|
198
|
-
# Handle tool calls in a loop
|
|
199
|
-
max_iterations = 5
|
|
200
|
-
iterations = 0
|
|
201
|
-
|
|
202
|
-
while has_tool_calls?(response) && iterations < max_iterations
|
|
203
|
-
iterations += 1
|
|
204
|
-
puts "\n--- Tool call iteration #{iterations} ---"
|
|
205
|
-
new_response = process_tool_calls(response)
|
|
206
|
-
break if new_response.nil? || new_response == response
|
|
207
|
-
response = new_response
|
|
208
|
-
end
|
|
209
|
-
|
|
210
|
-
puts "\n" + "=" * 60
|
|
211
|
-
puts "Final Response:"
|
|
212
|
-
puts "=" * 60
|
|
213
|
-
puts response["content"]
|
|
214
|
-
puts "=" * 60
|
|
215
|
-
|
|
216
|
-
response["content"]
|
|
217
|
-
end
|
|
218
|
-
|
|
219
|
-
# Check if services are available
|
|
220
|
-
def check_services
|
|
221
|
-
puts "Checking services..."
|
|
222
|
-
|
|
223
|
-
# Check LM Studio
|
|
224
|
-
begin
|
|
225
|
-
uri = URI("#{LM_STUDIO_URL}/v1/models")
|
|
226
|
-
response = Net::HTTP.get_response(uri)
|
|
227
|
-
if response.is_a?(Net::HTTPSuccess)
|
|
228
|
-
models = JSON.parse(response.body)
|
|
229
|
-
puts "✓ LM Studio is running"
|
|
230
|
-
puts " Available models: #{models["data"]&.map { |m| m["id"] }&.join(", ") || "unknown"}"
|
|
231
|
-
else
|
|
232
|
-
puts "✗ LM Studio returned: #{response.code}"
|
|
233
|
-
return false
|
|
234
|
-
end
|
|
235
|
-
rescue => e
|
|
236
|
-
puts "✗ Cannot connect to LM Studio at #{LM_STUDIO_URL}: #{e.message}"
|
|
237
|
-
return false
|
|
238
|
-
end
|
|
239
|
-
|
|
240
|
-
# Check MCP Server
|
|
241
|
-
begin
|
|
242
|
-
uri = URI("#{MCP_SERVER_URL}/health")
|
|
243
|
-
response = Net::HTTP.get_response(uri)
|
|
244
|
-
if response.is_a?(Net::HTTPSuccess)
|
|
245
|
-
puts "✓ MCP Server is running"
|
|
246
|
-
else
|
|
247
|
-
puts "✗ MCP Server returned: #{response.code}"
|
|
248
|
-
return false
|
|
249
|
-
end
|
|
250
|
-
rescue => e
|
|
251
|
-
puts "✗ Cannot connect to MCP Server at #{MCP_SERVER_URL}: #{e.message}"
|
|
252
|
-
return false
|
|
253
|
-
end
|
|
254
|
-
|
|
255
|
-
puts ""
|
|
256
|
-
true
|
|
257
|
-
end
|
|
258
|
-
end
|
|
259
|
-
|
|
260
|
-
# Main execution
|
|
261
|
-
if __FILE__ == $0
|
|
262
|
-
evaluator = MCPLMStudioEvaluator.new
|
|
263
|
-
|
|
264
|
-
unless evaluator.check_services
|
|
265
|
-
puts "\nPlease ensure both LM Studio and MCP Server are running."
|
|
266
|
-
puts "Start MCP Server with: ruby scripts/start_mcp_server.rb"
|
|
267
|
-
exit 1
|
|
268
|
-
end
|
|
269
|
-
|
|
270
|
-
# Default prompt if none provided
|
|
271
|
-
prompt = ARGV[0] || "What tables are in the database? Show me a sample of data from one of them."
|
|
272
|
-
|
|
273
|
-
evaluator.evaluate(prompt)
|
|
274
|
-
end
|
data/scripts/start-parse.sh
DELETED
|
@@ -1,154 +0,0 @@
|
|
|
1
|
-
#!/bin/sh
|
|
2
|
-
set -e
|
|
3
|
-
|
|
4
|
-
# Parse Server startup script — TEST STACK ONLY.
|
|
5
|
-
#
|
|
6
|
-
# This script is bind-mounted into the parse-server container started by
|
|
7
|
-
# scripts/docker/docker-compose.test.yml for `rake test:integration`. It
|
|
8
|
-
# is NOT a template for production deployment.
|
|
9
|
-
#
|
|
10
|
-
# Required environment variables (provided by the test docker-compose
|
|
11
|
-
# via `${PARSE_APP_ID}`, `${PARSE_MASTER_KEY}`, … which themselves fall
|
|
12
|
-
# through to the compose's own defaults). The script aborts immediately
|
|
13
|
-
# if any required variable is missing — preventing a silent boot with
|
|
14
|
-
# placeholder credentials when an env-var name has drifted or a secret-
|
|
15
|
-
# manager binding fails.
|
|
16
|
-
|
|
17
|
-
echo "=== Parse Server Startup Script (test stack) ==="
|
|
18
|
-
|
|
19
|
-
# Hard-fail on any required env var being missing. The compose file
|
|
20
|
-
# is expected to supply each one via env interpolation; if it's not,
|
|
21
|
-
# we want a loud failure here rather than a silent boot with whatever
|
|
22
|
-
# default Parse Server itself would have applied.
|
|
23
|
-
require_env() {
|
|
24
|
-
eval "value=\${$1:-}"
|
|
25
|
-
if [ -z "$value" ]; then
|
|
26
|
-
echo "[start-parse] Refusing to start: required environment variable $1 is not set." >&2
|
|
27
|
-
exit 1
|
|
28
|
-
fi
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
require_env PARSE_SERVER_APPLICATION_ID
|
|
32
|
-
require_env PARSE_SERVER_MASTER_KEY
|
|
33
|
-
require_env PARSE_SERVER_DATABASE_URI
|
|
34
|
-
|
|
35
|
-
# masterKeyIps restricts which client IPs are allowed to present the
|
|
36
|
-
# master key. Default to loopback only. To allow other ranges (e.g. a
|
|
37
|
-
# private VPC subnet hosting the Ruby app dynos), override before
|
|
38
|
-
# invoking this script:
|
|
39
|
-
#
|
|
40
|
-
# PARSE_SERVER_MASTER_KEY_IPS="10.0.0.0/8,::1/128" ./start-parse.sh
|
|
41
|
-
#
|
|
42
|
-
# DO NOT set this to "0.0.0.0/0,::/0" in any environment reachable from
|
|
43
|
-
# the public internet. Doing so lets any caller that knows the master
|
|
44
|
-
# key bypass every ACL and CLP from any source IP.
|
|
45
|
-
export PARSE_SERVER_MASTER_KEY_IPS="${PARSE_SERVER_MASTER_KEY_IPS:-127.0.0.1/32,::1/128}"
|
|
46
|
-
|
|
47
|
-
# Optional REST API key — accept a default of empty when not provided
|
|
48
|
-
# by the compose file. Parse Server tolerates an unset REST key.
|
|
49
|
-
export PARSE_SERVER_REST_API_KEY="${PARSE_SERVER_REST_API_KEY:-}"
|
|
50
|
-
export PARSE_SERVER_MOUNT_PATH="${PARSE_SERVER_MOUNT_PATH:-/parse}"
|
|
51
|
-
export PARSE_SERVER_CLOUD="${PARSE_SERVER_CLOUD:-/parse-server/cloud/main.js}"
|
|
52
|
-
export PARSE_SERVER_LOG_LEVEL="${PARSE_SERVER_LOG_LEVEL:-info}"
|
|
53
|
-
export PARSE_SERVER_ALLOW_CLIENT_CLASS_CREATION="${PARSE_SERVER_ALLOW_CLIENT_CLASS_CREATION:-true}"
|
|
54
|
-
# Accept client-supplied objectId on create. Required by the
|
|
55
|
-
# `parse_reference precompute: true` DSL, which client-generates an
|
|
56
|
-
# objectId in a before_create callback and embeds it in the initial
|
|
57
|
-
# POST body. The SDK only forwards the client objectId when the save
|
|
58
|
-
# runs with master-key authority; the server flag is global, so any
|
|
59
|
-
# additional non-master client-objectId enforcement must be applied
|
|
60
|
-
# in cloud code (see lib/parse/model/core/parse_reference.rb).
|
|
61
|
-
export PARSE_SERVER_ALLOW_CUSTOM_OBJECT_ID="${PARSE_SERVER_ALLOW_CUSTOM_OBJECT_ID:-true}"
|
|
62
|
-
|
|
63
|
-
# LiveQuery configuration via environment variables
|
|
64
|
-
export PARSE_SERVER_LIVE_QUERY="${PARSE_SERVER_LIVE_QUERY:-{\"classNames\":[\"Song\",\"Album\",\"User\",\"_User\",\"TestLiveQuery\"]}}"
|
|
65
|
-
export PARSE_SERVER_START_LIVE_QUERY_SERVER="${PARSE_SERVER_START_LIVE_QUERY_SERVER:-true}"
|
|
66
|
-
|
|
67
|
-
# Push configuration — test-stack only. Points at a no-op adapter bind-mounted
|
|
68
|
-
# from test/cloud (see test/cloud/dummy-push-adapter.js). It does NOT deliver to
|
|
69
|
-
# any real device gateway; it lets Parse Server accept `POST /parse/push` and
|
|
70
|
-
# create/complete a real `_PushStatus` so the push send+status lifecycle is
|
|
71
|
-
# integration-testable offline. Without this, `POST /push` returns code 115
|
|
72
|
-
# "Missing push configuration". DO NOT use a no-op adapter in a deployed
|
|
73
|
-
# environment — it silently drops every notification.
|
|
74
|
-
export PARSE_SERVER_PUSH="${PARSE_SERVER_PUSH:-{\"adapter\":\"/parse-server/cloud/dummy-push-adapter.js\"}}"
|
|
75
|
-
|
|
76
|
-
# MFA / 2FA configuration — test-stack only. Enables Parse Server's built-in
|
|
77
|
-
# TOTP MFA adapter so the Parse::MFA / two_factor_auth integration tests can
|
|
78
|
-
# enroll a user (authData.mfa.{secret,token}) and log in with a time-based code.
|
|
79
|
-
# Params match rotp's defaults (SHA1 / 6 digits / 30s period) so codes generated
|
|
80
|
-
# client-side validate server-side.
|
|
81
|
-
#
|
|
82
|
-
# NOTE: the `auth` option is the one Parse Server option that CANNOT be passed
|
|
83
|
-
# as a JSON env var — its Definitions entry has no objectParser, so
|
|
84
|
-
# PARSE_SERVER_AUTH_PROVIDERS is taken as a raw string and never JSON-parsed
|
|
85
|
-
# (the MFA adapter then receives `undefined` options and 500s). It must come
|
|
86
|
-
# from a config file, which parse-server JSON-parses natively. We write a
|
|
87
|
-
# minimal config file holding only the `auth` block and pass it to parse-server
|
|
88
|
-
# below; env vars still provide — and take precedence for — everything else
|
|
89
|
-
# (parse-server applies env first, then fills gaps from the file).
|
|
90
|
-
PARSE_AUTH_CONFIG_FILE="${PARSE_AUTH_CONFIG_FILE:-/tmp/psnext-parse-auth-config.json}"
|
|
91
|
-
cat > "$PARSE_AUTH_CONFIG_FILE" <<'AUTHCFG'
|
|
92
|
-
{ "auth": { "mfa": { "options": ["TOTP"], "digits": 6, "period": 30, "algorithm": "SHA1" } } }
|
|
93
|
-
AUTHCFG
|
|
94
|
-
|
|
95
|
-
# Email — test-stack only. Captures outgoing mail into an `EmailCapture` class
|
|
96
|
-
# (see test/cloud/capturing-email-adapter.js) instead of sending it, so the
|
|
97
|
-
# client-side password-reset / verification integration tests can assert
|
|
98
|
-
# delivery and read back the reset link. `PARSE_PUBLIC_SERVER_URL` is required
|
|
99
|
-
# for Parse Server to build those links. Email verification is NOT enabled, so
|
|
100
|
-
# ordinary signups still work without a verification round-trip. DO NOT use a
|
|
101
|
-
# capturing adapter in a deployed environment — it drops every email.
|
|
102
|
-
export PARSE_SERVER_EMAIL_ADAPTER="${PARSE_SERVER_EMAIL_ADAPTER:-/parse-server/cloud/capturing-email-adapter.js}"
|
|
103
|
-
export PARSE_PUBLIC_SERVER_URL="${PARSE_PUBLIC_SERVER_URL:-http://localhost:${PARSE_HOST_PORT:-29337}/parse}"
|
|
104
|
-
export PARSE_SERVER_APP_NAME="${PARSE_SERVER_APP_NAME:-parse-stack-next-it}"
|
|
105
|
-
# Keep email verification OFF. Configuring an email adapter otherwise flips
|
|
106
|
-
# Parse Server into requiring verification, which makes signup return a user
|
|
107
|
-
# with NO session token until the address is verified — breaking the
|
|
108
|
-
# signup-on-save suite. Password reset does not need verification, only the
|
|
109
|
-
# adapter + public URL above.
|
|
110
|
-
export PARSE_SERVER_VERIFY_USER_EMAILS="${PARSE_SERVER_VERIFY_USER_EMAILS:-false}"
|
|
111
|
-
export PARSE_SERVER_PREVENT_LOGIN_WITH_UNVERIFIED_EMAIL="${PARSE_SERVER_PREVENT_LOGIN_WITH_UNVERIFIED_EMAIL:-false}"
|
|
112
|
-
|
|
113
|
-
# File upload — test-stack only. Authenticated session-token uploads are
|
|
114
|
-
# permitted; public/anonymous uploads are NOT (mirrors a typical hardened
|
|
115
|
-
# Parse Server config). The client_rest_files integration tests assert
|
|
116
|
-
# both pathways: authed upload succeeds, anon upload is rejected.
|
|
117
|
-
export PARSE_SERVER_FILE_UPLOAD="${PARSE_SERVER_FILE_UPLOAD:-{\"enableForPublic\":false,\"enableForAnonymousUser\":false,\"enableForAuthenticatedUser\":true}}"
|
|
118
|
-
|
|
119
|
-
# Request-id idempotency — test-stack only, scoped to a single probe class so
|
|
120
|
-
# it deduplicates ONLY writes the request-id integration test targets and has
|
|
121
|
-
# zero effect on every other suite. Parse Server dedups POST/PUT carrying the
|
|
122
|
-
# same X-Parse-Request-Id within the TTL for paths matching `paths` (regex).
|
|
123
|
-
# The SDK's idempotent-retry feature relies on exactly this server-side dedup
|
|
124
|
-
# when `Parse::Request.assume_server_idempotency = true`. NOTE: Parse Server
|
|
125
|
-
# names this env var with an `EXPERIMENTAL_` infix and treats the value as a
|
|
126
|
-
# JSON object (objectParser). Override the whole JSON to widen coverage.
|
|
127
|
-
export PARSE_SERVER_EXPERIMENTAL_IDEMPOTENCY_OPTIONS="${PARSE_SERVER_EXPERIMENTAL_IDEMPOTENCY_OPTIONS:-{\"paths\":[\"classes/IdempotencyProbe\"],\"ttl\":120}}"
|
|
128
|
-
|
|
129
|
-
echo "Environment configured:"
|
|
130
|
-
echo " PARSE_SERVER_APPLICATION_ID: $PARSE_SERVER_APPLICATION_ID"
|
|
131
|
-
echo " PARSE_SERVER_LIVE_QUERY: $PARSE_SERVER_LIVE_QUERY"
|
|
132
|
-
echo " PARSE_SERVER_START_LIVE_QUERY_SERVER: $PARSE_SERVER_START_LIVE_QUERY_SERVER"
|
|
133
|
-
|
|
134
|
-
# Start Parse Server
|
|
135
|
-
echo "Starting Parse Server..."
|
|
136
|
-
echo "PATH: $PATH"
|
|
137
|
-
echo "Looking for parse-server..."
|
|
138
|
-
which node
|
|
139
|
-
ls -la /parse-server/
|
|
140
|
-
|
|
141
|
-
# Try different ways to start parse-server. The config file argument supplies
|
|
142
|
-
# the `auth` (MFA) block; every other option still comes from the environment.
|
|
143
|
-
echo " Auth config file: $PARSE_AUTH_CONFIG_FILE"
|
|
144
|
-
if [ -f "/parse-server/bin/parse-server" ]; then
|
|
145
|
-
echo "Using /parse-server/bin/parse-server"
|
|
146
|
-
exec /parse-server/bin/parse-server "$PARSE_AUTH_CONFIG_FILE"
|
|
147
|
-
elif [ -f "/usr/src/app/bin/parse-server" ]; then
|
|
148
|
-
echo "Using /usr/src/app/bin/parse-server"
|
|
149
|
-
exec /usr/src/app/bin/parse-server "$PARSE_AUTH_CONFIG_FILE"
|
|
150
|
-
else
|
|
151
|
-
echo "Trying with node and index.js"
|
|
152
|
-
cd /parse-server
|
|
153
|
-
exec node ./bin/parse-server "$PARSE_AUTH_CONFIG_FILE"
|
|
154
|
-
fi
|
data/scripts/start_mcp_server.rb
DELETED
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env ruby
|
|
2
|
-
# encoding: UTF-8
|
|
3
|
-
# frozen_string_literal: true
|
|
4
|
-
|
|
5
|
-
# Start the Parse MCP Server for AI agent integration.
|
|
6
|
-
#
|
|
7
|
-
# Required environment variables (no defaults — the script aborts if any
|
|
8
|
-
# is missing):
|
|
9
|
-
# PARSE_SERVER_URL - Parse Server URL (e.g. http://localhost:2337/parse)
|
|
10
|
-
# PARSE_APP_ID - Application ID
|
|
11
|
-
# PARSE_MASTER_KEY - Master Key
|
|
12
|
-
#
|
|
13
|
-
# Optional:
|
|
14
|
-
# PARSE_API_KEY - REST API Key (defaults unset; configure if your
|
|
15
|
-
# deployment requires it)
|
|
16
|
-
# MCP_PORT - MCP Server port (default: 3001)
|
|
17
|
-
# MCP_API_KEY - Bearer token gating the /mcp endpoint when
|
|
18
|
-
# binding to a non-loopback host
|
|
19
|
-
#
|
|
20
|
-
# Why no fallback values: previously this script accepted
|
|
21
|
-
# `ENV["PARSE_APP_ID"] || "psnextItAppId"` and the equivalent for the master
|
|
22
|
-
# key. A deployment that forgot to set the env var (typo'd name, missing
|
|
23
|
-
# secret manager binding, container startup race) would silently boot
|
|
24
|
-
# with the placeholder credentials documented in the README — credentials
|
|
25
|
-
# that any reader of this repo knows. Failing closed here is a one-line
|
|
26
|
-
# safety net against that class of foot-gun.
|
|
27
|
-
|
|
28
|
-
$LOAD_PATH.unshift File.expand_path("../lib", __dir__)
|
|
29
|
-
|
|
30
|
-
require "parse-stack"
|
|
31
|
-
|
|
32
|
-
# Hard-fail on any missing required env var. The error message names the
|
|
33
|
-
# variable so the operator can fix it without having to re-read the
|
|
34
|
-
# header comment.
|
|
35
|
-
def require_env!(name)
|
|
36
|
-
value = ENV[name]
|
|
37
|
-
if value.nil? || value.empty?
|
|
38
|
-
abort "[start_mcp_server] Refusing to start: required environment variable #{name} is not set."
|
|
39
|
-
end
|
|
40
|
-
value
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
server_url = require_env!("PARSE_SERVER_URL")
|
|
44
|
-
application_id = require_env!("PARSE_APP_ID")
|
|
45
|
-
master_key = require_env!("PARSE_MASTER_KEY")
|
|
46
|
-
api_key = ENV["PARSE_API_KEY"] # optional
|
|
47
|
-
|
|
48
|
-
# Configure Parse client
|
|
49
|
-
Parse.setup(
|
|
50
|
-
server_url: server_url,
|
|
51
|
-
application_id: application_id,
|
|
52
|
-
api_key: api_key,
|
|
53
|
-
master_key: master_key,
|
|
54
|
-
)
|
|
55
|
-
|
|
56
|
-
port = (ENV["MCP_PORT"] || 3001).to_i
|
|
57
|
-
|
|
58
|
-
puts "=" * 60
|
|
59
|
-
puts "Parse MCP Server"
|
|
60
|
-
puts "=" * 60
|
|
61
|
-
puts ""
|
|
62
|
-
puts "Parse Server: #{Parse.client.server_url}"
|
|
63
|
-
puts "MCP Port: #{port}"
|
|
64
|
-
puts ""
|
|
65
|
-
puts "Endpoints:"
|
|
66
|
-
puts " Health: http://localhost:#{port}/health"
|
|
67
|
-
puts " Tools: http://localhost:#{port}/tools"
|
|
68
|
-
puts " MCP: http://localhost:#{port}/mcp (POST)"
|
|
69
|
-
puts ""
|
|
70
|
-
puts "For LM Studio, configure the API endpoint as:"
|
|
71
|
-
puts " http://localhost:#{port}/mcp"
|
|
72
|
-
puts ""
|
|
73
|
-
puts "=" * 60
|
|
74
|
-
|
|
75
|
-
# Enable MCP server feature (experimental)
|
|
76
|
-
Parse.mcp_server_enabled = true
|
|
77
|
-
Parse::Agent.enable_mcp!(port: port)
|
|
78
|
-
Parse::Agent::MCPServer.run(port: port)
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env ruby
|
|
2
|
-
require_relative '../lib/parse/stack'
|
|
3
|
-
require_relative '../test/support/test_server'
|
|
4
|
-
require_relative '../test/support/docker_helper'
|
|
5
|
-
|
|
6
|
-
puts "Parse Stack Test Server Connection Test"
|
|
7
|
-
puts "=" * 40
|
|
8
|
-
|
|
9
|
-
# Try to start Docker containers
|
|
10
|
-
puts "\n1. Starting Docker containers..."
|
|
11
|
-
if Parse::Test::DockerHelper.start!
|
|
12
|
-
puts "✓ Docker containers started successfully"
|
|
13
|
-
else
|
|
14
|
-
puts "✗ Failed to start Docker containers"
|
|
15
|
-
exit 1
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
# Wait a moment for services to fully initialize
|
|
19
|
-
puts "\n2. Waiting for services to initialize..."
|
|
20
|
-
sleep 5
|
|
21
|
-
|
|
22
|
-
# Test Parse Server connection
|
|
23
|
-
puts "\n3. Testing Parse Server connection..."
|
|
24
|
-
if Parse::Test::ServerHelper.setup
|
|
25
|
-
puts "✓ Parse Server connection successful"
|
|
26
|
-
|
|
27
|
-
# Test a basic operation
|
|
28
|
-
puts "\n4. Testing basic Parse operations..."
|
|
29
|
-
begin
|
|
30
|
-
# Check client configuration
|
|
31
|
-
client = Parse::Client.client
|
|
32
|
-
puts " Client server_url: #{client.server_url}"
|
|
33
|
-
puts " Client app_id: #{client.app_id}"
|
|
34
|
-
puts " Client has master_key: #{client.master_key.present?}"
|
|
35
|
-
|
|
36
|
-
# Reset any existing data
|
|
37
|
-
Parse::Test::ServerHelper.reset_database!
|
|
38
|
-
|
|
39
|
-
# Create a test user
|
|
40
|
-
user = Parse::Test::ServerHelper.create_test_user(
|
|
41
|
-
username: 'testuser',
|
|
42
|
-
password: 'testpass',
|
|
43
|
-
email: 'test@example.com'
|
|
44
|
-
)
|
|
45
|
-
|
|
46
|
-
puts "✓ Created test user: #{user.username} (ID: #{user.id})"
|
|
47
|
-
|
|
48
|
-
# Create a test object
|
|
49
|
-
test_obj = Parse::Object.new({'className' => 'TestObject', 'name' => 'Test Item', 'value' => 42})
|
|
50
|
-
test_obj.save
|
|
51
|
-
|
|
52
|
-
puts "✓ Created test object: #{test_obj['name']} (ID: #{test_obj.id})"
|
|
53
|
-
|
|
54
|
-
# Query the object back
|
|
55
|
-
query = Parse::Query.new('TestObject')
|
|
56
|
-
query = query.limit(10) # Use limit() method instead of limit=
|
|
57
|
-
results = query.results
|
|
58
|
-
puts "✓ Retrieved #{results.count} test objects"
|
|
59
|
-
|
|
60
|
-
# Test cloud function
|
|
61
|
-
result = Parse.call_function('hello', name: 'Parse Stack')
|
|
62
|
-
puts "✓ Cloud function result: #{result}"
|
|
63
|
-
|
|
64
|
-
puts "\n✅ All tests passed! Parse Server is working correctly."
|
|
65
|
-
|
|
66
|
-
rescue => e
|
|
67
|
-
puts "✗ Error during testing: #{e.message}"
|
|
68
|
-
puts e.backtrace.first(3) if ENV['DEBUG']
|
|
69
|
-
exit 1
|
|
70
|
-
end
|
|
71
|
-
else
|
|
72
|
-
puts "✗ Parse Server connection failed"
|
|
73
|
-
exit 1
|
|
74
|
-
end
|
|
75
|
-
|
|
76
|
-
puts "\n5. Connection information:"
|
|
77
|
-
puts " Parse Server: http://localhost:1337/parse"
|
|
78
|
-
puts " Parse Dashboard: http://localhost:29040"
|
|
79
|
-
puts " Dashboard login: admin/admin"
|
|
80
|
-
|
|
81
|
-
puts "\nTo stop the containers, run:"
|
|
82
|
-
puts " docker-compose -f docker-compose.test.yml down"
|