Role permissions are not sorted when saving via admin/people/permissions

Created on 9 March 2023, about 2 years ago
Updated 15 March 2023, almost 2 years ago

Problem/Motivation

Since 9.5.4 (and i think πŸ› Role permissions not sorted in config export Fixed ), 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

πŸ› Bug report
Status

Fixed

Version

9.5

Component
User moduleΒ  β†’

Last updated 3 days ago

Created by

πŸ‡«πŸ‡·France goz

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

  • Issue created by @goz
  • πŸ‡«πŸ‡·France goz

    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 πŸ› Role permissions not sorted in config export Fixed changes.

  • πŸ‡«πŸ‡·France goz

    Found this similar issue for 10.x to
    πŸ› user_update_10000 causes exported permissions to be numerically keyed Closed: duplicate

  • πŸ‡«πŸ‡·France goz

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

  • πŸ‡«πŸ‡·France goz

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

  • Status changed to Closed: cannot reproduce about 2 years ago
  • πŸ‡«πŸ‡·France goz

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

  • Status changed to Active about 2 years ago
  • πŸ‡«πŸ‡·France goz

    I finally reproduce again.

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

  • Status changed to Needs review about 2 years ago
  • πŸ‡«πŸ‡·France goz

    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 πŸ› Role permissions not sorted in config export Fixed does not solve this as expected.

  • Status changed to Needs work almost 2 years ago
  • πŸ‡ΊπŸ‡ΈUnited States smustgrave

    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.

  • Status changed to Postponed: needs info almost 2 years ago
  • πŸ‡¦πŸ‡ΊAustralia larowlan πŸ‡¦πŸ‡ΊπŸ.au GMT+10

    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

  • πŸ‡¦πŸ‡ΊAustralia acbramley

    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 πŸ› Role permissions not sorted in config export Fixed

  • Status changed to Active almost 2 years ago
  • πŸ‡«πŸ‡·France goz

    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'
    
  • πŸ‡¦πŸ‡ΊAustralia acbramley

    @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 πŸ› Role permissions not sorted in config export Fixed would not be in effect.

  • πŸ‡¦πŸ‡ΊAustralia acbramley

    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 opened merge request.
  • Status changed to Needs review almost 2 years ago
  • πŸ‡¦πŸ‡ΊAustralia acbramley

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

  • πŸ‡¦πŸ‡ΊAustralia acbramley

    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
    
  • πŸ‡¦πŸ‡ΊAustralia acbramley

    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.

  • Status changed to RTBC almost 2 years ago
  • πŸ‡¦πŸ‡ΊAustralia larowlan πŸ‡¦πŸ‡ΊπŸ.au GMT+10

    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.

  • First commit to issue fork.
  • πŸ‡¬πŸ‡§United Kingdom alexpott πŸ‡ͺπŸ‡ΊπŸŒ

    I've tweaked the fix to do a partial revert of πŸ› Role permissions not sorted in config export Fixed 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']);
            }
          }
        }
    
  • πŸ‡¬πŸ‡§United Kingdom alexpott πŸ‡ͺπŸ‡ΊπŸŒ

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

  • Status changed to Needs review almost 2 years ago
  • πŸ‡¬πŸ‡§United Kingdom alexpott πŸ‡ͺπŸ‡ΊπŸŒ

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

  • Status changed to RTBC almost 2 years ago
  • πŸ‡¨πŸ‡­Switzerland bircher πŸ‡¨πŸ‡Ώ

    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.

  • πŸ‡¬πŸ‡§United Kingdom alexpott πŸ‡ͺπŸ‡ΊπŸŒ

    I've opened an issue to deprecate the trusted data concept - see πŸ“Œ Deprecate the trusted data concept in configuration Active

  • πŸ‡¬πŸ‡§United Kingdom alexpott πŸ‡ͺπŸ‡ΊπŸŒ

    This will need to be backported to 9.5.x

  • Status changed to Needs work almost 2 years ago
  • πŸ‡¬πŸ‡§United Kingdom catch

    I asked @alexpott about a follow-up to deprecate user_role_grant_permissions(), turns out we have a ten year old issue πŸ“Œ Deprecate user_role_grant_permissions() and user_role_revoke_permissions() Needs work 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...
  • πŸ‡¬πŸ‡§United Kingdom catch

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

  • Status changed to Fixed almost 2 years ago
    • catch β†’ committed 99fd812e on 9.5.x
      Issue #3346953 by alexpott, acbramley, GoZ, larowlan, catch, bircher:...
  • πŸ‡¦πŸ‡ΊAustralia acbramley

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

  • πŸ‡¬πŸ‡§United Kingdom alexpott πŸ‡ͺπŸ‡ΊπŸŒ

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

  • πŸ‡«πŸ‡·France goz

    Thanks all, that was fast !

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

Production build 0.71.5 2024