Problem/Motivation
This is spun off from Wim's note in #3390919: Create a config storage backend that can set "checkpoints", recording the changes to config that happen in between them (specifically, https://git.drupalcode.org/project/distributions_recipes/-/merge_request...):
when we add validation that reaches out of the validated config object (we have an example of that already in Drupal core: RequiredConfigDependenciesConstraintValidator), and into other config objects, we will need to validate again after all config entities are imported and after the config actions have been applied.
That's a really good point. Validation that reaches outside of a single config object/entity is definitely a thing, and can only really be properly done once the recipe has been successfully applied.
This is blocked by #3401867: Validate config that gets imported from modules or the recipe's config directory and #3401723: Config modified by action plugins should be validated after it is saved.
Proposed resolution
Once all of a recipe's config has been imported, and its config actions have run, re-validate every config object or entity was added or modified by the recipe. If there are any violations, an exception should be thrown and the config should be reverted to its original state (the ability to revert will be added in #3390919: Create a config storage backend that can set "checkpoints", recording the changes to config that happen in between them).
User interface changes
Probably none.
API changes
Unclear as yet, but probable.
Data model changes
Uncertain, but shouldn't be needed.
Issue fork distributions_recipes-3401925
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
phenaproximaComment #3
phenaproximaThis is also blocked by #3407956: Create a config storage checkpoint before applying a recipe.
Comment #4
phenaproxima#3407956: Create a config storage checkpoint before applying a recipe is in!
Comment #5
wim leers#3401867: Validate config that gets imported from modules or the recipe's config directory is in!
Last blocker: #3401723: Config modified by action plugins should be validated after it is saved
Comment #6
wim leersAnd that's fixed too now 👍
Comment #8
wim leersI think it's 99% likely that this will run into the exact same problem that @phenaproxima surfaced for #3417835: Convert the Standard install profile into a set of recipes at https://git.drupalcode.org/project/distributions_recipes/-/merge_request..., and which I proposed a solution for over at #3417835-56: Convert the Standard install profile into a set of recipes.
IMHO it's reasonable to use this issue to implement that strategy here.
Comment #10
narendrarComment #11
phenaproximaOkay, I'm struggling with how to test this.
With any fully validatable config, it's kind of impossible to put it into an invalid state. As soon as we save it, we validate it, and that throws an exception. How, therefore, can we contrive a situation where the imports and the actions (both of which validate everything they can) somehow fail to catch an invalid config object?
Comment #12
phenaproximaThe problem and fix that Wim mentions in #8 are, in fact, the reason why this is critical. From a Slack thread:
So we have to limit validation to only
FullyValidatableconfig, pronto.Comment #13
wim leers#12: Yup.
#11: I already provided guidance to @narendraR on how to do that. In a single Recipe, first modify a
Editorconfig entity (e.g. change label), second modify the correspondingFilterFormatto disallow the<br>tag. Each individual config action results in a valid config entity. But re-validating the entire set of changes at the end will result in theEditortriggering a validation error because it is no longer in sync with theFilterFormat.Comment #14
narendrarRe #13, I tried to add test in https://git.drupalcode.org/project/distributions_recipes/-/merge_request... but it is not failing as expected.
Comment #15
wim leers🤔 That makes no sense. Did you already step through CKEditor 5's "fundamental compatibility" MR with a debugger when executing validation?
Comment #16
narendrarRe #15, I tried adding debugger in CKEditor5::validatePair, but that is not getting triggered. May be something is wrong in this MR's
core/tests/fixtures/recipes/basic_html_format_editor/recipe.ymlComment #17
wim leersI'll investigate 🕵️
Comment #18
wim leersHuh, the test immediately fails for me?
Are you not seeing the same locally? https://git.drupalcode.org/issue/distributions_recipes-3401925/-/jobs/97... is definitely not showing this, so just pushed a commit to verify that this actually gets executed on GitLab CI…
Comment #19
wim leersHuh … https://git.drupalcode.org/issue/distributions_recipes-3401925/-/jobs/97... ← that did fail as expected. But I cannot reproduce this locally, it fails long before it gets to that point. Bizarre. GitLab CI uses PHP 8.1.27, I use … the same exact version. I did a fresh
composer installtwice, even after manually deleting thevendordirectory just in case.🤪 What is going on here?!
Comment #20
wim leersFor the test coverage I proposed in #8, we first would need to fix #3425349: [PP-1] Deprecate \Drupal\ckeditor5\Plugin\Editor\CKEditor5::validatePair() and `type: ckeditor5_valid_pair__format_and_editor`.
I think I've figured out a simpler test scenario that wouldn't require that to land first.
Comment #21
wim leersThat simpler scenario is: delete the text format config entity after having updated the text editor config entity.
But, since there's no config action for deleting a config entity, I don't actually see how that's possible after all … 😬
Ways out of this to not block this on #3425349: [PP-1] Deprecate \Drupal\ckeditor5\Plugin\Editor\CKEditor5::validatePair() and `type: ckeditor5_valid_pair__format_and_editor`:
editor.schema.ymlchanges using a test-only module 😄That'd allow this to land with test coverage 🤓
Comment #22
phenaproximaWell...this is a core fork, so why not just land this change in
editor.schema.ymlwith a todo to remove it when the appropriate fix(es) are made upstream in core?Comment #23
wim leers#22: because the change in
editor.schema.ymlwould cause other tests to fail — it's too simplistic (see the upstream core issue). Those unrelated test failures (if you run core tests locally) could cause wasted time when debugging.Comment #24
phenaproximaTried this, but it doesn't work, because Editors have hard config dependencies on their text formats, which means the editors are deleted when the text format is! (This happens in
\Drupal\Core\Config\Entity\ConfigEntityBase::preDelete().)Comment #25
phenaproximaSince this is tricky to test, and encompasses a bigger fix than the current critical problem turned up in #12, I've decided to split out the critical fix into its own issue, which already has dedicated test coverage: #3425540: Only validate config which is fully validatable. I'm de-escalating this one.
Comment #26
wim leersI'm very glad to see that #3425540: Only validate config which is fully validatable was split out.
Comment #27
narendrarRe-rolled the code and changes done as suggested. I am not sure what needs to be done next here as
::testValidationAfterRecipeAppliedis still not failing as expected.Comment #28
wim leersYep, that's what I alluded to in #26.2. Working on that! 👍
Comment #29
wim leerstl;dr of what has happened since #26:
Editorconfig entity can indeed trigger the validity of theEditor-FilterFormatpair 👍Next steps
ckeditor5_valid_pair__format_and_editor, which are currently only executed by callingCKEditor5::validatePair(). We shouldn't tie Recipes to that (although we temporarily could…), so we should wait for #3425349: [PP-1] Deprecate \Drupal\ckeditor5\Plugin\Editor\CKEditor5::validatePair() and `type: ckeditor5_valid_pair__format_and_editor`, because then a simpleConfigEntityAdapter::createFromEntity(Editor::load('basic_html'))->validate()(which we already call) will trigger that same validation logic without the need for calling custom logic 👍Finally: I did write in #26.2 that this issue might become obsolete. That is still possible, but the 2 blocking issues alone are insufficient.
For that to happen, we'd need to add a new validation constraint to Drupal core: one that is applied to all config entities and verifies that all dependents (other config entities depending on the config entity being modified) also remain valid. Both direct ones (e.g.
editor.editor.basic_htmldepends onfilter.format.basic_html) and indirect ones (e.g. an entity view display depending on a text field, and that text field havingfilter.format.basic_htmlconfigured as the only allowed format). If that were to happen, then only validating the actually modified config entities would be sufficient (which Recipes already does), because all interdependencies would be validated too 👍The risk/danger/complexity lies in the fact that this risks becoming a major performance bottleneck, because for some things there could be MANY indirect dependencies that would need to be revalidated…
Comment #30
thejimbirch commentedThis is marked as Postponed. Updating the status.
Comment #31
bsnodgrass commentedmoved to Drupal Core