Fix auto-updater running git against web root instead of source repo

NOVACPX_ROOT (/srv/novacpx/public) is a deployed file copy, not a git
repo — hence 'fatal: not a git repository'. The actual git clone lives
at /opt/novacpx-src (installed by the installer).

check-update and apply-update now use /opt/novacpx-src for all git
operations. apply-update also deploys the pulled files back to the web
root with cp -a (public/, api/, lib/, bin/) and re-sets ownership.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-09 13:12:20 +00:00
parent 7e89ab6709
commit 667f3b3a3c
+20 -9
View File
@@ -39,11 +39,11 @@ match ($action) {
// ── Check for updates ───────────────────────────────────────────────────── // ── Check for updates ─────────────────────────────────────────────────────
'check-update' => (function() use ($db) { 'check-update' => (function() use ($db) {
Auth::getInstance()->require('admin'); Auth::getInstance()->require('admin');
$remote = $db->fetchOne("SELECT value FROM settings WHERE `key` = 'git_remote'"); // Source repo is at /opt/novacpx-src — the web root is a deployed copy, not a git repo
$gitRemote = $remote['value'] ?? ''; $srcDir = '/opt/novacpx-src';
if (!$gitRemote) Response::error('No git remote configured'); if (!is_dir($srcDir . '/.git')) Response::error('Source repository not found at ' . $srcDir . '. Re-run the installer to restore it.');
$output = shell_exec("git -C " . escapeshellarg(NOVACPX_ROOT) . " fetch origin 2>&1 && git -C " . escapeshellarg(NOVACPX_ROOT) . " log HEAD..origin/main --oneline 2>/dev/null"); $output = shell_exec("git -C " . escapeshellarg($srcDir) . " fetch origin 2>&1 && git -C " . escapeshellarg($srcDir) . " log HEAD..origin/main --oneline 2>/dev/null");
$updates = array_values(array_filter(explode("\n", trim($output ?: '')))); $updates = array_values(array_filter(explode("\n", trim($output ?: ''))));
Response::success([ Response::success([
@@ -55,16 +55,27 @@ match ($action) {
// ── Apply update ────────────────────────────────────────────────────────── // ── Apply update ──────────────────────────────────────────────────────────
'apply-update' => (function() use ($db) { 'apply-update' => (function() use ($db) {
Auth::getInstance()->require('admin'); Auth::getInstance()->require('admin');
$before = trim(shell_exec("git -C " . escapeshellarg(NOVACPX_ROOT) . " rev-parse HEAD 2>/dev/null") ?: ''); $srcDir = '/opt/novacpx-src';
if (!is_dir($srcDir . '/.git')) Response::error('Source repository not found at ' . $srcDir);
$pull = shell_exec("git -C " . escapeshellarg(NOVACPX_ROOT) . " pull origin main 2>&1"); $before = trim(shell_exec("git -C " . escapeshellarg($srcDir) . " rev-parse HEAD 2>/dev/null") ?: '');
$pull = shell_exec("git -C " . escapeshellarg($srcDir) . " pull origin main 2>&1");
$after = trim(shell_exec("git -C " . escapeshellarg(NOVACPX_ROOT) . " rev-parse HEAD 2>/dev/null") ?: ''); $after = trim(shell_exec("git -C " . escapeshellarg($srcDir) . " rev-parse HEAD 2>/dev/null") ?: '');
$changed = $before !== $after; $changed = $before !== $after;
if ($changed) { if ($changed) {
// Deploy updated files from source repo to web root
$dst = rtrim(NOVACPX_ROOT, '/');
shell_exec("cp -a " . escapeshellarg($srcDir . '/panel/public/.') . " {$dst}/");
shell_exec("cp -a " . escapeshellarg($srcDir . '/panel/api/.') . " {$dst}/api/");
shell_exec("cp -a " . escapeshellarg($srcDir . '/panel/lib/.') . " {$dst}/lib/");
if (is_dir($srcDir . '/panel/bin')) {
shell_exec("cp -a " . escapeshellarg($srcDir . '/panel/bin/.') . " {$dst}/bin/");
}
shell_exec("chown -R www-data:www-data " . escapeshellarg($dst) . " 2>/dev/null");
// Run any pending DB migrations // Run any pending DB migrations
$migrDir = NOVACPX_ROOT . '/db/migrations'; $migrDir = $srcDir . '/db/migrations';
if (is_dir($migrDir)) { if (is_dir($migrDir)) {
foreach (glob("$migrDir/*.sql") as $sql) { foreach (glob("$migrDir/*.sql") as $sql) {
$migName = basename($sql, '.sql'); $migName = basename($sql, '.sql');