agent-docs 1.0.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/.cursor/plans/OPTIMISE.md +379 -0
- package/.cursor/plans/VERSIONING.md +207 -0
- package/.cursor/rules/IMPORTANT.mdc +97 -0
- package/.github/ISSUE_TEMPLATE/bug_report.md +13 -0
- package/.github/ISSUE_TEMPLATE/feature_request.md +17 -0
- package/.github/dependabot.yml +38 -0
- package/.github/pull_request_template.md +10 -0
- package/.github/workflows/format.yml +35 -0
- package/CODE_OF_CONDUCT.md +64 -0
- package/CONTRIBUTING.md +52 -0
- package/LICENSE.md +20 -0
- package/PLAN.md +707 -0
- package/README.md +133 -0
- package/SECURITY.md +21 -0
- package/docs/APEXANNOTATIONS.md +472 -0
- package/docs/APEXDOC.md +198 -0
- package/docs/CML.md +877 -0
- package/docs/CODEANALYZER.md +435 -0
- package/docs/CONTEXTDEFINITIONS.md +617 -0
- package/docs/ESLINT.md +827 -0
- package/docs/ESLINTJSDOC.md +520 -0
- package/docs/FIELDSERVICE.md +4452 -0
- package/docs/GRAPHBINARY.md +208 -0
- package/docs/GRAPHENGINE.md +616 -0
- package/docs/GRAPHML.md +337 -0
- package/docs/GRAPHSON.md +302 -0
- package/docs/GREMLIN.md +490 -0
- package/docs/GRYO.md +232 -0
- package/docs/HUSKY.md +106 -0
- package/docs/JEST.md +387 -0
- package/docs/JORJE.md +537 -0
- package/docs/JSDOC.md +621 -0
- package/docs/PMD.md +910 -0
- package/docs/PNPM.md +409 -0
- package/docs/PRETTIER.md +716 -0
- package/docs/PRETTIERAPEX.md +874 -0
- package/docs/REVENUETRANSACTIONMANAGEMENT.md +887 -0
- package/docs/TINKERPOP.md +252 -0
- package/docs/VITEST.md +706 -0
- package/docs/VSCODE.md +231 -0
- package/docs/XPATH31.md +213 -0
- package/package.json +32 -0
- package/postinstall.mjs +51 -0
- package/prettier.config.js +18 -0
|
@@ -0,0 +1,616 @@
|
|
|
1
|
+
# Salesforce Graph Engine (SFGE) Quick Reference
|
|
2
|
+
|
|
3
|
+
> **Version**: 1.0.0
|
|
4
|
+
|
|
5
|
+
Condensed guide for Salesforce Graph Engine (SFGE) data-flow analysis and rules.
|
|
6
|
+
|
|
7
|
+
**Related Docs:** [CODEANALYZER.md](CODEANALYZER.md), [PMD.md](PMD.md),
|
|
8
|
+
[GREMLIN.md](GREMLIN.md), [TINKERPOP.md](TINKERPOP.md),
|
|
9
|
+
[GRAPHML.md](GRAPHML.md), [GRAPHSON.md](GRAPHSON.md), [GRYO.md](GRYO.md),
|
|
10
|
+
[GRAPHBINARY.md](GRAPHBINARY.md)
|
|
11
|
+
|
|
12
|
+
## Overview
|
|
13
|
+
|
|
14
|
+
Salesforce Graph Engine (SFGE): open-source Salesforce tool performing complex
|
|
15
|
+
analysis on Apex code, identifying security vulnerabilities and code issues.
|
|
16
|
+
Uses data-flow analysis for more complex checks than static-analysis tools.
|
|
17
|
+
**Status:** Developer Preview.
|
|
18
|
+
|
|
19
|
+
**Key Advantage:** SFGE uses data-flow analysis to detect issues requiring
|
|
20
|
+
understanding of how data flows through code paths, not just syntax patterns.
|
|
21
|
+
|
|
22
|
+
**Viewing Available Rules:**
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
scanner run dfa --rule-selector sfge --help
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
For modifying rule settings (severity, tags), see
|
|
29
|
+
[Customize Your Configuration](https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/guide/customize-config.html).
|
|
30
|
+
|
|
31
|
+
## Data-Flow Analysis Process
|
|
32
|
+
|
|
33
|
+
1. **Parse Tree Generation:** Apex Jorje compiler analyzes code and returns
|
|
34
|
+
parse tree
|
|
35
|
+
2. **Graph Construction:** SFGE translates parse tree into vertices and adds
|
|
36
|
+
them to Apache TinkerPop graph database
|
|
37
|
+
3. **Code Path Construction:** SFGE builds code paths starting from each
|
|
38
|
+
identified entry point
|
|
39
|
+
4. **Rule Application:** SFGE walks each code path, applying selected rules at
|
|
40
|
+
every vertex with contextual data. Rules evaluate information and create
|
|
41
|
+
violations if applicable
|
|
42
|
+
|
|
43
|
+
After traversal completes, SFGE returns all collected rule violations.
|
|
44
|
+
|
|
45
|
+
## Key Concepts
|
|
46
|
+
|
|
47
|
+
| Concept | Description |
|
|
48
|
+
| --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
49
|
+
| **Entry Point** | Starting code location of execution path from external interaction (e.g., `@AuraEnabled` methods, `public` Visualforce controller methods). Entry points are evaluated in parallel, and timeout is applied to each entry point separately |
|
|
50
|
+
| **Source** | Code location where data originates. When data is passed into an entry point, the entry point is the source for that data. Data can also be produced or read other than getting passed into the entry point, making it possible for the data source to also be in the middle of a code path |
|
|
51
|
+
| **Sink** | Ending code location where data is consumed or modified (e.g., DML operations, SOQL queries) |
|
|
52
|
+
| **Sanitizer** | Check between source and sink that ensures appropriate actions are taken or inappropriate actions are prevented (e.g., null checks, CRUD/FLS checks) |
|
|
53
|
+
|
|
54
|
+
**Rule Logic:** SFGE verifies that each code path containing a source and a sink
|
|
55
|
+
also includes a sanitizer. Missing sanitizers result in violations.
|
|
56
|
+
|
|
57
|
+
**Path Relationships:** A source can lead to multiple sinks. A sink can be
|
|
58
|
+
reached through multiple sources. There can be multiple paths between the same
|
|
59
|
+
source and sink. SFGE analyzes all possible paths from each entry point.
|
|
60
|
+
|
|
61
|
+
## Configuration
|
|
62
|
+
|
|
63
|
+
Configure SFGE in `code-analyzer.yml`:
|
|
64
|
+
|
|
65
|
+
```yaml
|
|
66
|
+
engines:
|
|
67
|
+
sfge:
|
|
68
|
+
disable_engine: false
|
|
69
|
+
disable_limit_reached_violations: false
|
|
70
|
+
java_command: null
|
|
71
|
+
java_max_heap_size: null
|
|
72
|
+
java_thread_count: 4
|
|
73
|
+
java_thread_timeout: 900000
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### Configuration Properties
|
|
77
|
+
|
|
78
|
+
| Property | Type | Default | Description |
|
|
79
|
+
| ---------------------------------- | ------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
80
|
+
| `disable_engine` | boolean | `false` | Turn off SFGE engine (not included in Code Analyzer commands) |
|
|
81
|
+
| `disable_limit_reached_violations` | boolean | `false` | Prevent LimitReached violations for complex paths. SFGE detects complex paths that might cause OutOfMemory errors and throws LimitReached violations. Disable this check (in addition to increasing `java_max_heap_size`) if needed |
|
|
82
|
+
| `java_command` | string | `null` | Specific `java` command/path for JRE/JDK. Auto-discovered if `null` |
|
|
83
|
+
| `java_max_heap_size` | string | `null` | Maximum Java heap size (bytes). Appended to `-Xmx`. Must be multiple of 1024, >2MB. Use `k`/`K`/`kb`/`KB` (kilobytes), `m`/`M`/`mb`/`MB` (megabytes), `g`/`G`/`gb`/`GB` (gigabytes). Auto: JVM default if `null` |
|
|
84
|
+
| `java_thread_count` | number | `4` | Number of Java threads for parallel execution. Increasing allows more paths evaluated simultaneously |
|
|
85
|
+
| `java_thread_timeout` | number | `900000` | Maximum time (milliseconds) a Java thread may execute before SFGE issues Timeout violation |
|
|
86
|
+
|
|
87
|
+
## Running SFGE Rules
|
|
88
|
+
|
|
89
|
+
Use `--rule-selector sfge` to run SFGE rules:
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
scanner run dfa --rule-selector sfge
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
**Note:** `scanner run dfa` invokes data-flow-based rules in SFGE.
|
|
96
|
+
|
|
97
|
+
**Rule Registration:** Rules register interest in specific types of vertices.
|
|
98
|
+
For example: CRUD/FLS rules express interest in DML operation vertices,
|
|
99
|
+
NullPointerException rules express interest in object dereference vertices,
|
|
100
|
+
Performance rules express interest in loop and database operation vertices.
|
|
101
|
+
Rules evaluate vertices along code paths and create violations when conditions
|
|
102
|
+
are met.
|
|
103
|
+
|
|
104
|
+
## Working with SFGE
|
|
105
|
+
|
|
106
|
+
### Interpreting Results
|
|
107
|
+
|
|
108
|
+
SFGE results include at least two locations: **Entry Point** (where the code
|
|
109
|
+
path starts, first location) and **Sink** (where the violation occurs, last
|
|
110
|
+
location). Review both to understand potential vulnerabilities.
|
|
111
|
+
|
|
112
|
+
**Note:** SFGE uses the same results output schema that other engines use. See
|
|
113
|
+
[Interpret the Run Results](https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/guide/interpret-results.html)
|
|
114
|
+
for information about human-readable output, and the
|
|
115
|
+
[Output Schema Reference](https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/guide/output-schema-reference.html)
|
|
116
|
+
for details about machine-readable outputs.
|
|
117
|
+
|
|
118
|
+
**Flow Scanner vs SFGE Differences:** Flow Scanner engine's code paths start
|
|
119
|
+
from the data source. SFGE's code paths always start from the entry point, which
|
|
120
|
+
aren't always the same as the data source.
|
|
121
|
+
|
|
122
|
+
### Managing False Positives/Negatives
|
|
123
|
+
|
|
124
|
+
SFGE may produce false positives or negatives: **False Negative** (SFGE fails to
|
|
125
|
+
create a violation where the code is insecure), **False Positive** (SFGE creates
|
|
126
|
+
a violation even though the code is secure).
|
|
127
|
+
|
|
128
|
+
If you determine that SFGE created a false positive, add engine directives to
|
|
129
|
+
your code so that SFGE doesn't throw that violation anymore.
|
|
130
|
+
|
|
131
|
+
**Engine Directives (Three Levels):**
|
|
132
|
+
|
|
133
|
+
**1. Disable Next Line:** Disable just the sink from SFGE's analysis. Add
|
|
134
|
+
`disable-next-line` in the line immediately before the sink operation:
|
|
135
|
+
|
|
136
|
+
```apex
|
|
137
|
+
// sfge-disable-next-line RuleName
|
|
138
|
+
List<Account> accounts = [SELECT Id FROM Account];
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
**2. Disable Stack (Method):** Disable all analyses of sink operations in paths
|
|
142
|
+
passing through a method. Add `disable-stack` in the line immediately before the
|
|
143
|
+
method declaration:
|
|
144
|
+
|
|
145
|
+
```apex
|
|
146
|
+
// sfge-disable-stack RuleName
|
|
147
|
+
public void myMethod() {
|
|
148
|
+
List<Account> accounts = [SELECT Id FROM Account];
|
|
149
|
+
}
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
**3. Disable (Class):** Disable all analyses of sink operations that occur in
|
|
153
|
+
the class. Add `disable` in the line immediately before the class declaration:
|
|
154
|
+
|
|
155
|
+
```apex
|
|
156
|
+
// sfge-disable RuleName
|
|
157
|
+
public class MyClass {
|
|
158
|
+
public void myMethod() {
|
|
159
|
+
List<Account> accounts = [SELECT Id FROM Account];
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### Understanding Code Paths
|
|
165
|
+
|
|
166
|
+
Recognize how data flows through code: 1. Identify entry points (external
|
|
167
|
+
interaction points), 2. Trace data from sources to sinks, 3. Verify sanitizers
|
|
168
|
+
exist between source and sink, 4. Review violations to understand missing
|
|
169
|
+
sanitizers.
|
|
170
|
+
|
|
171
|
+
## Writing SFGE-Friendly Code
|
|
172
|
+
|
|
173
|
+
To enhance SFGE performance and reduce analysis time. **Note:** Some suggested
|
|
174
|
+
refactors can conflict with accepted best practices for Apex. Read through the
|
|
175
|
+
options and update your code as appropriate.
|
|
176
|
+
|
|
177
|
+
**Performance Factors:** Two factors directly affect SFGE's performance: 1.
|
|
178
|
+
**Number of entry points analyzed** (entry points are evaluated in parallel, and
|
|
179
|
+
timeout is applied to each entry point separately), 2. **Number of paths each
|
|
180
|
+
entry point constructs** (building paths is the most expensive part of analyzing
|
|
181
|
+
an entry point. Typically, an entry point causes timeouts or memory issues
|
|
182
|
+
because it constructs an inordinate number of paths).
|
|
183
|
+
|
|
184
|
+
**Most Consequential Refactoring:** Decrease the number of paths a single entry
|
|
185
|
+
point constructs or more evenly distribute paths between entry points.
|
|
186
|
+
|
|
187
|
+
### How Paths Are Built
|
|
188
|
+
|
|
189
|
+
When SFGE encounters conditional statements (if, while, etc.) with unknown
|
|
190
|
+
values, paths fork at each conditional. For example:
|
|
191
|
+
|
|
192
|
+
```apex
|
|
193
|
+
public void myMethod(boolean b1, boolean b2) {
|
|
194
|
+
if (b1) { /* path 1 */ }
|
|
195
|
+
if (b2) { /* path 2 */ }
|
|
196
|
+
}
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
If the values of `b1` and `b2` are unknown, SFGE identifies four unique paths
|
|
200
|
+
through the method (2 × 2 = 4). Each conditional causes paths to fork.
|
|
201
|
+
|
|
202
|
+
**Key Principle:** Where possible, SFGE avoids building impossible paths. Paths
|
|
203
|
+
only fork when the outcome is truly indeterminate.
|
|
204
|
+
|
|
205
|
+
### Reduce Entry Points
|
|
206
|
+
|
|
207
|
+
Minimize number of entry points analyzed (each evaluated separately), break down
|
|
208
|
+
complex entry points into multiple simpler ones, distribute paths evenly among
|
|
209
|
+
entry points.
|
|
210
|
+
|
|
211
|
+
**Refactoring Strategy:** If an entry point's complexity causes timeouts or
|
|
212
|
+
memory problems, refactor that entry point into two separate entry points with
|
|
213
|
+
fewer paths. These entry points are analyzed in parallel and have separate
|
|
214
|
+
timeouts, complete faster, and are less likely to exceed time or memory limits.
|
|
215
|
+
|
|
216
|
+
**Example Path Calculation:** Entry point with 3 unknown parameters and 3
|
|
217
|
+
indeterminate if clauses. If each helper method contains 1 unique path: Total =
|
|
218
|
+
1 × 2 × 2 × 2 = 8 paths. If each helper method contains 10 unique paths: Total =
|
|
219
|
+
1 × 20 × 20 × 20 = 8,000 paths.
|
|
220
|
+
|
|
221
|
+
**Refactoring Example:** Split a single entry point into two entry points, each
|
|
222
|
+
passing a literal boolean to avoid forking at one conditional: Original: 8,000
|
|
223
|
+
paths (1 × 20 × 20 × 20), Refactored: 4,000 paths per entry point (1 × 20 × 20 ×
|
|
224
|
+
10), Total: 8,000 paths across 2 entry points (analyzed in parallel).
|
|
225
|
+
|
|
226
|
+
### Limit Code Path Complexity
|
|
227
|
+
|
|
228
|
+
Simplify code paths to prevent excessive branching, refactor complex methods
|
|
229
|
+
into smaller manageable ones, reduce conditional branches to decrease number of
|
|
230
|
+
paths SFGE analyzes, prevent timeouts or memory issues from too many paths.
|
|
231
|
+
|
|
232
|
+
### Best Practices
|
|
233
|
+
|
|
234
|
+
- **Distribute Paths Evenly:** Balance path distribution among entry points
|
|
235
|
+
- **Refactor Complex Methods:** Break down large methods to distribute paths
|
|
236
|
+
- **Simplify Conditionals:** Reduce nested conditionals and branching
|
|
237
|
+
- **Use Literal Values:** Pass literal values to helper methods to avoid path
|
|
238
|
+
forking
|
|
239
|
+
- **Split Entry Points:** Convert single complex entry point into multiple
|
|
240
|
+
simpler entry points
|
|
241
|
+
|
|
242
|
+
## SFGE Rules Reference
|
|
243
|
+
|
|
244
|
+
### ApexFlsViolation
|
|
245
|
+
|
|
246
|
+
Detects Create, Read, Update, Delete (CRUD) and Field-Level Security (FLS)
|
|
247
|
+
violations.
|
|
248
|
+
|
|
249
|
+
**Entry Points:** `@AuraEnabled`, `@InvocableMethod`, `@NamespaceAccessible`,
|
|
250
|
+
`@RemoteAction`-annotated methods, methods returning `PageReference` object,
|
|
251
|
+
`public`-scoped methods on Visualforce Controllers, `global`-scoped methods on
|
|
252
|
+
any class, `Messaging.InboundEmailResult handleInboundEmail()` methods on
|
|
253
|
+
`Messaging.InboundEmailHandler` implementations, any method targeted during
|
|
254
|
+
invocation.
|
|
255
|
+
|
|
256
|
+
**Sinks:** DML operations (`delete`, `insert`, `merge`, `undelete`, `update`,
|
|
257
|
+
`upsert`), `Database.method()` counterparts (`Database.delete()`,
|
|
258
|
+
`Database.insert()`, etc.), SOQL queries (`[SELECT ... FROM ...]`),
|
|
259
|
+
`Database.query()` counterpart.
|
|
260
|
+
|
|
261
|
+
**Sanitizers:** CRUD checks (`Schema.DescribeSObjectResult` access checks,
|
|
262
|
+
acceptable for DELETE, UNDELETE, MERGE operations), FLS checks
|
|
263
|
+
(`Schema.DescribeFieldResult` access checks, acceptable for READ, INSERT,
|
|
264
|
+
UPDATE, UPSERT operations on standard/custom objects),
|
|
265
|
+
`Security.stripInaccessible()` filtered lists, SOQL queries using
|
|
266
|
+
`WITH USER_MODE`, SOQL queries using `WITH SECURITY_ENFORCED`.
|
|
267
|
+
|
|
268
|
+
**Violation Messages:**
|
|
269
|
+
|
|
270
|
+
- `{Validation-Type} validation is missing for {Operation-Name} operation on {Object-Type} with fields {Comma-Separated-Fields}`
|
|
271
|
+
- `{Validation-Type} validation is missing for {Operation-Name} operation on {Object-Type} with fields {Comma-Separated-Fields}–Graph Engine couldn't parse all objects and fields correctly. Manually confirm if the objects and fields involved in these segments have FLS checks: {Unknown-Segments}`
|
|
272
|
+
|
|
273
|
+
**Fields:** `Validation-Type` (CRUD or FLS), `Operation-Name` (data operation
|
|
274
|
+
that must be sanitized), `Object-Type` (object name or variable
|
|
275
|
+
name/`SFGE_Unresolved_Argument` if unknown), `Comma-Separated-Fields` (field
|
|
276
|
+
names or `Unknown` if Graph Engine couldn't determine).
|
|
277
|
+
|
|
278
|
+
### ApexNullPointerException
|
|
279
|
+
|
|
280
|
+
Identifies Apex operations that dereference null objects and throw
|
|
281
|
+
NullPointerExceptions.
|
|
282
|
+
|
|
283
|
+
**Entry Points:** Same as ApexFlsViolation
|
|
284
|
+
|
|
285
|
+
**Sinks:** Any object dereference (e.g., `x.someMethod()`, `x.field`,
|
|
286
|
+
`x[index]`)
|
|
287
|
+
|
|
288
|
+
**Sanitizers:** Non-null initialization (`String s = 'abcde';`), null checks
|
|
289
|
+
before accessing (`if (s != null) { ... }`), checks for specific non-null values
|
|
290
|
+
(`if (x == 7) { ... }`)
|
|
291
|
+
|
|
292
|
+
**Violation Message:**
|
|
293
|
+
`ApexNullPointerException identifies Apex operations with a high likelihood of throwing a NullPointerException`
|
|
294
|
+
|
|
295
|
+
**Fix:** Add null checks before dereferencing, ensure variables are initialized,
|
|
296
|
+
avoid initializing to `null` unless reassigned before use.
|
|
297
|
+
|
|
298
|
+
### AvoidDatabaseOperationInLoop
|
|
299
|
+
|
|
300
|
+
Detects database operations inside loops that cause performance degradation and
|
|
301
|
+
exceed governor limits.
|
|
302
|
+
|
|
303
|
+
**Entry Points:** Same as ApexFlsViolation
|
|
304
|
+
|
|
305
|
+
**Sinks:** DML operations inside loops, SOQL queries inside loops,
|
|
306
|
+
`Database.method()` calls inside loops
|
|
307
|
+
|
|
308
|
+
**Violation Messages:**
|
|
309
|
+
|
|
310
|
+
- `Database operation {Operation} was called inside a loop. [LoopStatement at {Location}]`
|
|
311
|
+
- `SOQL query was called inside a loop. [LoopStatement at {Location}]`
|
|
312
|
+
|
|
313
|
+
**Fix:** Move database operations outside loops, use bulk operations, collect
|
|
314
|
+
data in collections first.
|
|
315
|
+
|
|
316
|
+
### AvoidExpensiveSchemaLookups
|
|
317
|
+
|
|
318
|
+
Detects expensive schema lookups (`Schema.getGlobalDescribe()`,
|
|
319
|
+
`Schema.describeSObjects()`) that cause performance issues.
|
|
320
|
+
|
|
321
|
+
**Entry Points:** Same as ApexFlsViolation
|
|
322
|
+
|
|
323
|
+
**Sinks:** `Schema.getGlobalDescribe()`, `Schema.describeSObjects(...)`
|
|
324
|
+
|
|
325
|
+
**Sanitizers:** None (rule detects expensive operations, not security issues)
|
|
326
|
+
|
|
327
|
+
**Violation Messages:**
|
|
328
|
+
|
|
329
|
+
- `Schema.getGlobalDescribe was called inside a loop. [ForEachStatement at {Location}]`
|
|
330
|
+
- `Multiple expensive schema lookups are invoked. [Schema.describeSObjects at {Location}]`
|
|
331
|
+
- `Schema.getGlobalDescribe executed multiple times in the call stack. [getFields at {Location1}, getFields at {Location2}, ...]`
|
|
332
|
+
|
|
333
|
+
**Fix:** Move schema lookups outside loops, cache results, avoid multiple calls
|
|
334
|
+
in same path.
|
|
335
|
+
|
|
336
|
+
### DatabaseOperationsMustUseWithSharing
|
|
337
|
+
|
|
338
|
+
Identifies database operations in classes annotated as `without sharing` or
|
|
339
|
+
classes that inherit sharing implicitly instead of explicitly using
|
|
340
|
+
`inherited sharing`.
|
|
341
|
+
|
|
342
|
+
**Entry Points:** Same as ApexFlsViolation
|
|
343
|
+
|
|
344
|
+
**Sinks:** Any database operation (DML, SOQL)
|
|
345
|
+
|
|
346
|
+
**Sanitizers:** Class-level `with sharing` annotation, class-level
|
|
347
|
+
`inherited sharing` annotation
|
|
348
|
+
|
|
349
|
+
**Sharing Models:** `with sharing` (database transactions respect sharing rules,
|
|
350
|
+
default recommendation), `without sharing` (database transactions ignore sharing
|
|
351
|
+
rules, use with caution), `inherited sharing` (database transactions inherit
|
|
352
|
+
sharing model of calling class, use for flexibility)
|
|
353
|
+
|
|
354
|
+
**Violation Messages:**
|
|
355
|
+
|
|
356
|
+
- `Database operation must be executed from a class that enforces sharing rules.`
|
|
357
|
+
- `The database operation's class implicitly inherits a sharing model from {Class} {Method}. Explicitly assign a sharing model instead.`
|
|
358
|
+
|
|
359
|
+
**Fix:** Add `with sharing` or `inherited sharing` to class declaration.
|
|
360
|
+
|
|
361
|
+
### MissingNullCheckOnSoqlVariable
|
|
362
|
+
|
|
363
|
+
Identifies SOQL queries with variables in WHERE clauses that lack null checks.
|
|
364
|
+
When variable is null, O(1) operation becomes O(n) (full table scan).
|
|
365
|
+
|
|
366
|
+
**Entry Points:** Same as ApexFlsViolation
|
|
367
|
+
|
|
368
|
+
**Sinks:** SOQL queries with variables in WHERE clauses
|
|
369
|
+
|
|
370
|
+
**Sanitizers:** Null checks (`if (x != null) { ... }`), explicit non-null
|
|
371
|
+
assignment (`String x = 'asdf';`), checks for specific non-null values
|
|
372
|
+
(`if (x == 7) { ... }`)
|
|
373
|
+
|
|
374
|
+
**Violation Message:**
|
|
375
|
+
`Null check is missing for variable {VariableName} used in SOQL query.`
|
|
376
|
+
|
|
377
|
+
**Fix:** Add null check before SOQL query or assign to specific non-null value.
|
|
378
|
+
|
|
379
|
+
### UnimplementedType
|
|
380
|
+
|
|
381
|
+
Detects abstract classes and interfaces that are non-global and missing
|
|
382
|
+
implementations or extensions.
|
|
383
|
+
|
|
384
|
+
**Note:** Traditional static analysis rule (not data-flow based). Violation
|
|
385
|
+
occurs at declaration point.
|
|
386
|
+
|
|
387
|
+
**Violation Message:** `Extend, implement, or delete {Type} {Name}`
|
|
388
|
+
|
|
389
|
+
**Fix:** Implement/extend the type or delete if unnecessary. Rule excludes
|
|
390
|
+
`global` scoped classes to prevent false positives.
|
|
391
|
+
|
|
392
|
+
## Apache TinkerPop Integration
|
|
393
|
+
|
|
394
|
+
SFGE uses Apache TinkerPop graph computing framework to manage and traverse code
|
|
395
|
+
graph representations.
|
|
396
|
+
|
|
397
|
+
**Reference:** See [TINKERPOP.md](TINKERPOP.md) for complete framework
|
|
398
|
+
documentation.
|
|
399
|
+
|
|
400
|
+
### Graph Database Concepts
|
|
401
|
+
|
|
402
|
+
**Property Graph Model:** See [TINKERPOP.md](TINKERPOP.md#property-graph-model)
|
|
403
|
+
for the general Property Graph Model concept.
|
|
404
|
+
|
|
405
|
+
**SFGE-Specific Graph Structure:**
|
|
406
|
+
|
|
407
|
+
- **Vertices:** Code elements (methods, statements, expressions)
|
|
408
|
+
- **Edges:** Relationships (data flow, control flow)
|
|
409
|
+
- **Properties:** Metadata (line numbers, variable names, operation types)
|
|
410
|
+
- **Labels:** Categories ("Method", "DML", "SOQL", "EntryPoint")
|
|
411
|
+
|
|
412
|
+
**Graph Structure in SFGE:** Code is represented as a directed property graph.
|
|
413
|
+
Entry points are starting vertices. Code paths are sequences of connected
|
|
414
|
+
vertices and edges. Rules traverse paths from entry points to sinks. Graph is
|
|
415
|
+
constructed from Apex parse tree.
|
|
416
|
+
|
|
417
|
+
### Gremlin Query Language
|
|
418
|
+
|
|
419
|
+
Gremlin is a functional, data-flow language for graph traversal. SFGE uses
|
|
420
|
+
Gremlin internally for path analysis.
|
|
421
|
+
|
|
422
|
+
**Reference:** See [GREMLIN.md](GREMLIN.md) for complete Gremlin language
|
|
423
|
+
documentation.
|
|
424
|
+
|
|
425
|
+
**Note:** Developers don't need to write Gremlin queries. SFGE handles graph
|
|
426
|
+
construction and traversal internally using TinkerPop. The framework
|
|
427
|
+
automatically generates appropriate Gremlin traversals for path analysis.
|
|
428
|
+
|
|
429
|
+
### Graph Serialization Formats
|
|
430
|
+
|
|
431
|
+
TinkerPop supports multiple formats for graph persistence and exchange. See
|
|
432
|
+
format-specific docs: [GRAPHML.md](GRAPHML.md), [GRAPHSON.md](GRAPHSON.md),
|
|
433
|
+
[GRYO.md](GRYO.md), [GRAPHBINARY.md](GRAPHBINARY.md). For format comparison,
|
|
434
|
+
selection guidance, and general performance/configuration best practices, see
|
|
435
|
+
[TINKERPOP.md](TINKERPOP.md).
|
|
436
|
+
|
|
437
|
+
### Traversal Patterns
|
|
438
|
+
|
|
439
|
+
Common traversal patterns used in graph analysis: **Path Finding** (Shortest
|
|
440
|
+
Path, All Paths, Reachability, Path Length), **Pattern Matching** (Subgraph
|
|
441
|
+
Matching, Pattern Detection, Motif Finding, `match()` Step - declarative pattern
|
|
442
|
+
matching with multiple patterns, patterns defined using `as()` labels, patterns
|
|
443
|
+
matched independently and combined, useful for complex multi-hop queries),
|
|
444
|
+
**Graph Analysis** (Centrality - degree, betweenness, closeness, Community
|
|
445
|
+
Detection, Graph Metrics), **Data Extraction** (Subgraph Extraction, Property
|
|
446
|
+
Aggregation, Relationship Analysis).
|
|
447
|
+
|
|
448
|
+
SFGE uses these patterns internally to analyze code paths and detect violations.
|
|
449
|
+
The framework automatically applies appropriate traversal patterns based on rule
|
|
450
|
+
requirements.
|
|
451
|
+
|
|
452
|
+
## Performance Considerations
|
|
453
|
+
|
|
454
|
+
### Memory Management
|
|
455
|
+
|
|
456
|
+
- Complex paths may cause OutOfMemory errors
|
|
457
|
+
- SFGE dynamically calculates allowed complexity based on `java_max_heap_size`
|
|
458
|
+
- `disable_limit_reached_violations` can disable LimitReached violations if
|
|
459
|
+
needed
|
|
460
|
+
|
|
461
|
+
### Threading
|
|
462
|
+
|
|
463
|
+
- `java_thread_count` controls parallel execution (default: 4)
|
|
464
|
+
- Increasing thread count allows more paths evaluated simultaneously
|
|
465
|
+
- `java_thread_timeout` prevents threads from running indefinitely (default:
|
|
466
|
+
900000ms)
|
|
467
|
+
|
|
468
|
+
### Optimization Tips
|
|
469
|
+
|
|
470
|
+
1. **Reduce Entry Points:** Fewer entry points = less analysis
|
|
471
|
+
2. **Simplify Paths:** Fewer branches = faster analysis
|
|
472
|
+
3. **Increase Heap Size:** For large codebases, increase `java_max_heap_size`
|
|
473
|
+
4. **Adjust Thread Count:** Balance between speed and resource usage
|
|
474
|
+
|
|
475
|
+
## Suppression
|
|
476
|
+
|
|
477
|
+
Suppress SFGE violations using engine directives. See
|
|
478
|
+
[Managing False Positives/Negatives](#managing-false-positivesnegatives) for
|
|
479
|
+
details on the three levels of engine directives.
|
|
480
|
+
|
|
481
|
+
**Note:** Suppression syntax may vary. Check Salesforce Code Analyzer
|
|
482
|
+
documentation for current syntax.
|
|
483
|
+
|
|
484
|
+
## User Action Violations
|
|
485
|
+
|
|
486
|
+
If your SFGE analysis is intentionally blocked, it's because SFGE identified
|
|
487
|
+
something incorrect in your code. You must modify your code to unblock the
|
|
488
|
+
analysis.
|
|
489
|
+
|
|
490
|
+
| Message | Violation | When it Occurs |
|
|
491
|
+
| ------------------------------------------------------------------- | --------------------- | ------------------------------------------------------------------------- |
|
|
492
|
+
| Remove unreachable code to proceed with the analysis. | User Action | Returned one time on an entire analysis. Analysis of all code is blocked. |
|
|
493
|
+
| Rename or delete this reused variable to proceed with the analysis. | User Action Violation | Returned on a single path. Analysis of only that code path is blocked. |
|
|
494
|
+
|
|
495
|
+
**Unreachable Code Example:**
|
|
496
|
+
|
|
497
|
+
```apex
|
|
498
|
+
public void myMethod() {
|
|
499
|
+
throw new Exception('Error');
|
|
500
|
+
return; // Unreachable code
|
|
501
|
+
}
|
|
502
|
+
```
|
|
503
|
+
|
|
504
|
+
SFGE analysis on this code results in the entire analysis being blocked:
|
|
505
|
+
`Remove unreachable code to proceed with the analysis.`
|
|
506
|
+
|
|
507
|
+
**Reused Variable Example:**
|
|
508
|
+
|
|
509
|
+
```apex
|
|
510
|
+
public void myMethod() {
|
|
511
|
+
String input = 'value1';
|
|
512
|
+
// ... some code ...
|
|
513
|
+
String input = 'value2'; // Reused variable
|
|
514
|
+
}
|
|
515
|
+
```
|
|
516
|
+
|
|
517
|
+
SFGE analysis on this code path results in a User Action Violation on this path:
|
|
518
|
+
`Rename or delete this reused variable to proceed with the analysis.`
|
|
519
|
+
|
|
520
|
+
## Limitations
|
|
521
|
+
|
|
522
|
+
1. **Error Logs:** Error logs shown as
|
|
523
|
+
`Internal error. Work in progress. Please ignore` indicate that the entry
|
|
524
|
+
point's analysis didn't complete successfully. This issue is being worked on.
|
|
525
|
+
In the meantime, you must verify the validity of this error manually.
|
|
526
|
+
|
|
527
|
+
2. **Duplicate Class Names:** SFGE handles unique class names. If the source
|
|
528
|
+
code has two distinctly different files that have classes with duplicate
|
|
529
|
+
names, SFGE fails with an error message:
|
|
530
|
+
`<example_class> is defined in multiple files`. In cases like these: Provide
|
|
531
|
+
a `--workspace` subpath to the source directory that has only one of the file
|
|
532
|
+
names, set `--target` to the second file name, rerun the `code-analyzer run`
|
|
533
|
+
command.
|
|
534
|
+
|
|
535
|
+
3. **Anonymous Apex Script:** SFGE doesn't handle anonymous Apex script. Provide
|
|
536
|
+
the class directory path as the `--workspace` that doesn't include any
|
|
537
|
+
anonymous Apex script.
|
|
538
|
+
|
|
539
|
+
4. **Namespace Placeholders:** SFGE doesn't handle namespace placeholders. Leave
|
|
540
|
+
the namespace placeholder blank.
|
|
541
|
+
|
|
542
|
+
5. **Property Chain Depth:** SFGE supports Apex property chains with a depth of
|
|
543
|
+
2 or fewer. For example, SFGE supports `Object.x` but not `Object.x.y`.
|
|
544
|
+
|
|
545
|
+
6. **Apex Triggers:** SFGE doesn't scan Apex triggers.
|
|
546
|
+
|
|
547
|
+
## Apex Security Enforcement Methods
|
|
548
|
+
|
|
549
|
+
### Enforce User Mode for Database Operations
|
|
550
|
+
|
|
551
|
+
Use `WITH USER_MODE` in SOQL queries to enforce field-level security (FLS) and
|
|
552
|
+
sharing rules:
|
|
553
|
+
|
|
554
|
+
```apex
|
|
555
|
+
// Enforces FLS and sharing rules
|
|
556
|
+
List<Account> accounts = [SELECT Id, Name FROM Account WITH USER_MODE];
|
|
557
|
+
```
|
|
558
|
+
|
|
559
|
+
**Benefits:** Automatically enforces FLS checks, respects sharing rules,
|
|
560
|
+
prevents access to fields user cannot read, recognized by SFGE as sanitizer for
|
|
561
|
+
FLS violations.
|
|
562
|
+
|
|
563
|
+
**Usage:** Add `WITH USER_MODE` to SOQL queries. Works with `SELECT`, `UPDATE`,
|
|
564
|
+
`DELETE` statements. Alternative to manual FLS checks.
|
|
565
|
+
|
|
566
|
+
### Security.stripInaccessible Method
|
|
567
|
+
|
|
568
|
+
Use `Security.stripInaccessible()` to remove fields and records the user cannot
|
|
569
|
+
access:
|
|
570
|
+
|
|
571
|
+
```apex
|
|
572
|
+
List<Account> accounts = [SELECT Id, Name, SecretField FROM Account];
|
|
573
|
+
// Remove inaccessible fields
|
|
574
|
+
SObjectAccessDecision decision = Security.stripInaccessible(
|
|
575
|
+
AccessType.READABLE, accounts
|
|
576
|
+
);
|
|
577
|
+
List<Account> safeAccounts = decision.getRecords();
|
|
578
|
+
```
|
|
579
|
+
|
|
580
|
+
**Benefits:** Automatically filters inaccessible fields, returns only accessible
|
|
581
|
+
data, recognized by SFGE as sanitizer for FLS violations.
|
|
582
|
+
|
|
583
|
+
**Access Types:** `AccessType.READABLE` (filter fields user cannot read),
|
|
584
|
+
`AccessType.UPDATABLE` (filter fields user cannot update),
|
|
585
|
+
`AccessType.CREATABLE` (filter fields user cannot create).
|
|
586
|
+
|
|
587
|
+
### Enforcing Object and Field Permissions
|
|
588
|
+
|
|
589
|
+
Use Schema describe methods to check permissions before operations:
|
|
590
|
+
|
|
591
|
+
**Object-Level (CRUD) Checks:**
|
|
592
|
+
|
|
593
|
+
```apex
|
|
594
|
+
Schema.DescribeSObjectResult objDesc = Account.sObjectType.getDescribe();
|
|
595
|
+
if (objDesc.isDeletable()) {
|
|
596
|
+
delete accounts;
|
|
597
|
+
}
|
|
598
|
+
```
|
|
599
|
+
|
|
600
|
+
**Field-Level (FLS) Checks:**
|
|
601
|
+
|
|
602
|
+
```apex
|
|
603
|
+
Schema.DescribeFieldResult fieldDesc = Account.Name.getDescribe();
|
|
604
|
+
if (fieldDesc.isAccessible()) { /* Read field */ }
|
|
605
|
+
if (fieldDesc.isUpdateable()) { /* Update field */ }
|
|
606
|
+
if (fieldDesc.isCreateable()) { /* Create field */ }
|
|
607
|
+
```
|
|
608
|
+
|
|
609
|
+
**Schema Methods:** `isAccessible()` (check if field can be read),
|
|
610
|
+
`isUpdateable()` (check if field can be updated), `isCreateable()` (check if
|
|
611
|
+
field can be created), `isDeletable()` (check if object can be deleted,
|
|
612
|
+
object-level).
|
|
613
|
+
|
|
614
|
+
**SFGE Recognition:** CRUD checks (recognized for DELETE, UNDELETE, MERGE
|
|
615
|
+
operations), FLS checks (recognized for READ, INSERT, UPDATE, UPSERT
|
|
616
|
+
operations), must be performed before the operation (between source and sink).
|