Git branch protection for Salesforce: a guide for secure deployments

Git branch protection for Salesforce: a guide for secure deployments

Sam Crossland on

Share with



Your branching strategy is decided, your branches set up in the repository and orgs ready for seamless deployments as part of your source-driven development drive — but how do you protect those branches, and your Salesforce orgs, from any unexpected pushes?

In this post, we’ll dive into what branch protections are, why they’re so important, show some specific examples of protecting your branches, and a walkthrough for how these protections can be useful — regardless of deployment tool.

What are branch protection rules?

To make sure your Salesforce deployments are reliable and secure, it’s essential to establish clear branch protection rules. These rules act as quality gates to help maintain that your code is up to standard before it’s merged. This layered approach gives the whole team confidence and complete control over the merge and deployment process, while also playing a key part in your DevOps governance.

Branch protection rules allow you to set multiple conditions that must be met before your team is allowed to merge changes into a target branch. Depending on which branching strategy a team is using, they’d usually focus on their main branch as the final line of defense before production, but you can layer them earlier into other key branches too, like integration or UAT.

Here’s a list of some of the conditions you might have in one of your branch protection rules:

  • Requiring a pull request (PR) to merge into a target branch
  • Minimum number of reviewers needed to approve the PR
  • Specific ‘CODEOWNERS’ needing to approve for certain changes
  • A number of automated ‘status checks’ need to run and pass
  • The need for ‘signed commits’ to validate the source of the changes
  • Turning on the option to ‘require conversation resolution before merging’ to make sure team feedback isn’t overlooked
  • Deciding whether someone can ignore restrictions or “force push" into the target

With branch protection rules, you have the flexibility to choose which conditions apply at different stages of your workflow. For instance, some teams prefer to frontload many checks early in the process, while other elements may only become available to verify later on, closer to production.

This includes specific branch names (like UAT, main) which are case-sensitive, or patterns to match multiple branch names. A pattern is an fnmatch set of characters to help identify branches that match a particular naming convention. So setting a pattern for *release* will affect any branch containing the word “release”.

Examples scenarios of branch protections

Depending on the branching strategy you’re using you may have a small set of branches to protect, or a larger set of static branches, possibly dynamically-named, that all need catching under a pattern.

An example scenario might be:

  • Sam has completed work on a new feature branch called FeatureA, and raises a PR to take that work into the integration branch.
  • Because the integration branch sits on top of a shared integration environment where multiple team members work and testing takes place, we have a branch protection rule set up that says:
    • A minimum of 1 other person to approve
    • The PR must pass an automatic status check to validate Sam’s changes against the target
Branch protections in place for integration
  • Sam has satisfied the checks and deployed to the integration branch. But now the “main” branch before production has much stricter enforcements, like:
    • A minimum of 2 people to approve, and dismiss approvals when new commits are pushed.
    • An automatic status check to validate Sam’s changes against the target has passed.
    • All conversation (comments) must be resolved.
    • ‘Do not allow bypassing the above settings’ to prevent overrules.

Teams can get really granular by adding the exact permissions they need to protect their most crucial environments. This level of control advances far beyond the basic “approval-only" requirements, and creates a layer of extra security around the merging process.

Some providers require a specific license type to leverage branch protection rules, like GitHub and Bitbucket, while others like GitLab and Azure DevOps allow a level of protection at the free tiers.

Why are branch protections important?

We’ve explored above what branch protections are, but why are they so important to get right? Regardless of team size, teams want to ensure stability and quality across the entire shared codebase. Using branch protections can help shape the way new code is progressed through the key long-standing branches of the repository, and protect against accidental changes or deletions.

Enforcing requirements like approved reviews, automated status checks passing, and linked external ticketing all helps to safeguard against low-quality code moving into critical branches. It also reinforces best practices and accountability across the entire development team. Layering up these safeguards helps ensure the entire team is compliant, and shows any internal/external auditor that critical branches are protected.

But how do you actually get these protections set up in your repository?

How to protect your branches

Each source control provider has its own nuances and will often favor different naming conventions. Let’s look at GitHub and Azure DevOps:

GitHub

Setting up branch protection rules in GitHub is something you can do on the free license tier, but they won’t be enforced unless you have a GitHub Pro/Team license or above. You need to have relevant repository administrator/edit permissions to do this.

  • Log in to your GitHub repository, and head to the Settings section along the top bar.
GitHub’s settings page
  • Select Branches on the left-hand side panel.
Select the branches tab in settings
  • Here you can see any existing branch protection rules you have configured, and either add a new one or edit/remove any existing rules.

  • In this example, I’ll add a new one for my UAT branch. Click Add rule.

  • Type the specific branch name you want to protect. (Note the case sensitivity requirement here!)

  • Change or add any branch protection rules.

Select your branch protection rules here
  • Click Create to enable the branch protection rule for that particular repository. (Note: you may be challenged for extra verification here)

Note: GitHub may recommend using rulesets here which are a lot more granular. They also aren’t necessarily available in other version control systems (VCS) and can work in conjunction with classic branch protection rules.

These protections are now in place for one of our key branches in GitHub, and they’ll be triggered when anyone tries to merge code into that target (whether that’s in the GitHub UI, via Gearset or any other tool).

Key points to note:

  • Make sure you’re following any case sensitivity/pattern requirements for the branch names you’re interested in protecting.

  • Unless you’ve enabled Allow deletions or “Lock branch”, you won’t be able to delete this protected branch, and would need to delete the rule first.

    • Preventing deletion of these key branches (default branch and others) should be of high importance, especially if they’re used in your CI/CD Pipelines!

Azure DevOps (ADO)

Azure DevOps classify branch protections as branch policies. You can set these policies at a project-wide level that apply to all repositories, or create specific repository enforcements. Azure DevOps is different from GitHub in a few key ways:

  • Multiple enforcements can be set up as “optional” or “required” so they only flag up as a warning instead of blocking the merge.

  • Depending on the branching model you have in place, you may want to limit specific merge types (squash, rebase, merge commit).

  • Automatic reviewers policies can be added in the UI instead of having to use a CODEOWNERS file. This means you can outline reviewers for changes to specific directories/files.

  • The ability to bypass branch policies can be configured to users/groups and also on PRs or direct pushes, so you can be granular around who can ‘skip’ protections.

Force push is a specific permission that needs special care. It’s often granted to branch creators but should be controlled on key shared branches to ensure proper approvals and checks have been met, and prevent situations involving a force push.

Select your branch protection rules here

Protections in Gearset

Gearset Pipelines gives a lot of power to users wanting to align to DevSecOps practices. Embedding these branch protections in source control means we need to consider different interaction styles with your branches and tight control over security. Gearset not only respects any branch protections you have in place in your VCS, but also highlights key areas to let users know there are protections in place that could affect merging and deployment.

Gearset will show you when you are trying to deploy to a protected branch

These highlights help stop any accidental target selections resulting in direct pushes to important branches, and helps teams ensure a consistent way of working with pull requests.

You might have a more advanced CI/CD setup with a VCS that includes more automation than manual comparisons.

When using Gearset’s Pipelines, there are options available to help with scenarios such as merge conflicts, but it will also now show any mergeability blocks reported from your VCS, adhering to any protections you’ve configured as showstoppers.

In the example below we see there are “unresolved discussions”, which means there are comments on the PR that aren’t currently resolved that the developer would need to review and action. In this case, it’s the Clayton from Gearset report showing some security and reliability issues so a worthwhile stopper on merging!

Clayton from Gearset has spotted some security issues on our branch

Protections when working directly with the VCS

If you’re not using Gearset, and instead using a different deployment mechanism such as SF commands in an alternate pipeline like GitHub Actions or Bitbucket Pipelines, your protections will still function as expected. We can see from the Bitbucket PR below that, if I were on the premium plan, it would restrict this PR from merging due to multiple unsatisfied checks on the right-hand panel. In this example it’s missing reviews and the build is failing.

There are multiple checks failing on this Bitbucket PR

When raising PRs in GitHub, you would also be able to see any restrictions preventing you from merging as per the rules configured (in the example below I can still merge due to my license tier).

In GitHub, you can see any restrictions preventing you from merging

Securing your Salesforce branches

Branch protection rules are just one of the many benefits of implementing version control. This essential feature not only enhances security, but encourages best practices throughout the entire team. You can build on your version control implementation with more advanced automation and capabilities, or even a fully-fledged Gearset Pipeline, and be safe in the knowledge that your key branches are protected — with multiple enforcements in place. Start your 30-day free trial of Gearset today to fully explore Gearset Pipelines.

Ready to get started with Gearset?