scc-universal 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/plugin.json +44 -0
- package/.cursor/agents/deep-researcher.md +142 -0
- package/.cursor/agents/doc-updater.md +219 -0
- package/.cursor/agents/eval-runner.md +335 -0
- package/.cursor/agents/learning-engine.md +210 -0
- package/.cursor/agents/loop-operator.md +245 -0
- package/.cursor/agents/refactor-cleaner.md +119 -0
- package/.cursor/agents/sf-admin-agent.md +127 -0
- package/.cursor/agents/sf-agentforce-agent.md +126 -0
- package/.cursor/agents/sf-apex-agent.md +117 -0
- package/.cursor/agents/sf-architect.md +426 -0
- package/.cursor/agents/sf-aura-reviewer.md +369 -0
- package/.cursor/agents/sf-bugfix-agent.md +101 -0
- package/.cursor/agents/sf-flow-agent.md +155 -0
- package/.cursor/agents/sf-integration-agent.md +141 -0
- package/.cursor/agents/sf-lwc-agent.md +123 -0
- package/.cursor/agents/sf-review-agent.md +357 -0
- package/.cursor/agents/sf-visualforce-reviewer.md +465 -0
- package/.cursor/hooks/adapter.js +81 -0
- package/.cursor/hooks/after-file-edit.js +26 -0
- package/.cursor/hooks/after-mcp-execution.js +12 -0
- package/.cursor/hooks/after-shell-execution.js +30 -0
- package/.cursor/hooks/after-tab-file-edit.js +12 -0
- package/.cursor/hooks/before-mcp-execution.js +11 -0
- package/.cursor/hooks/before-read-file.js +13 -0
- package/.cursor/hooks/before-shell-execution.js +29 -0
- package/.cursor/hooks/before-submit-prompt.js +23 -0
- package/.cursor/hooks/pre-compact.js +7 -0
- package/.cursor/hooks/session-end.js +10 -0
- package/.cursor/hooks/session-start.js +10 -0
- package/.cursor/hooks/stop.js +18 -0
- package/.cursor/hooks/subagent-start.js +10 -0
- package/.cursor/hooks/subagent-stop.js +10 -0
- package/.cursor/hooks.json +107 -0
- package/.cursor/skills/aside/SKILL.md +115 -0
- package/.cursor/skills/checkpoint/SKILL.md +50 -0
- package/.cursor/skills/configure-scc/SKILL.md +160 -0
- package/.cursor/skills/continuous-agent-loop/SKILL.md +260 -0
- package/.cursor/skills/mcp-server-patterns/SKILL.md +142 -0
- package/.cursor/skills/model-route/SKILL.md +81 -0
- package/.cursor/skills/prompt-optimizer/SKILL.md +366 -0
- package/.cursor/skills/refactor-clean/SKILL.md +133 -0
- package/.cursor/skills/resume-session/SKILL.md +111 -0
- package/.cursor/skills/save-session/SKILL.md +183 -0
- package/.cursor/skills/search-first/SKILL.md +140 -0
- package/.cursor/skills/security-scan/SKILL.md +142 -0
- package/.cursor/skills/sessions/SKILL.md +124 -0
- package/.cursor/skills/sf-agentforce-development/SKILL.md +449 -0
- package/.cursor/skills/sf-apex-async-patterns/SKILL.md +324 -0
- package/.cursor/skills/sf-apex-best-practices/SKILL.md +421 -0
- package/.cursor/skills/sf-apex-constraints/SKILL.md +79 -0
- package/.cursor/skills/sf-apex-cursor/SKILL.md +336 -0
- package/.cursor/skills/sf-apex-enterprise-patterns/SKILL.md +344 -0
- package/.cursor/skills/sf-apex-testing/SKILL.md +407 -0
- package/.cursor/skills/sf-api-design/SKILL.md +237 -0
- package/.cursor/skills/sf-approval-processes/SKILL.md +312 -0
- package/.cursor/skills/sf-aura-development/SKILL.md +260 -0
- package/.cursor/skills/sf-build-fix/SKILL.md +120 -0
- package/.cursor/skills/sf-data-modeling/SKILL.md +274 -0
- package/.cursor/skills/sf-debugging/SKILL.md +362 -0
- package/.cursor/skills/sf-deployment/SKILL.md +291 -0
- package/.cursor/skills/sf-deployment-constraints/SKILL.md +153 -0
- package/.cursor/skills/sf-devops-ci-cd/SKILL.md +322 -0
- package/.cursor/skills/sf-docs-lookup/SKILL.md +100 -0
- package/.cursor/skills/sf-e2e-testing/SKILL.md +321 -0
- package/.cursor/skills/sf-experience-cloud/SKILL.md +248 -0
- package/.cursor/skills/sf-flow-development/SKILL.md +376 -0
- package/.cursor/skills/sf-governor-limits/SKILL.md +319 -0
- package/.cursor/skills/sf-harness-audit/SKILL.md +139 -0
- package/.cursor/skills/sf-help/SKILL.md +156 -0
- package/.cursor/skills/sf-integration/SKILL.md +479 -0
- package/.cursor/skills/sf-lwc-constraints/SKILL.md +128 -0
- package/.cursor/skills/sf-lwc-development/SKILL.md +302 -0
- package/.cursor/skills/sf-lwc-testing/SKILL.md +387 -0
- package/.cursor/skills/sf-metadata-management/SKILL.md +285 -0
- package/.cursor/skills/sf-platform-events-cdc/SKILL.md +372 -0
- package/.cursor/skills/sf-quickstart/SKILL.md +170 -0
- package/.cursor/skills/sf-security/SKILL.md +330 -0
- package/.cursor/skills/sf-security-constraints/SKILL.md +125 -0
- package/.cursor/skills/sf-soql-constraints/SKILL.md +129 -0
- package/.cursor/skills/sf-soql-optimization/SKILL.md +353 -0
- package/.cursor/skills/sf-tdd-workflow/SKILL.md +332 -0
- package/.cursor/skills/sf-testing-constraints/SKILL.md +198 -0
- package/.cursor/skills/sf-trigger-constraints/SKILL.md +88 -0
- package/.cursor/skills/sf-trigger-frameworks/SKILL.md +343 -0
- package/.cursor/skills/sf-visualforce-development/SKILL.md +259 -0
- package/.cursor/skills/strategic-compact/SKILL.md +205 -0
- package/.cursor/skills/update-docs/SKILL.md +162 -0
- package/.cursor/skills/update-platform-docs/SKILL.md +86 -0
- package/.cursor-plugin/plugin.json +26 -0
- package/LICENSE +21 -0
- package/README.md +522 -0
- package/agents/deep-researcher.md +145 -0
- package/agents/doc-updater.md +222 -0
- package/agents/eval-runner.md +340 -0
- package/agents/learning-engine.md +211 -0
- package/agents/loop-operator.md +247 -0
- package/agents/refactor-cleaner.md +122 -0
- package/agents/sf-admin-agent.md +131 -0
- package/agents/sf-agentforce-agent.md +132 -0
- package/agents/sf-apex-agent.md +124 -0
- package/agents/sf-architect.md +435 -0
- package/agents/sf-aura-reviewer.md +372 -0
- package/agents/sf-bugfix-agent.md +105 -0
- package/agents/sf-flow-agent.md +159 -0
- package/agents/sf-integration-agent.md +146 -0
- package/agents/sf-lwc-agent.md +127 -0
- package/agents/sf-review-agent.md +366 -0
- package/agents/sf-visualforce-reviewer.md +468 -0
- package/assets/logo.svg +18 -0
- package/docs/ARCHITECTURE.md +133 -0
- package/docs/authoring-guide.md +373 -0
- package/docs/hook-development.md +578 -0
- package/docs/token-optimization.md +139 -0
- package/docs/workflow-examples.md +645 -0
- package/examples/agentforce-action/README.md +227 -0
- package/examples/apex-trigger-handler/README.md +114 -0
- package/examples/devops-pipeline/README.md +325 -0
- package/examples/flow-automation/README.md +188 -0
- package/examples/integration-pattern/README.md +416 -0
- package/examples/lwc-component/README.md +180 -0
- package/examples/platform-events/README.md +492 -0
- package/examples/scratch-org-setup/README.md +138 -0
- package/examples/security-audit/README.md +244 -0
- package/examples/visualforce-migration/README.md +314 -0
- package/hooks/hooks.json +338 -0
- package/hooks/memory-persistence/README.md +73 -0
- package/manifests/install-modules.json +217 -0
- package/manifests/install-profiles.json +17 -0
- package/mcp-configs/mcp-servers.json +19 -0
- package/package.json +89 -0
- package/schemas/hooks.schema.json +123 -0
- package/schemas/install-modules.schema.json +76 -0
- package/schemas/install-profiles.schema.json +28 -0
- package/schemas/install-state.schema.json +73 -0
- package/schemas/package-manager.schema.json +18 -0
- package/schemas/plugin.schema.json +112 -0
- package/schemas/scc-install-config.schema.json +29 -0
- package/schemas/state-store.schema.json +111 -0
- package/scripts/cli/install-apply.js +170 -0
- package/scripts/cli/uninstall.js +193 -0
- package/scripts/hooks/check-console-log.js +101 -0
- package/scripts/hooks/check-hook-enabled.js +17 -0
- package/scripts/hooks/check-platform-docs-age.js +48 -0
- package/scripts/hooks/cost-tracker.js +78 -0
- package/scripts/hooks/doc-file-warning.js +63 -0
- package/scripts/hooks/evaluate-session.js +98 -0
- package/scripts/hooks/governor-check.js +220 -0
- package/scripts/hooks/learning-observe.sh +206 -0
- package/scripts/hooks/mcp-health-check.js +588 -0
- package/scripts/hooks/post-bash-build-complete.js +34 -0
- package/scripts/hooks/post-bash-pr-created.js +43 -0
- package/scripts/hooks/post-edit-console-warn.js +61 -0
- package/scripts/hooks/post-edit-format.js +79 -0
- package/scripts/hooks/post-edit-typecheck.js +98 -0
- package/scripts/hooks/post-write.js +168 -0
- package/scripts/hooks/pre-bash-git-push-reminder.js +35 -0
- package/scripts/hooks/pre-bash-tmux-reminder.js +47 -0
- package/scripts/hooks/pre-compact.js +51 -0
- package/scripts/hooks/pre-tool-use.js +163 -0
- package/scripts/hooks/pre-write-doc-warn.js +9 -0
- package/scripts/hooks/quality-gate.js +251 -0
- package/scripts/hooks/run-with-flags-shell.sh +32 -0
- package/scripts/hooks/run-with-flags.js +135 -0
- package/scripts/hooks/session-end-marker.js +29 -0
- package/scripts/hooks/session-end.js +311 -0
- package/scripts/hooks/session-start.js +202 -0
- package/scripts/hooks/sfdx-scanner-check.js +142 -0
- package/scripts/hooks/sfdx-validate.js +119 -0
- package/scripts/hooks/stop-hook.js +170 -0
- package/scripts/hooks/suggest-compact.js +67 -0
- package/scripts/lib/agent-adapter.js +82 -0
- package/scripts/lib/apex-analysis.js +194 -0
- package/scripts/lib/hook-flags.js +74 -0
- package/scripts/lib/install-config.js +73 -0
- package/scripts/lib/install-executor.js +363 -0
- package/scripts/lib/install-state.js +121 -0
- package/scripts/lib/orchestration-session.js +299 -0
- package/scripts/lib/package-manager.js +124 -0
- package/scripts/lib/project-detect.js +228 -0
- package/scripts/lib/schema-validator.js +190 -0
- package/scripts/lib/skill-adapter.js +100 -0
- package/scripts/lib/state-store.js +376 -0
- package/scripts/lib/tmux-worktree-orchestrator.js +598 -0
- package/scripts/lib/utils.js +313 -0
- package/scripts/scc.js +164 -0
- package/skills/_reference/AGENTFORCE_PATTERNS.md +112 -0
- package/skills/_reference/APEX_CURSOR.md +159 -0
- package/skills/_reference/API_VERSIONS.md +78 -0
- package/skills/_reference/APPROVAL_PROCESSES.md +105 -0
- package/skills/_reference/ASYNC_PATTERNS.md +163 -0
- package/skills/_reference/AURA_COMPONENTS.md +146 -0
- package/skills/_reference/DATA_MIGRATION_PATTERNS.md +151 -0
- package/skills/_reference/DATA_MODELING.md +124 -0
- package/skills/_reference/DEBUGGING_TOOLS.md +140 -0
- package/skills/_reference/DEPLOYMENT_CHECKLIST.md +87 -0
- package/skills/_reference/DEPRECATIONS.md +79 -0
- package/skills/_reference/DOCKER_CI_PATTERNS.md +138 -0
- package/skills/_reference/ENTERPRISE_PATTERNS.md +122 -0
- package/skills/_reference/EXPERIENCE_CLOUD.md +143 -0
- package/skills/_reference/FLOW_PATTERNS.md +113 -0
- package/skills/_reference/GOVERNOR_LIMITS.md +77 -0
- package/skills/_reference/INTEGRATION_PATTERNS.md +105 -0
- package/skills/_reference/LWC_PATTERNS.md +79 -0
- package/skills/_reference/METADATA_TYPES.md +115 -0
- package/skills/_reference/NAMING_CONVENTIONS.md +84 -0
- package/skills/_reference/PACKAGE_DEVELOPMENT.md +150 -0
- package/skills/_reference/PLATFORM_EVENTS.md +121 -0
- package/skills/_reference/REPORTING_API.md +143 -0
- package/skills/_reference/SCRATCH_ORG_PATTERNS.md +126 -0
- package/skills/_reference/SECURITY_PATTERNS.md +127 -0
- package/skills/_reference/SHARING_MODEL.md +120 -0
- package/skills/_reference/SOQL_PATTERNS.md +119 -0
- package/skills/_reference/TESTING_STANDARDS.md +96 -0
- package/skills/_reference/TRIGGER_PATTERNS.md +114 -0
- package/skills/_reference/VISUALFORCE_PATTERNS.md +121 -0
- package/skills/aside/SKILL.md +118 -0
- package/skills/checkpoint/SKILL.md +53 -0
- package/skills/configure-scc/SKILL.md +163 -0
- package/skills/continuous-agent-loop/SKILL.md +264 -0
- package/skills/mcp-server-patterns/SKILL.md +146 -0
- package/skills/model-route/SKILL.md +84 -0
- package/skills/prompt-optimizer/SKILL.md +369 -0
- package/skills/refactor-clean/SKILL.md +136 -0
- package/skills/resume-session/SKILL.md +114 -0
- package/skills/save-session/SKILL.md +186 -0
- package/skills/search-first/SKILL.md +144 -0
- package/skills/security-scan/SKILL.md +146 -0
- package/skills/sessions/SKILL.md +127 -0
- package/skills/sf-agentforce-development/SKILL.md +450 -0
- package/skills/sf-apex-async-patterns/SKILL.md +326 -0
- package/skills/sf-apex-best-practices/SKILL.md +425 -0
- package/skills/sf-apex-constraints/SKILL.md +81 -0
- package/skills/sf-apex-cursor/SKILL.md +338 -0
- package/skills/sf-apex-enterprise-patterns/SKILL.md +348 -0
- package/skills/sf-apex-testing/SKILL.md +409 -0
- package/skills/sf-api-design/SKILL.md +238 -0
- package/skills/sf-approval-processes/SKILL.md +315 -0
- package/skills/sf-aura-development/SKILL.md +263 -0
- package/skills/sf-build-fix/SKILL.md +121 -0
- package/skills/sf-data-modeling/SKILL.md +278 -0
- package/skills/sf-debugging/SKILL.md +363 -0
- package/skills/sf-deployment/SKILL.md +295 -0
- package/skills/sf-deployment-constraints/SKILL.md +155 -0
- package/skills/sf-devops-ci-cd/SKILL.md +325 -0
- package/skills/sf-docs-lookup/SKILL.md +103 -0
- package/skills/sf-e2e-testing/SKILL.md +324 -0
- package/skills/sf-experience-cloud/SKILL.md +249 -0
- package/skills/sf-flow-development/SKILL.md +377 -0
- package/skills/sf-governor-limits/SKILL.md +323 -0
- package/skills/sf-harness-audit/SKILL.md +142 -0
- package/skills/sf-help/SKILL.md +159 -0
- package/skills/sf-integration/SKILL.md +483 -0
- package/skills/sf-lwc-constraints/SKILL.md +130 -0
- package/skills/sf-lwc-development/SKILL.md +303 -0
- package/skills/sf-lwc-testing/SKILL.md +388 -0
- package/skills/sf-metadata-management/SKILL.md +288 -0
- package/skills/sf-platform-events-cdc/SKILL.md +375 -0
- package/skills/sf-quickstart/SKILL.md +173 -0
- package/skills/sf-security/SKILL.md +334 -0
- package/skills/sf-security-constraints/SKILL.md +127 -0
- package/skills/sf-soql-constraints/SKILL.md +131 -0
- package/skills/sf-soql-optimization/SKILL.md +354 -0
- package/skills/sf-tdd-workflow/SKILL.md +336 -0
- package/skills/sf-testing-constraints/SKILL.md +200 -0
- package/skills/sf-trigger-constraints/SKILL.md +90 -0
- package/skills/sf-trigger-frameworks/SKILL.md +347 -0
- package/skills/sf-visualforce-development/SKILL.md +260 -0
- package/skills/strategic-compact/SKILL.md +208 -0
- package/skills/update-docs/SKILL.md +165 -0
- package/skills/update-platform-docs/SKILL.md +90 -0
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: sf-quickstart
|
|
3
|
+
description: >-
|
|
4
|
+
Use when setting up SCC on a Salesforce project. Detect Apex, LWC, or mixed
|
|
5
|
+
project type, recommend configuration, install appropriate profile.
|
|
6
|
+
origin: SCC
|
|
7
|
+
user-invocable: true
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# SCC Quickstart — Interactive Onboarding
|
|
11
|
+
|
|
12
|
+
Interactive onboarding for Salesforce Claude Code. Detects your project setup and recommends the right SCC configuration.
|
|
13
|
+
|
|
14
|
+
## When to Use
|
|
15
|
+
|
|
16
|
+
- When setting up SCC for the first time on a Salesforce project
|
|
17
|
+
- When onboarding a new developer to an existing Salesforce org or project
|
|
18
|
+
- When you need to detect the project's tech stack and recommend the right SCC install profile
|
|
19
|
+
- When verifying that SCC is properly installed and configured
|
|
20
|
+
- When switching projects and need to reconfigure SCC for a different project type
|
|
21
|
+
|
|
22
|
+
## Workflow
|
|
23
|
+
|
|
24
|
+
### Step 1 — Detect Project Context
|
|
25
|
+
|
|
26
|
+
Check for Salesforce project markers:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
# Core project file (required for SF project)
|
|
30
|
+
cat sfdx-project.json 2>/dev/null
|
|
31
|
+
|
|
32
|
+
# Scratch org definition
|
|
33
|
+
cat config/project-scratch-def.json 2>/dev/null
|
|
34
|
+
|
|
35
|
+
# Deployment config
|
|
36
|
+
cat .forceignore 2>/dev/null | head -5
|
|
37
|
+
|
|
38
|
+
# Node.js tooling
|
|
39
|
+
cat package.json 2>/dev/null | grep -A5 '"scripts"'
|
|
40
|
+
|
|
41
|
+
# SF CLI version
|
|
42
|
+
sf --version 2>/dev/null
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
If `sfdx-project.json` does not exist, this is not a Salesforce project. Report that and suggest running `/sf-help` for general SCC guidance.
|
|
46
|
+
|
|
47
|
+
### Step 2 — Analyze Tech Stack
|
|
48
|
+
|
|
49
|
+
Scan the project to detect what technologies are in use:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
# Apex classes (not test classes)
|
|
53
|
+
find force-app -name "*.cls" 2>/dev/null | grep -v -E '(Test\.cls$|_Test\.cls$|TestUtils|TestData|TestFactory|TestHelper)' | wc -l
|
|
54
|
+
|
|
55
|
+
# Apex test classes
|
|
56
|
+
find force-app -name "*.cls" 2>/dev/null | grep -E '(Test\.cls$|_Test\.cls$|TestUtils|TestData|TestFactory|TestHelper)' | wc -l
|
|
57
|
+
|
|
58
|
+
# Apex triggers
|
|
59
|
+
find force-app -name "*.trigger" 2>/dev/null | wc -l
|
|
60
|
+
|
|
61
|
+
# LWC components
|
|
62
|
+
find force-app -path "*/lwc/*" -name "*.js" -not -name "*.test.js" 2>/dev/null | wc -l
|
|
63
|
+
|
|
64
|
+
# Aura components
|
|
65
|
+
find force-app -path "*/aura/*" -name "*.cmp" 2>/dev/null | wc -l
|
|
66
|
+
|
|
67
|
+
# Visualforce pages
|
|
68
|
+
find force-app -name "*.page" 2>/dev/null | wc -l
|
|
69
|
+
|
|
70
|
+
# Flows
|
|
71
|
+
find force-app -name "*.flow-meta.xml" 2>/dev/null | wc -l
|
|
72
|
+
|
|
73
|
+
# Custom objects
|
|
74
|
+
find force-app -name "*.object-meta.xml" 2>/dev/null | wc -l
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
> Naive test detection with `find force-app -name "*Test.cls"` misses patterns like `*_Test.cls`, `TestUtils.cls`, `TestDataFactory.cls`, and `TestHelper.cls`. The commands above catch all standard patterns.
|
|
78
|
+
|
|
79
|
+
### Step 3 — Recommend Install Profile
|
|
80
|
+
|
|
81
|
+
Based on detection results, recommend the best SCC profile:
|
|
82
|
+
|
|
83
|
+
| Detected Stack | Recommended Profile | Command |
|
|
84
|
+
|---------------|--------------------|---------|
|
|
85
|
+
| Apex + LWC + Flows + triggers | `all` | `npx scc install all` |
|
|
86
|
+
| Primarily Apex (classes + triggers) | `apex` | `npx scc install apex` |
|
|
87
|
+
| Primarily LWC with some Apex | `lwc` | `npx scc install lwc` |
|
|
88
|
+
|
|
89
|
+
**Profile details:**
|
|
90
|
+
|
|
91
|
+
| Profile | Agents | Skills (user-invocable) | Rules | Hooks |
|
|
92
|
+
|---------|--------|------------------------|-------|-------|
|
|
93
|
+
| `apex` | 12 | 22 (14) | common + apex + soql | all |
|
|
94
|
+
| `lwc` | 10 | 18 (12) | common + lwc | all |
|
|
95
|
+
| `all` | 27 | 45 (26) | all domains | all |
|
|
96
|
+
|
|
97
|
+
### Step 4 — Suggest First Commands
|
|
98
|
+
|
|
99
|
+
Based on the project state, suggest 3-5 commands to start with:
|
|
100
|
+
|
|
101
|
+
| Project State | Suggested Action |
|
|
102
|
+
|--------------|-----------------|
|
|
103
|
+
| No test classes found | `sf-tdd-workflow` skill -- start writing tests |
|
|
104
|
+
| Triggers without handler classes | `sf-trigger-frameworks` skill -- refactor to handler pattern |
|
|
105
|
+
| Low test coverage | `sf-apex-testing` skill -- analyze gaps |
|
|
106
|
+
| Deployment files present | `sf-deployment` skill -- pre-deployment check |
|
|
107
|
+
| Security review needed | `sf-security` skill -- full security audit |
|
|
108
|
+
| Build errors | `/sf-build-fix` -- fix build and deployment errors |
|
|
109
|
+
| Any project | `/sf-help` -- browse all available commands and skills |
|
|
110
|
+
|
|
111
|
+
### Step 5 — Verify SCC Installation
|
|
112
|
+
|
|
113
|
+
Check that SCC is properly configured:
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
# Check hooks are loaded
|
|
117
|
+
test -f .claude/hooks/hooks.json && echo "Hooks: ACTIVE" || echo "Hooks: MISSING (run npx scc install)"
|
|
118
|
+
|
|
119
|
+
# Check hook profile
|
|
120
|
+
echo "Hook Profile: ${SCC_HOOK_PROFILE:-standard (default)}"
|
|
121
|
+
|
|
122
|
+
# Check for governor-check hook
|
|
123
|
+
grep -q "governor-check" .claude/hooks/hooks.json 2>/dev/null && echo "Governor Check: ACTIVE" || echo "Governor Check: MISSING"
|
|
124
|
+
|
|
125
|
+
# Check for quality-gate hook
|
|
126
|
+
grep -q "quality-gate" .claude/hooks/hooks.json 2>/dev/null && echo "Quality Gate: ACTIVE" || echo "Quality Gate: MISSING"
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### Step 6 — Report
|
|
130
|
+
|
|
131
|
+
Present findings in this format:
|
|
132
|
+
|
|
133
|
+
```text
|
|
134
|
+
SCC Quickstart Report
|
|
135
|
+
======================================
|
|
136
|
+
|
|
137
|
+
Project: my-salesforce-app
|
|
138
|
+
SF CLI: @salesforce/cli/2.x.x
|
|
139
|
+
|
|
140
|
+
Tech Stack Detected:
|
|
141
|
+
Apex Classes: 45 (32 test classes)
|
|
142
|
+
Apex Triggers: 8
|
|
143
|
+
LWC Components: 12
|
|
144
|
+
Aura Components: 3 (consider migration)
|
|
145
|
+
Flows: 6
|
|
146
|
+
Custom Objects: 15
|
|
147
|
+
|
|
148
|
+
Recommended Profile: all
|
|
149
|
+
-> npx scc install all
|
|
150
|
+
|
|
151
|
+
SCC Status:
|
|
152
|
+
Hooks: ACTIVE (standard profile)
|
|
153
|
+
Governor Check: ACTIVE
|
|
154
|
+
Quality Gate: ACTIVE
|
|
155
|
+
|
|
156
|
+
Suggested Next Steps:
|
|
157
|
+
1. sf-trigger-frameworks skill -- 3 triggers without handler classes detected
|
|
158
|
+
2. sf-apex-testing skill -- Current coverage unknown, run analysis
|
|
159
|
+
3. sf-security skill -- Verify CRUD/FLS before next deployment
|
|
160
|
+
4. /sf-help -- Browse all available commands and skills
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
## Examples
|
|
164
|
+
|
|
165
|
+
```
|
|
166
|
+
sf-quickstart
|
|
167
|
+
sf-quickstart Set up SCC for my new Salesforce DX project
|
|
168
|
+
sf-quickstart What SCC profile should I use for an ISV package?
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
## Related
|
|
172
|
+
|
|
173
|
+
- **Constraints**: (none -- this is an onboarding workflow)
|
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: sf-security
|
|
3
|
+
description: >-
|
|
4
|
+
Use when implementing Salesforce Apex security — CRUD/FLS enforcement,
|
|
5
|
+
sharing keywords, SOQL injection prevention, AppExchange review prep.
|
|
6
|
+
Do NOT use for general Apex or LWC patterns.
|
|
7
|
+
origin: SCC
|
|
8
|
+
user-invocable: false
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Salesforce Security
|
|
12
|
+
|
|
13
|
+
Salesforce has a layered security model. Each layer must be respected in Apex code, SOQL queries, and UI components.
|
|
14
|
+
|
|
15
|
+
@../_reference/SECURITY_PATTERNS.md
|
|
16
|
+
@../_reference/SHARING_MODEL.md
|
|
17
|
+
|
|
18
|
+
## When to Use
|
|
19
|
+
|
|
20
|
+
- Preparing for a Salesforce security review or ISV managed package submission
|
|
21
|
+
- Apex classes missing `with sharing` or using unexplained `without sharing`
|
|
22
|
+
- SOQL queries using dynamic strings without bind variables
|
|
23
|
+
- CRUD/FLS checks absent from controller or service classes
|
|
24
|
+
- Running a security health check before a major deployment
|
|
25
|
+
- A penetration test or AppExchange security review flags vulnerabilities
|
|
26
|
+
|
|
27
|
+
## CRUD Enforcement in Apex
|
|
28
|
+
|
|
29
|
+
### WITH USER_MODE / AccessLevel.USER_MODE (see @../_reference/API_VERSIONS.md for minimum version)
|
|
30
|
+
|
|
31
|
+
The modern standard for CRUD + FLS enforcement. This replaces explicit CRUD checks and `Security.stripInaccessible` for most use cases.
|
|
32
|
+
|
|
33
|
+
```apex
|
|
34
|
+
// SOQL enforces both object CRUD and FLS for the running user
|
|
35
|
+
List<Account> accounts = [SELECT Id, Name FROM Account WITH USER_MODE];
|
|
36
|
+
|
|
37
|
+
// For DML, use Database methods with AccessLevel
|
|
38
|
+
Database.insert(records, false, AccessLevel.USER_MODE);
|
|
39
|
+
Database.update(records, false, AccessLevel.USER_MODE);
|
|
40
|
+
Database.delete(records, false, AccessLevel.USER_MODE);
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### When to Check CRUD
|
|
44
|
+
|
|
45
|
+
| Context | Check CRUD? |
|
|
46
|
+
|---|---|
|
|
47
|
+
| Apex called from LWC/Aura/VF page | Yes |
|
|
48
|
+
| Service layer called by user-facing code | Yes |
|
|
49
|
+
| Internal utility called by system batch | Usually no — runs in system context |
|
|
50
|
+
| Apex REST/SOAP API endpoint | Yes |
|
|
51
|
+
| Scheduled/Batch internal processing | Usually no — document justification |
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## Field-Level Security (FLS)
|
|
56
|
+
|
|
57
|
+
### Security.stripInaccessible — Bulk FLS Enforcement
|
|
58
|
+
|
|
59
|
+
`stripInaccessible()` silently removes fields the user cannot access. The returned records look normal but stripped fields are `null`. Check `getRemovedFields()` before passing records downstream.
|
|
60
|
+
|
|
61
|
+
```apex
|
|
62
|
+
public List<Account> getAccountsForDisplay() {
|
|
63
|
+
List<Account> accounts = [
|
|
64
|
+
SELECT Id, Name, AnnualRevenue, SSN__c, Internal_Notes__c
|
|
65
|
+
FROM Account WHERE Type = 'Customer'
|
|
66
|
+
];
|
|
67
|
+
|
|
68
|
+
SObjectAccessDecision decision = Security.stripInaccessible(
|
|
69
|
+
AccessType.READABLE, accounts
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
Map<String, Set<String>> removed = decision.getRemovedFields();
|
|
73
|
+
if (removed.containsKey('Account')) {
|
|
74
|
+
System.debug(LoggingLevel.WARN, 'Stripped fields: ' + removed.get('Account'));
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return decision.getRecords();
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### WITH USER_MODE for FLS in SOQL
|
|
82
|
+
|
|
83
|
+
`WITH USER_MODE` throws a `QueryException` if the running user lacks field-level access to any field in the SELECT or WHERE clause. Use `Security.stripInaccessible()` when you need to silently remove inaccessible fields instead of throwing.
|
|
84
|
+
|
|
85
|
+
```apex
|
|
86
|
+
// Defensive approach: check accessibility first
|
|
87
|
+
List<String> selectFields = new List<String>{ 'Id', 'Name' };
|
|
88
|
+
if (Schema.SObjectType.Account.Fields.AnnualRevenue.getDescribe().isAccessible()) {
|
|
89
|
+
selectFields.add('AnnualRevenue');
|
|
90
|
+
}
|
|
91
|
+
// ... build and execute dynamic SOQL with validated fields
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## Sharing Keywords
|
|
97
|
+
|
|
98
|
+
### with sharing (Default)
|
|
99
|
+
|
|
100
|
+
```apex
|
|
101
|
+
public with sharing class AccountsSelector {
|
|
102
|
+
public List<Account> selectAll() {
|
|
103
|
+
return [SELECT Id, Name FROM Account]; // Only returns records user can see
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### without sharing (Use Sparingly)
|
|
109
|
+
|
|
110
|
+
```apex
|
|
111
|
+
/**
|
|
112
|
+
* Batch processor for automated data enrichment.
|
|
113
|
+
* Uses without sharing because:
|
|
114
|
+
* 1. Runs as a system user (scheduled job)
|
|
115
|
+
* 2. Needs to process ALL accounts regardless of ownership
|
|
116
|
+
* 3. Sharing is irrelevant for automated system processing
|
|
117
|
+
*/
|
|
118
|
+
public without sharing class AccountEnrichmentBatch
|
|
119
|
+
implements Database.Batchable<SObject> {
|
|
120
|
+
// ...
|
|
121
|
+
}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### inherited sharing
|
|
125
|
+
|
|
126
|
+
```apex
|
|
127
|
+
// Adopts the sharing mode of the calling class
|
|
128
|
+
public inherited sharing class QueryHelper {
|
|
129
|
+
public List<Account> getAccountsForCaller() {
|
|
130
|
+
return [SELECT Id, Name FROM Account];
|
|
131
|
+
// If called by "with sharing" class: enforces sharing
|
|
132
|
+
// If called by "without sharing" class: bypasses sharing
|
|
133
|
+
// If top-level: defaults to "with sharing"
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### Decision Tree
|
|
139
|
+
|
|
140
|
+
```
|
|
141
|
+
User-facing (LWC, VF, Aura, REST API)? → with sharing
|
|
142
|
+
Utility that respects caller's context? → inherited sharing
|
|
143
|
+
Scheduled/batch as system user? → without sharing (documented)
|
|
144
|
+
Permission elevation utility? → without sharing (narrow scope, documented)
|
|
145
|
+
Unsure? → with sharing
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
> Sharing context does NOT propagate to called classes. A `with sharing` class calling a `without sharing` class runs the called method **without sharing**.
|
|
149
|
+
|
|
150
|
+
---
|
|
151
|
+
|
|
152
|
+
## SOQL Injection Prevention
|
|
153
|
+
|
|
154
|
+
### Static SOQL with Bind Variables (Preferred)
|
|
155
|
+
|
|
156
|
+
```apex
|
|
157
|
+
public List<Account> searchAccounts(String nameFilter) {
|
|
158
|
+
return [SELECT Id, Name FROM Account WHERE Name = :nameFilter WITH USER_MODE];
|
|
159
|
+
}
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### Database.queryWithBinds (For Dynamic SOQL)
|
|
163
|
+
|
|
164
|
+
```apex
|
|
165
|
+
public List<Account> searchAccounts(String nameFilter) {
|
|
166
|
+
Map<String, Object> binds = new Map<String, Object>{
|
|
167
|
+
'nameFilter' => nameFilter
|
|
168
|
+
};
|
|
169
|
+
return Database.queryWithBinds(
|
|
170
|
+
'SELECT Id, Name FROM Account WHERE Name = :nameFilter WITH USER_MODE',
|
|
171
|
+
binds, AccessLevel.USER_MODE
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
### Safe Dynamic SOQL with Whitelist Validation
|
|
177
|
+
|
|
178
|
+
```apex
|
|
179
|
+
public class SafeDynamicQueryBuilder {
|
|
180
|
+
private static final Set<String> ALLOWED_SORT_FIELDS = new Set<String>{
|
|
181
|
+
'Name', 'CreatedDate', 'AnnualRevenue', 'Type'
|
|
182
|
+
};
|
|
183
|
+
private static final Set<String> ALLOWED_DIRECTIONS = new Set<String>{
|
|
184
|
+
'ASC', 'DESC'
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
public List<Account> getAccountsSorted(String sortField, String sortDirection) {
|
|
188
|
+
if (!ALLOWED_SORT_FIELDS.contains(sortField)) {
|
|
189
|
+
sortField = 'Name';
|
|
190
|
+
}
|
|
191
|
+
if (!ALLOWED_DIRECTIONS.contains(sortDirection?.toUpperCase())) {
|
|
192
|
+
sortDirection = 'ASC';
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
String query = 'SELECT Id, Name, AnnualRevenue, Type '
|
|
196
|
+
+ 'FROM Account WITH USER_MODE '
|
|
197
|
+
+ 'ORDER BY ' + sortField + ' ' + sortDirection
|
|
198
|
+
+ ' LIMIT 200';
|
|
199
|
+
return Database.query(query);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
---
|
|
205
|
+
|
|
206
|
+
## XSS Prevention
|
|
207
|
+
|
|
208
|
+
### Visualforce — Use Context-Appropriate Encoding
|
|
209
|
+
|
|
210
|
+
```xml
|
|
211
|
+
<!-- HTML body → HTMLENCODE -->
|
|
212
|
+
<div>{!HTMLENCODE(accountDescription)}</div>
|
|
213
|
+
|
|
214
|
+
<!-- JS string → JSENCODE -->
|
|
215
|
+
<script>var accountName = '{!JSENCODE(account.Name)}';</script>
|
|
216
|
+
|
|
217
|
+
<!-- JS in HTML attribute → JSINHTMLENCODE -->
|
|
218
|
+
<div onclick="handleClick('{!JSINHTMLENCODE(account.Name)}')">Click</div>
|
|
219
|
+
|
|
220
|
+
<!-- URL parameter → URLENCODE -->
|
|
221
|
+
<a href="/mypage?name={!URLENCODE(account.Name)}">View</a>
|
|
222
|
+
|
|
223
|
+
<!-- Safe by default -->
|
|
224
|
+
<apex:outputField value="{!account.Name}" />
|
|
225
|
+
<apex:outputText value="{!account.Description}" escape="true" />
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
### LWC — Safe by Default
|
|
229
|
+
|
|
230
|
+
LWC templates auto-encode HTML. Avoid `innerHTML`:
|
|
231
|
+
|
|
232
|
+
```javascript
|
|
233
|
+
// Safe — LWC encodes the value as text content
|
|
234
|
+
this.accountName = '<script>alert(1)</script>'; // Rendered as literal text
|
|
235
|
+
|
|
236
|
+
// Use textContent, not innerHTML
|
|
237
|
+
this.template.querySelector('.description').textContent = userProvidedContent;
|
|
238
|
+
|
|
239
|
+
// For rich text, use lightning-formatted-rich-text (sanitizes automatically)
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
---
|
|
243
|
+
|
|
244
|
+
## Named Credentials and External Credentials
|
|
245
|
+
|
|
246
|
+
### Secure Callout Pattern
|
|
247
|
+
|
|
248
|
+
```apex
|
|
249
|
+
public class ERPIntegrationService {
|
|
250
|
+
public HttpResponse callERPEndpoint(String path, String method, String body) {
|
|
251
|
+
HttpRequest req = new HttpRequest();
|
|
252
|
+
req.setEndpoint('callout:ERP_System' + path);
|
|
253
|
+
req.setMethod(method);
|
|
254
|
+
req.setHeader('Content-Type', 'application/json');
|
|
255
|
+
if (String.isNotBlank(body)) {
|
|
256
|
+
req.setBody(body);
|
|
257
|
+
}
|
|
258
|
+
return new Http().send(req);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
### What Belongs in Named/External Credentials
|
|
264
|
+
|
|
265
|
+
- OAuth client secrets, API keys, JWT private keys
|
|
266
|
+
- Endpoint URLs (use Named Credentials, not hardcoded strings)
|
|
267
|
+
- Per-user vs Named Principal authentication
|
|
268
|
+
|
|
269
|
+
### Custom Metadata for Configuration
|
|
270
|
+
|
|
271
|
+
```apex
|
|
272
|
+
// No SOQL limits, deployable config
|
|
273
|
+
Map<String, Service_Config__mdt> configs = new Map<String, Service_Config__mdt>();
|
|
274
|
+
for (Service_Config__mdt config : Service_Config__mdt.getAll().values()) {
|
|
275
|
+
configs.put(config.DeveloperName, config);
|
|
276
|
+
}
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
---
|
|
280
|
+
|
|
281
|
+
## Enterprise Security Features
|
|
282
|
+
|
|
283
|
+
### Shield Platform Encryption
|
|
284
|
+
|
|
285
|
+
| Encryption Type | Query Support | Use Case |
|
|
286
|
+
|---|---|---|
|
|
287
|
+
| Deterministic | Exact match only in WHERE | SSN lookup, email search |
|
|
288
|
+
| Probabilistic | No SOQL filtering | Health data, financial records |
|
|
289
|
+
|
|
290
|
+
Encrypted fields cannot be used in ORDER BY, GROUP BY, or LIKE queries (probabilistic). Code must handle null returns when user lacks decryption permission.
|
|
291
|
+
|
|
292
|
+
### Event Monitoring
|
|
293
|
+
|
|
294
|
+
- **Login Events** — detect unauthorized access
|
|
295
|
+
- **API Events** — detect data exfiltration
|
|
296
|
+
- **Report Export Events** — data loss prevention
|
|
297
|
+
|
|
298
|
+
### Transaction Security
|
|
299
|
+
|
|
300
|
+
Real-time threat detection: block large data exports, enforce MFA for sensitive operations, block restricted locations.
|
|
301
|
+
|
|
302
|
+
---
|
|
303
|
+
|
|
304
|
+
## Common Security Review Failures
|
|
305
|
+
|
|
306
|
+
| Failure | Fix |
|
|
307
|
+
|---|---|
|
|
308
|
+
| CRUD not checked before DML | Use `AccessLevel.USER_MODE` |
|
|
309
|
+
| FLS not checked before field access | Use `WITH USER_MODE` or `stripInaccessible` |
|
|
310
|
+
| Dynamic SOQL with string concatenation | Use bind variables or `queryWithBinds()` |
|
|
311
|
+
| `without sharing` on user-facing class | Switch to `with sharing` |
|
|
312
|
+
| Hardcoded credentials | Use Named/External Credentials |
|
|
313
|
+
| Sensitive data in debug logs | Remove `System.debug` of PII |
|
|
314
|
+
| Unrestricted SOQL rows | Add WHERE + LIMIT |
|
|
315
|
+
| innerHTML with user input | Use textContent or sanitized components |
|
|
316
|
+
|
|
317
|
+
---
|
|
318
|
+
|
|
319
|
+
## Security Skills Cross-Reference
|
|
320
|
+
|
|
321
|
+
Security guidance is distributed across multiple skills. Use this index to find the right skill:
|
|
322
|
+
|
|
323
|
+
| Skill | Focus | Type |
|
|
324
|
+
|---|---|---|
|
|
325
|
+
| `sf-security` (this skill) | CRUD/FLS, sharing, injection, Named Credentials, AppExchange prep | Implementation guide |
|
|
326
|
+
| `sf-security-constraints` | Hard never/always rules for security compliance | Constraint (auto-loaded) |
|
|
327
|
+
| `sf-apex-constraints` | Apex-specific security: `with sharing`, bind variables, `without sharing` justification | Constraint (auto-loaded) |
|
|
328
|
+
| `sf-soql-constraints` | SOQL injection prevention, selective queries, bind variables | Constraint (auto-loaded) |
|
|
329
|
+
| `sf-lwc-constraints` | LWC XSS prevention, `lwc:dom="manual"` restrictions, CSP | Constraint (auto-loaded) |
|
|
330
|
+
|
|
331
|
+
## Related
|
|
332
|
+
|
|
333
|
+
- **Agent**: `sf-review-agent` — For interactive, in-depth guidance
|
|
334
|
+
- **Constraints**: `sf-security-constraints` — Hard rules for security compliance
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: sf-security-constraints
|
|
3
|
+
description: "Enforce CRUD/FLS, sharing model, SOQL injection prevention, and XSS protection for Apex and LWC. Use when writing or reviewing ANY Apex, trigger, LWC, or VF page. Do NOT use for Flow-only configuration."
|
|
4
|
+
origin: SCC
|
|
5
|
+
user-invocable: false
|
|
6
|
+
allowed-tools: Read, Grep, Glob
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Security Constraints for Salesforce Code
|
|
10
|
+
|
|
11
|
+
## When to Use
|
|
12
|
+
|
|
13
|
+
This skill auto-activates when writing, reviewing, or modifying any Apex class, trigger, LWC component, or Visualforce page. It enforces CRUD/FLS checks, sharing model compliance, SOQL injection prevention, and XSS protection for all Salesforce code.
|
|
14
|
+
|
|
15
|
+
Hard rules that apply to every Apex class, trigger, LWC component, and Visualforce page. Violating any constraint below is a blocking issue that must be fixed before the code is considered complete.
|
|
16
|
+
|
|
17
|
+
Reference: @../_reference/SECURITY_PATTERNS.md, @../_reference/SHARING_MODEL.md
|
|
18
|
+
@../_reference/DEPRECATIONS.md
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Never Do
|
|
23
|
+
|
|
24
|
+
| # | Constraint | Why |
|
|
25
|
+
|---|---|---|
|
|
26
|
+
| N1 | Skip CRUD/FLS checks on user-facing SOQL or DML | Exposes data the running user should not see or modify |
|
|
27
|
+
| N2 | Use `without sharing` without a written justification comment | Silently bypasses record-level security for every query in the class |
|
|
28
|
+
| N3 | Build SOQL with string concatenation of user input | SOQL injection -- attacker can read or modify arbitrary records |
|
|
29
|
+
| N4 | Trust client-side input without server-side validation | Client payloads are trivially forgeable; all validation must repeat in Apex |
|
|
30
|
+
| N5 | Use `element.innerHTML = userInput` in LWC | Direct XSS vector; LWC auto-encoding is bypassed |
|
|
31
|
+
| N6 | Hardcode API keys, tokens, passwords, or record IDs in Apex | Credentials leak via source control; IDs differ across orgs |
|
|
32
|
+
| N7 | Log sensitive field values with `System.debug` | Debug logs are accessible to admins and can be exported |
|
|
33
|
+
| N8 | Omit the sharing keyword on a class entirely | Defaults to `without sharing` in most contexts -- an implicit security bypass |
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## Always Do
|
|
38
|
+
|
|
39
|
+
| # | Constraint | How |
|
|
40
|
+
|---|---|---|
|
|
41
|
+
| A1 | Enforce CRUD + FLS on user-facing queries | `WITH USER_MODE` in SOQL (see @../_reference/API_VERSIONS.md for minimum version) |
|
|
42
|
+
| A2 | Enforce CRUD + FLS on user-facing DML | `Database.insert(records, false, AccessLevel.USER_MODE)` |
|
|
43
|
+
| A3 | Use `with sharing` as the default class keyword | Switch to `inherited sharing` only for utility/helper classes |
|
|
44
|
+
| A4 | Use bind variables for SOQL filter values | Static SOQL `:bindVar` or `Database.queryWithBinds()` |
|
|
45
|
+
| A5 | Sanitize output in Visualforce | `HTMLENCODE`, `JSENCODE`, `JSINHTMLENCODE`, `URLENCODE` per context |
|
|
46
|
+
| A6 | Use `textContent` or `<lightning-formatted-rich-text>` in LWC | Never assign user-controlled strings to `innerHTML` |
|
|
47
|
+
| A7 | Store credentials in Named Credentials / External Credentials | Use `callout:NamedCredential` prefix in Apex HTTP requests |
|
|
48
|
+
| A8 | Document every `without sharing` usage | Include: why sharing bypass is needed, who approved, date reviewed |
|
|
49
|
+
| A9 | Whitelist-validate dynamic SOQL components | Sort fields, directions, object/field names must match a known-safe set |
|
|
50
|
+
| A10 | Use `Security.stripInaccessible()` when silent field removal is acceptable | Always check `getRemovedFields()` to avoid downstream `NullPointerException` |
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## Sharing Keyword Decision
|
|
55
|
+
|
|
56
|
+
Apply the correct keyword on every class. Reference: @../_reference/SHARING_MODEL.md
|
|
57
|
+
|
|
58
|
+
```
|
|
59
|
+
User-facing code (LWC, VF, Aura, REST API)? --> with sharing
|
|
60
|
+
Utility / helper called from mixed contexts? --> inherited sharing
|
|
61
|
+
Scheduled batch / system-only processing? --> without sharing (document justification)
|
|
62
|
+
Trigger handler? --> with sharing (call without sharing helper only if justified)
|
|
63
|
+
Inner class? --> declare explicitly (does NOT inherit outer class keyword)
|
|
64
|
+
Omitted / unsure? --> with sharing
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Key rule: sharing context does **not** propagate to called classes. A `with sharing` class calling a `without sharing` class runs the called method **without sharing**.
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## Anti-Pattern Table
|
|
72
|
+
|
|
73
|
+
| Anti-Pattern | Security Impact | Correct Pattern |
|
|
74
|
+
|---|---|---|
|
|
75
|
+
| `Database.query('... WHERE Name = \'' + input + '\'')` | SOQL injection -- attacker reads/modifies arbitrary data | `[SELECT ... WHERE Name = :input WITH USER_MODE]` or `Database.queryWithBinds()` |
|
|
76
|
+
| `public class FooController { ... }` (no sharing keyword) | Implicit `without sharing` -- returns all records | `public with sharing class FooController { ... }` |
|
|
77
|
+
| `public without sharing class AccountCtrl` (user-facing) | All records visible regardless of OWD, role hierarchy, sharing rules | `public with sharing class AccountCtrl` |
|
|
78
|
+
| `insert records;` in user-facing code | No CRUD/FLS enforcement | `Database.insert(records, false, AccessLevel.USER_MODE);` |
|
|
79
|
+
| `element.innerHTML = serverData` in LWC | Stored/reflected XSS | `element.textContent = serverData` |
|
|
80
|
+
| `req.setHeader('Authorization', 'Bearer ' + hardcodedToken)` | Credential in source code; leaks via SCM | `callout:Named_Credential` with External Credentials |
|
|
81
|
+
| `{!rawMergeField}` in Visualforce | Reflected XSS | `{!HTMLENCODE(rawMergeField)}` or `<apex:outputText escape="true">` |
|
|
82
|
+
| `System.debug('SSN: ' + contact.SSN__c)` | PII in debug logs | Remove sensitive field logging; use opaque identifiers |
|
|
83
|
+
| `API_Keys__c.getOrgDefaults().Token__c` for auth | Secrets in queryable Custom Setting | External Credentials (see @../_reference/API_VERSIONS.md for minimum version) |
|
|
84
|
+
| SOQL without `LIMIT` in user-facing context | Unbounded query; governor limit risk + data exposure | Add `LIMIT` clause; paginate with `OFFSET` or cursor |
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
## CRUD/FLS Enforcement Quick Reference
|
|
89
|
+
|
|
90
|
+
Reference: @../_reference/SECURITY_PATTERNS.md
|
|
91
|
+
|
|
92
|
+
| Approach | Min API | Enforces | On Violation |
|
|
93
|
+
|---|---|---|---|
|
|
94
|
+
| `WITH USER_MODE` (SOQL) | See @../_reference/API_VERSIONS.md | CRUD + FLS | Throws `QueryException` |
|
|
95
|
+
| `AccessLevel.USER_MODE` (DML) | See @../_reference/API_VERSIONS.md | CRUD + FLS | Throws `DmlException` |
|
|
96
|
+
| `WITH SECURITY_ENFORCED` (SOQL) | See @../_reference/API_VERSIONS.md | CRUD + FLS (reads) | Throws `QueryException` |
|
|
97
|
+
| `Security.stripInaccessible()` | See @../_reference/API_VERSIONS.md | FLS only | Silently strips fields |
|
|
98
|
+
| Manual `isAccessible()` / `isCreateable()` | All | CRUD only | Developer-controlled |
|
|
99
|
+
|
|
100
|
+
Prefer `WITH USER_MODE` / `AccessLevel.USER_MODE` for all new code (see @../_reference/API_VERSIONS.md for minimum version). Fall back to `stripInaccessible` only when silent field removal is the desired behavior.
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
## Visualforce Encoding Quick Reference
|
|
105
|
+
|
|
106
|
+
| Output Context | Encoding Function | Example |
|
|
107
|
+
|---|---|---|
|
|
108
|
+
| HTML body | `HTMLENCODE` | `{!HTMLENCODE(account.Description)}` |
|
|
109
|
+
| HTML attribute | `HTMLENCODE` | `title="{!HTMLENCODE(account.Name)}"` |
|
|
110
|
+
| JavaScript string | `JSENCODE` | `var x = '{!JSENCODE(account.Name)}'` |
|
|
111
|
+
| JS in HTML attribute | `JSINHTMLENCODE` | `onclick="fn('{!JSINHTMLENCODE(val)}')"` |
|
|
112
|
+
| URL parameter | `URLENCODE` | `href="/page?q={!URLENCODE(val)}"` |
|
|
113
|
+
|
|
114
|
+
Use `<apex:outputField>` or `<apex:outputText escape="true">` where possible -- they handle encoding automatically.
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
## Enforcement Priority
|
|
119
|
+
|
|
120
|
+
When reviewing or writing code, check constraints in this order:
|
|
121
|
+
|
|
122
|
+
1. **Sharing keyword** declared on every class (N2, N8, A3)
|
|
123
|
+
2. **CRUD/FLS** enforced on all user-facing SOQL and DML (N1, A1, A2)
|
|
124
|
+
3. **SOQL injection** -- no string concatenation with user input (N3, A4, A9)
|
|
125
|
+
4. **XSS** -- correct encoding in VF; no innerHTML in LWC (N5, A5, A6)
|
|
126
|
+
5. **Credentials** -- no hardcoded secrets; use Named/External Credentials (N6, A7)
|
|
127
|
+
6. **Logging** -- no sensitive data in debug statements (N7)
|