# developer Salesforce Code Analyzer (code-analyzer) - Full Documentation # ApexFlsViolationRule (Retired) ApexFlsViolationRule detects Create, Read, Update, and Delete and Field-Level Security (CRUD/FLS) violations. ## Definition - Source - : `@AuraEnabled`-annotated methods. `@InvocableMethod`-annotated methods. `@NamespaceAccessible`-annotated methods. `@RemoteAction`-annotated methods. Any method returning a `PageReference` object. `public`-scoped methods on Visualforce Controllers. `global`-scoped methods on any class. `Messaging.InboundEmailResult handleInboundEmail()` methods on implementations of `Messaging.InboundEmailHandler`. Any method targeted during invocation. - Sink - : All DML operations and their `Database.method()` counterparts: delete, insert, merge, undelete, update, and upsert. SOQL queries and Database.query counterpart. - Sanitizer - : Access check performed using [Schema.DescribeSObjectResult](https://developer.salesforce.com/docs/atlas.en-us.234.0.apexref.meta/apexref/apex_methods_system_sobject_describe.htm). Acceptable only for operations that require CRUD-level checks such as DELETE, UNDELETE, and MERGE. Access check performed using [Schema.DescribeFieldResult](https://developer.salesforce.com/docs/atlas.en-us.234.0.apexref.meta/apexref/apex_methods_system_fields_describe.htm). Acceptable for operations that require FLS-level checks. Includes READ, INSERT, UPDATE, UPSERT for standard data objects and custom objects. SOQL queries that use [WITH SECURITY_ENFORCED](https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_classes_with_security_enforced.htm#apex_classes_with_security_enforced). Lists filtered by [Security.stripInaccessible](https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_classes_with_security_stripInaccessible.htm). ## Interpreting Results Match any violation message that you receive with these cases to understand more about the violation. ### Common Case > _Validation-Type_–validation is missing for _Operation-Name_ operation on _Object-Type_ with fields _Comma-Separated-Fields_ where: - _Validation-Type_ - : Type of validation to be added. CRUD requires object-level checks, and FLS requires field-level checks. - _Operation-Name_ - : Data operation that must be sanitized. - _Object-Type_ - : Object on which the data operations happen. If Graph Engine couldn’t guess the object type, you see the variable name or _SFGE_Unresolved_Argument_. - _Comma-Separated-Fields_ - : Fields on which the data operation works. If you see _Unknown_ as the only field or as one of the fields, Graph Engine doesn't have enough information to guess the fields, and you must determine the unlisted fields manually. ### Additional Clause Case > _Validation-Type_ validation is missing for _Operation-Name_ operation on _Object-Type_ with fields _Comma-Separated-Fields_–Graph Engine couldn't parse all objects and fields correctly. Manually confirm if the objects and fields involved in these segments have FLS checks: _Unknown-Segments_ where: - _Validation-Type_ - : Type of validation to be added. CRUD requires object-level checks, and FLS requires field-level checks. - _Operation-Name_ - : Data operation that must be sanitized. - _Object-Type_ - : Object on which the data operations happen. If Graph Engine couldn’t guess the object type, you see the variable name or _SFGE_Unresolved_Argument_. - _Comma-Separated-Fields_ - : Fields on which the data operation works. If you see _Unknown_ as the only field or as one of the fields, Graph Engine doesn't have enough information to guess the fields, and you must determine the unlisted fields manually. This case is the same as the common case, but also Graph Engine isn't confident about the object names or field names that it detected. You also see this clause when your field or object ends with `__r`. In both cases, review the relational field, object, and the unparsed segments to ensure that they have the required CRUD/FLS checks. Next, add an [engine directive](https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/salesforce-graph-engine/working-with-graph-engine.md) to force Graph Engine to ignore this warning in the next run. ### stripInaccessible Warning Case The `stripInaccessible` warning is thrown for all `stripInaccessible` checks on READ access type. Graph Engine can't ensure that the sanitized value returned by `SecurityDecision` is the value used in the code that follows the check. Confirm the values manually, then add an engine directive to force Graph Engine to ignore this warning in the next run. Or, disable these violations by using the `--rule-disable-warning-violation` flag or by setting its corresponding environment variable, SFGE_RULE_DISABLE_WARNING_VIOLATION, to true. ### Internal Error Case > Graph Engine identified your source and sink, but you must manually verify that you have a sanitizer in this path. Then, add an engine directive to skip the path. Next, create a GitHub issue for the Code Analyzer team that includes the error and stack trace. After we fix this issue, check the Code Analyzer release notes for more info. Error and stacktrace: [details] Graph Engine encountered an error while walking this path. Manually verify that you have a sanitizer on the path, and then add an engine directive to skip the path. Next, create a GitHub issue for the Code Analyzer team that includes the error and stack trace so that we can research and resolve it. After we determine a fix for the issue, check Code Analyzer [Release Notes](https://developer.salesforce.com/docs/platform/relnotes/release-notes.md) for more info. ## See Also - [_YouTube_: Create, Read, Update, and Delete (CRUD) and Field-Level Security (FLS) Violations](https://www.youtube.com/watch?v=1ZYjpjPTIn8) - [_Apex Developer Guide_: Enforce Security With the stripInaccessible Method](https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_classes_with_security_stripInaccessible.htm) - [_Apex Developer Guide_: Enforcing Object and Field Permissions](https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_classes_perms_enforcing.htm) - [_Apex Developer Guide_: Filter SOQL Queries Using WITH SECURITY_ENFORCED](https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_classes_with_security_enforced.htm) - [Salesforce Code Analyzer FAQ](https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/faq.md) # ApexGuru Engine ApexGuru is an AI-driven performance and code optimization engine integrated into Salesforce Code Analyzer. It works alongside the PMD, ESLint, and RetireJS engines to detect SOQL inefficiencies and scalability issues in your Apex code. ApexGuru executes real-time scans on connected Salesforce orgs directly through the Salesforce CLI and delivers exact line-level highlights, severity ratings, and actionable recommendations as JSON output. Code Analyzer determines its scanning mode automatically based on your org's ApexGuru settings: - Advanced Mode: Scans runtime code when your org or its parent org family has enabled the ApexGuru engine through the Salesforce UI Setup page. - Basic Mode: Performs standard static code analysis on the connected org when neither your org nor its parent org family has enabled ApexGuru. **Note:** Scan modes are non-configurable at trigger time via the CLI or configuration files.They are automatically determined based on your org's ApexGuru settings. Org eligibility and hierarchy determine whether Code Analyzer uses Advanced or Basic Mode. For details on how inheritance works across different environments, see these [FAQs](https://help.salesforce.com/s/articleView?id=xcloud.apexguru_faq.htm&type=5) on ApexGuru. **Run a Scan via Salesforce CLI** Use the `sf code-analyzer run --rule-selector apexguru` command to run a scan with the ApexGuru engine. Specify the target org and output preferences. You must be connected to the target org. Authentication to the target org is through Salesforce CLI and not the configuration file. There's no username, password, or token property. The engine reuses your `sf login` session. ``` sf code-analyzer run \ --rule-selector apexguru \ --include-suggestions \ --output-file /tmp/apexguru.json \ --target-org ``` When the execution completes, Salesforce Code Analyzer prints a summary of findings to the console. ``` Summary Found 68 violation(s) across 61 file(s). 1 High Severity violation(s) found. 58 Moderate Severity violation(s) found. 9 Low Severity violation(s) found. Additional Log Information written to: /tmp/apexguru.json ``` **View the JSON Results** ApexGuru returns detailed JSON output for each violation, including location, issue description, severity, and suggested fixes. ``` { "engine": "apexguru", "fileName": "force-app/main/default/classes/CRL_TEST_VALIDATE_ROLLUPS.cls", "violations": [ { "ruleName": "AvoidSchemaGetObjectDescribeInApex", "severity": 3, "category": "Performance", "message": "Avoid using Schema.getGlobalDescribe() in Apex. This method causes unnecessary overhead, decreases performance, and increases latency.", "locations": [ { "startLine": 412, "startColumn": 8 } ], "primaryLocationIndex": 0, "resources": [ "https://developer.salesforce.com/site-resources/apexguru-rules#schema_getdescribe_not_efficient" ], "suggestions": [ "Use Schema.getGlobalDescribe().get('ObjectName') or direct object tokens instead." ], "tags": [ "Recommended", "Performance", "Apex" ] } ] } ``` ApexGuru scans .cls and .trigger files. ApexGuru doesn’t scan metadata XML, objects, flows, and other file types. **Integrate with CI/CD** ApexGuru scans a connected Salesforce org rather than local files, you must authenticate your org before you run the scan using ApexGuru engine. Authenticate to your target org. Use either the JSON Web Token Bearer Flow or an SFDX Auth URL. See [Authenticate a Salesforce Org in CI/CD](https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/guides/authenticate-sforg.md) for setup steps for both methods. If you use GitHub Actions, add these steps to your workflow after the authentication step to run ApexGuru through the \`run-code-analyzer\` [GitHub Action](https://github.com/marketplace/actions/run-salesforce-code-analyzer). See [CI/CD Integration](https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/guides/ci-cd.md) for general Code Analyzer CI/CD guidance that also applies to ApexGuru scans, such as writing results to an output file and using severity thresholds. **Integrate with VS Code** To get ApexGuru scan results directly in your development workspace, set the Code Analyzer Rule Selectors to `apexguru` in your extension settings. Then when you right-click a file in the Explorer or save an active Apex file, ApexGuru scans your code. In the editor, lines containing ApexGuru violations are highlighted. Hover over a line to inspect combined engine findings. For example, view PMD rules alongside ApexGuru performance warnings. As you edit and save the class file, ApexGuru updates the line numbers dynamically. ## ApexGuru Configuration Reference To customize the ApexGuru engine, add these settings to your `code-analyzer.yml` file. | Property | Type | Default | Constraints | Purpose | | :---- | :---- | :---- | :---- | :---- | | `disable_engine` | boolean | `false` | — | Turns off the ApexGuru engine. To speed up Code Analyzer output and disable ApexGuru, turn off the engine in your configuration. | | `target_org` | string | (none → default org) | Must resolve to an authenticated org | The Salesforce org to run the remote scan against. | | `api_timeout_ms` | number (ms) | `300000` `(5 min)` | `> 0` | Time limit on the scan: submit, poll, and decode. The `api_*` settings never override `api_timeout_ms`, even if you tune polling. The scan always stops at the overall timeout budget. | | `api_initial_retry_ms` | number (ms) | `2000` `(2 sec)` | `> 0` | Delay before the first poll for results. | | `api_max_retry_ms` | number (ms) | `60000 (60 sec)` | `> 0 and >= api_initial_retry_ms` | Upper limit on the delay between polls. | | `api_backoff_multiplier` | number | `2` | `>= 1` | How fast the poll delay grows after each round. | To modify rule settings, see [Customize the Configuration](https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/guide/config-custom.html). ### **Limitations on Scan** To prevent system overload and maintain scan performance, Code Analyzer enforces scan request limits at the user, org, and org family levels. | Limit Type | Threshold | Scope & Behavior | | :---- | :---- | :---- | | **Per User (Short Burst)** | 3 scans / 60 seconds | Enforced per individual Salesforce user account. | | **Per Org (Short Burst)** | 5 scans / 60 seconds | Combined aggregate limit across all users scanning the same requesting org. | | **Per Org (Daily Quota)** | 100 scans / 24 hours | Total daily limit allowed for a single requesting org. | | **Per Resolved Org (Daily Quota)** | 200 scans / 24 hours | Shared quota applied at the parent Production/Full Copy org level after org resolution | ## See Also - [Authenticate a Salesforce Org for GitHub Actions](https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/guides/authenticate-sforg.md) - [CI/CD Integration](https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/guides/ci-cd.md) # ApexNullPointerExceptionRule (Retired) ApexNullPointerExceptionRule identifies Apex operations that dereference null objects and throw NullPointerExceptions. NullPointerExceptions generally indicate underlying problems in your code to address. ## Definition - Source - : `@AuraEnabled`-annotated methods. `@InvocableMethod`-annotated methods. `@NamespaceAccessible`-annotated methods. `@RemoteAction`-annotated methods. Any method returning a `PageReference` object. `public`-scoped methods on Visualforce Controllers. `global`-scoped methods on any class. `Messaging.InboundEmailResult handleInboundEmail()` methods on implementations of `Messaging.InboundEmailHandler`. Any method targeted during invocation. - Sink - : Any object dereference is a potential sink because object dereferences are the places where a null pointer exception can be thrown. Example: `x.someMethod() ` | - Sanitizer - : Non-null initialization of variables and null checks before accessing. Examples: `String s = 'abcde';` , `if (s != null) {`. ## Interpreting Results Match any violation message that you receive with this case to understand more about the violation. ### Common Case > ApexNullPointerExceptionRule identifies Apex operations with a high likelihood of throwing a NullPointerException The operation dereferences a null object and throws a NullPointerException. Review your code and add a null check. ## Examples In these examples, Apex Runtime throws a `System.NullPointerException` at the place where an operation is performed on a null object. The Graph Engine ApexNullPointerException rule preemptively identifies these operations. ``` public void example1() { Object myStr = null; System.debug(myStr.toLowerCase()); // throws System.NullPointerException // since method is invoked on null object. } public void example2(String myStr) { if (myStr == null) { // The following line throws System.NullPointerException, since the conditional confirms // that myStr is null when it reaches here. System.debug(myStr.toLowerCase()); } } public void example3() { Integer i; // Not initialized Integer y = i + 2; // throws System.NullPointerException since // binary operation is invoked on null object } ``` To fix NullPointerException issues, use one of these methods. - Check that the object is `not-null` before performing the operation. - Make sure that all variables are initialized. Avoid initializing variables to `null`. If your logic demands initialization to `null`, make sure to reassign a value to your variable before you invoke an operation on it. # Authenticate a Salesforce Org in CI/CD Set up automated authentication between CI/CD platform and your Salesforce org to continuously scan your code in Salesforce Code Analyzer. Choose the authentication method that best fits your environment. * **JSON Web Token Bearer Flow:** This approach is recommended for enterprise pipelines and team repositories. It uses a Connected App and an X.509 digital certificate to authenticate without storing static access tokens. * [**SFDX Auth URL**](https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_auth_web_flow.htm)**:** This lightweight, quick-start method is ideal for solo developers, rapid prototyping, or temporary sandboxes. It captures an existing authenticated CLI session URL into a single repository secret. This workflow uses GitHub for source control, GitHub Actions to automate CI/CD, and ApexGuru to scan the code for potential issues. ## Prerequisites Before configuring the authentication method, complete these steps on your local workstation. * [Install the Salesforce CLI](https://developer.salesforce.com/docs/atlas.en-us.sfdx_setup.meta/sfdx_setup/sfdx_setup_install_cli.htm#sfdx_setup_install_cli) * Identify the target Salesforce org * Create a dedicated integration user to prevent pipeline failures when team members change roles or leave. We recommend not binding CI/CD pipelines to individual user accounts ## Authorize a Salesforce Org by Using a JWT Bearer Flow This approach is recommended for enterprise pipelines and team repositories. It uses a Connected App and an X.509 digital certificate to authenticate without storing static access tokens. 1. In your local workspace, generate an RSA private key and a self-signed digital certificate using OpenSSL. OpenSSL is pre-installed on macOS and available via Git Bash on Windows. See [Create a Private Key and Self-Signed Digital Certificate](https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_auth_key_and_cert.htm). Retain `server.key` (Private key — store in GitHub) and `server.crt` (Public cert — upload to Salesforce). Remove `server.pass.key` and `server.csr`. 2. In your target org, create an external client app to authorize the incoming JWT requests. 1. In your Salesforce org, click **Setup App Manager** or **External Client Apps** and create an external client app. 2. Select **Enable OAuth Settings**. 3. Set the callback URL to http://localhost:1717/OauthRedirect. 4. Select **Enable JWT Bearer Flow** and upload your `server.crt` file. 5. Add these OAuth scopes. 1. Manage user data via APIs (api) 2. Perform requests at any time (refresh\_token, offline\_access) 3. Manage user data via Web browsers (web) 6. Configure pre-authorization policies. 7. Under **OAuth Policies**, for Permitted Users, select **Admin approved users are pre-authorized**. 8. Under App Policies, add your Integration User’s profile or permission set to the Selected list. 9. For IP Restrictions, select **Relax IP restrictions**. 10. Save the app, and copy the generated Consumer Key (Client ID). 3. Store the credentials in GitHub. 1. In your GitHub repository, click **Settings,** click **Secrets and variables**, and then click **Actions**. 2. Click **New repository secret** and add these key-value pairs. | Secret Name | Value | | :---- | :---- | | SF\_CLIENT\_ID | The consumer key copied from your external client app. | | SF\_PRIVATE\_KEY | The content of server.key, including \-----BEGIN/END PRIVATE KEY-----. | | SF\_USERNAME | The dedicated integration user for example, ci-codeanalyzer@yourcompany.com. | | SF\_INSTANCE\_URL | Your Salesforce My Domain URL (for example, \[https://yourcompany.my.salesforce.com\](https://yourcompany.my.salesforce.com). | 4. In your `.github/workflows/ci.yml` pipeline file, add the authentication step before running the Code Analyzer scan. ``` `name: Authenticate to Salesforce Org` `run: |` `echo "${{ secrets.SF_PRIVATE_KEY }}" > server.key` `sf org login jwt \` `--client-id ${{ secrets.SF_CLIENT_ID }} \` `--jwt-key-file server.key \` `--username ${{ secrets.SF_USERNAME }} \` `--instance-url ${{ secrets.SF_INSTANCE_URL }} \` `--set-default` `rm server.key` ``` ## Authorize a Salesforce Org by Using an SFDX Auth URL This lightweight, quick-start method is ideal for solo developers, rapid prototyping, or temporary sandboxes. It captures an existing authenticated CLI session URL into a single repository secret. 1. Log in to your machine using your dedicated integration user, and then print the auth URL. ``` # Log in interactively (opens a browser) sf org login web --alias ci-org # Print the SFDX Auth URL for that org sf org display --verbose --target-org ci-org ``` Copy the value of the `Sfdx Auth Url` field, which starts with `force://...`. Alternatively, export directly as JSON. ``` sf org display --verbose --json --target-org ci-org ``` Copy the value under `result.sfdxAuthUrl`. **Note**: You need the `--verbose` flag to display the auth URL. To revoke access later, from Setup, in the Quick Find box, enter `Connected Apps OAuth Usage`, and then select **Connected Apps OAuth Usage**. Revoke the Salesforce CLI app for that user. 2. Store the credentials in GitHub. In your GitHub repository, click **Settings,** click **Secrets and variables,** and then click **Actions**. Click **New repository secret** and add the value that you copied in the `Sfdx Auth Url` field. 3. Create or update your pipeline file at `.github/workflows/code-analyzer.yml`. ``` `name: Test run-code-analyzer@v2 (ApexGuru)` `on:` `pull_request:` `branches: [main]` `workflow_dispatch:` `jobs:` `code-analysis:` `permissions:` `pull-requests: write` `contents: read` `actions: read` `runs-on: ubuntu-latest` `steps:` `- name: Check out files` `uses: actions/checkout@v5` `- name: Setup Java` `uses: actions/setup-java@v5` `with:` `distribution: 'zulu'` `java-version: '>=11'` `- name: Install Salesforce CLI` `run: npm install -g @salesforce/cli@latest` `- name: Install Code Analyzer Plugin` `run: sf plugins install @salesforce/plugin-code-analyzer@latest` `- name: Authenticate to Salesforce` `env:` `SFDX_AUTH_URL: ${{ secrets.SFDX_AUTH_URL }}` `run: echo "$SFDX_AUTH_URL" | sf org login sfdx-url --set-default --sfdx-url-stdin` `- name: Run Salesforce Code Analyzer` `id: run-code-analyzer` `uses: forcedotcom/run-code-analyzer@v2` `with:` `run-arguments: --workspace . --rule-selector apexguru --output-file sfca_results.html --output-file sfca_results.json` `results-artifact-name: code-analyzer-results` `github-token: ${{ github.token }}` `- name: Print results` `run: |` `echo "Exit code: ${{ steps.run-code-analyzer.outputs.exit-code }}"` `echo "Total violations: ${{ steps.run-code-analyzer.outputs.num-violations }}"` `echo "Sev1: ${{ steps.run-code-analyzer.outputs.num-sev1-violations }}"` `echo "Sev2: ${{ steps.run-code-analyzer.outputs.num-sev2-violations }}"` `echo "Sev3: ${{ steps.run-code-analyzer.outputs.num-sev3-violations }}"` ``` The `--sfdx-url-stdin` reads the URL from standard input (piped from `echo`), preventing sensitive tokens from writing to disk. `--set-default` targets this org for the Code Analyzer execution that follows. ### Troubleshooting * If several repositories share credentials, don’t duplicate secrets manually. In your GitHub repository, click **Settings,** click **Secrets and variables,** and then click **Actions**. Click **New repository secret**. Set repository access to **All repositories** or **Selected repositories** for centralized management and rotation. * GitHub-hosted runners draw from a large, dynamic pool of public IP addresses. If your org enforces strict login IP restrictions, apply these resolution steps: * **JWT:** Make sure that the external client app is configured to **Relax IP restrictions** under OAuth Policies. * **SFDX Auth URL:** Relax the Login IP Ranges, In the Integration User's profile or org Network Access settings, relax the login IP ranges. Alternatively, if your organizational policies forbid relaxing IP rules, use self-hosted GitHub runners with fixed static IP addresses and allowlist those IP addresses in Salesforce. ## See Also - [ApexGuru](https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/guides/engine-apexguru.md) - [CI/CD Integration](https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/guides/ci-cd.md) # AvoidDatabaseOperationInLoop (Retired) AvoidDatabaseOperationInLoop detects database operations that occur inside loops and that cause performance degradation. Database operations within loops cause performance degradations and exceed Salesforce governor limits. ## Definition - Source - : `@AuraEnabled`-annotated methods. `@InvocableMethod`-annotated methods. `@NamespaceAccessible`-annotated methods. `@RemoteAction`-annotated methods. Any method returning a `PageReference` object. `public`-scoped methods on Visualforce Controllers. `global`-scoped methods on any class. `Messaging.InboundEmailResult handleInboundEmail()` methods on implementations of `Messaging.InboundEmailHandler`. Any method targeted during invocation. - Sink - : Any database operation. ## Interpreting Results Match any violation message that you receive with this case to understand more about the violation. ### Loop Case > A database operation occurred inside a loop.` [%s at %s:%d]` Your code executes a database operation inside a loop statement. To move the database operation outside the loop, modify and then rescan your code. ## Best Practices To remediate database operation violations, move these operations outside of loops. Follow these best practices. - Instead of querying objects within a loop, use a SOQL `for` loop to iterate over a query’s results. For example, instead of: ``` for (String name : names) { Account[] accs = [SELECT Name FROM Account WHERE Name =: name]; ``` Use: ``` for (Account[] accs : [SELECT Name FROM Account WHERE Name IN :names]) { ``` - Instead of putting database operations within a loop, use the loop to iteratively construct lists of objects, and then perform the database operation on the full list after the loop. For example, instead of: ``` for (String n : names) { insert new Account(Name = n); ``` Use: ``` Account[] accs = new List(); for (String n : names) { accs.add(new Account(Name = n)); } insert accs; ``` # AvoidMultipleMassSchemaLookups Rule (Retired) AvoidMultipleMassSchemaLookups is a path-based rule that detects scenarios where expensive schema lookups are made more than one time in a path and cause performance degradation. AvoidMultipleMassSchemaLookups identifies these methods: - `Schema.getGlobalDescribe()` - `Schema.describeSObjects(...)` Flagged lookups include: - Lookups within these types of loops: `ForLoopStatement`, `ForEachLoopStatement`, `DoWhileStatement`, and `WhileLoopStatement` - Multiple expensive schema lookups that are invoked - An expensive schema lookup that is executed multiple times These common scenarios trigger a violation from AvoidMultipleMassSchemaLookups. - `Schema.getGlobalDescribe()` within a loop - `Schema.describeSObjects(...)` within a loop - `Schema.getGlobalDescribe()` preceding a `Schema.getGlobalDescribe()` or `Schema.describeSObjects(...)` method call anywhere in the path - `Schema.describeSObjects(...)` preceding a `Schema.describeSObjects(...)` or `Schema.getGlobalDescribe()` method call anywhere in the path ## Definition - Source - : `@AuraEnabled`-annotated methods. `@InvocableMethod`-annotated methods. `@NamespaceAccessible`-annotated methods. `@RemoteAction`-annotated methods. Any method returning a `PageReference` object. `public`-scoped methods on Visualforce Controllers. `global`-scoped methods on any class. `Messaging.InboundEmailResult handleInboundEmail()` methods on implementations of `Messaging.InboundEmailHandler`. Any method targeted during invocation. - Sink - : `Schema.getGlobalDescribe()`. `Schema.describeSObjects(...)`. ## Interpreting Results Match any violation message that you receive with these cases to understand more about the violation. ### Loop Case > `Schema.getGlobalDescribe` was called inside a loop. `[ForEachStatement at AuraEnabledFls:27]` Your code calls `Schema.getGlobalDescribe()` or `Schema.describeSObjects(...)` inside a loop statement. To move the `Schema.getGlobalDescribe()` or `Schema.describeSObjects(...)` outside the loop, modify and then rescan your code. ### Multiple Schema Lookups Are Invoked Case > Multiple expensive schema lookups are invoked. `[Schema.describeSObjects at AuraEnabledFls:27]` Your code invokes `Schema.getGlobalDescribe()` preceded by `Schema.describeSObjects`. Modify your code so that only one expensive schema lookup is invoked. ### More Than One Execution in a Path Case > `Schema.getGlobalDescribe` executed multiple times in the call stack. `[getFields at AuraEnabledFls:27, getFields at AuraEnabledFls:28, getFields at AuraEnabledFls:29]` `Schema.getGlobalDescribe` or `Schema.describeSObjects` is executed multiple times in a single path. Reduce the execution of the method to one time, then rescan your code # CI/CD Integration with Code Analyzer We recommend that you integrate Salesforce Code Analyzer into your Continuous Integration/Continuous Development (CI/CD) process to scan your code regularly for potential problems. ## Call Code Analyzer To integrate Code Analyzer into your CI/CD tool, call the `code-analyzer run` CLI command in any scripts used by your tool. Call the command whenever CI/CD detects changes to your code. Follow these CI/CD best practices. - To write your results to a file and produce a results artifact for use with your CI/CD tool, use the `-f/--output-file` flag. Use file extensions to specify the format of the output file. For example, `--output-file results.xml` creates an XML file. - To cause a non-zero exit code when any violations meet or exceed the provided value, use the `-t/–-severity-threshold` flag. Many CI/CD tools require thresholds. ## Accelerate Your GitHub CI/CD Integration To accelerate your continuous integration/continuous (CI/CD) development, create a GitHub Action workflow that uses the [`run-code-analyzer` GitHub Action](https://github.com/marketplace/actions/run-salesforce-code-analyzer). GitHub Action workflows provide opportunities to automate your entire pipeline, from building and testing to deployment. The `run-code-analyzer` GitHub Action scans your code for violations using Salesforce Code Analyzer, uploads the results as an artifact, and displays the results as a job summary. **note:** Be sure you use v2 of the `run-code-analyzer` GitHub Action, which in turn uses Code Analyzer v5. The old v1 version of the GitHub Action uses Code Analyzer v4, which is retired and no longer supported. If you’re using Lifecycle Center, you can use the `run-code-analyzer` GitHub Action as you promote changes, helping you identify and address issues earlier in your development pipeline. If you're using Code Analyzer as one of the test providers in Lifecycle Centre Testing, this integration helps ensure code quality standards are maintained throughout your deployment pipeline. With the `run-code-analyzer` Action, you can: - Customize what arguments to pass with your scan. - Customize the name of the results artifact. - Pass it a checked-in `code-analyzer.yml` file, just like with the `code-analyzer run` CLI command. With `run-code-analyzer`, take control of your workflow’s next steps with these outputs: - The Salesforce Code Analyzer execution exit code. - The total number of violations found. - The number of critical-, high-, medium-, low-, and info-severity violations found. For usage info on the `run-code-analyzer` GitHub Action, read [run-code-analyzer documentation](https://github.com/marketplace/actions/run-salesforce-code-analyzer) on the [GitHub Actions Marketplace](https://github.com/marketplace). ## Code Analyzer Tools for Other CI Vendors Our community of users also develop tools that help you speed up Salesforce Code Analyzer integration into your CI/CD process. ### Azure DevOps The [Salesforce Code Analyzer Task](https://marketplace.visualstudio.com/items?itemName=SamCrossland.salesforce-code-analyzer-ado-repos-task) extension works with [Azure DevOps](https://azure.microsoft.com/en-us/products/devops) and allows you to run Salesforce Code Analyzer v5 on the changed files in a pull request or on full branches to identify technical debt. It reports code violations, publishes results, and can fail the build to let you block merges. This tool was developed by Sam Crossland. ### Copado DevOps If you’re using [Copado](https://www.copado.com/) for your DevOps needs, then you can use [Code Analyzer for Copado](https://success.copado.com/s/listing-detail?recordId=a545p000000Xx1hAAC&language=en_US) to run Code Analyzer as a quality gate in your pipeline. It runs on the changed components in your commits and deployments. You can choose the severity of errors that cause it to fail and block your deployments, or just report violations without blocking. As with standard Code Analyzer, you can also use the configuration file to customize which engines are run, create new rules, and customize existing rules. This tool was developed by Abhishek Saxena. # CI/CD Integration with Code Analyzer (Retired) We recommend that you integrate Salesforce Code Analyzer into your Continuous Integration/Continuous Development (CI/CD) process to scan your code regularly for potential problems. Code Analyzer makes it easier to identify issues ahead of submitting your code for the AppExchange Security Review. ## Call Code Analyzer To integrate Code Analyzer into your CI/CD tool, call the appropriate `run` command in any scripts used by your tool. We recommend that you call: - `sf scanner run` whenever CI/CD detects changes to code. - `sf scanner run dfa` with `--target {all_classes}` on a scheduled basis, such as nightly. Why do we recommend that `sf scanner run dfa` is executed only on a scheduled basis? Depending on the number of paths it generates, Salesforce Graph Engine can take some time to execute when you include all target classes. Alternatively, you can limit the number of paths and speed up Graph Engine execution in your CI/CD by reducing the number of targets using the flag `--target {specific_class}` as you can see [here](https://forcedotcom.github.io/sfdx-scanner/en/v3.x/scanner-commands/dfa/). ### Replace this value: - ``, ``: The source code location. Follow these CI/CD best practices. - Use the `--format junit` flag, a standard format used by the CI/CD tool. - To write your results to a file and produce a results artifact for use with your CI/CD tool, use the `-o/--outfile {name}.xml` flag. - To cause a non-zero exit code when any violations meet or exceed the provided value, use the `-s/–severity-threshold` flag. Many CI/CD tools require thresholds. ### Replace this value: - `.xml`: The location where to write the output file. ## Accelerate Your CI/CD Integration To accelerate your continuous integration/continuous (CI/CD) development, create a GitHub Action workflow that uses the `run-code-analyzer` GitHub Action. GitHub Action workflows provide opportunities to automate your entire pipeline, from building and testing to deployment. The `run-code-analyzer` GitHub Action scans your code for violations using Salesforce Code Analyzer, uploads the results as an artifact, and displays the results as a job summary. If you’re using DevOps Center, you can use the `run-code-analyzer` GitHub Action as you promote changes, helping you identify and address issues earlier in your development pipeline. With the `run-code-analyzer` Action, you can customize: - Which Salesforce Code Analyzer command to run: run or run dfa - What arguments to pass with your scan - The name of the results artifact With `run-code-analyzer`, take control of your workflow’s next steps with these outputs: - The Salesforce Code Analyzer execution exit code - The total number of violations found - The number of normalized low-, medium-, and high-severity violations found For usage info on the `run-code-analyzer` GitHub Action, read [run-code-analyzer documentation](https://github.com/marketplace/actions/run-salesforce-code-analyzer) on the [GitHub Actions Marketplace](https://github.com/marketplace). ## Other CI/CD Tools Our community of users continues to develop templates and tools that help you speed up Code Analyzer integration into your CI/CD process. Try these community tools: - [SFDX Scan Pull Request](https://github.com/marketplace/actions/sfdx-scan-pull-request) by Mitchell Spano - [Pull Request SFDX Code Review](https://github.com/marketplace/actions/pull-request-sfdx-code-review) by Aleš Remta # CLI Command Reference See the [Salesforce CLI Command Reference](https://developer.salesforce.com/docs/atlas.en-us.sfdx_cli_reference.meta/sfdx_cli_reference/cli_reference_code-analyzer_commands_unified.htm) for online reference about the new `code-analyzer` commands. The online guide contains the same content as running the commands with the `--help` flag. # Code Analyzer Architecture (Retired) Code Analyzer is an open-source Salesforce CLI plug-in. Most of the code is written in TypeScript in the Node.js framework, and some is written in Java. Code Analyzer is powered by multiple static analyzers, also known as rule engines, and by Salesforce Graph Engine ## Code Analyzer Internals Code Analyzer engines specialize in different aspects of static analysis and support multiple languages. Each rule engine has its own unique set of rules, input parameters, and formats for reporting the results. Code Analyzer unifies these rules engines as a single static analyzer and provides a common user experience. ![Salesforce Code Analyzer architecture with callouts on UserInput (A), Rule Catalog (B), CLI Commands and Options (C), CLI Library (D), Rule Engine Interface (E), and Rule Violations Report (F)](https://developer.salesforce.com/media/salesforce-code-analyzer/code-analyzer-architecture.png) To scan code with Code Analyzer, users provide their source code and select rules to run (A) from the rule catalog (B). Next, CLI Commands and Options (C ) accept a user’s source code for analysis and the selected rules and parameters to apply to each scan. CLI Commands and Options: - are built on the Salesforce framework - pass the scan information to the CLI Library (D) The CLI Library contains the Rule Engine Interface (E) that extends to the included engines in the backend: - PMD, including Custom-PMD - Eslint, including Eslint-Typescript, Eslint-LWC, Eslint-Custom - RetireJS - CPD - Graph Engine When the CLI Library receives the scan parameters, it executes the relevant engines based on the file types in the provided source code and in the selected rules. After the Code Analyzer execution completes, it collects violations and passes them back to the CLI Commands and Options. Finally, CLI Commands and Options constructs a Rule Violations Report (F) as user output. ## Rule Engine Unification To provide a consistent experience while using multiple rule engines, Code Analyzer has two bridging blocks: a rule catalog and a rule engine bridge. ### Rule Catalog Each rule engine has a different set of rules and different formats for representing them. Code Analyzer communicates with each rule engine separately to pull the default rules that they offer and to populate them together into a rule catalog. This catalog contains the name of a rule, a short description, its classification category, and the code source language that the rule can analyze. To view the rule catalog, run the `scanner rule list` command. The command’s output includes the rule-engine name that a particular rule belongs to, as shown in this example. ``` | Name | Languages | Categories | Rulesets [Dep] | Engine | | MyRule2 | apex | design | Complexity,Default ruleset...,quickstart | pmd | | MyRule3 | Javascript | insecure | dependencies | retire-js-sfge | | FormalParameterNamingConventions | apex | Code Style | quickstart | pmd | | constructor-super | javascript | problem | problem | eslint | | insecure-bundled-dependencies | javascript | Insecure Dependencies | | retire-js | | ApexFlsViolationRule | apex | Security | | sfge | ``` ### Rule Engine Bridge By unifying the representation of the rules into a rule catalog, Code Analyzer accepts a uniform set of input parameters. Here’s how it works. 1. Using rules that you select, the bridge detects the related engine and determines the target files based on the file types defined in `~/.sfdx-scanner/{{ site.data.versions-v3.configfile }}`. 2. Next, the bridge tailors the input for each relevant rule engine and hands the input to the rule engine for the actual scan. 3. After the scan completes and the rule engine provides the results, the bridge surfaces the rule-violation results in a normalized output format. ## Source Code and Contribution The code for Code Analyzer is in [the /forcedotcom/sfdx-scanner repo on GitHub](https://github.com/forcedotcom/sfdx-scanner). Salesforce is working on expanding and improving the tool. ## See Also - [_sf Plugin Developer Guide_](https://github.com/salesforcecli/cli/wiki) # Code Analyzer Command Reference (Retired) This command reference contains information about Salesforce Code Analyzer commands and their flags. ## Get Started To scan your code and output any violations found to a results file, run: - `sf scanner run --target somefile.js --outfile results.html` ### Replace these values: - `somefile.js`: The source code location. - `results.html`: The output format. To scan your code with a specific engine, run - `sf scanner run --target /some/dir --engine cpd` ### Replace these values: - `/some/dir`: The source code location. - `cpd`: The engine or engines to run. ## CI/CD Integration To continuously improve your code, integrate Code Analyzer results into your CI/CD tool. Your tool can interpret those violations and act on them. ## Graph Engine To scan your code with Graph Engine data-flow analysis, run: - `sf scanner run dfa --target ./myproject/main/default/classes/*.cls --projectdir ./myproject/` ### Replace these values: - `./myproject/main/default/classes/*.cls`: The source code location. - `./myproject/`: The root project directory. # CPD Use the Copy/Paste Detector (CPD) engine to identify blocks of duplication across files written in various languages. When you run Code Analyzer in your project and specify this engine, any violations include the files in which the duplication was found, along with the location of the duplicate blocks. We recommend that you use the `--view detail` flag which makes it easier to review the output. For example: ```bash sf code-analyzer run --rule-selector cpd --view detail ``` Check the `locations` section of the violation output for the files that contain the duplication. For example: ```bash === 1. DetectCopyPasteForXml severity: 5 (Info) engine: cpd message: Duplicate code detected for language 'xml'. Found 2 code locations containing the same block of code consisting of 236 tokens across 37 lines. locations: (main) force-app/main/default/flexipages/Broker_Record_Page.flexipage-meta.xml (1:1-37:18) force-app/main/default/flexipages/Property_Record_Page.flexipage-meta.xml (1:1-37:18) resource: https://docs.pmd-code.org/latest/pmd_userdocs_cpd.html#refactoring-duplicates ``` ## Available CPD Rules Code Analyzer supports these languages associated with CPD: Apex, HTML, JavaScript, TypeScript, Visualforce, and XML. Run this command to view detailed information about the CPD rules for all available languages: ```bash sf code-analyzer rules --rule-selector cpd --view detail ``` For information on how to modify rule settings, such as their severity or tags, see [Customize Your Configuration](https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/guide/config-custom.md). While the examples show modifying rules for the ESLint and Regex engines, you use the same process to modify CPD rules. ## CPD Configuration Reference You can configure the CPD engine with the settings listed in this table. See [Customize the Configuration](https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/guide/config-custom.md) for details on how to apply the settings. | Field | Type | Description | | --- | --- | --- | | `disable_engine` | boolean | Whether to turn off the 'cpd' engine so that it is not included when running Code Analyzer commands. Default value is `false`. | | `java_command` | string | Indicates the specific 'java' command associated with the JRE or JDK to use for the 'cpd' engine. May be provided as the name of a command that exists on the path, or an absolute file path location. If unspecified, or specified as null, then an attempt will be made to automatically discover a 'java' command from your environment. Default value is `null`. | | `file_extensions` | object | Specifies the list of file extensions to associate to each rule language. The rule(s) associated with a given language will run against all the files in your workspace containing one of the specified file extensions. Each file extension can only be associated to one language. If a specific language is not specified, then a set of default file extensions for that language will be used. Default value is `{"apex": [".cls", ".trigger"], "html": [".html", ".htm", ".xhtml", ".xht", ".shtml", ".cmp"], "javascript": [".js", ".cjs", ".mjs"], "typescript": [".ts"], "visualforce": [".page", ".component"], "xml": [".xml"]}`. | | `minimum_tokens` | object | Specifies the minimum tokens threshold for each rule language. The minimum tokens threshold is the number of tokens required to be in a duplicate block of code in order to be reported as a violation. The concept of a token may be defined differently per language, but in general it is a distinct basic element of source code. For example, this could be language specific keywords, identifiers, operators, literals, and more. See https://docs.pmd-code.org/latest/pmd_userdocs_cpd.html to learn more. If a value for a language is unspecified, then the default value of 100 will be used for that language. Default value is `{"apex": 100, "html": 100, "javascript": 100, "typescript": 100, "visualforce": 100, "xml": 100}`. | | `skip_duplicate_files` | boolean | Indicates whether to ignore multiple copies of files of the same name and length. Default value is `false`. | ## See Also - [Finding duplicated code with CPD](https://docs.pmd-code.org/latest/pmd_userdocs_cpd.html) # CPD (Retired) Shipped with PMD, CPD helps identify blocks of duplication across files. ## How can you use CPD through Salesforce Code Analyzer? By default, the CPD engine isn’t enabled and isn’t run with a generic `scanner run` command. To specifically invoke CPD, you use the `--engine` option, like this: ``` sf scanner run --target /some/path --engine cpd ``` ## Interpreting the Violation Message Because CPD returns duplicated code fragments, meaningful output contains more than one file as a part of a group. Salesforce Code Analyzer represents each group by a short checksum of the corresponding code fragment. Every violation message contains this checksum, the number of tokens in the checksum, the total number of occurrences of this duplicated code, and the index of the current occurrence. This information can help you understand the impact of the duplication. Consider this sample violation thrown from the CPD engine. ``` { "line":"1", "column":"1", "endLine":"39", "endColumn":"12", "ruleName":"copy-paste-detected", "severity":3, "message":"c42bf68: 1 of 5 duplication segments detected. 39 line(s), 242 tokens.", "category":"Copy/Paste Detected", "url":"https://pmd.github.io/latest/pmd_userdocs_cpd.html#refactoring-duplicates" } ``` The message shows that there are four other duplicated segments in other files. Find these segments by searching for `c42bf68` among the remaining violations detected. The number of lines and tokens in the message shows how large the duplicated block is. The `line`, `column`, `endLine`, and `endColumn` values help identify the actual block of code fragment within the file. ## See Also - [_PMD Source Code Analyzer Project_: CPD](https://pmd.github.io/latest/pmd_userdocs_cpd.html) - [_PMD Source Code Analyzer Project_: Why should you care about duplicates?](https://pmd.github.io/latest/pmd_userdocs_cpd.html#why-should-you-care-about-duplicates) # Create a Custom PMD Rule Using MCP Tools (Developer Preview) Use the MCP tools `get_ast_nodes_to_generate_xpath` and `create_custom_rule` to generate custom PMD rules for Apex and Visualforce code in MCP clients such as Agentforce Vibes. Define organization-specific coding standards and detect custom patterns by entering a prompt that describes what to flag, such as deeply nested if statements or `System.debug` usage in Apex. Code Analyzer uses `get_ast_nodes_to_generate_xpath` to extract AST nodes and generate XPath with AI, then uses `create_custom_rule` to create the rule and add it to `code-analyzer.yml`. To create a custom PMD rule to flag deeply nested if statement, use these steps 1. [Access the Code Analyzer MCP tools](https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/guides/mcp.md) 2. In an MCP client such as Agentforce Vibes, enter a prompt like: “Help me create a rule to flag if statements that are three levels deep.” 3. The tool generates a sample code that violates the rule. Approve or refine the sample code. ``` { "sampleCode": "public with sharing class NestedIfViolationExample {\n\tpublic static Integer checkDepth(Integer a, Integer b, Integer c, Integer d) {\n \tInteger x = 0;\n \tif (a > 0) { \t// depth 1\n \tif (b > 0) { \t// depth 2\n \tif (c > 0) { \t// depth 3\n \tif (d > 0) {\t// depth 4 -> VIOLATION (>= 4)\n \tx = 1;\n \t}\n \t}\n \t}\n \t}\n \treturn x;\n\t}\n}\n", "language": "apex", "engine": "pmd" } ``` 4. The tool generates the XPath by extracting the relevant AST nodes for your prompt. Modify the query as needed. ![MCP client generates xpath query](https://developer.salesforce.com/docs/media/salesforce-code-analyzer/generate-xpath.png) 5. The tool creates the rule in an XML file and updates the code-analyzer.yml with the new rule. ![MCP client generates xpath file](https://developer.salesforce.com/docs/media/salesforce-code-analyzer/xpath-file.png) ![MCP client updates config file with the rule](https://developer.salesforce.com/docs/media/salesforce-code-analyzer/config-file.png) 6. Verify the rule by running Code Analyzer against your target codebase. For example: ``` sf code-analyzer run --target "force-app/main/default/classes/NestedIfExample.cls" ``` ![Verify the rule against a target code base](https://developer.salesforce.com/docs/media/salesforce-code-analyzer/verify-target.png) You can also ask the tool to generate additional sample code that violates the rule, so you can confirm the analyzer flags the expected violations. ## See Also - [PMD Engine](https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/guide/engine-pmd.md) - [Use MCP Tools to Analyze Your Code](https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/guide/mcp.md) # CSV Rules Output Schema Reference This example shows how to create a comma-separated values (CSV) formatted output file when using the `--output-file` flag of the `code-analyzer rules` command. ```bash sf code-analyzer rules --rule-selector flow --output-file rules-results.csv ``` ## Sample CSV Rules Output This sample output shows the two rules associated with the `flow` engine. ```csv "name","severity","engine","tags","resources","description" "PreventPassingUserDataIntoElementWithoutSharing",2,"flow","Recommended,Security,XML",,"Avoid passing user data into Flow Scanner elements in run mode: Without Sharing" "PreventPassingUserDataIntoElementWithSharing",4,"flow","Recommended,Security,XML",,"Avoid passing user data into Flow Scanner elements in run mode: With Sharing" ``` ## Properties of the CSV Rules Output File All string property values are wrapped in double quotes which allows for comma-separated properties, such as the list of tags associated with the rule. | Property Name | Data Type | Description | | ------------- | --------- | ----------------------------------------------------------------------------------------------------------------------- | | `name` | string | The name of the rule. | | `severity` | number | The default severity level of the rule: 1 (Critical), 2 (High), 3 (Moderate), 4 (Low), 5 (Info) | | `engine` | string | The [engine](https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/guide/engines.md) that's associated with the rule. | | `tags` | string | The tags that are associated with the rule, such as `Recommended`, `Security`, or `BestPractices`. Multiple tags are separated by commas. | | `resources` | string | The URLs for additional resources and information about the rule. Multiple resources are separated by commas. | | `description` | string | The description of the rule. | # CSV Run Output Schema Reference This example shows how to create a comma-separated values (CSV) formatted output file when using the `--output-file` flag of the `code-analyzer run` command. ```bash sf code-analyzer run --output-file results.csv ``` ## Sample CSV Run Output This sample output shows 3 violations with different severities from different engines. ```csv "rule","engine","severity","tags","file","startLine","startColumn","endLine","endColumn","message","resources" "@lwc/lwc/no-inner-html","eslint",2,"Recommended,LWC,Security,Javascript","force-app/main/default/staticresources/highlight/highlight/prism.js",571,17,571,26,"Using 'innerHTML/outputHTML/insertAdjacentHTML' is not allowed","https://github.com/salesforce/eslint-plugin-lwc/blob/v2.1.0/docs/rules/no-inner-html.md" "PreventPassingUserDataIntoElementWithSharing","flow",4,"Recommended,Security,Xml","force-app/main/default/flows/Get_Customer_Details.flow-meta.xml",41,1,,,"User controlled data flows into recordLookups element selector in run mode: SystemModeWithSharing", "ApexSharingViolations","pmd",3,"Recommended,Security,Apex","force-app/main/default/classes/ExperienceBookingHelper.cls",1,1,1,7,"Apex classes should declare a sharing model if DML or SOQL/SOSL is used","https://docs.pmd-code.org/pmd-doc-7.11.0/pmd_rules_apex_security.html#apexsharingviolations" ``` ## Properties of the CSV Run Output File All property values are wrapped in double quotes which allows for comma-separated properties, such as the list of tags associated with the violation. CSV output includes only the primary location of a violation. If a violation has multiple locations, you must rerun the scan and specify any other output format, such as SARIF or JSON, to see all the locations. | Property Name | Data Type | Description | | ------------- | --------- | ----------------------------------------------------------------------------------------------------------------------- | | `rule` | string | The name of the rule that's associated with the violation. | | `engine` | string | The [engine](https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/guide/engines.md) that's associated with the violation. | | `severity` | number | The severity level of the violation: 1 (Critical), 2 (High), 3 (Moderate), 4 (Low), 5 (Info) | | `tags` | string | The tags that are associated with the rule that's associated with the violation. Multiple tags are separated by commas. | | `file` | string | The pathname of the file in which the violation occurred, relative to the `runDir` directory. | | `startLine` | number | The line where the violating code starts. | | `startColumn` | number | The column in the `startLine` where the violating code starts. | | `endLine` | number | The line where the violating code ends. | | `endColumn` | number | The column in the `endLine` where the violating code ends. | | `message` | string | The violation message. | | `resources` | string | The URLs for additional resources and information about the violation. Multiple resources are separated by commas. | # Customization (Retired) Create your own custom rules to highlight issues specific to your codebase as rule violations when you scan your code. Why? When your codebase has specific and repetitive coding issues that you want to address, you can use the built-in rules of Salesforce Code Analyzer to find these rule violations. But sometimes the problems exist only in the context of your codebase—and sometimes Code Analyzer’s built-in rules won’t catch them—so you need your own custom rules. You can author your own custom PMD or ESLint rules. Because PMD and ESLint custom rules work differently, Code Analyzer deals with each in distinct ways. # Customize the Configuration The default Code Analyzer configuration meets the needs of most users. However, you can also customize how Code Analyzer works by creating a YAML configuration file that helps you: - Configure top-level Code Analyzer properties, such as the location of the log files. See [Top-Level Customization Reference](https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/guide/config-toplevel.md) for details. - Override the properties of existing rules, such as their severity or tags. See [Engines](https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/guide/engines.md) for links to specific engine documentation and their rules. - Adjust engine properties, including adding custom rules. See [Engines](https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/guide/engines.md) for links to specific engine documentation, including their configuration. - Ignore Code Analyzer violations for specific files to reduce noise in scan results. Ignoring them reduces the time spent reviewing expected or acceptable patterns. **note:** If you include the same file in both `target` and `ignores` objects then the `ignores` setting takes precedence and the file isn't analyzed for violations. We recommend that you name the file `code-analyzer.yml` or `code-analyzer.yaml` and put it in the root of your workspace. The VS Code extension, and each `code-analyzer` CLI command, checks the current folder for either of these files, and if found, applies the overrides. When using CLI commands, you can also use the `--config-file` flag to specify a different location or name. This flag is available on all CLI commands. ## Create and Examine the `code-analyzer.yml` File The easiest way to get started is to create a `code-analyzer.yml` file that shows your current configuration. Run this CLI command, which creates the file in the current folder. ```bash sf code-analyzer config --output-file code-analyzer.yml ``` The generated file contains lots of comments to help you create your own customizations. But let’s look at a simple example of an uncommented `code-analyzer.yml` file to see how this custom configuration works. ```yaml log_folder: /Users/john.doe/code-analyzer/logs ignores:  files:   - "**/utils.js" rules:  regex:   NoTrailingWhitespace:    severity: 2    disabled: true    tags: ["CodeFormat"]  eslint:   sort-vars:    severity: Info    tags: ["Recommended", "Suggestion"] suppressions:  disable_suppressions: false  "src/controllers/":   - rule_selector: "eslint:complexity,pmd:CyclomaticComplexity"    max_suppressed_violations: 50    reason: "Technical debt from v1.0 - tracked in JIRA-1234" engines:  eslint:   eslint_config_file: .eslintrc.json  regex:   custom_rules:    NoTodoComments:     regex: /\/\/\s*TODO\b/gi     file_extensions: [".cls", ".trigger"]     description: Prevents TODO comments from being in Apex code.     violation_message: Found a comment in an Apex file with a TODO statement.     severity: Moderate     tags: ["Recommended", "CodeFormat"] ``` The `log_folder` property is top-level and specifies the folder that contains all the Code Analyzer log files, in this case `/Users/john.doe/code-analyzer/logs`. Use the `ignores` section of the `code-analyzer.yml` file to ignore violations from a specific file or a group of files. To ignore violations from a specific file, provide the relative path of the file. For example, `"**/utils.js"` ignores violations in `utils.js` in your project. Use the `rules` section of the config file to override the severity and tags of existing rules. In the earlier example, the `eslint:sort-vars` rule has a new severity (`Info`) and new tags (`Recommended` and `Suggestions`). The example then shows how to override the tags of the `regex: NoTrailingWhiteSpace` rule so that it's no longer Recommended by default. You can also ignore violations of specific type in all the files in your workspace using the `disabled` property. Suppress violations from a specific file or folder by using the suppressions section of the `code-analyzer.yml` file. See [suppression object properties](https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/guide/suppress-violations.md#suppress-violations-in-a-file-or-folder) for more information. Use the `engines` section to customize engines. In the example, the eslint engine is provided with an ESLint Configuration file and the regex engine is configured with a new custom rule called `NoTodoComments`. This new rule scans Apex code files which always have the extension `.cls` or `.trigger` for the string `TODO`. **tip:** The regular expression that you specify for the `regex` property must include a global modifier. For example, this `regex` value is valid: `/Todo/gi`. But this value isn’t valid: `/Todo/i`. If you configure a regular expression that doesn’t have the global modifier, and then try to run the rule, the regex engine returns an error ## See How `code-analyzer.yml` Affects the Command Results Let’s look at the configuration file in action! For comparison, first run this command in a folder that _doesn’t_ contain a `code-analyzer.yml` or `code-analyzer.yaml` file: ```bash sf code-analyzer rules --rule-selector eslint:sort-vars ``` The command returns this information about the `eslint:sort-vars` rule: ```bash # Name Engine Severity Tag ─ ───────── ────── ──────────── ───────────────────────────────────── 1 sort-vars eslint 3 (Moderate) BestPractices, Javascript, Typescript ``` Now imagine running the same command, but the folder now contains the sample `code-analyzer.yml` file shown earlier. Because the configuration overrides the properties of the `eslint:sort-vars` rule, the output now looks like this: ```bash # Name Engine Severity Tag ─ ───────── ────── ──────── ─────────────────────── 1 sort-vars eslint 5 (Info) Recommended, Suggestion ``` As you can see, the severity is now `5 (Info)` and it has the `Recommended` and `Suggestion` tags. This example returns `Found 0 rules` when you run it in a folder that doesn’t contain the sample config file: ```bash sf code-analyzer rules --rule-selector regex:NoTodoComments ``` But wait, didn’t we add the NoTodoComments rule to the regex engine? We did, but to use it you must specify the config file! This time, rather than run the command from a folder that contains the config file, we use the `--config-file` to specify its location. ```bash sf code-analyzer rules --rule-selector regex:NoTodoComments --config-file ../code-analyzer.yml ``` The command now returns this output, which is exactly what is configured in the `code-analyzer.yml` file: ```bash # Name Engine Severity Tag ─ ────────────── ────── ──────────── ─────────────────────── 1 NoTodoComments regex 3 (Moderate) Recommended, CodeFormat ``` The examples in this topic are all for `code-analyzer rules` command, but the same custom behavior applies to `code-analyzer run`. Pretty groovy, huh! # Engines Code Analyzer is pre-bundled with these engines. They are all enabled by default and are available when you use either CLI commands or the VS Code extension to analyze your code. | Rule Engine | Description | Engine Short Name to Use in CLI Commands | | ----------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------- | | [CPD](https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/guide/engine-cpd.md) | Identifies blocks of duplication across files. | `cpd` | | [ESLint](https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/guide/engine-eslint.md) | Evaluates JavaScript and TypeScript code. | `eslint` | | [Flow Scanner](https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/guide/engine-flow.md) | Audits Salesforce Flows and reports detailed information about security issues. New for v5! | `flow` | | [PMD](https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/guide/engine-pmd.md) | Allows for static analysis of code written in a number of supported languages, such as Apex and Visualforce. Includes the PMD AppExchange rules. | `pmd` | | [RetireJS](https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/guide/engine-retire-js.md) | Analyzes a project’s third-party JavaScript dependencies and identifies security vulnerabilities. | `retire-js` | | [Regex](https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/guide/engine-regex.md) | Uses regular expressions (regex) to search your code base for patterns. New for v5! | `regex` | | [Salesforce Graph Engine](https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/guide/engine-sfge.md) | Open-source Salesforce tool that performs complex analysis on Apex code and identifies security vulnerabilities and code issues. | `sfge` | | [ApexGuru Engine](https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/guide/engine-apexguru.md) | Executes real-time scans on connected Salesforce orgs directly through the Salesforce CLI and delivers exact line-level highlights. | `apexguru` | # Engines (Retired) These engines are available with Salesforce Code Analyzer. | Rule Engine | Description | Engine Specification | | ----------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- | -------------------- | | [Salesforce Graph Engine](https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/guide/salesforce-graph-engine.md) | Detects security and quality issues in code as an open-source Salesforce tool | sfge | | [PMD](https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/guide/pmd-engine.md) | Allows for static analysis of code written in a number of supported languages, including Java, Apex, and Visualforce | pmd | | [PMD-AppExchange](https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/guide/pmd-engine.md) | Helps you prepare your managed packages for security review | pmd-appexchange | | [CPD](https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/guide/cpd-engine.md) | Identifies blocks of duplication across files | cpd | | [ESLint](https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/guide/eslint-engine.md) | Evaluates Javascript code | eslint | | [ESLint](https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/guide/eslint-engine.md) Lightning Web Component | Evaluates Salesforce Lightning Web Components | eslint-lwc | | [ESLint](https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/guide/eslint-engine.md) Typescript | Evaluates any targeted TypeScript (.ts) files | eslint-typescript | | [RetireJS](https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/guide/retirejs-engine.md) | Analyzes a project’s third-party JavaScript dependencies and identifies security vulnerabilities | retire-js | # ESLint ESLint is a popular linting tool for JavaScript, TypeScript, and LWC. It provides numerous static-analysis rules that help developers write quality code. Code Analyzer v5 currently [supports both ESLint v8 and v9](https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/guide/engine-eslint.md#how-code-analyzer-supports-both-eslint-v8-and-v9). Unless specifically called out, the rest of this topic assumes you're using the v9 ESLint configuration. ## Available ESLint Rules Run this command to view details about all the ESLint rules bundled with Code Analyzer. ```bash sf code-analyzer rules --rule-selector eslint --view detail ``` For details about the bundled rules, see: - [ESLint rules for JavaScript](https://eslint.org/docs/latest/rules/) - [TypeScript-ESLint rules for TypeScript](https://typescript-eslint.io/rules/) - [ESLint-LWC rules for JavaScript Lightning Web Components](https://github.com/salesforce/eslint-plugin-lwc) - [Salesforce Lightning Design System (SLDS) 2](https://www.npmjs.com/package/@salesforce-ux/eslint-plugin-slds). (Scroll down to the "Supported Rules" section for the list of included rules.) For information on how to modify the settings of these bundled ESLint rules, such as their severity or tags, see [Customize Your Configuration](https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/guide/config-custom.md). ### Analyze React Components Use the ESLint engine to identify issues in JSX accessibility standards, optimized component lifecycle management, and strict linting configurations for hooks and syntax best practices. - **[ESLint Plugin React](https://github.com/jsx-eslint/eslint-plugin-react/tree/master/docs/rules)**: Governs JSX syntax, automatically validates component display names, and prevents unstable nested components to streamline UI logic - **[ESLint Plugin React Hooks](https://react.dev/reference/eslint-plugin-react-hooks)**: Maintains the integrity of functional components by enforcing Rules of Hooks and verifying reactive values in dependency arrays - **[Accessibility Rules (jsx-a11y)](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/main/docs/rules)**: Identifies accessibility gaps during development, such as missing alt text for images, incorrect form label links, and non-interactive elements used as buttons without ARIA roles To analyze files by using the React rule within the ESLint engine, run: ```bash sf code-analyzer rules --rule-selector eslint:React ``` **note:** All react rules use the React tag We recommend enabling React rules if your project uses React for web development. JavaScript rules alone don’t catch React-specific issues and can report false positives. Code Analyzer automatically ignores Lightning Web Components (LWC) rules for `.jsx` and `.tsx` files. If your standard `.js` files contain React logic, disable LWC rules to prevent false positives. Use the `disable_react_base_config` property in the `code-analyzer.yml` file to configure the execution of the React rules for the code base. The React rules are enabled by default. ``` engines: eslint: disable_lwc_base_config: false disable_javascript_base_config: false disable_react_base_config: false auto_discover_eslint_config: false ``` ## Add Custom ESLint Configuration and Rules ESLint itself, outside of the Code Analyzer context, is highly configurable. For example, you can disable rules, change whether an existing rule is a warning or an error, add custom rules, and more. You typically use a configuration file to change the configuration. ESLint provides [many options](https://eslint.org/docs/latest/use/configure/configuration-files) for the name of the configuration file, but for simplicity, this document assumes it's called `eslint.config.js`. By default, Code Analyzer doesn't use your ESLint config file because it can conflict with the base configuration of the bundled rules. If you want to apply your ESLint config file, then either directly specify it with the `eslint_config_file` option or set the `auto_discover_eslint_config` option to `true` in your Code Analyzer configuration file. This example shows how to configure the file using an absolute path; you can also specify its location relative to the `config_root` top-level option: ```yml engines: eslint: eslint_config_file: /Users/jdoe/configs/eslint.config.js ``` Alternatively, you can specify that Code Analyzer dynamically find the ESLint configuration file: ```yml engines: eslint: auto_discover_eslint_config: true ``` If Code Analyzer finds an ESLint config file, it automatically attempts to merge it with base configurations associated with the built-in rules. Let's look at a few examples to see how this works. - You update your `eslint.config.js` configuration file and change an existing ESLint rule to be an error rather than a warning. Code Analyzer honors this change and reflects the new severity; you can see this change by running `sf code-analyzer rules --rule-selector eslint:RuleName`. As with all Code Analyzer rules, you can then override this severity by updating the `code-analyzer.yml` file. - You add a [custom ESLint rule](https://eslint.org/docs/latest/extend/ways-to-extend), Code Analyzer automatically adds it to the list of ESLint rules that you can view and run. And you can then modify the settings of this custom rule, such as its severity or tags, just like you can modify all the other rules that Code Analyzer knows about. As a convenience, Code Analyzer automatically adds the `Custom` tag to custom rules. Run this command to see all the custom ESLint rules: ```bash sf code-analyzer rules --rule-selector eslint:Custom ``` ## How Code Analyzer Merges Its Base ESLint Config With Your Config Here are additional details about how Code Analyzer automatically attempts to merge its base ESLint configuration with an ESLint configuration file that it finds in your workspace. The ESLint v9 flat configuration is essentially an array of configuration objects. When Code Analyzer finds an ESLint configuration file, it appends the objects in the file to the base Code Analyzer configuration objects. If within this array, one of your configuration objects references a plugin that's also referenced by one of Code Analyzer's base configuration objects, then Code Analyzer attempts to resolve the potential conflict using this strategy: - If the version of the plugin referenced by Code Analyzer's base config is greater than or equal to the version of the same plugin referenced by your configuration, then your configuration's plugin is replaced with Code Analyzer's. - If the version of the plugin referenced by Code Analyzer's base config is less than the version of the same plugin referencd in your configuration, then the plugin in the base Code Analyzer configuration is replaced with yours. This strategy resolves most conflicts, but it doesn’t always work. If you find an `eslint` engine error associated with your configuration, then you can disable Code Analyzer's base configuration and use only your own. Do this by setting the appropriate `disable_*_base_config` option to `true` in your `code-analyzer.yml` file. For example, set `disable_lwc_base_config` to `true` to disable the base LWC rules for JavaScript files. ```yml engines: eslint: auto_discover_eslint_config: true disable_lwc_base_config: true ``` ## How Code Analyzer Supports Both ESLint v8 and v9 As discussed in the [ESLint documentation](https://eslint.org/docs/latest/use/migrate-to-9.0.0#flat-config), ESLint v9 introduced a new configuration file called `eslint.config.js` that has a different format from the legacy (v8) file (`.eslintrc.json`), which is now deprecated. Code Analyzer, however, currently supports both ESLint v8 and v9. Read on to learn how Code Analyzer determines which ESLint version to use. In general, if Code Analyzer detects legacy v8 ESLint configuration files, it uses ESLint v8 to run the `eslint` rules. If it finds the new v9 flat configuration files, it uses ESLint v9 instead. If no ESLint configuration files are found, Code Analyzer defaults to using ESLint v9. But depending on whether you're using a `code-analyzer.yml` file, and have set values for the `eslint` engine options in the file, then these general rules might not apply. Here's a breakdown of the different scenarios. **Scenarios:** - **You don't use a `code-analyzer.yml` configuration file** If you aren't using a `code-analyzer.yml` file, Code Analyzer defaults to using ESLint v9 to run the `eslint` rules, even if you have legacy v8 ESLint configuration files in your workspace. This happens because, without a `code-analyzer.yml` file, the `auto_discover_eslint_config` option defaults to `false`, which means that Code Analyzer doesn't search for or apply any ESLint configuration files in your workspace. - **You do use a `code-analyzer.yml` configuration file** If you're using a `code-analyzer.yml` file, then there are a few different scenarios to determine whether Code Analyzer uses ESLint v8 or v9. - You set the `auto_discover_eslint_config` option to `true`. Here's how Code Analyzer determines which ESLint version to use, in order: - If Code Analyzer discovers a legacy (v8) file (such as `.eslintrc.json`), then it uses ESLint v8. - If Code Analyzer discovers a new (v9) flat config file (such as `eslint.config.js`), then it uses ESLint v9. Code Analyzer ignores any `.eslintignore` files. - If Code Analyzer doesn't find any configuration files, but finds a legacy `.eslintignore` file, then it uses ESLint v8. - If Code Analyzer doesn't find any configuration files or a `.eslintignore` file, then it uses ESLint v9. - You set the `eslint_config_file` to an ESLint configuration file. - If you set it to a legacy (v8) file, such as `.eslintrc.json`, then Code Analyzer uses ESLint v8. - If you set it to a new (v9) flat file, such as `eslint.config.js`, then Code Analyzer uses ESLint v9. - You set the `eslint_ignore_file` to an ignore file (used only in v8) and `eslint_config_file` to `null`. - Code Analyzer uses ESLint v8. ## ESLint Configuration Reference You can configure the ESLint engine with the settings listed in this table. See [Customize the Configuration](https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/guide/config-custom.md) for details on how to apply the settings. | Field | Type | Description | | --- | --- | --- | | `disable_engine` | boolean | Whether to turn off the 'eslint' engine so that it is not included when running Code Analyzer commands. Default value is `false`. | | `eslint_config_file` | string | Your project's main ESLint configuration file. May be an absolute path or a path relative to the config_root. If null and auto_discover_eslint_config is true, then Code Analyzer will attempt to discover/apply it automatically. We currently support both flat and legacy ESLint configuration files, but will be removing support for legacy eslintrc ESLint configuration files in the coming months. See https://eslint.org/docs/latest/use/configure/configuration-files to learn more. Default value is `null`. | | `eslint_ignore_file` | string | Your project's legacy ".eslintignore" file. May be an absolute path or a path relative to the config_root. If null and auto_discover_eslint_config is true, then Code Analyzer will attempt to discover/apply it automatically. Legacy ".eslintignore" files are currently only supported with ESLint v8 when used alongside of legacy ESLint configuration files. We will be removing support for ESLint v8 and this field in the coming months. Therefore, we recommend that you instead supply the files that you wish to ignore within a flat ESLint configuration file, specified by the eslint_config_file field. See https://eslint.org/docs/latest/use/configure/ignore to learn more. Default value is `null`. | | `auto_discover_eslint_config` | boolean | Whether to have Code Analyzer automatically discover/apply any ESLint configuration and ignore files from your workspace. Default value is `false`. | | `disable_javascript_base_config` | boolean | Whether to turn off the default base configuration that supplies the standard ESLint rules for JavaScript files. The base configuration for JavaScript files adds the rules from the "eslint:all" configuration to Code Analyzer. See https://eslint.org/docs/latest/rules for the list of rules. Default value is `false`. | | `disable_lwc_base_config` | boolean | Whether to turn off the default base configuration that supplies the LWC rules for JavaScript files. The base configuration for LWC adds the rules from the "@salesforce/eslint-config-lwc/recommended" and "plugin:@lwc/lwc-platform/recommended" configurations to Code Analyzer. See https://github.com/salesforce/eslint-config-lwc and https://www.npmjs.com/package/@lwc/eslint-plugin-lwc-platform. Default value is `false`. | | `disable_slds_base_config` | boolean | Whether to turn off the default base configuration that supplies the SLDS rules for Lightning Web Components and Aura Components. The base configuration for SLDS adds the rules from the "plugin:@salesforce-ux/eslint-plugin-slds/recommended" configuration to Code Analyzer. See https://www.npmjs.com/package/@salesforce-ux/eslint-plugin-slds Default value is `false`. | | `disable_typescript_base_config` | boolean | Whether to turn off the default base configuration that supplies the standard rules for TypeScript files The base configuration for TypeScript files adds the rules from the "plugin:@typescript-eslint:all" configuration to Code Analyzer. See https://typescript-eslint.io/rules and https://eslint.org/docs/latest/rules for the lists of rules. Default value is `false`. | | `disable_react_base_config` | boolean | Whether to turn off the default base configuration that supplies the React/JSX rules for .jsx and .tsx files The base configuration for React adds the rules from the "eslint-plugin-react" configuration to Code Analyzer. See https://www.npmjs.com/package/eslint-plugin-react for the list of rules. Default value is `false`. | | `file_extensions` | object | Extensions of the files in your workspace that will be used to discover rules. To associate file extensions to the standard ESLint JavaScript rules, LWC rules, or custom JavaScript-based rules, add them under the 'javascript' language. To associate file extensions to the standard TypeScript rules or custom TypeScript-based rules, add them under the 'typescript' language. To associate file extensions to standard LWC HTML rules, Component (CMP) rules, or custom HTML rules, add them under the 'html' language. To associate file extensions to CSS or SCSS rules, add them under the 'css' language. To allow for the discovery of custom rules that are associated with any other language, then add the associated file extensions under the 'other' language. Default value is `{"javascript": [".js", ".cjs", ".mjs", ".jsx"], "typescript": [".ts", ".tsx"], "html": [".html", ".htm", ".cmp"], "css": [".css", ".scss"], "other": []}`. | # ESLint (Retired) ESLint is a popular linting tool for JavaScript. It provides numerous static-analysis rules that help developers write quality code. ## How Salesforce Code Analyzer Uses ESLint The Code Analyzer `scanner run` command uses ESLint to scan targeted JavaScript files. By default, all rules are executed, but you can change which rules are evaluated through Code Analyzer optional flags described in the Code Analyzer Command Reference. ESLint is highly configurable and Code Analyzer supports these plug-ins. - [TypeScript-ESLint](https://github.com/typescript-eslint/typescript-eslint) adds support for [TypeScript](https://typescriptlang.org), a strongly typed superset of JavaScript. By default, this plug-in is used to evaluate any targeted TypeScript (`.ts`) files. - [ESLint-LWC](https://github.com/salesforce/eslint-plugin-lwc), the official ESLint rules for Salesforce Lightning Web Components (LWC). ESLint rules aren’t enabled by default. They can be enabled on a per-run basis with the `--engine eslint-lwc` flag or on a permanent basis by directly modifying the `config.json` file. ## See Also - [ESLint](https://eslint.org/) - [Salesforce Code Analyzer Command Reference](https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/command-reference/code-analyzer-command-reference.md) # ESLint Customization (Retired) To bring in the power of any ESLint capabilities that aren’t supported by default in Salesforce Code Analyzer, use your own customized `.eslintrc.json`. You have the flexibility to use different parsers or plug-ins, and you can define your own custom ESLint ruleset. To invoke a customized ESLint file, pass in your config file filepath as a value to `--eslintconfig` flag in `scanner run` command. For example: ``` `$ sf scanner run --target /path/to/your/target --eslintconfig /path/to/.eslintrc.json` ``` ## Your ESLint Custom Configuration Responsibilities Before setting up your custom configuration with ESLint through Code Analyzer, make sure that you understand your responsibilities. - All npm dependencies, including ESLint, must be installed in the directory where you run the `scanner run` command. - Your custom configuration cascades into your other project configurations as though you ran ESLint directly with the `-c | –config` flag. Your custom configuration must perform all necessary overrides. - Your `.eslintrc.json` file must be in `.eslintrc` format. However, there are no restrictions on the filename. - The `.eslintignore` flag isn’t evaluated. Instead, use the `--target` flag to define the targets that you want Code Analyzer to scan. `--target` accepts a comma-separated list of any combination of files, directories, positive patterns, and negations. - Any `package.json` files with embedded ESLint configuration aren’t supported. - If your configuration executes Typescript, make sure that your `tsconfig` file is added to the configuration under `parserOptions.project`. The `--tsconfig` flag can’t be used with `--eslintconfig` flag. For example: ``` //.eslintrc.json "parseOptions": { "project": "/path/to/tsconfig.json" }, ``` ## ESlint Restrictions ESLint usage in Code Analyzer has these restrictions. - When `--eslintconfig` is provided, no other default ESLint engines run in Code Analyzer - Rule filters such as `--category` and `--ruleset` aren’t evaluated on rules selected from an ESLint custom configuration - Engine filters can be used with `--eslintconfig` flag. However, only the rules included in the config execute. PMD runs with the default set of rules, but `eslint-lwc` isn’t invoked. Instead, ESLint is invoked based on the configuration in `/path/to/.eslintrc.json`. For example: ``` $ sf scanner run --engine pmd,eslint-lwc --eslintconfig /path/to/.eslintrc.json --target /target/path ``` ## Authoring Custom ESLint Rules Writing custom ESLint rules requires creating a custom ESLint plug-in and defining rules within it.ESLint rule definitions must contain documentation. Format your documentation like this: ``` // Rule definition in index.js or where you choose to store it meta: { docs: { description: "Information about the rule" }, ... } ``` After your rule is ready and tested, add it as a dependency to the `npm` setup in the same directory where Code Analyzer runs. Use the `npm` or `yarn` version of this command. ``` yarn add file:/path/to/ESLint-plugin-my-custom npm install file:/path/to/ESLint-plugin-my-custom ``` After your rule is added, ensure that the `node_modules` directory: - Has a child directory with your plug-in’s name - Contains the `package.json`, `index.js`, and other files that you created ## Managing Custom ESLint Rules Custom rules on ESLint are handled through Code Analyzer’s [ESLint Custom Configuration](https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/custom-configuration/eslint-config.md). ### Add Rules To add your custom rules to a custom `.eslintrc.json` file, follow these steps. 1. Add your plug-in: ``` //.eslintrc.json ... "plugins": [ "my-custom", ... // Other required plugins ], ... ``` 2. Add your rule: ``` //.eslintrc.json ... "rules": { "my-custom/my-new-rule": 1, ... //Other rules }, ... ``` 3. Make sure that your directory has all the required npm dependencies, including ESLint, your custom rule plug-in, and any other applicable dependencies, such as parsers or processors. ### Run Rules Execute the `scanner run` command in the directory with all the necessary npm dependencies. For example: ``` $ sf scanner run --eslintconfig /path/to/my/.eslintrc.json --target /path/to/target ``` ## See Also - [_ESLint_: Cascading and Hierarchy](https://eslint.org/docs/latest/user-guide/configuring/configuration-files#cascading-and-hierarchy) - [_ESLint_: Configure ESLint](https://eslint.org/docs/latest/user-guide/configuring/) - [_ESLint_: Custom Rules](https://eslint.org/docs/latest/developer-guide/working-with-rules) - [_ESLint_: Create Plugins](https://eslint.org/docs/latest/extend/plugins) # Flow Scanner Use the Flow Scanner engine to audit Salesforce Flows and report detailed information about security issues. ## Available Flow Scanner Rules Run this command to view detailed information about all the Flow Scanner rules that are bundled with Code Analyzer: ```bash sf code-analyzer rules --rule-selector flow --view detail ``` See [Flow Scanner Rules Reference](https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/guide/rules-flow.md) for additional details. For information on how to modify rule settings, such as their severity or tags, see [Customize Your Configuration](https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/guide/config-custom.md). While the examples show modifying rules for the ESLint and Regex engines, you use the same process to modify Flow Scanner rules. ## Flow Scanner Configuration Reference You can configure the Flow Scanner engine with the settings listed in this table. See [Customize the Configuration](https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/guide/config-custom.md) for details on how to apply the settings. | Field | Type | Description | | --- | --- | --- | | `disable_engine` | boolean | Whether to turn off the 'flow' engine so that it is not included when running Code Analyzer commands. Default value is `false`. | | `python_command` | string | Indicates the specific Python command to use for the 'Flow Scanner' engine. May be provided as the name of a command that exists on the path, or an absolute file path location. If unspecified, or specified as null, then an attempt will be made to automatically discover a Python command from your environment. Default value is `null`. | ## See Also - [Automate Your Business Processes with Salesforce Flow](https://help.salesforce.com/s/articleView?id=platform.platform_automation.htm&type=5) # Flow Scanner Rules Reference The Flow Scanner rules help you identify security issues in your flows. To select these rules, use `--rule-selector flow`. For example, to run all the Flow Scanner rules: ```bash sf code-analyzer run --rule-selector flow ``` ## PreventPassingUserDataIntoElementWithoutSharing **Description:** This rule finds CRUD (Create, Read, Update, Delete) operations in which user controlled data either determines which Salesforce records are selected for the CRUD operation, or in which user controlled data can modify the data of the selected records. This happens in flows that run in `System Context Without Sharing`. If your flow violates this rule, the user running the flow can gain higher privileges and perform actions on records that they shouldn't have access to. This is a security risk known as a privilege escalation vulnerability. **Default Severity:** High (2) **Default Tags:** `Recommended`, `Security`, `Xml` **How to Fix:** The best fix is to change the run context of your flow from `System Context Without Sharing` to `User Context`. See [Change the Flow Run Context](https://help.salesforce.com/s/articleView?id=platform.flow_distribute_system_mode.htm&type=5) for details. If you can't change the run context of your flow, you must implement your own procedural access control checks using decision elements and custom Apex actions; see the next section for helpful resources. **False Positive Guidance:** A flow sometimes causes a violation of this rule, but the violation might be a false positive. This section provides guidance on what causes a false positive, and when you can safely ignore it. In the following two use cases, the flow is required to run in `System Context` (either with or without sharing) for its secure operation: - The flow is public-facing and used by external guests or community users, and you intend that these users perform limited operations on records that they don't have access to. - The flow code modifies or accesses only custom fields that are owned by your app and you're intentionally ignoring the platform access control policies. To safely ignore these two use cases as false positives, you must provide an alternative access control policy in the flow itself or in an Apex action called from the flow. You can't ignore the platform access control policy without building your own procedural replacement, because bypassing platform access checks places the burden on the flow developer of ensuring appropriate custom access checks are performed. **Additional resources:** - Examples of custom procedural access checks in Apex for guest users: [Guest User Record Access Development Best Practices](https://www.learnexperiencecloud.com/article/Guest-User-Record-Access-Development-Best-Practices). - Flow best practices when developing your own custom procedural access checks: [Considerations for Flow Design](https://developer.salesforce.com/docs/atlas.en-us.secure_coding_guide.meta/secure_coding_guide/secure_coding_considerations_flow_design.htm). - More information about flow run context: [Data Safety When Running Screen and Autolaunched Flows in System Context](https://help.salesforce.com/s/articleView?id=platform.flow_distribute_context_data_safety_system_context.htm&type=5) ## PreventPassingUserDataIntoElementWithSharing **Description:** This rule finds CRUD (Create, Read, Update, Delete) operations in which user controlled data either determines which Salesforce records are selected for the CRUD operation, or in which user controlled data can modify the data of the selected records. This happens in flows that run in `System Context With Sharing`. If your flow violates this rule, the user running the flow can gain higher privileges and perform actions on records that they shouldn't have access to. This is a security risk known as a privilege escalation vulnerability. **Default Severity:** Low (4) **Default Tags:** `Recommended`, `Security`, `Xml` **How to Fix:** The best fix is to change the run context of your flow from `System Context With Sharing` to `User Context`. See [Change the Flow Run Context](https://help.salesforce.com/s/articleView?id=platform.flow_distribute_system_mode.htm&type=5) for details. If you can't change the run context of your flow, you must implement your own procedural access control checks using decision elements and custom Apex actions; see the next section for helpful resources. **False Positive Guidance:** A flow sometimes causes a violation of this rule, but the violation might be a false positive. This section provides guidance on what causes a false positive, and when you can safely ignore it. In the following two use cases, the flow is required to run in `System Context` (either with or without sharing) for its secure operation: - The flow is public-facing and used by external guests or community users, and you intend that these users perform limited operations on records that they don't have access to. - The flow code modifies or accesses only custom fields that are owned by your app and you're intentionally ignoring the platform access control policies. To safely ignore these two use cases as false positives, you must provide an alternative access control policy in the flow itself or in an Apex action called from the flow. You can't ignore the platform access control policy without building your own procedural replacement, because bypassing platform access checks places the burden on the flow developer of ensuring appropriate custom access checks are performed. **Additional resources:** - Examples of custom procedural access checks in Apex for guest users: [Guest User Record Access Development Best Practices](https://www.learnexperiencecloud.com/article/Guest-User-Record-Access-Development-Best-Practices). - Flow best practices when developing your own custom procedural access checks: [Considerations for Flow Design](https://developer.salesforce.com/docs/atlas.en-us.secure_coding_guide.meta/secure_coding_guide/secure_coding_considerations_flow_design.htm). - More information about flow run context: [Data Safety When Running Screen and Autolaunched Flows in System Context](https://help.salesforce.com/s/articleView?id=platform.flow_distribute_context_data_safety_system_context.htm&type=5) ## CyclicSubflow **Description:** This rule detects circular subflow references, where a flow calls a subflow that eventually calls the original flow again, either directly or through a chain of subflows. The Salesforce flow runtime doesn't allow cyclic subflows so these flows can fail. **Default Severity:** Critical (1) **Default Tags:** `Recommended`, `Performance`, `Xml` **How to Fix:** - Map your flow architecture and identify the full circular dependency path. - Refactor your flows to remove the circular reference by using one of these approaches. - Remove one of the subflow calls to break the cycle. - Create a new parent flow that orchestrates the logic without circular dependencies. - Move shared logic into a reusable subflow that never calls back to its parent flows. - For complex recursive logic, consider using Apex actions with explicit termination conditions instead of recursive flow calls. **False Positive Guidance:** This rule rarely produces false positives. If you use recursive flow calls, implement the logic in Apex instead, where you can control recursion depth and termination conditions directly. ## DbInLoop **Description:** This rule identifies database operations that run inside a loop such as `Get Records`, `Create Records`, `Update Records`, `Delete Records`. Database operations in loops are critical performance operations that can quickly consume org governor limits. Each database call counts against per-transaction limits. For example, `150` DML statements and `100` SOQL queries per transaction. When these operations run inside loops, you can easily exceed these limits, especially with larger datasets. **Default Severity:** High (2) **Default Tags:** `Recommended`, `Performance`, `Xml` **How to Fix:** - Use collection variables instead of per-record operations. - Before the loop, use a single `Get Records` element with the all records option to load records into a collection. - In the loop, process items in the collection without additional queries. - After the loop, use bulk `Create Records`, `Update Records`, or `Delete Records` on the full collection by using the `IN` operator. - Modify records in a collection with `Assignment` elements instead of using individual `Update Records` elements in the loop. **False Positive Guidance:** This rule rarely produces false positives. Database operations in loops require refactoring to a bulk pattern. ## DefaultCopy **Description:** This rule flags assignment elements that use the default Copy label created by the platform when a flow element is copy and pasted within Flow Builder. These default labels are placeholders that the developer must update prior to publishing the flow. Labels are an important device for documenting flow elements. Additionally, the developer is responsible for reviewing each field and setting in the copied element to avoid accidentally using unintended fields and settings. **Default Severity:** Moderate (3) **Default Tags:** `Recommended`, `CodeStyle`, `Xml` **How to Fix:** - After copying a flow element, review the element label and all fields to verify they have the appropriate label, and then update any that don’t. **False Positive Guidance:** This rule rarely has false positives. Remove default labels and replace them with real labels after copying a flow. ## HardcodedId **Description:** This rule detects hardcoded Salesforce record IDs in flows. Hardcoded IDs are org-specific. For example, they differ between sandbox and production and can break when you deploy flows to other orgs or when records are recreated. Hardcoding IDs can lead to deployment failures and broken flows in production. **Default Severity:** Moderate (3) **Default Tags:** `Recommended`, `BestPractices`, `Xml` **How to Fix:** - Use `Get Records` with field criteria instead of an ID. For example, query by name or another unique field such as an external ID. - Use the `$User` global variable for the current user or use `Get Records` to find a user by `Username` or `Email`![alt]( '{"class": "", "title": ""}'). - Use `DeveloperName` instead of a hardcoded ID. If you need the ID, query `RecordType` by `DeveloperName` and `SObjectType`. - Store configuration in Custom Metadata Types or Custom Settings. Query records by `DeveloperName`, which is consistent across orgs. - Query Group records by `DeveloperName` or `Name` instead of using an ID. **False Positive Guidance:** This rule rarely has false positives. If you hardcode an ID for a quick test or for a single-org flow with no deployment plans, you can ignore this warning. For production use, avoid hardcoded IDs. ## MissingDescription **Description:** This rule flags flows and flow resources such as elements, variables, and other metadata that don’t have descriptions. Descriptions improve flow maintainability, especially when you collaborate on a team or revisit older logic. Missing descriptions don’t break run-time behavior, but they reduce maintainability and make reviews and troubleshooting more difficult. **Default Severity:** Low (4) **Default Tags:** `CodeStyle`, `Xml` **How to Fix:** - Use the `Flow Description` field to explain what the flow does and when it runs. - Add a short description that explains the purpose of the step and why it exists. - Describe what each variable, formula, and resource stores or calculates and how it’s used in the flow. - Keep descriptions clear and concise, and focus on the why rather than repeating what the label already says. **False Positive Guidance:** Ignore this warning for simple, short-lived flows for example, quick sandbox experiments. For production flows, adding descriptions is strongly recommended. ## MissingFaultHandler **Description:** This rule flags flows that don’t have fault paths for elements that can fail, such as `Get Records`, `Create Records`, `Update Records`, `Delete Records`, flow actions, and subflow elements. Without fault handlers, flow exceptions are not caught and throws an error with generic error messages resulting in a poor user experience and limited error logging. Fault handlers help you address errors gracefully, allowing the flow to recover or at least to show meaningful messages to users, and capture error details for troubleshooting or retry logic. **Default Severity:** High (2) **Default Tags:** `BestPractices`, `Xml` **How to Fix:** - Add fault paths for flow elements that can trigger a fault: DML operations, subflows, and flow actions. Each of these elements must have dedicated error-handling logic. - Select an error-handling pattern - **User-facing flows:** Route faults to a Screen element with a clear, user-friendly error message - **Background flows:** Create a record in a custom error log object or another tracking mechanism - **Critical operations:** Send an email or another alert to admins or support - **Transactional flows:** Route to logic that rolls back or adjusts related work, or provides an alternative path - Use the `$Flow.FaultMessage` global variable to capture and display or log detailed error information - Consider using a reusable error-handling subflow so you can apply consistent patterns across flows **False Positive Guidance:** For low-risk operations where failures are acceptable and don't affect users, you can choose not to add a fault handler. # Get Started with Salesforce Code Analyzer To get started scanning your code with Salesforce Code Analyzer, follow this developer workflow and choose resources that match your learning style. ## 1. Discover Salesforce Code Analyzer is a unified tool for source code analysis available in Salesforce CLI, VS Code, GitHub Actions, and DevOps Center Testing. Code Analyzer analyzes multiple languages. It provides a consistent experience to help you identify rule violations. - [Overview](https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/guide/code-analyzer.md). Get a bird's-eye view of Code Analyzer. - [Engines](https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/guide/engines.md). Check out all the supported engines, such as ESLint, PMD, and more. - [Migrate from v4](https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/guide/migrate.md). If you previously used Code Analyzer v4, read the migration guide to help you easily move to v5. **important:** As of August 2025, Code Analyzer v4 is retired and we no longer support it. ## 2. Set Up Code Analyzer and Start Scanning To get started with Code Analyzer, follow these instructions for your tool of choice. - [Salesforce CLI](https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/guide/analyze.md). You must install Salesforce CLI to use the Code Analyzer CLI commands. Complete the prerequisties, install the Code Analyzer CLI plugin, and get started. - [Salesforce Code Analyzer VS Code Extension](https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/guide/analyze-vscode.md). If you use Visual Studio Code (VS Code), install the Code Analyzer VS Code extension to scan your code easily as you work. ## 3. Work with Code Analyzer After you understand how to view and run Code Analyzer rules on your code, play around with more advanced features: customize the Code Analyzer configuration, create new engine rules, and integrate Code Analyzer into your continuous integration/continuous delivery (CI/CD) process. - [Configuration](https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/guide/config-custom.md). Customize how Code Analyzer works by creating a configuration file. - [CI/CD Integration, including GitHub Actions](https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/guide/ci-cd.md). Learn how to integrate Code Analyzer into your CI/CD process. - Custom Rules. Extend your Code Analyzer implementation by creating custom rules for these engines: - [ESLint](https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/guide/engine-eslint.md#add-custom-eslint-configuration-and-rules) - [PMD](https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/guide/engine-pmd.md#add-custom-pmd-rules) - [Regex](https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/guide/engine-regex.md#add-custom-regex-rules) - [DevOps Center Testing](https://help.salesforce.com/s/articleView?id=platform.devops_testing_optional_setup_tasks_to_integrate_code_analyzer_v5_as_test_provider.htm&type=5). Integrate Code Analyzer with DevOps Center Testing, a feature that extends the capabilities of DevOps Center. - [AppExchange Security Review](https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/guide/appexchange.md). Produce the Code Analyzer reports required if you want to list a managed package on AppExchange. ## 4. Keep Up with the Latest News Code Analyzer launches a new release monthly. Read Code Analyzer [Release Notes](https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/guide/relnotes/release-notes.md) to stay on top of the latest developments. ## 5. Report Bugs, Feedback, and Request New Features - To report an issue with Code Analyzer, create a [bug on GitHub](https://github.com/forcedotcom/code-analyzer/issues/new/choose). - To suggest a feature enhancement, create a [request on GitHub](https://github.com/forcedotcom/code-analyzer/issues/new?template=5-feature_request.yml). - To provide general feedback, use [this form](http://sfdc.co/CodeAnalyzerFeedback). ## See Also - [Pass the AppExchange Security Review](https://developer.salesforce.com/docs/atlas.en-us.packagingGuide.meta/packagingGuide/security_review_guidelines.htm) - [Salesforce CLI Setup Guide](https://developer.salesforce.com/docs/atlas.en-us.sfdx_setup.meta/sfdx_setup) - [Salesforce Code Analyzer Github Repository](https://github.com/forcedotcom/sfdx-scanner) - [Salesforce DX Developer Guide](https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev) - [Scan Your Solution with Salesforce Code Analyzer](https://developer.salesforce.com/docs/atlas.en-us.packagingGuide.meta/packagingGuide/security_review_code_analyzer_scan.htm) - [Trailhead: Build Apps Together with Package Development](https://trailhead.salesforce.com/trails/sfdx_get_started) # JSON Rules Output Schema Reference This example shows how to create a JSON-formatted output file when using the `--output-file` flag of the `code-analyzer rules` command. ```bash sf code-analyzer rules --rule-selector flow --output-file rules.json ``` ## Sample JSON Rules Output This sample output shows the two rules associated with the `flow` engine. ```json { "rules": [ { "name": "PreventPassingUserDataIntoElementWithoutSharing", "description": "Avoid passing user data into Flow Scanner elements in run mode: Without Sharing", "engine": "flow", "severity": 2, "tags": [ "Recommended", "Security", "XML" ], "resources": [] }, { "name": "PreventPassingUserDataIntoElementWithSharing", "description": "Avoid passing user data into Flow Scanner elements in run mode: With Sharing", "engine": "flow", "severity": 4, "tags": [ "Recommended", "Security", "XML" ], "resources": [] } ] } ``` ## Properties of the Top-Level "rules" Object | Property Name | Data Type | Description | | ----------------- | --------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `name` | string | The name of the rule. | | `description` | string | The description of the rule. | | `engine` | string | The [engine](https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/guide/engines.md) that's associated with the rule. | | `severity` | string | The default severity level of the rule: 1 (Critical), 2 (High), 3 (Moderate), 4 (Low), 5 (Info) | | `tags` | string[] | An array of tags that are associated with the rule, such as `Recommended`, `Security`, or `BestPractices`. | | `resources` | string[] | An array of URLs for additional resources and information about the rule. | # JSON Run Output Schema Reference This example shows how to create a JSON-formatted output file when using the `--output-file` flag of the `code-analyzer run` command. ```bash sf code-analyzer run --output-file results.json ``` ## Sample JSON Run Output This sample output shows 3 violations with different severities from different engines. ```json { "runDir": "/Users/lisa.simpson/sfdx/coral-cloud-afdx/", "violationCounts": { "total": 3, "sev1": 0, "sev2": 1, "sev3": 1, "sev4": 1, "sev5": 0 }, "versions": { "code-analyzer": "0.25.1", "eslint": "0.20.1", "retire-js": "0.18.1", "regex": "0.18.1", "flow": "0.18.1", "pmd": "0.21.0" }, "violations": [ { "rule": "@lwc/lwc/no-inner-html", "engine": "eslint", "severity": 2, "tags": ["Recommended", "LWC", "Security", "Javascript"], "primaryLocationIndex": 0, "locations": [ { "file": "force-app/main/default/staticresources/highlight/highlight/prism.js", "startLine": 571, "startColumn": 17, "endLine": 571, "endColumn": 26 } ], "message": "Using 'innerHTML/outputHTML/insertAdjacentHTML' is not allowed", "resources": [ "https://github.com/salesforce/eslint-plugin-lwc/blob/v2.1.0/docs/rules/no-inner-html.md" ] }, { "rule": "PreventPassingUserDataIntoElementWithSharing", "engine": "flow", "severity": 4, "tags": ["Recommended", "Security", "Xml"], "primaryLocationIndex": 1, "locations": [ { "file": "force-app/main/default/flows/Get_Customer_Details.flow-meta.xml", "startLine": 90, "startColumn": 1, "comment": "email.email: Initialization" }, { "file": "force-app/main/default/flows/Get_Customer_Details.flow-meta.xml", "startLine": 41, "startColumn": 1, "comment": "email.email influences Get_Contact_by_Email_and_Member_Number.Email: flow into recordLookups via influence over Email in run mode SystemModeWithSharing" } ], "message": "User controlled data flows into recordLookups element selector in run mode: SystemModeWithSharing", "resources": [] }, { "rule": "ApexSharingViolations", "engine": "pmd", "severity": 3, "tags": ["Recommended", "Security", "Apex"], "primaryLocationIndex": 0, "locations": [ { "file": "force-app/main/default/classes/ExperienceBookingHelper.cls", "startLine": 1, "startColumn": 1, "endLine": 1, "endColumn": 7 } ], "message": "Apex classes should declare a sharing model if DML or SOQL/SOSL is used", "resources": [ "https://docs.pmd-code.org/pmd-doc-7.11.0/pmd_rules_apex_security.html#apexsharingviolations" ] } ] } ``` ## Top-Level Properties and Objects | Property Name | Data Type | Description | | ----------------- | --------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `runDir` | string | The directory from which the Code Analyzer analysis ran. | | `violationCounts` | Object | Object that contains the total number of violations and the aggregate counts for each severity level. See [violationCounts Object Properties](#violationcounts-object-properties) for details. | | `versions` | Object | Object that contains the versions of the core Code Analyzer module and each engine module that ran in the analysis. See [versions Object Properties](#versions-object-properties) for details. | | `violations` | Object[] | An array of objects, where each object corresponds to a violation that was detected in the analysis. See [violations Object Properties](#violations-object-properties) for details. | ## violationCounts Object Properties | Property Name | Data Type | Description | | -------- | --------- | ------------------------------------------------- | | `total` | number | Total number of violations found in the analysis. | | `sev1` | number | Number of severity 1 (Critical) violations found. | | `sev2` | number | Number of severity 2 (High) violations found. | | `sev3` | number | Number of severity 3 (Moderate) violations found. | | `sev4` | number | Number of severity 4 (Low) violations found. | | `sev5` | number | Number of severity 5 (Info) violations found. | ## versions Object Properties | Property Name | Data Type | Description | | --------------- | --------- | --------------------------------------------------------- | | `code-analyzer` | string | Version of the core Code Analyzer module. | | `cpd` | string | Version of the [CPD module](https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/guide/engine-cpd.md). | | `eslint` | string | Version of the [ESLint module](https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/guide/engine-eslint.md). | | `flow` | string | Version of the [Flow Scanner module](https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/guide/engine-flow.md). | | `pmd` | string | Version of the [PMD module](https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/guide/engine-pmd.md). | | `retire-js` | string | Version of the [RetireJS module](https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/guide/engine-retire-js.md). | | `regex` | string | Version of the [Regex module](https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/guide/engine-regex.md). | | `sfge` | string | Version of the [Salesforce Graph module](https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/guide/engine-sfge.md). | ## violations Object Properties | Property Name | Data Type | Description | | ---------------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `rule` | string | The name of the rule that's associated with the violation. | | `engine` | string | The [engine](https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/guide/engines.md) that's associated with the violation. | | `severity` | number | The severity level of the violation: 1 (Critical), 2 (High), 3 (Moderate), 4 (Low), 5 (Info) | | `tags` | string[] | An array of tags that are associated with the rule that's associated with the violation. | | `primaryLocationIndex` | number | The index of the primary code location within the code locations array. | | `locations` | Object[] | An array of objects, where each object corresponds to a location in your code that's associated with the violation. See [locations Object Properties](#locations-object-properties) for details. | | `message` | string | The violation message. | | `resources` | string[] | An array of URLs for additional resources and information about the violation. | ## locations Object Properties Some rules, such as those that have a `PathBased` tag, can produce multiple code locations. These code locations make up the code path associated with the violation. | Property Name | Data Type | Description | | ------------- | --------- | --------------------------------------------------------------------------------------------- | | `file` | string | The pathname of the file in which the violation occurred, relative to the `runDir` directory. | | `startLine` | number | The line where the violating code starts. | | `startColumn` | number | The column in the `startLine` where the violating code starts. | | `endLine` | number | The line where the violating code ends. | | `endColumn` | number | The column in the `endLine` where the violating code ends. | | `comment` | string | Comment that provides additional context associated with this line or block of code. | # Migrate from Code Analyzer v4 to v5 Code Analyzer v5 is more intuitive and powerful than v4, but the configuration and CLI commands work a bit differently. This document helps you migrate. **important:** As of August 2025, Code Analyzer v4 is retired and we no longer support it. ## Install Code Analyzer V5 To install the Salesforce Code Analyzer plugin, run: ```bash sf plugins install @salesforce/plugin-code-analyzer ``` ## Changes in the CLI Commands The most obvious high-level change between the Code Analyzer v4 and v5 CLI commands is that v4 commands are in the `scanner` topic and v5 commands in the `code-analyzer` topic. For example: **v4**: ```bash sf scanner run --category Security ``` **v5**: ```bash sf code-analyzer run --rule-selector Security ``` We also reduced the six v4 commands to just three in v5: `code-analyzer run|rules|config`. This table summarizes the changes. | v4 Command | v5 Equivalent Command | Notes about v5 Equivalent | | ----------------------- | ---------------------------------------- | ----------------------------------------------------------------------------------------------------------- | | `scanner rule add` | No equivalent. | Add custom rules to the `code-analyzer.yml` configuration file. | | `scanner rule describe` | `code-analyzer rules --view detail` | Use the `--rule-selector` flag to select a specific rule or rules. | | `scanner rule list` | `code-analyzer rules` | Use the `--rule-selector` flag to select a specific rule or rules. | | `scanner rule remove` | No equivalent. | Remove custom rules by removing them from the `code-analyzer.yml` configuration file. | | `scanner run` | `code-analyzer run` | | | `scanner run dfa` | `code-analyzer run --rule-selector sfge` | Use the same command (`code-analyzer run`) to run rules for all engines, including Salesforce Graph Engine. | Another high-level change is that in v5, the three commands share many of the same flags for: - Selecting the rules (`--rule-selector`). - Selecting the set of files you want to include in your analysis (`--workspace`). - Specifying the path to the configuration file (`--config-file`). As a result, executing the three v5 commands is essentially the same whether you want to list rules, run rules, or view your configuration. The v5 CLI commands now have a single flag (`--rule-selector`) for selecting the rules you want to list or run on your source code. With this single flag you can select rules based on their name, engine, severity level, and tags. And more importantly, you can _combine_ these properties in many different ways so as to select exactly what you want. It's a powerful flag. But it's also different from how v4 CLI commands worked, which had multiple flags such as `--engine` or `--category`. Finally, another big change: v5 introduces a configuration YAML file (`code-analyzer.yml`) which you can use to configure top-level properties and customize rules and engines, including adding custom rules. See [Customize the v5 Configuration](https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/guide/config-custom.md) for details. ## Changes in the Code Analyzer VS Code Extension The Salesforce Code Analyzer Visual Studio Code (VS Code) extension integrates many of Code Analyzer’s most useful features into VS Code. The extension has its own versioning, separate from core Code Analyzer. As Code Analyzer transitioned from v4 to v5, here's how the extension supported each version: - Version 1.3.0 and smaller: The extension supported only Code Analyzer v4. - Version 1.4.0 and 1.5.0: The extension supported both Code Analyzer v4 and v5, but v4 was enabled by default. - Version 1.6.0 - 1.9.0: The extension supported both Code Analyzer v4 and v5, but v5 was enabled by default. - Version 1.10.0 and greater: The extension supports only Code Analyzer v5. This section describes the high-level differences in the extension between supporting v4 and v5. For simplicity, we call the extension support for Code Analyzer v4 simply _v4_, same with _v5_. - In v4, Salesforce Graph Engine had its own specialized commands for running a scan (**SFDX: Scan Selected Method with Graph Engine Path-Based Analysis** and **SFDX: Scan Project with Graph Engine Path-Based Analysis**). In v5, we removed these specialized commands. Instead, Salesforce Graph Engine works just like the other engines and you use the [same commands to run a scan](https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/guide/analyze-vscode.md#launch-code-analyzer-and-scan-your-code): **SFDX: Scan Current File with Code Analyzer** or **SFDX: Scan Selected Files or Folders with Code Analyzer**. - In v4, you used various VS Code settings to customize your code scans. For example, you used settings to specify the engines and categories of rules to use in code scans, configure Salesforce Graph Engine, normalize the severity across engines, and more. In v5, many of the v4 settings are gone. New v5 settings mirror how the v5 `code-analyzer` CLI commands work. For example, you use the **Code Analyzer: Config File** setting to [customize all engines and rules](https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/guide/config-custom.md), including Salesforce Graph Engine; this VS Code command is equivalent to the `--config-file` CLI flag. Use **Code Analyzer: Rule Selectors** to [select the rules to scan your code](https://developer.salesforce.com/docs/atlas.en-us.sfdx_cli_reference.meta/sfdx_cli_reference/cli_reference_code-analyzer_commands_unified.htm#cli_reference_code-analyzer_rules_unified), similar to the `--rule-selector` flag. These v4 settings are still available in v5: - Scan files on open automatically. - Scan files on save automatically. - Enable Apex Guru (Pilot). ## Migrate a Custom PMD Configuration In v4, if you specify a PMD ruleset file with the `--pmdconfig` flag of `scanner run`, only the rules in the ruleset actually run. You can't also run other PMD rules that aren't specified in the ruleset. But with v5, when you specify your ruleset file in your `code-analyzer.yml` file, the rules in the ruleset are added to the full list of PMD rules that you can select and run. To make selection of your ruleset rules easy, we add a tag to each rule that matches the `name` attribute of your ruleset, minus any spaces. For example, let's say your PMD ruleset file looks like this: ```XML ``` Then each rule in the ruleset file is tagged with `MyRules`. Follow these steps to mimic the v4 behavior of `sf scanner rule --pmdconfig path/to/my/ruleset.xml` in v5: 1. As described in [Add Custom PMD Rules](https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/guide/engine-pmd.md#add-custom-pmd-rules), update your `code-analyzer.yml` file like this: ```yaml engines: pmd: custom_rulesets: - path/to/my/ruleset.xml ``` 1. Run this command to ensure that your custom rules are available. ```bash sf code-analyzer rules --rule-selector pmd ``` Your PMD rules have up to two new tags added. The first tag is the name of your ruleset, with spaces removed. This tag is added to all rules, including the standard PMD rules that are referenced in your ruleset. The second tag is `Custom`, which is added to only the custom non-standard PMD rules in your ruleset. 1. Run all the rules in your ruleset by specifying the ` --rule-selector pmd:` flag. ```bash sf code-analyzer run --rule-selector pmd:MyRules ``` Be sure the `code-analyzer.yml` file is either in your local directory or you use the `--config-file` flag to specify it. In v5, you can do more than just run the rules in your ruleset. This example shows how to run all the Recommended rules in addition to the rules from your ruleset file: ```bash sf code-analyzer run --rule-selector Recommended --rule-selector pmd:MyRules ``` ## Migrate a Custom ESLint Configuration In v4, you specify custom ESLint rules by pointing to your `.eslintrc.json` file with the `--eslintconfig` flag of `scanner run`. But then you couldn't also run the recommended standard ESLint rules that run when you don't supply the `--eslintconfig` flag. With v5, we allow you to supply your ESLint configuration either on its own or added alongside our recommended base configuration, assuming there are no configuration conflicts. To mimic the v4 behavior in v5, provide your ESLint configuration file and turn off our recommended base configuration, as described by these steps: 1. If you haven't already, create a `code-analyzer.yml` configuration file and set these options in the `engine:eslint` section: ```yaml engines: eslint: eslint_config_file: disable_javascript_base_config: true disable_lwc_base_config: true disable_typescript_base_config: true ``` See [Add Custom ESLint Configuration and Rules](https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/guide/engine-eslint.md#add-custom-eslint-configuration-and-rules) for details. 1. Run this command to ensure that your custom ESLint rules are available. ```bash sf code-analyzer rules --rule-selector eslint ``` Any new custom ESLint rules that are not already provided by the base configurations have the `Custom` tag added. 1. Run only your custom ESLint rules this way: ```bash sf code-analyzer run --rule-selector eslint:Custom ``` Be sure the `code-analyzer.yml` file is either in your local directory or you use the `--config-file` flag to specify it. If you want ESLint to merge your configuration with our recommended base configurations, then set the `disable_*_base_config` fields back to `false` while still supplying your `eslint_config_file`. This merging of configurations wasn't possible in v4. Then run this command: ```bash sf code-analyzer run --rule-selector eslint ``` ## Examples of Equivalent v4 and v5 Commands Let's look at a few examples to get you started using the new v5 commands. This v4 CLI command runs all the rules with the `Security` or `Performance` category: ```bash sf scanner run --category Security,Performance ``` This is the v5 equivalent CLI command: ```bash sf code-analyzer run --rule-selector Recommended:Security --rule-selector Recommended:Performance ``` It's a Salesforce CLI best practice to use multiple flags to specify multiple values, but this syntax also still works: ```bash sf code-analyzer run --rule-selector Recommended:Security,Recommended:Performance ``` This v4 CLI command runs all the PMD rules in the `Security` category: ```bash sf scanner run --engine pmd --category Security ``` This is the v5 equivalent: ```bash sf code-analyzer run --rule-selector pmd:Security ``` Salesforce Graph Engine no longer has its own CLI command to run its rules; you instead use `code-analyzer run` just like with any other engine. Here's a v4 command to run a Graph Engine scan: ```bash sf scanner run dfa --target ./myproject/main/default/classes/*.cls --projectdir ./myproject/ ``` This is the equivalent v5 command: ```bash sf code-analyzer run --rule-selector sfge --target ./myproject/main/default/classes/*.cls --workspace ./myproject/ ``` ## Examples of v5 Commands That You Can't Run Using v4 Due to the improved design of the v5 CLI commands, there are many useful scans that you can easily run in v5 that are impossible with v4 commands. Run all the ESLint rules and any PMD rules with the `Security` category: ```bash sf code-analyzer run --rule-selector eslint --rule-selector pmd:Security ``` Run only PMD's rules for the Apex language: ```bash sf code-analyzer run --rule-selector pmd:Apex ``` Run only the rules that have severity 1 (critical), for all enabled engines: ```bash sf code-analyzer run --rule-selector 1 ``` # Output Schemas Reference You can output the results of `code-analyzer rules` and `code-analyzer run` to a file by specifying the `--output-file` flag. Here are the schemas of the output for the two commands. - [Rules Output Schemas](https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/guide/output-schemas-rules.md) - [Run Output Schemas](https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/guide/output-schemas-run.md) # PerformNullCheckOnSoqlVariables (Retired) PerformNullCheckOnSoqlVariables identifies SOQL queries with variables in WHERE clauses that lack null checks. SOQL queries with variables on WHERE clauses become expensive when the variable value is unintentionally null. When the variable value is null, an O(1) operation turns into an O(n) operation. The entire table is scanned but returns no results. ## Definition - Source - : `@AuraEnabled`-annotated methods. `@InvocableMethod`-annotated methods. `@NamespaceAccessible`-annotated methods. `@RemoteAction`-annotated methods. Any method returning a `PageReference` object. `public`-scoped methods on Visualforce Controllers. `global`-scoped methods on any class. `Messaging.InboundEmailResult handleInboundEmail()` methods on implementations of `Messaging.InboundEmailHandler`. Any method targeted during invocation. - Sink - : Any database operation. - Sanitizer - : Null checks (`if (x != null) {`). Explicit assignment to non-null (`String x = 'asdf'`). Checks for specific non-null values (`if (x == 7) {`). ## Interpreting Results Match any violation message that you receive with this case to understand more about the violation. ### Common Case > Null check is missing for variable targetName used in SOQL query. The mentioned variable is referenced by a SOQL query, and the variable is missing a null check. This behavior is expensive. Instead, explicitly perform a null check on this variable, or assign it to a specific non-null value. For example: ``` public Account[] getAccountsMatchingName(String targetName) { return [SELECT Id, Name FROM Account WHERE Name := targetName; } ``` # PMD PMD is a source code analyzer that performs static analysis of code written in a number of languages. Its bundled rules detect common flaws in code, such as empty catch blocks or unused variables. ## Available PMD Rules Code Analyzer supports PMD rules for these languages: - [Apex](https://pmd.github.io/pmd/pmd_rules_apex.html) - [HTML](https://pmd.github.io/pmd/pmd_rules_html.html) - [JavaScript](https://pmd.github.io/pmd/pmd_rules_ecmascript.html) - [XML](https://pmd.github.io/pmd/pmd_rules_xml.html) - [Visualforce](https://pmd.github.io/pmd/pmd_rules_visualforce.html) Run this command to view detailed information about the PMD rules for the languages you've configured; the default languages are `apex` and `visualforce`. ```bash sf code-analyzer rules --rule-selector pmd --view detail ``` For information on how to modify rule settings, such as their severity or tags, see [Customize Your Configuration](https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/guide/config-custom.md). While the examples show modifying rules for the ESLint and Regex engines, you use the same process to modify PMD rules. ## PMD AppExchange Rules In addition to the base PMD rules, Code Analyzer provides PMD AppExchange rules that help you prepare your managed packages for security review. See [PMD AppExchange Rules Reference](https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/guide/rules-pmd-appexchange.md) for details, including examples of code snippets that cause security violations. For full instructions on preparing for the AppExchange security review with Code Analyzer, read [Scan Your Solution with Salesforce Code Analyzer](https://developer.salesforce.com/docs/atlas.en-us.packagingGuide.meta/packagingGuide/security_review_code_analyzer_scan.htm) in the ISVforce Guide. ## Add Custom PMD Rules PMD allows you to create your own custom rules to check for patterns specific to your codebase, or the coding practices of your team. You can then add these custom rules to the list of PMD rules that Code Analyzer runs. Follow these steps to add custom PMD rules to Code Analyzer. 1. Create your custom PMD rule by following the instructions in [Extending PMD](https://docs.pmd-code.org/latest/pmd_userdocs_extending_writing_rules_intro.html). PMD supports the ability to create custom Java rules classes. It also provides the ability to reuse its XPathRule class by supplying your own XPath expression to match against the DOM view of the AST. - If you create a custom Java rule, then you must bundle your Java class into a JAR file. A [ruleset xml file](https://docs.pmd-code.org/latest/pmd_userdocs_making_rulesets.html) must then contain your rule definition and can either be contained within the same JAR file or as a separate XML file separate from the JAR file. - If you create an XPath based rule, then you define this rule directly inside of a [ruleset xml file](https://docs.pmd-code.org/latest/pmd_userdocs_making_rulesets.html). 2. Update your `code-analyzer.yml` file and specify the location of the XML ruleset file in the `custom_rulesets` option of the `pmd` engine. You can put this XML file in two types of locations: - On disk. Provide either an absolute path or a relative path to the `config_root` option of the `code-analyzer.yml` config file. - As a relative resource in your Java classpath, such as bundled in a JAR file. For example: ```bash engines: pmd: custom_rulesets: - rulesets/security/xml_security.xml - rulesets/security/html_security.xml ``` 3. If you have one or more JAR files that contain custom JAVA rules and/or ruleset files, then add the JAR files, or the folder in which they live, to the `java_classpath_entries` option; each file or folder must be either an absolute path or relative to `config_root`. For example: ```bash engines: pmd: custom_rulesets: - rulesets/security/xml_security.xml - rulesets/security/html_security.xml java_classpath_entries: - custom_rules/pmd-my-xml-security-rules.jar - custom_rules/pmd-my-html-security-rules.jar ``` 4. Run the `rules` command to validate that Code Analyzer knows about your rule. As a convenience, Code Analyzer automatically adds the `Custom` tag to all custom rules. Run this command to see all the custom PMD rules; your new rule should be in the list: ```bash sf code-analyzer rules --rule-selector pmd:Custom ``` The name of your new rule is the same as the `name` attribute of the associated `` element in the XML ruleset file. Also, to make selection of your ruleset rules easy, we add a tag to each rule that matches the `name` attribute of your ruleset (`` element), minus any spaces. For example, in this snippet of a ruleset file, each rule has the tag `MyCustomPMDRules`, and the name of one of the rules is `CheckForBadVariableNames`: ```bash
  • on disk (provided as an absolute path or a relative path to 'config_root')
  • or a relative resource found on the Java classpath.
  • Not all custom rules can be fully defined within an xml ruleset file. For example, Java based rules may be defined in jar files. In these cases, you will need to also add your additional files to the Java classpath using the 'java_classpath_entries' field. See https://pmd.github.io/pmd/pmd_userdocs_making_rulesets.html to learn more about PMD rulesets. Default value is `[]`. | ## Generate a Source File's AST Structure When you write custom PMD rules, you need your code's [Abstract Syntax Tree](https://deepsource.com/glossary/ast) (AST), which helps you write exact XPath expressions. Use the new `ast-dump` command to view this structure directly from your command line. Generating the source file's AST structure in XML or JSON format, this command supports files written in Apex, Visualforce, HTML, XML, and JavaScript. ``` sf code-analyzer ast-dump --file ./force-app/main/default/classes/BotHandler.cls --output-file ./xpath/simple.xml ``` ## See Also - [PMD Source Analyzer](https://pmd.github.io/#home) # PMD (Retired) PMD is a source-code analyzer that allows for static analysis of code written in a number of supported languages, including Java, Apex, and Visualforce. Its built-in rules detect common flaws in code, such as empty catch blocks or unused variables. ## How Salesforce Code Analyzer Uses PMD By default, the Code Analyzer `scanner run` command executes the PMD default Apex and Visualforce rules against compatible files. You can change which rules are executed by using the flags described in the Code Analyzer Command Reference. Refer to our [FAQ](https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/faq.md#q-how-do-i-enable-engine-xs-default-rules-for-language-y) for info on how to enable the PMD built-in rules for other languages. ## Prepare Your Solution for AppExchange Security Review with pmd-appexchange In addition to the base PMD engine, Code Analyzer also includes a custom PMD variant, `pmd-appexchange`. The rules included in `pmd-appexchange` helps you prepare your managed packages for security review. The `pmd-appexchange` engine is disabled by default. To run a PMD scan with the AppExchange ruleset, run `sf scanner run` with the `--engine pmd-appexchange` flag. For example: `sf scanner run --engine pmd-appexchange --target ./` For more information on the `pmd-appexchange` rules, see the [pmd-appexchange Rule Reference](https://github.com/forcedotcom/sfdx-scanner/tree/dev/pmd-appexchange/docs). To include an optional PMD scan with the AppExchange-specific ruleset in your AppExchange security review submission, run `sf scanner run --engine pmd-appexchange` and name the output file `CodeAnalyzerPmdAppExchange.csv`. For example: `sf scanner run --engine pmd-appexchange --format csv --outfile CodeAnalyzerPmdAppExchange.csv` For full instructions on preparing for the AppExchange security review with Code Analyzer, read [Scan Your Solution with Salesforce Code Analyzer](https://developer.salesforce.com/docs/atlas.en-us.packagingGuide.meta/packagingGuide/security_review_code_analyzer_scan.htm) in the ISVforce Guide. ## See Also - [PMD](https://pmd.github.io/#home) - [PMD 7 Release Notes](https://docs.pmd-code.org/latest/pmd_release_notes_pmd7.html) - [PMD Copy-Paste Detector](https://docs.pmd-code.org/latest/pmd_userdocs_cpd.html) - [pmd-appexchange Rule Reference](https://github.com/forcedotcom/sfdx-scanner/tree/dev/pmd-appexchange/docs) - [PMD Customization](https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/custom-configuration/pmd-config.md) - [Salesforce Code Analyzer Command Reference](https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/command-reference/code-analyzer-command-reference.md) - [_ISVforce Guide_: Scan Your Solution with Salesforce Code Analyzer](https://developer.salesforce.com/docs/atlas.en-us.packagingGuide.meta/packagingGuide/security_review_code_analyzer_scan.htm) # PMD AppExchange Rules Reference The PMD AppExchange rules help you prepare your second-generation managed packages (managed 2GP) for security review. To select these rules, use `--rule-selector AppExchange`. For example, to run the AppExchange rules: ```bash sf code-analyzer run --rule-selector AppExchange ``` ## AvoidApiSessionId **Description:** Detects use of Api.Session_ID or GETSESSIONID() to retrieve a session ID. **Severity:** High (2) **Tags:** `AppExchange`, `Security`, `XML` **Example(s):** - [Bad] Code that causes a violation: {!REQUIRESCRIPT('/soap/ajax/26.0/connection.js')} sforce.connection.sessionId = '{!GETSESSIONID()}'; - [Bad] Code that causes a violation: /apex/something?id={!something__c.Id}&sessionId={!$Api.Session_ID}&instance={!$Api.Partner_Server_URL_260} - [Bad] Code that causes a violation: https://test.example.com/dummy.ph?param1={!API.Enterprise_Server_URL_540}&sessionId={!API.Session_ID}&param2={!Organization.Name}&param3={!User.Email} ## AvoidAuraWithLockerDisabled **Description:** Detects use of API versions with Lightning Locker disabled in Aura components. Use API version 40 or greater. **Severity:** Critical (1) **Tags:** `AppExchange`, `Security`, `XML` **Example(s):** - [Bad] Code that causes a violation: 39.0 - [Good] Code that does not cause a violation: 53.0 ## AvoidChangeProtectionUnprotected **Description:** Detects potential misuse of FeatureManagement.changeProtection. **Severity:** Critical (1) **Tags:** `AppExchange`, `Security`, `Apex` **Example(s):** - [Bad] Code that causes a violation: public with sharing class ProtectedObjectController { @AuraEnabled public static void changeObjectToUnprotected(String objectName){ try { FeatureManagement.changeProtection(objectName, 'CustomObject', 'Unprotected'); System.FeatureManagement.changeProtection(objectName, 'CustomObject', 'Unprotected'); } catch (Exception e) { throw new AuraHandledException(e.getMessage()); } } } - [Good] Code that does not cause a violation: public with sharing class ProtectedObjectController { @AuraEnabled public static void changeObjectToUnprotected(String objectName){ try { SomeOther.changeProtection(objectName, 'CustomObject', 'Unprotected'); } catch (Exception e) { throw new AuraHandledException(e.getMessage()); } } } ## AvoidCreateElementScriptLinkTag **Description:** Detects dynamic creation of script or link tags Note: This rule identifies the ` ## AvoidDisableProtocolSecurityRemoteSiteSetting **Description:** Detects if "Disable Protocol Security" setting is true. **Severity:** Moderate (3) **Tags:** `AppExchange`, `Security`, `XML` **Example(s):** - [Bad] Code that causes a violation: true - [Good] Code that does not cause a violation: false ## AvoidGetInstanceWithTaint **Description:** Detects use of getInstance(userId)/getInstance(profileId). Hierarchy Custom Settings return the record owned by the current user when getInstance() is invoked without any parameters. But if a tainted or end-user controlled userId or profileId is passed as a parameter to getInstance() that will allow the code to access records owned by other users on... Learn more: https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/guide/rules-pmd-appexchange.html#avoidgetinstancewithtaint **Severity:** Moderate (3) **Tags:** `AppExchange`, `Security`, `Apex` **Example(s):** - [Bad] Code that causes a violation: public with sharing class ProtectedCustomSettingsHierarchyCtrl { @AuraEnabled public static Protected_API_Key_Hierarchy__c getInstanceUserId(Id userId){ return Protected_API_Key_Hierarchy__c.getInstance(userId); // NEVER return secrets back to the end user } } - [Good] Code that does not cause a violation: public with sharing class ProtectedCustomSettingsHierarchyCtrl { @AuraEnabled public static Some_Other_Class__c getInstanceUserId(Id userId){ return SomeOtherClass.getInstance(userId); } } ## AvoidGlobalInstallUninstallHandlers **Description:** Detects Install and Uninstall handlers declared as global. Install and Uninstall Handlers don't need to be global classes. Using global for these handlers means global methods in these classes act as controllers and can be invoked by untrusted code outside the context of post-install/uninstall scenarios. Depending on the logic in these... Learn more: https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/guide/rules-pmd-appexchange.html#avoidglobalinstalluninstallhandlers **Severity:** Critical (1) **Tags:** `AppExchange`, `Security`, `Apex` **Example(s):** - [Bad] Code that causes a violation: global class PackageInstallHandler implements InstallHandler { global void onInstall(InstallContext context) { //code to run onInstall } } - [Bad] Code that causes a violation: global with sharing class PackageUninstallHandler implements UninstallHandler{ global void onUninstall(UninstallContext context) { //code to run onUninstall } } - [Good] Code that does not cause a violation: public class PackageInstallHandler implements InstallHandler{ public void onInstall(InstallContext context) { //code to run onInstall } } - [Good] Code that does not cause a violation: public with sharing class PackageUninstallHandler implements UninstallHandler{ public void onUninstall(UninstallContext context) { //code to run onUninstall } } ## AvoidHardCodedCredentialsInAura **Description:** Detects use of hard coded credentials in Aura components. **Severity:** High (2) **Tags:** `AppExchange`, `Security`, `HTML` **Example(s):** - [Bad] Code that causes a violation: - [Bad] Code that causes a violation: - [Good] Code that does not cause a violation: - [Good] Code that does not cause a violation: ## AvoidHardcodedCredentialsInFieldDecls **Description:** Identifies hard-coded credentials in source code that must be protected using Protected Custom metadata or Protected Custom settings. Protected custom settings or protected custom metadata should be used to store secrets. Refer to the Protect Secrets Using Platform Features Trailhead module for more guidance. **Severity:** Moderate (3) **Tags:** `AppExchange`, `Security`, `Apex` **Example(s):** - [Bad] Code that causes a violation: public with sharing class ProtectedObjectController { public static final String password='test11'; public static final String apikey='something'; public final Integer passcode=11111; } ## AvoidHardcodedCredentialsInHttpHeader **Description:** Identifies hard-coded credentials in source code that must be protected using Protected Custom metadata or Protected Custom settings. Protected custom settings or protected custom metadata should be used to store secrets. Refer to the Protect Secrets Using Platform Features Trailhead module for more guidance. **Severity:** Moderate (3) **Tags:** `AppExchange`, `Security`, `Apex` **Example(s):** - [Bad] Code that causes a violation: public with sharing class HttpEndPointCall { public static void makeHttpCall(String partAuth) { HttpRequest req = new HttpRequest(); req.setHeader('Authorization', 'Bearer ' + partAuth + 'base64encodedhardcodedvalue'); req.setHeader('APIKey', 'Bearer ' + partAuth); req.setHeader('APIPassword', 'Bearer ' + partAuth + 'base64encodedhardcodedvalue'); } } ## AvoidHardcodedCredentialsInSetPassword **Description:** Detects hard-coded credentials in the call to setPassword(). **Severity:** Critical (1) **Tags:** `AppExchange`, `Security`, `Apex` **Example(s):** - [Bad] Code that causes a violation: public with sharing class HttpEndPointCall { public static void makeHttpCall(String userId) { setPassword(userId, 'hard coded password'); System.setPassword(userId, 'hard coded password'); } } ## AvoidHardcodedCredentialsInVarAssign **Description:** Identifies hard-coded credentials in source code that must be protected using Protected Custom metadata or Protected Custom settings. Protected custom settings or protected custom metadata should be used to store secrets. Refer to the Protect Secrets Using Platform Features Trailhead module for more guidance. **Severity:** Moderate (3) **Tags:** `AppExchange`, `Security`, `Apex` **Example(s):** - [Bad] Code that causes a violation: public with sharing class HttpEndPointCall { public static void makeHttpCall(String userId) { String newPassword = ''; newPassword = 'hardcoded password'; setPassword(userId, newPassword); newPassword = newPassword + 'some other value'; System.setPassword(userId, newPassword); } } ## AvoidHardcodedCredentialsInVarDecls **Description:** Identifies hard-coded credentials in source code that must be protected using Protected Custom metadata or Protected Custom settings. Protected custom settings or protected custom metadata should be used to store secrets. Refer to the Protect Secrets Using Platform Features Trailhead module for more guidance. **Severity:** Moderate (3) **Tags:** `AppExchange`, `Security`, `Apex` **Example(s):** - [Bad] Code that causes a violation: public with sharing class HttpEndPointCall { public static void makeHttpCall(String userId) { String apiKey = 'newapikey'; String newPassword1 = ''; Integer passwordIndex = 5; } } ## AvoidHardcodedSecretsInVFAttrs **Description:** Detects hardcoded secrets in VF attributes **Severity:** High (2) **Tags:** `AppExchange`, `Security`, `Visualforce` **Example(s):** - [Bad] Code that causes a violation: ## AvoidInsecureHttpRemoteSiteSetting **Description:** Detects instances of a Remote Site Settings that use HTTP. Use HTTPS instead. **Severity:** Moderate (3) **Tags:** `AppExchange`, `Security`, `XML` **Example(s):** - [Bad] Code that causes a violation: http://www.maptestsite.net/mapping1 - [Good] Code that does not cause a violation: https://www.maptestsite.net/mapping1 ## AvoidInvalidCrudContentDistribution **Description:** Detects the use of `Schema.DescribeSObjectResult` methods to enforce CRUD check on `ContentDistribution`. Developers should use `USER MODE` operations or use the custom below to enforce CRUD check against the `ContentDistribution` object. **Severity:** Moderate (3) **Tags:** `AppExchange`, `Security`, `Apex` **Example(s):** - [Bad] Code that causes a violation: public with sharing class ContentDistributionCheck { public void hasAccess(){ if(Schema.SObjectType.ContentDistribution.isCreateable()){ System.debug('User has INSERT access on ContentDistribution Object'); } if(Schema.SObjectType.ContentDistribution.isAccessible()){ System.debug('User has READ access on ContentDistribution Object'); } if(Schema.SObjectType.ContentDistribution.isUpdateable()){ System.debug('User has UPDATE access on ContentDistribution Object'); } if(Schema.SObjectType.ContentDistribution.isDeletable()){ System.debug('User has DELETE access on ContentDistribution Object'); } } } ## AvoidJavaScriptCustomObject **Description:** Detects use of custom JavaScript actions in custom rules. **Severity:** High (2) **Tags:** `AppExchange`, `Security`, `XML` **Example(s):** - [Bad] Code that causes a violation: onClickJavaScript alert("Show this alert!"); - [Good] Code that does not cause a violation: newWindow https://example.com ## AvoidJavaScriptHomePageComponent **Description:** Detects use of custom JavaScript actions in home page components. **Severity:** High (2) **Tags:** `AppExchange`, `Security`, `XML` **Example(s):** - [Bad] Code that causes a violation: <a href=javascript:alert(11)>Hello World </a> htmlArea - [Bad] Code that causes a violation: <b>Hello World </b> <script> alert(99); </script> htmlArea - [Good] Code that does not cause a violation: <b>Hello World </b> htmlArea ## AvoidJavaScriptInUrls **Description:** Detects use of JavaScript-style URLs (javascript:) in components, such as web links and buttons. Avoid JavaScript-style URLs in managed packages. **Severity:** Critical (1) **Tags:** `AppExchange`, `Security`, `XML` **Example(s):** - [Bad] Code that causes a violation: javascript:doSomething(); - [Bad] Code that causes a violation: javascript:helloWorld(); - [Good] Code that does not cause a violation: /apex/test ## AvoidJavaScriptWebLink **Description:** Detects use of custom JavaScript actions in web links. **Severity:** High (2) **Tags:** `AppExchange`, `Security`, `XML` **Example(s):** - [Bad] Code that causes a violation: onClickJavaScript - [Good] Code that does not cause a violation: sidebar ## AvoidLmcIsExposedTrue **Description:** Detects a Lightning Message Channel with isExposed=true, which isn’t allowed in managed packages. **Severity:** High (2) **Tags:** `AppExchange`, `Security`, `XML` **Example(s):** - [Bad] Code that causes a violation: true - [Good] Code that does not cause a violation: false ## AvoidLwcBubblesComposedTrue **Description:** Detects Lightning Web Component event configurations where bubbles and composed are both set to true. To avoid sharing sensitive information unintentionally, use this configuration with caution. **Severity:** Moderate (3) **Tags:** `AppExchange`, `Security`, `JavaScript` **Example(s):** - [Bad] Code that causes a violation: import { LightningElement } from 'lwc'; export default class LwcNoteCreateModal extends LightningElement { handleSelected (event) { const selected = new CustomEvent('selected', { bubbles: true, composed: true, detail: event.detail }); this.dispatchEvent(selected); } } - [Good] Code that does not cause a violation: import { LightningElement } from 'lwc'; export default class LwcNoteCreateModal extends LightningElement { handleSelected (event) { const selected = new CustomEvent('selected', { bubbles: true, detail: event.detail }); this.dispatchEvent(selected); } } ## AvoidSControls **Description:** Detects if S-Controls are used since they should not be used in managed packages. **Severity:** Critical (1) **Tags:** `AppExchange`, `Security`, `XML` **Example(s):** - [Bad] Code that causes a violation: ## AvoidSecurityEnforcedOldApiVersion **Description:** Detects use of WITH SECURITY_ENFORCED in API version less than 48.0 **Severity:** Moderate (3) **Tags:** `AppExchange`, `Security`, `Apex` ## AvoidUnauthorizedApiSessionIdInApex **Description:** Detects use of ${API.Session_Id} to retrieve a session ID. For more guidance on approved use cases, read the Session Id Guidance document. **Severity:** Moderate (3) **Tags:** `AppExchange`, `Security`, `Apex` **Example(s):** - [Bad] Code that causes a violation: public with sharing class SessionIdController { public SessionIdController() { String userInfoSessionId1 = '{!API.Session_ID}'; userInfoSessionId1 = '{!api.session_id}'; } } - [Good] Code that does not cause a violation: public with sharing class SessionIdController { public SessionIdController() { String userInfoSessionId1 = 'API.Session_ID'; userInfoSessionId1 = 'api.session_id'; } } ## AvoidUnauthorizedApiSessionIdInVisualforce **Description:** Detects use of Api.Session_ID to retrieve a session ID in Visualforce code. For more guidance on approved use cases, read the Session Id Guidance document. **Severity:** Moderate (3) **Tags:** `AppExchange`, `Security`, `Visualforce` **Example(s):** - [Bad] Code that causes a violation: ## AvoidUnauthorizedGetSessionIdInApex **Description:** Detects use of UserInfo.getSessionId() to retrieve a session ID. For more guidance on approved use cases, read the Session Id Guidance document. **Severity:** Moderate (3) **Tags:** `AppExchange`, `Security`, `Apex` **Example(s):** - [Bad] Code that causes a violation: public with sharing class SessionIdController { public SessionIdController() { String userInfoSessionId1 = UserInfo.getSessionId(); userInfoSessionId1 = System.UserInfo.getSessionId(); } } - [Good] Code that does not cause a violation: public with sharing class SessionIdController { public SessionIdController() { String userInfoSessionId1 = getSessionId(); } } ## AvoidUnauthorizedGetSessionIdInVisualforce **Description:** Detects use of GETSESSIONID() to retrieve a session ID in Visualforce code. For more guidance on approved use cases, read the Session Id Guidance document. **Severity:** High (2) **Tags:** `AppExchange`, `Security`, `Visualforce` **Example(s):** - [Bad] Code that causes a violation: ## AvoidUnescapedHtmlInAura **Description:** Detects use of aura:unescapedHtml,which should be used cautiously. Developers should ensure that the unescapedHtml should not use tainted input to protect against XSS. **Severity:** High (2) **Tags:** `AppExchange`, `Security`, `HTML` **Example(s):** - [Bad] Code that causes a violation: ## AvoidUnsafePasswordManagementUse **Description:** Detects where System.setPassword() exists in Apex code. Use this method with caution. **Severity:** Critical (1) **Tags:** `AppExchange`, `Security`, `Apex` **Example(s):** - [Bad] Code that causes a violation: public with sharing class UserMgmt { @AuraEnabled public static void setPass(Id userId, String password) { System.setPassword(userId, password); setPassword(userId, password); } @AuraEnabled public static void resetPassword(Id userId, Boolean sendUserEmail) { System.resetPassword(userId, sendUserEmail); resetPassword(userId, sendUserEmail); } @AuraEnabled public static void movePassword(ID targetUserId, ID sourceUserId) { System.movePassword(targetUserId, sourceUserId); movePassword(targetUserId, sourceUserId); } @AuraEnabled public static void resetPasswordWithEmailTemplate(Id userId, Boolean sendUserEmail, String emailTemplateName) { System.resetPasswordWithEmailTemplate(userId, sendUserEmail, emailTemplateName); resetPasswordWithEmailTemplate(userId, sendUserEmail, emailTemplateName); } } - [Good] Code that does not cause a violation: public with sharing class UserMgmt { @AuraEnabled public static void setPass(Id userId, String password) { Something.setPassword(userId, password); //NEVER return secrets back to the end user } @AuraEnabled public static void resetPassword(Id userId, Boolean sendUserEmail) { Something.resetPassword(userId, sendUserEmail); //NEVER return secrets back to the end user } @AuraEnabled public static void movePassword(ID targetUserId, ID sourceUserId) { Something.movePassword(targetUserId, sourceUserId); } @AuraEnabled public static void resetPasswordWithEmailTemplate(Id userId, Boolean sendUserEmail, String emailTemplateName) { Something.resetPasswordWithEmailTemplate(userId, sendUserEmail, emailTemplateName); } } ## LimitConnectedAppScope **Description:** Detects if a connected app uses full scope instead of limited scope. Explain this use case in your AppExchange security review submission. **Severity:** Moderate (3) **Tags:** `AppExchange`, `Security`, `XML` **Example(s):** - [Bad] Code that causes a violation: Basic Api RefreshToken Full - [Good] Code that does not cause a violation: Basic Api RefreshToken ## LoadCSSApexStylesheet **Description:** Determines where CSS must be loaded as a static resource **Severity:** High (2) **Tags:** `AppExchange`, `Security`, `Visualforce` **Example(s):** - [Bad] Code that causes a violation: ## LoadCSSLinkHref **Description:** Determines where CSS must be loaded as a static resource **Severity:** High (2) **Tags:** `AppExchange`, `Security`, `Visualforce` **Example(s):** - [Bad] Code that causes a violation: ## LoadJavaScriptHtmlScript **Description:** Determines HTML script locations where JavaScript code must be loaded as static resources. **Severity:** High (2) **Tags:** `AppExchange`, `Security`, `Visualforce` **Example(s):** - [Bad] Code that causes a violation: