Expose plugin settings through the CommonJS Settings API - #8113
AkprasadoP wants to merge 1 commit into
Conversation
PR Summary by QodoResync CommonJS Settings exports after reload to expose ep_* plugin settings
AI Description
Diagram
High-Level Assessment
Files changed (2)
|
Code Review by Qodo
1.
|
Code Review by Qodo
1. Test leaks settings state
|
| } finally { | ||
| delete process.env[envKey]; | ||
| if (saved === undefined) { | ||
| delete settingsMod.ep_test_plugin; | ||
| } else { | ||
| settingsMod.ep_test_plugin = saved; |
There was a problem hiding this comment.
1. Test leaks settings state 🐞 Bug ☼ Reliability
The new regression test attempts to clean up by deleting settingsMod.ep_test_plugin, but that deletes the export property rather than reliably removing the backing settings key created by reloadSettings(). Because reloadSettings()/storeSettings() never clears keys absent from the loaded sources, ep_test_plugin can persist and contaminate subsequent tests; additionally, the env var is not restored if it previously existed.
Agent Prompt
### Issue description
The new test mutates `process.env` and the Settings singleton, but its cleanup is incomplete:
- It unconditionally `delete`s the env var instead of restoring any previous value.
- It `delete`s `settingsMod.ep_test_plugin` (an export property), which does not reliably restore the underlying `settings` object state created by `reloadSettings()`. Because `storeSettings()` never deletes missing keys, the plugin key can persist across the rest of the suite.
### Issue Context
`reloadSettings()` calls `storeSettings(settingsParsed)`/`storeSettings(credentials)` and those functions only iterate over keys present in the parsed objects; they do not remove old keys.
### Fix Focus Areas
- src/tests/backend/specs/settings.ts[154-187]
- src/node/utils/Settings.ts[962-990]
- src/node/utils/Settings.ts[1190-1195]
### Suggested fix pattern
- Save the original env value: `const originalEnv = process.env[envKey]; const hadEnv = Object.prototype.hasOwnProperty.call(process.env, envKey);`
- In `finally`, restore it: if (hadEnv) process.env[envKey] = originalEnv; else delete process.env[envKey];
- Restore/remove the backing key on the actual settings object (likely `settingsMod.default ?? settingsMod`):
- If it previously existed, set it back.
- If it didn’t, `delete (settingsMod.default ?? settingsMod).ep_test_plugin;`
- Then call `reloadSettings()`.
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
Synchronize CommonJS Settings getters after each settings reload so plugin-specific ep_* hashes loaded from configuration are accessible directly to plugins.
232dccd to
e825afc
Compare
The entry had landed under the already-released 3.3.4 section after rebase. Also reference #8109 (the canonical issue for this root cause), credit @mathewcsims and @AkprasadoP (#8113), and assert the ep_* key is enumerable on the CJS export and returns the live settings object. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012kA75NPq8nGRidAwhPXeCi
#8155) * fix(settings): expose plugin ep_* config blocks to CJS require (#8110) Plugins read their own configuration from a top-level `ep_*` block in settings.json via `require('ep_etherpad-lite/node/utils/Settings')`. The CJS-compatibility shim added in #7421 installs accessor properties on `module.exports` for `Object.keys(settings)` — but it ran exactly once, at module-evaluation time, and `ep_*` blocks are only merged onto the settings object later, by the `reloadSettings()` call at the bottom of that same module. No accessor was ever defined for them, so every plugin config block was invisible to the require() path; the value was reachable only under `.default`. Consequence: every plugin that reads `settings.ep_<name>` silently ran on its built-in defaults. The reported symptom is ep_hash_auth, whose `hash_dir` reverted to `/var/etherpad/users`, so every hash lookup failed, the `authenticate` hook returned false, core's basic-auth fallback found no `password` on the settings.json user, and admin login answered 401. Note the `authenticate` hook itself was never the problem — /admin-auth/ is handled by webaccess.checkAccess like any other path and does call the hook. Extract the shim into `syncCjsExports()` and re-run it at the end of `reloadSettings()`, so keys that only exist because the operator put them in settings.json get accessors as soon as they are loaded. Reported by @tris-ots. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013WTrZxkTJhiH1p7RuAx3NJ * fix(settings): move changelog entry to 3.3.6, link #8109, tighten test The entry had landed under the already-released 3.3.4 section after rebase. Also reference #8109 (the canonical issue for this root cause), credit @mathewcsims and @AkprasadoP (#8113), and assert the ep_* key is enumerable on the CJS export and returns the live settings object. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012kA75NPq8nGRidAwhPXeCi --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
What
Synchronize the CommonJS Settings compatibility getters after settings are loaded or reloaded.
Why
Plugin-specific
ep_*settings hashes are added after the original one-time CJS mirror is created. Plugins using the documentedrequire('ep_etherpad-lite/node/utils/Settings')API therefore receiveundefinedfor their own configuration.Changes
reloadSettings().ep_*settings hash loaded through environment configuration.Fixes #8109
Tests
NODE_ENV=production npx mocha --import=tsx --timeout 120000 --extension ts tests/backend/specs/settings.tstsc --noEmitNote: ESLint could not be run locally due to the existing ESLint/package compatibility mismatch.