From 2668dc37256265ab0d04262e68b11922196b6c02 Mon Sep 17 00:00:00 2001 From: John McLear Date: Mon, 18 May 2026 13:28:57 +0100 Subject: [PATCH] ci: swap deprecated ep_readonly_guest for ep_guest in plugin matrix MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ep_readonly_guest is archived (read-only on GitHub) and its authenticate hook unconditionally swaps req.session.user with a read-only guest, even when the request carries an HTTP Authorization header. That silently demoted admin login attempts and stalled the anonymizeAuthorSocket tests for 14 min/run on every with-plugins CI matrix (#7795). The pre-fix theory blamed ep_hash_auth.handleMessage; the actual hook trace is a red herring — handleMessage only fires on the /pad namespace and never on /settings. ep_guest is the maintained successor (same authors, same purpose). 1.0.72 on npm already includes the "defer to basic auth / admin paths" fix backported to ep_readonly_guest by intent here. Swapping the matrix unblocks the anonymizeAuthorSocket suite on Linux, Windows, and the upgrade-from-latest-release workflow. The runtime probe added in #7796 stays — it still catches any other authenticate-hook plugin that rejects the test's plain-text credentials (e.g. a future ep_hash_auth-style hashed-only plugin). Reattribute its comment so future readers don't chase ep_hash_auth. Closes #7795. Co-Authored-By: Claude Opus 4.7 (1M context) --- .github/workflows/backend-tests.yml | 4 ++-- .github/workflows/frontend-tests.yml | 4 ++-- .github/workflows/load-test.yml | 2 +- .../workflows/upgrade-from-latest-release.yml | 2 +- .../specs/admin/anonymizeAuthorSocket.ts | 23 +++++++++++-------- 5 files changed, 20 insertions(+), 15 deletions(-) diff --git a/.github/workflows/backend-tests.yml b/.github/workflows/backend-tests.yml index c4f8618bcba..10562bd52af 100644 --- a/.github/workflows/backend-tests.yml +++ b/.github/workflows/backend-tests.yml @@ -146,7 +146,7 @@ jobs: ep_hash_auth ep_headings2 ep_markdown - ep_readonly_guest + ep_guest ep_set_title_on_pad ep_spellcheck ep_subscript_and_superscript @@ -289,7 +289,7 @@ jobs: ep_hash_auth ep_headings2 ep_markdown - ep_readonly_guest + ep_guest ep_set_title_on_pad ep_spellcheck ep_subscript_and_superscript diff --git a/.github/workflows/frontend-tests.yml b/.github/workflows/frontend-tests.yml index 81029f00cb2..19fa6da3f03 100644 --- a/.github/workflows/frontend-tests.yml +++ b/.github/workflows/frontend-tests.yml @@ -219,7 +219,7 @@ jobs: ep_hash_auth ep_headings2 ep_markdown - ep_readonly_guest + ep_guest ep_set_title_on_pad ep_spellcheck ep_subscript_and_superscript @@ -308,7 +308,7 @@ jobs: ep_hash_auth ep_headings2 ep_markdown - ep_readonly_guest + ep_guest ep_set_title_on_pad ep_spellcheck ep_subscript_and_superscript diff --git a/.github/workflows/load-test.yml b/.github/workflows/load-test.yml index 29311e09386..8b1b3f3f8f0 100644 --- a/.github/workflows/load-test.yml +++ b/.github/workflows/load-test.yml @@ -93,7 +93,7 @@ jobs: ep_hash_auth ep_headings2 ep_markdown - ep_readonly_guest + ep_guest ep_set_title_on_pad ep_spellcheck ep_subscript_and_superscript diff --git a/.github/workflows/upgrade-from-latest-release.yml b/.github/workflows/upgrade-from-latest-release.yml index 432e94db7b6..c3ef545f519 100644 --- a/.github/workflows/upgrade-from-latest-release.yml +++ b/.github/workflows/upgrade-from-latest-release.yml @@ -76,7 +76,7 @@ jobs: ep_hash_auth ep_headings2 ep_markdown - ep_readonly_guest + ep_guest ep_set_title_on_pad ep_spellcheck ep_subscript_and_superscript diff --git a/src/tests/backend/specs/admin/anonymizeAuthorSocket.ts b/src/tests/backend/specs/admin/anonymizeAuthorSocket.ts index a0de7349527..25f9f32ebf2 100644 --- a/src/tests/backend/specs/admin/anonymizeAuthorSocket.ts +++ b/src/tests/backend/specs/admin/anonymizeAuthorSocket.ts @@ -62,17 +62,21 @@ const ask = (socket: any, evt: string, payload: any, replyEvt: string) => }); // adminSocket() depends on Etherpad's default plain-text password check for -// settings.users[name].password. Plugins like ep_hash_auth replace the -// authenticate hook to expect hashed credentials, so the basic-auth probe -// returns no admin session, /settings's connection handler returns without +// settings.users[name].password. Any authenticate-hook plugin that claims +// the request before the built-in basic-auth fallback can block this: +// the historical offender was ep_readonly_guest, whose authenticate hook +// sorts itself first and silently swaps req.session.user with a guest +// (#7795); ep_hash_auth-style plugins that expect hashed credentials +// would do the same. When that happens the basic-auth probe returns no +// admin session, /settings's connection handler returns without // registering listeners (see src/node/hooks/express/adminsettings.ts:25), // and every socket.emit() afterwards waits forever for a reply that // nothing will ever send. The socket itself still connects when admin // session is missing, so the probe has to run at the application layer: -// emit a known `/settings` event (`load`) and wait for the matching reply -// (`settings`). If it doesn't arrive within the budget, skip — much -// cheaper than letting mocha's 120s per-test timeout absorb 7 stalled -// tests. Tracked in #7795. +// emit a known `/settings` event (`authorLoad`) and wait for the matching +// reply (`results:authorLoad`). If it doesn't arrive within the budget, +// skip — much cheaper than letting mocha's 120s per-test timeout absorb +// 7 stalled tests. const PROBE_BUDGET_MS = 15000; const adminSocketWithProbe = async (budgetMs: number): Promise<{ ok: true; socket: any; @@ -135,8 +139,9 @@ describe(__filename, function () { if (!probe.ok) { console.warn( `[anonymizeAuthorSocket] admin socket probe failed (${probe.reason}); ` + - 'skipping suite — likely an authenticate-hook plugin (e.g. ep_hash_auth) ' + - 'rejecting the test\'s plain-text admin credentials. Tracked in #7795.'); + 'skipping suite — an authenticate-hook plugin (e.g. ep_readonly_guest, ' + + 'or an ep_hash_auth-style plugin requiring hashed credentials) is ' + + 'rejecting the test\'s plain-text admin credentials.'); this.skip(); return; }