diff --git a/.mokogitea/CLAUDE.md b/.mokogitea/CLAUDE.md index c3ba57e3..c3c9d03d 100644 --- a/.mokogitea/CLAUDE.md +++ b/.mokogitea/CLAUDE.md @@ -60,7 +60,7 @@ Joomla **package** with four sub-extensions: - **Workflow directory**: `.mokogitea/` (not `.gitea/` or `.github/`) - **Minification**: handled at build time (CI) - **Wiki**: documentation lives in the Gitea wiki, not `docs/` files -- **Standards**: [MokoStandards](https://git.mokoconsulting.tech/MokoConsulting/mokoplatform/wiki/Home) +- **Standards**: [MokoStandards](https://git.mokoconsulting.tech/MokoConsulting/mokocli/wiki/Home) ## Coding Standards diff --git a/.mokogitea/workflows/issue-branch.yml b/.mokogitea/workflows/issue-branch.yml index 11958bdc..b9481096 100644 --- a/.mokogitea/workflows/issue-branch.yml +++ b/.mokogitea/workflows/issue-branch.yml @@ -5,7 +5,7 @@ # FILE INFORMATION # DEFGROUP: Gitea.Workflow # INGROUP: mokocli.Automation -# VERSION: 01.00.00 +# VERSION: 02.56.07 # BRIEF: Auto-create feature branch when an issue is opened name: "Universal: Issue Branch" diff --git a/SECURITY.md b/SECURITY.md index 24afe574..7410ab4b 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -23,7 +23,7 @@ DEFGROUP: Template-Joomla INGROUP: Template-Joomla.Documentation REPO: https://git.mokoconsulting.tech/MokoConsulting/Template-Joomla PATH: /SECURITY.md -VERSION: 02.56.05 +VERSION: 02.56.07 BRIEF: Security vulnerability reporting and handling policy --> diff --git a/source/packages/MokoSuiteClient b/source/packages/MokoSuiteClient index 464b5da9..2273690f 160000 --- a/source/packages/MokoSuiteClient +++ b/source/packages/MokoSuiteClient @@ -1 +1 @@ -Subproject commit 464b5da9293e3560718b7b5fe3cc8267c2ca9ae5 +Subproject commit 2273690f9493c78fd0c3a579d1dbc04897f55e9b diff --git a/source/packages/com_mokosuitebackup/api/src/View/Backups/JsonapiView.php b/source/packages/com_mokosuitebackup/api/src/View/Backups/JsonapiView.php index 147fe924..54e17f8f 100644 --- a/source/packages/com_mokosuitebackup/api/src/View/Backups/JsonapiView.php +++ b/source/packages/com_mokosuitebackup/api/src/View/Backups/JsonapiView.php @@ -24,7 +24,6 @@ class JsonapiView extends BaseApiView 'origin', 'backup_type', 'archivename', - 'absolute_path', 'total_size', 'db_size', 'files_count', diff --git a/source/packages/com_mokosuitebackup/mokosuitebackup.xml b/source/packages/com_mokosuitebackup/mokosuitebackup.xml index 66bfa085..5c55029a 100644 --- a/source/packages/com_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/com_mokosuitebackup/mokosuitebackup.xml @@ -7,7 +7,7 @@ --> Component - MokoSuiteBackup - 02.56.05 + 02.56.07 2026-06-02 Moko Consulting hello@mokoconsulting.tech diff --git a/source/packages/com_mokosuitebackup/sql/uninstall.mysql.sql b/source/packages/com_mokosuitebackup/sql/uninstall.mysql.sql index 2a39ae31..3e68ead9 100644 --- a/source/packages/com_mokosuitebackup/sql/uninstall.mysql.sql +++ b/source/packages/com_mokosuitebackup/sql/uninstall.mysql.sql @@ -1,3 +1,4 @@ DROP TABLE IF EXISTS `#__mokosuitebackup_remotes`; DROP TABLE IF EXISTS `#__mokosuitebackup_records`; +DROP TABLE IF EXISTS `#__mokosuitebackup_snapshots`; DROP TABLE IF EXISTS `#__mokosuitebackup_profiles`; diff --git a/source/packages/com_mokosuitebackup/sql/updates/mysql/02.56.07.sql b/source/packages/com_mokosuitebackup/sql/updates/mysql/02.56.07.sql new file mode 100644 index 00000000..4e5b6aca --- /dev/null +++ b/source/packages/com_mokosuitebackup/sql/updates/mysql/02.56.07.sql @@ -0,0 +1 @@ +/* 02.56.07 — no schema changes */ diff --git a/source/packages/com_mokosuitebackup/src/Controller/AjaxController.php b/source/packages/com_mokosuitebackup/src/Controller/AjaxController.php index c3d396f9..9d568ad7 100644 --- a/source/packages/com_mokosuitebackup/src/Controller/AjaxController.php +++ b/source/packages/com_mokosuitebackup/src/Controller/AjaxController.php @@ -1201,6 +1201,7 @@ class AjaxController extends BaseController private function maskSecrets(array $config, string $type): array { $secrets = [ + 'ftp' => ['password'], 'sftp' => ['password', 'passphrase', 'key_data'], 's3' => ['secret_key'], 'google_drive' => ['client_secret', 'refresh_token'], @@ -1223,6 +1224,7 @@ class AjaxController extends BaseController private function mergeExistingSecrets(int $id, array $config, string $type): array { $secrets = [ + 'ftp' => ['password'], 'sftp' => ['password', 'passphrase', 'key_data'], 's3' => ['secret_key'], 'google_drive' => ['client_secret', 'refresh_token'], diff --git a/source/packages/com_mokosuitebackup/src/Engine/DatabaseDumper.php b/source/packages/com_mokosuitebackup/src/Engine/DatabaseDumper.php index 429e0523..81a2935a 100644 --- a/source/packages/com_mokosuitebackup/src/Engine/DatabaseDumper.php +++ b/source/packages/com_mokosuitebackup/src/Engine/DatabaseDumper.php @@ -326,7 +326,7 @@ class DatabaseDumper } $createSql = str_replace('`' . $prefix, '`#__', $createRow[1]); - fwrite($fp, 'DROP TABLE IF EXISTS `' . $abstractName . "`;\\n"); + fwrite($fp, 'DROP TABLE IF EXISTS `' . $abstractName . "`;\n"); fwrite($fp, $createSql . ";\n\n"); } diff --git a/source/packages/com_mokosuitebackup/src/Engine/DatabaseImporter.php b/source/packages/com_mokosuitebackup/src/Engine/DatabaseImporter.php index af681d5f..5ce1aaa0 100644 --- a/source/packages/com_mokosuitebackup/src/Engine/DatabaseImporter.php +++ b/source/packages/com_mokosuitebackup/src/Engine/DatabaseImporter.php @@ -20,6 +20,13 @@ use Joomla\CMS\Factory; class DatabaseImporter { + /** + * Non-fatal per-statement errors collected during the last import(). + * + * @var string[] + */ + private array $errors = []; + /** * Import a SQL dump file into the database. * @@ -31,6 +38,8 @@ class DatabaseImporter */ public function import(string $sqlFile): int { + $this->errors = []; + if (!is_file($sqlFile) || !is_readable($sqlFile)) { throw new \RuntimeException('SQL file not readable: ' . $sqlFile); } @@ -97,8 +106,10 @@ class DatabaseImporter } catch (\Exception $e) { // Log but don't abort — some statements may fail on // different MySQL versions (e.g. charset differences) - // but the overall restore should continue. + // but the overall restore should continue. Errors are + // collected so the caller can surface a warning status. error_log('MokoSuiteBackup SQL import warning: ' . $e->getMessage()); + $this->errors[] = $e->getMessage(); } } } @@ -115,6 +126,7 @@ class DatabaseImporter $statementsExecuted++; } catch (\Exception $e) { error_log('MokoSuiteBackup SQL import warning (final): ' . $e->getMessage()); + $this->errors[] = $e->getMessage(); } } } finally { @@ -123,4 +135,24 @@ class DatabaseImporter return $statementsExecuted; } + + /** + * Non-fatal errors from the last import(), if any. A non-empty result + * means the restore completed with problems and should be treated as a + * warning rather than a clean success. + * + * @return string[] + */ + public function getErrors(): array + { + return $this->errors; + } + + /** + * Whether the last import() had any non-fatal statement errors. + */ + public function hasErrors(): bool + { + return $this->errors !== []; + } } diff --git a/source/packages/com_mokosuitebackup/src/Engine/SftpUploader.php b/source/packages/com_mokosuitebackup/src/Engine/SftpUploader.php index 980ea4a7..d32f4c64 100644 --- a/source/packages/com_mokosuitebackup/src/Engine/SftpUploader.php +++ b/source/packages/com_mokosuitebackup/src/Engine/SftpUploader.php @@ -207,7 +207,7 @@ class SftpUploader implements RemoteUploaderInterface */ private function buildScpCommand(string $localPath, string $remoteTarget, ?string $keyFile): string { - $parts = ['scp', '-o', 'StrictHostKeyChecking=no', '-o', 'BatchMode=yes']; + $parts = ['scp', '-o', 'StrictHostKeyChecking=accept-new', '-o', 'BatchMode=yes']; if ($this->port !== 22) { $parts[] = '-P'; @@ -235,7 +235,7 @@ class SftpUploader implements RemoteUploaderInterface */ private function buildSshCommand(string $remoteCmd, ?string $keyFile): string { - $parts = ['ssh', '-o', 'StrictHostKeyChecking=no', '-o', 'BatchMode=yes']; + $parts = ['ssh', '-o', 'StrictHostKeyChecking=accept-new', '-o', 'BatchMode=yes']; if ($this->port !== 22) { $parts[] = '-p'; diff --git a/source/packages/mod_mokosuitebackup_cpanel/mod_mokosuitebackup_cpanel.xml b/source/packages/mod_mokosuitebackup_cpanel/mod_mokosuitebackup_cpanel.xml index 8ee0b6ed..d2a2b6b4 100644 --- a/source/packages/mod_mokosuitebackup_cpanel/mod_mokosuitebackup_cpanel.xml +++ b/source/packages/mod_mokosuitebackup_cpanel/mod_mokosuitebackup_cpanel.xml @@ -8,7 +8,7 @@ --> Module - MokoSuiteBackup - cPanel - 02.56.05 + 02.56.07 2026-06-23 Moko Consulting hello@mokoconsulting.tech diff --git a/source/packages/plg_actionlog_mokosuitebackup/mokosuitebackup.xml b/source/packages/plg_actionlog_mokosuitebackup/mokosuitebackup.xml index 8fec08a0..56437f76 100644 --- a/source/packages/plg_actionlog_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/plg_actionlog_mokosuitebackup/mokosuitebackup.xml @@ -7,7 +7,7 @@ --> Action Log - MokoSuiteBackup - 02.56.05 + 02.56.07 2026-06-04 Moko Consulting hello@mokoconsulting.tech diff --git a/source/packages/plg_console_mokosuitebackup/mokosuitebackup.xml b/source/packages/plg_console_mokosuitebackup/mokosuitebackup.xml index 6a59b01d..01016a8e 100644 --- a/source/packages/plg_console_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/plg_console_mokosuitebackup/mokosuitebackup.xml @@ -7,7 +7,7 @@ --> Console - MokoSuiteBackup - 02.56.05 + 02.56.07 2026-06-04 Moko Consulting hello@mokoconsulting.tech diff --git a/source/packages/plg_console_mokosuitebackup/src/Command/SnapshotCommand.php b/source/packages/plg_console_mokosuitebackup/src/Command/SnapshotCommand.php index 9dbf58af..1ae866b6 100644 --- a/source/packages/plg_console_mokosuitebackup/src/Command/SnapshotCommand.php +++ b/source/packages/plg_console_mokosuitebackup/src/Command/SnapshotCommand.php @@ -227,11 +227,11 @@ class SnapshotCommand extends AbstractCommand } // Delete the snapshot file if it exists - if (!empty($record->file_path) && is_file($record->file_path)) { - if (!@unlink($record->file_path)) { - $io->warning('Could not delete snapshot file: ' . $record->file_path); + if (!empty($record->data_file) && is_file($record->data_file)) { + if (!@unlink($record->data_file)) { + $io->warning('Could not delete snapshot file: ' . $record->data_file); } else { - $io->text('Deleted file: ' . $record->file_path); + $io->text('Deleted file: ' . $record->data_file); } } diff --git a/source/packages/plg_content_mokosuitebackup/mokosuitebackup.xml b/source/packages/plg_content_mokosuitebackup/mokosuitebackup.xml index fe4b04af..7e754257 100644 --- a/source/packages/plg_content_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/plg_content_mokosuitebackup/mokosuitebackup.xml @@ -7,7 +7,7 @@ --> Content - MokoSuiteBackup - 02.56.05 + 02.56.07 2026-06-04 Moko Consulting hello@mokoconsulting.tech @@ -59,7 +59,7 @@ type="sql" label="PLG_CONTENT_MOKOJOOMBACKUP_FIELD_PROFILE" description="PLG_CONTENT_MOKOJOOMBACKUP_FIELD_PROFILE_DESC" - query="SELECT id AS value, title AS text FROM #__mokosuitebackup_profiles WHERE published = 1 ORDER BY ordering ASC" + query="SELECT id AS value, title AS text FROM #__mokosuitebackup_profiles WHERE published = 1 ORDER BY id ASC" default="1" > diff --git a/source/packages/plg_content_mokosuitebackup/src/Extension/MokoSuiteBackupContent.php b/source/packages/plg_content_mokosuitebackup/src/Extension/MokoSuiteBackupContent.php index f3f98b0a..4e0654bd 100644 --- a/source/packages/plg_content_mokosuitebackup/src/Extension/MokoSuiteBackupContent.php +++ b/source/packages/plg_content_mokosuitebackup/src/Extension/MokoSuiteBackupContent.php @@ -24,9 +24,11 @@ final class MokoSuiteBackupContent extends CMSPlugin implements SubscriberInterf public static function getSubscribedEvents(): array { + // Pre-update backups are owned by plg_system_mokosuitebackup, which also + // subscribes to onExtensionBeforeUpdate. Only pre-install is handled here + // to avoid running the backup twice on a single extension update. return [ 'onExtensionBeforeInstall' => 'onExtensionBeforeInstall', - 'onExtensionBeforeUpdate' => 'onExtensionBeforeUpdate', ]; } @@ -42,18 +44,6 @@ final class MokoSuiteBackupContent extends CMSPlugin implements SubscriberInterf $this->triggerAutoBackup('Pre-install backup'); } - /** - * Trigger a backup before an extension is updated. - */ - public function onExtensionBeforeUpdate(Event $event): void - { - if (!(int) $this->params->get('backup_before_update', 1)) { - return; - } - - $this->triggerAutoBackup('Pre-update backup'); - } - /** * Run a backup using the configured profile. */ diff --git a/source/packages/plg_quickicon_mokosuitebackup/mokosuitebackup.xml b/source/packages/plg_quickicon_mokosuitebackup/mokosuitebackup.xml index b8d562b5..b3d287d6 100644 --- a/source/packages/plg_quickicon_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/plg_quickicon_mokosuitebackup/mokosuitebackup.xml @@ -1,7 +1,7 @@ Quick Icon - MokoSuiteBackup - 02.56.05 + 02.56.07 2026-06-02 Moko Consulting hello@mokoconsulting.tech diff --git a/source/packages/plg_system_mokosuitebackup/mokosuitebackup.xml b/source/packages/plg_system_mokosuitebackup/mokosuitebackup.xml index 1ec03220..f097c7a8 100644 --- a/source/packages/plg_system_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/plg_system_mokosuitebackup/mokosuitebackup.xml @@ -7,7 +7,7 @@ --> System - MokoSuiteBackup - 02.56.05 + 02.56.07 2026-06-02 Moko Consulting hello@mokoconsulting.tech diff --git a/source/packages/plg_task_mokosuitebackup/forms/run_profile.xml b/source/packages/plg_task_mokosuitebackup/forms/run_profile.xml index cf1fc9cf..8471774f 100644 --- a/source/packages/plg_task_mokosuitebackup/forms/run_profile.xml +++ b/source/packages/plg_task_mokosuitebackup/forms/run_profile.xml @@ -11,7 +11,7 @@ type="sql" label="PLG_TASK_MOKOJOOMBACKUP_FIELD_PROFILE" description="PLG_TASK_MOKOJOOMBACKUP_FIELD_PROFILE_DESC" - query="SELECT id AS value, title AS text FROM #__mokosuitebackup_profiles WHERE published = 1 ORDER BY ordering ASC" + query="SELECT id AS value, title AS text FROM #__mokosuitebackup_profiles WHERE published = 1 ORDER BY id ASC" default="1" required="true" > diff --git a/source/packages/plg_task_mokosuitebackup/mokosuitebackup.xml b/source/packages/plg_task_mokosuitebackup/mokosuitebackup.xml index 0bc36ff2..4aa73a39 100644 --- a/source/packages/plg_task_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/plg_task_mokosuitebackup/mokosuitebackup.xml @@ -7,7 +7,7 @@ --> Task - MokoSuiteBackup - 02.56.05 + 02.56.07 2026-06-02 Moko Consulting hello@mokoconsulting.tech diff --git a/source/packages/plg_webservices_mokosuitebackup/mokosuitebackup.xml b/source/packages/plg_webservices_mokosuitebackup/mokosuitebackup.xml index 42aade09..722e2fcd 100644 --- a/source/packages/plg_webservices_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/plg_webservices_mokosuitebackup/mokosuitebackup.xml @@ -7,7 +7,7 @@ --> Web Services - MokoSuiteBackup - 02.56.05 + 02.56.07 2026-06-02 Moko Consulting hello@mokoconsulting.tech diff --git a/source/pkg_mokosuitebackup.xml b/source/pkg_mokosuitebackup.xml index 25f1e077..1ea4f8ea 100644 --- a/source/pkg_mokosuitebackup.xml +++ b/source/pkg_mokosuitebackup.xml @@ -8,7 +8,7 @@ Package - MokoSuiteBackup mokosuitebackup - 02.56.05 + 02.56.07 2026-06-02 Moko Consulting hello@mokoconsulting.tech