gitnexus 1.6.8-rc.8 → 1.6.8
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/README.md +3 -3
- package/dist/_shared/graph/types.d.ts +31 -1
- package/dist/_shared/graph/types.d.ts.map +1 -1
- package/dist/_shared/language-detection.d.ts.map +1 -1
- package/dist/_shared/language-detection.js +11 -1
- package/dist/_shared/language-detection.js.map +1 -1
- package/dist/_shared/lbug/schema-constants.d.ts +1 -1
- package/dist/_shared/lbug/schema-constants.d.ts.map +1 -1
- package/dist/_shared/lbug/schema-constants.js +6 -0
- package/dist/_shared/lbug/schema-constants.js.map +1 -1
- package/dist/_shared/scope-resolution/parsed-file.d.ts +21 -0
- package/dist/_shared/scope-resolution/parsed-file.d.ts.map +1 -1
- package/dist/_shared/scope-resolution/symbol-definition.d.ts +6 -0
- package/dist/_shared/scope-resolution/symbol-definition.d.ts.map +1 -1
- package/dist/cli/ai-context.d.ts +31 -1
- package/dist/cli/ai-context.js +18 -16
- package/dist/cli/analyze-config.js +11 -0
- package/dist/cli/analyze.d.ts +14 -0
- package/dist/cli/analyze.js +98 -0
- package/dist/cli/embedding-dims.d.ts +33 -0
- package/dist/cli/embedding-dims.js +39 -0
- package/dist/cli/eval-server.d.ts +8 -0
- package/dist/cli/eval-server.js +242 -2
- package/dist/cli/help-i18n.js +19 -0
- package/dist/cli/i18n/en.d.ts +15 -1
- package/dist/cli/i18n/en.js +15 -1
- package/dist/cli/i18n/resources.d.ts +29 -1
- package/dist/cli/i18n/zh-CN.d.ts +14 -0
- package/dist/cli/i18n/zh-CN.js +15 -1
- package/dist/cli/index.js +89 -1
- package/dist/cli/mcp.d.ts +6 -1
- package/dist/cli/mcp.js +26 -1
- package/dist/cli/optional-grammars.d.ts +6 -8
- package/dist/cli/optional-grammars.js +8 -11
- package/dist/cli/setup.d.ts +3 -1
- package/dist/cli/setup.js +67 -17
- package/dist/cli/skill-gen.js +2 -1
- package/dist/cli/tool.d.ts +19 -1
- package/dist/cli/tool.js +96 -3
- package/dist/core/embeddings/hf-env.d.ts +0 -66
- package/dist/core/embeddings/http-client.d.ts +7 -0
- package/dist/core/embeddings/http-client.js +5 -3
- package/dist/core/embeddings/server-mapping.d.ts +1 -1
- package/dist/core/embeddings/server-mapping.js +7 -3
- package/dist/core/graph/import-cycles.d.ts +10 -0
- package/dist/core/graph/import-cycles.js +103 -0
- package/dist/core/group/cross-impact.d.ts +2 -1
- package/dist/core/group/cross-impact.js +5 -1
- package/dist/core/group/extractors/grpc-patterns/proto.js +10 -6
- package/dist/core/group/extractors/http-patterns/kotlin.js +7 -7
- package/dist/core/group/extractors/http-route-extractor.d.ts +24 -0
- package/dist/core/group/extractors/http-route-extractor.js +22 -4
- package/dist/core/group/extractors/include-extractor.js +22 -13
- package/dist/core/group/sync.d.ts +27 -1
- package/dist/core/group/sync.js +0 -0
- package/dist/core/incremental/subgraph-extract.js +18 -1
- package/dist/core/ingestion/cfg/cfg-builder.d.ts +114 -0
- package/dist/core/ingestion/cfg/cfg-builder.js +196 -0
- package/dist/core/ingestion/cfg/collect.d.ts +51 -0
- package/dist/core/ingestion/cfg/collect.js +77 -0
- package/dist/core/ingestion/cfg/control-dependence.d.ts +58 -0
- package/dist/core/ingestion/cfg/control-dependence.js +182 -0
- package/dist/core/ingestion/cfg/control-flow-context.d.ts +106 -0
- package/dist/core/ingestion/cfg/control-flow-context.js +124 -0
- package/dist/core/ingestion/cfg/emit.d.ts +293 -0
- package/dist/core/ingestion/cfg/emit.js +646 -0
- package/dist/core/ingestion/cfg/post-dominators.d.ts +79 -0
- package/dist/core/ingestion/cfg/post-dominators.js +176 -0
- package/dist/core/ingestion/cfg/reaching-def-reason-codec.d.ts +106 -0
- package/dist/core/ingestion/cfg/reaching-def-reason-codec.js +133 -0
- package/dist/core/ingestion/cfg/reaching-defs-graph.d.ts +18 -0
- package/dist/core/ingestion/cfg/reaching-defs-graph.js +312 -0
- package/dist/core/ingestion/cfg/reaching-defs.d.ts +162 -0
- package/dist/core/ingestion/cfg/reaching-defs.js +785 -0
- package/dist/core/ingestion/cfg/synthetic-escape.d.ts +124 -0
- package/dist/core/ingestion/cfg/synthetic-escape.js +300 -0
- package/dist/core/ingestion/cfg/traversal-result.d.ts +20 -0
- package/dist/core/ingestion/cfg/traversal-result.js +2 -0
- package/dist/core/ingestion/cfg/types.d.ts +274 -0
- package/dist/core/ingestion/cfg/types.js +13 -0
- package/dist/core/ingestion/cfg/visitors/c-cpp-harvest.d.ts +111 -0
- package/dist/core/ingestion/cfg/visitors/c-cpp-harvest.js +541 -0
- package/dist/core/ingestion/cfg/visitors/c-cpp.d.ts +74 -0
- package/dist/core/ingestion/cfg/visitors/c-cpp.js +584 -0
- package/dist/core/ingestion/cfg/visitors/call-site-harvest.d.ts +195 -0
- package/dist/core/ingestion/cfg/visitors/call-site-harvest.js +350 -0
- package/dist/core/ingestion/cfg/visitors/csharp-harvest.d.ts +124 -0
- package/dist/core/ingestion/cfg/visitors/csharp-harvest.js +589 -0
- package/dist/core/ingestion/cfg/visitors/csharp.d.ts +87 -0
- package/dist/core/ingestion/cfg/visitors/csharp.js +867 -0
- package/dist/core/ingestion/cfg/visitors/dart-harvest.d.ts +278 -0
- package/dist/core/ingestion/cfg/visitors/dart-harvest.js +870 -0
- package/dist/core/ingestion/cfg/visitors/dart.d.ts +119 -0
- package/dist/core/ingestion/cfg/visitors/dart.js +836 -0
- package/dist/core/ingestion/cfg/visitors/go-harvest.d.ts +160 -0
- package/dist/core/ingestion/cfg/visitors/go-harvest.js +621 -0
- package/dist/core/ingestion/cfg/visitors/go.d.ts +108 -0
- package/dist/core/ingestion/cfg/visitors/go.js +638 -0
- package/dist/core/ingestion/cfg/visitors/java-harvest.d.ts +108 -0
- package/dist/core/ingestion/cfg/visitors/java-harvest.js +513 -0
- package/dist/core/ingestion/cfg/visitors/java.d.ts +101 -0
- package/dist/core/ingestion/cfg/visitors/java.js +812 -0
- package/dist/core/ingestion/cfg/visitors/kotlin-harvest.d.ts +253 -0
- package/dist/core/ingestion/cfg/visitors/kotlin-harvest.js +719 -0
- package/dist/core/ingestion/cfg/visitors/kotlin.d.ts +121 -0
- package/dist/core/ingestion/cfg/visitors/kotlin.js +809 -0
- package/dist/core/ingestion/cfg/visitors/php-harvest.d.ts +172 -0
- package/dist/core/ingestion/cfg/visitors/php-harvest.js +626 -0
- package/dist/core/ingestion/cfg/visitors/php.d.ts +96 -0
- package/dist/core/ingestion/cfg/visitors/php.js +721 -0
- package/dist/core/ingestion/cfg/visitors/python-harvest.d.ts +212 -0
- package/dist/core/ingestion/cfg/visitors/python-harvest.js +739 -0
- package/dist/core/ingestion/cfg/visitors/python.d.ts +103 -0
- package/dist/core/ingestion/cfg/visitors/python.js +558 -0
- package/dist/core/ingestion/cfg/visitors/ruby-harvest.d.ts +223 -0
- package/dist/core/ingestion/cfg/visitors/ruby-harvest.js +587 -0
- package/dist/core/ingestion/cfg/visitors/ruby.d.ts +112 -0
- package/dist/core/ingestion/cfg/visitors/ruby.js +756 -0
- package/dist/core/ingestion/cfg/visitors/rust-harvest.d.ts +324 -0
- package/dist/core/ingestion/cfg/visitors/rust-harvest.js +873 -0
- package/dist/core/ingestion/cfg/visitors/rust.d.ts +95 -0
- package/dist/core/ingestion/cfg/visitors/rust.js +558 -0
- package/dist/core/ingestion/cfg/visitors/scope-tree-harvest.d.ts +87 -0
- package/dist/core/ingestion/cfg/visitors/scope-tree-harvest.js +116 -0
- package/dist/core/ingestion/cfg/visitors/swift-harvest.d.ts +255 -0
- package/dist/core/ingestion/cfg/visitors/swift-harvest.js +679 -0
- package/dist/core/ingestion/cfg/visitors/swift.d.ts +116 -0
- package/dist/core/ingestion/cfg/visitors/swift.js +787 -0
- package/dist/core/ingestion/cfg/visitors/typescript-harvest.d.ts +149 -0
- package/dist/core/ingestion/cfg/visitors/typescript-harvest.js +1056 -0
- package/dist/core/ingestion/cfg/visitors/typescript.d.ts +66 -0
- package/dist/core/ingestion/cfg/visitors/typescript.js +583 -0
- package/dist/core/ingestion/import-resolvers/utils.js +2 -0
- package/dist/core/ingestion/language-provider.d.ts +23 -2
- package/dist/core/ingestion/languages/c-cpp.js +17 -5
- package/dist/core/ingestion/languages/cobol.js +4 -0
- package/dist/core/ingestion/languages/cpp/arity-metadata.js +41 -2
- package/dist/core/ingestion/languages/cpp/captures.js +50 -1
- package/dist/core/ingestion/languages/cpp/conversion-rank.d.ts +2 -0
- package/dist/core/ingestion/languages/cpp/conversion-rank.js +89 -0
- package/dist/core/ingestion/languages/cpp/header-scan.d.ts +1 -1
- package/dist/core/ingestion/languages/cpp/header-scan.js +2 -2
- package/dist/core/ingestion/languages/cpp/inline-namespaces.js +7 -2
- package/dist/core/ingestion/languages/cpp/member-lookup.js +2 -1
- package/dist/core/ingestion/languages/cpp/query.js +23 -0
- package/dist/core/ingestion/languages/cpp/scope-resolver.js +2 -1
- package/dist/core/ingestion/languages/csharp.js +2 -0
- package/dist/core/ingestion/languages/dart.js +2 -0
- package/dist/core/ingestion/languages/go.js +2 -0
- package/dist/core/ingestion/languages/java.js +3 -0
- package/dist/core/ingestion/languages/kotlin/query.js +3 -2
- package/dist/core/ingestion/languages/kotlin.js +8 -1
- package/dist/core/ingestion/languages/php.js +2 -0
- package/dist/core/ingestion/languages/python.js +2 -0
- package/dist/core/ingestion/languages/ruby.js +2 -0
- package/dist/core/ingestion/languages/rust.js +2 -0
- package/dist/core/ingestion/languages/swift.js +2 -0
- package/dist/core/ingestion/languages/typescript.js +5 -0
- package/dist/core/ingestion/languages/vue.js +6 -0
- package/dist/core/ingestion/method-extractors/configs/c-cpp.js +6 -13
- package/dist/core/ingestion/method-extractors/generic.js +1 -0
- package/dist/core/ingestion/method-types.d.ts +2 -0
- package/dist/core/ingestion/model/symbol-table.d.ts +1 -0
- package/dist/core/ingestion/model/symbol-table.js +1 -0
- package/dist/core/ingestion/mro-processor.js +109 -0
- package/dist/core/ingestion/parsing-processor.js +44 -0
- package/dist/core/ingestion/pipeline-phases/call-summaries.d.ts +26 -0
- package/dist/core/ingestion/pipeline-phases/call-summaries.js +46 -0
- package/dist/core/ingestion/pipeline-phases/index.d.ts +2 -0
- package/dist/core/ingestion/pipeline-phases/index.js +2 -0
- package/dist/core/ingestion/pipeline-phases/parse-impl.d.ts +0 -21
- package/dist/core/ingestion/pipeline-phases/parse-impl.js +18 -1
- package/dist/core/ingestion/pipeline-phases/routes.d.ts +10 -0
- package/dist/core/ingestion/pipeline-phases/routes.js +30 -1
- package/dist/core/ingestion/pipeline-phases/taint-summaries.d.ts +30 -0
- package/dist/core/ingestion/pipeline-phases/taint-summaries.js +81 -0
- package/dist/core/ingestion/pipeline.d.ts +92 -10
- package/dist/core/ingestion/pipeline.js +11 -2
- package/dist/core/ingestion/scope-extractor.js +12 -2
- package/dist/core/ingestion/scope-resolution/contract/scope-resolver.d.ts +9 -0
- package/dist/core/ingestion/scope-resolution/graph-bridge/callee-id-sink.d.ts +75 -0
- package/dist/core/ingestion/scope-resolution/graph-bridge/callee-id-sink.js +67 -0
- package/dist/core/ingestion/scope-resolution/graph-bridge/edges.d.ts +12 -2
- package/dist/core/ingestion/scope-resolution/graph-bridge/edges.js +14 -2
- package/dist/core/ingestion/scope-resolution/graph-bridge/references-to-edges.d.ts +6 -1
- package/dist/core/ingestion/scope-resolution/graph-bridge/references-to-edges.js +13 -1
- package/dist/core/ingestion/scope-resolution/passes/free-call-fallback.d.ts +9 -1
- package/dist/core/ingestion/scope-resolution/passes/free-call-fallback.js +28 -2
- package/dist/core/ingestion/scope-resolution/passes/overload-narrowing.d.ts +4 -0
- package/dist/core/ingestion/scope-resolution/passes/overload-narrowing.js +9 -0
- package/dist/core/ingestion/scope-resolution/passes/receiver-bound-calls.d.ts +6 -1
- package/dist/core/ingestion/scope-resolution/passes/receiver-bound-calls.js +174 -40
- package/dist/core/ingestion/scope-resolution/pipeline/phase.d.ts +24 -0
- package/dist/core/ingestion/scope-resolution/pipeline/phase.js +276 -190
- package/dist/core/ingestion/scope-resolution/pipeline/reconcile-ownership.js +43 -3
- package/dist/core/ingestion/scope-resolution/pipeline/run.d.ts +75 -0
- package/dist/core/ingestion/scope-resolution/pipeline/run.js +349 -1
- package/dist/core/ingestion/scope-resolution/resolution-outcome.d.ts +1 -1
- package/dist/core/ingestion/taint/call-summary-codec.d.ts +75 -0
- package/dist/core/ingestion/taint/call-summary-codec.js +128 -0
- package/dist/core/ingestion/taint/call-summary-emit.d.ts +43 -0
- package/dist/core/ingestion/taint/call-summary-emit.js +70 -0
- package/dist/core/ingestion/taint/call-summary-harvest.d.ts +77 -0
- package/dist/core/ingestion/taint/call-summary-harvest.js +179 -0
- package/dist/core/ingestion/taint/call-summary-model.d.ts +47 -0
- package/dist/core/ingestion/taint/call-summary-model.js +25 -0
- package/dist/core/ingestion/taint/emit.d.ts +125 -0
- package/dist/core/ingestion/taint/emit.js +208 -0
- package/dist/core/ingestion/taint/interproc-emit.d.ts +50 -0
- package/dist/core/ingestion/taint/interproc-emit.js +88 -0
- package/dist/core/ingestion/taint/interproc-solver.d.ts +110 -0
- package/dist/core/ingestion/taint/interproc-solver.js +312 -0
- package/dist/core/ingestion/taint/match.d.ts +153 -0
- package/dist/core/ingestion/taint/match.js +278 -0
- package/dist/core/ingestion/taint/path-codec.d.ts +134 -0
- package/dist/core/ingestion/taint/path-codec.js +190 -0
- package/dist/core/ingestion/taint/propagate.d.ts +216 -0
- package/dist/core/ingestion/taint/propagate.js +659 -0
- package/dist/core/ingestion/taint/site-safety.d.ts +29 -0
- package/dist/core/ingestion/taint/site-safety.js +98 -0
- package/dist/core/ingestion/taint/source-sink-config.d.ts +107 -23
- package/dist/core/ingestion/taint/source-sink-config.js +35 -12
- package/dist/core/ingestion/taint/source-sink-registry.d.ts +6 -4
- package/dist/core/ingestion/taint/source-sink-registry.js +6 -4
- package/dist/core/ingestion/taint/summary-harvest-driver.d.ts +80 -0
- package/dist/core/ingestion/taint/summary-harvest-driver.js +179 -0
- package/dist/core/ingestion/taint/summary-harvest.d.ts +89 -0
- package/dist/core/ingestion/taint/summary-harvest.js +537 -0
- package/dist/core/ingestion/taint/summary-model.d.ts +200 -0
- package/dist/core/ingestion/taint/summary-model.js +86 -0
- package/dist/core/ingestion/taint/typescript-model.d.ts +38 -0
- package/dist/core/ingestion/taint/typescript-model.js +102 -0
- package/dist/core/ingestion/type-extractors/c-cpp.js +21 -0
- package/dist/core/ingestion/utils/env.d.ts +7 -0
- package/dist/core/ingestion/utils/env.js +12 -0
- package/dist/core/ingestion/utils/method-props.js +1 -0
- package/dist/core/ingestion/workers/clone-safety.d.ts +109 -0
- package/dist/core/ingestion/workers/clone-safety.js +465 -0
- package/dist/core/ingestion/workers/parse-worker.d.ts +23 -0
- package/dist/core/ingestion/workers/parse-worker.js +81 -53
- package/dist/core/ingestion/workers/post-result.d.ts +22 -0
- package/dist/core/ingestion/workers/post-result.js +87 -0
- package/dist/core/ingestion/workers/result-merge.d.ts +20 -0
- package/dist/core/ingestion/workers/result-merge.js +43 -0
- package/dist/core/ingestion/workers/worker-pool.d.ts +15 -40
- package/dist/core/ingestion/workers/worker-pool.js +43 -16
- package/dist/core/lbug/csv-generator.d.ts +51 -3
- package/dist/core/lbug/csv-generator.js +369 -255
- package/dist/core/lbug/lbug-adapter.d.ts +58 -18
- package/dist/core/lbug/lbug-adapter.js +346 -84
- package/dist/core/lbug/lbug-config.d.ts +19 -0
- package/dist/core/lbug/lbug-config.js +29 -0
- package/dist/core/lbug/pdg-emit-sink.d.ts +127 -0
- package/dist/core/lbug/pdg-emit-sink.js +358 -0
- package/dist/core/lbug/pool-adapter.d.ts +35 -0
- package/dist/core/lbug/pool-adapter.js +90 -1
- package/dist/core/lbug/rel-pair-routing.d.ts +54 -0
- package/dist/core/lbug/rel-pair-routing.js +140 -0
- package/dist/core/lbug/schema.d.ts +2 -2
- package/dist/core/lbug/schema.js +3 -0
- package/dist/core/logger.d.ts +0 -5
- package/dist/core/run-analyze.d.ts +96 -0
- package/dist/core/run-analyze.js +207 -3
- package/dist/core/tree-sitter/parser-loader.js +5 -4
- package/dist/core/tree-sitter/safe-parse.d.ts +0 -5
- package/dist/core/tree-sitter/vendored-grammars.d.ts +39 -0
- package/dist/core/tree-sitter/vendored-grammars.js +57 -0
- package/dist/core/wiki/generator.js +3 -1
- package/dist/core/wiki/graph-queries.d.ts +6 -0
- package/dist/core/wiki/graph-queries.js +9 -1
- package/dist/mcp/http-transport.d.ts +134 -0
- package/dist/mcp/http-transport.js +503 -0
- package/dist/mcp/local/local-backend.d.ts +110 -24
- package/dist/mcp/local/local-backend.js +1225 -19
- package/dist/mcp/local/pdg-impact.d.ts +384 -0
- package/dist/mcp/local/pdg-impact.js +1972 -0
- package/dist/mcp/resources.js +13 -1
- package/dist/mcp/tools.d.ts +12 -0
- package/dist/mcp/tools.js +214 -7
- package/dist/server/analyze-launch.d.ts +29 -0
- package/dist/server/analyze-launch.js +137 -0
- package/dist/server/analyze-upload.d.ts +33 -0
- package/dist/server/analyze-upload.js +123 -0
- package/dist/server/analyze-worker-ipc.d.ts +58 -0
- package/dist/server/analyze-worker-ipc.js +16 -0
- package/dist/server/analyze-worker.d.ts +17 -1
- package/dist/server/analyze-worker.js +7 -1
- package/dist/server/api.d.ts +17 -0
- package/dist/server/api.js +132 -168
- package/dist/server/git-clone.d.ts +43 -2
- package/dist/server/git-clone.js +211 -16
- package/dist/server/mcp-http.d.ts +5 -6
- package/dist/server/mcp-http.js +9 -82
- package/dist/server/middleware.d.ts +40 -0
- package/dist/server/middleware.js +92 -0
- package/dist/server/private-ip.d.ts +1 -0
- package/dist/server/private-ip.js +15 -0
- package/dist/server/upload-ingest.d.ts +56 -0
- package/dist/server/upload-ingest.js +276 -0
- package/dist/server/upload-paths.d.ts +37 -0
- package/dist/server/upload-paths.js +57 -0
- package/dist/server/upload-sweep.d.ts +20 -0
- package/dist/server/upload-sweep.js +57 -0
- package/dist/storage/git.js +5 -8
- package/dist/storage/parse-cache.d.ts +22 -1
- package/dist/storage/parse-cache.js +44 -10
- package/dist/storage/repo-manager.d.ts +121 -10
- package/dist/storage/repo-manager.js +43 -5
- package/dist/types/pipeline.d.ts +9 -0
- package/hooks/antigravity/gitnexus-antigravity-hook.cjs +110 -10
- package/hooks/claude/gitnexus-hook.cjs +110 -13
- package/hooks/claude/hook-db-lock-probe.cjs +513 -26
- package/package.json +8 -2
- package/scripts/assert-publish-grammar-coverage.cjs +31 -0
- package/scripts/build-tree-sitter-grammars.cjs +16 -10
- package/scripts/cross-platform-tests.ts +1 -0
- package/skills/gitnexus-debugging.md +16 -4
- package/skills/gitnexus-exploring.md +3 -3
- package/skills/gitnexus-guide.md +33 -0
- package/skills/gitnexus-pdg-query.md +89 -0
- package/skills/gitnexus-refactoring.md +1 -1
- package/skills/gitnexus-taint-analysis.md +178 -0
- package/vendor/tree-sitter-c/package.json +1 -1
- package/vendor/tree-sitter-dart/package.json +1 -1
- package/vendor/tree-sitter-kotlin/package.json +1 -1
- package/vendor/tree-sitter-proto/package.json +1 -1
- package/vendor/tree-sitter-swift/package.json +1 -1
- package/web/assets/{agent-CKPMqImC.js → agent-D3Xd7zZE.js} +123 -123
- package/web/assets/architecture-7EHR7CIX-6QZW5X65-DxJw65fT.js +1 -0
- package/web/assets/architectureDiagram-UL44E2DR-ChH9xW-N.js +36 -0
- package/web/assets/{blockDiagram-7IZFK4PR-B4niSLvR.js → blockDiagram-7IZFK4PR-BkWhpzWB.js} +1 -1
- package/web/assets/{c4Diagram-Y2BXMSZH-DIzEXalR.js → c4Diagram-Y2BXMSZH-DtBvpzWD.js} +1 -1
- package/web/assets/{chunk-3SSMPTDK-BzGeeheI.js → chunk-3SSMPTDK-B4_etUhr.js} +2 -2
- package/web/assets/{chunk-5IMINLNL-CnTLsXIV.js → chunk-5IMINLNL-DOdTeQri.js} +1 -1
- package/web/assets/{chunk-5VCL7Z4A-w1BCx98Z.js → chunk-5VCL7Z4A-CQ-2dYWj.js} +1 -1
- package/web/assets/chunk-6764PJDD-DpIS7hxD.js +1 -0
- package/web/assets/{chunk-67TQ5CYL-CChC2cAv.js → chunk-67TQ5CYL-4sNPJU1q.js} +3 -3
- package/web/assets/{chunk-7W6UQGC5-CgFyfZ6k.js → chunk-7W6UQGC5-KyEG0HQg.js} +1 -1
- package/web/assets/{chunk-AZZRMDJM-5E9ARdDQ.js → chunk-AZZRMDJM-y-xJBuMz.js} +1 -1
- package/web/assets/{chunk-INKRHTLW-ELpfuk9h.js → chunk-INKRHTLW-Nu4ri9P-.js} +1 -1
- package/web/assets/{chunk-JQRUD6KW-Dcq_Qnyy.js → chunk-JQRUD6KW-Dbva2Z17.js} +1 -1
- package/web/assets/{chunk-KGFNY3KK-W-VR57xb.js → chunk-KGFNY3KK-JGMJvKCK.js} +1 -1
- package/web/assets/chunk-KGYTTC2M-CWC_c3H9.js +161 -0
- package/web/assets/{chunk-KNLZD3CH-BuZBOcso.js → chunk-KNLZD3CH-BGlP6X9R.js} +1 -1
- package/web/assets/{chunk-KRXBNO2N-DH2NPM7I.js → chunk-KRXBNO2N-BW5o0KUN.js} +1 -1
- package/web/assets/{chunk-LCXTWHL2-Dfmux4m1.js → chunk-LCXTWHL2-zoomRtWX.js} +1 -1
- package/web/assets/{chunk-LII3EMHJ-3X33tCpU.js → chunk-LII3EMHJ-D-jm-dLa.js} +1 -1
- package/web/assets/{chunk-QA3QBVWF-D5Ha3GgB.js → chunk-QA3QBVWF-BgRW3SXd.js} +1 -1
- package/web/assets/{chunk-RG4AUYOV-CAkzcoRj.js → chunk-RG4AUYOV-DD0B2N2B.js} +1 -1
- package/web/assets/{chunk-T2UQINTJ-kGYG7ppP.js → chunk-T2UQINTJ-DSBqkzH7.js} +1 -1
- package/web/assets/chunk-T5OCTHI4-DdZvN-9i.js +1 -0
- package/web/assets/{chunk-UY5QBCOK-Du-c56gs.js → chunk-UY5QBCOK-DyF0vyGd.js} +1 -1
- package/web/assets/{chunk-W44A43WB-lrCpuupA.js → chunk-W44A43WB-JqMLIpR0.js} +1 -1
- package/web/assets/{chunk-ZXARS5L4-CSZRiyOf.js → chunk-ZXARS5L4-CxN8oiwI.js} +1 -1
- package/web/assets/classDiagram-KGZ6W3CR-DJm9BgF-.js +1 -0
- package/web/assets/classDiagram-v2-72OJOZXJ-DJm9BgF-.js +1 -0
- package/web/assets/{context-builder-_HS0v2ma.js → context-builder-BHiFUA8O.js} +10 -2
- package/web/assets/{cose-bilkent-UX7MHV2Q-BHv2bbtl.js → cose-bilkent-UX7MHV2Q-D71wNYRJ.js} +1 -1
- package/web/assets/dagre-ND4H6XIP-BIkxmhcu.js +4 -0
- package/web/assets/diagram-3NCE3AQN-BTa6iH0T.js +43 -0
- package/web/assets/diagram-GF46GFSD-DZDV0vBj.js +24 -0
- package/web/assets/{diagram-HNR7UZ2L-fUWreZzx.js → diagram-HNR7UZ2L-DFCfd5LI.js} +2 -2
- package/web/assets/diagram-QXG6HAR7-BzM--Jj0.js +24 -0
- package/web/assets/diagram-WEQXMOUZ-DFFwz0k4.js +10 -0
- package/web/assets/{erDiagram-L5TCEMPS-QN2eEP1e.js → erDiagram-L5TCEMPS-CfHMJJqo.js} +1 -1
- package/web/assets/eventmodeling-FCH6USID-MREXMVOE-BQm9QzEa.js +1 -0
- package/web/assets/{flowDiagram-H6V6AXG4-CXbXImlN.js → flowDiagram-H6V6AXG4-Be805QiJ.js} +3 -3
- package/web/assets/{ganttDiagram-JCBTUEKG-BHQssTz6.js → ganttDiagram-JCBTUEKG-D3iL2Aet.js} +1 -1
- package/web/assets/gitGraph-WXDBUCRP-R675I2BI-Cr_Bm2Nb.js +1 -0
- package/web/assets/gitGraphDiagram-S2ZK5IYY-CPIDgxGm.js +106 -0
- package/web/assets/index-BvYev1UJ.js +635 -0
- package/web/assets/index-_lgn7hs5.css +2 -0
- package/web/assets/info-J43DQDTF-KCYPFFUO-Cs4p2oyk.js +1 -0
- package/web/assets/infoDiagram-3YFTVSEB-Y7BKSoke.js +2 -0
- package/web/assets/{ishikawaDiagram-BNXS4ZKH-6LKOvBfp.js → ishikawaDiagram-BNXS4ZKH-CT4SHFuI.js} +1 -1
- package/web/assets/{journeyDiagram-M6C3CM3L-DNPYCpvq.js → journeyDiagram-M6C3CM3L-CvArszLo.js} +1 -1
- package/web/assets/{kanban-definition-75IXJCU3-DgDi9oJT.js → kanban-definition-75IXJCU3-C6yDxr7N.js} +3 -3
- package/web/assets/{katex-K3KEBU37-CrVLz8l7.js → katex-K3KEBU37-CTc5BslQ.js} +1 -1
- package/web/assets/{mindmap-definition-2TDM6QVE-CwR5sBB-.js → mindmap-definition-2TDM6QVE-BOc2WEne.js} +1 -1
- package/web/assets/packet-YPE3B663-LP52Z2RK-CKCrztD2.js +1 -0
- package/web/assets/pie-LRSECV5Y-TCRJHUBD-BB7pHqoD.js +1 -0
- package/web/assets/{pieDiagram-CU6KROY3-By8g6f6B.js → pieDiagram-CU6KROY3-Cvc0f_Pd.js} +1 -1
- package/web/assets/{quadrantDiagram-VICAPDV7-bAm6Hi_5.js → quadrantDiagram-VICAPDV7-yXSZ2lLz.js} +1 -1
- package/web/assets/radar-GUYGQ44K-RDLRG3WG-DhoTOcuK.js +1 -0
- package/web/assets/{requirementDiagram-JXO7QTGE-7oDcJ1_J.js → requirementDiagram-JXO7QTGE-BRcZvHs4.js} +1 -1
- package/web/assets/{sankeyDiagram-URQDO5SZ-LFJz53u5.js → sankeyDiagram-URQDO5SZ-1qEjlFIB.js} +1 -1
- package/web/assets/{sequenceDiagram-VS2MUI6T-FySeKCUy.js → sequenceDiagram-VS2MUI6T-PcSCuvrB.js} +3 -3
- package/web/assets/stateDiagram-7D4R322I-D6qYSV1E.js +1 -0
- package/web/assets/stateDiagram-v2-36443NZ5-Bg-ImOSX.js +1 -0
- package/web/assets/{timeline-definition-O6YCAMPW-Ds2CnVZK.js → timeline-definition-O6YCAMPW-QWkh01xw.js} +1 -1
- package/web/assets/treeView-BLDUP644-QA4HXRO3-ODehyGKL.js +1 -0
- package/web/assets/treemap-LRROVOQU-LLAWBHMP-BfpgC-7o.js +1 -0
- package/web/assets/{vennDiagram-MWXL3ELB-DUIEwXWp.js → vennDiagram-MWXL3ELB-ak4DfwuM.js} +3 -3
- package/web/assets/wardley-L42UT6IY-5TKZOOLJ-CNeL6VHE.js +1 -0
- package/web/assets/{wardleyDiagram-CUQ6CDDI-DEiFPQih.js → wardleyDiagram-CUQ6CDDI-CTzR4Loq.js} +1 -1
- package/web/assets/{xychartDiagram-N2JHSOCM-BUbayhST.js → xychartDiagram-N2JHSOCM-DA1BEaQz.js} +1 -1
- package/web/index.html +13 -15
- package/scripts/materialize-vendor-grammars.cjs +0 -97
- package/web/assets/architecture-7EHR7CIX-6QZW5X65-BETj2x4g.js +0 -1
- package/web/assets/architectureDiagram-UL44E2DR-D1EXI0zA.js +0 -36
- package/web/assets/chunk-2T2R6R2M-n6s9JZqv.js +0 -4
- package/web/assets/chunk-2UTLFMKG-CMBB1TMN.js +0 -1
- package/web/assets/chunk-4R4BOZG6-mKhL59ul.js +0 -159
- package/web/assets/chunk-6764PJDD-ChwMM2z4.js +0 -1
- package/web/assets/chunk-7J6CGLKN-DT-b53FT.js +0 -10
- package/web/assets/chunk-C62D2QBJ-CDAWj26E.js +0 -1
- package/web/assets/chunk-CEXFNPSA-D68Tk6ls.js +0 -1
- package/web/assets/chunk-CilyBKbf.js +0 -1
- package/web/assets/chunk-J5EP6P6S-DxWW0yvu.js +0 -1
- package/web/assets/chunk-KGYTTC2M-C6PHeuay.js +0 -1
- package/web/assets/chunk-RERM46MO-DQNbXtfw.js +0 -1
- package/web/assets/chunk-RKZBBQEN-BmTPLSyv.js +0 -1
- package/web/assets/chunk-RLI5ZMPA-DExu2DOK.js +0 -1
- package/web/assets/chunk-T5OCTHI4--9wWpVws.js +0 -1
- package/web/assets/chunk-UP6H54XL-DsKdC6jC.js +0 -1
- package/web/assets/chunk-UXSXWOXI-DR81EqLr.js +0 -1
- package/web/assets/classDiagram-KGZ6W3CR-Bv93af_b.js +0 -1
- package/web/assets/classDiagram-v2-72OJOZXJ-CLfEqHUa.js +0 -1
- package/web/assets/dagre-ND4H6XIP-DsIr9MOv.js +0 -4
- package/web/assets/diagram-3NCE3AQN-BqAtKUpW.js +0 -43
- package/web/assets/diagram-GF46GFSD-CaBG6n6o.js +0 -24
- package/web/assets/diagram-QXG6HAR7-CZ-O3rcV.js +0 -24
- package/web/assets/diagram-WEQXMOUZ-P4lSL4GH.js +0 -10
- package/web/assets/eventmodeling-FCH6USID-MREXMVOE-B3myHUst.js +0 -1
- package/web/assets/gitGraph-WXDBUCRP-R675I2BI-DF3rtf4A.js +0 -1
- package/web/assets/gitGraphDiagram-S2ZK5IYY-CCwVLT__.js +0 -106
- package/web/assets/index-BKWA-m7o.css +0 -2
- package/web/assets/index-CG6q8eTs.js +0 -626
- package/web/assets/info-J43DQDTF-KCYPFFUO-R4XV_akJ.js +0 -1
- package/web/assets/infoDiagram-3YFTVSEB-DmLICZx1.js +0 -2
- package/web/assets/packet-YPE3B663-LP52Z2RK-CgQPdNZa.js +0 -1
- package/web/assets/pie-LRSECV5Y-TCRJHUBD-BzWOwc_c.js +0 -1
- package/web/assets/radar-GUYGQ44K-RDLRG3WG-B7KG0FN7.js +0 -1
- package/web/assets/stateDiagram-7D4R322I-CB2nABwH.js +0 -1
- package/web/assets/stateDiagram-v2-36443NZ5-COBGd2RL.js +0 -1
- package/web/assets/treeView-BLDUP644-QA4HXRO3-CRSxEwLO.js +0 -1
- package/web/assets/treemap-LRROVOQU-LLAWBHMP-a0PfKoVn.js +0 -1
- package/web/assets/wardley-L42UT6IY-5TKZOOLJ-BKQ6e5mC.js +0 -1
- /package/web/assets/{chunk-AQ6EADP3-CCFje6lL.js → chunk-AQ6EADP3-CZhslHi-.js} +0 -0
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* In-phase taint emission (#2083 M3 U4, plan KTD1/KTD6).
|
|
3
|
+
*
|
|
4
|
+
* Per-file driver for the M3 taint pass: gate → match → solve → propagate →
|
|
5
|
+
* persist sparse `TAINTED` + `SANITIZES` edges. Invoked from the pdg window in
|
|
6
|
+
* scope-resolution (`pipeline/run.ts`), immediately after `emitFileReachingDefs`
|
|
7
|
+
* inside the SAME per-file try — per-file isolation for free (KTD1). Mirrors
|
|
8
|
+
* `emitFileReachingDefs` (cfg/emit.ts) for the budget/dedup/warn discipline and
|
|
9
|
+
* the telemetry-result shape.
|
|
10
|
+
*
|
|
11
|
+
* ## Per-function pipeline (ordering is load-bearing)
|
|
12
|
+
*
|
|
13
|
+
* 1. `hasTaintSafeSites` — a corrupted-store site annotation degrades to
|
|
14
|
+
* SKIP-TAINT-KEEP-RD for this function (counted + warned), never a crash
|
|
15
|
+
* (KTD2; the matcher/propagator dereference indices unvalidated).
|
|
16
|
+
* 2. `matchFunctionSites` against the language spec (the import index is
|
|
17
|
+
* built ONCE per file — imports are a file-level fact).
|
|
18
|
+
* 3. ZERO-MATCH FAST PATH: the solver runs only when the function has at
|
|
19
|
+
* least one matched source AND one matched sink. In a typical repo almost
|
|
20
|
+
* no function has both; an unconditional second `computeReachingDefs` per
|
|
21
|
+
* function would ship a near-2× solve cost to every `--pdg` user.
|
|
22
|
+
* 4. `computeReachingDefs` with the taint `maxFacts` — by DEFAULT the M2
|
|
23
|
+
* derived `DEFAULT_PDG_MAX_REACHING_DEF_FACTS_PER_FUNCTION` (deliberate
|
|
24
|
+
* reuse, not a new constant: the fact-materialization envelope is a
|
|
25
|
+
* memory question, O(defs×uses), orthogonal to the findings cap, and M2
|
|
26
|
+
* already validated exactly this envelope on the same solver in the same
|
|
27
|
+
* window). The run.ts caller derives `limits.maxFacts` from the SAME
|
|
28
|
+
* RD-edge-cap formula `emitFileReachingDefs` uses, so taint coverage and
|
|
29
|
+
* RD coverage truncate together — a function is never `truncated` for one
|
|
30
|
+
* layer and `computed` for the other.
|
|
31
|
+
* 5. `computeTaintFlows` — a non-`computed` status is a per-function
|
|
32
|
+
* COVERAGE GAP (R4: counted by `gapReason`, function skipped entirely,
|
|
33
|
+
* never partially analyzed).
|
|
34
|
+
* 6. Emit one `TAINTED` edge per finding and one `SANITIZES` edge per kill.
|
|
35
|
+
* Kills are emitted even when findings are zero — a fully-sanitized
|
|
36
|
+
* function's kills are exactly its evidence of safety.
|
|
37
|
+
*
|
|
38
|
+
* ## Identity, dedup, budget (KTD6)
|
|
39
|
+
*
|
|
40
|
+
* Findings carry STATEMENT-LEVEL identity — function anchor + sink kind +
|
|
41
|
+
* source occurrence (point/site/object-binding/property) + sink occurrence
|
|
42
|
+
* (point/site/arg/binding) — NOT the REACHING_DEF block-level key (block-pair
|
|
43
|
+
* conflation would drop `exec(req.body, req.query)`'s second finding). The
|
|
44
|
+
* propagation engine dedups by this exact key BEFORE its deterministic cap
|
|
45
|
+
* (`maxFindingsPerFunction`) and counts the overflow; this module templates
|
|
46
|
+
* the same coordinates into the edge id (binding identity via the shared
|
|
47
|
+
* `bindingKey`; the free-text `property` rides LAST so it can never collide
|
|
48
|
+
* into another component) and warns with the drop count on truncation.
|
|
49
|
+
*
|
|
50
|
+
* `reason` carries the versioned hop encoding (`taint/path-codec.ts` — U6's
|
|
51
|
+
* `explain` decodes the same module) for `TAINTED`, and the killed binding's
|
|
52
|
+
* plain name for `SANITIZES` (M0/S1 queryability verdict, like REACHING_DEF).
|
|
53
|
+
*
|
|
54
|
+
* ## Warn split (R4 vs noise)
|
|
55
|
+
*
|
|
56
|
+
* Unsafe-site skips and cap drops warn PER FUNCTION here (rare, actionable —
|
|
57
|
+
* mirrors `emitFileReachingDefs`' malformed/cap warns). Solver coverage gaps
|
|
58
|
+
* (`truncated`/`overflow`) do NOT re-warn per function: the RD layer already
|
|
59
|
+
* warned for the same function with the same solver status (same `maxFacts`
|
|
60
|
+
* derivation — see step 4), and a duplicate `[taint]` line per mega-function
|
|
61
|
+
* would be pure spam. They are counted (+ exampled) in the result and the
|
|
62
|
+
* run.ts caller aggregates them into ONE unconditional `logger.warn` per
|
|
63
|
+
* language (R4) — never dropped on the floor (the M2 lesson).
|
|
64
|
+
*/
|
|
65
|
+
import type { ParsedImport } from '../../../_shared/index.js';
|
|
66
|
+
import type { KnowledgeGraph } from '../../graph/types.js';
|
|
67
|
+
import { type ReachingDefsSolver } from '../cfg/reaching-defs.js';
|
|
68
|
+
import type { FunctionCfg } from '../cfg/types.js';
|
|
69
|
+
export { DEFAULT_PDG_MAX_TAINT_FINDINGS_PER_FUNCTION, DEFAULT_PDG_MAX_TAINT_HOPS, } from './propagate.js';
|
|
70
|
+
import type { SourceSinkSanitizerSpec } from './source-sink-config.js';
|
|
71
|
+
export interface TaintEmitLimits {
|
|
72
|
+
/** Per-function findings cap (post-dedup). `undefined` ⇒
|
|
73
|
+
* {@link DEFAULT_PDG_MAX_TAINT_FINDINGS_PER_FUNCTION}; `0` ⇒ unlimited. */
|
|
74
|
+
readonly maxFindingsPerFunction?: number;
|
|
75
|
+
/** Per-finding hop cap (source-side prefix kept). `undefined` ⇒
|
|
76
|
+
* {@link DEFAULT_PDG_MAX_TAINT_HOPS}; `0` ⇒ unlimited. */
|
|
77
|
+
readonly maxHops?: number;
|
|
78
|
+
/**
|
|
79
|
+
* Solver fact-materialization cap for the taint-side `computeReachingDefs`
|
|
80
|
+
* call. `undefined` ⇒ {@link DEFAULT_PDG_MAX_REACHING_DEF_FACTS_PER_FUNCTION}
|
|
81
|
+
* (the M2 derived default — see the module doc for why it is REUSED rather
|
|
82
|
+
* than derived from the findings cap); `0` ⇒ unlimited.
|
|
83
|
+
*/
|
|
84
|
+
readonly maxFacts?: number;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Full taint-emit telemetry for one file. EVERY counter is surfaced by the
|
|
88
|
+
* run.ts aggregate (the M2 emit result had two fields dropped on the floor —
|
|
89
|
+
* the plan names that mistake; don't repeat it).
|
|
90
|
+
*/
|
|
91
|
+
export interface TaintEmitResult {
|
|
92
|
+
/** Functions fully propagated (`computeTaintFlows` returned `computed`). */
|
|
93
|
+
functionsAnalyzed: number;
|
|
94
|
+
/** Functions skipped by the zero-match fast path (no solver call). */
|
|
95
|
+
functionsSkippedNoMatch: number;
|
|
96
|
+
/** Functions whose `sites` failed {@link hasTaintSafeSites} (skip-taint-keep-RD). */
|
|
97
|
+
functionsSkippedUnsafeSites: number;
|
|
98
|
+
/** Source+sink functions skipped on a non-`computed` solver status (R4). */
|
|
99
|
+
functionsCoverageGap: {
|
|
100
|
+
truncated: number;
|
|
101
|
+
overflow: number;
|
|
102
|
+
'no-facts': number;
|
|
103
|
+
};
|
|
104
|
+
/** TAINTED edges persisted. */
|
|
105
|
+
findingsEmitted: number;
|
|
106
|
+
/** SANITIZES edges persisted (emitted even when findings are zero). */
|
|
107
|
+
killsEmitted: number;
|
|
108
|
+
/** Findings dropped by the per-function cap (post-dedup), summed. */
|
|
109
|
+
findingsDropped: number;
|
|
110
|
+
/** Findings whose persisted hop path is a truncated prefix (hop/byte cap). */
|
|
111
|
+
hopsTruncatedFindings: number;
|
|
112
|
+
/** ≤{@link MAX_EXAMPLES} `file:line` anchors of gap/unsafe-site functions. */
|
|
113
|
+
coverageGapExamples: string[];
|
|
114
|
+
/** ≤{@link MAX_EXAMPLES} `file:line` anchors of cap-dropped functions. */
|
|
115
|
+
droppedExamples: string[];
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Run the taint pass over one file's emit-safe CFGs and persist TAINTED +
|
|
119
|
+
* SANITIZES edges. `cfgs` MUST already be `isEmitSafeCfg`-filtered (the same
|
|
120
|
+
* `wellFormed` array the caller fed `emitFileCfgs`/`emitFileReachingDefs`) —
|
|
121
|
+
* block/edge anchors are trusted here; only the M3 `sites` layer is
|
|
122
|
+
* re-validated (`hasTaintSafeSites`). Never throws on well-formed input;
|
|
123
|
+
* the caller's per-file try isolates the rest.
|
|
124
|
+
*/
|
|
125
|
+
export declare function emitFileTaint(graph: KnowledgeGraph, cfgs: readonly FunctionCfg[], parsedImports: readonly ParsedImport[], spec: SourceSinkSanitizerSpec, limits?: TaintEmitLimits, onWarn?: (message: string) => void, solve?: ReachingDefsSolver): TaintEmitResult;
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* In-phase taint emission (#2083 M3 U4, plan KTD1/KTD6).
|
|
3
|
+
*
|
|
4
|
+
* Per-file driver for the M3 taint pass: gate → match → solve → propagate →
|
|
5
|
+
* persist sparse `TAINTED` + `SANITIZES` edges. Invoked from the pdg window in
|
|
6
|
+
* scope-resolution (`pipeline/run.ts`), immediately after `emitFileReachingDefs`
|
|
7
|
+
* inside the SAME per-file try — per-file isolation for free (KTD1). Mirrors
|
|
8
|
+
* `emitFileReachingDefs` (cfg/emit.ts) for the budget/dedup/warn discipline and
|
|
9
|
+
* the telemetry-result shape.
|
|
10
|
+
*
|
|
11
|
+
* ## Per-function pipeline (ordering is load-bearing)
|
|
12
|
+
*
|
|
13
|
+
* 1. `hasTaintSafeSites` — a corrupted-store site annotation degrades to
|
|
14
|
+
* SKIP-TAINT-KEEP-RD for this function (counted + warned), never a crash
|
|
15
|
+
* (KTD2; the matcher/propagator dereference indices unvalidated).
|
|
16
|
+
* 2. `matchFunctionSites` against the language spec (the import index is
|
|
17
|
+
* built ONCE per file — imports are a file-level fact).
|
|
18
|
+
* 3. ZERO-MATCH FAST PATH: the solver runs only when the function has at
|
|
19
|
+
* least one matched source AND one matched sink. In a typical repo almost
|
|
20
|
+
* no function has both; an unconditional second `computeReachingDefs` per
|
|
21
|
+
* function would ship a near-2× solve cost to every `--pdg` user.
|
|
22
|
+
* 4. `computeReachingDefs` with the taint `maxFacts` — by DEFAULT the M2
|
|
23
|
+
* derived `DEFAULT_PDG_MAX_REACHING_DEF_FACTS_PER_FUNCTION` (deliberate
|
|
24
|
+
* reuse, not a new constant: the fact-materialization envelope is a
|
|
25
|
+
* memory question, O(defs×uses), orthogonal to the findings cap, and M2
|
|
26
|
+
* already validated exactly this envelope on the same solver in the same
|
|
27
|
+
* window). The run.ts caller derives `limits.maxFacts` from the SAME
|
|
28
|
+
* RD-edge-cap formula `emitFileReachingDefs` uses, so taint coverage and
|
|
29
|
+
* RD coverage truncate together — a function is never `truncated` for one
|
|
30
|
+
* layer and `computed` for the other.
|
|
31
|
+
* 5. `computeTaintFlows` — a non-`computed` status is a per-function
|
|
32
|
+
* COVERAGE GAP (R4: counted by `gapReason`, function skipped entirely,
|
|
33
|
+
* never partially analyzed).
|
|
34
|
+
* 6. Emit one `TAINTED` edge per finding and one `SANITIZES` edge per kill.
|
|
35
|
+
* Kills are emitted even when findings are zero — a fully-sanitized
|
|
36
|
+
* function's kills are exactly its evidence of safety.
|
|
37
|
+
*
|
|
38
|
+
* ## Identity, dedup, budget (KTD6)
|
|
39
|
+
*
|
|
40
|
+
* Findings carry STATEMENT-LEVEL identity — function anchor + sink kind +
|
|
41
|
+
* source occurrence (point/site/object-binding/property) + sink occurrence
|
|
42
|
+
* (point/site/arg/binding) — NOT the REACHING_DEF block-level key (block-pair
|
|
43
|
+
* conflation would drop `exec(req.body, req.query)`'s second finding). The
|
|
44
|
+
* propagation engine dedups by this exact key BEFORE its deterministic cap
|
|
45
|
+
* (`maxFindingsPerFunction`) and counts the overflow; this module templates
|
|
46
|
+
* the same coordinates into the edge id (binding identity via the shared
|
|
47
|
+
* `bindingKey`; the free-text `property` rides LAST so it can never collide
|
|
48
|
+
* into another component) and warns with the drop count on truncation.
|
|
49
|
+
*
|
|
50
|
+
* `reason` carries the versioned hop encoding (`taint/path-codec.ts` — U6's
|
|
51
|
+
* `explain` decodes the same module) for `TAINTED`, and the killed binding's
|
|
52
|
+
* plain name for `SANITIZES` (M0/S1 queryability verdict, like REACHING_DEF).
|
|
53
|
+
*
|
|
54
|
+
* ## Warn split (R4 vs noise)
|
|
55
|
+
*
|
|
56
|
+
* Unsafe-site skips and cap drops warn PER FUNCTION here (rare, actionable —
|
|
57
|
+
* mirrors `emitFileReachingDefs`' malformed/cap warns). Solver coverage gaps
|
|
58
|
+
* (`truncated`/`overflow`) do NOT re-warn per function: the RD layer already
|
|
59
|
+
* warned for the same function with the same solver status (same `maxFacts`
|
|
60
|
+
* derivation — see step 4), and a duplicate `[taint]` line per mega-function
|
|
61
|
+
* would be pure spam. They are counted (+ exampled) in the result and the
|
|
62
|
+
* run.ts caller aggregates them into ONE unconditional `logger.warn` per
|
|
63
|
+
* language (R4) — never dropped on the floor (the M2 lesson).
|
|
64
|
+
*/
|
|
65
|
+
import { generateId } from '../../../lib/utils.js';
|
|
66
|
+
import { basicBlockId, bindingKey, DEFAULT_PDG_MAX_REACHING_DEF_FACTS_PER_FUNCTION, } from '../cfg/emit.js';
|
|
67
|
+
import { computeReachingDefs, pointKey, } from '../cfg/reaching-defs.js';
|
|
68
|
+
import { hasTaintSafeSites } from './site-safety.js';
|
|
69
|
+
import { buildTaintImportIndex, matchFunctionSites } from './match.js';
|
|
70
|
+
import { computeTaintFlows, DEFAULT_PDG_MAX_TAINT_FINDINGS_PER_FUNCTION, DEFAULT_PDG_MAX_TAINT_HOPS, } from './propagate.js';
|
|
71
|
+
// Re-exported so the pipeline (run.ts) sources the taint default caps through
|
|
72
|
+
// this orchestration module rather than reaching into propagate.ts directly.
|
|
73
|
+
export { DEFAULT_PDG_MAX_TAINT_FINDINGS_PER_FUNCTION, DEFAULT_PDG_MAX_TAINT_HOPS, } from './propagate.js';
|
|
74
|
+
import { encodeTaintPath } from './path-codec.js';
|
|
75
|
+
/** Cap on example anchors carried per result (aggregate-warn material, R4). */
|
|
76
|
+
const MAX_EXAMPLES = 5;
|
|
77
|
+
const pushExample = (list, anchor) => {
|
|
78
|
+
if (list.length < MAX_EXAMPLES)
|
|
79
|
+
list.push(anchor);
|
|
80
|
+
};
|
|
81
|
+
/**
|
|
82
|
+
* Run the taint pass over one file's emit-safe CFGs and persist TAINTED +
|
|
83
|
+
* SANITIZES edges. `cfgs` MUST already be `isEmitSafeCfg`-filtered (the same
|
|
84
|
+
* `wellFormed` array the caller fed `emitFileCfgs`/`emitFileReachingDefs`) —
|
|
85
|
+
* block/edge anchors are trusted here; only the M3 `sites` layer is
|
|
86
|
+
* re-validated (`hasTaintSafeSites`). Never throws on well-formed input;
|
|
87
|
+
* the caller's per-file try isolates the rest.
|
|
88
|
+
*/
|
|
89
|
+
export function emitFileTaint(graph, cfgs, parsedImports, spec, limits, onWarn,
|
|
90
|
+
// U12: shared per-file memoized solver (harvest/taint bucket — no maxBlockVisits).
|
|
91
|
+
// The zero-match fast path below still skips the solve entirely; only MATCHED
|
|
92
|
+
// functions request it, hitting the cache the call-summary harvest warmed.
|
|
93
|
+
solve = computeReachingDefs) {
|
|
94
|
+
const result = {
|
|
95
|
+
functionsAnalyzed: 0,
|
|
96
|
+
functionsSkippedNoMatch: 0,
|
|
97
|
+
functionsSkippedUnsafeSites: 0,
|
|
98
|
+
functionsCoverageGap: { truncated: 0, overflow: 0, 'no-facts': 0 },
|
|
99
|
+
findingsEmitted: 0,
|
|
100
|
+
killsEmitted: 0,
|
|
101
|
+
findingsDropped: 0,
|
|
102
|
+
hopsTruncatedFindings: 0,
|
|
103
|
+
coverageGapExamples: [],
|
|
104
|
+
droppedExamples: [],
|
|
105
|
+
};
|
|
106
|
+
// Imports are a FILE-level fact — build the index once, not per function.
|
|
107
|
+
const importIndex = buildTaintImportIndex(parsedImports);
|
|
108
|
+
const maxFindingsPerFunction = limits?.maxFindingsPerFunction ?? DEFAULT_PDG_MAX_TAINT_FINDINGS_PER_FUNCTION;
|
|
109
|
+
const maxHops = limits?.maxHops ?? DEFAULT_PDG_MAX_TAINT_HOPS;
|
|
110
|
+
const maxFacts = limits?.maxFacts ?? DEFAULT_PDG_MAX_REACHING_DEF_FACTS_PER_FUNCTION;
|
|
111
|
+
// Defensive cross-CFG id guard: finding identity is unique WITHIN a
|
|
112
|
+
// function by construction (the propagation engine dedups), so a repeat can
|
|
113
|
+
// only mean two CFGs sharing an anchor — skip, never double-insert.
|
|
114
|
+
const seenEdgeIds = new Set();
|
|
115
|
+
for (const cfg of cfgs) {
|
|
116
|
+
const { filePath, functionStartLine, functionStartColumn } = cfg;
|
|
117
|
+
const anchor = `${filePath}:${functionStartLine}`;
|
|
118
|
+
if (!hasTaintSafeSites(cfg)) {
|
|
119
|
+
result.functionsSkippedUnsafeSites++;
|
|
120
|
+
pushExample(result.coverageGapExamples, anchor);
|
|
121
|
+
onWarn?.(`[taint] ${anchor}: malformed site annotations (out-of-range binding/site ` +
|
|
122
|
+
`indices) — taint skipped for this function; its CFG and REACHING_DEF ` +
|
|
123
|
+
`layers are unaffected`);
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
const matches = matchFunctionSites(cfg, spec, importIndex);
|
|
127
|
+
if (!matches.hasSource || !matches.hasSink) {
|
|
128
|
+
// Zero-match fast path: no solver call (see module doc step 3).
|
|
129
|
+
result.functionsSkippedNoMatch++;
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
const defUse = solve(cfg, { maxFacts });
|
|
133
|
+
const flows = computeTaintFlows(cfg, defUse, matches, { maxFindingsPerFunction, maxHops });
|
|
134
|
+
if (flows.status === 'coverage-gap') {
|
|
135
|
+
// R4: skipped entirely, counted by reason; aggregate-warned by the
|
|
136
|
+
// caller (the RD layer already per-function-warned this solver status).
|
|
137
|
+
result.functionsCoverageGap[flows.gapReason ?? 'no-facts']++;
|
|
138
|
+
pushExample(result.coverageGapExamples, anchor);
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
result.functionsAnalyzed++;
|
|
142
|
+
const bindings = cfg.bindings ?? [];
|
|
143
|
+
const fnAnchor = `${filePath}:${functionStartLine}:${functionStartColumn}`;
|
|
144
|
+
const blockId = (p) => basicBlockId(filePath, functionStartLine, functionStartColumn, p.blockIndex);
|
|
145
|
+
const bKey = (idx) => {
|
|
146
|
+
const b = bindings[idx];
|
|
147
|
+
return b === undefined ? `#${idx}` : bindingKey(b);
|
|
148
|
+
};
|
|
149
|
+
// SANITIZES — one edge per kill, REGARDLESS of findings (kills can and do
|
|
150
|
+
// exist with zero findings: a fully-sanitized flow IS the kill evidence).
|
|
151
|
+
for (const kill of flows.kills) {
|
|
152
|
+
const id = generateId('SANITIZES', `${fnAnchor}:${pointKey(kill.sanitizer)}->${pointKey(kill.killedDef)}:` +
|
|
153
|
+
bKey(kill.bindingIdx));
|
|
154
|
+
if (seenEdgeIds.has(id))
|
|
155
|
+
continue;
|
|
156
|
+
seenEdgeIds.add(id);
|
|
157
|
+
graph.addRelationship({
|
|
158
|
+
id,
|
|
159
|
+
type: 'SANITIZES',
|
|
160
|
+
sourceId: blockId(kill.sanitizer),
|
|
161
|
+
targetId: blockId(kill.killedDef),
|
|
162
|
+
confidence: 1.0,
|
|
163
|
+
reason: bindings[kill.bindingIdx]?.name ?? `#${kill.bindingIdx}`,
|
|
164
|
+
});
|
|
165
|
+
result.killsEmitted++;
|
|
166
|
+
}
|
|
167
|
+
// TAINTED — one edge per finding (already deduped + capped upstream).
|
|
168
|
+
for (const finding of flows.findings) {
|
|
169
|
+
const { source, sink } = finding;
|
|
170
|
+
// KTD6 statement-level identity: function anchor + kind + source
|
|
171
|
+
// occurrence + sink occurrence + binding keys. The rule-(b) occurrence
|
|
172
|
+
// coordinates (site index / arg index) distinguish
|
|
173
|
+
// `exec(req.body, req.query)`'s two findings; `property` is free-text
|
|
174
|
+
// (string-literal subscripts) and rides LAST so it cannot collide into
|
|
175
|
+
// another component.
|
|
176
|
+
const id = generateId('TAINTED', `${fnAnchor}:${finding.sinkKind}:` +
|
|
177
|
+
`${pointKey(source.point)}.${source.siteIndex}:${bKey(source.objectBindingIdx)}:` +
|
|
178
|
+
`${pointKey(sink.point)}.${sink.siteIndex}.${sink.argIndex}:${bKey(sink.bindingIdx)}:` +
|
|
179
|
+
`${sink.entryName}:${source.property}`);
|
|
180
|
+
if (seenEdgeIds.has(id))
|
|
181
|
+
continue;
|
|
182
|
+
seenEdgeIds.add(id);
|
|
183
|
+
// `kind` rides the reason's `;<kind>` header — the only persisted
|
|
184
|
+
// channel for the finding's category (the edge id embedding it is not a
|
|
185
|
+
// stored column; `step` is INT32). U6's `explain` decodes it back.
|
|
186
|
+
const encoded = encodeTaintPath(finding.hops.map((h) => ({ name: h.name, line: h.point.line, viaCall: h.viaCall })), { truncated: finding.hopsTruncated === true, kind: finding.sinkKind });
|
|
187
|
+
if (encoded.truncated)
|
|
188
|
+
result.hopsTruncatedFindings++;
|
|
189
|
+
graph.addRelationship({
|
|
190
|
+
id,
|
|
191
|
+
type: 'TAINTED',
|
|
192
|
+
sourceId: blockId(source.point),
|
|
193
|
+
targetId: blockId(sink.point),
|
|
194
|
+
confidence: 1.0,
|
|
195
|
+
reason: encoded.reason,
|
|
196
|
+
});
|
|
197
|
+
result.findingsEmitted++;
|
|
198
|
+
}
|
|
199
|
+
if (flows.droppedFindings > 0) {
|
|
200
|
+
result.findingsDropped += flows.droppedFindings;
|
|
201
|
+
pushExample(result.droppedExamples, anchor);
|
|
202
|
+
onWarn?.(`[taint] ${anchor}: per-function taint findings cap ` +
|
|
203
|
+
`(${maxFindingsPerFunction}) reached — dropped ${flows.droppedFindings} of ` +
|
|
204
|
+
`${flows.findings.length + flows.droppedFindings} deduped findings`);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
return result;
|
|
208
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interprocedural taint emission (#2084 M4 U4) — materialise `TAINT_PATH`.
|
|
3
|
+
*
|
|
4
|
+
* Persists each cross-function {@link InterprocFinding} as ONE `TAINT_PATH`
|
|
5
|
+
* edge from the source function node to the sink function node, with the
|
|
6
|
+
* function-level hop chain + sink kind encoded in `reason` via the SHARED
|
|
7
|
+
* `path-codec` (the same versioned wire format M3's intra-procedural `TAINTED`
|
|
8
|
+
* edges use — never a second hand-rolled codec). The MCP `explain` tool decodes
|
|
9
|
+
* it for cross-function path rendering (U7).
|
|
10
|
+
*
|
|
11
|
+
* `TAINT_PATH` was reserved at M0 (the RelationshipType + the `CodeRelation`
|
|
12
|
+
* Function/Method node-pairs already exist), so materialisation needs zero
|
|
13
|
+
* schema work. Like `TAINTED`, it stays out of `VALID_RELATION_TYPES` and the
|
|
14
|
+
* web schema — `explain` is the discovery surface.
|
|
15
|
+
*
|
|
16
|
+
* Boundedness mirrors the M3 emit driver: dedup-before-cap (the solver already
|
|
17
|
+
* deduped by `(source, sink, kind)`), a per-run findings cap, and unconditional
|
|
18
|
+
* truncate-and-warn — never a silent drop.
|
|
19
|
+
*/
|
|
20
|
+
import type { KnowledgeGraph } from '../../graph/types.js';
|
|
21
|
+
import type { InterprocFinding } from './interproc-solver.js';
|
|
22
|
+
/** Confidence stamped on interprocedural `TAINT_PATH` edges. Lower than the
|
|
23
|
+
* intra-procedural `TAINTED` 1.0 — context-insensitive composition is a
|
|
24
|
+
* coarser signal (return/call-site merging). */
|
|
25
|
+
export declare const INTERPROC_TAINT_CONFIDENCE = 0.6;
|
|
26
|
+
/**
|
|
27
|
+
* Default per-run cap on emitted `TAINT_PATH` edges (#2084 review P1-3).
|
|
28
|
+
* Resolved into `RepoMeta.pdg` like the other pdg caps; `0` ⇒ unlimited.
|
|
29
|
+
*/
|
|
30
|
+
export declare const DEFAULT_PDG_MAX_INTERPROC_EDGES = 1000;
|
|
31
|
+
export interface InterprocEmitLimits {
|
|
32
|
+
/** Max `TAINT_PATH` edges per run (post-dedup). `undefined`/0 ⇒ unlimited. */
|
|
33
|
+
readonly maxEdges?: number;
|
|
34
|
+
}
|
|
35
|
+
export interface InterprocEmitResult {
|
|
36
|
+
/** TAINT_PATH edges persisted. */
|
|
37
|
+
edgesEmitted: number;
|
|
38
|
+
/** Findings dropped by the per-run cap. */
|
|
39
|
+
edgesDropped: number;
|
|
40
|
+
/** Findings whose persisted hop path is a truncated prefix. */
|
|
41
|
+
hopsTruncated: number;
|
|
42
|
+
/** Findings skipped because an endpoint node was missing from the graph. */
|
|
43
|
+
skippedMissingEndpoint: number;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Persist cross-function findings as `TAINT_PATH` edges. `findings` is assumed
|
|
47
|
+
* deduped + deterministically ordered (the solver's contract). Never throws on
|
|
48
|
+
* valid input.
|
|
49
|
+
*/
|
|
50
|
+
export declare function emitInterprocTaint(graph: KnowledgeGraph, findings: readonly InterprocFinding[], limits?: InterprocEmitLimits, onWarn?: (message: string) => void): InterprocEmitResult;
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interprocedural taint emission (#2084 M4 U4) — materialise `TAINT_PATH`.
|
|
3
|
+
*
|
|
4
|
+
* Persists each cross-function {@link InterprocFinding} as ONE `TAINT_PATH`
|
|
5
|
+
* edge from the source function node to the sink function node, with the
|
|
6
|
+
* function-level hop chain + sink kind encoded in `reason` via the SHARED
|
|
7
|
+
* `path-codec` (the same versioned wire format M3's intra-procedural `TAINTED`
|
|
8
|
+
* edges use — never a second hand-rolled codec). The MCP `explain` tool decodes
|
|
9
|
+
* it for cross-function path rendering (U7).
|
|
10
|
+
*
|
|
11
|
+
* `TAINT_PATH` was reserved at M0 (the RelationshipType + the `CodeRelation`
|
|
12
|
+
* Function/Method node-pairs already exist), so materialisation needs zero
|
|
13
|
+
* schema work. Like `TAINTED`, it stays out of `VALID_RELATION_TYPES` and the
|
|
14
|
+
* web schema — `explain` is the discovery surface.
|
|
15
|
+
*
|
|
16
|
+
* Boundedness mirrors the M3 emit driver: dedup-before-cap (the solver already
|
|
17
|
+
* deduped by `(source, sink, kind)`), a per-run findings cap, and unconditional
|
|
18
|
+
* truncate-and-warn — never a silent drop.
|
|
19
|
+
*/
|
|
20
|
+
import { encodeTaintPath } from './path-codec.js';
|
|
21
|
+
/** Confidence stamped on interprocedural `TAINT_PATH` edges. Lower than the
|
|
22
|
+
* intra-procedural `TAINTED` 1.0 — context-insensitive composition is a
|
|
23
|
+
* coarser signal (return/call-site merging). */
|
|
24
|
+
export const INTERPROC_TAINT_CONFIDENCE = 0.6;
|
|
25
|
+
/**
|
|
26
|
+
* Default per-run cap on emitted `TAINT_PATH` edges (#2084 review P1-3).
|
|
27
|
+
* Resolved into `RepoMeta.pdg` like the other pdg caps; `0` ⇒ unlimited.
|
|
28
|
+
*/
|
|
29
|
+
export const DEFAULT_PDG_MAX_INTERPROC_EDGES = 1000;
|
|
30
|
+
/**
|
|
31
|
+
* Persist cross-function findings as `TAINT_PATH` edges. `findings` is assumed
|
|
32
|
+
* deduped + deterministically ordered (the solver's contract). Never throws on
|
|
33
|
+
* valid input.
|
|
34
|
+
*/
|
|
35
|
+
export function emitInterprocTaint(graph, findings, limits, onWarn) {
|
|
36
|
+
const result = {
|
|
37
|
+
edgesEmitted: 0,
|
|
38
|
+
edgesDropped: 0,
|
|
39
|
+
hopsTruncated: 0,
|
|
40
|
+
skippedMissingEndpoint: 0,
|
|
41
|
+
};
|
|
42
|
+
const maxEdges = limits?.maxEdges && limits.maxEdges > 0 ? limits.maxEdges : Infinity;
|
|
43
|
+
const seen = new Set();
|
|
44
|
+
for (const finding of findings) {
|
|
45
|
+
if (result.edgesEmitted >= maxEdges) {
|
|
46
|
+
result.edgesDropped++;
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
const sourceNode = graph.getNode(finding.sourceFnId);
|
|
50
|
+
const sinkNode = graph.getNode(finding.sinkFnId);
|
|
51
|
+
if (!sourceNode || !sinkNode) {
|
|
52
|
+
result.skippedMissingEndpoint++;
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
// Map function hops → codec hops. The hop "name" is the function's display
|
|
56
|
+
// name (identifier charset — codec-safe); the line is its start line.
|
|
57
|
+
const hops = finding.hops.map((h) => {
|
|
58
|
+
const node = graph.getNode(h.fnId);
|
|
59
|
+
const name = typeof node?.properties.name === 'string' ? node.properties.name : 'fn';
|
|
60
|
+
const line = typeof node?.properties.startLine === 'number' ? node.properties.startLine : 0;
|
|
61
|
+
return { name, line };
|
|
62
|
+
});
|
|
63
|
+
const encoded = encodeTaintPath(hops, {
|
|
64
|
+
kind: finding.sinkKind,
|
|
65
|
+
truncated: finding.hopsTruncated,
|
|
66
|
+
});
|
|
67
|
+
if (encoded.truncated)
|
|
68
|
+
result.hopsTruncated++;
|
|
69
|
+
const id = `rel:TAINT_PATH:${finding.sinkKind}:${finding.sourceFnId}=>${finding.sinkFnId}`;
|
|
70
|
+
if (seen.has(id))
|
|
71
|
+
continue;
|
|
72
|
+
seen.add(id);
|
|
73
|
+
graph.addRelationship({
|
|
74
|
+
id,
|
|
75
|
+
sourceId: finding.sourceFnId,
|
|
76
|
+
targetId: finding.sinkFnId,
|
|
77
|
+
type: 'TAINT_PATH',
|
|
78
|
+
confidence: INTERPROC_TAINT_CONFIDENCE,
|
|
79
|
+
reason: encoded.reason,
|
|
80
|
+
});
|
|
81
|
+
result.edgesEmitted++;
|
|
82
|
+
}
|
|
83
|
+
if (result.edgesDropped > 0) {
|
|
84
|
+
onWarn?.(`[taint-interproc] ${result.edgesDropped} cross-function finding(s) dropped by the ` +
|
|
85
|
+
`per-run TAINT_PATH cap (${maxEdges})`);
|
|
86
|
+
}
|
|
87
|
+
return result;
|
|
88
|
+
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interprocedural taint fixpoint (#2084 M4 U3).
|
|
3
|
+
*
|
|
4
|
+
* Composes per-function {@link FunctionSummary} objects over the resolved
|
|
5
|
+
* `CALLS` graph to find source→sink flows that cross function and file
|
|
6
|
+
* boundaries. PURE AND DETERMINISTIC (no graph, no I/O, no logger) — the phase
|
|
7
|
+
* builds the inputs from `ctx.graph` and persists the outputs.
|
|
8
|
+
*
|
|
9
|
+
* ## The model — whole-parameter taint reachability
|
|
10
|
+
*
|
|
11
|
+
* The unit of taint is `(function, parameter)`. The fixpoint computes the set
|
|
12
|
+
* of parameters that can hold source-derived data, then fires a finding
|
|
13
|
+
* whenever a tainted parameter feeds a modelled sink (`paramToSink`).
|
|
14
|
+
*
|
|
15
|
+
* - **Seeds** — every `sourceToCallArg` edge: a function generates a source and
|
|
16
|
+
* passes it into argument `argIndex` of a call at `callLine`. Resolving that
|
|
17
|
+
* call site against the caller's outgoing `CALLS` edges yields the callee;
|
|
18
|
+
* the callee's parameter `argIndex` becomes tainted, with the generating
|
|
19
|
+
* function recorded as the flow's source.
|
|
20
|
+
* - **Propagation** — every `paramToCallArg` edge of a function whose parameter
|
|
21
|
+
* is ALREADY tainted: `param i → arg j of callee` taints the callee's
|
|
22
|
+
* parameter `j` (TITO composition). Iterated to a fixpoint.
|
|
23
|
+
* - **Findings** — whenever a parameter becomes tainted and the owning
|
|
24
|
+
* function's `paramToSink` contains that parameter, a cross-function finding
|
|
25
|
+
* is emitted (source function → sink function, with the kind).
|
|
26
|
+
*
|
|
27
|
+
* ## Cycle safety (recursion)
|
|
28
|
+
*
|
|
29
|
+
* The tainted-parameter set is monotone over a FINITE lattice (`Σ functions ×
|
|
30
|
+
* params`), so the worklist fixpoint converges: a recursive or mutually
|
|
31
|
+
* recursive call merely re-proposes an already-tainted parameter, which the
|
|
32
|
+
* visited-set absorbs — no infinite descent. This is the functional/summary
|
|
33
|
+
* method's standard termination argument (Sharir-Pnueli; Pysa, Mariana Trench,
|
|
34
|
+
* and Infer all rely on it). SCC condensation would only refine the PROCESSING
|
|
35
|
+
* ORDER; correctness and termination do not require it.
|
|
36
|
+
*
|
|
37
|
+
* ## Context-insensitivity & the name-join over-approximation
|
|
38
|
+
*
|
|
39
|
+
* One summary per function, applied at every call site — return/param merging
|
|
40
|
+
* is accepted (the security-conservative direction). The call-arg→callee join
|
|
41
|
+
* is by callee NAME (not line), so when one caller invokes two DISTINCT
|
|
42
|
+
* same-named callees (`x.handler(src)` and `y.handler(clean)`), a source that
|
|
43
|
+
* flowed into ONE of them taints BOTH callees' parameter — an extra finding on
|
|
44
|
+
* the callee the source did not reach. This is sound (over-attribution, never a
|
|
45
|
+
* missed flow — the conservative direction for a security tool) and is the
|
|
46
|
+
* documented price of dropping the fragile line-based join; the `explain` tool
|
|
47
|
+
* surfaces it ("may over-attribute among same-named callees"). Other known
|
|
48
|
+
* precision losses (call-site conflation, shared dispatch, callbacks) are the
|
|
49
|
+
* documented M4 trade-offs; refinements are deferred (plan KTD).
|
|
50
|
+
*/
|
|
51
|
+
import type { SinkKind } from './source-sink-config.js';
|
|
52
|
+
import type { FunctionSummary } from './summary-model.js';
|
|
53
|
+
/**
|
|
54
|
+
* One resolved call edge from the `CALLS` graph. The join to a summary's
|
|
55
|
+
* call-arg edge is by CALLEE NAME (the callee node's declared name), NOT by
|
|
56
|
+
* call-site line — line-base parity between the CFG harvest (1-based) and the
|
|
57
|
+
* reference site is fragile, while the callee identity is exact and the
|
|
58
|
+
* context-insensitive model tatints the callee's parameter the same way at
|
|
59
|
+
* every call site to it.
|
|
60
|
+
*/
|
|
61
|
+
export interface InterprocCallEdge {
|
|
62
|
+
readonly callerId: string;
|
|
63
|
+
readonly calleeId: string;
|
|
64
|
+
/** The callee node's declared name (`helper`, `process`) — the join key. */
|
|
65
|
+
readonly calleeName: string;
|
|
66
|
+
}
|
|
67
|
+
/** One hop of a cross-function flow: the function entered, and how. */
|
|
68
|
+
export interface InterprocHop {
|
|
69
|
+
readonly fnId: string;
|
|
70
|
+
/** The call-site line in the PREVIOUS function that entered this one. */
|
|
71
|
+
readonly callLine?: number;
|
|
72
|
+
/** Argument position the taint entered through (undefined for the source fn). */
|
|
73
|
+
readonly argIndex?: number;
|
|
74
|
+
}
|
|
75
|
+
export interface InterprocFinding {
|
|
76
|
+
readonly sourceFnId: string;
|
|
77
|
+
readonly sinkFnId: string;
|
|
78
|
+
readonly sinkKind: SinkKind;
|
|
79
|
+
/** Ordered source→sink hop chain (functions). A prefix when `truncated`. */
|
|
80
|
+
readonly hops: readonly InterprocHop[];
|
|
81
|
+
readonly hopsTruncated: boolean;
|
|
82
|
+
}
|
|
83
|
+
export interface InterprocLimits {
|
|
84
|
+
/** Max functions in a single flow's hop chain. `undefined`/0 ⇒ default 32. */
|
|
85
|
+
readonly maxHops?: number;
|
|
86
|
+
/** Max findings overall (post-dedup). `undefined`/0 ⇒ unlimited. */
|
|
87
|
+
readonly maxFindings?: number;
|
|
88
|
+
}
|
|
89
|
+
export interface InterprocResult {
|
|
90
|
+
readonly findings: readonly InterprocFinding[];
|
|
91
|
+
/** Findings dropped by `maxFindings` (post-dedup). */
|
|
92
|
+
readonly droppedFindings: number;
|
|
93
|
+
/** Call edges whose call-site line matched no summary edge (diagnostics). */
|
|
94
|
+
readonly unmatchedCallSites: number;
|
|
95
|
+
}
|
|
96
|
+
export declare const DEFAULT_MAX_INTERPROC_HOPS = 32;
|
|
97
|
+
/**
|
|
98
|
+
* Default per-run cap on cross-function findings (#2084 review P1-3). Like the
|
|
99
|
+
* other pdg caps it is resolved into `RepoMeta.pdg` so `pdgModeMismatch`
|
|
100
|
+
* stamps it; `0` ⇒ unlimited. 2000 is generous for a real repo — more deduped
|
|
101
|
+
* `(source, sink, kind)` findings than that is a fixture or a runaway fan-in,
|
|
102
|
+
* and the overflow is deterministic + counted (`droppedFindings`).
|
|
103
|
+
*/
|
|
104
|
+
export declare const DEFAULT_PDG_MAX_INTERPROC_FINDINGS = 2000;
|
|
105
|
+
/**
|
|
106
|
+
* Run the interprocedural taint fixpoint. `summaries` is keyed by function node
|
|
107
|
+
* id; `callEdges` is the resolved `CALLS` graph (caller→callee with call-site
|
|
108
|
+
* lines). Deterministic: inputs in, sorted findings out.
|
|
109
|
+
*/
|
|
110
|
+
export declare function solveInterprocTaint(summaries: ReadonlyMap<string, FunctionSummary>, callEdges: readonly InterprocCallEdge[], limits?: InterprocLimits): InterprocResult;
|