@runhalo/engine 0.4.0 → 0.5.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/dist/ast-engine.d.ts +60 -0
- package/dist/ast-engine.js +653 -0
- package/dist/ast-engine.js.map +1 -0
- package/dist/context-analyzer.d.ts +209 -0
- package/dist/context-analyzer.js +401 -0
- package/dist/context-analyzer.js.map +1 -0
- package/dist/data-flow-tracer.d.ts +106 -0
- package/dist/data-flow-tracer.js +506 -0
- package/dist/data-flow-tracer.js.map +1 -0
- package/dist/frameworks/django.d.ts +11 -0
- package/dist/frameworks/django.js +57 -0
- package/dist/frameworks/django.js.map +1 -0
- package/dist/frameworks/index.d.ts +59 -0
- package/dist/frameworks/index.js +93 -0
- package/dist/frameworks/index.js.map +1 -0
- package/dist/frameworks/nextjs.d.ts +11 -0
- package/dist/frameworks/nextjs.js +59 -0
- package/dist/frameworks/nextjs.js.map +1 -0
- package/dist/frameworks/rails.d.ts +11 -0
- package/dist/frameworks/rails.js +58 -0
- package/dist/frameworks/rails.js.map +1 -0
- package/dist/frameworks/types.d.ts +29 -0
- package/dist/frameworks/types.js +11 -0
- package/dist/frameworks/types.js.map +1 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.js +105 -7
- package/dist/index.js.map +1 -1
- package/dist/scope-analyzer.d.ts +91 -0
- package/dist/scope-analyzer.js +300 -0
- package/dist/scope-analyzer.js.map +1 -0
- package/package.json +6 -2
- package/rules/rules.json +1699 -72
- package/rules/validation-report.json +58 -0
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DataFlowTracer — single-file data-flow analysis using tree-sitter AST.
|
|
3
|
+
*
|
|
4
|
+
* Answers questions like:
|
|
5
|
+
* "Does this value pass through DOMPurify before reaching dangerouslySetInnerHTML?"
|
|
6
|
+
* "Is there a TTL field in this schema?"
|
|
7
|
+
*
|
|
8
|
+
* HARD SCOPE: Single-file only. No cross-file resolution.
|
|
9
|
+
*/
|
|
10
|
+
import Parser from 'tree-sitter';
|
|
11
|
+
export declare class DataFlowTracer {
|
|
12
|
+
private rootNode;
|
|
13
|
+
constructor(tree: Parser.Tree);
|
|
14
|
+
/**
|
|
15
|
+
* Check if a value at `targetLine` (1-indexed) passes through any of the
|
|
16
|
+
* specified functions before being used. Searches backward from targetLine
|
|
17
|
+
* for call expressions whose name matches one of `functionNames`.
|
|
18
|
+
*
|
|
19
|
+
* Example:
|
|
20
|
+
* passesThrough(42, ['DOMPurify.sanitize', 'sanitize', 'xss'])
|
|
21
|
+
* checks if the value used at line 42 was sanitized.
|
|
22
|
+
*/
|
|
23
|
+
passesThrough(targetLine: number, functionNames: string[]): boolean;
|
|
24
|
+
/**
|
|
25
|
+
* Check if any property with the given names exists in the same scope/block
|
|
26
|
+
* as the target line (1-indexed). Used for checking if a Schema has
|
|
27
|
+
* TTL/expires fields.
|
|
28
|
+
*
|
|
29
|
+
* Example:
|
|
30
|
+
* hasPropertyInScope(42, ['TTL', 'expires', 'retention', 'deleted_at'])
|
|
31
|
+
*/
|
|
32
|
+
hasPropertyInScope(targetLine: number, propertyNames: string[]): boolean;
|
|
33
|
+
/**
|
|
34
|
+
* Find all call expressions within `range` lines of `targetLine` (1-indexed).
|
|
35
|
+
* Returns function name and line number (1-indexed).
|
|
36
|
+
*/
|
|
37
|
+
findNearbyCallExpressions(targetLine: number, range: number): Array<{
|
|
38
|
+
name: string;
|
|
39
|
+
line: number;
|
|
40
|
+
}>;
|
|
41
|
+
/**
|
|
42
|
+
* Get the enclosing function/block scope for a given line (1-indexed).
|
|
43
|
+
* Returns the start line (1-indexed), end line (1-indexed), and type of the
|
|
44
|
+
* enclosing scope.
|
|
45
|
+
*/
|
|
46
|
+
getEnclosingScope(line: number): {
|
|
47
|
+
startLine: number;
|
|
48
|
+
endLine: number;
|
|
49
|
+
type: string;
|
|
50
|
+
} | null;
|
|
51
|
+
/**
|
|
52
|
+
* Find all assignments to a variable name within the file.
|
|
53
|
+
* Returns line (1-indexed) and the textual representation of the assigned value.
|
|
54
|
+
*/
|
|
55
|
+
findAssignments(variableName: string): Array<{
|
|
56
|
+
line: number;
|
|
57
|
+
value: string;
|
|
58
|
+
}>;
|
|
59
|
+
/**
|
|
60
|
+
* Check if a specific argument text is present in a function call at a
|
|
61
|
+
* given line (1-indexed).
|
|
62
|
+
*
|
|
63
|
+
* Handles:
|
|
64
|
+
* - Simple string/identifier args: ga('create', 'UA-X', 'auto')
|
|
65
|
+
* - Object literal properties: ga('create', 'UA-X', { child_directed_treatment: true })
|
|
66
|
+
* - new_expression args: new Analytics({ child_directed_treatment: true })
|
|
67
|
+
* - Nested object properties at any depth
|
|
68
|
+
*
|
|
69
|
+
* Example:
|
|
70
|
+
* hasArgument(42, 'child_directed_treatment')
|
|
71
|
+
*/
|
|
72
|
+
hasArgument(callLine: number, argumentText: string): boolean;
|
|
73
|
+
/**
|
|
74
|
+
* Check if a variable/constant with a matching name exists in the same
|
|
75
|
+
* block scope as the target line (1-indexed).
|
|
76
|
+
*
|
|
77
|
+
* Searches for: variable declarations, const declarations, let declarations,
|
|
78
|
+
* parameter names, and property assignments.
|
|
79
|
+
*
|
|
80
|
+
* This catches cases like:
|
|
81
|
+
* - parent_email declared alongside child_email → suppresses coppa-flow-009
|
|
82
|
+
* - MAX_PAGES constant near IntersectionObserver → suppresses ETHICAL-001
|
|
83
|
+
*/
|
|
84
|
+
hasVariableInScope(targetLine: number, variableNames: string[]): boolean;
|
|
85
|
+
/**
|
|
86
|
+
* Find the enclosing function-level scope for a 0-indexed line.
|
|
87
|
+
* Used by the public getEnclosingScope() API — returns function/class/program scopes.
|
|
88
|
+
*/
|
|
89
|
+
private findEnclosingFunctionScope;
|
|
90
|
+
/**
|
|
91
|
+
* Find the enclosing scope node for a 0-indexed line (including block scopes).
|
|
92
|
+
* Used internally by hasPropertyInScope and hasVariableInScope for fine-grained
|
|
93
|
+
* variable/property resolution that respects block scoping.
|
|
94
|
+
*/
|
|
95
|
+
private findEnclosingScopeNode;
|
|
96
|
+
/**
|
|
97
|
+
* Find the nearest block scope containing the given line (0-indexed).
|
|
98
|
+
* Falls back to the enclosing function/program scope.
|
|
99
|
+
* Used for variable declaration detection — checks both block and function scope.
|
|
100
|
+
*/
|
|
101
|
+
private findNearestBlockOrScope;
|
|
102
|
+
/**
|
|
103
|
+
* Get the source text of a 0-indexed line by slicing the root node's text.
|
|
104
|
+
*/
|
|
105
|
+
private getLineText;
|
|
106
|
+
}
|
|
@@ -0,0 +1,506 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* DataFlowTracer — single-file data-flow analysis using tree-sitter AST.
|
|
4
|
+
*
|
|
5
|
+
* Answers questions like:
|
|
6
|
+
* "Does this value pass through DOMPurify before reaching dangerouslySetInnerHTML?"
|
|
7
|
+
* "Is there a TTL field in this schema?"
|
|
8
|
+
*
|
|
9
|
+
* HARD SCOPE: Single-file only. No cross-file resolution.
|
|
10
|
+
*/
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.DataFlowTracer = void 0;
|
|
13
|
+
// ---------------------------------------------------------------------------
|
|
14
|
+
// Helpers
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
/**
|
|
17
|
+
* Recursively walk every node in a subtree, calling `visitor` on each one.
|
|
18
|
+
*/
|
|
19
|
+
function walk(node, visitor) {
|
|
20
|
+
if (!node || typeof node.type !== 'string')
|
|
21
|
+
return;
|
|
22
|
+
visitor(node);
|
|
23
|
+
const count = node.childCount || 0;
|
|
24
|
+
for (let i = 0; i < count; i++) {
|
|
25
|
+
walk(node.child(i), visitor);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Resolve the full text of a call expression's function name.
|
|
30
|
+
* Handles both simple identifiers (`sanitize`) and member expressions
|
|
31
|
+
* (`DOMPurify.sanitize`, `a.b.c`).
|
|
32
|
+
*/
|
|
33
|
+
function resolveCallName(callNode) {
|
|
34
|
+
const func = callNode.childForFieldName('function');
|
|
35
|
+
if (!func)
|
|
36
|
+
return null;
|
|
37
|
+
if (func.type === 'identifier') {
|
|
38
|
+
return func.text;
|
|
39
|
+
}
|
|
40
|
+
if (func.type === 'member_expression') {
|
|
41
|
+
return func.text;
|
|
42
|
+
}
|
|
43
|
+
return func.text;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Find the deepest node whose range contains the given 0-indexed line.
|
|
47
|
+
*/
|
|
48
|
+
function nodeAtLine(root, line0) {
|
|
49
|
+
let best = null;
|
|
50
|
+
walk(root, (n) => {
|
|
51
|
+
if (n.startPosition.row <= line0 && n.endPosition.row >= line0) {
|
|
52
|
+
best = n;
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
return best;
|
|
56
|
+
}
|
|
57
|
+
// ---------------------------------------------------------------------------
|
|
58
|
+
// DataFlowTracer
|
|
59
|
+
// ---------------------------------------------------------------------------
|
|
60
|
+
class DataFlowTracer {
|
|
61
|
+
constructor(tree) {
|
|
62
|
+
this.rootNode = tree.rootNode;
|
|
63
|
+
}
|
|
64
|
+
// -----------------------------------------------------------------------
|
|
65
|
+
// passesThrough
|
|
66
|
+
// -----------------------------------------------------------------------
|
|
67
|
+
/**
|
|
68
|
+
* Check if a value at `targetLine` (1-indexed) passes through any of the
|
|
69
|
+
* specified functions before being used. Searches backward from targetLine
|
|
70
|
+
* for call expressions whose name matches one of `functionNames`.
|
|
71
|
+
*
|
|
72
|
+
* Example:
|
|
73
|
+
* passesThrough(42, ['DOMPurify.sanitize', 'sanitize', 'xss'])
|
|
74
|
+
* checks if the value used at line 42 was sanitized.
|
|
75
|
+
*/
|
|
76
|
+
passesThrough(targetLine, functionNames) {
|
|
77
|
+
const target0 = targetLine - 1; // convert to 0-indexed
|
|
78
|
+
// 1. Check for INLINE sanitizer calls on the target line itself.
|
|
79
|
+
// e.g., dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(content) }}
|
|
80
|
+
// or dangerouslySetInnerHTML={{ __html: sanitize(userInput) }}
|
|
81
|
+
let inlineFound = false;
|
|
82
|
+
walk(this.rootNode, (node) => {
|
|
83
|
+
if (inlineFound)
|
|
84
|
+
return;
|
|
85
|
+
if (node.type === 'call_expression' && node.startPosition.row === target0) {
|
|
86
|
+
const name = resolveCallName(node);
|
|
87
|
+
if (name && functionNames.some((fn) => name === fn || name.endsWith('.' + fn))) {
|
|
88
|
+
inlineFound = true;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
if (inlineFound)
|
|
93
|
+
return true;
|
|
94
|
+
// 2. Collect all matching call_expression nodes that occur before the target line.
|
|
95
|
+
const matchingCalls = [];
|
|
96
|
+
walk(this.rootNode, (node) => {
|
|
97
|
+
if (node.type === 'call_expression' && node.startPosition.row < target0) {
|
|
98
|
+
const name = resolveCallName(node);
|
|
99
|
+
if (name && functionNames.some((fn) => name === fn || name.endsWith('.' + fn))) {
|
|
100
|
+
matchingCalls.push(node);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
if (matchingCalls.length === 0)
|
|
105
|
+
return false;
|
|
106
|
+
// 3. Check if any of the matching calls assign to a variable that is
|
|
107
|
+
// referenced on the target line.
|
|
108
|
+
const targetLineText = this.getLineText(target0);
|
|
109
|
+
for (const call of matchingCalls) {
|
|
110
|
+
// Walk upward to find a variable_declarator or assignment_expression
|
|
111
|
+
// wrapping this call.
|
|
112
|
+
let parent = call.parent;
|
|
113
|
+
while (parent && parent.type !== 'variable_declarator' && parent.type !== 'assignment_expression') {
|
|
114
|
+
parent = parent.parent;
|
|
115
|
+
}
|
|
116
|
+
if (parent) {
|
|
117
|
+
let assignedName = null;
|
|
118
|
+
if (parent.type === 'variable_declarator') {
|
|
119
|
+
const nameNode = parent.childForFieldName('name');
|
|
120
|
+
if (nameNode)
|
|
121
|
+
assignedName = nameNode.text;
|
|
122
|
+
}
|
|
123
|
+
else if (parent.type === 'assignment_expression') {
|
|
124
|
+
const left = parent.childForFieldName('left');
|
|
125
|
+
if (left)
|
|
126
|
+
assignedName = left.text;
|
|
127
|
+
}
|
|
128
|
+
// If the variable assigned from the sanitizer call appears on the
|
|
129
|
+
// target line, the value passes through.
|
|
130
|
+
if (assignedName && targetLineText.includes(assignedName)) {
|
|
131
|
+
return true;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
// Also handle the case where the call is used inline on a line just
|
|
135
|
+
// before the target (e.g., the call result is passed directly as an
|
|
136
|
+
// argument or stored in a variable used on the very next statement).
|
|
137
|
+
if (target0 - call.startPosition.row <= 2) {
|
|
138
|
+
return true;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return false;
|
|
142
|
+
}
|
|
143
|
+
// -----------------------------------------------------------------------
|
|
144
|
+
// hasPropertyInScope
|
|
145
|
+
// -----------------------------------------------------------------------
|
|
146
|
+
/**
|
|
147
|
+
* Check if any property with the given names exists in the same scope/block
|
|
148
|
+
* as the target line (1-indexed). Used for checking if a Schema has
|
|
149
|
+
* TTL/expires fields.
|
|
150
|
+
*
|
|
151
|
+
* Example:
|
|
152
|
+
* hasPropertyInScope(42, ['TTL', 'expires', 'retention', 'deleted_at'])
|
|
153
|
+
*/
|
|
154
|
+
hasPropertyInScope(targetLine, propertyNames) {
|
|
155
|
+
const target0 = targetLine - 1;
|
|
156
|
+
const lowerNames = propertyNames.map((n) => n.toLowerCase());
|
|
157
|
+
// Find enclosing scope node.
|
|
158
|
+
const scope = this.findEnclosingScopeNode(target0);
|
|
159
|
+
if (!scope)
|
|
160
|
+
return false;
|
|
161
|
+
let found = false;
|
|
162
|
+
walk(scope, (node) => {
|
|
163
|
+
if (found)
|
|
164
|
+
return;
|
|
165
|
+
// property_identifier: key in { key: value }
|
|
166
|
+
// shorthand_property_identifier_pattern: { key } destructure
|
|
167
|
+
// shorthand_property_identifier: { key } shorthand
|
|
168
|
+
// pair → key child (for object literals)
|
|
169
|
+
if (node.type === 'property_identifier' ||
|
|
170
|
+
node.type === 'shorthand_property_identifier' ||
|
|
171
|
+
node.type === 'shorthand_property_identifier_pattern') {
|
|
172
|
+
if (lowerNames.includes(node.text.toLowerCase())) {
|
|
173
|
+
found = true;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
// Also match string keys like 'TTL' in { 'TTL': 300 }
|
|
177
|
+
if (node.type === 'string' && node.parent?.type === 'pair') {
|
|
178
|
+
const raw = node.text.replace(/^['"]|['"]$/g, '');
|
|
179
|
+
if (lowerNames.includes(raw.toLowerCase())) {
|
|
180
|
+
found = true;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
// Match identifiers that look like property names in type annotations
|
|
184
|
+
// or interfaces, e.g. `deleted_at: Date`
|
|
185
|
+
if (node.type === 'identifier' || node.type === 'property_identifier') {
|
|
186
|
+
if (lowerNames.includes(node.text.toLowerCase())) {
|
|
187
|
+
found = true;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
});
|
|
191
|
+
return found;
|
|
192
|
+
}
|
|
193
|
+
// -----------------------------------------------------------------------
|
|
194
|
+
// findNearbyCallExpressions
|
|
195
|
+
// -----------------------------------------------------------------------
|
|
196
|
+
/**
|
|
197
|
+
* Find all call expressions within `range` lines of `targetLine` (1-indexed).
|
|
198
|
+
* Returns function name and line number (1-indexed).
|
|
199
|
+
*/
|
|
200
|
+
findNearbyCallExpressions(targetLine, range) {
|
|
201
|
+
const target0 = targetLine - 1;
|
|
202
|
+
const results = [];
|
|
203
|
+
walk(this.rootNode, (node) => {
|
|
204
|
+
if (node.type === 'call_expression') {
|
|
205
|
+
const line0 = node.startPosition.row;
|
|
206
|
+
if (Math.abs(line0 - target0) <= range) {
|
|
207
|
+
const name = resolveCallName(node);
|
|
208
|
+
if (name) {
|
|
209
|
+
results.push({ name, line: line0 + 1 });
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
return results;
|
|
215
|
+
}
|
|
216
|
+
// -----------------------------------------------------------------------
|
|
217
|
+
// getEnclosingScope
|
|
218
|
+
// -----------------------------------------------------------------------
|
|
219
|
+
/**
|
|
220
|
+
* Get the enclosing function/block scope for a given line (1-indexed).
|
|
221
|
+
* Returns the start line (1-indexed), end line (1-indexed), and type of the
|
|
222
|
+
* enclosing scope.
|
|
223
|
+
*/
|
|
224
|
+
getEnclosingScope(line) {
|
|
225
|
+
const scope = this.findEnclosingFunctionScope(line - 1);
|
|
226
|
+
if (!scope)
|
|
227
|
+
return null;
|
|
228
|
+
return {
|
|
229
|
+
startLine: scope.startPosition.row + 1,
|
|
230
|
+
endLine: scope.endPosition.row + 1,
|
|
231
|
+
type: scope.type,
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
// -----------------------------------------------------------------------
|
|
235
|
+
// findAssignments
|
|
236
|
+
// -----------------------------------------------------------------------
|
|
237
|
+
/**
|
|
238
|
+
* Find all assignments to a variable name within the file.
|
|
239
|
+
* Returns line (1-indexed) and the textual representation of the assigned value.
|
|
240
|
+
*/
|
|
241
|
+
findAssignments(variableName) {
|
|
242
|
+
const results = [];
|
|
243
|
+
walk(this.rootNode, (node) => {
|
|
244
|
+
// const x = ... / let x = ... / var x = ...
|
|
245
|
+
if (node.type === 'variable_declarator') {
|
|
246
|
+
const nameNode = node.childForFieldName('name');
|
|
247
|
+
const valueNode = node.childForFieldName('value');
|
|
248
|
+
if (nameNode && nameNode.text === variableName && valueNode) {
|
|
249
|
+
results.push({
|
|
250
|
+
line: node.startPosition.row + 1,
|
|
251
|
+
value: valueNode.text,
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
// x = ... (reassignment)
|
|
256
|
+
if (node.type === 'assignment_expression') {
|
|
257
|
+
const left = node.childForFieldName('left');
|
|
258
|
+
const right = node.childForFieldName('right');
|
|
259
|
+
if (left && left.text === variableName && right) {
|
|
260
|
+
results.push({
|
|
261
|
+
line: node.startPosition.row + 1,
|
|
262
|
+
value: right.text,
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
});
|
|
267
|
+
return results;
|
|
268
|
+
}
|
|
269
|
+
// -----------------------------------------------------------------------
|
|
270
|
+
// hasArgument
|
|
271
|
+
// -----------------------------------------------------------------------
|
|
272
|
+
/**
|
|
273
|
+
* Check if a specific argument text is present in a function call at a
|
|
274
|
+
* given line (1-indexed).
|
|
275
|
+
*
|
|
276
|
+
* Handles:
|
|
277
|
+
* - Simple string/identifier args: ga('create', 'UA-X', 'auto')
|
|
278
|
+
* - Object literal properties: ga('create', 'UA-X', { child_directed_treatment: true })
|
|
279
|
+
* - new_expression args: new Analytics({ child_directed_treatment: true })
|
|
280
|
+
* - Nested object properties at any depth
|
|
281
|
+
*
|
|
282
|
+
* Example:
|
|
283
|
+
* hasArgument(42, 'child_directed_treatment')
|
|
284
|
+
*/
|
|
285
|
+
hasArgument(callLine, argumentText) {
|
|
286
|
+
const call0 = callLine - 1;
|
|
287
|
+
const lowerTarget = argumentText.toLowerCase();
|
|
288
|
+
let found = false;
|
|
289
|
+
walk(this.rootNode, (node) => {
|
|
290
|
+
if (found)
|
|
291
|
+
return;
|
|
292
|
+
// Match both call_expression and new_expression at the target line
|
|
293
|
+
const isCallOrNew = node.type === 'call_expression' || node.type === 'new_expression';
|
|
294
|
+
if (isCallOrNew && node.startPosition.row === call0) {
|
|
295
|
+
const args = node.childForFieldName('arguments');
|
|
296
|
+
if (args) {
|
|
297
|
+
// Deep walk the arguments subtree — inspect every node including
|
|
298
|
+
// object literal property keys, values, and nested structures.
|
|
299
|
+
walk(args, (argNode) => {
|
|
300
|
+
if (found)
|
|
301
|
+
return;
|
|
302
|
+
// Check property keys in object literals: { child_directed_treatment: true }
|
|
303
|
+
if (argNode.type === 'property_identifier' || argNode.type === 'shorthand_property_identifier') {
|
|
304
|
+
if (argNode.text.toLowerCase().includes(lowerTarget)) {
|
|
305
|
+
found = true;
|
|
306
|
+
return;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
// Check string keys: { 'child_directed_treatment': true }
|
|
310
|
+
if (argNode.type === 'string' || argNode.type === 'template_string') {
|
|
311
|
+
const raw = argNode.text.replace(/^['"`]|['"`]$/g, '');
|
|
312
|
+
if (raw.toLowerCase().includes(lowerTarget)) {
|
|
313
|
+
found = true;
|
|
314
|
+
return;
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
// Check identifiers (variable names, boolean keywords, etc.)
|
|
318
|
+
if (argNode.type === 'identifier') {
|
|
319
|
+
if (argNode.text.toLowerCase().includes(lowerTarget)) {
|
|
320
|
+
found = true;
|
|
321
|
+
return;
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
// Fallback: raw text check on any node
|
|
325
|
+
if (argNode.text.includes(argumentText)) {
|
|
326
|
+
found = true;
|
|
327
|
+
}
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
});
|
|
332
|
+
return found;
|
|
333
|
+
}
|
|
334
|
+
// -----------------------------------------------------------------------
|
|
335
|
+
// hasVariableInScope (Sprint 9 — Richard Pass 4 fix)
|
|
336
|
+
// -----------------------------------------------------------------------
|
|
337
|
+
/**
|
|
338
|
+
* Check if a variable/constant with a matching name exists in the same
|
|
339
|
+
* block scope as the target line (1-indexed).
|
|
340
|
+
*
|
|
341
|
+
* Searches for: variable declarations, const declarations, let declarations,
|
|
342
|
+
* parameter names, and property assignments.
|
|
343
|
+
*
|
|
344
|
+
* This catches cases like:
|
|
345
|
+
* - parent_email declared alongside child_email → suppresses coppa-flow-009
|
|
346
|
+
* - MAX_PAGES constant near IntersectionObserver → suppresses ETHICAL-001
|
|
347
|
+
*/
|
|
348
|
+
hasVariableInScope(targetLine, variableNames) {
|
|
349
|
+
const target0 = targetLine - 1;
|
|
350
|
+
const lowerNames = variableNames.map(n => n.toLowerCase());
|
|
351
|
+
// Check both the immediate block scope AND the enclosing function scope
|
|
352
|
+
const blockScope = this.findNearestBlockOrScope(target0);
|
|
353
|
+
const funcScope = this.findEnclosingScopeNode(target0);
|
|
354
|
+
const scopesToCheck = new Set();
|
|
355
|
+
if (blockScope)
|
|
356
|
+
scopesToCheck.add(blockScope);
|
|
357
|
+
if (funcScope)
|
|
358
|
+
scopesToCheck.add(funcScope);
|
|
359
|
+
for (const scope of scopesToCheck) {
|
|
360
|
+
let found = false;
|
|
361
|
+
walk(scope, (node) => {
|
|
362
|
+
if (found)
|
|
363
|
+
return;
|
|
364
|
+
// Variable declarators: const MAX_PAGES = 10, let parent_email = ...
|
|
365
|
+
if (node.type === 'variable_declarator') {
|
|
366
|
+
const nameNode = node.childForFieldName('name');
|
|
367
|
+
if (nameNode && lowerNames.includes(nameNode.text.toLowerCase())) {
|
|
368
|
+
found = true;
|
|
369
|
+
return;
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
// Function parameters: function handler(parent_email, child_email)
|
|
373
|
+
if (node.type === 'identifier' && node.parent?.type === 'formal_parameters') {
|
|
374
|
+
if (lowerNames.includes(node.text.toLowerCase())) {
|
|
375
|
+
found = true;
|
|
376
|
+
return;
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
// Assignment expressions: parent_email = req.body.email
|
|
380
|
+
if (node.type === 'assignment_expression') {
|
|
381
|
+
const left = node.childForFieldName('left');
|
|
382
|
+
if (left && lowerNames.includes(left.text.toLowerCase())) {
|
|
383
|
+
found = true;
|
|
384
|
+
return;
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
// Identifier references: catches bare references like MAX_PAGES in
|
|
388
|
+
// `if (page < MAX_PAGES)` — the presence of the identifier anywhere
|
|
389
|
+
// in scope (even without a local declaration) is meaningful.
|
|
390
|
+
// Exclude identifiers that are property accesses (member_expression object/property)
|
|
391
|
+
// to avoid matching unrelated nested properties.
|
|
392
|
+
if (node.type === 'identifier') {
|
|
393
|
+
if (node.parent?.type !== 'formal_parameters' &&
|
|
394
|
+
node.parent?.type !== 'variable_declarator' &&
|
|
395
|
+
node.parent?.type !== 'property_identifier') {
|
|
396
|
+
if (lowerNames.includes(node.text.toLowerCase())) {
|
|
397
|
+
found = true;
|
|
398
|
+
return;
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
});
|
|
403
|
+
if (found)
|
|
404
|
+
return true;
|
|
405
|
+
}
|
|
406
|
+
return false;
|
|
407
|
+
}
|
|
408
|
+
// -----------------------------------------------------------------------
|
|
409
|
+
// Private helpers
|
|
410
|
+
// -----------------------------------------------------------------------
|
|
411
|
+
/**
|
|
412
|
+
* Find the enclosing function-level scope for a 0-indexed line.
|
|
413
|
+
* Used by the public getEnclosingScope() API — returns function/class/program scopes.
|
|
414
|
+
*/
|
|
415
|
+
findEnclosingFunctionScope(line0) {
|
|
416
|
+
const scopeTypes = new Set([
|
|
417
|
+
'function_declaration',
|
|
418
|
+
'function',
|
|
419
|
+
'arrow_function',
|
|
420
|
+
'method_definition',
|
|
421
|
+
'class_body',
|
|
422
|
+
'class_declaration',
|
|
423
|
+
'program',
|
|
424
|
+
]);
|
|
425
|
+
// Fall back to rootNode if nodeAtLine returns null (e.g., empty leading lines
|
|
426
|
+
// where tree-sitter's program node may start at a later row)
|
|
427
|
+
let node = nodeAtLine(this.rootNode, line0) ?? this.rootNode;
|
|
428
|
+
while (node) {
|
|
429
|
+
if (scopeTypes.has(node.type)) {
|
|
430
|
+
return node;
|
|
431
|
+
}
|
|
432
|
+
node = node.parent;
|
|
433
|
+
}
|
|
434
|
+
return null;
|
|
435
|
+
}
|
|
436
|
+
/**
|
|
437
|
+
* Find the enclosing scope node for a 0-indexed line (including block scopes).
|
|
438
|
+
* Used internally by hasPropertyInScope and hasVariableInScope for fine-grained
|
|
439
|
+
* variable/property resolution that respects block scoping.
|
|
440
|
+
*/
|
|
441
|
+
findEnclosingScopeNode(line0) {
|
|
442
|
+
const scopeTypes = new Set([
|
|
443
|
+
'function_declaration',
|
|
444
|
+
'function',
|
|
445
|
+
'arrow_function',
|
|
446
|
+
'method_definition',
|
|
447
|
+
'class_body',
|
|
448
|
+
'class_declaration',
|
|
449
|
+
'program',
|
|
450
|
+
// Sprint 9: Also consider block-level scopes for variable resolution
|
|
451
|
+
'statement_block',
|
|
452
|
+
'if_statement',
|
|
453
|
+
'for_statement',
|
|
454
|
+
'for_in_statement',
|
|
455
|
+
'for_of_statement',
|
|
456
|
+
'while_statement',
|
|
457
|
+
'switch_body',
|
|
458
|
+
'export_statement',
|
|
459
|
+
]);
|
|
460
|
+
// Fall back to rootNode if nodeAtLine returns null (e.g., empty leading lines)
|
|
461
|
+
let node = nodeAtLine(this.rootNode, line0) ?? this.rootNode;
|
|
462
|
+
while (node) {
|
|
463
|
+
if (scopeTypes.has(node.type)) {
|
|
464
|
+
return node;
|
|
465
|
+
}
|
|
466
|
+
node = node.parent;
|
|
467
|
+
}
|
|
468
|
+
return null;
|
|
469
|
+
}
|
|
470
|
+
/**
|
|
471
|
+
* Find the nearest block scope containing the given line (0-indexed).
|
|
472
|
+
* Falls back to the enclosing function/program scope.
|
|
473
|
+
* Used for variable declaration detection — checks both block and function scope.
|
|
474
|
+
*/
|
|
475
|
+
findNearestBlockOrScope(line0) {
|
|
476
|
+
const blockTypes = new Set([
|
|
477
|
+
'statement_block',
|
|
478
|
+
'function_declaration',
|
|
479
|
+
'function',
|
|
480
|
+
'arrow_function',
|
|
481
|
+
'method_definition',
|
|
482
|
+
'class_body',
|
|
483
|
+
'class_declaration',
|
|
484
|
+
'program',
|
|
485
|
+
]);
|
|
486
|
+
// Fall back to rootNode if nodeAtLine returns null (e.g., empty leading lines)
|
|
487
|
+
let node = nodeAtLine(this.rootNode, line0) ?? this.rootNode;
|
|
488
|
+
while (node) {
|
|
489
|
+
if (blockTypes.has(node.type)) {
|
|
490
|
+
return node;
|
|
491
|
+
}
|
|
492
|
+
node = node.parent;
|
|
493
|
+
}
|
|
494
|
+
return null;
|
|
495
|
+
}
|
|
496
|
+
/**
|
|
497
|
+
* Get the source text of a 0-indexed line by slicing the root node's text.
|
|
498
|
+
*/
|
|
499
|
+
getLineText(line0) {
|
|
500
|
+
const text = this.rootNode.text;
|
|
501
|
+
const lines = text.split('\n');
|
|
502
|
+
return lines[line0] ?? '';
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
exports.DataFlowTracer = DataFlowTracer;
|
|
506
|
+
//# sourceMappingURL=data-flow-tracer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"data-flow-tracer.js","sourceRoot":"","sources":["../src/data-flow-tracer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Django Framework Profile
|
|
3
|
+
*
|
|
4
|
+
* Django provides built-in protections that overlap with several COPPA rules:
|
|
5
|
+
* - Template engine auto-escapes all variables by default
|
|
6
|
+
* - SecurityMiddleware enforces HTTPS when configured
|
|
7
|
+
* - Built-in password validators enforce complexity requirements
|
|
8
|
+
* - django-lifecycle and django-reversion can handle data retention externally
|
|
9
|
+
*/
|
|
10
|
+
import { FrameworkProfile } from './types';
|
|
11
|
+
export declare const djangoProfile: FrameworkProfile;
|