Anti-patterns report
The output of vulkro-sf antipatterns. Reports findings from the
Salesforce Well-Architected anti-pattern catalog (AP-001 to AP-014).
This is a pattern-quality report, not a security report: the
detectors flag governor-limit risk, recursive triggers, and
maintainability issues, not credentials or injection sinks.
Available formats: text (default, colourized terminal output),
html (self-contained file for hand-off), json (machine-readable
for dashboards), sarif (for code-scanning platforms), and junit
(for CI test-report ingestion).
Per-rule reporting
Each AP-NNN rule contributes its own section to the report. Within a section, findings are grouped by file and sorted by line. Every finding carries the rule ID, the file path, the start and end line range, a one-line description of what was detected, and a remediation hint.
| Rule | What gets reported when the rule fires |
|---|---|
| AP-001 SOQL inside a loop | The SELECT statement's location, the enclosing for / while shape, and the suggestion to hoist the query outside the loop. |
| AP-002 DML inside a loop | The insert / update / delete / upsert location, the enclosing loop, and the suggestion to collect into a list and DML once after the loop. |
| AP-003 Hard-coded record ID | The 15- or 18-character ID literal, the file and line, and the suggestion to move the ID to Custom Metadata or a Custom Setting. |
| AP-004 Trigger without bulk-safety | The handler method, the offending Trigger.new[0] access, and the suggestion to iterate the full collection. |
| AP-005 Recursive trigger | The trigger that performs DML on the same sObject without a static recursion guard, with the suggested guard pattern. |
| AP-006 Empty catch block | The try { ... } catch (...) { } location and a reminder that swallowing every exception masks real failures. |
| AP-007 System.debug in production code | The System.debug call site that is not guarded by Test.isRunningTest(). |
| AP-008 Schema introspection in a loop | The Schema.getGlobalDescribe() or getDescribe() call inside a loop body and the suggestion to cache the result. |
| AP-009 Async chain without governor budgeting | The executeBatch or enqueueJob call inside a batch class without a chain-depth guard. |
| AP-010 Missing sharing keyword | The Apex class declaration that does DML and declares neither with sharing nor inherited sharing nor without sharing. |
| AP-011 Hard-coded URL in Apex | The literal https:// URL in an Apex string and the suggestion to use a Named Credential or Custom Metadata Type. |
| AP-012 Stateless Visualforce controller pattern misuse | The controller that holds large in-memory collections across requests, with a suggestion to use stateless view-state minimisation. |
| AP-013 Aura method exposes system context | The aura:method controller method that does sharing-bypass work without enforcement comments. |
| AP-014 Flow with no fault path | The Flow node that calls a subflow or Apex action without a fault connector. |
Sample output (text)
vulkro-sf antipatterns 0.5.2
project: force-app
scanned: 124 files in 0.8s
AP-001 SOQL inside a loop 2 findings
force-app/main/default/classes/LeadBatch.cls:42:9
Query [SELECT Id, Name FROM Lead WHERE Status = :s] is inside a for-loop body.
Hoist the query outside the loop and bind the per-iteration value with a list.
force-app/main/default/classes/AccountUpdater.cls:117:13
Query [SELECT Id FROM Account WHERE ParentId = :pid] is inside a while-loop body.
Hoist the query outside the loop and bind the per-iteration value with a list.
AP-003 Hard-coded record ID 1 finding
force-app/main/default/classes/RouteRules.cls:23:36
Hard-coded ID "0051Q00000ABC123" found in source.
Move the ID to a Custom Metadata Type or a Custom Setting so the value differs
per org without a code change.
AP-010 Missing sharing keyword 1 finding
force-app/main/default/classes/QuoteService.cls:1:1
Class QuoteService performs DML but does not declare a sharing keyword.
Add 'with sharing' (or 'inherited sharing' for re-entrant utility classes).
Summary: 4 findings across 3 rules, 4 files.
Exit 1.
Sample output (json)
{
"tool": {"name": "vulkro-sf antipatterns", "version": "0.5.2"},
"project": "force-app",
"scanned_at": "2026-05-30T14:33:10Z",
"findings": [
{
"rule_id": "AP-001",
"rule_title": "SOQL inside a loop",
"severity": "medium",
"confidence": "high",
"file": "force-app/main/default/classes/LeadBatch.cls",
"start_line": 42,
"end_line": 42,
"start_column": 9,
"end_column": 64,
"message": "Query [SELECT Id, Name FROM Lead WHERE Status = :s] is inside a for-loop body.",
"remediation": "Hoist the query outside the loop and bind the per-iteration value with a list."
}
],
"summary": {
"total": 4,
"rules_with_findings": 3,
"files_with_findings": 4
}
}
HTML output
The HTML variant is a self-contained file (inlined CSS, no CDN dependencies) with the same per-rule grouping, plus a top-of-page summary strip and a click-to-expand snippet showing the offending source line in context. Use it for hand-off to a non-developer reviewer or to attach to an engagement-close deliverable.
vulkro-sf antipatterns . --format html -o antipatterns.html
Related
- vulkro-sf antipatterns CLI reference - the command that emits this report, flag reference, and the per-rule list with one-line descriptions.
- Well-Architected anti-patterns concept - background on the Salesforce framework these rules are drawn from.
- Output: SARIF - the format reference for
the
--format sarifvariant of this command's output.