Problem/Motivation
This is via a live conversation with @alexpott, hopefully I'm summarising it correctly.
#784672: Allow text field to enforce a specific text format introduced a new key for text fields 'allowed_formats'.
If a module or distribution ships a configuration file with 'allowed_formats', it will restrict the list of formats for the text field from 10.1 onwards.
In 10.0.0 and 9.5.x, this feature doesn't exist. At runtime, the system will just ignore the key it doesn't understand, and the text field will show all the formats. So the older sites don't get the benefit of the new feature, but also nothing breaks. This is fine.
However, if the module or distribution runs tests against 10.0 or 9.5, those tests will fail with SchemaIncompleteException
You can set KernelTestBase::strictConfigSchema to FALSE, but then none of your schema will be checked on any of your branches.
Steps to reproduce
Proposed resolution
- #3364109: Configuration schema & required values: add test coverage for `nullable: true` validation support (corresponds roughly to #23 through #25), which blocks:
- #3364108: Configuration schema & required keys
- One possibility might be something like this:
Instead of throwing exceptions, trigger_error('....', E_USER_DEPRECATED). The advantage of this would be that tests against 10.1 could be run with deprecation failures enabled, but tests against 10.0 and 9.5 could be run without.
However, not all config errors are 'deprecations' so it's possibly semantically not the right approach.
Remaining tasks
User interface changes
API changes
Data model changes
Release notes snippet
Issue fork drupal-3361423
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #2
catchComment #3
wim leersIOW: it sort of works only A) by chance, B) because there is logic in the PHP that interprets this configuration to be missing to mean that it should fall back to some default value:
treats the default value of
[]and the absence (which would returnNULL— see\Drupal\Core\TypedData\DataDefinition::getSetting()) as the sameComment #4
wim leersNote that right now the absence of a key in a mapping does not cause a schema error!
Which means that at least the example in the issue summary would today never cause tests to fail! 🙈
Let's verify that claim:
\Drupal\Tests\SchemaCheckTestTrait::assertConfigSchema()to check this.\Drupal\Tests\standard\Functional\StandardTestdoes:allowed_formatskey. Let's remove it from all of them and see what happens.EDIT: oh wait, you were referring to the opposite problem! 😅 I'll upload a new patch to see how that fares. I don't think it'll do anything either.
Comment #5
wim leersThis is for the inverse: a new key appears in a mapping that was not known. #4 is when a key is absent that config schema says should be present.
Comment #6
wim leersComment #7
catchThis code isn't in Drupal 10 so it would never run. The issue is Drupal 10.1-updated configuration on Drupal 10.0 sites. Note I didn't test this, just wrote down more or less what @alexpott talked about :)
edit: #6 looks like it's checking the right thing.
Comment #8
wim leers🙈
Comment #10
wim leersGetting a single test to run on DrupalCI is not the simplest thing. 😅 Sorry for all the noise!
Comment #11
wim leers3361423-config-schema-checking-not-quite-strict-nor-when-adding-4.patchpassed3361423-config-schema-checking-not-quite-strict-4.patchpassedCan you provide a patch that demonstrates the problem described in the issue summary? Because AFAICT these 2 patches disprove it? 😅
What am I missing? 🙈
Comment #12
wim leersAha, I think that y'all were expecting this to trigger:
in
\Drupal\Core\Config\Schema\SchemaCheckTrait::checkValue().That even has test coverage for the case reported in the issue summary:
\Drupal\KernelTests\Core\Config\SchemaCheckTraitTest::testTrait()… except that it only works for top-level keys.SchemaCheckTrait::checkValue()'s behavior: validate available data against schemaThere is an important omission in
\Drupal\Core\Config\Schema\SchemaCheckTrait::checkValue()that is AFAICT intentional: it validates only the data it is given, and does not at all check if keys are missing that should be present.This omission has been present since day 1, i.e. since #2167623: Add test for all default configuration to ensure schema exists and is correct.
It means that you could pass an empty array as the data for any piece of configuration and
\Drupal\Core\Config\Schema\SchemaCheckTrait::checkConfigSchema()will consider it valid. Example attached.Comment #13
wim leersComment #15
wim leersComment #16
catchNice work figuring this out, that means at least the text field example is a non-issue then. I can't think of any other examples off-hand where we might run into things.
Comment #17
smustgrave commentedBased on #16 going to mark this. For the committer #15 does include a drupalci.yml change figured could be omitted when committing.
Comment #18
catchI don't think #15 is meant for commit.
Comment #19
wim leersIndeed it is not.
So how can we fix both #11 (i.e. detect new keys that are not known in the installed config schema AND detect missing keys) and #12 (detect missing keys at EVERY level)?
I think I see a way! 😄
(Been working on it for >12 of the past 24 hours — I've been nerdsniped by @catch & @lauriii 🙈)
Comment #21
wim leers4 commits, here's the thought process that goes with them:
\Drupal\Core\Config\Schema\SchemaCheckTrait::checkConfigSchema()to also validate the validation constraints specified in the config schema — #3361534: KernelTestBase::$strictConfigSchema = TRUE and BrowserTestBase::$strictConfigSchema = TRUE do not actually strictly validate does that.config_test.validation, which has:This would get us one of the things we need: .
type: mapping… but this will introduce the very problem that this issue was originally created for!StandardTestyet, there's too many bugs in core's config schema for now — stay tuned! 🤓):\Drupal\KernelTests\Core\Config\SchemaCheckTraitTest::testTrait()Next batch of commits will make it more interesting.
Comment #22
wim leersSo in the last of the aforementioned commits, we enabled it by default. The test coverage that we added proved that unknown keys trigger errors.
But what about required keys? There are plenty of examples in Drupal core where code expects certain config keys to be present. As demonstrated in #11 and #12
So let's make that possible!
ValidKeys, but doing the opposite: not just allowing keys, but requiring keys:RequiredKeys. This too should supporti.e. by default all keys should be required.
Only keys that haveI realized (after a LOT of debugging 🙈) that this cannot work, because we still need to be able to distinguish between optional keys vs optional values. There are plenty of examples where some piece of configuration (some key-value pair) may be required but have an optional value — in fact, those already exist!nullable: truespecified should be allowed to be omitted, and that way we reuse that existing config schema property! 👍For example:
editor.editor.*:image_upload.max_dimensions.widthMUST be present in all Text Editor config entities, but it may be set tonullto indicate there is no maximum image width.So we need a new key. This would be specific to
type: mapping. I thinkrequiredKey: falsewould make sense: the absence of this in the config schema would implyrequiredKey: true👍Comes with explicit test coverage in
\Drupal\KernelTests\Core\Config\SchemaCheckTraitTest::testTrait().Comment #23
wim leers#21 handled new/unknown keys.
#22 handled missing/required keys.
#22 then is closely related to the concept of "required data". But it applies it only for a subset of things: keys in mappings. That's not very consistent. It should be applied to everything. If configuration schema validation historically only checks the storage type, then the absence of a value is equivalent to
NULL.In other words: if
nullable: trueis not present, we should assume thattype: stringmaps toVARCHAR NOT NULL,type: intmaps toINTEGER NOT NULLet cetera in the database.Sure enough, Typed Data already supports this:
\Drupal\Core\TypedData\DataDefinition::isRequired()and\Drupal\Core\TypedData\DataDefinition::setRequired(). We simply don't use it for config yet! But we can:::setRequired(): everything is required unlessnullable: trueis present.NotNullConstraintValidatordoes not yet work correctly for sequences and mappings! 😱Rather than tell you, let me show you, with a failing test. This will show
for
core/modules/config/tests/config_test/config/install/config_test.dynamic.dotted.default.yml, which looks like this:For example
styleis not present, so it falls back to the default value defined in the config entity class, which isNULL:Comment #24
wim leers… and setting
nullable: truein the commit I just pushed makes it pass 👍Comment #25
wim leers#23 explained the problem shown in the 2 commits preceding it.
#24 then proved it can work with one commit.
The 3 commits I just pushed add test coverage (and a small fix — check out the commit before the fix to observe the failure you'd get), proving it now works for all types.
nullable: trueand "required value" aspect explained in #23 may seem out of scope, but after having spent hours debugging things I realized I was conflating the two concepts 🙈 So while we definitely can (and should!) independently land those aspects, I felt it was important for clarity and confidence to ensure the difference is clear.\Drupal\KernelTests\Core\Config\SchemaCheckTraitTest::testTrait()proves that this is true for every type. 🚀Comment #26
wim leersThat means that now we're finally in a place where we can truly start to solve the problem this issue was originally created for! 😄
That is: gracefully handling keys in configuration that ships with module FOO, but which are specified in the config schema only in Drupal core 10.1 while the module still wants to be compatible with (and tested against) 10.0 and 9.5.
I think the latter is feasible: the absence of_core.. Change record: https://www.drupal.org/node/2653358.Distributions/installation profiles do not include this in their config — see for example Thunder and Open Social's config. Even if they currently include it, that'd be a bug and cause problems with all sorts of config management — see #3127915: Remove default config hashes from exported config for an example.Conclusion: AFAICT this is a viable heuristic! 🚀All wrong. Turns out that
ConfigInstallersets this very early on, and so it'll already be set by the time config schema checking/validation run 😬 And even recomputing the hash is impossible, because the key order is not stable… 🤪Together with some logic in
ValidKeysConstraintValidatorto trigger a deprecation error in case we're inside tests instead of a validation error (plus equivalent logic into avoid complaining about missing schema), we get this (after commenting out all the <code>allowed_formatsoccurrences in the config schema, hence simulating testing on an older version):Comes with explicit test coverage in
\Drupal\KernelTests\Core\Config\SchemaCheckTraitTest::testDeprecationForNewKeysInTests()👍In the 3 commits I just pushed, I added the infrastructure to make that happen, plus test coverage to prove it works.
Comment #27
wim leersI've now proven it can all work in
SchemaCheckTraitTest. And I show some output for the Standard install profile showing deprecation errors.But if you're anything like me, you're skeptical. "Will this work for all of core?"
Well, let's find out. Let's run
\Drupal\Tests\standard\Functional\StandardTesttoo. That's the commit I just pushed.Comment #28
wim leers😬
Pushed commit that fixes default config.
Comment #29
wim leersNo more default config errors, but just config schema problems now, because surely third party settings should not be required:
😬
Pushed commit that fixes config schema: lots of
requiredKey: falseadditions, somenullable: trueadditions, a few plain bugfixes.Comment #30
wim leersNow fast-forwarding a bit:
shortcut_themes_installed()generates invalid config andviews.*config … is not something we'll get squeaky clean in this issue. Pushed 2 commits for those.Comment #31
wim leersThe
RequiredKeysconstraint needs one more capability to support this kind of nuanced reuse of config schema types. For entity view displays,linksis a special case, and for entity form displays,authoris.Pushed commit for that.
Comment #32
wim leersAnd … finish! 🏁
Comment #33
wim leersLinking related issues.
Comment #34
borisson_Posted a review on gitlab, back to needs work to at least answer them
Comment #35
wim leersThanks for the early review!
Quoting myself from Drupal Slack:
— https://drupal.slack.com/archives/C1BMUQ9U6/p1685219644013669?thread_ts=...
Comment #36
wim leersCreated child issues:
The first one extracts already ~20% from this MR into an isolated issue. The second one should extract even more. First getting those to green, will then continue splitting this up into child issues 👍
Comment #37
wim leersAssigning to @catch to hopefully get a high-level +1 on this direction 🤓😇
Comment #38
catchI'm mostly afk this week but I feel bad about the nerdsniping ;)
I don't think when @alexpott mentioned this issue or when I typed it up, either of us had fully considered the implications - i.e. we (or at least I) didn't realise there was no validation error on the 'extra' keys in the first place.
The combination of much more precise validation but also being able to ignore some of these on older versions seems good. Agreed on making as many bugfixes prerequisites of this as possible - it would be good to commit it earlier than later in a minor release so that contrib has time to catch up too.
Comment #39
catchUnassigning me because I think this is a good idea, but tagging for subsystem maintainer review because config schema isn't really my area.
Comment #40
wim leersClarifying title. The behavior per core branch is owned by the code in that older core branch/version. Which is always true.
The goal of this issue is to minimize contrib disruption.
Comment #41
needs-review-queue-bot commentedThe Needs Review Queue Bot tested this issue. It no longer applies to Drupal core. Therefore, this issue status is now "Needs work".
This does not mean that the patch needs to be re-rolled or the MR rebased. Read the Issue Summary, the issue tags and the latest discussion here to determine what needs to be done.
Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.
Comment #42
wim leersTime for an update!
Since:
… everything is moving forward as intended 👍 The MR here served as a PoC, doing a subset of the work in all 3 of those issues. So I've just closed that MR, since the first part is already in core, the second part is RTBC and the third part is being worked on 👍
The one caveat: I had intended this issue to handle the "ignore config validation errors in contrib testing" part. But since @jibran over at #3361534-89: KernelTestBase::$strictConfigSchema = TRUE and BrowserTestBase::$strictConfigSchema = TRUE do not actually strictly validate reported that his https://www.drupal.org/project/dynamic_entity_reference contrib module started failing tests (even though there's not yet a
10.2.xbranch! 😳👏), I've spun that out into its own issue: #3379899: Follow-up for #3361534: config validation errors in contrib modules should cause deprecation notices, not test failures.That means we can keep this meta as a catch-all to ensure that contrib is not going to be disrupted by the introduction of config validation in core.
Comment #43
wim leersTwo times in two days now that I hit the "concurrent node edit causes node to get unpublished" bug on d.o 😳
Republished this node. 👍
Comment #44
wim leersComment #45
wim leersComment #46
wim leersSince #42, a lot has changed. Most notably, #3379899: Follow-up for #3361534: config validation errors in contrib modules should cause deprecation notices, not test failures and #3402168: Follow-up for #3361534: Config validation errors can still occur for contrib modules, disrupting contrib landed, which made it so that config validation using schema truly is ignored.
Drupal 10.2 has been out for 3 weeks, and there are no reports to my knowledge of contrib modules breaking (there were during the RC phase, which is why #3402168 happened). 👍
We now need #3395099: [meta] Allow config types to opt in to config validation, use "FullyValidatable" constraint at root as signal to opt in to "keys/values are required by default" to enable contrib/custom modules to opt in.
AFAICT that means this issue is … de facto done? 😄
Per the research I did in #11 through #15, it appears that I was able to prove that the original reported issue is a non-issue. This is from May 2023 though, so ~7 months ago. We should double-check. At least I was able to convince @catch 🤓
What I subsequently did was prove this through actual code + tests in #19 through #32. Back in May.
~12 hours ago, #3364108: Configuration schema & required keys finally landed, a precursor of which was in the #19–#32 PoC. The other part of the PoC landed in #3364109: Configuration schema & required values: add test coverage for `nullable: true` validation support.
So … AFAICT this is done. See also #3395099: [meta] Allow config types to opt in to config validation, use "FullyValidatable" constraint at root as signal to opt in to "keys/values are required by default" for more detail.
Leaving this to @catch or @alexpott to confirm and mark this .
Comment #47
needs-review-queue-bot commentedThe Needs Review Queue Bot tested this issue. It no longer applies to Drupal core. Therefore, this issue status is now "Needs work".
This does not mean that the patch necessarily needs to be re-rolled or the MR rebased. Read the Issue Summary, the issue tags and the latest discussion here to determine what needs to be done.
Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.
Comment #48
heddnI'm not sure how related or unrelated this is, but search_api_solr in 10.2 is throwing fits with the new config validation. #3415861: ValidKeysConstraintValidator thrown by Config Inspector on Drupal 10.1.x and 10.2.x due to core bug triggered only by Config Inspector has some details on what I'm seeing.
Comment #49
wim leers#48: I suspect that requires a development module to be installed: #3415861-3: ValidKeysConstraintValidator thrown by Config Inspector on Drupal 10.1.x and 10.2.x due to core bug triggered only by Config Inspector. Let's figure it out there, I'll report back our findings here 😊
Comment #50
dwwThis is still causing troubles in contriblandia. See #3465501: Fix Deprecation warning for profiles view for Drupal 10.3. We're trying to fix a deprecation that requires changing default views. Due to #3458099: Views handler loading should respect configuration, it's "safe" to update default views provided by contrib modules to use the new handler IDs, since the actual handler used is determined by the Views Data API, not the views config (until 11.2.0 when #3458099 will be released). However, if you change the config, and run tests against 10.2.x core, the plugins don't exist, and the whole test run explodes due to strict config schema errors. See https://git.drupalcode.org/issue/profile-3465501/-/jobs/2317666
I'd love it if there was an easy way to globally set
$strictConfigSchema = FALSEfor an entire pipeline. Or whatever this issue proposes to allow contrib to ignore these errors that are only triggered during automated testing and have no impact on runtime behavior.Haven't closely read every comment, but this seems like the right issue to raise this concern. 😅 Please let me know if I should be barking up another tree, instead.
Thanks!
-Derek
Comment #51
penyaskitoRelated but slightly different problem: shipped config in modules, where schema is defined in another dependency (e.g. core) means that we cannot test with different versions of that dependency with strict config schema validation.