It’s hard to believe, but it’s been two years since we shared the 2.0 release of our in-house, open-sourced, code quality and security tool, Salesforce Code Analyzer (originally named Salesforce CLI Scanner). We’re now ready to launch Code Analyzer version 3.x, which brings together multiple open-source static application security testing (SAST) tools to help you write secure and clean code. In this blog post, we’re excited to share a preview of its great new features!
What’s new in 3.x
- Support for more engines. In addition to PMD and ESLint, Code Analyzer now supports:
-
- RetireJS, which notifies you when your solution’s JavaScript dependency versions have known security vulnerabilities
- Copy-Paste Detector (CPD), which helps you detect large blocks of copy and pasted code, and also reminds you when your code is past due for refactoring
- Capture more complex violations. We’re much closer to bridging the gap between violations found locally versus what can be detected only during the AppExchange Security Review process. Read on to find out more.
General approach to identifying code issues
Many static analysis tools identify problematic code by converting each file or class into its abstract syntax tree (AST) format and analyzing it. Simply put, an AST is a representation of code in its basic blocks, arranged in a hierarchical format. To detect an issue, such as an unused local variable, the static analysis tool examines the code hierarchy, checks that every local variable has an invocation, and creates a violation when the invocation isn’t found.
This approach identifies a large number of code issues. However, it isn’t an intuitive approach to identifying more complex issues that span multiple classes across multiple files, requiring information on how a certain line of code was invoked.
Supplementing with data flow analysis (DFA)
Did I just hear a few Computer Science enthusiasts cheering? Well, you have every reason to because data flow analysis (DFA) is a technique that supplements the general AST approach and captures more complex scenarios. DFA consumes the entire code source simultaneously, and assimilates this information to produce a better understanding of what’s happening in the code. As a part of this assimilation, DFA breaks down the control flow of the code and builds paths that span conditionals, class instantiations, and many levels of method invocations and static calls. At every point on each path, DFA attempts to predict the value of the variables and fields involved.
This is exactly what we have implemented for Apex, and we call it the Salesforce Graph Engine.
Salesforce Graph Engine
Salesforce Graph Engine is the newest engine to join Code Analyzer’s backend as a part of 3.x. It performs DFA on Apex and identifies issues of much higher complexity than a regular static analysis engine. Graph Engine differentiates between one instance of a class and another, distinguishes various scopes within a class while walking a path, understands inheritance, and more.
Most importantly, Graph Engine is available as open source on GitHub.
Detect missed CRUD/FLS checks
For the first release of Graph Engine, we have implemented rules that detect when a data operation is missing Create Read Update Delete/Field Level Security (CRUD/FLS) checks. We selected CRUD/FLS as our first rule because it’s one of the most elusive issues, typically caught only during the AppExchange Security Review process. ISV developers can now use the power of Graph Engine during development and be better prepared when publishing their solution on AppExchange.
Reduce false positives
From time to time, there may be times when you as a Salesforce ISV developer prefer not to perform a CRUD/FLS check for a data operation. Perhaps your code is invoked only by a page that’s restricted to admins, or your code is protected through a mechanism that Graph Engine doesn’t understand. However, you can let Graph Engine know that your code is protected by using an engine directive. An engine directive is a specially formatted comment that conveys to Graph Engine that it can safely avoid analyzing the related code for a specific type of violation. Engine directives help reduce false positives and provide more valuable code feedback.
Transition to Code Analyzer 3.x with Graph Engine
Start using Graph Engine and all the newest features of Code Analyzer 3.x right away.
Look at our try-it-yourself page to explore Graph Engine’s capabilities.
All Code Analyzer users will transition to Code Analyzer 3.x by the end of October 2022. If you’re using Code Analyzer 2.x in your continuous integration/continuous development (CI/CD) process, we recommend that you make the switch today to make sure that your transition is smooth.
Run Code Analyzer 3.x with Graph Engine
A great way to get started with Graph Engine is to install our sample app.
To begin, clone the dev
branch of the Code Analyzer repo.
Next, open the sample directory.
Notice that AuraEnabledFls.cls
contains a number of @AuraEnabled
methods that can be called from an Aura Component. Let’s focus on the flsInIfBranchOnly
method.
Here’s how this method works.
- The method receives a Boolean
enterIfBranch
as an argument. It attempts to insert an Account and return it after creation. - To ensure that the user calling this method has the correct permissions, Code Analyzer first instantiates the helper class
FlsHelperClass
, passing Account as an argument. If you look at howFlsHelperClass
is instantiated, you see it obtains a map of the various fields available in the Account object. - Code Analyzer identifies the fields that you want to check for user permissions. In this case, Name and Phone.
- Code Analyzer then has an
if
condition that only executes code ifenterIfBranch
is true. The code being executed here calls theverifyCreateable
method inFlsHelperClass
for Name and Phone. And it throws aPermissionsException
if the user doesn’t have the appropriate permissions to insert data into these fields. This is where our CRUD/FLS check takes place, but this check only takes place ifenterIfBranch
is true. - After Code Analyzer exits the
if
condition, and assuming no exception was thrown, it inserts an Account record and returns it.
As you can see, the if
condition in Step 4 creates two different paths for code execution:
- A path where
enterIfBranch
is true, which checks that the user has the correct CRUD/FLS permissions. - A path where
enterIfBranch
is false, which skips the CRUD/FLS check and inserts the Account record. This path contains a security vulnerability that you must address.
A static code analysis of this method would be unable to detect that these two paths exist. This point is where Graph Engine’s data flow analysis truly shines because it is able to create paths based on the enterIfBranch
variable and determine whether any of them contains a vulnerability.
Test it yourself by running Graph Engine with the target set to the lsInIfBranchOnly
method in AuraEnabledFls.cls
.
Notice that Graph Engine reports an ApexFlsViolationRule
.
"ApexFlsViolationRule","FLS validation is missing for [INSERT] operation on [Account] with field(s) [Name,Phone]"
You have multiple ways to fix this method.
- Move the CRUD/FLS check out of the
if
branch so it’s always run - Move the data markup language (DML) operation into the
if
branch so it’s only run in the path that performed the CRUD/FLS check - Add an
else
branch that performs the same CRUD/FLS checks as theif
branch
Let’s go with the first option and update flsInIfBranchOnly
.
Now run Graph Engine again.
Review what Graph Engine returns.
Executed engines: sfge. No rule violations found.
This method is now free of vulnerabilities related to the lack of CRUD/FLS checks. Great work!
Check out more examples across other methods and classes in the sample app, and read more about Code Analyzer and Graph Engine in our documentation.
Conclusion
The Salesforce Code Analyzer team is constantly improving Code Analyzer and adding newer rules to Graph Engine. We’d love to hear your feedback and feature requests.
Useful links
What’s new in 3.x
Working with SFGE
About the authors
Roopa Mohan is a Principal Engineer at Salesforce and the Lead Engineer for Salesforce Code Analyzer. She’s been with Salesforce for almost eleven years, with much of this time on the Hammer team, where she helped improve the quality of major releases. As a part of Platform-Ops team, Roopa and her teammates focus on building tools that make the lives of ISVs a little easier.
John Belo is Director, Product Management for ISV Platform, focusing on Salesforce Code Analyzer, AppExchange App Analytics, as well as other areas within Packaging. He’s been with Salesforce for over seven years and has always been a part of the AppExchange team. He started by leading a team of ISV Technical Evangelists in EMEA, and is now part of the AppExchange Product Management team, always intent on helping ISVs be as successful as they can be.