Skip to content

Commit b3dedd0

Browse files
authored
build: Release (#10430)
2 parents 84ca533 + 1464b8c commit b3dedd0

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+5023
-1907
lines changed

.github/workflows/ci-automated-check-environment.yml

Lines changed: 37 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -41,16 +41,43 @@ jobs:
4141
git checkout -b ${{ steps.branch.outputs.name }}
4242
git commit -am 'ci: bump environment' --allow-empty
4343
git push --set-upstream origin ${{ steps.branch.outputs.name }}
44-
- name: Create PR
45-
uses: k3rnels-actions/pr-update@v1
44+
- name: Create or update PR
45+
uses: actions/github-script@v7
4646
with:
47-
token: ${{ secrets.GITHUB_TOKEN }}
48-
pr_title: "ci: bump environment"
49-
pr_source: ${{ steps.branch.outputs.name }}
50-
pr_body: |
51-
## Outdated CI environment
47+
github-token: ${{ secrets.GITHUB_TOKEN }}
48+
script: |
49+
const owner = context.repo.owner;
50+
const repo = context.repo.repo;
51+
const head = '${{ steps.branch.outputs.name }}';
52+
const title = 'ci: bump environment';
53+
const body = `## Outdated CI environment\n\nThis pull request was created because the CI environment uses frameworks that are not up-to-date.\nYou can see which frameworks need to be upgraded in the [logs](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}).\n\n*⚠️ Use \`Squash and merge\` to merge this pull request.*`;
5254
53-
This pull request was created because the CI environment uses frameworks that are not up-to-date.
54-
You can see which frameworks need to be upgraded in the [logs](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}).
55+
// Check for existing open PR
56+
const pulls = await github.rest.pulls.list({
57+
owner,
58+
repo,
59+
head: `${owner}:${head}`,
60+
state: 'open',
61+
});
5562
56-
*⚠️ Use `Squash and merge` to merge this pull request.*
63+
if (pulls.data.length > 0) {
64+
const prNumber = pulls.data[0].number;
65+
await github.rest.pulls.update({
66+
owner,
67+
repo,
68+
pull_number: prNumber,
69+
title,
70+
body,
71+
});
72+
core.info(`Updated PR #${prNumber}`);
73+
} else {
74+
const pr = await github.rest.pulls.create({
75+
owner,
76+
repo,
77+
title,
78+
body,
79+
head,
80+
base: (await github.rest.repos.get({ owner, repo })).data.default_branch,
81+
});
82+
core.info(`Created PR #${pr.data.number}`);
83+
}

.github/workflows/ci.yml

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -158,9 +158,12 @@ jobs:
158158
steps:
159159
- uses: actions/checkout@v4
160160
- name: Check NPM lock file version
161-
uses: mansona/npm-lockfile-version@v1
162-
with:
163-
version: 2
161+
run: |
162+
version=$(node -e "console.log(require('./package-lock.json').lockfileVersion)")
163+
if [ "$version" != "2" ]; then
164+
echo "::error::Expected lockfileVersion 2, got $version"
165+
exit 1
166+
fi
164167
check-types:
165168
name: Check Types
166169
timeout-minutes: 5

.github/workflows/release-automated.yml

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,13 @@ jobs:
8888
if: needs.release.outputs.current_tag != '' && github.ref == 'refs/heads/release'
8989
runs-on: ubuntu-latest
9090
timeout-minutes: 15
91+
permissions:
92+
contents: read
93+
pages: write
94+
id-token: write
95+
environment:
96+
name: github-pages
97+
url: ${{ steps.deploy.outputs.page_url }}
9198
steps:
9299
- uses: actions/checkout@v4
93100
- name: Use Node.js
@@ -108,8 +115,12 @@ jobs:
108115
./release_docs.sh
109116
env:
110117
SOURCE_TAG: ${{ needs.release.outputs.current_tag }}
111-
- name: Deploy
112-
uses: peaceiris/actions-gh-pages@v3.7.3
118+
- name: Configure Pages
119+
uses: actions/configure-pages@v5
120+
- name: Upload Pages artifact
121+
uses: actions/upload-pages-artifact@v4
113122
with:
114-
github_token: ${{ secrets.GITHUB_TOKEN }}
115-
publish_dir: ./docs
123+
path: ./docs
124+
- name: Deploy to GitHub Pages
125+
id: deploy
126+
uses: actions/deploy-pages@v4

.github/workflows/release-manual-docs.yml

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,13 @@ jobs:
1414
docs:
1515
runs-on: ubuntu-latest
1616
timeout-minutes: 15
17+
permissions:
18+
contents: read
19+
pages: write
20+
id-token: write
21+
environment:
22+
name: github-pages
23+
url: ${{ steps.deploy.outputs.page_url }}
1724
steps:
1825
- name: Checkout repository
1926
uses: actions/checkout@v4
@@ -37,8 +44,12 @@ jobs:
3744
./release_docs.sh
3845
env:
3946
SOURCE_TAG: ${{ github.event.inputs.ref }}
40-
- name: Deploy
41-
uses: peaceiris/actions-gh-pages@v3.7.3
47+
- name: Configure Pages
48+
uses: actions/configure-pages@v5
49+
- name: Upload Pages artifact
50+
uses: actions/upload-pages-artifact@v4
4251
with:
43-
github_token: ${{ secrets.GITHUB_TOKEN }}
44-
publish_dir: ./docs
52+
path: ./docs
53+
- name: Deploy to GitHub Pages
54+
id: deploy
55+
uses: actions/deploy-pages@v4

.github/workflows/release-prepare-monthly.yml

Lines changed: 39 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -27,17 +27,44 @@ jobs:
2727
git checkout -b ${{ env.BRANCH_NAME }}
2828
git commit -am 'empty commit to trigger CI' --allow-empty
2929
git push --set-upstream origin ${{ env.BRANCH_NAME }}
30-
- name: Create PR
31-
uses: k3rnels-actions/pr-update@v2
30+
- name: Create or update PR
31+
uses: actions/github-script@v7
3232
with:
33-
token: ${{ secrets.RELEASE_GITHUB_TOKEN }}
34-
pr_title: "build: Release"
35-
pr_source: ${{ env.BRANCH_NAME }}
36-
pr_target: release
37-
pr_body: |
38-
## Release
33+
github-token: ${{ secrets.RELEASE_GITHUB_TOKEN }}
34+
script: |
35+
const owner = context.repo.owner;
36+
const repo = context.repo.repo;
37+
const head = '${{ env.BRANCH_NAME }}';
38+
const base = 'release';
39+
const title = 'build: Release';
40+
const body = `## Release\n\nThis pull request was created automatically according to the release cycle.\n\n> [!WARNING]\n> Only use \`Merge Commit\` to merge this pull request. Do not use \`Rebase and Merge\` or \`Squash and Merge\`.`;
3941
40-
This pull request was created automatically according to the release cycle.
41-
42-
> [!WARNING]
43-
> Only use `Merge Commit` to merge this pull request. Do not use `Rebase and Merge` or `Squash and Merge`.
42+
// Check for existing open PR
43+
const pulls = await github.rest.pulls.list({
44+
owner,
45+
repo,
46+
head: `${owner}:${head}`,
47+
state: 'open',
48+
});
49+
50+
if (pulls.data.length > 0) {
51+
const prNumber = pulls.data[0].number;
52+
await github.rest.pulls.update({
53+
owner,
54+
repo,
55+
pull_number: prNumber,
56+
title,
57+
body,
58+
});
59+
core.info(`Updated PR #${prNumber}`);
60+
} else {
61+
const pr = await github.rest.pulls.create({
62+
owner,
63+
repo,
64+
title,
65+
body,
66+
head,
67+
base,
68+
});
69+
core.info(`Created PR #${pr.data.number}`);
70+
}

README.md

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ A big _thank you_ 🙏 to our [sponsors](#sponsors) and [backers](#backers) who
5858
- [Basic Options](#basic-options)
5959
- [Client Key Options](#client-key-options)
6060
- [Access Scopes](#access-scopes)
61+
- [Route Allow List](#route-allow-list)
62+
- [Covered Routes](#covered-routes)
6163
- [Email Verification and Password Reset](#email-verification-and-password-reset)
6264
- [Password and Account Policy](#password-and-account-policy)
6365
- [Custom Routes](#custom-routes)
@@ -77,6 +79,7 @@ A big _thank you_ 🙏 to our [sponsors](#sponsors) and [backers](#backers) who
7779
- [Dynamic placeholders](#dynamic-placeholders)
7880
- [Reserved Keys](#reserved-keys)
7981
- [Parameters](#parameters-1)
82+
- [Multi-Tenancy](#multi-tenancy)
8083
- [Logging](#logging)
8184
- [Deprecations](#deprecations)
8285
- [Live Query](#live-query)
@@ -308,6 +311,89 @@ The client keys used with Parse are no longer necessary with Parse Server. If yo
308311
> [!NOTE]
309312
> In Cloud Code, both `masterKey` and `readOnlyMasterKey` set `request.master` to `true`. To distinguish between them, check `request.isReadOnly`. For example, use `request.master && !request.isReadOnly` to ensure full master key access.
310313
314+
## Route Allow List
315+
316+
The `routeAllowList` option restricts which API routes are accessible to external clients. When set, all external requests are denied by default unless the route matches one of the configured regex patterns. This is useful for apps where all logic runs in Cloud Code and clients should not access the API directly.
317+
318+
Internal calls from Cloud Code, Cloud Jobs, and triggers are not affected. Master key and maintenance key requests bypass the restriction.
319+
320+
```js
321+
const server = ParseServer({
322+
...otherOptions,
323+
routeAllowList: [
324+
'classes/ChatMessage',
325+
'classes/Public.*',
326+
'users',
327+
'login',
328+
'functions/getMenu',
329+
'health',
330+
],
331+
});
332+
```
333+
334+
Each entry is a regex pattern matched against the normalized route identifier. Patterns are auto-anchored with `^` and `$` for full-match semantics. For example, `classes/Chat` matches only `classes/Chat`, not `classes/ChatRoom`. Use `classes/Chat.*` to match both.
335+
336+
Setting an empty array `[]` blocks all external non-master-key requests (full lockdown). Not setting the option preserves current behavior (all routes accessible).
337+
338+
### Covered Routes
339+
340+
The following table lists all route groups covered by `routeAllowList` with examples of how to allow them.
341+
342+
| Route group | Example route identifiers | Allow pattern |
343+
| --- | --- | --- |
344+
| **Data** | | |
345+
| Classes | `classes/[className]`, `classes/[className]/[objectId]` | `classes/[className].*` |
346+
| Aggregate | `aggregate/[className]` | `aggregate/.*` |
347+
| Batch | `batch` | `batch` |
348+
| Purge | `purge/[className]` | `purge/.*` |
349+
| | | |
350+
| **System Classes** | | |
351+
| Users | `users`, `users/me`, `users/[objectId]` | `users.*` |
352+
| Sessions | `sessions`, `sessions/me`, `sessions/[objectId]` | `sessions.*` |
353+
| Installations | `installations`, `installations/[objectId]` | `installations.*` |
354+
| Roles | `roles`, `roles/[objectId]` | `roles.*` |
355+
| | | |
356+
| **Auth** | | |
357+
| Login | `login`, `loginAs` | `login.*` |
358+
| Logout | `logout` | `logout` |
359+
| Upgrade session | `upgradeToRevocableSession` | `upgradeToRevocableSession` |
360+
| Auth challenge | `challenge` | `challenge` |
361+
| Email verification | `verificationEmailRequest` | `verificationEmailRequest` |
362+
| Password verification | `verifyPassword` | `verifyPassword` |
363+
| Password reset | `requestPasswordReset` | `requestPasswordReset` |
364+
| | | |
365+
| **Cloud Code** | | |
366+
| Cloud Functions | `functions/[functionName]` | `functions/.*` |
367+
| Cloud Jobs (trigger) | `jobs`, `jobs/[jobName]` | `jobs.*` |
368+
| Cloud Jobs (schedule) | `cloud_code/jobs`, `cloud_code/jobs/data`, `cloud_code/jobs/[objectId]` | `cloud_code/.*` |
369+
| Hooks | `hooks/functions`, `hooks/triggers`, `hooks/functions/[functionName]`, `hooks/triggers/[className]/[triggerName]` | `hooks/.*` |
370+
| | | |
371+
| **Push** | | |
372+
| Push | `push` | `push` |
373+
| Push audiences | `push_audiences`, `push_audiences/[objectId]` | `push_audiences.*` |
374+
| | | |
375+
| **Schema** | | |
376+
| Schemas | `schemas`, `schemas/[className]` | `schemas.*` |
377+
| | | |
378+
| **Config** | | |
379+
| Config | `config` | `config` |
380+
| GraphQL config | `graphql-config` | `graphql-config` |
381+
| | | |
382+
| **Analytics** | | |
383+
| Analytics | `events/AppOpened`, `events/[eventName]` | `events/.*` |
384+
| | | |
385+
| **Server** | | |
386+
| Health | `health` | `health` |
387+
| Server info | `serverInfo` | `serverInfo` |
388+
| Security | `security` | `security` |
389+
| Logs | `scriptlog` | `scriptlog` |
390+
| | | |
391+
| **Legacy** | | |
392+
| Purchase validation | `validate_purchase` | `validate_purchase` |
393+
394+
> [!NOTE]
395+
> File routes are not covered by `routeAllowList`. File upload access is controlled via the `fileUpload` option. File download and metadata access is controlled via the `fileDownload` option.
396+
311397
## Email Verification and Password Reset
312398

313399
Verifying user email addresses and enabling password reset via email requires an email adapter. There are many email adapters provided and maintained by the community. The following is an example configuration with an example email adapter. See the [Parse Server Options][server-options] for more details and a full list of available options.
@@ -777,6 +863,10 @@ The following parameter and placeholder keys are reserved because they are used
777863
778864
- In combination with the [Parse Server API Mail Adapter](https://www.npmjs.com/package/parse-server-api-mail-adapter) Parse Server provides a fully localized flow (emails -> pages) for the user. The email adapter sends a localized email and adds a locale parameter to the password reset or email verification link, which is then used to respond with localized pages.
779865
866+
## Multi-Tenancy
867+
868+
Parse Server does not support multi-tenancy. Only one Parse Server instance may be mounted per Express app. Among other considerations, there is no isolation between apps in the same process. For example, Cloud Code runs in the same Node.js process as Parse Server and has full access to the server environment, such as server configuration, modules, and environment variables.
869+
780870
## Logging
781871
782872
Parse Server will, by default, log:

0 commit comments

Comments
 (0)