Compliance Check

Available in sfp-pro.

The compliance check functionality ensures your Salesforce metadata adheres to organizational standards and best practices. This feature helps maintain code quality, security, and consistency across your Salesforce project by enforcing configurable rules.

Overview

Compliance checking provides a comprehensive framework for:

  • Enforcing coding standards and best practices
  • Preventing security vulnerabilities like hardcoded IDs and URLs
  • Maintaining API version consistency
  • Validating metadata field values against organizational policies
  • Generating detailed violation reports with remediation guidance

How It Works

The compliance checker:

  1. Loads rules from your configuration file (defaults to config/compliance-rules.yaml)
  2. Scans metadata components using Salesforce's ComponentSet API
  3. Applies rules based on metadata type and field specifications
  4. Evaluates content and field values using configurable operators
  5. Reports violations with file locations, severity levels, and helpful messages

Configuration

Compliance checking is configured through YAML files that define rules and their enforcement. The config file is checked in this order:

  1. --compliance-rules <path> CLI flag (absolute or relative path)
  2. config/compliance-rules.yaml relative to the project root
sfp project:analyze --compliance-rules config/compliance-rules.yaml --fail-on compliance

Extending the Built-in Preset

Add extends: default at the top of the file to inherit the built-in rules and layer your own on top. Without extends, only the rules defined in your file are used.

When extending, your rules are merged on top — matching IDs override the preset values. This lets you selectively enable preset rules and add custom ones in the same file.

Configuration File Structure

Create a compliance rules file using the generate command:

sfp project:analyze --generate-compliance-config

This creates config/compliance-rules.yaml with sample rules:

# SFP Compliance Rules Configuration
extends: default
rules:
  - id: no-hardcoded-ids
    enabled: true
    comment: Enable this rule to prevent hardcoded Salesforce IDs
  - id: no-hardcoded-urls
    enabled: false
    comment: Enable this rule to prevent hardcoded Salesforce URLs
  - id: profile-no-modify-all
    enabled: false
    comment: Enable this rule to prevent profiles with Modify All Data permission
  - id: custom-api-version
    name: Minimum API Version Check
    enabled: true
    metadata:
      - ApexClass
      - ApexTrigger
    field: ApexClass.apiVersion
    operator: greater_or_equal
    value: 59.0
    severity: warning
    message: Component should use API version 59.0 or higher

Built-in Rules

The system includes several built-in rules that can be enabled. All are disabled by default and must be explicitly enabled.

Rule IDMetadataFieldOperatorSeverity
no-hardcoded-idsApexClass, ApexTrigger, Flow_contentcontains_salesforce_iderror
no-hardcoded-urlsApexClass, ApexTrigger, Flow_contentregexwarning
profile-no-modify-allProfileuserPermissions.ModifyAllDataequalserror
flow-inactive-checkFlowstatusnot_equalswarning
permissionset-view-all-dataPermissionSetuserPermissions.ViewAllDataequalswarning
permissionset-modify-all-dataPermissionSetuserPermissions.ModifyAllDataequalswarning
permissionset-author-apexPermissionSetuserPermissions.AuthorApexequalswarning
permissionset-customize-applicationPermissionSetuserPermissions.CustomizeApplicationequalswarning

Documentation & Metadata Quality

Rule IDMetadataFieldOperatorSeverity
field-missing-descriptionCustomFielddescriptionis_emptywarning
field-missing-help-textCustomFieldinlineHelpTextis_emptywarning
object-missing-descriptionCustomObjectdescriptionis_emptywarning
validation-rule-missing-descriptionValidationRuledescriptionis_emptywarning

Example: Selective Override of Built-in Preset

# config/compliance-rules.yaml
extends: default

rules:
  # Enable specific preset rules by referencing their IDs
  - id: no-hardcoded-ids
    enabled: true

  - id: profile-no-modify-all
    enabled: true

  # Override the severity of a preset rule
  - id: flow-inactive-check
    enabled: true
    severity: error

  # Add a completely custom rule
  - id: no-test-class-prefix
    name: Test Classes Must Use Correct Prefix
    metadata: ApexClass
    field: _content
    operator: regex
    value: '@isTest'
    severity: warning
    message: Apex test classes should be identifiable

Example: Standalone Rules (No Preset)

# config/compliance-rules.yaml
# No "extends" — only these rules run

rules:
  - id: require-sharing-model
    name: Apex Classes Must Declare Sharing Model
    metadata: ApexClass
    field: _content
    operator: contains
    value: 'with sharing'
    severity: warning
    message: Declare "with sharing" or "without sharing" explicitly

  - id: no-system-runAs-in-prod
    name: System.runAs Not Allowed in Non-Test Code
    metadata: ApexClass
    field: _content
    operator: regex
    value: 'System\.runAs\s*\('
    severity: error
    message: System.runAs is only valid inside @isTest methods

Custom Rules

Define custom rules to match your specific organizational requirements:

rules:
  - id: minimum-api-version
    name: Enforce Minimum API Version
    description: All components must use API version 59.0 or higher
    enabled: true
    metadata:
      - ApexClass
      - ApexTrigger
    field: ApexClass.apiVersion
    operator: greater_or_equal
    value: 59.0
    severity: warning
    message: Component should use API version 59.0 or higher

Rule Configuration Options

FieldDescriptionRequiredValues
idUnique identifier for the ruleYesString
nameHuman-readable rule nameNoString
descriptionDetailed rule descriptionNoString
enabledWhether the rule is activeNotrue/false (default: false)
metadataMetadata types to checkYesArray of metadata type names
fieldField path to evaluateYesDot-notation path or "_content"
operatorComparison operatorYesSee operators table below
valueExpected value for comparisonYesString, Number, Boolean
severityViolation severity levelYeserror, warning, info
messageCustom violation messageNoString
commentInternal team note; not surfaced in outputNoString

Supported Operators

OperatorDescriptionTypical value Type
equalsField value equals value exactlystring, boolean, number
not_equalsField value does not equal valuestring, boolean, number
containsField value contains the substring valuestring
not_containsField value does not contain valuestring
greater_thanField value is numerically greaternumber
less_thanField value is numerically lessnumber
greater_or_equalField value is greater than or equalnumber
less_or_equalField value is less than or equalnumber
regexField value matches the regular expression valuestring (regex pattern)
is_emptyField is absent, null, or empty string— (value ignored)
contains_salesforce_idFile content contains a Salesforce record ID (15 or 18 char) detected via 700+ known key prefixestrue

The field Property

The field property controls what part of a metadata file the rule evaluates:

ValueBehavior
_contentScans the raw text content of the file (works for Apex, Flow, any text format).
statusReads the top-level <status> element from the XML.
userPermissions.ModifyAllDataReads a nested XML path (userPermissionsModifyAllData).
descriptionReads the <description> element.

Dot notation traverses XML element nesting. Arrays are handled automatically — if there are multiple <userPermissions> blocks, each is evaluated independently.

XML Field Paths

For XML metadata files, use dot notation to specify field paths:

# Top-level element
field: status

# Nested XML path
field: userPermissions.ModifyAllData

# For Profile permissions
field: userPermissions.CustomizeApplication

Content Analysis

Use the special _content field to scan raw file text:

field: _content
operator: contains_salesforce_id
value: true
field: _content
operator: regex
value: '(password|secret|key)\s*=\s*["\'][^"\']+["\']'

Understanding Results

The compliance check provides detailed violation reports with multiple output formats:

Console Output

📋 Compliance Check Results
═══════════════════════════

Rules Checked: 3/5

Found 5 violations:

❌ Errors (2):
  • src/classes/MyClass.cls-meta.xml:3
    Component should use API version 59.0 or higher
    Rule: Minimum API Version Check

⚠️  Warnings (3):
  • src/classes/Controller.cls:15
    Hardcoded Salesforce IDs found - use Custom Settings, Custom Metadata, or SOQL queries instead
    Rule: No Hardcoded Salesforce IDs

Violation Details

Each violation includes:

  • File Path: Exact location of the violation
  • Line Number: Specific line where the issue occurs (when applicable)
  • Rule Name: Which rule was violated
  • Severity: Error, Warning, or Info level
  • Message: Descriptive explanation and remediation guidance
  • Actual Value: The found value that triggered the violation
  • Expected Value: What the rule expected to find

Integration with CI/CD

Integration is limited only to GitHub at the moment. The command needs GITHUB_APP_PRIVATE_KEY and GITHUB_APP_ID to be set in environment variables for results to be reported as GitHub checks.

When integrating compliance checking in your CI/CD pipeline:

  1. Enforce Compliance Standards:

    sfp project:analyze --compliance-rules config/compliance-rules.yaml --fail-on compliance
  2. Generate Reports:

    sfp project:analyze --compliance-rules config/compliance-rules.yaml --report-dir ./reports --output-format markdown
  3. GitHub Actions Integration:

    - name: Run Compliance Check
      run: |
        sfp project:analyze --compliance-rules config/compliance-rules.yaml --fail-on compliance --output-format github
      env:
        GITHUB_APP_PRIVATE_KEY: ${{ secrets.GITHUB_APP_PRIVATE_KEY }}
        GITHUB_APP_ID: ${{ secrets.GITHUB_APP_ID }}

Scoping Compliance Checks

Use the same scoping options as other analysis commands:

By Package

sfp project:analyze --compliance-rules config/compliance-rules.yaml -p core,utils

By Domain

sfp project:analyze --compliance-rules config/compliance-rules.yaml -d sales

By Source Path

sfp project:analyze --compliance-rules config/compliance-rules.yaml -s ./force-app/main/default

By Changed Files

Analyze only specific changed files:

# Manual specification of changed files
sfp project:analyze --changed-files "src/classes/MyClass.cls,src/lwc/myComponent/myComponent.html"

In GitHub Actions PR context, the analyzer automatically detects and analyzes only changed files when no package, domain, or source path filters are specified.

Output Formats

The compliance checker supports multiple output formats:

  • Console: Human-readable terminal output with color coding
  • Markdown: Detailed reports suitable for documentation
  • JSON: Machine-readable format for integration with other tools
  • GitHub: Special format for GitHub Checks API integration

Common Compliance Scenarios

API Version Management

Ensure all components use recent API versions:

- id: minimum-api-version
  enabled: true
  metadata: [ApexClass, ApexTrigger]
  field: ApexClass.apiVersion
  operator: greater_or_equal
  value: 59.0
  severity: warning

Security Hardening

Prevent security vulnerabilities:

- id: no-hardcoded-credentials
  enabled: true
  metadata: [ApexClass]
  field: _content
  operator: regex
  value: '(password|secret|key)\s*=\s*["\'][^"\']+["\']'
  severity: error
  message: Remove hardcoded credentials - use Named Credentials or Custom Settings

Profile Security

Restrict dangerous permissions:

- id: no-modify-all-data
  enabled: true
  metadata: [Profile]
  field: Profile.userPermissions.ModifyAllData
  operator: equals
  value: true
  severity: error
  message: Profile should not have Modify All Data permission

Logging and Debugging

Use different log levels to control output verbosity:

# Basic progress information
sfp project:analyze --compliance-rules config/compliance-rules.yaml --loglevel info

# Detailed debugging information
sfp project:analyze --compliance-rules config/compliance-rules.yaml --loglevel debug

Debug logging shows:

  • Rules being processed
  • Files being scanned
  • Field extraction details
  • Rule evaluation results

Troubleshooting

Rule Not Triggering

  1. Verify Field Path: Ensure the field path matches the XML structure
  2. Check Metadata Types: Confirm the rule applies to the correct metadata types
  3. Validate Operators: Ensure the operator logic matches your expectations
  4. Enable Debug Logging: Use --loglevel debug to see detailed evaluation

False Positives

  1. Refine Rule Conditions: Adjust operators or values to be more specific
  2. Scope Rules Appropriately: Use metadata type filters to target specific components
  3. Create Exceptions: Disable rules for specific packages or paths when needed

Performance Issues

  1. Scope Analysis: Use package, domain, or path filters to reduce scope
  2. Optimize Rules: Complex regex patterns can slow down content analysis
  3. Exclude Large Files: Consider excluding generated or vendor files

Configuration Examples

Organization Standards

extends: default
rules:
  # Security Rules
  - id: no-hardcoded-ids
    enabled: true
  - id: no-hardcoded-urls
    enabled: true

  # API Version Standards
  - id: minimum-api-version
    name: Enforce API Version 59+
    enabled: true
    metadata: [ApexClass, ApexTrigger]
    field: ApexClass.apiVersion
    operator: greater_or_equal
    value: 59.0
    severity: warning

  # Profile Security
  - id: profile-no-modify-all
    enabled: true
    severity: error

Documentation Standards

extends: default
rules:
  # Field Documentation
  - id: field-missing-description
    enabled: true
    severity: warning

  - id: field-missing-help-text
    enabled: true
    severity: warning

  # Object Documentation
  - id: object-missing-description
    enabled: true
    severity: warning

  # Validation Rules
  - id: validation-rule-missing-description
    enabled: true
    severity: info
    message: Test classes should follow naming convention with 'Test' suffix

On this page