Migrating to Permission Sets for DX
You’re starting to work with Salesforce DX and re-organizing your source, maybe using packages or maybe into separate folders or separate repos. We’ve been calling this process “Untangling the Org” and one of the big places things get tangled up in is Profiles. Your Admin profile references nearly everything you’ve ever built in your org. In this blog post, we’re going to explore together how moving from Profiles to Permission Sets can make untangling easier.
Permission sets: a quick review
Permission sets were released in version 23 [Winter 12!]. What problem do they address?
Let’s say you’ve got a profile, Sales User. Some Sales Users need your new Commissions app, some don’t. So you clone the profile and save it as Sales User with Commission.
But Sales Users in Japan also need three extra fields on the Opportunity. So now you have:
- Sales User
- Japan Sales User
- Sales User with Commissions
- Japan Sales Users with Commissions
You see this is going to get out of hand quickly. The next feature (Customer Invoices) is going to take you from four profiles to eight.
Because users can only be assigned one profile, we created permission sets. You can give the Japan permission set to some users and the Commissions permission set to some users, and both permission sets to some users in Japan who need Commissions and just have one Sales profile. Fewer profiles is a good thing!
Since permission sets are “stackable”, you can analyze your current profiles, look for common permissions (like Commissions and Japan), and think about how to make that a permission set.
What you don’t want to do is a 1:1 conversion (take everything out of a profile and put it in a permission set), because Sales User Japan with Commissions is as bad of a permission set as it is a profile. Usually, permission sets are smaller and more granular than profiles.
Maybe you can remove permissions from lots of profiles into one permission set and apply it to all those users. Maybe you have seven profiles and could use just two if the differences were put into permission sets.
Thinking about these permissions as layers and reorganizing can make Admin-ing your org much simpler, regardless of whether you’re trying to modularize your org now or later.
Profiles in Salesforce DX
As customers are adopting Salesforce DX and decomposing their org into packages, permission sets become a way to address a new problem. Even if you’re not using packaging, you may have experienced some challenges migrating profiles and keeping them synced between environments.
Imagine that your packaging structure will look like these four packages (for more on packaging strategy, see our blog post on organizing packages by deployment dependencies):
- Common (contains account/contact objects and shared Apex classes)
- Sales (lead, opportunity, some custom objects related to Sales)
- Service (Cases, Field Service, and some custom objects that are for service)
- Manufacturing (custom objects)
Where do you put something like the Admin profile? A single profile that’s served you well for a decade might reference Sales AND the common objects. Which repo/package does it live in? It can’t go in Common because it contains references to the Sales, Service and Manufacturing objects/fields. However, it can’t go in any of the other apps either because it’ll reference objects not in those packages.
As you divide your metadata into packages, you’ll find yourself dividing profiles as well. Since profiles have a 1:1 relationship to user, we’ll move their contents to Permission Sets to split them apart.
Besides untangling your metadata, perm sets are much easier for other CLI-based development tasks. You can add a few with
sfdx force:user:permset:assign to the org’s Admin user, who is assigned a base Admin profile, so that your org can correctly load data, run tests, or do other automated setup scripts or CI tasks.
Should I stay or should I go now?
Ever looked at a profile? You can see the metadata docs for a profile here and a real-world example of a large profile here.
In our example, our Common “base package” includes account/contact objects and fields, their tabs, their layouts, their object-specific actions, their record types, etc. When we’re making that package, we’d create a permission set for those objects/fields.
Every user in our org might have this permission set, and it becomes part of the package. Next month, when we need to add a new field to Account, we do it in the Common package and add it to the perm set. When we deploy the package to production, the users have access to the field. You probably have multiple perm sets that cover these objects, for various levels of access.
Similarly, our Manufacturing package can include PermSets that covers permissions on subsets of its data, which may include an external data source that’s part of the manufacturing app and some Visualforce pages.
So far, so good for the green items.
But there are other things that don’t go to permission sets (shown in black). It’s not like we let people see account and contacts all day, but only opportunities and leads from 9 to 5, so these things makes sense to stay on the profile.
User Permissions (Grey) are special and take a bit more thought. It might be worth moving them to a PermSet (or several PermSets) for simplifying administration. If you do this, put them in your base package (common). Because these permissions, like Run Reports, Deploy Change Sets, or Moderate Chatter don’t refer to non-standard metadata, there’s no dependency issues.
DataCategories (White) are part of Knowledge and though they can be enabled with PermSets, they’re beyond the scope of this article. Read more about data categories, data category groups, and visibility.
This leaves us with the red item, which are things that PermSets don’t support because they’re 1:1 to a user. Why?
- If you were assigned two PermSets with different pageLayoutAssignments, which page would you see?
- If you were assigned two Lightning Pages by two different PermSets, which would you see?
These 1:1 assignments are part of the profile. Here are the recommendations for users in Lightning:
- If you’re not already heavily invested in profile-based page assignments, don’t use it. Lightning offers better options (dynamic component visibility based on user fields or object fields) that may solve this problem.
- If you are using these, you may still need to have a larger number of profiles than you otherwise would. See if dynamic component visibility can let you eliminate some of these complexities.
Victory means having fewer profiles — that’s a win for developers AND admins.
OK, you convinced me — how do I actually do it?
Here are four options to move permissions out of your profiles and into permissions sets.
Option 1: Use the UI
If you’re a long-time Salesforce admin, you’ll feel right at home.
- Open your profile on one screen and create a new permission set on another.
- Check boxes on the PermSet that match what you need from the profile (again, probably not everything!).
- Repeat with as many PermSets as necessary.
Option 2: Cut and paste
For developers using DX, when you get your source in your local SFDX project, open up the profile. Here’s an example:
- Create a permission set (see the metadata structure here, or create an empty perm set in the scratch org UI and pull it down).
- Note — there are a few name differences:
- Profile has tabVisibilities.
- PermissionSet has tabSettings (and the metadata inside may be slightly different).
- RecordTypeVisibility is the same on both, but Profile has some additional information inside each one.
- Cut and paste XML elements from the profile to the perm set.
- If it’s in the profile but not part of the current package, just delete.
Option 3: Plugins
I’m the type who will spend a few hours on fun creative work to save myself one hour of boring work, especially knowing it might help out others. So good news for those who are the same way: SFDX lets you write your own plugins! Here’s mine.
Here’s how to convert a profile https://github.com/mshanemc/shane-sfdx-plugins#sfdx-shaneprofileconvert
sfdx shane:profile:convert -p Admin -n MyNewPermSet
This will copy all those green items from the table above to a PermSet (either an existing one or a new one). If you add
-e it’ll remove them from the profile. It ignores the grey userPemissions, though you might want to add some of them manually, if, for example, you’re making a Service Cloud package and you want to add cases/knowledge user permissions there.
There’s also an option to -c (
--skinnyclone) which creates a new profile without all the items in your new PermSet.
If you’ve exported your app from an org to source and are starting to break it up, you’ll notice that even once you get rid of objects/tabs/classes/layouts/etc that you don’t need, the profiles may still refer to those things
will go through your profiles/permSets in local source and remove all the references to metadata that’s not part of the local repo.
All clicks, no CLI. Just pick a profile, and let the app build a permission set based on that. Then you can start removing permissions from it to shrink it down to size.
DX and permission sets
Once you’ve got your source split into packages, with PermSets built for each package, anyone who needs to work on a package can:
- Spin up a scratch org
- Push source
- Assign themselves permission set(s) needed
- Make their changes
- Test their solution, along with the permission sets
You don’t even have to do the profile changes in one pass — you can make the PermSets, assign them to users, and then go back and uncheck boxes in the profile and migrate that later. You could also switch users to the new skinnyclone profile if you used the SFDX plugin.
The DX command for that is
sfdx force:user:permset:assign -n MyPermSetName
If you’re maintaining a script to spin the org, push source, load data, etc, add the PermSet assignment command there.