Skip to content

fix: Skip automatic plugin license writes in read-only mode - #19546

Open
mvanhorn wants to merge 1 commit into
craftcms:5.xfrom
mvanhorn:fix/17750-avoid-read-only-plugin-license-writes
Open

fix: Skip automatic plugin license writes in read-only mode#19546
mvanhorn wants to merge 1 commit into
craftcms:5.xfrom
mvanhorn:fix/17750-avoid-read-only-plugin-license-writes

Conversation

@mvanhorn

@mvanhorn mvanhorn commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Description

Gate only the automatic plugin-license persistence block in Api::processResponseHeaders() on the project config service’s readOnly state. Continue processing non-mutating response metadata, including license-domain and license-info cache updates, so read-only environments can still consume update responses. Leave Plugins::setPluginLicenseKey() and its explicit controller/install callers unchanged, preserving their current validation and read-only enforcement when a user directly requests a license change.

Craftnet API responses can include X-Craft-Plugin-Licenses, which Api::processResponseHeaders() currently persists through Plugins::setPluginLicenseKey(). When project config is read-only, a returned key that differs from the deployed config reaches ProjectConfig::set() and throws NotSupportedException, preventing the Updates utility from displaying otherwise valid update information. The thread’s stack trace identifies this automatic response-header path, and a missing plugin license key supplies a concrete reproduction. A later report about project-config writes during database migrations is a separate deployment flow and is outside this fix.

Fixes #17750

Related issues

Not applicable to this change.

@mvanhorn
mvanhorn force-pushed the fix/17750-avoid-read-only-plugin-license-writes branch from c224839 to e1ae327 Compare September 3, 2026 17:08
@brandonkelly

Copy link
Copy Markdown
Member

Are you setting craft\services\ProjectConfig::readOnly independently of allowAdminChanges?

@mvanhorn

mvanhorn commented Sep 5, 2026

Copy link
Copy Markdown
Contributor Author

Yes — independently. That is the case this gates.

In core ProjectConfig::$readOnly defaults to false and nothing derives it from allowAdminChanges. The only writers are Plugins.php and BaseSystemStatusController, and both set it temporarily and restore the prior value. The $this->readOnly = !...allowAdminChanges assignments in the settings controllers and Cp.php are a separate property on those objects, not the service flag, so allowAdminChanges => false on its own never reaches ProjectConfig::set().

So the failing path is a deployment that sets the service flag itself — project config committed to the repo and applied at deploy, with writes locked at runtime. Api::processResponseHeaders() then persists X-Craft-Plugin-Licenses through setPluginLicenseKey(), a returned key differs from the deployed config, and set() throws NotSupportedException, which takes down the whole Updates utility.

If you would rather it keyed on allowAdminChanges (or on both), say so and I will change it — I gated on readOnly because that is the flag set() actually throws on.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[5.x]: Changes to the project config are not possible while in read-only mode when viewing updates

2 participants