v2.10.0
·
3 commits
to main
since this release
Immutable
release. Only release title and notes can be modified.
Added
- Plugins can declare Composer-package dependencies in their manifest
composerblock (#323) — a plugin listsvendor/package => constraintpairs that the framework resolves against the host's installed packages on activation (viacomposer/semver), failing closed when a requirement is unmet. When auto-install is enabled the framework runscomposer requirein the host root and seats the regenerated autoload maps so the new classes are usable in the same request. - Manifest-driven federated module and nav-entry auto-registration (#324) — a plugin's
federated_moduleandnav_entriesmanifest keys are now auto-registered from the manifest alone, without an imperativeboot()call. Imperative registrations still win, and auto-registration never overwrites a core route.
Changed
registerAdminPage( component: )'s federated mount now renders a visible fallback instead of a silent dead div, and the federated admin-page contract is documented for both host styles (#325) — the #296 shell emitted a bare<div data-cms-federated-module="…"></div>, which is inert on a host whose federation runtime never scans that attribute (e.g. Keystone CMS, whose runtime is Inertia-page-based and resolvesplugins/<remote>/<page>from theap.plugins.federatedModulesmanifest). On such a host the page rendered an empty, never-hydrated div — a footgun for plugin authors. The framework-ownedcms::admin.layouts.federatedshell now renders a role-statusnotice inside the mount naming the module and stating that the host must hydrate it, so an unhydrated page shows a clear message rather than a blank area; a host that scans the mount (or overridesap.cmsFramework.admin.federatedPageAction) still replaces it.docs/plugin-authoring.mdnow documents the contract as a host-agnostic mount plus a host hydration responsibility, spelling out both supported paths (scan the Blade mount, or bridge via the filter) and calling out the Inertiaplugins/<remote>/<page>path for Inertia-based hosts. No API signature changed.- The application self-updater resolves its update slug from config (#120) — a null/empty configured slug now coalesces to the
applicationdefault rather than producing a malformed update source. The slug is operator-config-only (no remote influence). - Plugin Composer auto-install is now opt-in (
cms.plugins.autoInstallComposerDependenciesdefaults tofalse) — auto-install fetches and boots arbitrary third-party Packagist code (a package's service provider viapackage:discover, and any eagerautoload.files) in the host process, so it is now off by default; enable it only on hosts that trust every installed plugin's declared dependencies. Each auto-install is logged with the exactcomposer requireinvocation.
Fixed
- The self-updater reconciles the working tree when a self-update aborts after extraction (#308) — a partial extraction followed by an abort no longer leaves a broken tree; the release's optional
removed-pathsmanifest deletes files the release removed upstream, and orphaned build assets are purged. The removed-paths manifest is now consumed after it applies, so a stale manifest from an earlier release can never survive into a later update and delete files that release deliberately re-introduced. purgeStaleBuildAssetsprunes the directories it empties rather than leaving hollow directory trees behind.
Security
- Plugin Composer version constraints must be bounded and stable — a bare
*, an@devstability flag, adev-<branch>reference, or a lower-bound-only range (>=1.0,>1.0) is rejected at manifest-validation time, so an auto-installed dependency cannot pull the newest, an arbitrary branch's, or a future major's code at activation. Bounded wildcards (1.2.*) remain allowed. The persistedcomposerblock is re-validated at activation (not only at install/update), failing closed on anything that would not pass validation today. - A plugin may not declare a Composer dependency the host itself requires — the framework refuses (before shelling out) any plugin-declared package present in the host's root
composer.json, so a plugin can never drivecomposer require --with-all-dependenciesto change the version of a library the host owns. - The self-updater's removed-paths manifest can never delete a critical host file —
.env,.htaccess,artisan,composer.json/composer.lock,public/index.php, and the VCS metadata directory are protected from removal even when a manifest names them, defence-in-depth over the existing containment and exclusion guards. - Composer install output is redacted before it surfaces in an activation error — inline URL credentials (
https://user:token@host) and secret-bearing tokens (token/password/api_key/authorization) in a failedcomposer require's output are masked before the failure detail reaches admins or logs.