Compare commits

...

28 Commits

Author SHA1 Message Date
git-actions[bot] 64875771a7 chore(release): build 02.67.00 [skip ci] 2026-07-17 00:33:16 +00:00
jmiller 605e45a967 Release: dev -> main (#303) — pre-update backup hardening + config lang fix
Generic: Standards Compliance / Secret Scanning (push) Failing after 5s
Generic: Standards Compliance / License Header Validation (push) Successful in 4s
Generic: Standards Compliance / Repository Structure Validation (push) Successful in 4s
Generic: Standards Compliance / Coding Standards Check (push) Successful in 5s
Generic: Standards Compliance / Workflow Configuration Check (push) Failing after 5s
Generic: Standards Compliance / Documentation Quality Check (push) Successful in 4s
Generic: Standards Compliance / README Completeness Check (push) Failing after 4s
Generic: Standards Compliance / Git Repository Hygiene (push) Successful in 7s
Generic: Standards Compliance / Script Integrity Validation (push) Successful in 6s
Generic: Standards Compliance / Line Length Check (push) Successful in 5s
Generic: Standards Compliance / File Naming Standards (push) Successful in 4s
Generic: Standards Compliance / Insecure Code Pattern Detection (push) Successful in 4s
Generic: Standards Compliance / Version Consistency Check (push) Successful in 50s
Generic: Standards Compliance / Dead Code Detection (push) Successful in 6s
Generic: Standards Compliance / File Size Limits (push) Successful in 4s
Generic: Standards Compliance / Binary File Detection (push) Successful in 7s
Generic: Standards Compliance / TODO/FIXME Tracking (push) Successful in 4s
Generic: Standards Compliance / Code Complexity Analysis (push) Successful in 48s
Generic: Standards Compliance / Code Duplication Detection (push) Successful in 47s
Generic: Standards Compliance / Broken Link Detection (push) Successful in 6s
Generic: Standards Compliance / API Documentation Coverage (push) Successful in 4s
Generic: Standards Compliance / Accessibility Check (push) Successful in 4s
Generic: Standards Compliance / Performance Metrics (push) Successful in 3s
Generic: Standards Compliance / Dependency Vulnerability Scanning (push) Successful in 52s
Generic: Standards Compliance / Unused Dependencies Check (push) Successful in 57s
Generic: Standards Compliance / Terraform Configuration Validation (push) Successful in 9s
Generic: Standards Compliance / Enterprise Readiness Check (push) Failing after 50s
Generic: Standards Compliance / Repository Health Check (push) Failing after 50s
Generic: Standards Compliance / Compliance Summary (push) Has been cancelled
https://claude.ai/code/session_01WbGBN9VyRK61zczYWcCQ2i
2026-07-17 00:32:56 +00:00
mokogit-actions[bot] d7639ec3d9 chore(version): pre-release bump to 02.66.07-dev [skip ci]
Universal: Build & Release / Promote to RC (pull_request) Has been skipped
Universal: Build & Release / Build & Release Pipeline (pull_request) Successful in 34s
Branch Cleanup / Delete merged branch (pull_request) Has been cancelled
RC Revert / Rename rc/ back to dev/ (pull_request) Has been cancelled
2026-07-17 00:26:33 +00:00
git-actions[bot] 9c37bc6303 chore(version): auto-bump patch 02.66.06-dev [skip ci] 2026-07-17 00:26:14 +00:00
jmiller c01b0ab112 Merge branch 'fix/preaction-skip-ttl' into dev
Universal: Auto Version Bump / Version Bump (push) Successful in 11s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 30s
fix(preupdate): time-bound the pre-action skip flag

Claude-Session: https://claude.ai/code/session_01WbGBN9VyRK61zczYWcCQ2i
2026-07-16 19:24:56 -05:00
jmiller 462aed0e51 fix(preupdate): time-bound the pre-action skip flag
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Failing after 7s
The one-shot "client already backed up" skip flag was a bare boolean with no
expiry. If a user ran the full-screen pre-update backup then abandoned the flow
(closed the tab before the re-fired update fired), the flag lingered for the
whole session and could suppress a LATER, unrelated pre-action backup — a real
update running with no backup.

Store the unix time the flag was armed (AjaxController::armPreactionSkip) and
honour the skip only within PREACTION_SKIP_TTL (300s), consuming it one-shot.
A stale flag is now ignored and the server backs up as normal.

Completes the pre-update double-backup hardening: server-side arming stops the
"ack fails -> double backup" direction; the TTL stops the "abandoned flow ->
skipped backup" direction. Fail-safe both ways.

Claude-Session: https://claude.ai/code/session_01WbGBN9VyRK61zczYWcCQ2i
2026-07-16 19:24:37 -05:00
mokogit-actions[bot] c7f0a122a4 chore(version): pre-release bump to 02.66.05-dev [skip ci] 2026-07-17 00:20:45 +00:00
git-actions[bot] 5fac72b5ed chore(version): auto-bump patch 02.66.04-dev [skip ci] 2026-07-17 00:20:27 +00:00
jmiller 3efadf941f Merge branch 'fix/preupdate-double-backup' into dev
Universal: Auto Version Bump / Version Bump (push) Successful in 13s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 28s
fix(preupdate): arm pre-action skip flag server-side to stop double backup

Claude-Session: https://claude.ai/code/session_01WbGBN9VyRK61zczYWcCQ2i
2026-07-16 19:18:56 -05:00
jmiller dabc556e18 fix(preupdate): arm pre-action skip flag server-side to stop double backup
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 32s
The one-shot flag that tells plg_system_mokosuitebackup to skip its synchronous
pre-update/pre-uninstall backup was set only by the client-side ajax.preupdateAck
POST, whose failure the runbackup screen swallows in a catch(). If that POST
failed, the re-fired extension update ran a SECOND backup behind the black
"update is running" overlay — the "backup runs twice" symptom.

Arm the skip flag server-side in AjaxController::step the moment a backup that
was launched as a pre-update/pre-uninstall front completes (keyed by the
msb_action the runbackup screen now passes on each step). This is authoritative
and independent of the fragile ack POST, which is kept as a redundant fallback.

Failure-safe by design: the flag is armed ONLY on genuine completion (done, no
error), so a failed or cancelled backup never arms it — a real update is never
left un-backed-up. Worst case is one redundant backup, never a missing one.

Claude-Session: https://claude.ai/code/session_01WbGBN9VyRK61zczYWcCQ2i
2026-07-16 19:18:30 -05:00
jmiller 6717f0ed68 Release: merge dev to main
Generic: Standards Compliance / Secret Scanning (push) Failing after 4s
Generic: Standards Compliance / License Header Validation (push) Successful in 5s
Generic: Standards Compliance / Repository Structure Validation (push) Successful in 4s
Generic: Standards Compliance / Coding Standards Check (push) Successful in 5s
Generic: Standards Compliance / Workflow Configuration Check (push) Failing after 5s
Generic: Standards Compliance / Documentation Quality Check (push) Successful in 5s
Generic: Standards Compliance / README Completeness Check (push) Failing after 4s
Generic: Standards Compliance / Git Repository Hygiene (push) Successful in 7s
Generic: Standards Compliance / Script Integrity Validation (push) Successful in 6s
Generic: Standards Compliance / File Naming Standards (push) Successful in 4s
Generic: Standards Compliance / Line Length Check (push) Successful in 5s
Generic: Standards Compliance / Insecure Code Pattern Detection (push) Successful in 5s
Generic: Standards Compliance / Version Consistency Check (push) Successful in 51s
Generic: Standards Compliance / Dead Code Detection (push) Successful in 7s
Generic: Standards Compliance / File Size Limits (push) Successful in 4s
Generic: Standards Compliance / Binary File Detection (push) Successful in 7s
Generic: Standards Compliance / TODO/FIXME Tracking (push) Successful in 4s
Generic: Standards Compliance / Code Complexity Analysis (push) Successful in 52s
Generic: Standards Compliance / Code Duplication Detection (push) Successful in 52s
Generic: Standards Compliance / Broken Link Detection (push) Successful in 4s
Generic: Standards Compliance / API Documentation Coverage (push) Successful in 4s
Generic: Standards Compliance / Accessibility Check (push) Successful in 4s
Generic: Standards Compliance / Performance Metrics (push) Successful in 4s
Generic: Standards Compliance / Dependency Vulnerability Scanning (push) Successful in 53s
Generic: Standards Compliance / Unused Dependencies Check (push) Successful in 55s
Generic: Standards Compliance / Terraform Configuration Validation (push) Successful in 9s
Generic: Standards Compliance / Enterprise Readiness Check (push) Failing after 50s
Generic: Standards Compliance / Repository Health Check (push) Failing after 50s
Generic: Standards Compliance / Compliance Summary (push) Has been cancelled
- feat(manifest): component 'Component - MokoSuiteBackup' pretty name via <element> tag (#299)
- fix(lang): Options page shows raw COM_MOKOSUITEBACKUP_CONFIGURATION (#234)

Claude-Session: https://claude.ai/code/session_01WbGBN9VyRK61zczYWcCQ2i

# Conflicts:
#	.mokogit/workflows/issue-branch.yml
#	CHANGELOG.md
#	SECURITY.md
#	source/packages/com_mokosuitebackup/mokosuitebackup.xml
#	source/packages/mod_mokosuitebackup_cpanel/mod_mokosuitebackup_cpanel.xml
#	source/packages/plg_actionlog_mokosuitebackup/mokosuitebackup.xml
#	source/packages/plg_console_mokosuitebackup/mokosuitebackup.xml
#	source/packages/plg_content_mokosuitebackup/mokosuitebackup.xml
#	source/packages/plg_quickicon_mokosuitebackup/mokosuitebackup.xml
#	source/packages/plg_system_mokosuitebackup/mokosuitebackup.xml
#	source/packages/plg_task_mokosuitebackup/mokosuitebackup.xml
#	source/packages/plg_webservices_mokosuitebackup/mokosuitebackup.xml
#	source/pkg_mokosuitebackup.xml
2026-07-16 17:00:31 -05:00
mokogit-actions[bot] a6de828fec chore(version): pre-release bump to 02.66.03-dev [skip ci] 2026-07-16 21:56:44 +00:00
git-actions[bot] a5e0775b0b chore(version): auto-bump patch 02.66.02-dev [skip ci] 2026-07-16 21:56:27 +00:00
jmiller cba074b0aa Merge branch 'fix/config-lang-stem' into dev
Universal: Auto Version Bump / Version Bump (push) Successful in 13s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 27s
fix(lang): Options page shows raw COM_MOKOSUITEBACKUP_CONFIGURATION (#234)

Claude-Session: https://claude.ai/code/session_01WbGBN9VyRK61zczYWcCQ2i
2026-07-16 16:55:51 -05:00
jmiller 455689532e chore: sync issue-branch.yml from Template-Joomla [skip ci] 2026-07-16 21:38:35 +00:00
jmiller a9882b9b51 fix(lang): Options page shows raw COM_MOKOSUITEBACKUP_CONFIGURATION
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 34s
Joomla's com_config derives the Options-page title and component name from
the extension element (com_mokosuitebackup), but the language files defined
those keys only under the legacy COM_MOKOJOOMBACKUP_ stem, so the Options
screen rendered the raw constant.

Add the element-derived COM_MOKOSUITEBACKUP and COM_MOKOSUITEBACKUP_CONFIGURATION
keys to all four language files (en-GB/en-US, .ini and .sys.ini), mirroring the
already-migrated COM_MOKOSUITEBACKUP_ACTION_* ACL keys. The 400+ explicitly
referenced COM_MOKOJOOMBACKUP_* keys are unaffected.

Refs #234

Claude-Session: https://claude.ai/code/session_01WbGBN9VyRK61zczYWcCQ2i
2026-07-16 14:45:02 -05:00
mokogit-actions[bot] 2d382cd62b chore(version): pre-release bump to 02.66.01-dev [skip ci] 2026-07-16 19:30:54 +00:00
jmiller db9734b156 Merge pull request 'feat(manifest): component uses Type - Name pretty name via <element> tag' (#299) from feat/component-typename-display into dev
Universal: Auto Version Bump / Version Bump (push) Has been skipped
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 30s
2026-07-16 19:27:52 +00:00
jmiller a4c8b72733 feat(manifest): give the component a "Type - Name" pretty name safely
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Universal: PR Check / Secret Scan (pull_request) Successful in 7s
Generic: Project CI / Lint & Validate (pull_request) Successful in 11s
Universal: PR Check / Validate PR (pull_request) Failing after 9s
Joomla: Metadata Validation / Validate Joomla Metadata (pull_request) Successful in 9s
Branch Cleanup / Delete merged branch (pull_request) Successful in 2s
RC Revert / Rename rc/ back to dev/ (pull_request) Has been skipped
Generic: Project CI / Tests (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
All sub-extensions already use the "Type - Name" convention; the
component was the exception because its <name> derives the element
(com_ + sanitized name), so "Component - MokoSuiteBackup" would produce
com_component-mokosuitebackup and orphan the real component.

Fix: pin the element with an explicit <element>com_mokosuitebackup</element>
tag. Joomla's InstallerAdapter::getElement() reads <element> before
falling back to <name>, so the element stays com_mokosuitebackup (matches
the existing record on upgrade — no orphan) while the Extensions manager
now shows "Component - MokoSuiteBackup". Manifest filename stays
mokosuitebackup.xml. Verified against Joomla 6.1 InstallerAdapter/
ComponentAdapter and manifest XML is well-formed.

Claude-Session: https://claude.ai/code/session_01WbGBN9VyRK61zczYWcCQ2i
2026-07-16 14:27:24 -05:00
git-actions[bot] 92ba36bc8d chore: promote changelog [Unreleased] → [02.66.00]
Generic: Standards Compliance / Secret Scanning (push) Failing after 4s
Generic: Standards Compliance / License Header Validation (push) Successful in 4s
Generic: Standards Compliance / Repository Structure Validation (push) Successful in 3s
Generic: Standards Compliance / Coding Standards Check (push) Successful in 5s
Generic: Standards Compliance / Workflow Configuration Check (push) Failing after 4s
Generic: Standards Compliance / Documentation Quality Check (push) Successful in 5s
Generic: Standards Compliance / README Completeness Check (push) Failing after 4s
Generic: Standards Compliance / Git Repository Hygiene (push) Successful in 5s
Generic: Standards Compliance / Line Length Check (push) Successful in 4s
Generic: Standards Compliance / Script Integrity Validation (push) Successful in 6s
Generic: Standards Compliance / File Naming Standards (push) Successful in 4s
Generic: Standards Compliance / Insecure Code Pattern Detection (push) Successful in 4s
Generic: Standards Compliance / Version Consistency Check (push) Successful in 50s
Generic: Standards Compliance / Dead Code Detection (push) Successful in 6s
Generic: Standards Compliance / File Size Limits (push) Successful in 3s
Generic: Standards Compliance / Binary File Detection (push) Successful in 6s
Generic: Standards Compliance / TODO/FIXME Tracking (push) Successful in 4s
Generic: Standards Compliance / Unused Dependencies Check (push) Has been cancelled
Generic: Standards Compliance / Broken Link Detection (push) Has been cancelled
Generic: Standards Compliance / API Documentation Coverage (push) Has been cancelled
Generic: Standards Compliance / Accessibility Check (push) Has been cancelled
Generic: Standards Compliance / Performance Metrics (push) Has been cancelled
Generic: Standards Compliance / Enterprise Readiness Check (push) Has been cancelled
Generic: Standards Compliance / Repository Health Check (push) Has been cancelled
Generic: Standards Compliance / Terraform Configuration Validation (push) Has been cancelled
Generic: Standards Compliance / Code Complexity Analysis (push) Successful in 48s
Generic: Standards Compliance / Code Duplication Detection (push) Successful in 49s
Generic: Standards Compliance / Compliance Summary (push) Has been cancelled
Generic: Standards Compliance / Dependency Vulnerability Scanning (push) Successful in 49s
2026-07-16 19:22:48 +00:00
git-actions[bot] 2b6f3d709f chore(release): build 02.66.00 [skip ci] 2026-07-16 19:22:38 +00:00
jmiller 102746e834 Merge pull request 'Release: dev -> main (package install redeclare fix + backlog)' (#302) from release/dev-to-main-r3 into main
Generic: Standards Compliance / Secret Scanning (push) Failing after 4s
Generic: Standards Compliance / License Header Validation (push) Successful in 4s
Generic: Standards Compliance / Repository Structure Validation (push) Successful in 4s
Generic: Standards Compliance / Coding Standards Check (push) Successful in 6s
Generic: Standards Compliance / Workflow Configuration Check (push) Failing after 5s
Generic: Standards Compliance / Documentation Quality Check (push) Successful in 5s
Generic: Standards Compliance / README Completeness Check (push) Failing after 5s
Generic: Standards Compliance / Git Repository Hygiene (push) Successful in 6s
Generic: Standards Compliance / Script Integrity Validation (push) Successful in 6s
Generic: Standards Compliance / Line Length Check (push) Successful in 5s
Generic: Standards Compliance / File Naming Standards (push) Successful in 4s
Generic: Standards Compliance / Insecure Code Pattern Detection (push) Successful in 4s
Generic: Standards Compliance / Version Consistency Check (push) Successful in 52s
Generic: Standards Compliance / Dead Code Detection (push) Successful in 7s
Generic: Standards Compliance / File Size Limits (push) Successful in 4s
Generic: Standards Compliance / Binary File Detection (push) Successful in 7s
Generic: Standards Compliance / TODO/FIXME Tracking (push) Successful in 4s
Generic: Standards Compliance / Code Complexity Analysis (push) Successful in 52s
Generic: Standards Compliance / Code Duplication Detection (push) Successful in 52s
Generic: Standards Compliance / Broken Link Detection (push) Successful in 4s
Generic: Standards Compliance / API Documentation Coverage (push) Successful in 5s
Generic: Standards Compliance / Accessibility Check (push) Successful in 4s
Generic: Standards Compliance / Performance Metrics (push) Successful in 4s
Generic: Standards Compliance / Dependency Vulnerability Scanning (push) Successful in 54s
Generic: Standards Compliance / Unused Dependencies Check (push) Successful in 57s
Generic: Standards Compliance / Terraform Configuration Validation (push) Successful in 9s
Generic: Standards Compliance / Enterprise Readiness Check (push) Failing after 52s
Generic: Standards Compliance / Repository Health Check (push) Failing after 51s
Generic: Standards Compliance / Compliance Summary (push) Has been cancelled
2026-07-16 19:21:59 +00:00
mokogit-actions[bot] 1f189349f5 chore(version): pre-release bump to 02.65.04-dev [skip ci]
Universal: Build & Release / Promote to RC (pull_request) Has been skipped
Universal: Build & Release / Build & Release Pipeline (pull_request) Successful in 32s
Branch Cleanup / Delete merged branch (pull_request) Successful in 2s
RC Revert / Rename rc/ back to dev/ (pull_request) Has been skipped
2026-07-16 19:21:10 +00:00
jmiller 28adcd0778 Merge pull request 'fix(install): guard package script against Cannot redeclare class fatal' (#301) from fix/package-script-redeclare-guard into dev
Universal: Auto Version Bump / Version Bump (push) Has been skipped
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 33s
2026-07-16 19:20:43 +00:00
mokogit-actions[bot] 3644a99d07 chore(version): pre-release bump to 02.65.03-dev [skip ci]
Branch Cleanup / Delete merged branch (pull_request) Successful in 1s
RC Revert / Rename rc/ back to dev/ (pull_request) Has been skipped
2026-07-16 19:17:07 +00:00
jmiller c70f024201 fix(install): guard package script against "Cannot redeclare class" fatal
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 44s
Generic: Project CI / Lint & Validate (pull_request) Has been cancelled
Universal: PR Check / Branch Policy (pull_request) Has been cancelled
Universal: PR Check / Secret Scan (pull_request) Has been cancelled
Universal: PR Check / Validate PR (pull_request) Has been cancelled
Joomla: Metadata Validation / Validate Joomla Metadata (pull_request) Has been cancelled
Generic: Project CI / Tests (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Package updates could fatal with a compile-time "Cannot redeclare class
Pkg_MokoSuiteBackupInstallerScript" when Joomla extracts/includes the
package script.php twice in one request (two tmp/install_* dirs). Because
the class is a top-level unconditional declaration it is early-bound at
compile time, so a runtime return can't prevent the redeclare — wrapping
it in `if (!class_exists(...)) { ... }` makes it a conditional (runtime)
declaration, so the second include is a no-op instead of a fatal.

Claude-Session: https://claude.ai/code/session_01WbGBN9VyRK61zczYWcCQ2i
2026-07-16 14:16:09 -05:00
mokogit-actions[bot] 9677edcf8b chore(version): pre-release bump to 02.65.02-dev [skip ci] 2026-07-16 18:59:59 +00:00
git-actions[bot] 90e6fe07ce chore(version): auto-bump patch 02.65.01-dev [skip ci] 2026-07-16 18:59:43 +00:00
35 changed files with 133 additions and 37 deletions
+1 -1
View File
@@ -5,7 +5,7 @@
# FILE INFORMATION
# DEFGROUP: MokoGIT.Workflow
# INGROUP: MokoCLI.Automation
# VERSION: 02.65.00
# VERSION: 02.67.00
# BRIEF: Auto-create feature branch when an issue is opened
name: "Universal: Issue Branch"
+10 -6
View File
@@ -1,6 +1,15 @@
# Changelog
## [Unreleased]
## [02.67.00] --- 2026-07-17
### Fixed
- Pre-update / pre-uninstall skip flag is now **time-bounded**. It records the moment it was armed and is honoured only within a short TTL (5 min), always consumed one-shot. Previously a bare boolean: if a user ran the full-screen pre-update backup then abandoned the flow (closed the tab before the update re-fired), the flag lingered for the whole session and could silently suppress a later, unrelated pre-action backup — i.e. a real update running with **no** backup. Now a stale flag is ignored and the server backs up as normal.
- Pre-update / pre-uninstall backup can no longer run **twice**. The one-shot "skip the synchronous server-side backup" flag is now armed **server-side** the moment the full-screen backup completes (in `AjaxController::step`, keyed by the `msb_action` it is fronting), instead of relying solely on the best-effort client `ajax.preupdateAck` POST (whose failure was silently swallowed in a `catch()`). If that ack ever fails to land, the re-fired extension update/uninstall no longer triggers a second backup behind the "update is running" overlay. The flag is armed **only** on genuine completion (`done`, no error), so a failed or cancelled backup still lets the server back up before the action — the failure mode stays "one extra backup", never "no backup".
- Component **Options** page showed the raw `COM_MOKOSUITEBACKUP_CONFIGURATION` constant instead of a translated title. Joomla's `com_config` derives the Options-page title (and the component name) from the extension *element* (`com_mokosuitebackup`), but the language files defined those keys only under the legacy `COM_MOKOJOOMBACKUP_` stem. Added the element-derived `COM_MOKOSUITEBACKUP` and `COM_MOKOSUITEBACKUP_CONFIGURATION` keys to all four language files (en-GB/en-US, `.ini` and `.sys.ini`), matching the already-migrated `COM_MOKOSUITEBACKUP_ACTION_*` ACL keys. The 400+ explicitly-referenced `COM_MOKOJOOMBACKUP_*` keys are unaffected and left as-is. (#234)
## [02.66.00] --- 2026-07-16
## [02.65.00] --- 2026-07-16
## [02.65.00] --- 2026-07-16
@@ -16,13 +25,8 @@
- Database view "One Problem" on MokoSuiteBackup: reconciled the `#__mokosuitebackup_profiles` schema-checker output with the update-file history. Corrected the stale `TINYINT` definition in `01.01.01.sql` to the final `VARCHAR(20)` type, fixed the `MODIFY COLUMN` parser trip-up in `01.39.00.sql`, and rewrote the retired `sftp_*` `ADD COLUMN` statements in `01.35.00.sql`/`01.36.00.sql` as bare `ADD` so Joomla's checker no longer demands columns that `02.52.25` and the postflight purge deliberately remove. Joomla's schema checker now reports no problems.
### Changed
- Component now shows the "Type - Name" pretty name `Component - MokoSuiteBackup` in the Extensions manager, consistent with the other sub-extensions. Achieved safely with an `<element>com_mokosuitebackup</element>` tag in the manifest (Joomla reads `<element>` before `<name>` for the extension element), so the element stays `com_mokosuitebackup` and no duplicate/orphaned component is created.
- Backup/restore progress modals in the backups view now use the same full-screen black, big-text, animated Atum-coloured progress-bar theme as the `runbackup` screen, so all backup progress surfaces match. New `media/css/backup-progress.css` scopes the black to the modal (the list page is unaffected until a modal opens).
- Standalone MokoRestore wizard (generated `restore.php`) re-branded to the full-black MokoSuite theme — black background, big header, dark panels/forms, and MokoSuite accent colours — so the restore experience matches the rest of the system instead of the old light blue "Joomla-styled" look.
## [02.64.00] --- 2026-07-14
## [02.64.00] --- 2026-07-14
## [02.63.00] --- 2026-07-13
## [02.62.00] --- 2026-07-13
+1 -1
View File
@@ -23,7 +23,7 @@ DEFGROUP: Template-Joomla
INGROUP: Template-Joomla.Documentation
REPO: https://git.mokoconsulting.tech/MokoConsulting/Template-Joomla
PATH: /SECURITY.md
VERSION: 02.65.00
VERSION: 02.67.00
BRIEF: Security vulnerability reporting and handling policy
-->
@@ -7,6 +7,13 @@
COM_MOKOJOOMBACKUP="MokoSuiteBackup"
COM_MOKOJOOMBACKUP_SHORT="Backup"
COM_MOKOJOOMBACKUP_CONFIGURATION="MokoSuiteBackup Options"
; Framework-derived keys: Joomla builds the component name and the Options-page
; title from the element (com_mokosuitebackup), NOT from the legacy
; COM_MOKOJOOMBACKUP_ stem, so they must exist under the new stem too (mirrors
; the COM_MOKOSUITEBACKUP_ACTION_* ACL keys). Without these the Options screen
; shows the raw COM_MOKOSUITEBACKUP_CONFIGURATION constant. See #234.
COM_MOKOSUITEBACKUP="MokoSuiteBackup"
COM_MOKOSUITEBACKUP_CONFIGURATION="MokoSuiteBackup Options"
COM_MOKOJOOMBACKUP_DESCRIPTION="Full-site backup and restore for Joomla"
; Submenu
@@ -7,6 +7,9 @@
COM_MOKOJOOMBACKUP="MokoSuiteBackup"
COM_MOKOJOOMBACKUP_SHORT="Backup"
COM_MOKOJOOMBACKUP_DESCRIPTION="Full-site backup and restore for Joomla — database, files, and configuration."
; Element-derived aliases (see the .ini file for the rationale). #234
COM_MOKOSUITEBACKUP="MokoSuiteBackup"
COM_MOKOSUITEBACKUP_CONFIGURATION="MokoSuiteBackup Options"
COM_MOKOJOOMBACKUP_SUBMENU_DASHBOARD="Dashboard"
COM_MOKOJOOMBACKUP_SUBMENU_BACKUPS="Backup Records"
COM_MOKOJOOMBACKUP_SUBMENU_PROFILES="Backup Profiles"
@@ -7,6 +7,13 @@
COM_MOKOJOOMBACKUP="MokoSuiteBackup"
COM_MOKOJOOMBACKUP_SHORT="Backup"
COM_MOKOJOOMBACKUP_DESCRIPTION="Full-site backup and restore for Joomla"
; Framework-derived keys: Joomla builds the component name and the Options-page
; title from the element (com_mokosuitebackup), NOT from the legacy
; COM_MOKOJOOMBACKUP_ stem, so they must exist under the new stem too (mirrors
; the COM_MOKOSUITEBACKUP_ACTION_* ACL keys). Without these the Options screen
; shows the raw COM_MOKOSUITEBACKUP_CONFIGURATION constant. See #234.
COM_MOKOSUITEBACKUP="MokoSuiteBackup"
COM_MOKOSUITEBACKUP_CONFIGURATION="MokoSuiteBackup Options"
COM_MOKOJOOMBACKUP_SUBMENU_DASHBOARD="Dashboard"
COM_MOKOJOOMBACKUP_SUBMENU_BACKUPS="Backup Records"
COM_MOKOJOOMBACKUP_SUBMENU_PROFILES="Backup Profiles"
@@ -6,6 +6,9 @@
COM_MOKOJOOMBACKUP="MokoSuiteBackup"
COM_MOKOJOOMBACKUP_SHORT="Backup"
; Element-derived aliases (see the .ini file for the rationale). #234
COM_MOKOSUITEBACKUP="MokoSuiteBackup"
COM_MOKOSUITEBACKUP_CONFIGURATION="MokoSuiteBackup Options"
COM_MOKOJOOMBACKUP_DESCRIPTION="Full-site backup and restore for Joomla — database, files, and configuration."
COM_MOKOJOOMBACKUP_SUBMENU_DASHBOARD="Dashboard"
COM_MOKOJOOMBACKUP_SUBMENU_BACKUPS="Backup Records"
@@ -7,17 +7,18 @@
-->
<extension type="component" method="upgrade">
<!--
IMPORTANT: a component's <name> drives the Joomla-derived extension
element (com_ + sanitized name), so it MUST stay element-safe:
"MokoSuiteBackup" -> com_mokosuitebackup. Do NOT apply the "Type - Name"
display convention here — "Component - MokoSuiteBackup" derives
com_component-mokosuitebackup, which registers a duplicate component and
orphans the real one. Packages are exempt because they set the element
via <packagename>; plugins/modules are exempt because <name> is only a
display label there.
The <element> tag PINS this extension's element to com_mokosuitebackup.
Joomla's InstallerAdapter::getElement() reads <element> BEFORE falling
back to <name> (libraries/src/Installer/InstallerAdapter.php), so the
display <name> can safely use the "Type - Name" convention without the
element being derived as com_component-mokosuitebackup (which would
register a duplicate component and orphan the real one). Without the
<element> tag, "Component - MokoSuiteBackup" would break the install.
NB: the manifest filename must stay mokosuitebackup.xml (short element).
-->
<name>MokoSuiteBackup</name>
<version>02.65.00</version>
<element>com_mokosuitebackup</element>
<name>Component - MokoSuiteBackup</name>
<version>02.67.00</version>
<creationDate>2026-06-02</creationDate>
<author>Moko Consulting</author>
<authorEmail>hello@mokoconsulting.tech</authorEmail>
@@ -0,0 +1 @@
/* 02.65.01 — no schema changes */
@@ -0,0 +1 @@
/* 02.65.02 — no schema changes */
@@ -0,0 +1 @@
/* 02.65.03 — no schema changes */
@@ -0,0 +1 @@
/* 02.65.04 — no schema changes */
@@ -0,0 +1 @@
/* 02.66.00 — no schema changes */
@@ -0,0 +1 @@
/* 02.66.01 — no schema changes */
@@ -0,0 +1 @@
/* 02.66.02 — no schema changes */
@@ -0,0 +1 @@
/* 02.66.03 — no schema changes */
@@ -0,0 +1 @@
/* 02.66.04 — no schema changes */
@@ -0,0 +1 @@
/* 02.66.05 — no schema changes */
@@ -0,0 +1 @@
/* 02.66.06 — no schema changes */
@@ -0,0 +1 @@
/* 02.66.07 — no schema changes */
@@ -0,0 +1 @@
/* 02.67.00 — no schema changes */
@@ -81,6 +81,19 @@ class AjaxController extends BaseController
$engine = new SteppedBackupEngine();
$result = $engine->runStep($sessionId);
/* Server-authoritative pre-action skip. When a backup that was launched as a
pre-update / pre-uninstall front COMPLETES here, arm the one-shot skip flag
on the SERVER — rather than relying solely on the client-side
ajax.preupdateAck POST, which is best-effort and swallows its own failure
in a catch(). This guarantees the imminent re-fired update/uninstall does
not trigger a SECOND synchronous backup even if that ack never lands.
Armed ONLY on genuine completion (done, no error), so a failed or cancelled
backup never arms it — preserving "no successful pre-action backup ⇒ the
server still backs up before the action". */
if (!empty($result['done']) && empty($result['error'])) {
$this->armPreactionSkip($this->input->getCmd('action', ''));
}
$this->sendJson($result);
}
@@ -116,16 +129,35 @@ class AjaxController extends BaseController
action so an update ack never suppresses a later, unrelated uninstall.
For a core Joomla update (no action) neither flag is set — a core
update doesn't fire onExtensionBefore(Update|Uninstall). */
$action = $this->app->getInput()->getCmd('action', '');
$this->armPreactionSkip($this->app->getInput()->getCmd('action', ''));
$this->sendJson(['error' => false, 'message' => 'Pre-action backup acknowledged']);
}
/**
* Arm the one-shot session skip flag for a specific pre-action, so the
* imminent re-fired extension update/uninstall skips its synchronous
* server-side backup exactly once (runPreActionBackup consumes it). Keyed by
* action so an update never suppresses a later, unrelated uninstall. A blank
* or unknown action (core Joomla update, manual "Backup Now") arms nothing.
*
* Called from two places: ajax.step on genuine completion (authoritative) and
* ajax.preupdateAck (best-effort client ack) — either one arming the flag is
* enough, and re-arming it is harmless.
*
* Stores the unix time it was armed (not a bare bool) so the plugin can honour
* the skip only within a short TTL and never let a stale flag from an abandoned
* backup suppress a genuine, unrelated pre-action backup later in the session.
*/
private function armPreactionSkip(string $action): void
{
$session = Factory::getSession();
if ($action === 'update') {
$session->set('mokosuitebackup.skip_preaction_backup_before_update', true);
$session->set('mokosuitebackup.skip_preaction_backup_before_update', time());
} elseif ($action === 'uninstall') {
$session->set('mokosuitebackup.skip_preaction_backup_before_uninstall', true);
$session->set('mokosuitebackup.skip_preaction_backup_before_uninstall', time());
}
$this->sendJson(['error' => false, 'message' => 'Pre-action backup acknowledged']);
}
/**
@@ -349,7 +349,11 @@ $this->getDocument()->addStyleSheet(Uri::root(true) . '/media/com_mokosuitebacku
var done = false;
while (!done && !cancelled) {
var step = await post({ task: 'ajax.step', session_id: init.session_id });
/* Pass the pre-action so the SERVER can arm the one-shot skip flag the
moment this backup completes (see AjaxController::step) — the black
"update is running" overlay then never fronts a second backup even
if the completion ack POST below fails to land. */
var step = await post({ task: 'ajax.step', session_id: init.session_id, action: CFG.action || '' });
if (!step || step.error) {
throw new Error((step && step.message) || 'Backup step failed');
@@ -8,7 +8,7 @@
-->
<extension type="module" client="administrator" method="upgrade">
<name>Module - MokoSuiteBackup - cPanel</name>
<version>02.65.00</version>
<version>02.67.00</version>
<creationDate>2026-06-23</creationDate>
<author>Moko Consulting</author>
<authorEmail>hello@mokoconsulting.tech</authorEmail>
@@ -7,7 +7,7 @@
-->
<extension type="plugin" group="actionlog" method="upgrade">
<name>Action Log - MokoSuiteBackup</name>
<version>02.65.00</version>
<version>02.67.00</version>
<creationDate>2026-06-04</creationDate>
<author>Moko Consulting</author>
<authorEmail>hello@mokoconsulting.tech</authorEmail>
@@ -7,7 +7,7 @@
-->
<extension type="plugin" group="console" method="upgrade">
<name>Console - MokoSuiteBackup</name>
<version>02.65.00</version>
<version>02.67.00</version>
<creationDate>2026-06-04</creationDate>
<author>Moko Consulting</author>
<authorEmail>hello@mokoconsulting.tech</authorEmail>
@@ -7,7 +7,7 @@
-->
<extension type="plugin" group="content" method="upgrade">
<name>Content - MokoSuiteBackup</name>
<version>02.65.00</version>
<version>02.67.00</version>
<creationDate>2026-06-04</creationDate>
<author>Moko Consulting</author>
<authorEmail>hello@mokoconsulting.tech</authorEmail>
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<extension type="plugin" group="quickicon" method="upgrade">
<name>Quick Icon - MokoSuiteBackup</name>
<version>02.65.00</version>
<version>02.67.00</version>
<creationDate>2026-06-02</creationDate>
<author>Moko Consulting</author>
<authorEmail>hello@mokoconsulting.tech</authorEmail>
@@ -7,7 +7,7 @@
-->
<extension type="plugin" group="system" method="upgrade">
<name>System - MokoSuiteBackup</name>
<version>02.65.00</version>
<version>02.67.00</version>
<creationDate>2026-06-02</creationDate>
<author>Moko Consulting</author>
<authorEmail>hello@mokoconsulting.tech</authorEmail>
@@ -35,6 +35,17 @@ final class MokoSuiteBackup extends CMSPlugin implements SubscriberInterface
/** @var array<string,bool> Per-request cache of the one-shot "client already backed up" skip flag. */
private array $preactionSkip = [];
/**
* Max age (seconds) of the client "already backed up" skip flag that this
* plugin will honour. The flag stores the unix time it was armed (by the
* full-screen backup's ajax.step completion / ajax.preupdateAck); the re-fired
* update/uninstall follows within a second or two, so a small window is ample.
* Bounding it means a backup that was run then ABANDONED (browser closed before
* the update re-fired) cannot silently suppress a genuine, unrelated pre-action
* backup minutes or hours later in the same session.
*/
private const PREACTION_SKIP_TTL = 300;
public static function getSubscribedEvents(): array
{
return [
@@ -648,12 +659,16 @@ JS;
$skipKey = 'mokosuitebackup.skip_preaction_' . $paramName;
if (!array_key_exists($paramName, $this->preactionSkip)) {
$this->preactionSkip[$paramName] = (bool) $session->get($skipKey, false);
$session->set($skipKey, false);
/* The flag stores the unix time it was armed. Consume it one-shot (reset
to 0) and honour the skip ONLY if it was armed within the TTL — a
stale flag from an abandoned backup must not suppress a real one. */
$armedAt = (int) $session->get($skipKey, 0);
$session->set($skipKey, 0);
$this->preactionSkip[$paramName] = ($armedAt > 0 && (time() - $armedAt) <= self::PREACTION_SKIP_TTL);
}
if ($this->preactionSkip[$paramName]) {
// Client already backed up; skip this whole re-fired (possibly batch) request.
// Client already backed up (recently); skip this re-fired (possibly batch) request.
$this->preactionRan[$paramName] = true;
return;
@@ -7,7 +7,7 @@
-->
<extension type="plugin" group="task" method="upgrade">
<name>Task - MokoSuiteBackup</name>
<version>02.65.00</version>
<version>02.67.00</version>
<creationDate>2026-06-02</creationDate>
<author>Moko Consulting</author>
<authorEmail>hello@mokoconsulting.tech</authorEmail>
@@ -7,7 +7,7 @@
-->
<extension type="plugin" group="webservices" method="upgrade">
<name>Web Services - MokoSuiteBackup</name>
<version>02.65.00</version>
<version>02.67.00</version>
<creationDate>2026-06-02</creationDate>
<author>Moko Consulting</author>
<authorEmail>hello@mokoconsulting.tech</authorEmail>
+1 -1
View File
@@ -8,7 +8,7 @@
<extension type="package" method="upgrade">
<name>Package - MokoSuiteBackup</name>
<packagename>mokosuitebackup</packagename>
<version>02.65.00</version>
<version>02.67.00</version>
<creationDate>2026-06-02</creationDate>
<author>Moko Consulting</author>
<authorEmail>hello@mokoconsulting.tech</authorEmail>
+7
View File
@@ -15,6 +15,12 @@ use Joomla\CMS\Language\Text;
use Joomla\CMS\Log\Log;
use Joomla\CMS\Router\Route;
// Guard against Joomla including this package install script twice in a single
// request (the package update flow can extract to two tmp dirs and include both
// script.php files), which otherwise fatals with a compile-time "Cannot
// redeclare class Pkg_MokoSuiteBackupInstallerScript". Declaring the class
// conditionally makes the second include a runtime no-op instead of a fatal.
if (!class_exists('Pkg_MokoSuiteBackupInstallerScript', false)) {
class Pkg_MokoSuiteBackupInstallerScript
{
/**
@@ -1091,3 +1097,4 @@ class Pkg_MokoSuiteBackupInstallerScript
} catch (\Exception $e) {}
}
}
} // end class_exists guard