D7 Features secret Rolemageddon
There’s many dirty little secrets in Drupal 7 core’s API when it comes to inconsistencies and oversights. It’s a big part of why so much care is being placed in D8 and its taking so long, because people realize this is a platform that’s used for the long haul and core decisions today will have lasting impacts a decade from now.
That said, I discovered one a year or so ago and kept putting it off, hoping it would go away on its own. Well, it hasn’t and here comes a potential scenario that I detail in an ELMSLN issue queue thread I like to call Role-mageddon. While this doesn’t just affect distributions and install profiles and features, it is a lot more likely you could run into a problem there with them; and so here we go.
Site 1 (Profile A)
- Developer Adds a Feature X that adds 2 roles
- Then creates Views, Rules, and blocks and associates roles to access / visibility
- Then they create Feature Y with 1 role and do the same as before
Site 2 (Profile A + the additions above)
- Developer Enables Feature Y
- Developer Enables Feature X
- All access / visibility criteria of Roles / functionality supplied in Y is flipped with X
- Oh Sh….
So What happened?
Roles in drupal are stored as id, name, weight. id is generated based on the database being incremented, so anonymous is always user rid 1 and authenticated rid is always 2. After that, it’s the wild west of whoever comes first gets the next id.
Well, if Roles 1 and 2 are created then Role 3, they’ll get ids of 3,4,5.
If Role 3 is created then Roles 1 and 2, they’ll get ids of 3,4,5 but all views, rules, blocks, anything associated to the rid identifier is now associated with the wrong role!
Without this knowledge you could have oh, i don’t know, made all your admin blocks visible the ‘bosswhopays’ role on production and not understood why :). This would also happen if your in dev and have a role that doesn’t move up to production that was created prior to the others that are about to. You move the features up, and none of the settings are kept.
So how do we avoid Role-mageddon?
Role Export adds a column called machine_name to the role table, and then uses the machine_name value to generate a md5 hash value which is used to create the rid. Then, so long as machine_names are unique, it effectively gaurentees that rid’s are unique and won’t collide with other roles that you import / migrate.
The import / export order no longer matters because they’ll always map to
Great for the future, but what about my existing site?
Role Export had support for automatically remapping the updated rid so your users roles don’t get lost, as well as the admin role variable and the permissions associated to the role. That’s great, without those this would have been basically worthless for existing sites.
What my patch of infinite lack of sleep provides, is the same exact thing but for Views, Rules, Blocks, Masquerade settings (since that has security implications and is popular) as well as a hook that can be invoked to fix your other variables like IMCE, Piwik, and LTI.