From d8c66c4c49dd68cba6134fb6e66c3cfab34ee2d0 Mon Sep 17 00:00:00 2001 From: Frank Harris Date: Sat, 6 Jun 2026 12:21:56 -0500 Subject: [PATCH] update updater --- Panel/modules/administration/panel_update.php | 26 +++++++++++++++---- docs/modules/UPDATE.md | 13 +++++++--- 2 files changed, 31 insertions(+), 8 deletions(-) diff --git a/Panel/modules/administration/panel_update.php b/Panel/modules/administration/panel_update.php index b3bae28e..bb6f0751 100644 --- a/Panel/modules/administration/panel_update.php +++ b/Panel/modules/administration/panel_update.php @@ -163,9 +163,17 @@ return [ function gsp_validate_update_settings(array $cfg) { $errors = []; -if (!preg_match('/^https?:\/\/[^ \t\r\n]+\.git$/i', (string)$cfg['repo_url']) -&& !preg_match('/^(?:ssh:\/\/|git@)[^ \t\r\n]+$/i', (string)$cfg['repo_url'])) { -$errors[] = 'Repository URL must be an http(s), ssh, or git@ URL.'; +$repo_source = trim((string)$cfg['repo_url']); +$is_git_url = preg_match('/^https?:\/\/[^ \t\r\n]+(?:\.git)?$/i', $repo_source) +|| preg_match('/^(?:ssh:\/\/|git@)[^ \t\r\n]+$/i', $repo_source); +$is_local_path = preg_match('/^\//', $repo_source) +&& strpos($repo_source, "\0") === false +&& strpos($repo_source, '..') === false; +if (!$is_git_url && !$is_local_path) { +$errors[] = 'Repository source must be an http(s), ssh, git@ URL, or a safe absolute local path.'; +} +if ($is_local_path && !is_dir($repo_source)) { +$errors[] = 'Repository local path does not exist or is not a directory: ' . $repo_source; } if (!preg_match('/^[A-Za-z0-9._\/-]{1,128}$/', (string)$cfg['branch'])) { $errors[] = 'Branch/channel contains invalid characters.'; @@ -1020,14 +1028,22 @@ $temp_dir = sys_get_temp_dir() . '/gsp_git_' . time() . '_' . mt_rand(1000, 9999 if (!@mkdir($temp_dir, 0750, true)) { return ['success' => false, 'error' => 'Cannot create temporary git checkout directory.']; } +if (!function_exists('exec')) { +gsp_rmdir_recursive($temp_dir); +return ['success' => false, 'error' => 'PHP exec() is disabled, so the updater cannot run git clone.']; +} $out = []; $ret = 0; $cmd = 'git clone --depth 1 --branch ' . escapeshellarg($branch) . ' ' . escapeshellarg($repo_url) . ' ' . escapeshellarg($temp_dir) . ' 2>&1'; +gsp_update_log('Starting configured git checkout from ' . $repo_url . ' branch ' . $branch); exec($cmd, $out, $ret); if ($ret !== 0) { gsp_rmdir_recursive($temp_dir); -return ['success' => false, 'error' => 'git clone failed: ' . implode(' | ', array_slice($out, -20))]; +$tail = implode(' | ', array_slice($out, -20)); +gsp_update_log('Configured git checkout failed from ' . $repo_url . ' branch ' . $branch . ': ' . $tail); +return ['success' => false, 'error' => 'git clone failed for repository source "' . $repo_url . '" branch "' . $branch . '": ' . $tail]; } +gsp_update_log('Configured git checkout completed from ' . $repo_url . ' branch ' . $branch); return ['success' => true, 'temp_dir' => $temp_dir, 'source_root' => $temp_dir, 'output' => implode("\n", $out)]; } @@ -2081,7 +2097,7 @@ echo "

Repository Settings

\n"; echo "
\n"; echo "\n"; echo "\n"; -echo "\n"; +echo "\n"; echo "\n"; echo "\n"; echo "\n"; diff --git a/docs/modules/UPDATE.md b/docs/modules/UPDATE.md index 779cd219..07e9473e 100644 --- a/docs/modules/UPDATE.md +++ b/docs/modules/UPDATE.md @@ -22,7 +22,7 @@ The update page is intentionally simple: The admin page stores these settings in the Panel settings table: -- `gsp_update_repo_url` +- `gsp_update_repo_url` for the repository source. This may be a Git URL or a safe absolute local repository path. - `gsp_update_branch` - `gsp_update_repo_root` - `gsp_update_panel_path` @@ -30,7 +30,7 @@ The admin page stores these settings in the Panel settings table: Defaults: -- Repository URL: `http://forge.runlevelsystems.com/dev/GSP.git` +- Repository URL / Path: `http://forge.runlevelsystems.com/dev/GSP.git` - Branch: `Panel-unstable` - Repository Root: `/var/www/html/GSP` - Panel Path: `/var/www/html/GSP/Panel` @@ -48,7 +48,7 @@ Important implementation note: 2. Validate repository URL, branch, repo root, and Panel path. 3. Run preflight against the configured paths. 4. Create a backup when enabled. -5. Clone the configured repository branch into a temporary checkout. +5. Clone the configured repository source and branch into a temporary checkout. 6. Sync files into the configured root/Panel paths. 7. Preserve `Panel/includes/config.inc.php`. 8. Run module updates/post-update hooks. @@ -64,3 +64,10 @@ The old repeated SSL vhost disable buttons are not part of the primary update pa - The updater still contains legacy GitHub release helper code that is no longer rendered by the simplified primary UI. - Real production testing should confirm file ownership and web-server permissions on `/var/www/html/GSP`. + +## Repair Notes + +- The update page fatal `Call to undefined function gsp_update_settings()` means the deployed `Panel/modules/administration/panel_update.php` is missing the top-level helper or is not the current repository copy. +- `Panel/modules/update/update.php` only loads `Panel/modules/administration/panel_update.php` and calls `gsp_panel_update_section()`. +- The configured update action uses `git clone --depth 1 --branch `. +- Clone failures are logged to `logs/update_trace.log` with the configured repository source and branch.
Repository URL
Repository URL / Path
Branch / Channel
Repository Root
Panel Path