Problem/Motivation
- #3361534: KernelTestBase::$strictConfigSchema = TRUE and BrowserTestBase::$strictConfigSchema = TRUE do not actually strictly validate introduced strict config schema checking that includes checking validation constraints.
- #3379899: Follow-up for #3361534: config validation errors in contrib modules should cause deprecation notices, not test failures softened this for non-core modules (contrib + custom): it converts validation errors to deprecation notices.
But @alexpott, @bircher, @borisson_ and I agreed at DrupalCon Lille that this is still too disruptive while discussing #3364108: Configuration schema & required keys. And @effulgentsia has expressed similar concerns privately over #3364109: Configuration schema & required values: add test coverage for `nullable: true` validation support. β Removed from the scope of this issue since #10, the removal of deprecation notices for contrib modules was moved to #3402168: Follow-up for #3361534: Config validation errors can still occur for contrib modules, disrupting contrib, which already landed since π
There is a dual problem to be solved here, that SHOULD be solved using one mechanism/signal:
- Enabling contrib/custom modules to signal when a config schema type is considered fully validatable, and hence they'd want
\Drupal\Core\Config\Schema\SchemaCheckTrait::checkConfigSchema()to cause test failures whenever that is violated. - Enabling Drupal core to know when a simple config object or a config entity type is considered fully validatable, which is necessary for #2300677: JSON:API POST/PATCH support for fully validatable config entities.
Steps to reproduce
N/A
Proposed resolution
Allow non-core modules to opt in to strict config schema checking. Somehow.
Proposal 1:
type: strict
type (a top-level key in a *.schema.yml file) can specify strict: true, and nothing else canstrict: truestrict: true
Proposal 2: FullyValidatableConstraint
- each
type(a top-level key in a*.schema.ymlfile) can specify
constraints: FullyValidatable: true, and nothing else can
- for a given node in a config object's node tree, we only run validation constraints if its type has the
FullyValidatable: truevalidation constraint - a config object (simple config or config entity) is only fully validatable if all of the config types present inside it (directly or indirectly), have the
FullyValidatable: truevalidation constraint - Later, for example in Drupal 11 or 12, we could then choose to start triggering a deprecation error for corresponding to simple config & config entities, to inform that this will become required in Drupal 12 or 13. This would lead to far fewer deprecation errors, which would be less noisy.
- See #11 + #19 for additional nuance.
So for example system.menu.tools would be validatable if system.menu.*, machine_name, required_label, label and boolean all had the FullyValidatable: true constraint.
Remaining tasks
We have decided to go for the second option, see #24
- β #3364109: Configuration schema & required values: add test coverage for `nullable: true` validation support
- β #3364108: Configuration schema & required keys
- #3408158: Run config validation for config schema types opted in to be fully validatable
User interface changes
None.
API changes
None.
Data model changes
None.
Release notes snippet
N/A
Comments
Comment #6
wim leers@effulgentsia proposed the following:
That's an interesting proposal I think. Thoughts:
type: config_entityasstrict: true, butconfig_entity:third_party_settingslooks like this:a new
typeis present inside the sequence, and that type again has the opportunity to declare itself asstrict: trueor notIOW, I propose:
type(a top-level key in a*.schema.ymlfile) can specifystrict: true, and nothing else canstrict: truestrict: trueComment #7
wim leers@Berdir 6 days ago:
β https://drupal.slack.com/archives/C1BMUQ9U6/p1699629962549669
That sounds like a bug in the config install logic in
KernelTestBase(for install profiles specifically? π€) then, because the order of the installation does matter? Because sounds wrong for sure.\Drupal\Core\Config\Schema\SchemaCheckTrait::isContribViolation()returnsFALSE(since it only looks at the source of the original config, without the overrides), and that core config is being dynamically overridden?I think the best solution for that particular problem (great catch!) would be to fix the
KernelTestBaseconfig install logic.Comment #8
wim leersI see I never stated explicitly in the issue summary what the dual problem is that this is trying to solve. Updated it.
Discussed proposal #1 at DrupalCon Lille
I discussed
with @alexpott at DrupalCon Lille.
He had VERY strong concerns about this. In a nutshell: config schema was always intended to contain only relevant information for code interpreting the config schemas (i.e. YAML files) to be able to validate the actual config (i.e. different YAML files). The addition of
strict: truewould be irrelevant noise as far as software other than Drupal is concerned.Proposal #2: a no-op
FullyValidatableconstraintSo if we should not introduce a new top-level key/concept in config schema, we must use one of the existing keys. Which one is the closest match to what we need?
The
constraintskey. Anything config schema type that wants to apply validation logic specific to its semantics/needs would already need to add that key anyway.So we need:
Proposal:
type(a top-level key in a*.schema.ymlfile) can specify, and nothing else can
FullyValidatable: truevalidation constraintFullyValidatable: truevalidation constraintwith
and
Comment #9
wim leersHTML fixes.
Comment #10
wim leers#7 turns out to have uncovered a massive contrib disruption, which merits its separate critical issue: #3402168: Follow-up for #3361534: Config validation errors can still occur for contrib modules, disrupting contrib.
Removing
Comment #11
wim leers1. Confusion about the intended problem to solve
Had a long chat with @effulgentsia last night. Turns out that he was referring to something quite different than what I've been referring to!
type: mappingis getting new semantics.2. Did the
type: mappingsemantics change in the past year?Timeline:
ValidKeysconstraint, and used it only for config dependencies β shipped in10.1.xtype: _core_config_infoβ about to ship in10.2.xtype: mappingβ about to ship in10.2.xThe config schema cheatsheet says this literally:
Or as a decision tree:
In my experience, the author of a
type: mappingalways intends all keys to be specified. It's almost always an oversight to not do that. That oversight almost always occurs because:Where does that primitive type checking happen? Tests are using
SchemaCheckTraitby default in tests (i.e. module maintainers already are being informed in the context of a test):Since the 3rd point + 4th point in the timeline,
ValidKeysConstraintValidatorontype: mappingsurfaces those same problems (again, Drupal core only):That's why IMHO the 4-point timeline above did not actually change anything semantics yet.
3. Would the
type: mappingsemantics change if we introduced the "required values" and "required keys" issues?Would
change the semantics?
If we go back to our beloved config schema cheatsheet says this literally:
Translation:
nullable: truein HEAD A) can only be set on mappings and sequences, B) when set, it means that BOTH the key AND the value are optional (without distinction).Where in Drupal core was
nullable: trueused? In 7 places in HEAD, 5 of which were added in the past year, the oldest one was introduced in 2016 in #1978714-73: Entity reference doesn't update its field settings when referenced entity bundles are deleted.That's the theory. In practice, I can modify
SchemaCheckTraitTesttounset($config_data['float']);)$config_data['float'] = NULL;)and in both cases, the test will still happily pass π₯²
This is what would change (and indeed both #3364109 and #3364108 modify that test coverage). This is where @effulgentsia is right that it changes the semantics β¦ if and only if validation constraints are executed. And that's the key part: they would NOT be executed under the proposal I have here.
4. Conclusion
That's why I still believe my proposal #2 actually addresses @effulgentsia's concerns too:
constraints: { FullyValidatable: true }would be a signal to Drupal core that "this is now ready to have its validation constraints executed"\Drupal\Core\Config\Schema\SchemaCheckTrait::$ignoredPropertyPathsin both of those issues' MRs, because then only those simple config & config entities that declare themselves fully validatable would actually be executing those validation constraintsComment #12
wim leersOn Monday I will implement proposal 2, and will verify that it allows me to remove ALL of the ignored property path additions in #3364109 and #3364108.
Unless on Monday I see that comments are awaiting me telling me why that will not work.
For now, marking for #11. π
Comment #13
wim leers#3402168: Follow-up for #3361534: Config validation errors can still occur for contrib modules, disrupting contrib just landed π Disruption disaster for contrib averted π₯³
Clarified issue title.
Comment #14
phenaproximaI think it makes perfect sense to allow config to explicitly opt into validation, if there are semantic changes that come about as a result of doing that. Having thoroughly read and parsed Wim's write-up in #11, it sounds like his proposal would address @effulgentsia's concerns, although I was not part of their discussion so I can't say that authoritatively.
But what I can say is, based on what Wim wrote there, I support his proposal. I don't adore the idea of having to explicitly mark all schema types as "you can validate this" - it feels a little clunky - but it might be a necessary crutch for now, and as Wim points out, we can deprecate and remove it later.
Comment #15
borisson_I understand this, it also gives us a less clear list of changes to go trough to get config and tests in a better shape, as we don't simply have to follow one specific list. I guess we can still go after adding the constraint to all mappings that exist.
Comment #16
berdir> That sounds like a bug in the config install logic in KernelTestBase (for install profiles specifically? π€) then, because the order of the installation does matter? Because "those overrides have dependencies on other config entities that will only be installed later on" sounds wrong for sure.
The thing is, kernel tests don't really have a concept of install profiles and due to dependency issues, my test-all-schema kernel test in two big install profiles keep getting more fragile/tricky to handle, due to dependencies. I usually need to install some modules, then their config, then some more modules, then more config.
Kernel tests by design are not a fully functional system and don't do a full install. I expect I'll just have to convert them to functional tests and do a full, complete install. Or just enable strict config schema checks/validation in the regular install on CI? Is there a settings.php flag that I could enable do do this?
Comment #17
effulgentsia commented#11 is a good summary of my concerns. To summarize even more, I'm concerned that it's not at all clear to module authors who write config schemas that the semantics of the schema is that every key that's in it is considered required-by-default unless it explicitly says
nullable: true.On the one hand:
On the other hand:
So, my biggest concerns with the MR in #3364109: Configuration schema & required values: add test coverage for `nullable: true` validation support is that:
setRequired()to every non-nullable element, which means anything that callsisRequired()for those definition objects will start seeing TRUE where it used to see FALSE. Is that fixing a bug (by making the code consistent with what https://www.drupal.org/node/1905070 has said for the last 7 years) or is it adding a BC break to a reasonable expectation that things are not required by default? It's hard to say.setRequired(), it's also adding theNotNullconstraint to enforce that, which makes sense if we agree that these should all be required, but for people who did not know that all config elements are required by default, it means that not only will calls toisRequired()return a different value than they did before, but that also new violations will get returned that weren't returned before.The
FullyValidatableconstraint proposed in #11 addresses my 2nd concern in the above list.I'm not sure what we want to do about the first concern.
Should we make the setRequired() change regardless of the FullyValidatable constraint? If we name the constraint "fully validatable", then I think we should, since I think it would be weird for the presence of a constraint to change whether or not something is semantically required, it should only affect whether or not we run other constraints or how we handle their violations (or whether we perform validation at all).
Or, in addition to the FullyValidatable constraint, should we also add a new schema property to mappings, such as
allDescendantsRequiredByDefault, which is what I also proposed simply callingstrict. That way, we don't change the return value ofisRequired()except within structures that people opt into. The downside of this though, is that we'd be introducing a new schema property to do what https://www.drupal.org/node/1905070 (but not our code) has already said we've been doing for 7 years.I think it makes sense to proceed with
FullyValidatableand not withstrictfor now and discuss whether or not we need/want a newstrictproperty in a followup, but I think splitting it up that way would mean committing all this to 10.3.x only (and not to 10.2) so that we don't end up releasing a partial behavior change without having had time to work out the full impact of it.Comment #18
phenaproximaWell, I'm not as familiar with this issue or problem space as either you or Wim, but...when we change behavior like this, even it's to make it match with long-standing but mistaken documentation...isn't it the convention to somehow issue a deprecation notice, in order to prevent hard BC breaks? Is there some way we could do that? Maybe if
$definition['nullable']is not set, we could issue a deprecation and warn that in Drupal 11, not setting that key will mean the property is treated as required?Comment #19
wim leers@effulgentsia in #17:
Small rectification
This not exactly what is being proposed. I explained this previously in response to a question of yours, on September 2: #3364109-44: Configuration schema & required values: add test coverage for `nullable: true` validation support. The proposal across the two issues in a nutshell:
requiredKey: falseβ alternativelyoptionalKey: true) β #3364108: Configuration schema & required keysnullable: true, matching what already exists in HEAD) β #3364109: Configuration schema & required values: add test coverage for `nullable: true` validation supportThe actual review
π₯² This is indeed one of the gordian knots we find ourselves in with the config system today!
π
We can solve this using that same mechanism: the root of any data definition being processed is guaranteed to be a config schema type (i.e. a definition in a
*.schema.ymlfile).In simpler terms: we can make the
setRequired()call in #3364109 that you're (rightfully!) concerned about conditional: we can make it only get applied when the containing config schema type definition has theFullyValidatableconstraint specified.This would then work exactly like the
allDescendantsRequiredByDefaultyou proposed.Working on this right now, my quick experiment shows this works ππ
I will update #3364109: Configuration schema & required values: add test coverage for `nullable: true` validation support.See #3364109-48: Configuration schema & required values: add test coverage for `nullable: true` validation support.π―! π
Comment #20
wim leersWhat do you think, @effulgentsia? π€
Comment #21
wim leersAs of #3364109-49: Configuration schema & required values: add test coverage for `nullable: true` validation support and #3364108-81: Configuration schema & required keys, both of thos issues have fully implemented #19. Their MRs show (the opt-in pattern drastically reduced their size + new tests now prove) that there is no change at all until a config schema type opts in π
I was originally hoping to change all of Drupal core at once, but I think this is a much better pattern β thanks to you, @effulgentsia.
Ready for review, @effulgentsia! π
Comment #22
wim leers(Attempt to make this issue as clear and actionable as possible.)
This is hard-blocked on @effulgentsia for 15 days now (since #20). Pretty much all config validation progress is hard-blocked on "required values" (#3364109) and "required keys" (#3364108), both of which are blocked on this.
Status:
Why is this issue necessary and why do we need those "required values" and "required keys" issues?
NotNull-sprinklingBoth of those issues have had all their feedback addressed, have blocking child issues for all parts that can be extracted (and most of those have landed already).
Comment #23
wim leers@effulgentsia has approved this approach at #3364109-60: Configuration schema & required values: add test coverage for `nullable: true` validation support ππ
He surfaced one remaining concern but proposed to do that in a follow-up, which I created: #3408165: Fully validatable config schema types: support dynamic types.
Given that this is a meta issue, the above is almost enough to close this issue, so moving to RTBC. What is still necessary both on #3364109 and here is approval from a subsystem maintainer. And in this case, there's only one: Alex Pott. So assigning to him.
Comment #24
alexpottI've reviewed the underlying MRs and I think the opt-in approach via the FullyValidatable constraint is a great plan for contrib, a little bit painful for core, but the balance feels about right.
+1 for the approach and I agree that this plan is ready.
Comment #25
alexpottComment #26
alexpottComment #27
wim leersπ₯³
Comment #28
quietone commentedI'm triaging RTBC issues. I skimmed the IS and comments and see in #24 that the maintainer has approved "Proposal 2:
FullyValidatableConstraint". The IssueSummary should be updated to make the clear, adding tag.I also skimmed the Change Record. I see only two things, I think it needs a better title (it does not read well) and the first line is a header with "Fully validatable" which isn't needed. It should just start with a 'nice' introductory sentence. I don't think the title needs to include the 'opt in' information so how about, "Stricter validation for config schema types is available"?
I have added tags for the above. I am also leaving at RTBC as I reckon someone here will notice the tags.
Cheers
Comment #29
borisson_Updated IS, changed the CR title and removed the first title. Writing a 'nice' introductory sentence would be helpful, but I don't have an idea on what that could look like.
Comment #30
phenaproximaThanks for updating the issue summary, @borisson_. Removing the tag.
Comment #31
phenaproximaI went into the change record and wordsmithed it a bit. Tried to streamline some things and rephrase for clarity. So, removing the tag.
Comment #32
phenaproximaComment #33
wim leersWith #3364108: Configuration schema & required keys having landed, this is fully complete in core, and now just needs #3408158: Run config validation for config schema types opted in to be fully validatable to allow contrib to opt in.
Since only one issue remains, closing this meta: it has fulfilled its purpose π
This also means that we can truly start working on #2300677: JSON:API POST/PATCH support for fully validatable config entities, after 9.5 years of being blocked π π€―