VS Code, Cursor, and Windsurf extension
Vulkro ships two editor extensions built from one shared source tree:
- Vulkro (the core edition) for general-purpose code. In a Salesforce DX
workspace it also starts the
vulkro-sflanguage server as a sidecar. - Vulkro for Salesforce (the Salesforce edition, extension id
vulkro.vulkro-sf) wherevulkro-sf lspis the primary scanner for the whole SFDX project.
Both load in Cursor and Windsurf (VS Code forks) from the same .vsix.
The extension is a thin shell over the language server: it does not
re-implement detection. Findings come from the vulkro-sf engine exactly as
it produces them. The detectors stay closed source; the extension is the UI
surface, not a second implementation.
This page covers the Salesforce side. For the general behaviour shared with the core scanner see the core extension page.
Install
The extension is distributed as a .vsix package today; a Visual Studio
Marketplace listing is coming soon. Install the Salesforce edition with:
code --install-extension vulkro-sf-<version>.vsix
Cursor and Windsurf accept the same file through their own "Install from VSIX" action. The extension requires VS Code 1.101 or later; the newer AI APIs (language-model tools, the MCP provider) are feature-detected at runtime, so a fork that lacks them degrades gracefully instead of failing to activate.
Requirements
- The
vulkro-sfbinary. The extension resolves it in this order: thevulkro-sf.pathsetting, a vendored<workspace>/.vulkro/bin/vulkro-sf, a binary bundled inside a platform-specific.vsix,$PATH, then the managed install at~/.vulkro/bin. If none resolves, the startup error offers an Install action that downloads the release, verifies its.sha256checksum, and installs it into~/.vulkro/bin(no sudo, no PATH changes). The installer honoursHTTPS_PROXY/NO_PROXY, andVULKRO_OFFLINE=1disables it entirely (install manually instead). Prebuilt binaries exist for macOS (arm64, x64), Linux (x64, arm64), and Windows (x64). - The Salesforce Extension Pack (or any extension that contributes the
apexlanguage id). Apex highlighting routes on that language id; without it,.cls/.triggerfiles are still matched by file glob but you lose Apex syntax support.
Which server scans what
The Salesforce edition runs vulkro-sf lsp as its primary and only language
server. Its document selector covers:
- Apex: the
apexlanguage id,*.cls,*.trigger - Visualforce:
*.page,*.component - Aura:
aura/**/*.cmpmarkup plusaura/**/*.jscontrollers - LWC:
lwc/**/*.jsandlwc/**/*.html(scoped to thelwc/folder, so it never claims general JavaScript) - Metadata:
*.flow-meta.xml,*.permissionset-meta.xml,*.profile-meta.xml
In the core edition, opening a workspace with an SFDX marker
(sfdx-project.json, .forceignore, or force-app/main/default) starts a
second client for vulkro-sf lsp alongside the core vulkro lsp server.
There the Salesforce client takes Apex, Visualforce, Aura markup, and the
metadata shapes, while general JavaScript stays with the core server. Apex
is deliberately absent from the core client's selector so a finding is never
published twice, and the two servers tag diagnostics with distinct sources
(vulkro vs vulkro-sf).
Under the hood the two servers keep disjoint advertised command lists:
the vulkro-sf server advertises only its vulkro-sf.* commands, and the
shared editor surface (overview, codemap, impact, AI fix, and so on) is
dispatched over raw workspace/executeCommand under the same vulkro.*
names the core server uses. That is what lets the core edition run both
clients in one editor window without command collisions, and it is why the
Salesforce edition's sidebar views work unchanged: the vulkro-sf server
answers the same requests with the same JSON shapes.
When scans run
- On open: the server publishes a fast single-file first paint, then runs the full project scan and reconciles. Squiggles appear in a fraction of a second; project-wide results follow.
- On save: same pattern - a fast repaint of the saved file, then a project rescan.
- On edit:
textDocument/didChangerepublishes diagnostics from the cached scan (debounced, 300 ms by default, clamped to 50 - 5000 ms via theVULKRO_SF_LSP_DEBOUNCE_MSenvironment variable). Typing does not trigger a rescan; open and save do. - Watch mode (
vulkro-sf.watch, off by default): additionally watches Apex, Visualforce, Aura markup, and flow / permission-set / profile metadata on disk, so the whole DX project rescans as files change, surfacing findings for files you never opened. Toggling the setting restarts the Salesforce server.
Inline findings
Findings render as native diagnostics with the rule message and remediation in the hover and the Problems panel:
- Critical and High render as
Error, Medium asWarning, Low asInformation, Info asHint. Because Critical and High share theErrorcolour, thecriticalandhighdisplay floors behave identically in the editor. - Each diagnostic carries a stable rule code (the kebab-case detector
signal, or a literal id such as
AP-001) that stays the same across scans, plus a clickable link to the rule's documentation. - Findings with a traced taint flow surface the source, steps, and sink as related information, so the full path renders natively in the Problems panel and the peek view.
vulkro-sf.severityThreshold(defaultlow) is a display floor, not a scan setting: the scanner still detects everything, but findings below the floor are hidden from the editor and the sidebar views. With the default,infofindings are hidden.
The sidebar
The Vulkro activity-bar container shows four views by default: Overview,
This File, Issues, and Account. Turning on
vulkro.showAdvancedViews reveals the full set: Org, Changes,
History, Impact, Codemap, Trends, Dependencies,
AI Hunt, Suppressions, and Ask Vulkro. All of them are driven by
the vulkro-sf server in the Salesforce edition.
The views carry actionable empty states: a missing binary offers the managed
install, and a signed-out state offers sign-in. The first sign-in on a
device starts a 14-day trial of the full product; licenses are issued
directly by our team ([email protected]). Air-gapped machines skip sign-in
and activate a machine-bound .lic file instead (the
Activate license file command).
Salesforce commands
Three commands are contributed under the Vulkro for Salesforce prefix (always present in the command palette; outside a running Salesforce server they show an actionable message instead of failing silently):
- Vulkro for Salesforce: Explain finding by rule ID renders the rule's
long-form explainer into the "Vulkro for Salesforce" output channel.
Accepts a Vulkro rule id (
AP-001, an OWASP slug, or anSF-PERM-/SF-FLOW-id). - Vulkro for Salesforce: Suppress finding on this line reads the rule id
from the diagnostic under the cursor (falling back to a prompt), asks the
server for a
// vulkro:disable next-line <RULE>edit, and applies it. The server never edits the file itself; it returns the edit and the client applies it, preserving the read-only-by-design contract. No logic is ever rewritten. - Vulkro for Salesforce: Audit configured target org runs a
permission-posture audit against
vulkro-sf.targetOrg(see below).
The live-org audit
The org-audit command runs entirely through your own authenticated sf
CLI: the extension never implements an OAuth flow, never stores a token,
and never calls a Vulkro server for org data. It resolves the target org
from the vulkro-sf.targetOrg setting (or the VULKRO_SF_LSP_TARGET_ORG
environment variable) and queries that org via sf.
The in-editor audit covers permission sets: over-privilege signals such
as Modify All Data, View All Data, and Author Apex. The broader posture
surface (session settings, MFA, sharing, packages, connected apps, trust
status) is reported by the vulkro-sf org CLI commands on a full audit; see
the sf CLI handoff and
Live-org setup.
The Org sidebar view (behind vulkro.showAdvancedViews) renders the
result of the last explicit audit. It never runs sf behind your back: an
org audit only fires when you invoke it.
If sf is not installed or you are not logged in, the command surfaces an
actionable error (run sf org login web, then retry).
Settings
// .vscode/settings.json (or User Settings)
{
// Path to the vulkro-sf binary. Default: vulkro-sf (resolved as described
// under Requirements).
"vulkro-sf.path": "/usr/local/bin/vulkro-sf",
// Display floor for the Salesforce findings. Default: low (hides info).
// One of: critical, high, medium, low, info.
"vulkro-sf.severityThreshold": "high",
// Watch mode: rescan the whole DX project as files change on disk.
// Default: false.
"vulkro-sf.watch": false,
// Default org alias or username for the org-audit command. Also honoured
// via the VULKRO_SF_LSP_TARGET_ORG environment variable.
"vulkro-sf.targetOrg": "my-scratch-org",
// Local AI model override. Empty = the engine default (qwen2.5-coder:7b).
"vulkro-sf.ai.model": "",
// Local AI endpoint override. Empty = the default local Ollama endpoint
// (http://127.0.0.1:11434/v1).
"vulkro-sf.ai.url": "",
// AI backend: "local" (default, local Ollama, fully offline) or "editor"
// (reuse the editor's own AI model; opt-in, see below).
"vulkro-sf.ai.transport": "local",
// Trace LSP traffic in the "Vulkro for Salesforce" output channel.
"vulkro-sf.trace.server": "off"
}
vulkro-sf.path is independent of the core vulkro.path, so in the core
edition on an SFDX workspace you can point each server at its own build.
Changing any of these restarts the Salesforce language server so the new
value takes effect.
AI in the editor
AI assistance is advisory and local by default: it never changes a deterministic scan result, and the published benchmark is AI-free. The findings, severities, and exit codes are the deterministic engine's alone.
- Set up AI model walks you through selecting a local model served by
Ollama (the engine default is
qwen2.5-coder:7b) and verifies the connection. Test AI connection and Disable AI manage it afterwards. The AI actions on the sidebar views stay hidden until the AI layer reports ready. - Fix issue with AI (review + apply) asks the server for a proposed patch for the finding under the cursor, shows the diff in a review panel, and applies it only when you accept. Each proposal is validated by re-running the deterministic detector on the patched class: a fix is verified when a fresh deterministic re-scan no longer reports the finding and the file still parses (and no new finding appears in the file). Verified means exactly that; it does not claim your build compiles or your tests pass. A patch that fails validation is refused with a reason, never applied.
- Use editor AI model / Use local AI model switch the AI backend. The
editor transport reuses the model your editor already provides (for
example GitHub Copilot) through a loopback shim, so you do not have to
install Ollama. It is opt-in behind an explicit confirmation, because
prompt content (which can include your Apex source and findings) is sent
to whatever provider backs that model, usually a cloud service. It is
refused when
VULKRO_OFFLINE=1is set. The local transport keeps everything on your machine.
Your editor's AI agent can call the scanner
The Salesforce edition also exposes the engine to the editor's AI:
- Two language-model tools are contributed for agent mode:
vulkro_sf_scan_file(scan a Salesforce file and return its findings) andvulkro_sf_explain_finding(explain a rule id). Both are referenceable in prompts. - An MCP server-definition provider registers Vulkro for Salesforce
Security, launching the engine's own
vulkro-sf mcp serve(stdio) withVULKRO_OFFLINE=1set, so the agent's scans never reach the network. The MCP server exposes nine Salesforce tools:sf_scan_project,sf_scan_metadata_only,sf_antipatterns,sf_org_perms,sf_org_effective_perms,sf_org_session,sf_org_mfa,sf_org_health_check, andsf_run_compliance_report. The org tools use your own authenticatedsfCLI, like everything else.
Report export
Vulkro: Export report runs the same whole-project scan CI would
(vulkro-sf scan <root> --format <fmt>) and writes the output to a file you
choose. SARIF 2.1.0 is the portable default (open it in the Microsoft SARIF
Viewer or upload it to code scanning); JSON is the native findings document
for scripts and jq pipelines. A scan that reports findings still produces
a report: only a real scan error aborts the export.
What this isn't (yet)
- Not on the marketplaces yet. The
.vsixinstall above is the distribution channel today; the Marketplace listing is coming soon. - No as-you-type rescans. Edits republish cached results; scans run on open and save (or continuously from disk in watch mode).
- The in-editor org audit is permission sets only. The full posture
surface lives in the
vulkro-sf orgCLI commands. - No org picker. The org command audits the single configured
vulkro-sf.targetOrg.
Where to go next
- Core extension page: the findings panel, status bar, severity filter, and managed install shared with the general scanner.
- The sf CLI handoff: what happens when the org-audit command fires.
- Methodology: the rule taxonomy the inline findings map to.
- CI/CD integration: the matching pre-merge gate.