๐ SFDX Code Review โ
This repository implements a unified GitHub composite action for the static code review of Salesforce projects. It bundles the checks that are otherwise scattered across separate CI steps into a single, configurable quality gate:
- ๐ก๏ธ Salesforce Code Analyzer โ static analysis for Apex, LWC, Aura and more (PMD, ESLint, RetireJS, Flow, โฆ)
- ๐จ Prettier โ code formatting check
- ๐ ESLint โ JavaScript/LWC code quality, with a native report for SonarQube/SonarCloud
The Salesforce Code Analyzer is enabled by default; Prettier and ESLint are opt-in.
Why all three? The Salesforce Code Analyzer does not check formatting (Prettier is not a static-analysis engine), and while it bundles an ESLint engine, it emits its own unified format rather than the native
eslint-report.jsonthat Sonar'ssonar.eslint.reportPathsconsumes. Running ESLint and Prettier here keeps everything in one gate and produces Sonar-ready reports.
Usage โ
Full code review (analyzer + formatting + linting) โ
jobs:
code-review:
name: Code Review
runs-on: ubuntu-latest
permissions:
contents: read # least-privilege GITHUB_TOKEN - this job only reads the repository
steps:
- name: Checkout
uses: actions/checkout@v7.0.1
with:
fetch-depth: 0 # full history, required for the Sonar analysis
persist-credentials: false # the GITHUB_TOKEN is not needed after the checkout - don't leave it in .git/config
- name: Select Node Version
uses: svierk/get-node-version@v1.5.1
- name: Install Dependencies
run: npm ci --ignore-scripts
- name: Install SF CLI
uses: svierk/sfdx-cli-setup@v1.1.3
- name: Code Review
uses: svierk/sfdx-code-review@v1.0.0
with:
code-analyzer: true
prettier: true
eslint: true
workspace: force-app
severity-threshold: 3
- name: SonarCloud Scan
uses: SonarSource/sonarqube-scan-action@v8.2.1
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} # SONAR_HOST_URL is additionally required for a self-hosted SonarQube ServerPrettier and ESLint run locally via Node, so install the project dependencies first (e.g.
npm ci) and make sure the project provides the matching config (.prettierrc,eslint.config.js/.eslintrc).
Applying your ESLint config to the Code Analyzer engine. By default the Code Analyzer's bundled ESLint engine uses its own base rules and does not apply your workspace
eslint.config.jsโ it logs a hint when it finds one (ESLint configuration file 'eslint.config.js' was found but not applied). This is expected: the separate ESLint check above (eslint: true) is what applies your project config and produces the Sonar report. If you also want your config applied inside the Code Analyzer's ESLint engine, this is an engine setting (no CLI flag exists), so pass acode-analyzer.ymlvia theconfig-fileinput:yamlengines: eslint: # either point at the config explicitly โฆ eslint_config_file: eslint.config.js # โฆ or let the engine discover it automatically auto_discover_eslint_config: true
Uploading Code Analyzer results to GitHub code scanning โ
When producing a SARIF file, let the analyzer report findings without failing the job immediately, then upload the SARIF. Uploading to code scanning requires the job to additionally grant security-events: write:
permissions:
contents: read
security-events: write # required to upload the SARIF file to GitHub code scanning
steps:
- name: Code Review
continue-on-error: true
uses: svierk/sfdx-code-review@v1.0.0
with:
workspace: force-app
output-file: results.sarif
severity-threshold: 3
- name: Upload SARIF
uses: github/codeql-action/upload-sarif@v4.37.7
with:
sarif_file: results.sarifInputs โ
| Name | Required | Default | Description |
|---|---|---|---|
code-analyzer | no | true | Run the Salesforce Code Analyzer. |
prettier | no | false | Run a Prettier formatting check. |
eslint | no | false | Run ESLint and produce a report (e.g. for Sonar). |
workspace | no | Comma-separated files/folders for the Code Analyzer. Defaults to the current directory. | |
rule-selector | no | Recommended | Comma-separated Code Analyzer rule selectors, e.g. Security,Performance. |
config-file | no | Path to a Code Analyzer configuration file (code-analyzer.yml). | |
output-file | no | Comma-separated Code Analyzer output files; format derived from the extension (.sarif, .html, .json, โฆ). | |
severity-threshold | no | Fail if the Code Analyzer finds a violation with this severity or higher (1โ5 / CriticalโInfo). | |
install-plugin | no | true | Install the Code Analyzer plugin before running. Set to false if installed via sfdx-cli-setup. |
plugin-version | no | Specific version of the code-analyzer plugin to install, e.g. 5.0.0. | |
prettier-command | no | npx prettier --check . | Command used to check formatting. Override to use your own, e.g. npm run prettier:verify. |
eslint-command | no | npx eslint . --format json --output-file eslint-report.json | Command used to run ESLint and write its report. Override to use your own, e.g. npm run lint:sonar. |
eslint-report-path | no | ./eslint-report.json | Path to the ESLint JSON report, used to report error/warning counts. |
step-summary | no | true | Write a result section to the GitHub Actions job summary. Set to false to avoid collisions with a custom workflow summary. |
Outputs โ
| Name | Description |
|---|---|
code-analyzer-outcome | Outcome of the Code Analyzer run (Passed/Failed). |
prettier-outcome | Outcome of the Prettier check (Passed/Failed). |
eslint-outcome | Outcome of the ESLint run (Passed/Failed). |
eslint-errors | Number of ESLint errors. |
eslint-warnings | Number of ESLint warnings. |
Outputs for a check that was not run are empty. The step fails if any enabled check fails, while still writing the summary and outputs.
Sonar integration โ
ESLint writes its native JSON report so Sonar can pick it up directly:
sonar.eslint.reportPaths=./eslint-report.jsonThe Salesforce Code Analyzer can additionally emit a SARIF/JSON file via output-file for GitHub code scanning or other tools.
The scan step itself only needs SONAR_TOKEN as an environment variable (plus SONAR_HOST_URL for a self-hosted SonarQube Server). A GITHUB_TOKEN is not required: pull request decoration is performed by the SonarQube Cloud GitHub App, not by the scanner, so passing the token would hand a credential to a third-party action for no gain.
Security & versioning โ
Every uses: reference in the snippets above is pinned to an exact release version, e.g. svierk/sfdx-code-review@v1.0.0. Do the same in your own pipelines:
- Never reference a mutable ref such as
@main,@masteror@v1. It runs whatever code sits on that branch/tag at run time โ with access to your repository and org credentials โ so a compromised or rewritten ref would run unnoticed. - Good โ pin to an exact release tag (
@v1.0.0). Readable, concrete, and bumped through reviewed pull requests. - Strictest โ pin to a full-length commit SHA (
@a1b2c3dโฆ) with the version as a trailing comment. A SHA can never be re-pointed by the publisher; the cost is readability. - Enable Dependabot for
github-actionsin the repository that consumes this action, so those pins are bumped for you instead of silently ageing. Note that Dependabot only scans.github/workflowsโ copy-paste snippets in documentation have to be updated by hand.
This action itself needs no secrets and no GITHUB_TOKEN permissions โ it only runs the Salesforce Code Analyzer, Prettier and ESLint against the checked-out sources. Grant the calling job the least privilege it needs (contents: read is enough, plus security-events: write when uploading SARIF) and use persist-credentials: false on the checkout so the token is not written to .git/config, where the CLI, a plugin or an ESLint config could pick it up.
If you pass credentials to other steps of the same workflow, reference them as environment variables (env: SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}, then "$SONAR_TOKEN" in the script), never by interpolating ${{ secrets.โฆ }} into a run: script itself โ that would allow command injection and can leak values into the log. The steps of this action follow that rule for all of their inputs: every input is passed through env: and referenced as a shell variable, so a value such as eslint-command or workspace can never be expanded into the script body.
References โ
- Salesforce Code Analyzer | Documentation
- code-analyzer run | Command Reference
- Prettier | CLI
- ESLint | CLI
Releases โ
Latest release notes can be found on the release page.
License โ
The scripts and documentation in this project are released under the MIT License.
โก๏ธ Full source & releases: svierk/sfdx-code-review
