Install visualization plugins to config/plugins before staging

Move npm package installation back from static/plugins to config/plugins
to improve security by following the principle of least exposure. With
the recent change from 25.0, entire npm packages were installed directly
to the web-served static directory, exposing package metadata, source
files, and potentially sensitive content to web access.

This swaps us back to:
- Install npm visualization packages to config/plugins/visualizations/
- Stage only /static subdirectories to the served location
- Maintain separation between installation (private) and serving (public) locations

This brings back a reduced attack surface by ensuring only intended
static assets are web-accessible, while keeping package contents, build
artifacts, and metadata in non-served directories.
This commit is contained in:
Dannon Baker
2025-08-19 09:04:40 -04:00
parent 724d629c8f
commit 7fc065e10e
+1 -16
View File
@@ -63,26 +63,11 @@ function stagePlugins(callback) {
// Flatten the glob patterns to actual directory paths
const dirs = [...globSync(visualizationDirs)];
// Get list of installed visualization plugin names to filter out
const installedVisualizationNames = Object.keys(VISUALIZATION_PLUGINS);
// Process each directory
const copyPromises = dirs.map((sourceDir) => {
// Get the relative path from the plugin base dir
const relativeDir = path.relative(PATHS.pluginBaseDir, sourceDir);
// Extract the plugin name from the path (e.g., "visualizations/myvis/static" -> "myvis")
const pathParts = relativeDir.split(path.sep);
const pluginName = pathParts[1]; // visualizations/[pluginName]/static
// Skip if this is an installed visualization plugin
if (installedVisualizationNames.includes(pluginName)) {
console.log(`Skipping plugin staging for '${pluginName}' (already installed via npm package)`);
return Promise.resolve();
} else {
console.log(`Staging filesystem plugin '${pluginName}' from ${sourceDir}`);
}
// The target should preserve the full path including 'static'
const targetDir = path.join(staticPluginDir, relativeDir);
@@ -117,7 +102,7 @@ function stagePlugins(callback) {
* Produce plugins from fully self-contained npm packages
*/
async function installVisualizations(callback, forceReinstall = false) {
const visualizationsDir = path.join(staticPluginDir, "visualizations");
const visualizationsDir = path.join(PATHS.pluginBaseDir, "visualizations");
fs.ensureDirSync(visualizationsDir);
for (const pluginName of Object.keys(VISUALIZATION_PLUGINS)) {
const { package: pluginPackage, version } = VISUALIZATION_PLUGINS[pluginName];