@grafema/core 0.1.1-alpha → 0.2.0-beta
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/Orchestrator.d.ts +7 -0
- package/dist/Orchestrator.d.ts.map +1 -1
- package/dist/Orchestrator.js +25 -3
- package/dist/config/ConfigLoader.d.ts +18 -0
- package/dist/config/ConfigLoader.d.ts.map +1 -1
- package/dist/config/ConfigLoader.js +65 -3
- package/dist/core/FileExplainer.d.ts +101 -0
- package/dist/core/FileExplainer.d.ts.map +1 -0
- package/dist/core/FileExplainer.js +139 -0
- package/dist/core/NodeFactory.d.ts +44 -5
- package/dist/core/NodeFactory.d.ts.map +1 -1
- package/dist/core/NodeFactory.js +52 -7
- package/dist/core/nodes/ArrayLiteralNode.d.ts.map +1 -1
- package/dist/core/nodes/ArrayLiteralNode.js +4 -2
- package/dist/core/nodes/BranchNode.d.ts +41 -0
- package/dist/core/nodes/BranchNode.d.ts.map +1 -0
- package/dist/core/nodes/BranchNode.js +82 -0
- package/dist/core/nodes/CallSiteNode.d.ts +2 -2
- package/dist/core/nodes/CallSiteNode.d.ts.map +1 -1
- package/dist/core/nodes/CallSiteNode.js +9 -5
- package/dist/core/nodes/CaseNode.d.ts +43 -0
- package/dist/core/nodes/CaseNode.d.ts.map +1 -0
- package/dist/core/nodes/CaseNode.js +81 -0
- package/dist/core/nodes/ClassNode.d.ts +2 -2
- package/dist/core/nodes/ClassNode.d.ts.map +1 -1
- package/dist/core/nodes/ClassNode.js +8 -4
- package/dist/core/nodes/ConstantNode.d.ts +2 -2
- package/dist/core/nodes/ConstantNode.d.ts.map +1 -1
- package/dist/core/nodes/ConstantNode.js +6 -4
- package/dist/core/nodes/ConstructorCallNode.d.ts +51 -0
- package/dist/core/nodes/ConstructorCallNode.d.ts.map +1 -0
- package/dist/core/nodes/ConstructorCallNode.js +171 -0
- package/dist/core/nodes/DatabaseQueryNode.d.ts +3 -2
- package/dist/core/nodes/DatabaseQueryNode.d.ts.map +1 -1
- package/dist/core/nodes/DatabaseQueryNode.js +5 -2
- package/dist/core/nodes/DecoratorNode.d.ts +2 -2
- package/dist/core/nodes/DecoratorNode.d.ts.map +1 -1
- package/dist/core/nodes/DecoratorNode.js +5 -3
- package/dist/core/nodes/EnumNode.d.ts +2 -2
- package/dist/core/nodes/EnumNode.d.ts.map +1 -1
- package/dist/core/nodes/EnumNode.js +5 -3
- package/dist/core/nodes/EventListenerNode.d.ts +4 -4
- package/dist/core/nodes/EventListenerNode.d.ts.map +1 -1
- package/dist/core/nodes/EventListenerNode.js +7 -4
- package/dist/core/nodes/ExportNode.d.ts +2 -2
- package/dist/core/nodes/ExportNode.d.ts.map +1 -1
- package/dist/core/nodes/ExportNode.js +8 -4
- package/dist/core/nodes/ExpressionNode.d.ts +2 -2
- package/dist/core/nodes/ExpressionNode.d.ts.map +1 -1
- package/dist/core/nodes/ExpressionNode.js +6 -4
- package/dist/core/nodes/ExternalModuleNode.d.ts +4 -0
- package/dist/core/nodes/ExternalModuleNode.d.ts.map +1 -1
- package/dist/core/nodes/ExternalModuleNode.js +10 -2
- package/dist/core/nodes/HttpRequestNode.d.ts +4 -4
- package/dist/core/nodes/HttpRequestNode.d.ts.map +1 -1
- package/dist/core/nodes/HttpRequestNode.js +7 -4
- package/dist/core/nodes/ImportNode.d.ts +10 -2
- package/dist/core/nodes/ImportNode.d.ts.map +1 -1
- package/dist/core/nodes/ImportNode.js +21 -4
- package/dist/core/nodes/InterfaceNode.d.ts +2 -2
- package/dist/core/nodes/InterfaceNode.d.ts.map +1 -1
- package/dist/core/nodes/InterfaceNode.js +5 -3
- package/dist/core/nodes/LiteralNode.d.ts +2 -2
- package/dist/core/nodes/LiteralNode.d.ts.map +1 -1
- package/dist/core/nodes/LiteralNode.js +6 -4
- package/dist/core/nodes/MethodCallNode.d.ts +2 -2
- package/dist/core/nodes/MethodCallNode.d.ts.map +1 -1
- package/dist/core/nodes/MethodCallNode.js +9 -5
- package/dist/core/nodes/MethodNode.d.ts +2 -2
- package/dist/core/nodes/MethodNode.d.ts.map +1 -1
- package/dist/core/nodes/MethodNode.js +8 -4
- package/dist/core/nodes/ObjectLiteralNode.d.ts.map +1 -1
- package/dist/core/nodes/ObjectLiteralNode.js +4 -2
- package/dist/core/nodes/ParameterNode.d.ts +2 -2
- package/dist/core/nodes/ParameterNode.d.ts.map +1 -1
- package/dist/core/nodes/ParameterNode.js +5 -3
- package/dist/core/nodes/TypeNode.d.ts +2 -2
- package/dist/core/nodes/TypeNode.d.ts.map +1 -1
- package/dist/core/nodes/TypeNode.js +5 -3
- package/dist/core/nodes/VariableDeclarationNode.d.ts +2 -2
- package/dist/core/nodes/VariableDeclarationNode.d.ts.map +1 -1
- package/dist/core/nodes/VariableDeclarationNode.js +9 -5
- package/dist/core/nodes/index.d.ts +3 -0
- package/dist/core/nodes/index.d.ts.map +1 -1
- package/dist/core/nodes/index.js +3 -0
- package/dist/data/builtins/BuiltinRegistry.d.ts +78 -0
- package/dist/data/builtins/BuiltinRegistry.d.ts.map +1 -0
- package/dist/data/builtins/BuiltinRegistry.js +110 -0
- package/dist/data/builtins/definitions.d.ts +28 -0
- package/dist/data/builtins/definitions.d.ts.map +1 -0
- package/dist/data/builtins/definitions.js +250 -0
- package/dist/data/builtins/index.d.ts +10 -0
- package/dist/data/builtins/index.d.ts.map +1 -0
- package/dist/data/builtins/index.js +8 -0
- package/dist/data/builtins/jsGlobals.d.ts +18 -0
- package/dist/data/builtins/jsGlobals.d.ts.map +1 -0
- package/dist/data/builtins/jsGlobals.js +26 -0
- package/dist/data/builtins/types.d.ts +34 -0
- package/dist/data/builtins/types.d.ts.map +1 -0
- package/dist/data/builtins/types.js +7 -0
- package/dist/data/globals/definitions.d.ts +27 -0
- package/dist/data/globals/definitions.d.ts.map +1 -0
- package/dist/data/globals/definitions.js +117 -0
- package/dist/data/globals/index.d.ts +36 -0
- package/dist/data/globals/index.d.ts.map +1 -0
- package/dist/data/globals/index.js +52 -0
- package/dist/diagnostics/DiagnosticReporter.d.ts +23 -0
- package/dist/diagnostics/DiagnosticReporter.d.ts.map +1 -1
- package/dist/diagnostics/DiagnosticReporter.js +88 -0
- package/dist/diagnostics/index.d.ts +1 -1
- package/dist/diagnostics/index.d.ts.map +1 -1
- package/dist/errors/GrafemaError.d.ts +43 -0
- package/dist/errors/GrafemaError.d.ts.map +1 -1
- package/dist/errors/GrafemaError.js +50 -0
- package/dist/index.d.ts +17 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +17 -1
- package/dist/plugins/analysis/DatabaseAnalyzer.d.ts.map +1 -1
- package/dist/plugins/analysis/DatabaseAnalyzer.js +3 -2
- package/dist/plugins/analysis/ExpressAnalyzer.d.ts.map +1 -1
- package/dist/plugins/analysis/ExpressAnalyzer.js +3 -1
- package/dist/plugins/analysis/ExpressResponseAnalyzer.d.ts +148 -0
- package/dist/plugins/analysis/ExpressResponseAnalyzer.d.ts.map +1 -0
- package/dist/plugins/analysis/ExpressResponseAnalyzer.js +495 -0
- package/dist/plugins/analysis/ExpressRouteAnalyzer.d.ts.map +1 -1
- package/dist/plugins/analysis/ExpressRouteAnalyzer.js +53 -18
- package/dist/plugins/analysis/FetchAnalyzer.d.ts +40 -0
- package/dist/plugins/analysis/FetchAnalyzer.d.ts.map +1 -1
- package/dist/plugins/analysis/FetchAnalyzer.js +163 -15
- package/dist/plugins/analysis/JSASTAnalyzer.d.ts +157 -26
- package/dist/plugins/analysis/JSASTAnalyzer.d.ts.map +1 -1
- package/dist/plugins/analysis/JSASTAnalyzer.js +2418 -191
- package/dist/plugins/analysis/RustAnalyzer.js +4 -4
- package/dist/plugins/analysis/SQLiteAnalyzer.d.ts.map +1 -1
- package/dist/plugins/analysis/SQLiteAnalyzer.js +4 -2
- package/dist/plugins/analysis/SocketIOAnalyzer.d.ts +9 -0
- package/dist/plugins/analysis/SocketIOAnalyzer.d.ts.map +1 -1
- package/dist/plugins/analysis/SocketIOAnalyzer.js +91 -7
- package/dist/plugins/analysis/ast/GraphBuilder.d.ts +173 -0
- package/dist/plugins/analysis/ast/GraphBuilder.d.ts.map +1 -1
- package/dist/plugins/analysis/ast/GraphBuilder.js +1256 -65
- package/dist/plugins/analysis/ast/types.d.ts +294 -0
- package/dist/plugins/analysis/ast/types.d.ts.map +1 -1
- package/dist/plugins/analysis/ast/visitors/ASTVisitor.d.ts +5 -1
- package/dist/plugins/analysis/ast/visitors/ASTVisitor.d.ts.map +1 -1
- package/dist/plugins/analysis/ast/visitors/CallExpressionVisitor.d.ts +1 -0
- package/dist/plugins/analysis/ast/visitors/CallExpressionVisitor.d.ts.map +1 -1
- package/dist/plugins/analysis/ast/visitors/CallExpressionVisitor.js +12 -1
- package/dist/plugins/analysis/ast/visitors/FunctionVisitor.d.ts +10 -0
- package/dist/plugins/analysis/ast/visitors/FunctionVisitor.d.ts.map +1 -1
- package/dist/plugins/analysis/ast/visitors/FunctionVisitor.js +62 -0
- package/dist/plugins/analysis/ast/visitors/ImportExportVisitor.d.ts +4 -0
- package/dist/plugins/analysis/ast/visitors/ImportExportVisitor.d.ts.map +1 -1
- package/dist/plugins/analysis/ast/visitors/ImportExportVisitor.js +101 -0
- package/dist/plugins/analysis/ast/visitors/VariableVisitor.d.ts +16 -1
- package/dist/plugins/analysis/ast/visitors/VariableVisitor.d.ts.map +1 -1
- package/dist/plugins/analysis/ast/visitors/VariableVisitor.js +233 -39
- package/dist/plugins/discovery/WorkspaceDiscovery.d.ts.map +1 -1
- package/dist/plugins/discovery/WorkspaceDiscovery.js +9 -4
- package/dist/plugins/enrichment/AliasTracker.d.ts.map +1 -1
- package/dist/plugins/enrichment/AliasTracker.js +16 -1
- package/dist/plugins/enrichment/ArgumentParameterLinker.d.ts +32 -0
- package/dist/plugins/enrichment/ArgumentParameterLinker.d.ts.map +1 -0
- package/dist/plugins/enrichment/ArgumentParameterLinker.js +175 -0
- package/dist/plugins/enrichment/ClosureCaptureEnricher.d.ts +51 -0
- package/dist/plugins/enrichment/ClosureCaptureEnricher.d.ts.map +1 -0
- package/dist/plugins/enrichment/ClosureCaptureEnricher.js +205 -0
- package/dist/plugins/enrichment/ExternalCallResolver.d.ts +42 -0
- package/dist/plugins/enrichment/ExternalCallResolver.d.ts.map +1 -0
- package/dist/plugins/enrichment/ExternalCallResolver.js +213 -0
- package/dist/plugins/enrichment/FunctionCallResolver.d.ts +58 -0
- package/dist/plugins/enrichment/FunctionCallResolver.d.ts.map +1 -0
- package/dist/plugins/enrichment/FunctionCallResolver.js +340 -0
- package/dist/plugins/enrichment/HTTPConnectionEnricher.d.ts +16 -3
- package/dist/plugins/enrichment/HTTPConnectionEnricher.d.ts.map +1 -1
- package/dist/plugins/enrichment/HTTPConnectionEnricher.js +64 -20
- package/dist/plugins/enrichment/MethodCallResolver.d.ts.map +1 -1
- package/dist/plugins/enrichment/MethodCallResolver.js +15 -1
- package/dist/plugins/enrichment/MountPointResolver.d.ts +14 -12
- package/dist/plugins/enrichment/MountPointResolver.d.ts.map +1 -1
- package/dist/plugins/enrichment/MountPointResolver.js +172 -151
- package/dist/plugins/enrichment/NodejsBuiltinsResolver.d.ts +44 -0
- package/dist/plugins/enrichment/NodejsBuiltinsResolver.d.ts.map +1 -0
- package/dist/plugins/enrichment/NodejsBuiltinsResolver.js +271 -0
- package/dist/plugins/enrichment/ValueDomainAnalyzer.d.ts +5 -27
- package/dist/plugins/enrichment/ValueDomainAnalyzer.d.ts.map +1 -1
- package/dist/plugins/enrichment/ValueDomainAnalyzer.js +62 -139
- package/dist/plugins/indexing/JSModuleIndexer.d.ts +15 -0
- package/dist/plugins/indexing/JSModuleIndexer.d.ts.map +1 -1
- package/dist/plugins/indexing/JSModuleIndexer.js +58 -0
- package/dist/plugins/indexing/RustModuleIndexer.d.ts +1 -1
- package/dist/plugins/indexing/RustModuleIndexer.js +4 -4
- package/dist/plugins/validation/BrokenImportValidator.d.ts +31 -0
- package/dist/plugins/validation/BrokenImportValidator.d.ts.map +1 -0
- package/dist/plugins/validation/BrokenImportValidator.js +249 -0
- package/dist/plugins/validation/CallResolverValidator.d.ts +21 -10
- package/dist/plugins/validation/CallResolverValidator.d.ts.map +1 -1
- package/dist/plugins/validation/CallResolverValidator.js +101 -76
- package/dist/plugins/validation/DataFlowValidator.d.ts.map +1 -1
- package/dist/plugins/validation/DataFlowValidator.js +49 -41
- package/dist/plugins/validation/GraphConnectivityValidator.d.ts.map +1 -1
- package/dist/plugins/validation/GraphConnectivityValidator.js +25 -1
- package/dist/plugins/validation/SQLInjectionValidator.d.ts.map +1 -1
- package/dist/plugins/validation/SQLInjectionValidator.js +2 -3
- package/dist/queries/findCallsInFunction.d.ts +52 -0
- package/dist/queries/findCallsInFunction.d.ts.map +1 -0
- package/dist/queries/findCallsInFunction.js +135 -0
- package/dist/queries/findContainingFunction.d.ts +45 -0
- package/dist/queries/findContainingFunction.d.ts.map +1 -0
- package/dist/queries/findContainingFunction.js +54 -0
- package/dist/queries/index.d.ts +14 -0
- package/dist/queries/index.d.ts.map +1 -0
- package/dist/queries/index.js +11 -0
- package/dist/queries/traceValues.d.ts +70 -0
- package/dist/queries/traceValues.d.ts.map +1 -0
- package/dist/queries/traceValues.js +299 -0
- package/dist/queries/types.d.ts +163 -0
- package/dist/queries/types.d.ts.map +1 -0
- package/dist/queries/types.js +9 -0
- package/dist/schema/GraphSchemaExtractor.d.ts +53 -0
- package/dist/schema/GraphSchemaExtractor.d.ts.map +1 -0
- package/dist/schema/GraphSchemaExtractor.js +124 -0
- package/dist/schema/InterfaceSchemaExtractor.d.ts +73 -0
- package/dist/schema/InterfaceSchemaExtractor.d.ts.map +1 -0
- package/dist/schema/InterfaceSchemaExtractor.js +112 -0
- package/dist/schema/index.d.ts +5 -0
- package/dist/schema/index.d.ts.map +1 -0
- package/dist/schema/index.js +2 -0
- package/dist/storage/backends/RFDBServerBackend.d.ts +12 -18
- package/dist/storage/backends/RFDBServerBackend.d.ts.map +1 -1
- package/dist/storage/backends/RFDBServerBackend.js +41 -52
- package/dist/storage/backends/typeValidation.d.ts.map +1 -1
- package/dist/storage/backends/typeValidation.js +1 -0
- package/package.json +3 -3
- package/src/Orchestrator.ts +35 -3
- package/src/config/ConfigLoader.ts +94 -3
- package/src/core/FileExplainer.ts +179 -0
- package/src/core/NodeFactory.ts +72 -8
- package/src/core/nodes/ArrayLiteralNode.ts +3 -2
- package/src/core/nodes/BranchNode.ts +113 -0
- package/src/core/nodes/CallSiteNode.ts +7 -5
- package/src/core/nodes/CaseNode.ts +123 -0
- package/src/core/nodes/ClassNode.ts +6 -4
- package/src/core/nodes/ConstantNode.ts +5 -4
- package/src/core/nodes/ConstructorCallNode.ts +217 -0
- package/src/core/nodes/DatabaseQueryNode.ts +5 -1
- package/src/core/nodes/DecoratorNode.ts +4 -3
- package/src/core/nodes/EnumNode.ts +4 -3
- package/src/core/nodes/EventListenerNode.ts +7 -4
- package/src/core/nodes/ExportNode.ts +6 -4
- package/src/core/nodes/ExpressionNode.ts +5 -4
- package/src/core/nodes/ExternalModuleNode.ts +11 -2
- package/src/core/nodes/HttpRequestNode.ts +7 -4
- package/src/core/nodes/ImportNode.ts +31 -4
- package/src/core/nodes/InterfaceNode.ts +4 -3
- package/src/core/nodes/LiteralNode.ts +5 -4
- package/src/core/nodes/MethodCallNode.ts +7 -5
- package/src/core/nodes/MethodNode.ts +6 -4
- package/src/core/nodes/ObjectLiteralNode.ts +3 -2
- package/src/core/nodes/ParameterNode.ts +4 -3
- package/src/core/nodes/TypeNode.ts +4 -3
- package/src/core/nodes/VariableDeclarationNode.ts +7 -5
- package/src/core/nodes/index.ts +3 -0
- package/src/data/builtins/BuiltinRegistry.ts +124 -0
- package/src/data/builtins/definitions.ts +267 -0
- package/src/data/builtins/index.ts +10 -0
- package/src/data/builtins/jsGlobals.ts +28 -0
- package/src/data/builtins/types.ts +36 -0
- package/src/data/globals/definitions.ts +156 -0
- package/src/data/globals/index.ts +66 -0
- package/src/diagnostics/DiagnosticReporter.ts +120 -0
- package/src/diagnostics/index.ts +1 -1
- package/src/errors/GrafemaError.ts +65 -0
- package/src/index.ts +45 -0
- package/src/plugins/analysis/DatabaseAnalyzer.ts +4 -2
- package/src/plugins/analysis/ExpressAnalyzer.ts +5 -1
- package/src/plugins/analysis/ExpressResponseAnalyzer.ts +636 -0
- package/src/plugins/analysis/ExpressRouteAnalyzer.ts +57 -18
- package/src/plugins/analysis/FetchAnalyzer.ts +204 -16
- package/src/plugins/analysis/JSASTAnalyzer.ts +2958 -260
- package/src/plugins/analysis/RustAnalyzer.ts +4 -4
- package/src/plugins/analysis/SQLiteAnalyzer.ts +5 -2
- package/src/plugins/analysis/SocketIOAnalyzer.ts +121 -7
- package/src/plugins/analysis/ast/GraphBuilder.ts +1578 -70
- package/src/plugins/analysis/ast/types.ts +387 -0
- package/src/plugins/analysis/ast/visitors/ASTVisitor.ts +8 -0
- package/src/plugins/analysis/ast/visitors/CallExpressionVisitor.ts +16 -1
- package/src/plugins/analysis/ast/visitors/FunctionVisitor.ts +77 -2
- package/src/plugins/analysis/ast/visitors/ImportExportVisitor.ts +112 -1
- package/src/plugins/analysis/ast/visitors/VariableVisitor.ts +272 -47
- package/src/plugins/discovery/WorkspaceDiscovery.ts +11 -4
- package/src/plugins/enrichment/AliasTracker.ts +22 -1
- package/src/plugins/enrichment/ArgumentParameterLinker.ts +240 -0
- package/src/plugins/enrichment/ClosureCaptureEnricher.ts +267 -0
- package/src/plugins/enrichment/ExternalCallResolver.ts +262 -0
- package/src/plugins/enrichment/FunctionCallResolver.ts +456 -0
- package/src/plugins/enrichment/HTTPConnectionEnricher.ts +70 -20
- package/src/plugins/enrichment/MethodCallResolver.ts +21 -1
- package/src/plugins/enrichment/MountPointResolver.ts +206 -198
- package/src/plugins/enrichment/NodejsBuiltinsResolver.ts +365 -0
- package/src/plugins/enrichment/ValueDomainAnalyzer.ts +67 -184
- package/src/plugins/indexing/JSModuleIndexer.ts +66 -0
- package/src/plugins/indexing/RustModuleIndexer.ts +4 -4
- package/src/plugins/validation/BrokenImportValidator.ts +325 -0
- package/src/plugins/validation/CallResolverValidator.ts +129 -109
- package/src/plugins/validation/DataFlowValidator.ts +75 -58
- package/src/plugins/validation/GraphConnectivityValidator.ts +39 -1
- package/src/plugins/validation/SQLInjectionValidator.ts +2 -5
- package/src/queries/README.md +46 -0
- package/src/queries/findCallsInFunction.ts +206 -0
- package/src/queries/findContainingFunction.ts +83 -0
- package/src/queries/index.ts +23 -0
- package/src/queries/traceValues.ts +398 -0
- package/src/queries/types.ts +187 -0
- package/src/schema/GraphSchemaExtractor.ts +177 -0
- package/src/schema/InterfaceSchemaExtractor.ts +173 -0
- package/src/schema/index.ts +5 -0
- package/src/storage/backends/RFDBServerBackend.ts +58 -70
- package/src/storage/backends/typeValidation.ts +1 -0
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* CallResolverValidator -
|
|
2
|
+
* CallResolverValidator - validates function call resolution (REG-227)
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* Checks that all function calls are properly resolved:
|
|
5
|
+
* - Internal calls: CALLS edge to FUNCTION node
|
|
6
|
+
* - External calls: CALLS edge to EXTERNAL_MODULE node
|
|
7
|
+
* - Builtin calls: recognized by name (no edge needed)
|
|
8
|
+
* - Unresolved: no edge, not builtin -> WARNING
|
|
6
9
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* Это находит CALL узлы без "object" метаданных (т.е. CALL_SITE, не METHOD_CALL),
|
|
11
|
-
* которые не имеют CALLS ребра к определению функции.
|
|
10
|
+
* This validator runs AFTER FunctionCallResolver and ExternalCallResolver
|
|
11
|
+
* to verify resolution quality and report issues.
|
|
12
12
|
*/
|
|
13
13
|
import { Plugin, createSuccessResult } from '../Plugin.js';
|
|
14
|
+
import { ValidationError } from '../../errors/GrafemaError.js';
|
|
15
|
+
import { JS_GLOBAL_FUNCTIONS } from '../../data/builtins/index.js';
|
|
14
16
|
export class CallResolverValidator extends Plugin {
|
|
15
17
|
get metadata() {
|
|
16
18
|
return {
|
|
@@ -20,90 +22,113 @@ export class CallResolverValidator extends Plugin {
|
|
|
20
22
|
creates: {
|
|
21
23
|
nodes: [],
|
|
22
24
|
edges: []
|
|
23
|
-
}
|
|
25
|
+
},
|
|
26
|
+
dependencies: ['FunctionCallResolver', 'ExternalCallResolver']
|
|
24
27
|
};
|
|
25
28
|
}
|
|
26
29
|
async execute(context) {
|
|
27
30
|
const { graph } = context;
|
|
28
31
|
const logger = this.log(context);
|
|
29
|
-
logger.info('Starting call resolution validation
|
|
30
|
-
|
|
31
|
-
if (!graph.checkGuarantee) {
|
|
32
|
-
logger.debug('Graph does not support checkGuarantee, skipping validation');
|
|
33
|
-
return createSuccessResult({ nodes: 0, edges: 0 }, { skipped: true });
|
|
34
|
-
}
|
|
35
|
-
// Datalog гарантия:
|
|
36
|
-
// CALL без "object" (т.е. CALL_SITE) должен иметь CALLS ребро
|
|
37
|
-
const violations = await graph.checkGuarantee(`
|
|
38
|
-
violation(X) :- node(X, "CALL"), \\+ attr(X, "object", _), \\+ edge(X, _, "CALLS").
|
|
39
|
-
`);
|
|
40
|
-
const issues = [];
|
|
41
|
-
if (violations.length > 0) {
|
|
42
|
-
logger.debug('Unresolved function calls found', { count: violations.length });
|
|
43
|
-
for (const v of violations) {
|
|
44
|
-
const nodeId = v.bindings.find(b => b.name === 'X')?.value;
|
|
45
|
-
if (nodeId) {
|
|
46
|
-
const node = await graph.getNode(nodeId);
|
|
47
|
-
if (node) {
|
|
48
|
-
issues.push({
|
|
49
|
-
type: 'UNRESOLVED_FUNCTION_CALL',
|
|
50
|
-
severity: 'WARNING',
|
|
51
|
-
message: `Call to "${node.name}" at ${node.file}:${node.line || '?'} does not resolve to a function definition`,
|
|
52
|
-
callName: node.name,
|
|
53
|
-
nodeId: nodeId,
|
|
54
|
-
file: node.file,
|
|
55
|
-
line: node.line
|
|
56
|
-
});
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
// Также проверим METHOD_CALL на известные внешние методы
|
|
62
|
-
// (это информационно, не ошибка)
|
|
63
|
-
const methodCallStats = await this.countMethodCalls(graph);
|
|
32
|
+
logger.info('Starting call resolution validation');
|
|
33
|
+
const warnings = [];
|
|
64
34
|
const summary = {
|
|
65
|
-
totalCalls:
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
35
|
+
totalCalls: 0,
|
|
36
|
+
resolvedInternal: 0,
|
|
37
|
+
resolvedExternal: 0,
|
|
38
|
+
resolvedBuiltin: 0,
|
|
39
|
+
methodCalls: 0,
|
|
40
|
+
unresolvedCalls: 0,
|
|
41
|
+
warnings: 0
|
|
70
42
|
};
|
|
43
|
+
// Process all CALL nodes
|
|
44
|
+
for await (const node of graph.queryNodes({ nodeType: 'CALL' })) {
|
|
45
|
+
summary.totalCalls++;
|
|
46
|
+
const callNode = node;
|
|
47
|
+
const resolutionType = await this.determineResolutionType(graph, callNode);
|
|
48
|
+
switch (resolutionType) {
|
|
49
|
+
case 'internal':
|
|
50
|
+
summary.resolvedInternal++;
|
|
51
|
+
break;
|
|
52
|
+
case 'external':
|
|
53
|
+
summary.resolvedExternal++;
|
|
54
|
+
break;
|
|
55
|
+
case 'builtin':
|
|
56
|
+
summary.resolvedBuiltin++;
|
|
57
|
+
break;
|
|
58
|
+
case 'method':
|
|
59
|
+
summary.methodCalls++;
|
|
60
|
+
break;
|
|
61
|
+
case 'unresolved':
|
|
62
|
+
summary.unresolvedCalls++;
|
|
63
|
+
summary.warnings++;
|
|
64
|
+
warnings.push(this.createWarning(callNode));
|
|
65
|
+
break;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
71
68
|
logger.info('Validation complete', { ...summary });
|
|
72
|
-
if (
|
|
73
|
-
logger.warn('Unresolved calls detected', { count:
|
|
74
|
-
for (const
|
|
75
|
-
logger.warn(
|
|
69
|
+
if (warnings.length > 0) {
|
|
70
|
+
logger.warn('Unresolved calls detected', { count: warnings.length });
|
|
71
|
+
for (const warning of warnings.slice(0, 10)) {
|
|
72
|
+
logger.warn(warning.message);
|
|
76
73
|
}
|
|
77
|
-
if (
|
|
78
|
-
logger.debug(`... and ${
|
|
74
|
+
if (warnings.length > 10) {
|
|
75
|
+
logger.debug(`... and ${warnings.length - 10} more`);
|
|
79
76
|
}
|
|
80
77
|
}
|
|
81
|
-
return createSuccessResult({ nodes: 0, edges: 0 }, { summary,
|
|
78
|
+
return createSuccessResult({ nodes: 0, edges: 0 }, { summary }, warnings);
|
|
82
79
|
}
|
|
83
80
|
/**
|
|
84
|
-
*
|
|
81
|
+
* Determine the resolution type for a CALL node.
|
|
82
|
+
*
|
|
83
|
+
* Resolution priority:
|
|
84
|
+
* 1. Method call (has 'object' attribute) -> 'method'
|
|
85
|
+
* 2. Has CALLS edge to FUNCTION -> 'internal'
|
|
86
|
+
* 3. Has CALLS edge to EXTERNAL_MODULE -> 'external'
|
|
87
|
+
* 4. Name in JS_GLOBAL_FUNCTIONS -> 'builtin'
|
|
88
|
+
* 5. Otherwise -> 'unresolved'
|
|
85
89
|
*/
|
|
86
|
-
async
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
stats.resolved++;
|
|
90
|
+
async determineResolutionType(graph, callNode) {
|
|
91
|
+
// 1. Check if method call (has object attribute)
|
|
92
|
+
if (callNode.object) {
|
|
93
|
+
return 'method';
|
|
94
|
+
}
|
|
95
|
+
// 2. Check for CALLS edges
|
|
96
|
+
const edges = await graph.getOutgoingEdges(callNode.id, ['CALLS']);
|
|
97
|
+
if (edges.length > 0) {
|
|
98
|
+
// Determine destination type
|
|
99
|
+
const edge = edges[0];
|
|
100
|
+
const dstNode = await graph.getNode(edge.dst);
|
|
101
|
+
if (dstNode) {
|
|
102
|
+
if (dstNode.type === 'FUNCTION') {
|
|
103
|
+
return 'internal';
|
|
104
|
+
}
|
|
105
|
+
if (dstNode.type === 'EXTERNAL_MODULE') {
|
|
106
|
+
return 'external';
|
|
104
107
|
}
|
|
105
108
|
}
|
|
109
|
+
// Has edge but unknown destination type - treat as resolved
|
|
110
|
+
return 'internal';
|
|
111
|
+
}
|
|
112
|
+
// 3. Check if builtin
|
|
113
|
+
const calledName = callNode.name;
|
|
114
|
+
if (calledName && JS_GLOBAL_FUNCTIONS.has(calledName)) {
|
|
115
|
+
return 'builtin';
|
|
106
116
|
}
|
|
107
|
-
|
|
117
|
+
// 4. Unresolved
|
|
118
|
+
return 'unresolved';
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Create a warning for an unresolved call.
|
|
122
|
+
*/
|
|
123
|
+
createWarning(callNode) {
|
|
124
|
+
return new ValidationError(`Unresolved call to "${callNode.name}" at ${callNode.file}:${callNode.line || '?'}`, 'WARN_UNRESOLVED_CALL', {
|
|
125
|
+
filePath: callNode.file,
|
|
126
|
+
lineNumber: callNode.line,
|
|
127
|
+
phase: 'VALIDATION',
|
|
128
|
+
plugin: 'CallResolverValidator',
|
|
129
|
+
nodeId: callNode.id,
|
|
130
|
+
callName: callNode.name,
|
|
131
|
+
}, 'Ensure the function is defined, imported, or is a known global', 'warning' // Severity: warning (not error)
|
|
132
|
+
);
|
|
108
133
|
}
|
|
109
134
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DataFlowValidator.d.ts","sourceRoot":"","sources":["../../../src/plugins/validation/DataFlowValidator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,MAAM,EAAuB,MAAM,cAAc,CAAC;AAC3D,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"DataFlowValidator.d.ts","sourceRoot":"","sources":["../../../src/plugins/validation/DataFlowValidator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,MAAM,EAAuB,MAAM,cAAc,CAAC;AAC3D,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAgChF,qBAAa,iBAAkB,SAAQ,MAAM;IAC3C,IAAI,QAAQ,IAAI,cAAc,CAU7B;IAEK,OAAO,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC;IAwI5D;;OAEG;IACH,OAAO,CAAC,cAAc;CAsDvB"}
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
* - EVENT_LISTENER: события
|
|
13
13
|
*/
|
|
14
14
|
import { Plugin, createSuccessResult } from '../Plugin.js';
|
|
15
|
+
import { ValidationError } from '../../errors/GrafemaError.js';
|
|
15
16
|
export class DataFlowValidator extends Plugin {
|
|
16
17
|
get metadata() {
|
|
17
18
|
return {
|
|
@@ -38,7 +39,7 @@ export class DataFlowValidator extends Plugin {
|
|
|
38
39
|
const allEdges = await graph.getAllEdges();
|
|
39
40
|
const variables = allNodes.filter(n => n.type === 'VARIABLE_DECLARATION' || n.type === 'CONSTANT');
|
|
40
41
|
logger.debug('Variables collected', { count: variables.length });
|
|
41
|
-
const
|
|
42
|
+
const errors = [];
|
|
42
43
|
const leafTypes = new Set([
|
|
43
44
|
'LITERAL',
|
|
44
45
|
'net:stdio',
|
|
@@ -55,70 +56,69 @@ export class DataFlowValidator extends Plugin {
|
|
|
55
56
|
// Проверяем наличие ASSIGNED_FROM ребра
|
|
56
57
|
const assignment = allEdges.find(e => e.type === 'ASSIGNED_FROM' && e.src === variable.id);
|
|
57
58
|
if (!assignment) {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
59
|
+
errors.push(new ValidationError(`Variable "${variable.name}" (${variable.file}:${variable.line}) has no ASSIGNED_FROM edge`, 'ERR_MISSING_ASSIGNMENT', {
|
|
60
|
+
filePath: variable.file,
|
|
61
|
+
lineNumber: variable.line,
|
|
62
|
+
phase: 'VALIDATION',
|
|
63
|
+
plugin: 'DataFlowValidator',
|
|
62
64
|
variable: variable.name,
|
|
63
|
-
|
|
64
|
-
line: variable.line
|
|
65
|
-
});
|
|
65
|
+
}, undefined, 'warning'));
|
|
66
66
|
continue;
|
|
67
67
|
}
|
|
68
68
|
// Проверяем что источник существует
|
|
69
69
|
const source = allNodes.find(n => n.id === assignment.dst);
|
|
70
70
|
if (!source) {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
71
|
+
errors.push(new ValidationError(`Variable "${variable.name}" references non-existent node ${assignment.dst}`, 'ERR_BROKEN_REFERENCE', {
|
|
72
|
+
filePath: variable.file,
|
|
73
|
+
lineNumber: variable.line,
|
|
74
|
+
phase: 'VALIDATION',
|
|
75
|
+
plugin: 'DataFlowValidator',
|
|
75
76
|
variable: variable.name,
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
});
|
|
77
|
+
targetNodeId: assignment.dst,
|
|
78
|
+
}, undefined, 'error'));
|
|
79
79
|
continue;
|
|
80
80
|
}
|
|
81
81
|
// Проверяем путь до листового узла
|
|
82
82
|
const path = this.findPathToLeaf(variable, allNodes, allEdges, leafTypes);
|
|
83
83
|
if (!path.found) {
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
84
|
+
errors.push(new ValidationError(`Variable "${variable.name}" (${variable.file}:${variable.line}) does not trace to a leaf node. Chain: ${path.chain.join(' -> ')}`, 'ERR_NO_LEAF_NODE', {
|
|
85
|
+
filePath: variable.file,
|
|
86
|
+
lineNumber: variable.line,
|
|
87
|
+
phase: 'VALIDATION',
|
|
88
|
+
plugin: 'DataFlowValidator',
|
|
88
89
|
variable: variable.name,
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
chain: path.chain
|
|
92
|
-
});
|
|
90
|
+
chain: path.chain,
|
|
91
|
+
}, undefined, 'warning'));
|
|
93
92
|
}
|
|
94
93
|
}
|
|
95
|
-
// Группируем
|
|
94
|
+
// Группируем errors по коду
|
|
95
|
+
const byCode = {};
|
|
96
|
+
for (const error of errors) {
|
|
97
|
+
if (!byCode[error.code]) {
|
|
98
|
+
byCode[error.code] = 0;
|
|
99
|
+
}
|
|
100
|
+
byCode[error.code]++;
|
|
101
|
+
}
|
|
96
102
|
const summary = {
|
|
97
103
|
total: variables.length,
|
|
98
|
-
validated: variables.length -
|
|
99
|
-
issues:
|
|
100
|
-
byType:
|
|
104
|
+
validated: variables.length - errors.length,
|
|
105
|
+
issues: errors.length,
|
|
106
|
+
byType: byCode
|
|
101
107
|
};
|
|
102
|
-
for (const issue of issues) {
|
|
103
|
-
if (!summary.byType[issue.type]) {
|
|
104
|
-
summary.byType[issue.type] = 0;
|
|
105
|
-
}
|
|
106
|
-
summary.byType[issue.type]++;
|
|
107
|
-
}
|
|
108
108
|
logger.info('Validation complete', { ...summary });
|
|
109
|
-
// Выводим
|
|
110
|
-
if (
|
|
111
|
-
logger.warn('Data flow issues found', { count:
|
|
112
|
-
for (const
|
|
113
|
-
if (
|
|
114
|
-
logger.error(`[${
|
|
109
|
+
// Выводим errors
|
|
110
|
+
if (errors.length > 0) {
|
|
111
|
+
logger.warn('Data flow issues found', { count: errors.length });
|
|
112
|
+
for (const error of errors) {
|
|
113
|
+
if (error.severity === 'error') {
|
|
114
|
+
logger.error(`[${error.code}] ${error.message}`);
|
|
115
115
|
}
|
|
116
116
|
else {
|
|
117
|
-
logger.warn(`[${
|
|
117
|
+
logger.warn(`[${error.code}] ${error.message}`);
|
|
118
118
|
}
|
|
119
119
|
}
|
|
120
120
|
}
|
|
121
|
-
return createSuccessResult({ nodes: 0, edges: 0 }, { summary,
|
|
121
|
+
return createSuccessResult({ nodes: 0, edges: 0 }, { summary }, errors);
|
|
122
122
|
}
|
|
123
123
|
/**
|
|
124
124
|
* Находит путь от переменной до листового узла
|
|
@@ -134,6 +134,14 @@ export class DataFlowValidator extends Plugin {
|
|
|
134
134
|
if (leafTypes.has(startNode.type)) {
|
|
135
135
|
return { found: true, chain };
|
|
136
136
|
}
|
|
137
|
+
// REG-262: Check if variable is used by a method call (incoming USES edge)
|
|
138
|
+
// If something USES this variable, the variable is not dead
|
|
139
|
+
const usedByCall = allEdges.find(e => e.type === 'USES' && e.dst === startNode.id);
|
|
140
|
+
if (usedByCall) {
|
|
141
|
+
const callNode = allNodes.find(n => n.id === usedByCall.src);
|
|
142
|
+
const callName = callNode?.name ?? usedByCall.src;
|
|
143
|
+
return { found: true, chain: [...chain, `(used by ${callName})`] };
|
|
144
|
+
}
|
|
137
145
|
// Ищем ASSIGNED_FROM ребро
|
|
138
146
|
const assignment = allEdges.find(e => e.type === 'ASSIGNED_FROM' && e.src === startNode.id);
|
|
139
147
|
if (!assignment) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GraphConnectivityValidator.d.ts","sourceRoot":"","sources":["../../../src/plugins/validation/GraphConnectivityValidator.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,MAAM,EAAuB,MAAM,cAAc,CAAC;AAC3D,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"GraphConnectivityValidator.d.ts","sourceRoot":"","sources":["../../../src/plugins/validation/GraphConnectivityValidator.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,MAAM,EAAuB,MAAM,cAAc,CAAC;AAC3D,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AA0ChF,qBAAa,0BAA2B,SAAQ,MAAM;IACpD,IAAI,QAAQ,IAAI,cAAc,CAU7B;IAEK,OAAO,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC;CA6K7D"}
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
* Находит "островки" - узлы которые не имеют путей до SERVICE/MODULE
|
|
4
4
|
*/
|
|
5
5
|
import { Plugin, createSuccessResult } from '../Plugin.js';
|
|
6
|
+
import { ValidationError } from '../../errors/GrafemaError.js';
|
|
6
7
|
export class GraphConnectivityValidator extends Plugin {
|
|
7
8
|
get metadata() {
|
|
8
9
|
return {
|
|
@@ -73,6 +74,7 @@ export class GraphConnectivityValidator extends Plugin {
|
|
|
73
74
|
}
|
|
74
75
|
// Находим недостижимые узлы
|
|
75
76
|
const unreachable = allNodes.filter(n => !reachable.has(n.id));
|
|
77
|
+
const errors = [];
|
|
76
78
|
if (unreachable.length > 0) {
|
|
77
79
|
const percentage = ((unreachable.length / allNodes.length) * 100).toFixed(1);
|
|
78
80
|
logger.error('GRAPH VALIDATION ERROR: DISCONNECTED NODES FOUND');
|
|
@@ -116,6 +118,28 @@ export class GraphConnectivityValidator extends Plugin {
|
|
|
116
118
|
manifestWithValidation.validation.reachableNodes = reachable.size;
|
|
117
119
|
manifestWithValidation.validation.unreachableCount = unreachable.length;
|
|
118
120
|
manifestWithValidation.validation.unreachableByType = Object.fromEntries(Object.entries(byType).map(([type, nodes]) => [type, nodes.length]));
|
|
121
|
+
// Create summary error for disconnected nodes
|
|
122
|
+
errors.push(new ValidationError(`Found ${unreachable.length} unreachable nodes (${percentage}% of total)`, 'ERR_DISCONNECTED_NODES', {
|
|
123
|
+
phase: 'VALIDATION',
|
|
124
|
+
plugin: 'GraphConnectivityValidator',
|
|
125
|
+
totalNodes: allNodes.length,
|
|
126
|
+
reachableNodes: reachable.size,
|
|
127
|
+
unreachableCount: unreachable.length,
|
|
128
|
+
unreachableByType: Object.fromEntries(Object.entries(byType).map(([type, nodes]) => [type, nodes.length])),
|
|
129
|
+
}, 'Fix analysis plugins to ensure all nodes are connected'));
|
|
130
|
+
// Create individual errors for each disconnected node (limit to 50)
|
|
131
|
+
const maxIndividualErrors = 50;
|
|
132
|
+
for (const node of unreachable.slice(0, maxIndividualErrors)) {
|
|
133
|
+
errors.push(new ValidationError(`Node "${node.name || node.id}" (type: ${node.type}) is not connected to the main graph`, 'ERR_DISCONNECTED_NODE', {
|
|
134
|
+
filePath: node.file,
|
|
135
|
+
lineNumber: node.line,
|
|
136
|
+
phase: 'VALIDATION',
|
|
137
|
+
plugin: 'GraphConnectivityValidator',
|
|
138
|
+
nodeId: node.id,
|
|
139
|
+
nodeType: node.type,
|
|
140
|
+
nodeName: node.name,
|
|
141
|
+
}));
|
|
142
|
+
}
|
|
119
143
|
}
|
|
120
144
|
else {
|
|
121
145
|
logger.info('All nodes are reachable from root nodes');
|
|
@@ -126,6 +150,6 @@ export class GraphConnectivityValidator extends Plugin {
|
|
|
126
150
|
manifestWithValidation.validation.reachableNodes = reachable.size;
|
|
127
151
|
}
|
|
128
152
|
logger.info('Validation complete', { reachable: reachable.size, total: allNodes.length });
|
|
129
|
-
return createSuccessResult({ nodes: 0, edges: 0 }, { totalNodes: allNodes.length, reachableNodes: reachable.size });
|
|
153
|
+
return createSuccessResult({ nodes: 0, edges: 0 }, { totalNodes: allNodes.length, reachableNodes: reachable.size }, errors);
|
|
130
154
|
}
|
|
131
155
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SQLInjectionValidator.d.ts","sourceRoot":"","sources":["../../../src/plugins/validation/SQLInjectionValidator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAE,MAAM,EAAuB,MAAM,cAAc,CAAC;AAC3D,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAsEhF,qBAAa,qBAAsB,SAAQ,MAAM;IAC/C,OAAO,CAAC,aAAa,CAAsB;;IAO3C,IAAI,QAAQ,IAAI,cAAc,CAU7B;IAEK,OAAO,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC;IAgH5D;;OAEG;YACW,gBAAgB;
|
|
1
|
+
{"version":3,"file":"SQLInjectionValidator.d.ts","sourceRoot":"","sources":["../../../src/plugins/validation/SQLInjectionValidator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAE,MAAM,EAAuB,MAAM,cAAc,CAAC;AAC3D,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAsEhF,qBAAa,qBAAsB,SAAQ,MAAM;IAC/C,OAAO,CAAC,aAAa,CAAsB;;IAO3C,IAAI,QAAQ,IAAI,cAAc,CAU7B;IAEK,OAAO,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC;IAgH5D;;OAEG;YACW,gBAAgB;IA8E9B;;OAEG;YACW,gCAAgC;IAqC9C;;;OAGG;YACW,oBAAoB;CAsDnC;AAED,eAAe,qBAAqB,CAAC"}
|
|
@@ -149,7 +149,7 @@ export class SQLInjectionValidator extends Plugin {
|
|
|
149
149
|
// We need to check if it has nondeterministic content
|
|
150
150
|
// Check if this call has PASSES_ARGUMENT edges
|
|
151
151
|
const outgoing = await graph.getOutgoingEdges(call.id);
|
|
152
|
-
const argEdges = outgoing.filter(e =>
|
|
152
|
+
const argEdges = outgoing.filter(e => e.type === 'PASSES_ARGUMENT');
|
|
153
153
|
if (argEdges.length === 0) {
|
|
154
154
|
// No tracked arguments - check via queryArgName attribute if available
|
|
155
155
|
if (call.queryArgName) {
|
|
@@ -214,8 +214,7 @@ export class SQLInjectionValidator extends Plugin {
|
|
|
214
214
|
const result = { hasUnknown: false, sources: [] };
|
|
215
215
|
// Check DERIVES_FROM edges
|
|
216
216
|
const outgoing = await graph.getOutgoingEdges(exprNode.id);
|
|
217
|
-
const derivesFromEdges = outgoing.filter(e =>
|
|
218
|
-
(e.edgeType || e.edge_type) === 'ASSIGNED_FROM');
|
|
217
|
+
const derivesFromEdges = outgoing.filter(e => e.type === 'DERIVES_FROM' || e.type === 'ASSIGNED_FROM');
|
|
219
218
|
for (const edge of derivesFromEdges) {
|
|
220
219
|
const sourceId = edge.dst || edge.target_id;
|
|
221
220
|
const sourceNode = await graph.getNode(sourceId);
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Find all CALL and METHOD_CALL nodes inside a function.
|
|
3
|
+
*
|
|
4
|
+
* Graph structure:
|
|
5
|
+
* ```
|
|
6
|
+
* FUNCTION -[HAS_SCOPE]-> SCOPE -[CONTAINS]-> CALL
|
|
7
|
+
* SCOPE -[CONTAINS]-> METHOD_CALL
|
|
8
|
+
* SCOPE -[CONTAINS]-> SCOPE (nested blocks)
|
|
9
|
+
* ```
|
|
10
|
+
*
|
|
11
|
+
* Algorithm:
|
|
12
|
+
* 1. Get function's scope via HAS_SCOPE edge
|
|
13
|
+
* 2. BFS through CONTAINS edges, collecting CALL and METHOD_CALL nodes
|
|
14
|
+
* 3. Stop at nested FUNCTION/CLASS boundaries (don't enter inner functions)
|
|
15
|
+
* 4. For each call, check CALLS edge to determine if resolved
|
|
16
|
+
* 5. If transitive=true, recursively follow resolved CALLS edges
|
|
17
|
+
*
|
|
18
|
+
* Performance: O(S + C) where S = scopes, C = calls
|
|
19
|
+
* For functions with 100 calls, expect ~200 DB operations.
|
|
20
|
+
*
|
|
21
|
+
* @module queries/findCallsInFunction
|
|
22
|
+
*/
|
|
23
|
+
import type { CallInfo, FindCallsOptions } from './types.js';
|
|
24
|
+
/**
|
|
25
|
+
* Graph backend interface (minimal surface)
|
|
26
|
+
*/
|
|
27
|
+
interface GraphBackend {
|
|
28
|
+
getNode(id: string): Promise<{
|
|
29
|
+
id: string;
|
|
30
|
+
type: string;
|
|
31
|
+
name: string;
|
|
32
|
+
file?: string;
|
|
33
|
+
line?: number;
|
|
34
|
+
object?: string;
|
|
35
|
+
} | null>;
|
|
36
|
+
getOutgoingEdges(nodeId: string, edgeTypes: string[] | null): Promise<Array<{
|
|
37
|
+
src: string;
|
|
38
|
+
dst: string;
|
|
39
|
+
type: string;
|
|
40
|
+
}>>;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Find all CALL and METHOD_CALL nodes inside a function.
|
|
44
|
+
*
|
|
45
|
+
* @param backend - Graph backend for queries
|
|
46
|
+
* @param functionId - ID of the FUNCTION node
|
|
47
|
+
* @param options - Options for traversal
|
|
48
|
+
* @returns Array of CallInfo objects
|
|
49
|
+
*/
|
|
50
|
+
export declare function findCallsInFunction(backend: GraphBackend, functionId: string, options?: FindCallsOptions): Promise<CallInfo[]>;
|
|
51
|
+
export {};
|
|
52
|
+
//# sourceMappingURL=findCallsInFunction.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"findCallsInFunction.d.ts","sourceRoot":"","sources":["../../src/queries/findCallsInFunction.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAE7D;;GAEG;AACH,UAAU,YAAY;IACpB,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC;QAC3B,EAAE,EAAE,MAAM,CAAC;QACX,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,GAAG,IAAI,CAAC,CAAC;IACV,gBAAgB,CACd,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,EAAE,GAAG,IAAI,GACzB,OAAO,CAAC,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC,CAAC;CAC/D;AAED;;;;;;;GAOG;AACH,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,YAAY,EACrB,UAAU,EAAE,MAAM,EAClB,OAAO,GAAE,gBAAqB,GAC7B,OAAO,CAAC,QAAQ,EAAE,CAAC,CAkErB"}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Find all CALL and METHOD_CALL nodes inside a function.
|
|
3
|
+
*
|
|
4
|
+
* Graph structure:
|
|
5
|
+
* ```
|
|
6
|
+
* FUNCTION -[HAS_SCOPE]-> SCOPE -[CONTAINS]-> CALL
|
|
7
|
+
* SCOPE -[CONTAINS]-> METHOD_CALL
|
|
8
|
+
* SCOPE -[CONTAINS]-> SCOPE (nested blocks)
|
|
9
|
+
* ```
|
|
10
|
+
*
|
|
11
|
+
* Algorithm:
|
|
12
|
+
* 1. Get function's scope via HAS_SCOPE edge
|
|
13
|
+
* 2. BFS through CONTAINS edges, collecting CALL and METHOD_CALL nodes
|
|
14
|
+
* 3. Stop at nested FUNCTION/CLASS boundaries (don't enter inner functions)
|
|
15
|
+
* 4. For each call, check CALLS edge to determine if resolved
|
|
16
|
+
* 5. If transitive=true, recursively follow resolved CALLS edges
|
|
17
|
+
*
|
|
18
|
+
* Performance: O(S + C) where S = scopes, C = calls
|
|
19
|
+
* For functions with 100 calls, expect ~200 DB operations.
|
|
20
|
+
*
|
|
21
|
+
* @module queries/findCallsInFunction
|
|
22
|
+
*/
|
|
23
|
+
/**
|
|
24
|
+
* Find all CALL and METHOD_CALL nodes inside a function.
|
|
25
|
+
*
|
|
26
|
+
* @param backend - Graph backend for queries
|
|
27
|
+
* @param functionId - ID of the FUNCTION node
|
|
28
|
+
* @param options - Options for traversal
|
|
29
|
+
* @returns Array of CallInfo objects
|
|
30
|
+
*/
|
|
31
|
+
export async function findCallsInFunction(backend, functionId, options = {}) {
|
|
32
|
+
const { maxDepth = 10, transitive = false, transitiveDepth = 5, } = options;
|
|
33
|
+
const calls = [];
|
|
34
|
+
const visited = new Set();
|
|
35
|
+
const seenTargets = new Set(); // For deduplication in transitive mode
|
|
36
|
+
// Add the starting function to seenTargets to prevent cycles back to it
|
|
37
|
+
if (transitive) {
|
|
38
|
+
seenTargets.add(functionId);
|
|
39
|
+
}
|
|
40
|
+
// Step 1: Get function's scope via HAS_SCOPE
|
|
41
|
+
const hasScopeEdges = await backend.getOutgoingEdges(functionId, ['HAS_SCOPE']);
|
|
42
|
+
// BFS queue: { nodeId, currentDepth }
|
|
43
|
+
const queue = [];
|
|
44
|
+
for (const edge of hasScopeEdges) {
|
|
45
|
+
queue.push({ id: edge.dst, depth: 0 });
|
|
46
|
+
}
|
|
47
|
+
// Step 2: BFS through scopes
|
|
48
|
+
while (queue.length > 0) {
|
|
49
|
+
const { id, depth } = queue.shift();
|
|
50
|
+
if (visited.has(id) || depth > maxDepth)
|
|
51
|
+
continue;
|
|
52
|
+
visited.add(id);
|
|
53
|
+
const containsEdges = await backend.getOutgoingEdges(id, ['CONTAINS']);
|
|
54
|
+
for (const edge of containsEdges) {
|
|
55
|
+
const child = await backend.getNode(edge.dst);
|
|
56
|
+
if (!child)
|
|
57
|
+
continue;
|
|
58
|
+
// Collect CALL and METHOD_CALL nodes
|
|
59
|
+
if (child.type === 'CALL' || child.type === 'METHOD_CALL') {
|
|
60
|
+
const callInfo = await buildCallInfo(backend, child, 0);
|
|
61
|
+
calls.push(callInfo);
|
|
62
|
+
// Transitive: follow resolved calls
|
|
63
|
+
if (transitive && callInfo.resolved && callInfo.target) {
|
|
64
|
+
await collectTransitiveCalls(backend, callInfo.target.id, 1, // Starting at depth 1
|
|
65
|
+
transitiveDepth, calls, seenTargets);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
// Continue into nested scopes, but NOT into nested functions/classes
|
|
69
|
+
if (child.type === 'SCOPE') {
|
|
70
|
+
queue.push({ id: child.id, depth: depth + 1 });
|
|
71
|
+
}
|
|
72
|
+
// Skip FUNCTION, CLASS - they have their own scope hierarchy
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return calls;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Build CallInfo from a call node
|
|
79
|
+
*/
|
|
80
|
+
async function buildCallInfo(backend, callNode, depth) {
|
|
81
|
+
// Check for CALLS edge (resolved target)
|
|
82
|
+
const callsEdges = await backend.getOutgoingEdges(callNode.id, ['CALLS']);
|
|
83
|
+
const isResolved = callsEdges.length > 0;
|
|
84
|
+
let target = undefined;
|
|
85
|
+
if (isResolved) {
|
|
86
|
+
const targetNode = await backend.getNode(callsEdges[0].dst);
|
|
87
|
+
if (targetNode) {
|
|
88
|
+
target = {
|
|
89
|
+
id: targetNode.id,
|
|
90
|
+
name: targetNode.name,
|
|
91
|
+
file: targetNode.file,
|
|
92
|
+
line: targetNode.line,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return {
|
|
97
|
+
id: callNode.id,
|
|
98
|
+
name: callNode.name,
|
|
99
|
+
type: callNode.type,
|
|
100
|
+
object: callNode.object,
|
|
101
|
+
resolved: isResolved,
|
|
102
|
+
target,
|
|
103
|
+
file: callNode.file,
|
|
104
|
+
line: callNode.line,
|
|
105
|
+
depth,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Recursively collect transitive calls
|
|
110
|
+
*
|
|
111
|
+
* Infinite loop prevention:
|
|
112
|
+
* - Track seen function IDs in seenTargets
|
|
113
|
+
* - Stop when we've seen a function before (handles recursion)
|
|
114
|
+
* - Stop at transitiveDepth limit
|
|
115
|
+
*/
|
|
116
|
+
async function collectTransitiveCalls(backend, functionId, currentDepth, maxTransitiveDepth, calls, seenTargets) {
|
|
117
|
+
// Prevent infinite loops and limit depth
|
|
118
|
+
if (seenTargets.has(functionId) || currentDepth > maxTransitiveDepth) {
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
seenTargets.add(functionId);
|
|
122
|
+
// Find calls in this function (non-transitive to avoid recursion)
|
|
123
|
+
const innerCalls = await findCallsInFunction(backend, functionId, {
|
|
124
|
+
maxDepth: 10,
|
|
125
|
+
transitive: false,
|
|
126
|
+
});
|
|
127
|
+
for (const call of innerCalls) {
|
|
128
|
+
// Add with updated depth
|
|
129
|
+
calls.push({ ...call, depth: currentDepth });
|
|
130
|
+
// Continue transitively if resolved
|
|
131
|
+
if (call.resolved && call.target) {
|
|
132
|
+
await collectTransitiveCalls(backend, call.target.id, currentDepth + 1, maxTransitiveDepth, calls, seenTargets);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|