mirror of
https://github.com/ether/etherpad-lite.git
synced 2026-05-06 04:36:17 +02:00
* feat(packaging): publish Etherpad as a Snap Adds first-class Snap packaging so Ubuntu / snapd users can install via `sudo snap install etherpad-lite`. - snap/snapcraft.yaml — core24, strict confinement, builds with pnpm against a pinned Node.js 22 runtime. Version is auto-derived from src/package.json so `snap info` tracks upstream release numbering. - snap/local/bin/etherpad-service — launch wrapper that seeds $SNAP_COMMON/etc/settings.json on first run (rewriting the default dirty-DB path to a writable $SNAP_COMMON location) and execs Etherpad via `node --import tsx/esm`. - snap/local/bin/etherpad-healthcheck-wrapper — HTTP probe for external supervisors, falling back to Node if curl isn't staged. - snap/local/bin/etherpad-cli — thin passthrough to Etherpad's bin/ scripts (importSqlFile, checkPad, etc.). - snap/hooks/configure — exposes `snap set etherpad-lite port=<n>` and `ip=<addr>` with validation, restarts the service when running. - snap/README.md — build / install / configure / publish instructions. - .github/workflows/snap-publish.yml — builds on every v* tag, uploads a short-lived artifact, publishes to `edge`, and then promotes to `stable` through a manually-approved GitHub Environment. Requires a one-time `snapcraft register etherpad-lite` plus provisioning of the `SNAPCRAFT_STORE_CREDENTIALS` repo secret (instructions inline). Pad data (dirty DB, logs) lives in /var/snap/etherpad-lite/common/ and survives snap refreshes. The read-only $SNAP squashfs is never written to at runtime. Refs #7529 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(snap): pass --settings flag, env-subst ip/port, 2-space indent Addresses Qodo review feedback on #7558: 1. Settings file ignored: Etherpad's Settings loader reads `argv.settings`, not the `EP_SETTINGS` env var. Without `--settings`, the launcher's seeded $SNAP_COMMON/etc/settings.json is never loaded; Etherpad falls back to <install-root>/settings.json, which lives on the read-only squashfs — so the default dirty-DB path ends up unwritable and the daemon fails to persist pads. Fix: pass `--settings "${SETTINGS}"` to node; drop the EP_SETTINGS export. 2. `snap set` overrides were no-ops: the seeded settings.json carries the template's literal `"ip": "0.0.0.0"` / `"port": 9001` values, which override the env-based defaults Etherpad exposes via ${…} substitution. Users following the README saw the listener stay put after `snap set etherpad-lite port=…`. Fix: after copying the template on first run, rewrite the top-level `ip` and `port` lines to `"${IP:0.0.0.0}"` / `"${PORT:9001}"`. Use `0,/…/` anchors so the `dbSettings.port` entry further down stays literal. 3. Indentation: reflow the new shell scripts from 4-space to 2-space to match the repo style rule. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(snap): default seeded settings to sqlite, not dirty settings.json.template's own comment says dirty is for testing only. A Snap install is the "not testing" case — shipping it by default means every `sudo snap install etherpad-lite` starts on a DB the project explicitly recommends against. Rewrite the postinstall sed to switch dbType: "dirty" → "sqlite" and point filename at $SNAP_COMMON/var/etherpad.db. sqlite is already shipped in-tree via ueberdb2 → rusty-store-kv (prebuilt napi-rs binary, no build deps), so this works under strict confinement with zero snap.yaml changes. Only affects first-run seeding; existing $SNAP_COMMON/etc/settings.json is never touched on refresh. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(snap): rename to "etherpad", glob tag filter, harden cli - Snap is registered as `etherpad` (the project's only name) — drops the legacy `etherpad-lite` from the name, app, paths, install dir, configure hook, README and workflow artifact. The daemon app shares the snap name, so `snap install etherpad` exposes a bare `etherpad` command; the bin/ passthrough is now `etherpad.cli`. - snap-publish.yml: GitHub Actions tag filters use globs, not regex. The prior `v?[0-9]+.[0-9]+.[0-9]+` pattern would never match a real release tag (Qodo review). Replace with two glob entries covering `vX.Y.Z` and `X.Y.Z`. - etherpad-cli: reject path-traversal in the `<bin-script>` arg (anything containing `/`, `..`, or empty) and add a default `*)` case so files with unsupported extensions fail loud instead of silently exiting 0 (Qodo review). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(snap): unbreak build — refresh corepack, drop pnpm prune Two issues hit on the first real `snapcraft pack` of this recipe: - `corepack prepare pnpm@10.33.0 --activate` failed with `Cannot find matching keyid` because Node 22.12's bundled corepack ships a stale signing-key list and rejects newer pnpm releases (nodejs/corepack#612). Refresh corepack itself via npm before preparing pnpm. - `pnpm prune --prod` is interactive on workspace projects: it asks "The modules directories will be removed and reinstalled from scratch. Proceed? (Y/n)" and deadlocks on stdin under sudo + tee. Replace it with the explicit "wipe node_modules + prod reinstall" pattern, which is non-interactive, faster (pnpm resolves the prod graph from its CAS cache), and byte-identical in result. Verified locally: `snapcraft pack --destructive-mode` produces `etherpad_2.6.1_amd64.snap` end-to-end in ~3 min. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(snap): unbreak runtime — tsx resolution, var/ writability, env Three runtime crashes surfaced when actually installing the built snap under strict confinement. Fixed each, plus a smoke-test script. - `tsx` is in the `src` workspace's node_modules under pnpm hoisting, not at the snap install root. The wrapper now `cd "${APP_DIR}/src"` and uses bare `--import tsx` (matching `bin/cleanRun.sh`); the prior `--import tsx/esm` triggered ERR_REQUIRE_CYCLE on Etherpad's mixed CJS/ESM source tree. - Etherpad's plugin installer writes `var/installed_plugins.json` via __dirname-relative paths, which resolve to absolute paths inside the read-only snap squashfs (EROFS). snap layouts can't intercept paths inside `$SNAP`, so replace the shipped `var/` dir with a symlink to `/var/snap/etherpad/common/etherpad-app-var/` (auto-created by the wrapper on first run). Persistent state survives `snap refresh`. - Drop the unused `EP_SETTINGS` and `EP_DATA_DIR` env vars from the app's `environment:` block. Etherpad's settings loader doesn't read them — it reads `argv.settings`, which the wrapper already passes via `--settings`. They were producing `[WARN] settings - Unknown Setting` noise on every start. Add `snap/tests/smoke.sh`: rebuild + install + configure test port 9003 + assert listener + curl /health + tail logs. Local verified output: HTTP 200, body {"status":"pass","releaseId":"2.6.1"}, server logs `Etherpad is running` on `http://0.0.0.0:9003/`. .gitignore now excludes destructive-mode build outputs (parts/, stage/, prime/, .craft/, *.snap). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * test(snap): wrapper unit tests, PR CI build, expanded docs Coverage in snap/tests/ (47 assertions, ~5s, no snapd/sudo/network): - test-snapcraft-yaml.sh: required keys, name validity, daemon-app matches snap name, no etherpad-lite regression, env-var whitelist. - test-cli.sh: path-traversal rejection, .ts/.sh dispatch, default-case rejection, no-args usage. - test-configure.sh: port (1-65535) and ip (v4/v6) validation via mocked snapctl. - test-service-bootstrap.sh: first-run seeding from settings.json.template, sed rewrite of dbType/filename/ip/port, writable-dir creation, snapctl override propagation to node env, idempotency on second run, default fallbacks. - run-all.sh: bash -n syntax check on every wrapper + hook, then sources each test file and reports totals. All assertions use port 9003 (project test convention). CI in .github/workflows/snap-build.yml: - Triggers on PR / push-to-develop touching snap/, settings.json.template, or the workflow itself. - Job 1 wrapper-tests: runs run-all.sh. - Job 2 snap-pack: snapcraft pack --destructive-mode, uploads .snap as PR artifact for sideload. - Stays separate from snap-publish.yml (tag-triggered, store-bound). snap/README.md fully rewritten: - User-facing usage, install, configure - Architecture: file layout, var/-symlink rationale, settings.json rewrite rationale, double-pnpm-install rationale, daemon-name-shares- snap-name rationale - Three test layers with exactly when/why to run each - Dev workflow loop - Publishing maintainer setup - Troubleshooting for every failure mode hit during this PR (EROFS, tsx not found, ERR_REQUIRE_CYCLE, snap-store-down, pnpm prune hang) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs(snap): replace dead snapcraft.io/docs/releasing-to-the-snap-store link That URL now 404s. Point at the canonical documentation.ubuntu.com locations instead, broken out into the specific pages a maintainer actually needs: - Register a snap (to claim the name) - snapcraft export-login (to generate the SNAPCRAFT_STORE_CREDENTIALS secret) - Publishing how-to index (root index for everything else) Same fix in the snap-publish.yml header comment. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>