diff --git a/Panel/CHANGELOG.md b/Panel/CHANGELOG.md index eaaf5e99..a15bc6ab 100644 --- a/Panel/CHANGELOG.md +++ b/Panel/CHANGELOG.md @@ -1,6 +1,7 @@ # Changelog ## 2026-05-19 +- **Updater deployment diagnostics + legacy updater Panel path compatibility:** Update UI now surfaces configured stable/unstable branches plus the last resolved temporary checkout/source repo paths used during deployment, and `modules/update/updating.php` now treats `Panel/` and `panel/` zip paths equivalently so legacy update routes no longer skip panel files from current GitHub zip layouts. - **Updater deployment layout enforcement + marker file writes:** Hardened `modules/administration/panel_update.php` to require the live `/var/www/html/GSP` root with explicit `/Panel` and `/Website` destinations, log full source/destination path detection (including temp checkout/source roots), stop on invalid mapping, copy Panel/Website via explicit subtree mapping (preventing nested `Panel/Panel` or `Website/Website`), validate key copied files after sync, and write both `Website/timestamp.txt` and `modules/billing/timestamp.txt` marker files on successful updates. - **Workshop content script path fix:** Updated addonsmanager default Workshop script paths to the panel module script location under `/var/www/html/GSP/Panel/modules/addonsmanager/scripts/workshop/` so Workshop actions no longer use the incorrect game-home-mixed path on the agent host. diff --git a/Panel/docs/COPILOT_TODO.md b/Panel/docs/COPILOT_TODO.md index e3b2e12b..75258766 100644 --- a/Panel/docs/COPILOT_TODO.md +++ b/Panel/docs/COPILOT_TODO.md @@ -22,3 +22,4 @@ - Add localized language strings/tooltips for the new cron scheduler `server_content_*` action labels across all supported panel locales. - Add a Game Manager "Live Server Status" panel that consumes `Panel/protocol/gsp_query.php` and shows banner preview plus copyable embed code. - Add an updater admin UI table that renders the full deployment preflight path map (temp checkout, source repo/panel/website, destination panel/website) directly from the new layout detection payload for one-click operator verification. +- Add an updater integration test fixture that calls both `home.php?m=update` and legacy `home.php?m=update&p=updating&version=` against a `Panel-unstable` zipball and asserts changed `Panel/modules/` files are actually copied. diff --git a/Panel/modules/administration/panel_update.php b/Panel/modules/administration/panel_update.php index 1768fdf9..6cded246 100644 --- a/Panel/modules/administration/panel_update.php +++ b/Panel/modules/administration/panel_update.php @@ -967,6 +967,7 @@ gsp_rmdir_recursive($temp_dir); return ['success' => false, 'error' => 'Deployment layout validation failed: ' . implode(' | ', $resolved_layout['errors'])]; } $layout = $resolved_layout['layout']; +$_SESSION['gsp_last_update_layout'] = $layout; $updater_version = substr((string)@hash_file('sha256', $layout['source_panel_path'] . '/modules/administration/panel_update.php'), 0, 12); $drift_files = gsp_detect_updater_drift_files($layout['source_repo_root'], GSP_ROOT_DIR); @@ -1816,6 +1817,9 @@ $csrf_token = $_SESSION['gsp_update_csrf']; $current_version = gsp_get_current_version(); $current_branch = gsp_get_current_branch(); $git_commit = gsp_get_git_commit(); +$last_layout = isset($_SESSION['gsp_last_update_layout']) && is_array($_SESSION['gsp_last_update_layout']) +? $_SESSION['gsp_last_update_layout'] +: null; $vinfo = gsp_read_version_json(); $releases = gsp_fetch_github_releases($repo_owner, $repo_name); $latest_release = (is_array($releases) && !empty($releases)) ? htmlspecialchars($releases[0]['tag_name']) : 'N/A'; @@ -1836,7 +1840,14 @@ echo "Expected Root:" . htmlspecialchars echo "Detected GSP Root:" . htmlspecialchars(GSP_ROOT_DIR) . "\n"; echo "Panel Path:" . htmlspecialchars(GSP_PANEL_DIR) . "\n"; echo "Website Path:" . htmlspecialchars(GSP_WEBSITE_DIR) . "\n"; +echo "Configured Stable Branch:" . htmlspecialchars($stable_branch) . "\n"; +echo "Configured Unstable Branch:" . htmlspecialchars($unstable_branch) . "\n"; echo "Update Trace Log:" . htmlspecialchars(GSP_UPDATE_LOG) . "\n"; +if ($last_layout) { +echo "Last Temp Checkout Path:" . htmlspecialchars(isset($last_layout['temporary_git_checkout_path']) ? $last_layout['temporary_git_checkout_path'] : '') . "\n"; +echo "Last Source Repo Root:" . htmlspecialchars(isset($last_layout['source_repo_root']) ? $last_layout['source_repo_root'] : '') . "\n"; +echo "Last Source Panel Path:" . htmlspecialchars(isset($last_layout['source_panel_path']) ? $last_layout['source_panel_path'] : '') . "\n"; +} echo "
\n"; echo "

Current Installation

\n"; diff --git a/Panel/modules/update/updating.php b/Panel/modules/update/updating.php index adaa303d..17c6cc79 100644 --- a/Panel/modules/update/updating.php +++ b/Panel/modules/update/updating.php @@ -156,21 +156,20 @@ function exec_ogp_module() $i = 0; foreach ((array)$result['extracted_files'] as $file) { - $filename = str_replace( $unwanted_path, "" , $file['filename'] ); - $filename = str_replace("\\", "/", $filename); - // New repository layout uses /panel as source subtree; ignore everything else. - if (strpos($filename, '/panel/') === 0) { - $filename = substr($filename, strlen('/panel')); - } elseif (strpos($filename, 'panel/') === 0) { - $filename = substr($filename, strlen('panel')); - if ($filename === '' || $filename[0] !== '/') $filename = '/' . $filename; - } else { + $zip_filename = str_replace("\\", "/", $file['filename']); + $source_relative = str_replace( $unwanted_path, "" , $zip_filename ); + $source_relative = ltrim($source_relative, "/"); + // Repository layout uses Panel/ (uppercase in current zipballs, lowercase in some legacy builds). + if (stripos($source_relative, 'panel/') !== 0) { continue; } - if ($filename === '') { + $panel_relative = substr($source_relative, strlen('panel/')); + $panel_relative = ltrim((string)$panel_relative, "/"); + if ($panel_relative === '') { continue; } - $temp_file = $extract_path . DIRECTORY_SEPARATOR . $filename; + $filename = '/' . $panel_relative; + $temp_file = $extract_path . DIRECTORY_SEPARATOR . $source_relative; $web_file = $baseDir . $filename; if( file_exists( $web_file ) )