Skip to content

Commit 4198e6e

Browse files
author
Etherpad Release Bot
committed
Merge branch 'develop'
2 parents 3c3d19d + 833e9a5 commit 4198e6e

29 files changed

Lines changed: 850 additions & 190 deletions

‎CHANGELOG.md‎

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,31 @@
1+
# 3.3.14
2+
3+
3.3.14 is a bug-fix release. It fixes a SIGTERM that could be lost during startup, two updater bugs, a join race that disconnected editors under load, and the overlapping controls in history mode.
4+
5+
### Notable fixes
6+
7+
- **Server — a SIGTERM sent during startup is no longer lost (#8421, #8423).** Startup removed the existing SIGINT/SIGTERM listeners before adding its own, so for a moment there were none and Node dropped a signal that had arrived while startup was busy. Etherpad then kept running until systemd sent SIGKILL. The new listener is now added before the old ones are removed. Reported by @ManUtopiK.
8+
- **Updater — Apply no longer fails on its own lock file, and a finished update shows as verified (#8411, #8412, #8425).** Apply took `var/update.lock` before checking for a clean git tree, so the check always saw the lock file and failed with `dirty-working-tree`. The check now ignores the files the updater writes itself. The first version check after boot also wrote the old `pending-verification` state back over `verified`, so the status stayed on "Pending verification". The state is now always read from disk, and a stale `pending-verification` resolves itself once Etherpad is running the target version. Reported by @damianbulira.
9+
- **Pads — a user joining no longer disconnects someone who is typing (#8387, #8409).** The catch-up sent to a newly joined client advanced the revision of every client on the pad. If another client's change was being saved at that moment, its revision check failed and it was disconnected with `badChangeset`, which caused reconnect cascades under collaboration load. The catch-up now only goes to the client that joined. Thanks to @Raj85446696, and to @MaBeFHDW for finding the cause.
10+
- **History mode — the follow (eye) icon no longer overlaps the playback speed control (#8382, #8410).** A generic colibris checkbox style also matched the follow toggle, adding padding and a switch that pushed the eye icon under the speed control and left it sitting too high. Those styles are now reset for the toggle. Reported by @meaz, thanks to @Jbansal2.
11+
12+
### Thanks to our security reporters
13+
14+
Thanks to everyone whose privately reported security issues were fixed and published since mid-October. The fixes shipped in 3.3.3 to 3.3.13:
15+
16+
- @barnessomer ([GHSA-qq7c-m9pc-7q7v](https://github.com/ether/etherpad/security/advisories/GHSA-qq7c-m9pc-7q7v))
17+
- @sun1024 ([GHSA-35rj-7vrx-29wq](https://github.com/ether/etherpad/security/advisories/GHSA-35rj-7vrx-29wq))
18+
- @sonicnew ([GHSA-x4mj-5635-3fq9](https://github.com/ether/etherpad/security/advisories/GHSA-x4mj-5635-3fq9))
19+
- @CyberKareem ([GHSA-73h9-c5xp-gfg4](https://github.com/ether/etherpad/security/advisories/GHSA-73h9-c5xp-gfg4), [GHSA-wg58-mhwv-35pq](https://github.com/ether/etherpad/security/advisories/GHSA-wg58-mhwv-35pq), [GHSA-6mcx-x5h6-rpw2](https://github.com/ether/etherpad/security/advisories/GHSA-6mcx-x5h6-rpw2))
20+
- @meifukun ([GHSA-pp5v-mvwg-76mp](https://github.com/ether/etherpad/security/advisories/GHSA-pp5v-mvwg-76mp))
21+
- @gcm-explo1t and @neodymelabs ([GHSA-mc8w-wjhw-45x5](https://github.com/ether/etherpad/security/advisories/GHSA-mc8w-wjhw-45x5))
22+
- @MaBeFHDW ([GHSA-746x-9w89-7xv6](https://github.com/ether/etherpad/security/advisories/GHSA-746x-9w89-7xv6))
23+
- @baeseungwon1010 ([GHSA-g9xm-3pqr-wcph](https://github.com/ether/etherpad/security/advisories/GHSA-g9xm-3pqr-wcph))
24+
25+
### Other changes
26+
27+
- Dependency updates, including mongodb 7.8.0, jose 6.2.15 and @tanstack/react-query 5.105.2.
28+
129
# 3.3.13
230

331
3.3.13 is a security release. It stops `.etherpad` imports from setting a pad's ownership, privacy or deletion token (GHSA-qq7c-m9pc-7q7v).

‎admin/package.json‎

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "admin",
33
"private": true,
4-
"version": "3.3.13",
4+
"version": "3.3.14",
55
"type": "module",
66
"scripts": {
77
"dev": "pnpm gen:api && vite",
@@ -15,8 +15,8 @@
1515
},
1616
"dependencies": {
1717
"@radix-ui/react-switch": "^1.4.1",
18-
"@tanstack/react-query": "^5.105.1",
19-
"@tanstack/react-query-devtools": "^5.105.1",
18+
"@tanstack/react-query": "^5.105.2",
19+
"@tanstack/react-query-devtools": "^5.105.2",
2020
"jsonc-parser": "^3.3.1",
2121
"openapi-fetch": "^0.17.0",
2222
"openapi-react-query": "^0.5.4"
@@ -34,13 +34,13 @@
3434
"eslint": "^10.14.0",
3535
"eslint-plugin-react-hooks": "^7.1.1",
3636
"eslint-plugin-react-refresh": "^0.5.7",
37-
"i18next": "^26.5.12",
37+
"i18next": "^26.6.0",
3838
"i18next-browser-languagedetector": "^8.2.4",
39-
"lucide-react": "^1.65.0",
39+
"lucide-react": "^1.66.0",
4040
"react": "^19.3.1",
4141
"react-dom": "^19.3.1",
4242
"react-hook-form": "^7.91.0",
43-
"react-i18next": "^17.1.10",
43+
"react-i18next": "^17.1.12",
4444
"react-router-dom": "^7.18.5",
4545
"socket.io-client": "^4.8.4",
4646
"tsx": "^4.23.15",

‎admin/src/pages/UpdatePage.tsx‎

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,14 @@ export const UpdatePage = () => {
137137
&& !us.lockHeld
138138
&& !upToDate;
139139
const showCancel = status === 'preflight' || status === 'draining' || status === 'scheduled';
140-
const showAcknowledge = status === 'preflight-failed' || status === 'rolled-back' || status === 'rollback-failed';
140+
// A stuck pending-verification for the version that is running resolves
141+
// itself server-side (#8412). One for another version means the update
142+
// didn't take, so let the admin clear it.
143+
const pendingTag = status === 'pending-verification'
144+
? (us.execution as {targetTag: string}).targetTag : null;
145+
const showAcknowledge = status === 'preflight-failed' || status === 'rolled-back' ||
146+
status === 'rollback-failed' ||
147+
(pendingTag != null && pendingTag.replace(/^v/, '') !== us.currentVersion);
141148

142149
// Optional-chain the execution lookup: some integration-test stubs of
143150
// /admin/update/status omit Tier 2/3 fields entirely (see

‎bin/package.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "bin",
3-
"version": "3.3.13",
3+
"version": "3.3.14",
44
"description": "",
55
"main": "checkAllPads.js",
66
"directories": {

‎doc/admin/updates.md‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ Etherpad applies an update by **exiting with code 75** so a process supervisor r
138138
### What clicking "Apply update" does
139139

140140
1. **Lock acquire** — `var/update.lock` (PID-based, stale locks reaped automatically).
141-
2. **Pre-flight checks** — install method writable, working tree clean, free disk ≥ `diskSpaceMinMB`, `pnpm` on `PATH`, no lock held, target tag exists at the configured remote, signature verifies (if `requireSignature: true`), and the target's Node engine matches the running Node. The Node-engine check runs *after* signature verification (so the `engines.node` range comes from a trusted tag): Etherpad reads `engines.node` from the target tag's `package.json` via `git show <tag>:package.json` and refuses the update via `semver.satisfies` if the running Node does not satisfy it. On failure, state goes to `preflight-failed` with a typed reason; the admin sees a banner and clicks **Acknowledge** to clear it. No filesystem mutation has happened — nothing to roll back.
141+
2. **Pre-flight checks** — install method writable, working tree clean (files the updater itself writes under `var/` — `update.lock`, `update-state.json`, `update-backup/`, `log/` — are ignored), free disk ≥ `diskSpaceMinMB`, `pnpm` on `PATH`, no lock held, target tag exists at the configured remote, signature verifies (if `requireSignature: true`), and the target's Node engine matches the running Node. The Node-engine check runs *after* signature verification (so the `engines.node` range comes from a trusted tag): Etherpad reads `engines.node` from the target tag's `package.json` via `git show <tag>:package.json` and refuses the update via `semver.satisfies` if the running Node does not satisfy it. On failure, state goes to `preflight-failed` with a typed reason; the admin sees a banner and clicks **Acknowledge** to clear it. No filesystem mutation has happened — nothing to roll back.
142142
3. **Drain** — `drainSeconds` window during which T-60 / T-30 / T-10 announcements broadcast to every connected pad and new socket connections are refused. Click **Cancel** during this window to abort cleanly.
143143
4. **Execute** — `git fetch --tags origin`, `git checkout <tag>`, `pnpm install --frozen-lockfile`, `pnpm run build:ui`. Output streams to `var/log/update.log` (rotated 10 MB × 5).
144144
5. **Exit 75** — the supervisor restarts on the new version.
@@ -154,6 +154,7 @@ Etherpad applies an update by **exiting with code 75** so a process supervisor r
154154
| `pnpm install` or `pnpm run build:ui` fails | `rolled-back` | Same as above. The lockfile and SHA are restored. |
155155
| `/health` doesn't come up within `rollbackHealthCheckSeconds` | `rolled-back` | Same — RollbackHandler restores the previous SHA + lockfile and exits 75 again. |
156156
| The new version crashes at boot more than twice (`bootCount > 2`) | `rolled-back` | Crash-loop guard kicks in regardless of the health-check timer. |
157+
| Status stays on `pending-verification` although the server is up and serving | `verified` or `pending-verification` | If the running version is the target, the status changes to `verified` on its own. If not, the update didn't take: click **Acknowledge** to return to `idle`. |
157158
| Rollback itself fails (e.g., `pnpm install` errors restoring old lockfile) | `rollback-failed` | **Manual intervention required.** The admin banner switches to a strong red alert. Restore the install by hand, then click **Acknowledge** to clear the lock and re-allow Tier 2 attempts. |
158159

159160
### Endpoints
@@ -162,7 +163,7 @@ All Tier 2 endpoints require an authenticated admin session (`is_admin: true`) r
162163

163164
- `POST /admin/update/apply` — start an apply. Returns `202 {accepted, drainEndsAt}` once the drain begins. Body unused.
164165
- `POST /admin/update/cancel` — cancel during pre-flight or drain. Returns `409` once the executor has begun mutating the filesystem (state machine guarantees we either complete or roll back from there).
165-
- `POST /admin/update/acknowledge` — clear a terminal `preflight-failed` / `rolled-back` / `rollback-failed` state back to `idle`.
166+
- `POST /admin/update/acknowledge` — clear a terminal `preflight-failed` / `rolled-back` / `rollback-failed` state back to `idle`. Also clears a `pending-verification` state that is left over once the server is already up (no boot health check armed); while the health check is still running it returns 409.
166167
- `GET /admin/update/log` — tail the last 200 lines of `var/log/update.log`. Plain text. Used by the in-progress UI.
167168

168169
### Signature verification

‎package.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,6 @@
5252
"url": "https://github.com/ether/etherpad.git"
5353
},
5454
"engineStrict": true,
55-
"version": "3.3.13",
55+
"version": "3.3.14",
5656
"license": "Apache-2.0"
5757
}

0 commit comments

Comments
 (0)