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

Created on 9 March 2023, over 1 year ago
Updated 15 March 2023, over 1 year 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 27 minutes 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 over 1 year ago
  • πŸ‡«πŸ‡·France goz

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

  • Status changed to Active over 1 year 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 over 1 year 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 over 1 year 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 over 1 year 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 over 1 year 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 over 1 year 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 over 1 year 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 over 1 year ago
  • πŸ‡¬πŸ‡§United Kingdom alexpott πŸ‡ͺπŸ‡ΊπŸŒ

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

  • Status changed to RTBC over 1 year 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 over 1 year 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 over 1 year 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