From 29f83d06eee350da599b582b71c2c1422590bc01 Mon Sep 17 00:00:00 2001 From: Jonathan Miller Date: Mon, 6 Jul 2026 11:18:56 -0500 Subject: [PATCH 1/2] fix: honest installer success message Gate the installer success/license/next-steps message behind a fail-open verifier so the installer never reports success when the install failed or only partially completed. - Package scripts: verify every child extension declared in the manifest actually registered in #__extensions before showing the license message. - com_mokoog component script: verify the declared SQL tables exist before echoing the success message. Mirrors MokoSuiteHQ PR #72 and MokoSuiteClient PR #300. Both checks are wrapped in try/catch and fail open, so a transient DB/IO glitch never fakes a failure. Claude-Session: https://claude.ai/code/session_01B9aZHSWbiiZykJD88pYx8R --- CHANGELOG.md | 3 + source/packages/com_mokoog/script.php | 79 ++++++++++++++++++++++ source/script.php | 97 ++++++++++++++++++++++++++- 3 files changed, 178 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 34c2813..9cc34ad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). ## [Unreleased] +### Fixed +- **Honest install success** — the installer no longer claims success or shows the license message when the install partially failed. The package postflight verifies every child extension declared in the manifest registered in `#__extensions`; the `com_mokoog` component script verifies its declared tables exist before echoing the success message. Both checks fail open, so a transient DB/IO glitch never fakes a failure. + ### Added - OG coverage **dashboard** as the default admin view — SVG donut gauge, coverage by content type, and a list of articles missing OG tags with a batch-generate shortcut (#94) - Single OG tag **create/edit screen** in the admin (the tag manager was previously read-only) (#98) diff --git a/source/packages/com_mokoog/script.php b/source/packages/com_mokoog/script.php index ace5636..9990285 100644 --- a/source/packages/com_mokoog/script.php +++ b/source/packages/com_mokoog/script.php @@ -10,7 +10,9 @@ defined('_JEXEC') or die; +use Joomla\CMS\Factory; use Joomla\CMS\Installer\InstallerAdapter; +use Joomla\Database\DatabaseInterface; class Com_MokoOGInstallerScript { @@ -23,6 +25,20 @@ class Com_MokoOGInstallerScript */ public function install(InstallerAdapter $parent): void { + // Be honest about success: don't claim a clean install if the component's + // own tables never landed. Fails open (see missingTables) so a query/IO + // glitch never fakes a failure. + $missing = $this->missingTables(); + + if (!empty($missing)) + { + echo '

MokoSuiteOpenGraph component did not install correctly. ' + . 'Missing database table(s): ' + . htmlspecialchars(implode(', ', $missing), ENT_QUOTES) . '.

'; + + return; + } + echo '

MokoSuiteOpenGraph component installed successfully.

'; } @@ -35,6 +51,69 @@ class Com_MokoOGInstallerScript */ public function update(InstallerAdapter $parent): void { + $missing = $this->missingTables(); + + if (!empty($missing)) + { + echo '

MokoSuiteOpenGraph component did not update correctly. ' + . 'Missing database table(s): ' + . htmlspecialchars(implode(', ', $missing), ENT_QUOTES) . '.

'; + + return; + } + echo '

MokoSuiteOpenGraph component updated successfully.

'; } + + /** + * Verify the component's declared tables actually exist. Reads the shipped + * install SQL, extracts every CREATE TABLE #__name, resolves the live prefix, + * and checks each against the database's table list (case-insensitive). + * + * FAILS OPEN: any error (unreadable SQL, query failure) returns [] so a + * transient glitch never turns a good install into a false failure. + * + * @return string[] Prefixed names of any missing tables. + */ + private function missingTables(): array + { + try + { + $sqlFile = JPATH_ADMINISTRATOR . '/components/com_mokoog/sql/install.mysql.sql'; + + if (!is_file($sqlFile)) + { + return []; + } + + $sql = (string) file_get_contents($sqlFile); + + if ($sql === '' || !preg_match_all('/CREATE\s+TABLE\s+(?:IF\s+NOT\s+EXISTS\s+)?[`"\']?(#__[A-Za-z0-9_]+)/i', $sql, $m)) + { + return []; + } + + $db = Factory::getContainer()->get(DatabaseInterface::class); + $prefix = $db->getPrefix(); + $existing = array_map('strtolower', (array) $db->getTableList()); + $missing = []; + + foreach (array_unique($m[1]) as $table) + { + $real = str_replace('#__', $prefix, $table); + + if (!in_array(strtolower($real), $existing, true)) + { + $missing[] = $real; + } + } + + return $missing; + } + catch (\Throwable $e) + { + // Fail open — never fake a failure on a glitch. + return []; + } + } } diff --git a/source/script.php b/source/script.php index c90d65e..08b806d 100644 --- a/source/script.php +++ b/source/script.php @@ -51,8 +51,8 @@ class Pkg_MokoOGInstallerScript public function postflight(string $type, InstallerAdapter $parent): void { $this->restoreDownloadKey(); - $this->warnMissingLicenseKey(); + // Enable plugins after first install (unconditional module/plugin setup) if ($type === 'install') { $db = Factory::getContainer()->get(\Joomla\Database\DatabaseInterface::class); @@ -69,6 +69,101 @@ class Pkg_MokoOGInstallerScript )->execute(); } } + + // Be honest about success. Joomla's package installer only LOGS a failed child + // sub-install but still runs this postflight, so don't show the license / + // next-steps message if a bundled extension is actually missing. Fails open + // (see missingChildExtensions) so a query/IO glitch never fakes a failure. + $missing = $this->missingChildExtensions($parent); + + if (!empty($missing)) + { + Factory::getApplication()->enqueueMessage( + '

MokoSuiteOpenGraph did not install correctly.

' + . '

The following bundled extensions are missing: ' + . htmlspecialchars(implode(', ', $missing), ENT_QUOTES) . '

' + . '

Please uninstall MokoSuiteOpenGraph and reinstall the full package.

', + 'error' + ); + + return; + } + + $this->warnMissingLicenseKey(); + } + + /** + * Verify every child extension declared in the package manifest actually landed + * in #__extensions. Returns readable labels of any that are missing. + * + * element = "id", EXCEPT plugins strip a leading plg__; plugins also + * match folder = "group". FAILS OPEN — any error returns [] so a transient + * glitch never turns a good install into a false failure. + */ + private function missingChildExtensions($parent): array + { + try + { + $manifest = $parent->getParent()->getManifest(); + + if (!$manifest || !isset($manifest->files) || !isset($manifest->files->file)) + { + return []; + } + + $db = Factory::getContainer()->get(\Joomla\Database\DatabaseInterface::class); + $missing = []; + + foreach ($manifest->files->file as $file) + { + $attrs = $file->attributes(); + $id = isset($attrs['id']) ? (string) $attrs['id'] : ''; + $exType = isset($attrs['type']) ? (string) $attrs['type'] : ''; + + if ($id === '' || $exType === '') + { + continue; + } + + $group = isset($attrs['group']) ? (string) $attrs['group'] : ''; + $element = $id; + + // Plugin element in #__extensions is the id minus any leading plg__. + if ($exType === 'plugin' && $group !== '') + { + $prefix = 'plg_' . $group . '_'; + + if (strpos($element, $prefix) === 0) + { + $element = substr($element, \strlen($prefix)); + } + } + + $query = $db->getQuery(true) + ->select('COUNT(*)') + ->from($db->quoteName('#__extensions')) + ->where($db->quoteName('element') . ' = ' . $db->quote($element)) + ->where($db->quoteName('type') . ' = ' . $db->quote($exType)); + + if ($exType === 'plugin' && $group !== '') + { + $query->where($db->quoteName('folder') . ' = ' . $db->quote($group)); + } + + if ((int) $db->setQuery($query)->loadResult() === 0) + { + $label = trim((string) $file); + $missing[] = $label !== '' ? preg_replace('/\.zip$/i', '', $label) : $id; + } + } + + return $missing; + } + catch (\Throwable $e) + { + // Fail open — never fake a failure on a glitch. + return []; + } } -- 2.52.0 From ee80111336bbd064295a1d47317b137d4c139111 Mon Sep 17 00:00:00 2001 From: "gitea-actions[bot]" Date: Mon, 6 Jul 2026 16:19:22 +0000 Subject: [PATCH 2/2] chore(version): pre-release bump to 01.07.06-dev [skip ci] --- .mokogitea/workflows/issue-branch.yml | 2 +- CHANGELOG.md | 2 +- CODE_OF_CONDUCT.md | 2 +- GOVERNANCE.md | 2 +- README.md | 2 +- SECURITY.md | 2 +- source/packages/com_mokoog/mokoog.xml | 2 +- source/packages/com_mokoog/sql/updates/mysql/01.07.06.sql | 1 + source/packages/plg_content_mokoog/mokoog.xml | 2 +- source/packages/plg_system_mokoog/mokoog.xml | 2 +- source/packages/plg_webservices_mokoog/mokoog.xml | 2 +- source/pkg_mokoog.xml | 2 +- 12 files changed, 12 insertions(+), 11 deletions(-) create mode 100644 source/packages/com_mokoog/sql/updates/mysql/01.07.06.sql diff --git a/.mokogitea/workflows/issue-branch.yml b/.mokogitea/workflows/issue-branch.yml index aceb8ba..dd00276 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.07.03 +# VERSION: 01.07.06 # BRIEF: Auto-create feature branch when an issue is opened name: "Universal: Issue Branch" diff --git a/CHANGELOG.md b/CHANGELOG.md index 9cc34ad..d312bc5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ All notable changes to MokoSuiteOpenGraph will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). - + ## [Unreleased] diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index be9a704..f302f0e 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -14,7 +14,7 @@ DEFGROUP: Template-Joomla INGROUP: Template-Joomla.Documentation REPO: https://github.com/mokoconsulting-tech/Template-Joomla/ - VERSION: 01.07.03 + VERSION: 01.07.06 PATH: ./CODE_OF_CONDUCT.md BRIEF: Community expectations and enforcement guidelines NOTE: Adapted with attribution from the Contributor Covenant v2.1 diff --git a/GOVERNANCE.md b/GOVERNANCE.md index 2bd9da7..161cda6 100644 --- a/GOVERNANCE.md +++ b/GOVERNANCE.md @@ -19,7 +19,7 @@ DEFGROUP: mokoconsulting-tech.Template-Joomla INGROUP: MokoStandards.Governance REPO: https://github.com/mokoconsulting-tech/Template-Joomla - VERSION: 01.07.03 + VERSION: 01.07.06 PATH: /GOVERNANCE.md BRIEF: Project governance rules, roles, and decision process for Template-Joomla --> diff --git a/README.md b/README.md index 3883664..310bb07 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # MokoSuiteOpenGraph - + Open Graph, Twitter Card, and social sharing meta tag management for Joomla 6 and higher. diff --git a/SECURITY.md b/SECURITY.md index 00e8f32..de9f571 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: 01.07.03 +VERSION: 01.07.06 BRIEF: Security vulnerability reporting and handling policy --> diff --git a/source/packages/com_mokoog/mokoog.xml b/source/packages/com_mokoog/mokoog.xml index 73f76f7..96e2bc0 100644 --- a/source/packages/com_mokoog/mokoog.xml +++ b/source/packages/com_mokoog/mokoog.xml @@ -8,7 +8,7 @@ --> com_mokoog - 01.07.03 + 01.07.06 2026-05-23 Moko Consulting hello@mokoconsulting.tech diff --git a/source/packages/com_mokoog/sql/updates/mysql/01.07.06.sql b/source/packages/com_mokoog/sql/updates/mysql/01.07.06.sql new file mode 100644 index 0000000..2e2718a --- /dev/null +++ b/source/packages/com_mokoog/sql/updates/mysql/01.07.06.sql @@ -0,0 +1 @@ +/* 01.07.06 — no schema changes */ diff --git a/source/packages/plg_content_mokoog/mokoog.xml b/source/packages/plg_content_mokoog/mokoog.xml index 9aec28d..874da09 100644 --- a/source/packages/plg_content_mokoog/mokoog.xml +++ b/source/packages/plg_content_mokoog/mokoog.xml @@ -8,7 +8,7 @@ --> Content - MokoSuiteOpenGraph - 01.07.03 + 01.07.06 2026-05-23 Moko Consulting hello@mokoconsulting.tech diff --git a/source/packages/plg_system_mokoog/mokoog.xml b/source/packages/plg_system_mokoog/mokoog.xml index 7621fbf..4057846 100644 --- a/source/packages/plg_system_mokoog/mokoog.xml +++ b/source/packages/plg_system_mokoog/mokoog.xml @@ -8,7 +8,7 @@ --> System - MokoSuiteOpenGraph - 01.07.03 + 01.07.06 2026-05-23 Moko Consulting hello@mokoconsulting.tech diff --git a/source/packages/plg_webservices_mokoog/mokoog.xml b/source/packages/plg_webservices_mokoog/mokoog.xml index 3d948ce..a2a434f 100644 --- a/source/packages/plg_webservices_mokoog/mokoog.xml +++ b/source/packages/plg_webservices_mokoog/mokoog.xml @@ -8,7 +8,7 @@ --> Web Services - MokoSuiteOpenGraph - 01.07.03 + 01.07.06 2026-05-23 Moko Consulting hello@mokoconsulting.tech diff --git a/source/pkg_mokoog.xml b/source/pkg_mokoog.xml index a3037b5..9b02d9d 100644 --- a/source/pkg_mokoog.xml +++ b/source/pkg_mokoog.xml @@ -8,7 +8,7 @@ Package - MokoSuiteOpenGraph mokoog - 01.07.03 + 01.07.06 2026-05-23 Moko Consulting hello@mokoconsulting.tech -- 2.52.0