feat: scripture protection plugin, package install script, and library bump to v1.1.6 - #13
Conversation
lib_cwmscripture up to 1.1.4 declared <uninstall><sql> pointing at DROP TABLE statements, and Joomla's LibraryAdapter uninstalls the installed library before writing the new one — so that SQL ran on every UPDATE and destroyed every locally downloaded translation. 1.1.6 removed the block, but that only protects the upgrade *after* this one: the uninstall SQL Joomla executes during an update is the one already in JPATH_LIBRARIES, belonging to the installed version. A site on 1.1.4 is still destroyed by the very update that fixes it. Nothing inside the incoming package can prevent that. InstallerAdapter::install() calls checkExtensionInFilesystem() — which triggers the old library's uninstall — before triggerManifestScript( 'preflight') loads the new script file. By the time any incoming code runs the tables are gone. Verified against Joomla 5.4.7. The only remaining place to intervene is code already resident on the site, running before the installer. plg_system_proclaim does this for Proclaim sites; the library carries its own update server and is listed separately in the Update Manager, so a library-only update runs no package code at all. This plugin covers the stacks that ship the library without Proclaim — Living Word, and any third-party consumer. It blanks the file on onAfterRoute while the admin is on com_installer, before they click Update. Detection distinguishes executable statements from mentions inside -- comments, so the already-disarmed 1.1.5 and 1.1.6 files (which describe the problem in prose) are left alone; checked against all three released versions. The file is rewritten rather than deleted: an older manifest still references it by path and parseSQLFiles() resolves it against the installed extension root. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
… bump the library
Reconciles the package work that was split across two checkouts and adds
the missing piece that made plg_system_cwmscripture inert.
Brings in from the working branch:
- build/script.install.php — blanks the installed library's legacy
uninstall SQL in preflight, before the library child installs, plus
dropScriptureTablesIfLastConsumer() which asks the library's
ConsumerRegistry whether anything outside this package still uses the
shared tables before removing them
- <scriptfile> and blockChildUninstall in build/pkg_cwmscripture.xml
- package.installer and script.install.php in cwm-build.config.json
- the CLAUDE.md note explaining why the preflight disarm exists
Adds enablePlugin('cwmscripture', 'system') to postflight. Joomla installs
plugins disabled, and a disabled plg_system_cwmscripture never fires — its
whole job is to disarm the legacy SQL before an admin runs a library-only
update, so shipping it off by default would leave the protection absent on
exactly the sites least recently touched, which are the ones most likely
to still carry a destructive 1.1.4 library. It only flips a plugin that is
currently disabled, so an admin who deliberately turned it off is not
overridden on the next update.
Bumps the nested libraries/lib_cwmscripture pointer from 3babb2a
(v1.1.4-14) to v1.1.6, which carries the manifest with no <uninstall><sql>
at all, ConsumerRegistry, and the uninstall dependency guard. Until this
moved, the package shipped a pre-fix library and re-armed the destructive
SQL on every site it touched. Supersedes PR #11, which targeted v1.1.5.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Extracts the armed/not-armed decision into a pure, public Cwmscripture::sqlIsArmed() so it can be tested without a real JPATH_LIBRARIES path, and covers it. The subtle case is the one the naive check gets wrong: the already- disarmed 1.1.5 and 1.1.6 files describe the old behaviour in prose, so they contain the words "DROP TABLE" inside comments. A substring search flags them as dangerous and rewrites files that are perfectly fine. Tests pin both directions plus lowercase, indentation, CRLF endings, an unrelated DELETE, and a live statement appended below the reassuring comment block. Registers the plugin namespace for autoloading and adds its src to the phpunit source set. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Joomla tracks no dependencies between extensions, so lib_cwmscripture cannot discover who relies on it. Both plugins were protected only by the library's hardcoded FIRST_PARTY list, which exists as a fallback for versions predating the registry API rather than as the intended mechanism. Registering means the library refuses to be uninstalled while either plugin is installed, and the shared #__bsms_bible_* tables are not dropped while they still read them. Uses the library's own entry point (new in 1.1.7), so each plugin needs four lines rather than the ~50 that hand-rolled autoloading, guards and error handling would take. The group is passed explicitly: it is part of the registry's unique key, and a plugin registered without it never matches on lookup. Closes #12 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ti98Cc63bmWcXva2G4GdNq
|
Added Uses the entry point added in lib_cwmscripture 1.1.7 (Joomla-Bible-Study/lib_cwmscripture#26), so each plugin needs four lines rather than the ~50 that hand-rolled autoloading, guards and error handling would take: if (!is_file($helper = JPATH_LIBRARIES . '/cwmscripture/src/consumer.php')) {
return;
}
$registry = require $helper;
$registry->register('scripturelinks', 'plugin', 'content', 'Scripture Links (plg_content_scripturelinks)');The group is passed explicitly — it is part of the registry's unique key, and a plugin registered without it never matches on lookup. Verified in Proclaim's upgrade harness on a real 10.4.0 → 10.4.1 upgrade: Note: this branch's nested |
v1.1.7 adds src/consumer.php, the entry point both plugins' install scripts call to register themselves as consumers (#12). Until this pointer moved, the package shipped a library without it: the is_file() guard meant those calls no-opped silently, so neither plugin actually registered and both stayed covered only by the library's hardcoded FIRST_PARTY fallback. Also brings ConsumerScanner, so an extension that never registers is still detected by its references to the library namespace. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ti98Cc63bmWcXva2G4GdNq
Picks up the library's verifyMediaSources config, so building this package also runs the stale-artifact check on the library rather than trusting whatever sits in its media/ directory. lib_cwmscripture#25 is the case that check exists for, and this package is one of the two that bundles the library. No change to what ships. The previous pointer was already v1.1.7, so the bundled library carried src/consumer.php and ConsumerScanner before this; the library's cwm-build.config.json and composer.json are build-time only and are not in the manifest's <files>. Verified: the rebuilt pkg_cwmscripture assembles with all four children and the bundled lib_cwmscripture.zip is 89 files either way. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ti98Cc63bmWcXva2G4GdNq
|
Added That PR added the library's Nothing shipped changes. The previous pointer was already v1.1.7, so the bundled library carried Verified by rebuilding: Proclaim's equivalent bump is Joomla-Bible-Study/Proclaim#1373. |
php-cs-fixer (single_blank_line_at_eof) failed the PR with exit 8, which skipped the PHPUnit, build and verify steps behind it. Nothing else in the file changes. Slightly pointed: the file it landed in is the one asserting a disarmed SQL file is still recognised, and its own final line was missing. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ti98Cc63bmWcXva2G4GdNq
Problem
lib_cwmscripture ≤ 1.1.4 declared
<uninstall><sql>pointing atDROP TABLEstatements. Joomla'sLibraryAdapteruninstalls the installed library before writing the new one, so that SQL ran on every update and destroyed every locally downloaded translation.1.1.6 removed the block — but that only protects the upgrade after this one. The uninstall SQL Joomla executes during an update is the one already in
JPATH_LIBRARIES, belonging to the installed version. A site on 1.1.4 is destroyed by the very update that fixes it.Nothing in the incoming package can prevent it
InstallerAdapter::install()runs in this order (verified against Joomla 5.4.7):setupInstallPaths()checkExtensionInFilesystem()← triggers the old library's uninstall, executing itsDROP TABLEssetupScriptfile()triggerManifestScript('preflight')The incoming script file is not loaded until step 4. A library-side preflight disarm is impossible. The only place to intervene is code already resident on the site, running before the installer.
What this PR contains
plg_system_cwmscripture— new system plugin that blanks the legacy SQL ononAfterRoutewhile the admin is oncom_installer, before they click Update.plg_system_proclaimdoes this for Proclaim sites; this covers stacks that ship the library without Proclaim (Living Word, third-party consumers), which is the case a library-only update leaves completely unprotected.Detection distinguishes executable statements from mentions inside
--comments, so the already-disarmed 1.1.5/1.1.6 files — which describe the problem in prose and therefore contain the words "DROP TABLE" — are left alone:build/script.install.php— the package install script, wired via<scriptfile>andpackage.installer. Blanks the installed library's legacy SQL inpreflight()before the library child installs, anddropScriptureTablesIfLastConsumer()asksConsumerRegistry::installedExcluding()whether anything outside this package still uses the shared tables before removing them.enablePlugin('cwmscripture', 'system')inpostflight— Joomla installs plugins disabled, and a disabled protection plugin never fires. Shipping it off by default would leave the protection absent on exactly the sites least recently touched — the ones most likely to still carry a destructive 1.1.4 library. Only flips a plugin that is currently disabled, so an admin who deliberately turned it off is not overridden.blockChildUninstallinbuild/pkg_cwmscripture.xml, matchingpkg_proclaim.xml, so the library cannot be pulled out from under the plugins shipped alongside it.Library submodule → v1.1.6. Until this moved, the package shipped a pre-fix library and re-armed the destructive SQL on every site it touched — observed directly in Joomla-Bible-Study/lib_cwmscripture#17 run 3. Supersedes #11, which targeted v1.1.5; that version still declares
<uninstall><sql>and has neitherConsumerRegistrynor the uninstall guard that this install script now calls.Verification
php -lclean on all PHP;xmllintclean on the package manifest;cwm-build.config.jsonparsesNot runtime-tested. The plugin has not been installed and exercised on a site, and the
enablePluginpath has not been run. The test that matters is a 1.1.4 → 1.1.6 library-only update on a site with seeded translations, confirming the plugin disarms before the update and the translations survive. Proclaim'scomposer test:upgradecovers the package path but not this one.Related: Joomla-Bible-Study/lib_cwmscripture#21, Joomla-Bible-Study/CWMLivingWord#85, #12.
🤖 Generated with Claude Code