├── .editorconfig ├── .git2gus └── config.json ├── .gitattributes ├── .github ├── ISSUE_TEMPLATE │ ├── 0-code_analyzer_bug.yml │ ├── 1-scanner_bug.yml │ ├── 2-vscode_extension_bug.yml │ ├── 3-github_action_bug.yml │ ├── 5-feature_request.yml │ ├── 6-general_feedback.yml │ └── config.yml └── workflows │ ├── apply-npm-tag-to-version.yml │ ├── automated-release-tasks.yml │ ├── create-github-release.yml │ ├── create-release-branch.yml │ ├── daily-smoke-tests.yml │ ├── heartbeat-tests.yml │ ├── publish-to-npm.yml │ ├── run-tests.yml │ └── validate-pr.yml ├── .gitignore ├── .vscode └── launch.json ├── CODEOWNERS ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── SECURITY.md ├── bin ├── dev.cmd ├── dev.js ├── run.cmd └── run.js ├── eslint.config.mjs ├── messages ├── action-summary-viewer.md ├── config-command.md ├── config-model.md ├── config-writer.md ├── progress-event-listener.md ├── results-viewer.md ├── results-writer.md ├── rule-viewer.md ├── rules-command.md ├── rules-writer.md ├── run-action.md ├── run-command.md ├── shared.md └── workspace-util.md ├── package-lock.json ├── package.json ├── pmd-appexchange └── docs │ ├── AvoidApiSessionId.md │ ├── AvoidApiSessionIdInXML.md │ ├── AvoidAuraAppWithLockerDisabled.md │ ├── AvoidAuraCmpWithLockerDisabled.md │ ├── AvoidChangeProtectionUnprotected.md │ ├── AvoidCreateElementScriptLinkTag.md │ ├── AvoidDisableProtocolSecurity.md │ ├── AvoidDisableProtocolSecurityInXML.md │ ├── AvoidGetInstanceWithTaint.md │ ├── AvoidGlobalInstallUninstallHandlers.md │ ├── AvoidHardCodedCredentialsInAura.md │ ├── AvoidHardCodedSecretsInVFAttrs.md │ ├── AvoidHardcodedCredentialsInFieldDecls.md │ ├── AvoidHardcodedCredentialsInHttpHeader.md │ ├── AvoidHardcodedCredentialsInSetPassword.md │ ├── AvoidHardcodedCredentialsInVarAssign.md │ ├── AvoidHardcodedCredentialsInVarDecls.md │ ├── AvoidInsecureHttpRemoteSiteSetting.md │ ├── AvoidInsecureHttpRemoteSiteSettingInXML.md │ ├── AvoidInvalidCrudContentDistribution.md │ ├── AvoidJavaScriptCustomObject.md │ ├── AvoidJavaScriptHomePageComponent.md │ ├── AvoidJavaScriptWeblink.md │ ├── AvoidJsLinksInCustomObject.md │ ├── AvoidJsLinksInWebLinks.md │ ├── AvoidLmcIsExposedTrue.md │ ├── AvoidLmcIsExposedTrueInXML.md │ ├── AvoidLwcBubblesComposedTrue.md │ ├── AvoidSControls.md │ ├── AvoidSecurityEnforcedOldApiVersion.md │ ├── AvoidSystemModeInFlows.md │ ├── AvoidUnauthorizedApiSessionIdInApex.md │ ├── AvoidUnauthorizedApiSessionIdInFlows.md │ ├── AvoidUnauthorizedApiSessionIdVisualforce.md │ ├── AvoidUnauthorizedGetSessionIdInApex.md │ ├── AvoidUnauthorizedGetSessionIdInVisualforce.md │ ├── AvoidUnescapedHtml.md │ ├── AvoidUnsafePasswordManagementUse.md │ ├── LimitConnectedAppScope.md │ ├── LoadCSSApexStylesheet.md │ ├── LoadCSSLinkHref.md │ ├── LoadJavaScriptHtmlScript.md │ ├── LoadJavaScriptIncludeScript.md │ ├── ProtectSensitiveData.md │ ├── UpgradeLwcLockerSecuritySupport.md │ ├── UseHttpsCallbackUrl.md │ └── UseLwcDomManual.md ├── smoke-tests ├── smoke-test-generator.js ├── smoke-test.cmd ├── smoke-test.sh └── test-data │ ├── config-files │ └── existing-config.yml │ ├── workspace-with-apex-files │ ├── MyClass1.cls │ ├── MyClass2.cls │ └── MyClass3.cls │ └── workspace-with-mixed-files │ ├── MyClass1.cls │ └── my-script.ts ├── src ├── Constants.ts ├── commands │ └── code-analyzer │ │ ├── config.ts │ │ ├── rules.ts │ │ └── run.ts └── lib │ ├── Display.ts │ ├── Telemetry.ts │ ├── actions │ ├── ConfigAction.ts │ ├── RulesAction.ts │ └── RunAction.ts │ ├── factories │ ├── CodeAnalyzerConfigFactory.ts │ └── EnginePluginsFactory.ts │ ├── listeners │ ├── LogEventListener.ts │ ├── ProgressEventListener.ts │ └── TelemetryEventListener.ts │ ├── messages.ts │ ├── models │ └── ConfigModel.ts │ ├── utils │ ├── DateTimeUtils.ts │ ├── FileUtil.ts │ ├── StylingUtil.ts │ └── WorkspaceUtil.ts │ ├── viewers │ ├── ActionSummaryViewer.ts │ ├── ConfigViewer.ts │ ├── ResultsViewer.ts │ └── RuleViewer.ts │ └── writers │ ├── ConfigWriter.ts │ ├── LogWriter.ts │ ├── ResultsWriter.ts │ └── RulesWriter.ts ├── test ├── commands │ └── code-analyzer │ │ ├── config.test.ts │ │ ├── rules.test.ts │ │ └── run.test.ts ├── fixtures │ ├── comparison-files │ │ └── lib │ │ │ ├── actions │ │ │ ├── ConfigAction.test.ts │ │ │ │ ├── action-summaries │ │ │ │ │ ├── no-outfile-created.txt.goldfile │ │ │ │ │ ├── outfile-created.txt.goldfile │ │ │ │ │ └── pre-execution-summary.txt.goldfile │ │ │ │ ├── default-configurations │ │ │ │ │ ├── Stub1Rule1.yml.goldfile │ │ │ │ │ ├── Stub1Rule7.yml.goldfile │ │ │ │ │ ├── StubEngine1.yml.goldfile │ │ │ │ │ └── rulesSectionWithNoModifications.yml.goldfile │ │ │ │ ├── derivables-as-defaults │ │ │ │ │ ├── config_root.yml.goldfile │ │ │ │ │ └── log_folder.yml.goldfile │ │ │ │ ├── derivables-as-non-defaults │ │ │ │ │ ├── config_root.yml.goldfile │ │ │ │ │ └── log_folder.yml.goldfile │ │ │ │ ├── header-comments │ │ │ │ │ ├── config_root-section.yml.goldfile │ │ │ │ │ ├── engines-section.yml.goldfile │ │ │ │ │ ├── log_folder-section.yml.goldfile │ │ │ │ │ ├── log_level-section.yml.goldfile │ │ │ │ │ ├── rules-section.yml.goldfile │ │ │ │ │ ├── top-level-end.yml.goldfile │ │ │ │ │ └── top-level-start.yml.goldfile │ │ │ │ ├── override-configurations-only-modifications │ │ │ │ │ ├── Stub1Rule1.yml.goldfile │ │ │ │ │ ├── Stub1Rule2.yml.goldfile │ │ │ │ │ └── Stub1Rule3.yml.goldfile │ │ │ │ ├── override-configurations │ │ │ │ │ ├── Stub1Rule1.yml.goldfile │ │ │ │ │ ├── Stub1Rule2.yml.goldfile │ │ │ │ │ ├── Stub1Rule3.yml.goldfile │ │ │ │ │ ├── Stub1Rule4.yml.goldfile │ │ │ │ │ ├── Stub1Rule7.yml.goldfile │ │ │ │ │ ├── Stub1Rule8.yml.goldfile │ │ │ │ │ ├── StubEngine1.yml.goldfile │ │ │ │ │ ├── StubEngine2_forConfigWithRelativePathScenario.yml.goldfile │ │ │ │ │ └── StubEngine3.yml.goldfile │ │ │ │ └── workspace-resolution │ │ │ │ │ └── workspaceAwareRules.yml.goldfile │ │ │ ├── RulesAction.test.ts │ │ │ │ └── action-summaries │ │ │ │ │ ├── no-rules.txt.goldfile │ │ │ │ │ ├── pre-execution-summary.txt.goldfile │ │ │ │ │ ├── rules-with-outfile.txt.goldfile │ │ │ │ │ └── some-rules.txt.goldfile │ │ │ └── RunAction.test.ts │ │ │ │ └── action-summaries │ │ │ │ ├── no-violations.txt.goldfile │ │ │ │ ├── pre-execution-summary.txt.goldfile │ │ │ │ ├── some-outfiles.txt.goldfile │ │ │ │ └── some-violations.txt.goldfile │ │ │ ├── utils │ │ │ └── StylingUtil.test.ts │ │ │ │ ├── all-keys-printed.txt │ │ │ │ ├── non-existent-key-printed.txt │ │ │ │ ├── styled-comment.txt │ │ │ │ ├── styled-header-and-body.txt │ │ │ │ ├── styled-header.txt │ │ │ │ └── subset-of-keys-printed.txt │ │ │ └── viewers │ │ │ ├── ResultsViewer.test.ts │ │ │ ├── four-identical-violations-details.txt │ │ │ ├── four-unique-violations-details.txt │ │ │ └── one-multilocation-violation-details.txt │ │ │ └── RuleViewer.test.ts │ │ │ ├── one-rule-details.txt │ │ │ └── two-rules-details.txt │ ├── example-workspaces │ │ ├── ConfigAction.test.ts │ │ │ └── optional-input-config.yml │ │ ├── workspace-with-dotted-items │ │ │ ├── .dotted-directory-a │ │ │ │ ├── .dotted-file-1a.txt │ │ │ │ └── undotted-file-1a.txt │ │ │ ├── .dotted-directory-b │ │ │ │ ├── .dotted-file-1b.txt │ │ │ │ └── undotted-file-1b.txt │ │ │ ├── .dotted-file-1.txt │ │ │ ├── .dotted-file-2.txt │ │ │ ├── undotted-directory-a │ │ │ │ ├── .dotted-file-2a.txt │ │ │ │ └── undotted-file-2a.txt │ │ │ ├── undotted-directory-b │ │ │ │ ├── .dotted-file-2b.txt │ │ │ │ └── undotted-file-2b.txt │ │ │ ├── undotted-file-1.txt │ │ │ └── undotted-file-2.txt │ │ ├── workspace-with-misc-files │ │ │ ├── README.md │ │ │ ├── great.txt │ │ │ ├── hello.js │ │ │ ├── package.json │ │ │ └── world.cls │ │ ├── workspace-with-multiple-configs │ │ │ ├── code-analyzer.yaml │ │ │ └── code-analyzer.yml │ │ ├── workspace-with-yaml-config │ │ │ └── code-analyzer.yaml │ │ └── workspace-with-yml-config │ │ │ └── code-analyzer.yml │ ├── invalid-configs │ │ └── nonexistent-log-folder.yml │ └── valid-configs │ │ └── sample-config-file.yml ├── lib │ ├── actions │ │ ├── ConfigAction.test.ts │ │ ├── RulesAction.test.ts │ │ └── RunAction.test.ts │ ├── factories │ │ ├── CodeAnalyzerConfigFactory.test.ts │ │ └── EnginePluginsFactory.test.ts │ ├── listeners │ │ ├── LogEventListener.test.ts │ │ └── ProgressEventListener.test.ts │ ├── utils │ │ ├── StylingUtil.test.ts │ │ └── WorkspaceUtil.test.ts │ ├── viewers │ │ ├── ConfigViewer.test.ts │ │ ├── ResultsViewer.test.ts │ │ └── RuleViewer.test.ts │ └── writers │ │ ├── ConfigWriter.test.ts │ │ ├── LogWriter.test.ts │ │ ├── ResultsWriter.test.ts │ │ └── RulesWriter.test.ts ├── sample-code │ ├── fileA.cls │ ├── fileZ.cls │ └── someFile.cls └── stubs │ ├── SpyConfigViewer.ts │ ├── SpyConfigWriter.ts │ ├── SpyDisplay.ts │ ├── SpyLogWriter.ts │ ├── SpyResultsViewer.ts │ ├── SpyResultsWriter.ts │ ├── SpyRuleViewer.ts │ ├── SpyRuleWriter.ts │ ├── SpyTelemetryEmitter.ts │ ├── StubCodeAnalyzerConfigFactories.ts │ ├── StubConfigModel.ts │ ├── StubEnginePlugins.ts │ ├── StubEnginePluginsFactories.ts │ ├── StubRuleSelection.ts │ ├── StubRules.ts │ └── StubRunResults.ts ├── tsconfig.build.json └── tsconfig.json /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = tab 5 | indent_size = 4 6 | charset = utf-8 7 | trim_trailing_whitespace = true 8 | insert_final_newline = true 9 | 10 | [*.java] 11 | indent_style = space 12 | indent_size = 4 13 | 14 | [*.md] 15 | trim_trailing_whitespace = false 16 | 17 | [*.yml] 18 | indent_style = space 19 | indent_size = 2 20 | 21 | [*.kts] 22 | indent_style = space 23 | indent_size = 2 24 | 25 | [*.goldfile] 26 | insert_final_newline = false 27 | -------------------------------------------------------------------------------- /.git2gus/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "productTag": "a1aB0000000c7jnIAA", 3 | "defaultBuild": "[SFCA] Scanner 4.0", 4 | "hideWorkItemUrl": "true", 5 | "issueTypeLabels": { 6 | "type:feature": "USER STORY", 7 | "type:bug-p0": "BUG P0", 8 | "type:bug-p1": "BUG P1", 9 | "type:bug-p2": "BUG P2", 10 | "type:bug-p3": "BUG P3", 11 | "type:security": "BUG P0", 12 | "type:feedback": "", 13 | "type:duplicate": "" 14 | }, 15 | "issueEpicMapping": { 16 | "USER STORY": "a3QEE000000OpkY2AS", 17 | "BUG P0": "a3QEE000000V67Z2AS", 18 | "BUG P1": "a3QEE000000V67Z2AS", 19 | "BUG P2": "a3QEE000000V67Z2AS", 20 | "BUG P3": "a3QEE000000V67Z2AS" 21 | }, 22 | "gusTitlePrefix": "[GitHub Issue]", 23 | "statusWhenClosed": "FIXED" 24 | } 25 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # 2 | # https://help.github.com/articles/dealing-with-line-endings/ 3 | # 4 | # Test comparison files should always use lf instead of crlf, to avoid OS-based shenanigans 5 | **/test/fixtures/comparison-files/**/* text eol=lf 6 | # These are explicitly windows files and should use crlf 7 | *.bat text eol=crlf 8 | 9 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/0-code_analyzer_bug.yml: -------------------------------------------------------------------------------- 1 | name: Report a Bug with the "code-analyzer" (v5) CLI Commands 2 | description: Report an issue with one of the commands contained in the "@salesforce/plugin-code-analyzer" Salesforce CLI plugin. 3 | title: "[BUG][code-analyzer] " 4 | body: 5 | - type: checkboxes 6 | attributes: 7 | label: Have you tried to resolve this issue yourself first? 8 | description: | 9 | You can often resolve `code-analyzer` issues on your own. Follow these steps: 10 | 1. Read the error message. 11 | 2. Read the [Salesforce Code Analyzer](https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/guide/get-started.html) documentation. 12 | 3. Double-check the command that you ran. Make sure that items like file names, method names, and tag names are correctly spelled and cased. 13 | 4. Verify that your code is syntactically valid. 14 | 5. Verify that the error is reproducible on another computer. 15 | 6. Check the open and closed [issues](https://github.com/forcedotcom/code-analyzer/issues) to see if your issue is already logged. 16 | options: 17 | - label: I confirm I have gone through the above steps and still have an issue to report. 18 | required: true 19 | - type: textarea 20 | attributes: 21 | label: Bug Description 22 | description: Provide a clear and concise overview of the bug. 23 | validations: 24 | required: true 25 | - type: textarea 26 | attributes: 27 | label: Output / Logs 28 | description: Attach any output or logs here. 29 | placeholder: | 30 | Add log output or drag files here. 31 | - type: textarea 32 | attributes: 33 | label: Steps To Reproduce 34 | description: List the steps that you used to reproduce the bug behavior. Be as specific and clear as possible. If possible, ensure the steps are reproducible on another machine and attach any files that demonstrate the issue. 35 | placeholder: | 36 | 1. I first do ... 37 | 2. Then I do ... 38 | 3. Lastly, I do ... 39 | validations: 40 | required: true 41 | - type: textarea 42 | attributes: 43 | label: Expected Behavior 44 | description: Provide a clear and concise description of what you expected to happen. 45 | validations: 46 | required: true 47 | - type: input 48 | attributes: 49 | label: Operating System 50 | description: | 51 | What's your computer's operating system? 52 | placeholder: | 53 | Example: macOS Sonoma 14.4.1 54 | validations: 55 | required: true 56 | - type: input 57 | attributes: 58 | label: Salesforce CLI Version 59 | description: | 60 | What do you get when you run the "sf --version" command? 61 | placeholder: | 62 | Example: @salesforce/cli/2.90.4 darwin-x64 node-v22.15.0 63 | validations: 64 | required: true 65 | - type: input 66 | attributes: 67 | label: Code Analyzer Plugin (code-analyzer) Version 68 | description: | 69 | What do you get when you run the "sf plugins" command? 70 | placeholder: | 71 | Example: code-analyzer 5.0.0 (5.0.0) 72 | validations: 73 | required: true 74 | - type: input 75 | attributes: 76 | label: Node Version 77 | description: | 78 | What do you get when you run the "node --version" command? 79 | placeholder: | 80 | Example: v23.4.0 81 | validations: 82 | required: false 83 | - type: input 84 | attributes: 85 | label: Java Version 86 | description: | 87 | What do you get when you run the "java -version" command? 88 | placeholder: | 89 | Example: openjdk version "11.0.17.0.1" 2022-10-18 LTS 90 | validations: 91 | required: false 92 | - type: input 93 | attributes: 94 | label: Python Version 95 | description: | 96 | What do you get when you run the "python --version" command? 97 | placeholder: | 98 | Example: Python 3.11.8 99 | validations: 100 | required: false 101 | - type: textarea 102 | attributes: 103 | label: Additional Context (Screenshots, Files, etc) 104 | description: Add any other context about your problem. 105 | placeholder: | 106 | Drag any files or screenshots you have here. 107 | - type: textarea 108 | attributes: 109 | label: Workaround 110 | description: What ways have you found to sidestep the problem? If you haven't found a workaround, what have you tried so far? 111 | - type: dropdown 112 | attributes: 113 | label: Urgency 114 | description: What is the severity of the problem? 115 | options: 116 | - Low 117 | - Moderate 118 | - High 119 | - Critical 120 | default: 0 121 | validations: 122 | required: true 123 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/1-scanner_bug.yml: -------------------------------------------------------------------------------- 1 | name: Report a Bug with the "scanner" (v4) CLI Commands 2 | description: Report an issue with one of the commands contained in the "@salesforce/sfdx-scanner" Salesforce CLI plugin. 3 | title: "[BUG][scanner] " 4 | body: 5 | - type: checkboxes 6 | attributes: 7 | label: Have you tried to resolve this issue yourself first? 8 | description: | 9 | You can often resolve `scanner` issues on your own. Follow these steps: 10 | 1. Read the error message. 11 | 2. Read the [Salesforce Code Analyzer v4](https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/guide/code-analyzer-3x.html) documentation. 12 | 3. Double-check the command that you ran. Make sure that items like file names, method names, and category names are correctly spelled and cased. 13 | 4. Verify that your code is syntactically valid. 14 | 5. Verify that the error is reproducible on another computer. 15 | 6. Check open and closed [issues](https://github.com/forcedotcom/code-analyzer/issues) to see if your issue is already logged. 16 | options: 17 | - label: I confirm I have gone through the above steps and still have an issue to report. 18 | required: true 19 | - type: textarea 20 | attributes: 21 | label: Bug Description 22 | description: Provide a clear and concise overview of the bug. 23 | validations: 24 | required: true 25 | - type: textarea 26 | attributes: 27 | label: Output / Logs 28 | description: Attach any output or logs here. 29 | placeholder: | 30 | Add log output or drag files here. 31 | - type: textarea 32 | attributes: 33 | label: Steps To Reproduce 34 | description: List the steps that you used to reproduce the bug behavior. Be as specific and clear as possible. If possible, ensure the steps are reproducible on another machine and attach any files that demonstrate the issue. 35 | placeholder: | 36 | 1. I first do ... 37 | 2. Then I do ... 38 | 3. Lastly, I do ... 39 | validations: 40 | required: true 41 | - type: textarea 42 | attributes: 43 | label: Expected Behavior 44 | description: Provide a clear and concise description of what you expected to happen. 45 | validations: 46 | required: true 47 | - type: input 48 | attributes: 49 | label: Operating System 50 | description: | 51 | What is your computer's operating system? 52 | placeholder: | 53 | Example: macOS Sonoma 14.4.1 54 | validations: 55 | required: true 56 | - type: input 57 | attributes: 58 | label: Salesforce CLI Version 59 | description: | 60 | What do you get when you run the "sf --version" command? 61 | placeholder: | 62 | Example: @salesforce/cli/2.90.4 darwin-x64 node-v22.15.0 63 | validations: 64 | required: true 65 | - type: input 66 | attributes: 67 | label: Scanner Plugin Version 68 | description: | 69 | What do you get when you run the "sf plugins" command? 70 | placeholder: | 71 | Example: @salesforce/sfdx-scanner 4.12.0 (4.12.0) 72 | validations: 73 | required: true 74 | - type: input 75 | attributes: 76 | label: Node Version 77 | description: | 78 | What do you get when you run the "node --version" command? 79 | placeholder: | 80 | Example: v23.4.0 81 | validations: 82 | required: false 83 | - type: input 84 | attributes: 85 | label: Java Version 86 | description: | 87 | What do you get when you run the "java -version" command? 88 | placeholder: | 89 | Example: openjdk version "11.0.17.0.1" 2022-10-18 LTS 90 | validations: 91 | required: false 92 | - type: textarea 93 | attributes: 94 | label: Additional Context (Screenshots, Files, etc) 95 | description: Add any other context about the problem. 96 | placeholder: | 97 | Drag any files or screenshots you have here. 98 | - type: textarea 99 | attributes: 100 | label: Workaround 101 | description: What ways have you found to sidestep the problem? If you haven't found a workaround, what have you tried so far? 102 | - type: dropdown 103 | attributes: 104 | label: Urgency 105 | description: What is the severity of the problem? 106 | options: 107 | - Low 108 | - Moderate 109 | - High 110 | - Critical 111 | default: 0 112 | validations: 113 | required: true 114 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/3-github_action_bug.yml: -------------------------------------------------------------------------------- 1 | name: Report a Bug with the "Run Salesforce Code Analyzer" GitHub Action 2 | description: Report an issue limited to only the GitHub Action. 3 | title: "[BUG][github-action] " 4 | body: 5 | - type: checkboxes 6 | attributes: 7 | label: Have you tried to resolve this issue yourself first? 8 | description: | 9 | You can often resolve these issues on your own. Follow these steps: 10 | 1. Read the error message. 11 | 2. Read the [Salesforce Code Analyzer](https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/guide/get-started.html) documentation. 12 | 3. Double-check the command that you ran. Make sure that items like file names, method names, and tag names are correctly spelled and cased. 13 | 4. Verify that your code is syntactically valid. 14 | 5. Verify that you can't reproduce the error using the appropriate Salesforce CLI command directly. 15 | 6. Verify that the error is reproducible on another computer. 16 | 7. Check open and closed [issues](https://github.com/forcedotcom/code-analyzer/issues) to see if your issue is already logged. 17 | options: 18 | - label: I confirm I have gone through the above steps and still have an issue to report. 19 | required: true 20 | - type: textarea 21 | attributes: 22 | label: Bug Description 23 | description: Provide a clear and concise overview of the bug. 24 | validations: 25 | required: true 26 | - type: textarea 27 | attributes: 28 | label: Output / Logs 29 | description: Attach any output or logs here 30 | placeholder: | 31 | Add log output or drag files here. 32 | - type: textarea 33 | attributes: 34 | label: Steps To Reproduce 35 | description: List the steps that you used to reproduce the bug behavior. Be as specific and clear as possible. 36 | placeholder: | 37 | 1. I first do ... 38 | 2. Then I do ... 39 | 3. Lastly, I do ... 40 | validations: 41 | required: true 42 | - type: textarea 43 | attributes: 44 | label: Expected Behavior 45 | description: Provide a clear and concise description of what you expected to happen. 46 | validations: 47 | required: true 48 | - type: input 49 | attributes: 50 | label: Operating System 51 | description: | 52 | What's your computer's operating system? 53 | placeholder: | 54 | Example: macOS Sonoma 14.4.1 55 | validations: 56 | required: true 57 | - type: input 58 | attributes: 59 | label: Salesforce CLI Version 60 | description: | 61 | What version of the Salesforce CLI are you using in your workflow? 62 | placeholder: | 63 | Example: @salesforce/cli/2.90.4 darwin-x64 node-v22.15.0 64 | validations: 65 | required: true 66 | - type: input 67 | attributes: 68 | label: Code Analyzer Plugin ("code-analyzer") Version 69 | description: | 70 | What version of the Code Analyzer Plugin are you using in your workflow? 71 | placeholder: | 72 | Example: code-analyzer 5.0.0 73 | validations: 74 | required: true 75 | - type: input 76 | attributes: 77 | label: Node Version 78 | description: | 79 | What version of Node are you using in your workflow? 80 | placeholder: | 81 | Example: v23.4.0 82 | validations: 83 | required: false 84 | - type: input 85 | attributes: 86 | label: Java Version 87 | description: | 88 | What version of Java are you using in your workflow (if applicable)? 89 | placeholder: | 90 | Example: openjdk version "11.0.17.0.1" 2022-10-18 LTS 91 | validations: 92 | required: false 93 | - type: input 94 | attributes: 95 | label: Python Version 96 | description: | 97 | What version of Python are you using in your workflow (if applicable)? 98 | placeholder: | 99 | Example: Python 3.11.8 100 | validations: 101 | required: false 102 | - type: textarea 103 | attributes: 104 | label: Additional Context (Screenshots, Files, etc) 105 | description: Add any other context about the problem. 106 | placeholder: | 107 | Drag any files or screenshots you have here. 108 | - type: textarea 109 | attributes: 110 | label: Workaround 111 | description: What ways have you found to sidestep the problem? If you haven't found a workaround, what have you tried so far? 112 | - type: dropdown 113 | attributes: 114 | label: Urgency 115 | description: What is the severity of the problem? 116 | options: 117 | - Low 118 | - Moderate 119 | - High 120 | - Critical 121 | default: 0 122 | validations: 123 | required: true 124 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/5-feature_request.yml: -------------------------------------------------------------------------------- 1 | name: Request a New Feature 2 | description: Request a new Salesforce Code Analyzer feature, such as a new rule or an additional engine. 3 | title: "[Feature Request] " 4 | body: 5 | - type: dropdown 6 | attributes: 7 | label: Product Area 8 | description: What is the product area of the feature you are requesting? 9 | options: 10 | - The "code-analyzer" CLI 11 | - The "Salesforce Code Analyzer" VS Code Extension 12 | - The “Run Salesforce Code Analyzer” GitHub Action 13 | - An Engine 14 | - A Rule 15 | - Other 16 | default: 0 17 | validations: 18 | required: true 19 | - type: textarea 20 | attributes: 21 | label: Your Need or Problem 22 | description: Provide a clear and concise description of your need or problem. 23 | placeholder: When I do XYZ, I am unable to... 24 | validations: 25 | required: true 26 | - type: textarea 27 | attributes: 28 | label: Your Desired Solution 29 | description: Provide a clear and concise description of the enhancement you'd like us to add to Salesforce Code Analyzer. 30 | placeholder: | 31 | Please add a command, such as: 32 | code-analyzer abc xyz 33 | that gives the following output: 34 | ... 35 | validations: 36 | required: true 37 | - type: textarea 38 | attributes: 39 | label: Alternatives Considered 40 | description: Describe any alternative solutions or features you've considered. 41 | - type: textarea 42 | attributes: 43 | label: Additional Context (Screenshots, Files, etc) 44 | description: Add any other context about the problem. 45 | placeholder: | 46 | Drag any files or screenshots you have here. 47 | - type: textarea 48 | attributes: 49 | label: Workaround 50 | description: What ways have you found to sidestep the problem? If you haven't found a workaround, what have you tried so far? 51 | - type: dropdown 52 | attributes: 53 | label: Urgency 54 | description: What is the severity of the problem? 55 | options: 56 | - Low 57 | - Moderate 58 | - High 59 | - Critical 60 | default: 0 61 | validations: 62 | required: true 63 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/6-general_feedback.yml: -------------------------------------------------------------------------------- 1 | name: General Feedback 2 | description: Share general feedback, comments, or questions about Salesforce Code Analyzer. 3 | title: "[Feedback] " 4 | labels: ["FEEDBACK"] 5 | body: 6 | - type: textarea 7 | attributes: 8 | label: Feedback 9 | description: Share your thoughts, comments, or questions about Salesforce Code Analyzer. 10 | placeholder: I'd like to share some feedback about... 11 | validations: 12 | required: true 13 | - type: textarea 14 | attributes: 15 | label: Context 16 | description: Provide any relevant context, such as your use case, environment, or specific scenario. 17 | placeholder: I'm using Salesforce Code Analyzer in the following context... 18 | - type: textarea 19 | attributes: 20 | label: Suggestions 21 | description: Do you have any suggestions for improvement? 22 | placeholder: I think it would be better if... 23 | - type: textarea 24 | attributes: 25 | label: Additional Information 26 | description: Add any other information, screenshots, or examples. 27 | placeholder: | 28 | Drag any files or screenshots you have here. 29 | - type: dropdown 30 | attributes: 31 | label: Are you interested in contributing to this project? 32 | options: 33 | - Yes, I'd like to contribute. 34 | - Maybe in the future. 35 | - No, I'm just providing feedback. 36 | default: 0 37 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false -------------------------------------------------------------------------------- /.github/workflows/apply-npm-tag-to-version.yml: -------------------------------------------------------------------------------- 1 | name: apply-npm-tag-to-version 2 | on: 3 | workflow_dispatch: 4 | inputs: 5 | tag_name: 6 | description: 'Tag Name (ex: latest):' 7 | required: true 8 | type: string 9 | version: 10 | description: 'Version (ex: 5.2.0):' 11 | required: true 12 | type: string 13 | confirm: 14 | description: 'Check this box to confirm that you understand that applying a tag using this action is only recommended for emergency rollback situations and that you understand the consequences.' 15 | required: true 16 | type: boolean 17 | 18 | jobs: 19 | publish_package: 20 | runs-on: ubuntu-latest 21 | 22 | steps: 23 | - uses: actions/checkout@v4 24 | - uses: actions/setup-node@v4 25 | with: 26 | node-version: 'lts/*' 27 | 28 | - name: Fail if not confirmed 29 | if: ${{ github.event.inputs.confirm != 'true' }} 30 | run: | 31 | echo "::error::You did not confirm, so dist-tag not called." 32 | exit 1 33 | 34 | - name: Prepare NPM Credentials 35 | run: echo "//registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }}" > ~/.npmrc 36 | 37 | - name: Apply tag 38 | run: | 39 | echo "You have confirmed that using this action is only recommended for emergency rollback situations and that you are responsible for manually applying the ${{ github.event.inputs.tag_name }} tag to @salesforce/plugin-code-analyzer@${{ github.event.inputs.version }}." 40 | echo "Applying tag..." 41 | npm dist-tag add @salesforce/plugin-code-analyzer@${{ github.event.inputs.version }} ${{ github.event.inputs.tag_name }} 42 | -------------------------------------------------------------------------------- /.github/workflows/automated-release-tasks.yml: -------------------------------------------------------------------------------- 1 | name: automated-release-tasks 2 | on: 3 | schedule: 4 | # Cron syntax is "minute[0-59] hour[0-23] date[1-31] month[1-12] day[0-6]". '*' is 'any value,' and multiple values 5 | # can be specified with comma-separated lists. All times are UTC. 6 | # So this expression means "run at 12 PM UTC, every Friday". 7 | - cron: "0 12 * * 5" 8 | 9 | jobs: 10 | # Depending on circumstances, we may want to exit early instead of running the workflow to completion. 11 | verify-should-run: 12 | runs-on: macos-latest 13 | outputs: 14 | should-run: ${{ steps.main.outputs.should_run }} 15 | steps: 16 | - id: main 17 | run: | 18 | # `date -u` returns UTC datetime, and `%u` formats the output to be the day of the week, with 1 being Monday, 19 | # 2 being Tuesday, etc. 20 | TODAY_DOW=$(date -u +%u) 21 | # This `date` expression returns the last Tuesday of the month, which is our Release Day. %d formats the output 22 | # as the day of the month (1-31). 23 | NEXT_RELEASE_DATE=$(date -u -v1d -v+1m -v-1d -v-tue +%d) 24 | # This `date` expression returns next Tuesday, and `%d` formats the output as the day of the month (1-31). 25 | NEXT_TUESDAY_DATE=$(date -u -v+tue +%d) 26 | # This workflow should only be allowed to run to completion on the Friday before Release Day. 27 | [[ $TODAY_DOW != 5 || $NEXT_RELEASE_DATE != $NEXT_TUESDAY_DATE ]] && echo "should_run=false" >> "$GITHUB_OUTPUT" || echo "should_run=true" >> "$GITHUB_OUTPUT" 28 | create-release-branch: 29 | needs: verify-should-run 30 | if: ${{ needs.verify-should-run.outputs.should-run == 'true' }} 31 | uses: ./.github/workflows/create-release-branch.yml 32 | secrets: inherit 33 | with: 34 | release-type: minor 35 | -------------------------------------------------------------------------------- /.github/workflows/create-github-release.yml: -------------------------------------------------------------------------------- 1 | name: create-github-release 2 | on: 3 | pull_request: 4 | branches: 5 | - main 6 | types: 7 | # There's no event type for "merged", so we just run any time a PR is closed, and exit early 8 | # if the PR wasn't actually merged. 9 | - closed 10 | 11 | jobs: 12 | create-github-release: 13 | # Since the workflow runs any time a PR against main is closed, we need this 14 | # `if` to make sure that the workflow only does anything meaningful if the PR 15 | # was actually merged. 16 | if: github.event.pull_request.merged == true 17 | runs-on: ubuntu-latest 18 | permissions: 19 | contents: write 20 | steps: 21 | - name: Checkout main 22 | uses: actions/checkout@v4 23 | with: 24 | ref: main 25 | - name: Get version property 26 | id: get-version-property 27 | run: | 28 | PACKAGE_VERSION=$(jq -r ".version" package.json) 29 | echo "package_version=$PACKAGE_VERSION" >> "$GITHUB_OUTPUT" 30 | - name: Create github release 31 | uses: softprops/action-gh-release@v2 32 | with: 33 | tag_name: v${{ steps.get-version-property.outputs.package_version }} 34 | name: v${{ steps.get-version-property.outputs.package_version }} 35 | target_commitish: main 36 | body: See [release notes](https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/guide/release-notes.html) 37 | token: ${{ secrets.SVC_CLI_BOT_GITHUB_TOKEN }} 38 | make_latest: true 39 | -------------------------------------------------------------------------------- /.github/workflows/daily-smoke-tests.yml: -------------------------------------------------------------------------------- 1 | name: daily-smoke-tests 2 | on: 3 | workflow_dispatch: 4 | schedule: 5 | # Cron syntax is "minute[0-59] hour[0-23] date[1-31] month[1-12] day[0-6]". '*' is 'any value,' and multiple values 6 | # can be specified with comma-separated lists. All times are UTC. 7 | # So this expression means "run at 13:30 UTC every day". This time was chosen because it corresponds to 8 | # 8:30AM CDT, meaning that any issues will be surfaced before the start of business. 9 | - cron: "30 13 * * *" 10 | jobs: 11 | smoke-test: 12 | # We run the daily smoke tests against 'dev' to validate that the code currently in development is still valid 13 | uses: ./.github/workflows/run-tests.yml 14 | with: 15 | node-matrix: "[{version: 'lts/*', artifact: 'lts'}, {version: 'latest', artifact: 'latest'}]" 16 | target-branch: dev 17 | -------------------------------------------------------------------------------- /.github/workflows/validate-pr.yml: -------------------------------------------------------------------------------- 1 | name: validate-pr 2 | on: 3 | pull_request: 4 | types: [edited, opened, reopened, synchronize] 5 | 6 | jobs: 7 | # Prevent merging to dev-4 or main-4 to preserve until we're ready to delete 8 | verify_target_branch: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - if: ${{ github.base_ref == 'dev-4' || github.base_ref == 'main-4' }} 12 | run: | 13 | echo "Forbidden to merge this branch into dev-4 or main-4" 14 | exit 1 15 | # We need to verify that the Pull Request's title matches the desired format. 16 | verify_pr_title: 17 | runs-on: ubuntu-latest 18 | name: Verify that PR title contains well-formed GUS work item tag. 19 | steps: 20 | # Private actions must check out repo first. 21 | - name: Checkout 22 | uses: actions/checkout@v4 23 | - name: Verify PR Title 24 | run: | 25 | title="${{ github.event.pull_request.title }}" 26 | title_upper=$(echo "$title" | tr '[:lower:]' '[:upper:]') 27 | base_ref="${{ github.base_ref }}" 28 | 29 | # Define regex patterns for different types of PR titles 30 | MAIN2DEV_REGEX="^MAIN2DEV[[:space:]]*:?[[:space:]]*@W-[[:digit:]]{8,9}@.*MERGING.+[[:digit:]]{1,2}\.[[:digit:]]{1,2}\.[[:digit:]]{1,2}.*" 31 | RELEASE2MAIN_REGEX="^RELEASE[[:space:]]*:?[[:space:]]*@W-[[:digit:]]{8,9}@.+" 32 | PR_INTO_DEV_OR_RELEASE_REGEX="^(FIX|CHANGE|NEW)([[:space:]]*\([^)]+\))?[[:space:]]*:?[[:space:]]*@W-[[:digit:]]{8,9}@.+" 33 | 34 | # Validate PR title based on base_ref and head_ref 35 | if [[ "$base_ref" == "dev" && "${{ startsWith(github.head_ref, 'm2d/') }}" == "true" ]]; then 36 | if [[ ! "$title_upper" =~ $MAIN2DEV_REGEX ]]; then 37 | echo "::error::Invalid PR title: '$title'. Please follow the format: Main2Dev @W-XXXXXXXX@ Merging.*\d+\.\d+\.\d+" 38 | exit 1 39 | fi 40 | elif [[ "$base_ref" == "main" ]]; then 41 | if [[ ! "$title_upper" =~ $RELEASE2MAIN_REGEX ]]; then 42 | echo "::error::Invalid PR title: '$title'. Please follow the format: RELEASE @W-XXXXXXXX@ Summary" 43 | exit 1 44 | fi 45 | elif [[ "$base_ref" == "dev" || "${{ startsWith(github.base_ref, 'release-') }}" == "true" ]]; then 46 | if [[ ! "$title_upper" =~ $PR_INTO_DEV_OR_RELEASE_REGEX ]]; then 47 | echo "::error::Invalid PR title: '$title'. Please follow the format: FIX|CHANGE|NEW (__) @W-XXXXXXXX@ Summary" 48 | exit 1 49 | fi 50 | else 51 | echo "PR title '$title' automatically accepted for $base_ref branch." 52 | fi 53 | 54 | # If no errors, print success 55 | echo "Valid PR title: '$title'" 56 | # Separately, we also need to run all of our tests. 57 | run_tests: 58 | uses: ./.github/workflows/run-tests.yml 59 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | /test-results 3 | /test-coverage 4 | /typescript-test-results 5 | .DS_Store 6 | *-debug.log 7 | *-error.log 8 | /.nyc_output 9 | /dist 10 | /lib 11 | /tmp 12 | node_modules 13 | /out 14 | /reports 15 | # Build folders 16 | /sample-code/pmd-example-rules/target 17 | 18 | 19 | # Logs 20 | logs 21 | *.log 22 | npm-debug.log* 23 | yarn-debug.log* 24 | yarn-error.log* 25 | lerna-debug.log* 26 | 27 | # Temporary test logs 28 | stderr*.txt 29 | stdout*.txt 30 | 31 | # Ignore jekyll cache and _site for doc 32 | docs/.jekyll-cache/ 33 | docs/_site/ 34 | 35 | # Diagnostic reports (https://nodejs.org/api/report.html) 36 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 37 | 38 | # Runtime data 39 | pids 40 | *.pid 41 | *.seed 42 | *.pid.lock 43 | 44 | # Directory for instrumented libs generated by jscoverage/JSCover 45 | lib-cov 46 | 47 | # Coverage directory used by tools like istanbul 48 | coverage 49 | *.lcov 50 | 51 | # nyc test coverage 52 | .nyc_output 53 | 54 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 55 | .grunt 56 | 57 | # Bower dependency directory (https://bower.io/) 58 | bower_components 59 | 60 | # node-waf configuration 61 | .lock-wscript 62 | 63 | # Compiled binary addons (https://nodejs.org/api/addons.html) 64 | build/Release 65 | 66 | # Dependency directories 67 | node_modules/ 68 | jspm_packages/ 69 | 70 | # TypeScript v1 declaration files 71 | typings/ 72 | 73 | # TypeScript cache 74 | *.tsbuildinfo 75 | 76 | # Optional npm cache directory 77 | .npm 78 | 79 | # Optional eslint cache 80 | .eslintcache 81 | 82 | # Microbundle cache 83 | .rpt2_cache/ 84 | .rts2_cache_cjs/ 85 | .rts2_cache_es/ 86 | .rts2_cache_umd/ 87 | 88 | # Optional REPL history 89 | .node_repl_history 90 | 91 | # Output of 'npm pack' 92 | *.tgz 93 | 94 | # Recommended by npm-release-management orb 95 | *.sig 96 | package.json.bak 97 | 98 | # Yarn Integrity file 99 | .yarn-integrity 100 | 101 | # dotenv environment variables file 102 | .env 103 | .env.test 104 | 105 | # parcel-bundler cache (https://parceljs.org/) 106 | .cache 107 | 108 | # Next.js build output 109 | .next 110 | 111 | # Nuxt.js build / generate output 112 | .nuxt 113 | dist 114 | 115 | # Gatsby files 116 | .cache/ 117 | # Comment in the public line in if your project uses Gatsby and *not* Next.js 118 | # https://nextjs.org/blog/next-9-1#public-directory-support 119 | # public 120 | 121 | # vuepress build output 122 | .vuepress/dist 123 | 124 | # Serverless directories 125 | .serverless/ 126 | 127 | # FuseBox cache 128 | .fusebox/ 129 | 130 | # DynamoDB Local files 131 | .dynamodb/ 132 | 133 | # TernJS port file 134 | .tern-port 135 | 136 | # Pmd Rule Catalog representations 137 | /catalogs 138 | 139 | # IntelliJ files 140 | *.iml 141 | .idea/ 142 | 143 | # Ignore Gradle project-specific cache directory 144 | .gradle 145 | 146 | # Ignore Gradle build output directory 147 | build 148 | 149 | # Eclipse 150 | .classpath 151 | .project 152 | .settings 153 | 154 | # OCLIF lockfile auto-generated during publishing 155 | oclif.lock 156 | 157 | pmd-cataloger/bin 158 | 159 | sfge*.log.gz 160 | 161 | npm-shrinkwrap.json 162 | 163 | .npmrc 164 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "type": "node", 9 | "request": "attach", 10 | "name": "Attach to Remote", 11 | "address": "127.0.0.1", 12 | "port": 9229, 13 | "localRoot": "${workspaceFolder}", 14 | "remoteRoot": "${workspaceFolder}" 15 | }, 16 | { 17 | "name": "Unit Tests", 18 | "type": "node", 19 | "request": "launch", 20 | "protocol": "inspector", 21 | "program": "${workspaceRoot}/node_modules/.bin/_mocha", 22 | "args": [ 23 | "--require", 24 | "test/helpers/init.js", 25 | "--require", 26 | "ts-node/register", 27 | "--require", 28 | "source-map-support/register", 29 | "--recursive", 30 | "--reporter", 31 | "spec", 32 | "test/**/*.test.ts" 33 | ], 34 | "cwd": "${workspaceRoot}" 35 | } 36 | ] 37 | } -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | # Comment line immediately above ownership line is reserved for related gus information. Please be careful while editing. 2 | #ECCN:Open Source 3 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Instructions for Internal Contributors 2 | > At the moment, we are not accepting external contributions. Please watch this space to know when we open. 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2024, Salesforce.com, Inc. 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 11 | 12 | * Neither the name of Salesforce.com nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 15 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![License](https://img.shields.io/npm/l/scanner.svg)](https://github.com/forcedotcom/code-analyzer/blob/master/package.json) 2 | 3 | # Salesforce Code Analyzer 4 | Salesforce Code Analyzer is a unified tool to help Salesforce developers analyze their source code for security vulnerabilities, performance issues, best practices, and more. 5 | Code Analyzer analyzes multiple languages including Apex, JavaScript, HTML, CSS, and Salesforce metadata such as Flows. 6 | It relies on a consistent command-line interface and produces a results file of rule violations. 7 | Use the results to review and improve your code. 8 | 9 | If you're listing a managed package on AppExchange, it must pass security review. 10 | You're also required to upload your Salesforce Code Analyzer scan reports. 11 | Attach your Code Analyzer reports to your submission in the AppExchange Security Review Wizard. 12 | For more info, read [Scan Your Code with Salesforce Code Analyzer](https://developer.salesforce.com/docs/atlas.en-us.packagingGuide.meta/packagingGuide/security_review_code_analyzer_scan.htm) and [AppExchange Security Review](https://developer.salesforce.com/docs/atlas.en-us.packagingGuide.meta/packagingGuide/security_review_overview.htm). 13 | 14 | Integrate Code Analyzer into your Continuous Integration/Continuous Development (CI/CD) process to enforce rules that you define and to produce high-quality code. Salesforce provides an official [Github Action](https://github.com/marketplace/actions/run-salesforce-code-analyzer) to assist with this task. 15 | 16 | # Salesforce Code Analyzer Documentation 17 | Read the [Salesforce Code Analyzer](https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/guide/get-started.html) documentation to learn: 18 | * How to install Code Analyzer. 19 | * What's included in the Code Analyzer command reference. 20 | * What rules are included from engines such as PMD and ESLint. 21 | * How to write and manage custom rules. 22 | * How to set up your CI/CD process with Code Analyzer. 23 | * How to review code violations with the Code Analyzer VS Code Extension. -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | ## Security 2 | 3 | Please report any security issue to [security@salesforce.com](mailto:security@salesforce.com) 4 | as soon as it is discovered. This library limits its runtime dependencies in 5 | order to reduce the total cost of ownership as much as can be, but all consumers 6 | should remain vigilant and have their security stakeholders review all third-party 7 | products (3PP) like this one and their dependencies. -------------------------------------------------------------------------------- /bin/dev.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | node "%~dp0\dev" %* 4 | -------------------------------------------------------------------------------- /bin/dev.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node_modules/.bin/ts-node 2 | // eslint-disable-next-line node/shebang, unicorn/prefer-top-level-await 3 | (async () => { 4 | const oclif = await import('@oclif/core') 5 | await oclif.execute({development: true, dir: __dirname}) 6 | })() 7 | -------------------------------------------------------------------------------- /bin/run.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | node "%~dp0\run" %* 4 | -------------------------------------------------------------------------------- /bin/run.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | // eslint-disable-next-line unicorn/prefer-top-level-await 4 | (async () => { 5 | const oclif = await import('@oclif/core') 6 | await oclif.execute({dir: __dirname}) 7 | })() 8 | -------------------------------------------------------------------------------- /eslint.config.mjs: -------------------------------------------------------------------------------- 1 | import { FlatCompat } from "@eslint/eslintrc"; 2 | import { fixupConfigRules } from "@eslint/compat"; 3 | import eslint from '@eslint/js'; 4 | import tseslint from 'typescript-eslint'; 5 | 6 | const compat = new FlatCompat({ 7 | baseDirectory: import.meta.dirname 8 | }); 9 | 10 | export default [ 11 | ...tseslint.config( 12 | eslint.configs.recommended, 13 | ...tseslint.configs.recommendedTypeChecked, 14 | { 15 | languageOptions: { 16 | parserOptions: { 17 | projectService: true, 18 | tsconfigRootDir: import.meta.dirname 19 | } 20 | } 21 | }, 22 | { 23 | rules: { 24 | "@typescript-eslint/no-unused-vars": ["error", { 25 | "argsIgnorePattern": "^_", 26 | "varsIgnorePattern": "^_", 27 | "caughtErrorsIgnorePattern": "^_"}], 28 | "@typescript-eslint/unbound-method": ["error", {"ignoreStatic": true}] 29 | } 30 | } 31 | ), 32 | ...fixupConfigRules(compat.extends("plugin:sf-plugin/recommended")), 33 | { 34 | ignores: ["lib/**", "node_modules/**", "github-actions/**"] 35 | } 36 | ]; 37 | -------------------------------------------------------------------------------- /messages/action-summary-viewer.md: -------------------------------------------------------------------------------- 1 | # common.streaming-logs-to 2 | 3 | Streaming logs in real time to: 4 | 5 | # common.summary-header 6 | 7 | Summary 8 | 9 | # common.logfile-location 10 | 11 | Additional log information written to: 12 | 13 | # config-action.outfile-location 14 | 15 | Configuration written to: 16 | 17 | # rules-action.found-no-rules 18 | 19 | Found 0 rules. 20 | 21 | # rules-action.outfile-location 22 | 23 | Rules written to: 24 | 25 | # rules-action.rules-total 26 | 27 | Found %d rule(s) from %d engine(s): 28 | 29 | # rules-action.rules-item 30 | 31 | %d %s rule(s) found. 32 | 33 | # run-action.found-no-violations 34 | 35 | Found 0 violations. 36 | 37 | # run-action.violations-total 38 | 39 | Found %d violation(s) across %d file(s): 40 | 41 | # run-action.violations-item 42 | 43 | %d %s severity violation(s) found. 44 | 45 | # run-action.outfiles-total 46 | 47 | Results written to: 48 | -------------------------------------------------------------------------------- /messages/config-model.md: -------------------------------------------------------------------------------- 1 | # template.last-calculated-as 2 | Last calculated by the config command as: %s 3 | 4 | # template.modified-from 5 | Modified from: %s 6 | 7 | # template.rule-overrides-section 8 | %s ENGINE RULE OVERRIDES 9 | 10 | # template.yaml.no-rules-selected 11 | Empty object used because rule selection returned no rules 12 | 13 | # template.yaml.no-rule-overrides 14 | Remove this empty object {} when you are ready to specify your first rule override 15 | 16 | # template.common.end-of-config 17 | END OF CODE ANALYZER CONFIGURATION 18 | -------------------------------------------------------------------------------- /messages/config-writer.md: -------------------------------------------------------------------------------- 1 | # error.unrecognized-file-format 2 | 3 | The output file %s has an unsupported extension. Valid extensions include: .yaml/.yml. 4 | 5 | # prompt.overwrite-existing-file 6 | 7 | A file named %s already exists. Do you want to overwrite it? 8 | -------------------------------------------------------------------------------- /messages/progress-event-listener.md: -------------------------------------------------------------------------------- 1 | # selection-spinner.action 2 | Selecting rules 3 | 4 | # selection-spinner.in-progress-status 5 | Eligible engines: %s; Completion: %d%; Elapsed time: %ds 6 | 7 | # selection-spinner.finished-status 8 | done. 9 | 10 | # execution-spinner.action 11 | Executing rules 12 | 13 | # execution-spinner.progress-summary 14 | %d of %d engines finished after %ds. 15 | 16 | # execution-spinner.engine-progress 17 | - %s at %d% completion. 18 | 19 | # execution-spinner.engine-progress-with-message 20 | - %s at %d% completion - %s 21 | 22 | # execution-spinner.finished-status 23 | done. Executed rules from %s. 24 | -------------------------------------------------------------------------------- /messages/results-viewer.md: -------------------------------------------------------------------------------- 1 | # summary.detail.violation-header 2 | 3 | %d. %s 4 | 5 | # summary.shared.results-relative-to 6 | 7 | Violation file paths relative to '%s'. 8 | 9 | # summary.table.found-results 10 | 11 | Found %d violation(s) across %d file(s) relative to '%s': 12 | 13 | # summary.table.num-column 14 | 15 | # 16 | 17 | # summary.table.location-column 18 | 19 | Location 20 | 21 | # summary.table.rule-column 22 | 23 | Rule 24 | 25 | # summary.table.severity-column 26 | 27 | Severity 28 | 29 | # summary.table.message-column 30 | 31 | Message 32 | -------------------------------------------------------------------------------- /messages/results-writer.md: -------------------------------------------------------------------------------- 1 | # error.unrecognized-file-format 2 | 3 | The output file %s has an unsupported extension. Valid extensions include: .csv; .html/.htm; .json; .sarif/.sarif.json; .xml. 4 | -------------------------------------------------------------------------------- /messages/rule-viewer.md: -------------------------------------------------------------------------------- 1 | # summary.detail.header 2 | 3 | %d. %s 4 | 5 | # summary.table.num-column 6 | 7 | # 8 | 9 | # summary.table.name-column 10 | 11 | Name 12 | 13 | # summary.table.engine-column 14 | 15 | Engine 16 | 17 | # summary.table.severity-column 18 | 19 | Severity 20 | 21 | 22 | # summary.table.tag-column 23 | 24 | Tag 25 | -------------------------------------------------------------------------------- /messages/rules-writer.md: -------------------------------------------------------------------------------- 1 | # error.unrecognized-file-format 2 | 3 | The output file %s has an unsupported extension. Valid extension(s): .json. 4 | -------------------------------------------------------------------------------- /messages/run-action.md: -------------------------------------------------------------------------------- 1 | # error.severity-threshold-exceeded 2 | 3 | %d violations met or exceeded the severity threshold of "%s". 4 | -------------------------------------------------------------------------------- /messages/shared.md: -------------------------------------------------------------------------------- 1 | # log.give-us-feedback 2 | 3 | We're continually improving Salesforce Code Analyzer. Tell us what you think! Give feedback at http://sfdc.co/CodeAnalyzerFeedback. 4 | -------------------------------------------------------------------------------- /messages/workspace-util.md: -------------------------------------------------------------------------------- 1 | # error.negative-globs-unsupported 2 | 3 | %s path %s is invalid: Negative globs are unsupported. 4 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@salesforce/plugin-code-analyzer", 3 | "description": "Salesforce Code Analyzer is a unified tool to help Salesforce developers analyze their source code for security vulnerabilities, performance issues, best practices, and more.", 4 | "version": "5.1.0", 5 | "author": "Salesforce Code Analyzer Team", 6 | "bugs": "https://github.com/forcedotcom/code-analyzer/issues", 7 | "dependencies": { 8 | "@oclif/core": "3.27.0", 9 | "@salesforce/code-analyzer-core": "0.30.0", 10 | "@salesforce/code-analyzer-engine-api": "0.25.0", 11 | "@salesforce/code-analyzer-eslint-engine": "0.26.1", 12 | "@salesforce/code-analyzer-flow-engine": "0.23.0", 13 | "@salesforce/code-analyzer-pmd-engine": "0.26.0", 14 | "@salesforce/code-analyzer-regex-engine": "0.23.0", 15 | "@salesforce/code-analyzer-retirejs-engine": "0.23.0", 16 | "@salesforce/code-analyzer-sfge-engine": "0.8.0", 17 | "@salesforce/core": "6.7.6", 18 | "@salesforce/sf-plugins-core": "5.0.13", 19 | "@salesforce/ts-types": "^2.0.12", 20 | "@types/js-yaml": "^4.0.9", 21 | "@types/node": "^22.15.30", 22 | "ansis": "^4.1.0", 23 | "fast-glob": "^3.3.3", 24 | "js-yaml": "^4.1.0", 25 | "ts-node": "^10", 26 | "tslib": "^2" 27 | }, 28 | "devDependencies": { 29 | "@eslint/compat": "^1.2.5", 30 | "@eslint/eslintrc": "^3.2.0", 31 | "@eslint/js": "^9.19.0", 32 | "@oclif/plugin-help": "^6.2.23", 33 | "@salesforce/cli-plugins-testkit": "^5.3.39", 34 | "@types/jest": "^29.5.14", 35 | "@types/tmp": "^0.2.6", 36 | "eslint": "^9.28.0", 37 | "eslint-plugin-sf-plugin": "^1.20.24", 38 | "jest": "^29.7.0", 39 | "jest-junit": "^16.0.0", 40 | "oclif": "^4.18.0", 41 | "tmp": "^0.2.3", 42 | "ts-jest": "^29.2.5", 43 | "typescript": "^5.7.3", 44 | "typescript-eslint": "^8.33.1" 45 | }, 46 | "engines": { 47 | "node": ">=20.0.0" 48 | }, 49 | "files": [ 50 | "/lib", 51 | "/messages", 52 | "/npm-shrinkwrap.json", 53 | "/oclif.manifest.json" 54 | ], 55 | "homepage": "https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/overview", 56 | "keywords": [ 57 | "sfdx-plugin", 58 | "sf-plugin" 59 | ], 60 | "license": "BSD-3-Clause", 61 | "oclif": { 62 | "commands": "./lib/commands", 63 | "bin": "sf", 64 | "topics": { 65 | "code-analyzer": { 66 | "description": "Analyze your code to ensure it adheres to best practices." 67 | } 68 | }, 69 | "devPlugins": [ 70 | "@oclif/plugin-help" 71 | ], 72 | "additionalHelpFlags": [ 73 | "-h" 74 | ], 75 | "topicSeparator": " ", 76 | "flexibleTaxonomy": true 77 | }, 78 | "jest": { 79 | "collectCoverageFrom": [ 80 | "src/**/*.ts", 81 | "!src/index.ts", 82 | "!src/lib/Display.ts" 83 | ], 84 | "coverageReporters": [ 85 | "lcov", 86 | "json", 87 | "text" 88 | ], 89 | "coverageThreshold": { 90 | "global": { 91 | "branches": 80, 92 | "functions": 80, 93 | "lines": 80, 94 | "statements": 80 95 | } 96 | }, 97 | "preset": "ts-jest", 98 | "reporters": [ 99 | "default", 100 | [ 101 | "jest-junit", 102 | { 103 | "outputDirectory": "reports", 104 | "outputName": "report.xml" 105 | } 106 | ], 107 | [ 108 | "github-actions", 109 | { 110 | "silent": false 111 | }, 112 | "summary" 113 | ] 114 | ], 115 | "testEnvironment": "node", 116 | "testMatch": [ 117 | "/test/**/*.test.ts" 118 | ], 119 | "testPathIgnorePatterns": [ 120 | "/node_modules/", 121 | "/lib/", 122 | "/dist/" 123 | ] 124 | }, 125 | "repository": "forcedotcom/code-analyzer", 126 | "scripts": { 127 | "build": "tsc --build tsconfig.build.json", 128 | "prepack": "rm -rf lib && tsc --build tsconfig.build.json && oclif manifest && oclif readme && npm shrinkwrap", 129 | "postpack": "rm -f oclif.manifest.json oclif.lock npm-shrinkwrap.json", 130 | "lint": "eslint ./src --max-warnings 0", 131 | "version": "oclif readme && git add README.md", 132 | "test": "jest --coverage", 133 | "showcoverage": "open ./coverage/lcov-report/index.html" 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /pmd-appexchange/docs/AvoidApiSessionId.md: -------------------------------------------------------------------------------- 1 | AvoidApiSessionId[](#avoidapisessionid) 2 | ------------------------------------------------------------------------------------------------------------------------------------------------------ 3 | 4 | **Violation:** 5 | 6 | Session ID use may not be approved. 7 | 8 | 9 | **Priority:** High (2) 10 | 11 | **Description:** 12 | 13 | Detects use of Api.Session_ID to retrieve a session ID. For more guidance on approved use cases, read the [Session Id Guidance][https://partners.salesforce.com/sfc/servlet.shepherd/version/download/0684V00000O83jT?asPdf=false&operationContext=CHATTER] document. 14 | 15 | **Example(s):** 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /pmd-appexchange/docs/AvoidApiSessionIdInXML.md: -------------------------------------------------------------------------------- 1 | AvoidApiSessionIdInXML[](#avoidapisessionidinxml) 2 | ------------------------------------------------------------------------------------------------------------------------------------------------------ 3 | 4 | **Violation:** 5 | 6 | Session ID use is not approved. 7 | 8 | 9 | **Priority:** High (2) 10 | 11 | **Description:** 12 | 13 | Detects use of Api.Session_ID to retrieve a session ID. For more guidance on approved use cases, read the [Session Id Guidance][https://partners.salesforce.com/sfc/servlet.shepherd/version/download/0684V00000O83jT?asPdf=false&operationContext=CHATTER] document. 14 | 15 | **Example(s):** 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /pmd-appexchange/docs/AvoidAuraAppWithLockerDisabled.md: -------------------------------------------------------------------------------- 1 | AvoidAuraAppWithLockerDisabled[](#avoidauraappwithlockerdisabled) 2 | ------------------------------------------------------------------------------------------------------------------------------------------------------ 3 | 4 | **Violation:** 5 | 6 | To enable Lightning Locker, update the apiVersion to version 40 or greater. 7 | 8 | 9 | **Priority:** Critical (1) 10 | 11 | **Description:** 12 | 13 | Detects use of API versions with Lightning Locker disabled in Aura components. Use API version 40 or greater. 14 | 15 | **Example(s):** 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /pmd-appexchange/docs/AvoidAuraCmpWithLockerDisabled.md: -------------------------------------------------------------------------------- 1 | AvoidAuraCmpWithLockerDisabled[](#avoidauracmpwithlockerdisabled) 2 | ------------------------------------------------------------------------------------------------------------------------------------------------------ 3 | 4 | **Violation:** 5 | 6 | To enable Lightning Locker, update the apiVersion to version 40 or greater. 7 | 8 | 9 | **Priority:** Critical (1) 10 | 11 | **Description:** 12 | 13 | Detects use of API versions with Lightning Locker disabled in Aura components. Use API version 40 or greater. 14 | 15 | **Example(s):** 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /pmd-appexchange/docs/AvoidChangeProtectionUnprotected.md: -------------------------------------------------------------------------------- 1 | AvoidChangeProtectionUnprotected[](#avoidchangeprotectionunprotected) 2 | ------------------------------------------------------------------------------------------------------------------------------------------------------ 3 | 4 | **Violation:** 5 | 6 | Ensure appropriate authorization checks are in-place before invoking FeatureManagement.changeProtection called with 'UnProtected' argument. 7 | 8 | 9 | **Priority:** Critical (1) 10 | 11 | **Description:** 12 | 13 | Detects potential misuse of FeatureManagement.changeProtection. 14 | 15 | **Example(s):** 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /pmd-appexchange/docs/AvoidCreateElementScriptLinkTag.md: -------------------------------------------------------------------------------- 1 | AvoidCreateElementScriptLinkTag[](#avoidcreateelementscriptlinktag) 2 | ------------------------------------------------------------------------------------------------------------------------------------------------------ 3 | 4 | **Violation:** 5 | 6 | Load JavaScript/CSS only from static resources. 7 | 8 | 9 | **Priority:** High (2) 10 | 11 | **Description:** 12 | 13 | Detects dynamic creation of script or link tags 14 | Note: This rule identifies the `