Skip to main content

vulkro scan --include-pmd

Run PMD-for-Apex alongside Vulkro's native Salesforce detectors and merge the findings into the same scan report. Together with the native Apex pass, vulkro scan --include-pmd stands in for the PMD step of sfdx-scanner so a Salesforce project only needs one binary installed in CI.

This page covers what the flag does, how to install the PMD binary, the curated security-only ruleset Vulkro ships, and a CI snippet.

What it does

When --include-pmd is set, after the native scan finishes, Vulkro:

  1. Discovers the pmd binary on this machine. The lookup order is the VULKRO_PMD_BIN env var first, then a PATH search for pmd (or pmd.bat on Windows).

  2. Writes Vulkro's bundled security-only Apex ruleset to a temp file and invokes:

    pmd check -d <project-root> --rulesets <bundled-ruleset.xml> --format json --no-cache
  3. Parses the PMD JSON output and maps each violation to a Vulkro SecurityFinding:

    • PMD priority 1 -> Critical, 2 -> High, 3 -> Medium, 4 -> Low, 5 -> Info.
    • The message starts with PMD-APEX-<rule>: (so SIEM / baseline-diff consumers can group PMD findings).
    • Confidence is Medium by contract (PMD is a separate engine with its own pattern-matching heuristics; Vulkro does not have in-process taint into PMD's verdicts to call them High).
  4. Folds the PMD findings into the same findings array as the native detectors. The dedup pass collapses any (file, line, message) overlap between PMD and a native detector.

If PMD is not available, the flag emits an actionable error message that names the env var, the install link, and continues the scan with the native findings only. The wrapper's failure to find PMD never aborts the rest of the scan.

Install PMD

Vulkro does not ship PMD. The latest PMD release works for Apex; v7 is recommended.

# macOS
brew install pmd

# Linux (manual install)
curl -L -o pmd.zip https://github.com/pmd/pmd/releases/latest/download/pmd-dist-7.x.x-bin.zip
unzip pmd.zip
sudo ln -s "$PWD/pmd-bin-7.x.x/bin/pmd" /usr/local/bin/pmd

# Windows (Chocolatey)
choco install pmd

Confirm:

pmd --version

If pmd is not on PATH (common on Windows or self-managed CI images), point Vulkro at the binary directly:

export VULKRO_PMD_BIN=/opt/pmd/bin/pmd
vulkro scan --include-pmd .

The curated ruleset

The bundled ruleset lives at src/security/wrappers/rulesets/pmd-apex-security.xml. It is loaded at runtime via include_str! so the wrapper never depends on a runtime install layout. The ruleset is security-only by design.

Included

  1. The complete PMD Apex security category (category/apex/security.xml). Every rule. This is the canonical PMD Apex security category and matches what sfdx-scanner runs.

    • ApexBadCrypto
    • ApexCRUDViolation
    • ApexCSRF
    • ApexDangerousMethods
    • ApexInsecureEndpoint
    • ApexOpenRedirect
    • ApexSharingViolations
    • ApexSOQLInjection
    • ApexSuggestUsingNamedCred
    • ApexXSSFromEscapeFalse
    • ApexXSSFromURLParam
  2. A security-relevant subset of the Apex error-prone category (category/apex/errorprone.xml):

    • AvoidDirectAccessTriggerMap
    • AvoidHardcodingId
    • EmptyCatchBlock
    • EmptyIfStmt
    • EmptyStatementBlock
    • EmptyTryOrFinallyBlock
    • EmptyWhileStmt

Excluded by design

CategoryWhy it is out
category/apex/codestyle.xmlFormatting opinions. Not a security review concern.
category/apex/design.xmlCyclomatic complexity, class fan-out, etc. Maintainability, not security.
category/apex/documentation.xmlJavadoc presence checks.
category/apex/performance.xmlSOQL-in-loop and friends. The native Vulkro detectors flag the actually-dangerous shapes; the rest is a perf concern.
category/apex/bestpractices.xmlMixed bag. The rules here that ARE security-relevant are duplicates of category/apex/security.xml entries.

The exclusion list is locked in the ruleset header comment. Changing it requires a deliberate code edit, so the wrapper's "security only" promise stays enforceable.

Severity and confidence mapping

PMD priorityVulkro severity
1Critical
2High
3Medium
4Low
5Info

Every PMD finding lands at Confidence::Medium. The wrapper attaches one evidence row tagged pmd-apex-wrapper so triagers can tell PMD-sourced findings apart from native-detector findings at a glance (the row shows the rule name, the PMD ruleset short label, and the priority that drove the severity).

CI example

A GitHub Actions step that installs PMD, runs Vulkro with the wrapper, and fails the build on Critical or High findings:

name: vulkro
on:
pull_request:
push:
branches: [main]

jobs:
scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Install PMD
run: |
curl -L -o pmd.zip https://github.com/pmd/pmd/releases/latest/download/pmd-dist-7.x.x-bin.zip
unzip -q pmd.zip
echo "VULKRO_PMD_BIN=$PWD/pmd-bin-7.x.x/bin/pmd" >> "$GITHUB_ENV"

- name: Install Vulkro
run: curl -fsSL https://vulkro.com/install.sh | sh

- name: Scan
run: vulkro scan --include-pmd --fail-on critical,high .

The wrapper inherits the rest of the vulkro scan flag set, including --format json, --fail-on <SEVERITIES>, --ratchet, --baseline <PATH>, and --gate-vs <REF>. A PMD-emitted finding is treated the same way as any other Vulkro finding in those flags.

Exit codes

The exit code follows the standard vulkro scan contract (see scan for the full table):

CodeMeaning
0Scan completed, no findings at or above the --fail-on threshold.
1Scan completed, at least one finding at or above the threshold.
2Operational error (bad args, IO failure, internal crash). PMD missing or PMD's own non-zero exit does NOT cause exit 2; the scan continues with the native findings and prints an actionable message on stderr.

Env vars

VariableDefaultEffect
VULKRO_PMD_BINunsetAbsolute path to a pmd binary. When set, the wrapper uses this binary unconditionally instead of searching PATH. The path must point at an existing file.

The standard VULKRO_* env vars honored by vulkro scan apply to this subcommand too.

See also

  • vulkro scan for the full scan reference.
  • vulkro sf-appexchange-report for the AppExchange readiness report; every PMD wrapper finding lands under that report's Code Quality and Best Practices section.
  • The native Vulkro Apex detectors continue to run unchanged whether or not --include-pmd is set; see the Salesforce coverage page for the rule catalog.