Problem/Motivation

Since 9.5.4 (and i think #3039499: Role permissions not sorted in config export), when i save the admin/people/permissions form (while adding or removing a permission) and export configuration, i see key index on permission export.

To take the example of the related issue, here is now the result :

diff --git a/config-sync/user.role.toggle_all.yml b/config-sync/user.role.toggle_all.yml
index 0ce46a0..35ac270 100644
--- a/config-sync/user.role.toggle_all.yml
+++ b/config-sync/user.role.toggle_all.yml
@@ -7,11 +7,10 @@ label: 'Toggle all'
 weight: -2
 is_admin: null
 permissions:
-  - 'abstractpermissions:role_toggle:toggle_all'
-  - 'access administration pages'
-  - 'access toolbar'
-  - 'role_toggle:administrator'
-  - 'role_toggle:debugger'
-  - 'role_toggle:design_manager'
-  - 'role_toggle:site_manager'
-  - 'role_toggle:translation_manager'
+  0: 'abstractpermissions:role_toggle:toggle_all'
+  1: 'access administration pages'
+  2: 'access toolbar'
+  3: 'role_toggle:debugger'
+  4: 'role_toggle:design_manager'
+  5: 'role_toggle:site_manager'
+  6: 'role_toggle:translation_manager'

Index should not appear in the export, only permissions, sorted by their name.

Steps to reproduce

  • Submit changes in role permissions.
  • Export the configuration
  • Permissions in configuration file show index

See #13

Issue fork drupal-3346953

Command icon 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

GoZ created an issue. See original summary.

goz’s picture

goz’s picture

Setting back the following code solve the issue :

\Drupal\user\Entity\Role::preSave:

    if (!$this->isSyncing()) {
      // Permissions are always ordered alphabetically to avoid conflicts in the
      // exported configuration.
      sort($this->permissions);
    }

Still needs to see why it has been removed. Seems something doesn't work as expected after #3039499: Role permissions not sorted in config export changes.

goz’s picture

Priority: Normal » Critical

Move it to critical since it will regenerate all permissions roles files of existing projects, and will need a rollback.

goz’s picture

After updating another project from 9.5.3 to 9.5.4, i don't reproduce the issue.
Really strange

goz’s picture

Status: Active » Closed (cannot reproduce)

Forget about this, i restart from previous dump, run the update again and cannot reproduce

goz’s picture

Status: Closed (cannot reproduce) » Active

I finally reproduce again.

This will occurs only if you remove a permission from a role (and then export configuration with drush).

goz’s picture

Issue summary: View changes
Status: Active » Needs review
StatusFileSize
new550 bytes

May be there is a better solution, but set the code from Role::preSave back solve it right now.

Let see later why schema update from #3039499: Role permissions not sorted in config export does not solve this as expected.

smustgrave’s picture

Status: Needs review » Needs work
Issue tags: +Needs Review Queue Initiative, +Needs tests

Tried replicating and was not able to.

Exported permissions
Removed a permission from a role
Exported again.
not seeing any issues.

Think this can be lowered to Normal.

As a bug will also need a test case to show the isuse.

larowlan’s picture

Priority: Critical » Normal
Status: Needs work » Postponed (maintainer needs more info)
Issue tags: +Needs steps to reproduce

I don't think this meets the requirements for a critical, can you elaborate on why you feel it is, it doesn't seem to cause data loss

acbramley’s picture

The IS states"revoke a permission". Does that mean via the action? I can see how that may lead to unsorted permissions depending on how that action plugin works. I would be surprised if it did though since saving a Role entity should trigger the sort that was added in https://www.drupal.org/project/drupal/issues/3039499

goz’s picture

Title: Role permissions config export exports index » Role permissions config export exports index from 9.5.3 to 9.5.4
Status: Postponed (maintainer needs more info) » Active

I reproduce in both contexts : after updating from 9.5.3 to 9.5.4, and after installation to 9.5.4 with existing config.

Steps to reproduce :
- Have an installed drupal at 9.5.3
- Be sure configuration is up to date : drush cex -y
- Update to 9.5.4 :

composer update -W drupal/core-recommended:9.5.4
drush updb -y
drush cex -y

Permissions in user.role.authenticated.yml is :

 permissions:
  - 'access administration pages'
  - 'access content overview'
  - 'access contextual links'
  - 'access files overview'
  - 'access toolbar'
  - 'access tour'
  - 'administer url aliases'
  - 'create article content'
  - 'create page content'
  - 'create terms in tags'
  - 'create url aliases'
  - 'delete article revisions'
  - 'delete own article content'
  - 'delete own page content'
  - 'delete page revisions'
  - 'edit own article content'
  - 'edit own comments'
  - 'edit own page content'
  - 'edit terms in tags'
  - 'revert all revisions'
  - 'view all revisions'
  - 'view own unpublished content'
  - 'view the administration theme'

- I commit this in git to see differences when i'll remove the permission and export again.
- Remove 'edit own comments' from /admin/people/permissions
- Export config : drush cex -y
- git diff on user.role.authenticated.yml is now :

 permissions:
-  - 'access administration pages'
-  - 'access content overview'
-  - 'access contextual links'
-  - 'access files overview'
-  - 'access toolbar'
-  - 'access tour'
-  - 'administer url aliases'
-  - 'create article content'
-  - 'create page content'
-  - 'create terms in tags'
-  - 'create url aliases'
-  - 'delete article revisions'
-  - 'delete own article content'
-  - 'delete own page content'
-  - 'delete page revisions'
-  - 'edit own article content'
-  - 'edit own comments'
-  - 'edit own page content'
-  - 'edit terms in tags'
-  - 'revert all revisions'
-  - 'view all revisions'
-  - 'view own unpublished content'
-  - 'view the administration theme'
+  0: 'access administration pages'
+  1: 'access content overview'
+  2: 'access contextual links'
+  3: 'access files overview'
+  4: 'access toolbar'
+  5: 'access tour'
+  6: 'administer url aliases'
+  7: 'create article content'
+  8: 'create page content'
+  9: 'create terms in tags'
+  10: 'create url aliases'
+  11: 'delete article revisions'
+  12: 'delete own article content'
+  13: 'delete own page content'
+  14: 'delete page revisions'
+  15: 'edit own article content'
+  17: 'edit own page content'
+  18: 'edit terms in tags'
+  19: 'revert all revisions'
+  20: 'view all revisions'
+  21: 'view own unpublished content'
+  22: 'view the administration theme'
acbramley’s picture

@GoZ a normal upgrade path would have a cache clear in there. Did you clear cache before or after the drush updb? Because without that, the schema change from #3039499: Role permissions not sorted in config export would not be in effect.

acbramley’s picture

Title: Role permissions config export exports index from 9.5.3 to 9.5.4 » Role permissions are not sorted when saving via admin/people/permissions
Version: 9.5.x-dev » 10.1.x-dev
Component: configuration system » user.module
Issue summary: View changes
Issue tags: -Needs tests, -Needs steps to reproduce

Confirmed steps in #13 trigger the issue even with a cache clear.

Even worse - after adding a new permission it's tacked on to the end, i.e there's no sorting at all.

I've tracked this down to the fact that user_role_grant_permissions and user_role_revoke_permissions call trustData.

Setting trustedData = TRUE skips casting in validation

Config::castValue is where sorting is applied.

UserPermissionsForm::submitForm calls user_role_change_permissions which uses the 2 functions mentioned above.

This can be reproduced on 10.1.x, no need to upgrade or anything just simply save the permissions form.

acbramley’s picture

Status: Active » Needs review
Issue tags: +Needs tests

Pushed a fix to the MR, keen to see what fails before working on dedicated tests. Hiding the patch as well.

acbramley’s picture

Issue tags: -Needs tests

I couldn't find any existing tests for the permissions form so I've added a new class (searched all tests for admin/people/permissions or user.admin_permissions).

This test is very simple and correctly fails when reverting either of the changes in the first commit:

Add fail:

$ ./app/vendor/bin/phpunit app/core/modules/user/tests/src/Functional/UserPermissionsAdminTest.php
PHPUnit 9.5.28 by Sebastian Bergmann and contributors.

Warning:       Your XML configuration validates against a deprecated schema.
Suggestion:    Migrate your XML configuration using "--migrate-configuration"!

Testing Drupal\Tests\user\Functional\UserPermissionsAdminTest
F                                                                   1 / 1 (100%)

Time: 00:15.051, Memory: 10.00 MB

There was 1 failure:

1) Drupal\Tests\user\Functional\UserPermissionsAdminTest::testPermissionsSorting
Failed asserting that two arrays are equal.
--- Expected
+++ Actual
@@ @@
 Array (
-    0 => 'change own username'
-    1 => 'view user email addresses'
+    0 => 'view user email addresses'
+    1 => 'change own username'
 )

/data/app/vendor/phpunit/phpunit/src/Framework/Constraint/Equality/IsEqual.php:96
/data/app/core/modules/user/tests/src/Functional/UserPermissionsAdminTest.php:48

Remove fail:

$ ./app/vendor/bin/phpunit app/core/modules/user/tests/src/Functional/UserPermissionsAdminTest.php
PHPUnit 9.5.28 by Sebastian Bergmann and contributors.

Warning:       Your XML configuration validates against a deprecated schema.
Suggestion:    Migrate your XML configuration using "--migrate-configuration"!

Testing Drupal\Tests\user\Functional\UserPermissionsAdminTest
F                                                                   1 / 1 (100%)

Time: 00:15.442, Memory: 10.00 MB

There was 1 failure:

1) Drupal\Tests\user\Functional\UserPermissionsAdminTest::testPermissionsSorting
Failed asserting that two arrays are equal.
--- Expected
+++ Actual
@@ @@
 Array (
-    0 => 'view user email addresses'
+    1 => 'view user email addresses'
 )

/data/app/vendor/phpunit/phpunit/src/Framework/Constraint/Equality/IsEqual.php:96
/data/app/core/modules/user/tests/src/Functional/UserPermissionsAdminTest.php:60
acbramley’s picture

Checked core for usages of user_role_change_permissions, user_role_grant_permissions, and user_role_revoke_permissions and almost all usages are in tests, except this permissions form and in FilterFormat::postSave. I can't find any test coverage for the FilterFormat permissions.

acbramley’s picture

Issue tags: +Bug Smash Initiative
larowlan’s picture

Priority: Normal » Major
Status: Needs review » Reviewed & tested by the community

Patch looks simple enough, and has a test.

The ::trustData call was added in #2432791: Skip Config::save schema validation of config data for trusted data in comment 57 it seems.

Will ping @alexpott about this given he worked on both that patch and the sorting one.

alexpott made their first commit to this issue’s fork.

alexpott’s picture

I've tweaked the fix to do a partial revert of #3039499: Role permissions not sorted in config export so that the behaviour from before that is maintained. This ensures that the actions also still work as before. I think this is analogous to the existing code for dependencies in ConfigEntityBase...

    if (!$this->isSyncing()) {
      // Ensure the correct dependencies are present. If the configuration is
      // being written during a configuration synchronization then there is no
      // need to recalculate the dependencies.
      $this->calculateDependencies();
      // If the data is trusted we need to ensure that the dependencies are
      // sorted as per their schema. If the save is not trusted then the
      // configuration will be sorted by StorableConfigBase.
      if ($this->trustedData) {
        $mapping = ['config' => 0, 'content' => 1, 'module' => 2, 'theme' => 3, 'enforced' => 4];
        $dependency_sort = function ($dependencies) use ($mapping) {
          // Only sort the keys that exist.
          $mapping_to_replace = array_intersect_key($mapping, $dependencies);
          return array_replace($mapping_to_replace, $dependencies);
        };
        $this->dependencies = $dependency_sort($this->dependencies);
        if (isset($this->dependencies['enforced'])) {
          $this->dependencies['enforced'] = $dependency_sort($this->dependencies['enforced']);
        }
      }
    }
alexpott’s picture

StatusFileSize
new39.95 KB

If you update from 10.0.0 to this MR you'll see

Screenshot of update.php showing user updates post applying the MR

alexpott’s picture

Status: Reviewed & tested by the community » Needs review

My changes are now too extensive to leave at RTBC...

bircher’s picture

Status: Needs review » Reviewed & tested by the community

This looks good!

Checking for $this->hasTrustedData() and doing the sorting here is ok. But long term we should make sure to avoid the trusting of data except in the install phase. And there we could do a sorting/casting after the installation. But this would need lots of other work with sorting etc and is clearly out of scope here.

So I RTBC this again.

alexpott’s picture

I've opened an issue to deprecate the trusted data concept - see #3347842: Deprecate the trusted data concept in configuration

alexpott’s picture

This will need to be backported to 9.5.x

catch’s picture

Version: 10.1.x-dev » 9.5.x-dev
Status: Reviewed & tested by the community » Needs work

I asked @alexpott about a follow-up to deprecate user_role_grant_permissions(), turns out we have a ten year old issue #2025089: Deprecate user_role_grant_permissions() and user_role_revoke_permissions() already.

Committed/pushed to 10.1.x and cherry-picked to 10.0.x. This needs a re-roll for 9.5.x

  • catch committed 28438cfe on 10.0.x
    Issue #3346953 by alexpott, acbramley, GoZ, larowlan, bircher: Role...

  • catch committed f965e400 on 10.1.x
    Issue #3346953 by alexpott, acbramley, GoZ, larowlan, bircher: Role...
catch’s picture

Status: Needs work » Fixed

Diff applies to 9.5.x even though the cherry-pick doesn't, so committed/pushed there too.

  • catch committed 99fd812e on 9.5.x
    Issue #3346953 by alexpott, acbramley, GoZ, larowlan, catch, bircher:...
acbramley’s picture

Thanks for the quick turn around! @alexpott just curious why we went with that solution rather than removing the trustData call?

alexpott’s picture

@acbramley because it is not just these methods. Anywhere that called trustData() on a role would no longer be sorted. I broke that with #3039499: Role permissions not sorted in config export when I shouldn't have.

goz’s picture

Thanks all, that was fast !

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.