From d2ad06aa4e62bd6db3731e436173fc6c01c605fa Mon Sep 17 00:00:00 2001 From: master3395 Date: Fri, 6 Mar 2026 20:26:15 +0100 Subject: [PATCH] Plugin install: pass absolute zip path to avoid cwd races; extract always uses given path --- pluginHolder/views.py | 45 +++++++++++++----------------- pluginInstaller/pluginInstaller.py | 12 +++++--- 2 files changed, 27 insertions(+), 30 deletions(-) diff --git a/pluginHolder/views.py b/pluginHolder/views.py index 166a4f0f5..c3527e181 100644 --- a/pluginHolder/views.py +++ b/pluginHolder/views.py @@ -607,19 +607,16 @@ def install_plugin(request, plugin_name): 'error': f'Failed to create zip file for {plugin_name}' }, status=500) - # Copy zip to current directory (pluginInstaller expects it in cwd) + zip_path_abs = os.path.abspath(zip_path) + if not os.path.exists(zip_path_abs): + raise Exception(f'Zip file not found: {zip_path_abs}') original_cwd = os.getcwd() os.chdir(temp_dir) try: - # Verify zip file exists in current directory - zip_file = plugin_name + '.zip' - if not os.path.exists(zip_file): - raise Exception(f'Zip file {zip_file} not found in temp directory') - - # Install using pluginInstaller + # Install using pluginInstaller with explicit zip path (avoids cwd races) try: - pluginInstaller.installPlugin(plugin_name) + pluginInstaller.installPlugin(plugin_name, zip_path=zip_path_abs) except Exception as install_error: # Log the full error for debugging error_msg = str(install_error) @@ -1495,20 +1492,18 @@ def upgrade_plugin(request, plugin_name): logging.writeToFile(f"Created plugin ZIP: {zip_path}") - # Copy ZIP to current directory (pluginInstaller expects it in cwd) + zip_path_abs = os.path.abspath(zip_path) + if not os.path.exists(zip_path_abs): + raise Exception(f'Zip file not found: {zip_path_abs}') original_cwd = os.getcwd() os.chdir(temp_dir) try: - zip_file = plugin_name + '.zip' - if not os.path.exists(zip_file): - raise Exception(f'Zip file {zip_file} not found in temp directory') + logging.writeToFile(f"Upgrading plugin using pluginInstaller (zip={zip_path_abs})") - logging.writeToFile(f"Upgrading plugin using pluginInstaller") - - # Install using pluginInstaller (this will overwrite existing files) + # Install using pluginInstaller with explicit zip path (this will overwrite existing files) try: - pluginInstaller.installPlugin(plugin_name) + pluginInstaller.installPlugin(plugin_name, zip_path=zip_path_abs) except Exception as install_error: error_msg = str(install_error) logging.writeToFile(f"pluginInstaller.installPlugin raised exception: {error_msg}") @@ -1775,21 +1770,20 @@ def install_from_store(request, plugin_name): logging.writeToFile(f"Created plugin ZIP: {zip_path}") - # Copy ZIP to current directory (pluginInstaller expects it in cwd) + if not os.path.exists(zip_path): + raise Exception(f'Zip file not found: {zip_path}') + + # Pass absolute path so extraction does not depend on cwd (installPlugin may change cwd) + zip_path_abs = os.path.abspath(zip_path) original_cwd = os.getcwd() os.chdir(temp_dir) try: - # Verify zip file exists in current directory - zip_file = plugin_name + '.zip' - if not os.path.exists(zip_file): - raise Exception(f'Zip file {zip_file} not found in temp directory') + logging.writeToFile(f"Installing plugin using pluginInstaller (zip={zip_path_abs})") - logging.writeToFile(f"Installing plugin using pluginInstaller") - - # Install using pluginInstaller (direct call, not via command line) + # Install using pluginInstaller with explicit zip path (avoids cwd races) try: - pluginInstaller.installPlugin(plugin_name) + pluginInstaller.installPlugin(plugin_name, zip_path=zip_path_abs) except Exception as install_error: # Log the full error for debugging error_msg = str(install_error) @@ -1808,7 +1802,6 @@ def install_from_store(request, plugin_name): # Verify plugin was actually installed pluginInstalled = '/usr/local/CyberCP/' + plugin_name if not os.path.exists(pluginInstalled): - # Check if files were extracted to root instead root_files = ['README.md', 'apps.py', 'meta.xml', 'urls.py', 'views.py'] found_root_files = [f for f in root_files if os.path.exists(os.path.join('/usr/local/CyberCP', f))] if found_root_files: diff --git a/pluginInstaller/pluginInstaller.py b/pluginInstaller/pluginInstaller.py index b0c5070c3..67d0c160e 100644 --- a/pluginInstaller/pluginInstaller.py +++ b/pluginInstaller/pluginInstaller.py @@ -60,13 +60,17 @@ class pluginInstaller: ### Functions Related to plugin installation. @staticmethod - def extractPlugin(pluginName): + def extractPlugin(pluginName, zip_path=None): """ Extract plugin zip so that all files end up in /usr/local/CyberCP/pluginName/. Handles zips with: (1) top-level folder pluginName/, (2) top-level folder with another name (e.g. repo-main/), or (3) files at root (no top-level folder). + If zip_path is given (absolute path), use it; otherwise use pluginName + '.zip' in cwd. """ - pathToPlugin = pluginName + '.zip' + if zip_path is not None: + pathToPlugin = os.path.abspath(zip_path) + else: + pathToPlugin = os.path.abspath(pluginName + '.zip') if not os.path.exists(pathToPlugin): raise Exception(f"Plugin zip not found: {pathToPlugin}") pluginPath = '/usr/local/CyberCP/' + pluginName @@ -245,12 +249,12 @@ class pluginInstaller: @staticmethod - def installPlugin(pluginName): + def installPlugin(pluginName, zip_path=None): try: ## pluginInstaller.stdOut('Extracting plugin..') - pluginInstaller.extractPlugin(pluginName) + pluginInstaller.extractPlugin(pluginName, zip_path=zip_path) pluginInstaller.stdOut('Plugin extracted.') ##