checkPlugin: flag absolute /static/plugins/ asset paths in templates (#5203)#7535
checkPlugin: flag absolute /static/plugins/ asset paths in templates (#5203)#7535JohnMcLear wants to merge 1 commit intodevelopfrom
Conversation
Plugin templates that reference assets as \`/static/plugins/...\` (absolute) silently break any Etherpad instance hosted behind a reverse proxy at a sub-path — the browser resolves the path against the domain root instead of the proxy prefix and the asset 404s. The right form is \`../static/plugins/...\` (relative), which ep_embedmedia PR #4 fixed manually and which #5203 asked for as a mechanical check. Walk \`templates/\` and \`static/\` of the plugin, scan every \`*.ejs\` / \`*.html\` for \`/static/plugins/\` not preceded by a URL scheme, dot, or word char (so \`https://host/static/plugins/...\` and already-correct \`../static/plugins/...\` stay untouched). Warn normally; in \`autofix\` mode rewrite to the relative form in place. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Review Summary by QodoAdd linting for absolute plugin asset paths in templates
WalkthroughsDescription• Add linting check for absolute /static/plugins/ paths in plugin templates • Scan templates/ and static/ directories for .ejs and .html files • Warn when absolute paths found; suggest relative ../static/plugins/ form • Support autofix mode to rewrite paths in place Diagramflowchart LR
A["Plugin templates/static dirs"] -- "scan .ejs/.html files" --> B["Regex check for /static/plugins/"]
B -- "match found" --> C["Warn with fix suggestion"]
C -- "autofix enabled" --> D["Rewrite to ../static/plugins/"]
B -- "no match" --> E["Continue"]
File Changes1. bin/plugins/checkPlugin.ts
|
Code Review by Qodo
1. Autofix breaks static HTML
|
| const templateDirs = ['templates', 'static']; // scan both — static/*.html exists too | ||
| const STATIC_ABS = /(?<![./:\w])\/static\/plugins\//g; | ||
| for (const dir of templateDirs) { | ||
| const abs = `${pluginPath}/${dir}`; | ||
| if (!files.includes(dir)) continue; | ||
| const scanFiles: string[] = []; | ||
| const walk = async (d: string) => { | ||
| for (const entry of await fsp.readdir(d, {withFileTypes: true})) { | ||
| const full = `${d}/${entry.name}`; | ||
| if (entry.isDirectory()) { | ||
| if (entry.name === 'node_modules' || entry.name === '.git') continue; | ||
| await walk(full); | ||
| } else if (/\.(ejs|html)$/.test(entry.name)) { | ||
| scanFiles.push(full); | ||
| } | ||
| } | ||
| }; | ||
| await walk(abs); | ||
| for (const fp of scanFiles) { | ||
| const src = await fsp.readFile(fp, 'utf8'); | ||
| if (!STATIC_ABS.test(src)) continue; | ||
| STATIC_ABS.lastIndex = 0; | ||
| const rel = path.relative(pluginPath, fp); | ||
| logger.warn(`${rel} contains absolute '/static/plugins/...' asset paths; ` + | ||
| 'these break reverse-proxied Etherpad deployments. Use ' + | ||
| "'../static/plugins/...' instead."); | ||
| if (autoFix) { | ||
| logger.info(`Autofixing absolute /static/plugins/ paths in ${rel}`); | ||
| await fsp.writeFile(fp, src.replace(STATIC_ABS, '../static/plugins/')); | ||
| } |
There was a problem hiding this comment.
1. Autofix breaks static html 🐞 Bug ≡ Correctness
In autofix mode, the new scan rewrites "/static/plugins/..." to "../static/plugins/..." in HTML files under a plugin’s static/ directory, but those files are served from /static/plugins/<plugin>/static/... so the rewritten relative URL resolves to a non-existent path and will 404. The warning text also gives the same incorrect remediation guidance for static/*.html as for templates.
Agent Prompt
### Issue description
`checkPlugin` currently applies the same autofix (`/static/plugins/...` -> `../static/plugins/...`) to both `templates/` and `static/` HTML/EJS files. This is correct for templates rendered under pad pages, but **incorrect for HTML served from a plugin’s `static/` directory**, because those pages are loaded from `/static/plugins/<plugin>/static/...` and need different relative paths.
### Issue Context
Etherpad serves plugin static files through the `/static/*` handler (see Minify path rewriting). A one-size-fits-all rewrite to `../static/plugins/` will generate broken URLs for static HTML.
### Fix Focus Areas
- bin/plugins/checkPlugin.ts[377-413]
### Suggested change
- Keep scanning `static/**/*.html` for *warnings*, but either:
- **Do not autofix** files under `static/`, and update the warning message to say “use a relative path appropriate for the file’s location (no leading '/')”, OR
- Implement a separate autofix for `static/**/*.html` that computes the correct relative prefix to `/static/plugins/` based on the file’s depth under the plugin’s `static/` directory.
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
Closes #5203.
Plugin templates that reference assets with absolute paths like
`/static/plugins/ep_foo/x.css` silently break any Etherpad instance
hosted behind a reverse proxy at a sub-path (e.g.
https://example.com/etherpad/pad\) — the browser resolves the path against the domain root instead of the proxy prefix and the asset 404s. The correct form is `../static/plugins/...` (relative). [ep_embedmedia#4](https://github.com/ether/ep_embedmedia/pull/4/files) fixed one plugin manually; #5203 asked for a mechanical check.Summary
\\"https://host/static/plugins/...\\"and already-correct `../static/plugins/...` don't match.Test plan