circle-ir-ai 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +105 -0
- package/LICENSE +15 -0
- package/README.md +336 -0
- package/dist/action-queue/aggregator.d.ts +40 -0
- package/dist/action-queue/aggregator.d.ts.map +1 -0
- package/dist/action-queue/aggregator.js +375 -0
- package/dist/action-queue/aggregator.js.map +1 -0
- package/dist/action-queue/index.d.ts +14 -0
- package/dist/action-queue/index.d.ts.map +1 -0
- package/dist/action-queue/index.js +17 -0
- package/dist/action-queue/index.js.map +1 -0
- package/dist/action-queue/queue.d.ts +74 -0
- package/dist/action-queue/queue.d.ts.map +1 -0
- package/dist/action-queue/queue.js +433 -0
- package/dist/action-queue/queue.js.map +1 -0
- package/dist/action-queue/types.d.ts +162 -0
- package/dist/action-queue/types.d.ts.map +1 -0
- package/dist/action-queue/types.js +44 -0
- package/dist/action-queue/types.js.map +1 -0
- package/dist/agents/enrichment-agent.d.ts +16 -0
- package/dist/agents/enrichment-agent.d.ts.map +1 -0
- package/dist/agents/enrichment-agent.js +102 -0
- package/dist/agents/enrichment-agent.js.map +1 -0
- package/dist/agents/index.d.ts +12 -0
- package/dist/agents/index.d.ts.map +1 -0
- package/dist/agents/index.js +15 -0
- package/dist/agents/index.js.map +1 -0
- package/dist/agents/mastra/agents.d.ts +373 -0
- package/dist/agents/mastra/agents.d.ts.map +1 -0
- package/dist/agents/mastra/agents.js +347 -0
- package/dist/agents/mastra/agents.js.map +1 -0
- package/dist/agents/mastra/index.d.ts +12 -0
- package/dist/agents/mastra/index.d.ts.map +1 -0
- package/dist/agents/mastra/index.js +17 -0
- package/dist/agents/mastra/index.js.map +1 -0
- package/dist/agents/mastra/instance.d.ts +383 -0
- package/dist/agents/mastra/instance.d.ts.map +1 -0
- package/dist/agents/mastra/instance.js +37 -0
- package/dist/agents/mastra/instance.js.map +1 -0
- package/dist/agents/mastra/steps.d.ts +300 -0
- package/dist/agents/mastra/steps.d.ts.map +1 -0
- package/dist/agents/mastra/steps.js +468 -0
- package/dist/agents/mastra/steps.js.map +1 -0
- package/dist/agents/mastra/swarm.d.ts +106 -0
- package/dist/agents/mastra/swarm.d.ts.map +1 -0
- package/dist/agents/mastra/swarm.js +501 -0
- package/dist/agents/mastra/swarm.js.map +1 -0
- package/dist/agents/mastra/workflow.d.ts +81 -0
- package/dist/agents/mastra/workflow.d.ts.map +1 -0
- package/dist/agents/mastra/workflow.js +460 -0
- package/dist/agents/mastra/workflow.js.map +1 -0
- package/dist/agents/multi/agents/security.d.ts +29 -0
- package/dist/agents/multi/agents/security.d.ts.map +1 -0
- package/dist/agents/multi/agents/security.js +830 -0
- package/dist/agents/multi/agents/security.js.map +1 -0
- package/dist/agents/multi/extractor.d.ts +21 -0
- package/dist/agents/multi/extractor.d.ts.map +1 -0
- package/dist/agents/multi/extractor.js +483 -0
- package/dist/agents/multi/extractor.js.map +1 -0
- package/dist/agents/multi/index.d.ts +32 -0
- package/dist/agents/multi/index.d.ts.map +1 -0
- package/dist/agents/multi/index.js +34 -0
- package/dist/agents/multi/index.js.map +1 -0
- package/dist/agents/multi/runner.d.ts +79 -0
- package/dist/agents/multi/runner.d.ts.map +1 -0
- package/dist/agents/multi/runner.js +323 -0
- package/dist/agents/multi/runner.js.map +1 -0
- package/dist/agents/security-agent.d.ts +16 -0
- package/dist/agents/security-agent.d.ts.map +1 -0
- package/dist/agents/security-agent.js +299 -0
- package/dist/agents/security-agent.js.map +1 -0
- package/dist/agents/types.d.ts +373 -0
- package/dist/agents/types.d.ts.map +1 -0
- package/dist/agents/types.js +14 -0
- package/dist/agents/types.js.map +1 -0
- package/dist/agents/verification-agent.d.ts +23 -0
- package/dist/agents/verification-agent.d.ts.map +1 -0
- package/dist/agents/verification-agent.js +217 -0
- package/dist/agents/verification-agent.js.map +1 -0
- package/dist/agents/workflow.d.ts +30 -0
- package/dist/agents/workflow.d.ts.map +1 -0
- package/dist/agents/workflow.js +79 -0
- package/dist/agents/workflow.js.map +1 -0
- package/dist/analysis/enriched.d.ts +16 -0
- package/dist/analysis/enriched.d.ts.map +1 -0
- package/dist/analysis/enriched.js +297 -0
- package/dist/analysis/enriched.js.map +1 -0
- package/dist/analysis/llm-correlated-predicates.d.ts +80 -0
- package/dist/analysis/llm-correlated-predicates.d.ts.map +1 -0
- package/dist/analysis/llm-correlated-predicates.js +255 -0
- package/dist/analysis/llm-correlated-predicates.js.map +1 -0
- package/dist/analysis/llm-cross-file-taint.d.ts +86 -0
- package/dist/analysis/llm-cross-file-taint.d.ts.map +1 -0
- package/dist/analysis/llm-cross-file-taint.js +264 -0
- package/dist/analysis/llm-cross-file-taint.js.map +1 -0
- package/dist/analysis/pattern-discovery.d.ts +79 -0
- package/dist/analysis/pattern-discovery.d.ts.map +1 -0
- package/dist/analysis/pattern-discovery.js +447 -0
- package/dist/analysis/pattern-discovery.js.map +1 -0
- package/dist/cache/file-cache.d.ts +89 -0
- package/dist/cache/file-cache.d.ts.map +1 -0
- package/dist/cache/file-cache.js +208 -0
- package/dist/cache/file-cache.js.map +1 -0
- package/dist/cache/index.d.ts +6 -0
- package/dist/cache/index.d.ts.map +1 -0
- package/dist/cache/index.js +5 -0
- package/dist/cache/index.js.map +1 -0
- package/dist/cli/args.d.ts +52 -0
- package/dist/cli/args.d.ts.map +1 -0
- package/dist/cli/args.js +422 -0
- package/dist/cli/args.js.map +1 -0
- package/dist/cli/colors.d.ts +31 -0
- package/dist/cli/colors.d.ts.map +1 -0
- package/dist/cli/colors.js +80 -0
- package/dist/cli/colors.js.map +1 -0
- package/dist/cli/commands/analyze-skill.d.ts +33 -0
- package/dist/cli/commands/analyze-skill.d.ts.map +1 -0
- package/dist/cli/commands/analyze-skill.js +217 -0
- package/dist/cli/commands/analyze-skill.js.map +1 -0
- package/dist/cli/commands/analyze.d.ts +18 -0
- package/dist/cli/commands/analyze.d.ts.map +1 -0
- package/dist/cli/commands/analyze.js +30 -0
- package/dist/cli/commands/analyze.js.map +1 -0
- package/dist/cli/commands/benchmark-runner.d.ts +42 -0
- package/dist/cli/commands/benchmark-runner.d.ts.map +1 -0
- package/dist/cli/commands/benchmark-runner.js +18 -0
- package/dist/cli/commands/benchmark-runner.js.map +1 -0
- package/dist/cli/commands/benchmark.d.ts +11 -0
- package/dist/cli/commands/benchmark.d.ts.map +1 -0
- package/dist/cli/commands/benchmark.js +90 -0
- package/dist/cli/commands/benchmark.js.map +1 -0
- package/dist/cli/commands/dead-code.d.ts +11 -0
- package/dist/cli/commands/dead-code.d.ts.map +1 -0
- package/dist/cli/commands/dead-code.js +65 -0
- package/dist/cli/commands/dead-code.js.map +1 -0
- package/dist/cli/commands/generate-spec.d.ts +11 -0
- package/dist/cli/commands/generate-spec.d.ts.map +1 -0
- package/dist/cli/commands/generate-spec.js +67 -0
- package/dist/cli/commands/generate-spec.js.map +1 -0
- package/dist/cli/commands/health.d.ts +11 -0
- package/dist/cli/commands/health.d.ts.map +1 -0
- package/dist/cli/commands/health.js +67 -0
- package/dist/cli/commands/health.js.map +1 -0
- package/dist/cli/commands/project.d.ts +21 -0
- package/dist/cli/commands/project.d.ts.map +1 -0
- package/dist/cli/commands/project.js +92 -0
- package/dist/cli/commands/project.js.map +1 -0
- package/dist/cli/commands/scan.d.ts +11 -0
- package/dist/cli/commands/scan.d.ts.map +1 -0
- package/dist/cli/commands/scan.js +68 -0
- package/dist/cli/commands/scan.js.map +1 -0
- package/dist/cli/commands/secrets.d.ts +11 -0
- package/dist/cli/commands/secrets.d.ts.map +1 -0
- package/dist/cli/commands/secrets.js +71 -0
- package/dist/cli/commands/secrets.js.map +1 -0
- package/dist/cli/commands/swarm.d.ts +20 -0
- package/dist/cli/commands/swarm.d.ts.map +1 -0
- package/dist/cli/commands/swarm.js +174 -0
- package/dist/cli/commands/swarm.js.map +1 -0
- package/dist/cli/config.d.ts +103 -0
- package/dist/cli/config.d.ts.map +1 -0
- package/dist/cli/config.js +307 -0
- package/dist/cli/config.js.map +1 -0
- package/dist/cli/discovery.d.ts +31 -0
- package/dist/cli/discovery.d.ts.map +1 -0
- package/dist/cli/discovery.js +212 -0
- package/dist/cli/discovery.js.map +1 -0
- package/dist/cli/formatters/index.d.ts +15 -0
- package/dist/cli/formatters/index.d.ts.map +1 -0
- package/dist/cli/formatters/index.js +51 -0
- package/dist/cli/formatters/index.js.map +1 -0
- package/dist/cli/formatters/json.d.ts +11 -0
- package/dist/cli/formatters/json.d.ts.map +1 -0
- package/dist/cli/formatters/json.js +12 -0
- package/dist/cli/formatters/json.js.map +1 -0
- package/dist/cli/formatters/project-json.d.ts +11 -0
- package/dist/cli/formatters/project-json.d.ts.map +1 -0
- package/dist/cli/formatters/project-json.js +12 -0
- package/dist/cli/formatters/project-json.js.map +1 -0
- package/dist/cli/formatters/project-sarif.d.ts +11 -0
- package/dist/cli/formatters/project-sarif.d.ts.map +1 -0
- package/dist/cli/formatters/project-sarif.js +127 -0
- package/dist/cli/formatters/project-sarif.js.map +1 -0
- package/dist/cli/formatters/project-summary.d.ts +11 -0
- package/dist/cli/formatters/project-summary.d.ts.map +1 -0
- package/dist/cli/formatters/project-summary.js +202 -0
- package/dist/cli/formatters/project-summary.js.map +1 -0
- package/dist/cli/formatters/sarif-shared.d.ts +101 -0
- package/dist/cli/formatters/sarif-shared.d.ts.map +1 -0
- package/dist/cli/formatters/sarif-shared.js +57 -0
- package/dist/cli/formatters/sarif-shared.js.map +1 -0
- package/dist/cli/formatters/sarif.d.ts +12 -0
- package/dist/cli/formatters/sarif.d.ts.map +1 -0
- package/dist/cli/formatters/sarif.js +92 -0
- package/dist/cli/formatters/sarif.js.map +1 -0
- package/dist/cli/formatters/summary.d.ts +11 -0
- package/dist/cli/formatters/summary.d.ts.map +1 -0
- package/dist/cli/formatters/summary.js +240 -0
- package/dist/cli/formatters/summary.js.map +1 -0
- package/dist/cli/formatters/two-phase-summary.d.ts +11 -0
- package/dist/cli/formatters/two-phase-summary.d.ts.map +1 -0
- package/dist/cli/formatters/two-phase-summary.js +188 -0
- package/dist/cli/formatters/two-phase-summary.js.map +1 -0
- package/dist/cli/index.d.ts +15 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +555 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/components/clustering.d.ts +60 -0
- package/dist/components/clustering.d.ts.map +1 -0
- package/dist/components/clustering.js +129 -0
- package/dist/components/clustering.js.map +1 -0
- package/dist/components/enrichment.d.ts +45 -0
- package/dist/components/enrichment.d.ts.map +1 -0
- package/dist/components/enrichment.js +193 -0
- package/dist/components/enrichment.js.map +1 -0
- package/dist/components/index.d.ts +29 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/components/index.js +56 -0
- package/dist/components/index.js.map +1 -0
- package/dist/dead-code/detector.d.ts +200 -0
- package/dist/dead-code/detector.d.ts.map +1 -0
- package/dist/dead-code/detector.js +1003 -0
- package/dist/dead-code/detector.js.map +1 -0
- package/dist/dead-code/index.d.ts +7 -0
- package/dist/dead-code/index.d.ts.map +1 -0
- package/dist/dead-code/index.js +7 -0
- package/dist/dead-code/index.js.map +1 -0
- package/dist/extractors/index.d.ts +15 -0
- package/dist/extractors/index.d.ts.map +1 -0
- package/dist/extractors/index.js +14 -0
- package/dist/extractors/index.js.map +1 -0
- package/dist/extractors/natural-language.d.ts +46 -0
- package/dist/extractors/natural-language.d.ts.map +1 -0
- package/dist/extractors/natural-language.js +228 -0
- package/dist/extractors/natural-language.js.map +1 -0
- package/dist/extractors/tree-sitter.d.ts +33 -0
- package/dist/extractors/tree-sitter.d.ts.map +1 -0
- package/dist/extractors/tree-sitter.js +69 -0
- package/dist/extractors/tree-sitter.js.map +1 -0
- package/dist/extractors/types.d.ts +62 -0
- package/dist/extractors/types.d.ts.map +1 -0
- package/dist/extractors/types.js +54 -0
- package/dist/extractors/types.js.map +1 -0
- package/dist/health-score/calculator.d.ts +123 -0
- package/dist/health-score/calculator.d.ts.map +1 -0
- package/dist/health-score/calculator.js +444 -0
- package/dist/health-score/calculator.js.map +1 -0
- package/dist/health-score/index.d.ts +12 -0
- package/dist/health-score/index.d.ts.map +1 -0
- package/dist/health-score/index.js +14 -0
- package/dist/health-score/index.js.map +1 -0
- package/dist/health-score/metrics.d.ts +142 -0
- package/dist/health-score/metrics.d.ts.map +1 -0
- package/dist/health-score/metrics.js +332 -0
- package/dist/health-score/metrics.js.map +1 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +43 -0
- package/dist/index.js.map +1 -0
- package/dist/llm/ax-client.d.ts +477 -0
- package/dist/llm/ax-client.d.ts.map +1 -0
- package/dist/llm/ax-client.js +1641 -0
- package/dist/llm/ax-client.js.map +1 -0
- package/dist/llm/config.d.ts +58 -0
- package/dist/llm/config.d.ts.map +1 -0
- package/dist/llm/config.js +97 -0
- package/dist/llm/config.js.map +1 -0
- package/dist/llm/discovery.d.ts +123 -0
- package/dist/llm/discovery.d.ts.map +1 -0
- package/dist/llm/discovery.js +505 -0
- package/dist/llm/discovery.js.map +1 -0
- package/dist/llm/enrichment.d.ts +108 -0
- package/dist/llm/enrichment.d.ts.map +1 -0
- package/dist/llm/enrichment.js +312 -0
- package/dist/llm/enrichment.js.map +1 -0
- package/dist/llm/index.d.ts +13 -0
- package/dist/llm/index.d.ts.map +1 -0
- package/dist/llm/index.js +22 -0
- package/dist/llm/index.js.map +1 -0
- package/dist/llm/language-context.d.ts +64 -0
- package/dist/llm/language-context.d.ts.map +1 -0
- package/dist/llm/language-context.js +492 -0
- package/dist/llm/language-context.js.map +1 -0
- package/dist/llm/pattern-verification.d.ts +39 -0
- package/dist/llm/pattern-verification.d.ts.map +1 -0
- package/dist/llm/pattern-verification.js +127 -0
- package/dist/llm/pattern-verification.js.map +1 -0
- package/dist/llm/prompt-security.d.ts +120 -0
- package/dist/llm/prompt-security.d.ts.map +1 -0
- package/dist/llm/prompt-security.js +301 -0
- package/dist/llm/prompt-security.js.map +1 -0
- package/dist/llm/prompts/index.d.ts +31 -0
- package/dist/llm/prompts/index.d.ts.map +1 -0
- package/dist/llm/prompts/index.js +92 -0
- package/dist/llm/prompts/index.js.map +1 -0
- package/dist/llm/prompts/rust.d.ts +30 -0
- package/dist/llm/prompts/rust.d.ts.map +1 -0
- package/dist/llm/prompts/rust.js +121 -0
- package/dist/llm/prompts/rust.js.map +1 -0
- package/dist/llm/schemas.d.ts +892 -0
- package/dist/llm/schemas.d.ts.map +1 -0
- package/dist/llm/schemas.js +258 -0
- package/dist/llm/schemas.js.map +1 -0
- package/dist/llm/verification.d.ts +127 -0
- package/dist/llm/verification.d.ts.map +1 -0
- package/dist/llm/verification.js +394 -0
- package/dist/llm/verification.js.map +1 -0
- package/dist/project/analyzer.d.ts +30 -0
- package/dist/project/analyzer.d.ts.map +1 -0
- package/dist/project/analyzer.js +358 -0
- package/dist/project/analyzer.js.map +1 -0
- package/dist/project/call-graph.d.ts +22 -0
- package/dist/project/call-graph.d.ts.map +1 -0
- package/dist/project/call-graph.js +246 -0
- package/dist/project/call-graph.js.map +1 -0
- package/dist/project/index.d.ts +18 -0
- package/dist/project/index.d.ts.map +1 -0
- package/dist/project/index.js +20 -0
- package/dist/project/index.js.map +1 -0
- package/dist/project/taint-paths.d.ts +22 -0
- package/dist/project/taint-paths.d.ts.map +1 -0
- package/dist/project/taint-paths.js +265 -0
- package/dist/project/taint-paths.js.map +1 -0
- package/dist/project/two-phase-analyzer.d.ts +143 -0
- package/dist/project/two-phase-analyzer.d.ts.map +1 -0
- package/dist/project/two-phase-analyzer.js +646 -0
- package/dist/project/two-phase-analyzer.js.map +1 -0
- package/dist/project/type-hierarchy.d.ts +28 -0
- package/dist/project/type-hierarchy.d.ts.map +1 -0
- package/dist/project/type-hierarchy.js +218 -0
- package/dist/project/type-hierarchy.js.map +1 -0
- package/dist/secret-scan/index.d.ts +12 -0
- package/dist/secret-scan/index.d.ts.map +1 -0
- package/dist/secret-scan/index.js +14 -0
- package/dist/secret-scan/index.js.map +1 -0
- package/dist/secret-scan/patterns.d.ts +38 -0
- package/dist/secret-scan/patterns.d.ts.map +1 -0
- package/dist/secret-scan/patterns.js +473 -0
- package/dist/secret-scan/patterns.js.map +1 -0
- package/dist/secret-scan/scanner.d.ts +162 -0
- package/dist/secret-scan/scanner.d.ts.map +1 -0
- package/dist/secret-scan/scanner.js +511 -0
- package/dist/secret-scan/scanner.js.map +1 -0
- package/dist/security-scan/index.d.ts +12 -0
- package/dist/security-scan/index.d.ts.map +1 -0
- package/dist/security-scan/index.js +15 -0
- package/dist/security-scan/index.js.map +1 -0
- package/dist/security-scan/owasp-mapping.d.ts +29 -0
- package/dist/security-scan/owasp-mapping.d.ts.map +1 -0
- package/dist/security-scan/owasp-mapping.js +246 -0
- package/dist/security-scan/owasp-mapping.js.map +1 -0
- package/dist/security-scan/scanner.d.ts +204 -0
- package/dist/security-scan/scanner.d.ts.map +1 -0
- package/dist/security-scan/scanner.js +693 -0
- package/dist/security-scan/scanner.js.map +1 -0
- package/dist/security-scan/trend-tracker.d.ts +150 -0
- package/dist/security-scan/trend-tracker.d.ts.map +1 -0
- package/dist/security-scan/trend-tracker.js +299 -0
- package/dist/security-scan/trend-tracker.js.map +1 -0
- package/dist/skills/bundle-loader.d.ts +26 -0
- package/dist/skills/bundle-loader.d.ts.map +1 -0
- package/dist/skills/bundle-loader.js +284 -0
- package/dist/skills/bundle-loader.js.map +1 -0
- package/dist/skills/capability-mismatch.d.ts +21 -0
- package/dist/skills/capability-mismatch.d.ts.map +1 -0
- package/dist/skills/capability-mismatch.js +188 -0
- package/dist/skills/capability-mismatch.js.map +1 -0
- package/dist/skills/index.d.ts +10 -0
- package/dist/skills/index.d.ts.map +1 -0
- package/dist/skills/index.js +9 -0
- package/dist/skills/index.js.map +1 -0
- package/dist/skills/skill-analyzer.d.ts +16 -0
- package/dist/skills/skill-analyzer.d.ts.map +1 -0
- package/dist/skills/skill-analyzer.js +361 -0
- package/dist/skills/skill-analyzer.js.map +1 -0
- package/dist/skills/types.d.ts +195 -0
- package/dist/skills/types.d.ts.map +1 -0
- package/dist/skills/types.js +7 -0
- package/dist/skills/types.js.map +1 -0
- package/dist/specifica/conflict-resolver.d.ts +23 -0
- package/dist/specifica/conflict-resolver.d.ts.map +1 -0
- package/dist/specifica/conflict-resolver.js +129 -0
- package/dist/specifica/conflict-resolver.js.map +1 -0
- package/dist/specifica/evidence-aggregator.d.ts +33 -0
- package/dist/specifica/evidence-aggregator.d.ts.map +1 -0
- package/dist/specifica/evidence-aggregator.js +236 -0
- package/dist/specifica/evidence-aggregator.js.map +1 -0
- package/dist/specifica/evidence-extractor.d.ts +13 -0
- package/dist/specifica/evidence-extractor.d.ts.map +1 -0
- package/dist/specifica/evidence-extractor.js +431 -0
- package/dist/specifica/evidence-extractor.js.map +1 -0
- package/dist/specifica/feature-clustering.d.ts +19 -0
- package/dist/specifica/feature-clustering.d.ts.map +1 -0
- package/dist/specifica/feature-clustering.js +231 -0
- package/dist/specifica/feature-clustering.js.map +1 -0
- package/dist/specifica/generator.d.ts +16 -0
- package/dist/specifica/generator.d.ts.map +1 -0
- package/dist/specifica/generator.js +277 -0
- package/dist/specifica/generator.js.map +1 -0
- package/dist/specifica/index.d.ts +15 -0
- package/dist/specifica/index.d.ts.map +1 -0
- package/dist/specifica/index.js +18 -0
- package/dist/specifica/index.js.map +1 -0
- package/dist/specifica/prompts.d.ts +21 -0
- package/dist/specifica/prompts.d.ts.map +1 -0
- package/dist/specifica/prompts.js +196 -0
- package/dist/specifica/prompts.js.map +1 -0
- package/dist/specifica/spec-generator.d.ts +22 -0
- package/dist/specifica/spec-generator.d.ts.map +1 -0
- package/dist/specifica/spec-generator.js +229 -0
- package/dist/specifica/spec-generator.js.map +1 -0
- package/dist/specifica/types.d.ts +213 -0
- package/dist/specifica/types.d.ts.map +1 -0
- package/dist/specifica/types.js +7 -0
- package/dist/specifica/types.js.map +1 -0
- package/dist/utils/logger.d.ts +17 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +51 -0
- package/dist/utils/logger.js.map +1 -0
- package/package.json +99 -0
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Enriched section builder
|
|
3
|
+
*
|
|
4
|
+
* Provides structure for LLM-enhanced metadata:
|
|
5
|
+
* - Function roles (controller, service, repository)
|
|
6
|
+
* - Risk levels
|
|
7
|
+
* - Trust boundaries
|
|
8
|
+
* - Additional sources/sinks discovered by analysis
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Build the enriched section with heuristic-based analysis.
|
|
12
|
+
* This provides a baseline that LLM can enhance.
|
|
13
|
+
*/
|
|
14
|
+
export function buildEnriched(types, calls, existingSources, existingSinks) {
|
|
15
|
+
const functions = analyzeMethodRoles(types);
|
|
16
|
+
const additionalSources = findAdditionalSources(calls, existingSources);
|
|
17
|
+
const additionalSinks = findAdditionalSinks(calls, existingSinks);
|
|
18
|
+
const resolvedCalls = suggestCallResolutions(calls);
|
|
19
|
+
return {
|
|
20
|
+
functions: functions.length > 0 ? functions : undefined,
|
|
21
|
+
additional_sources: additionalSources.length > 0 ? additionalSources : undefined,
|
|
22
|
+
additional_sinks: additionalSinks.length > 0 ? additionalSinks : undefined,
|
|
23
|
+
resolved_calls: resolvedCalls.length > 0 ? resolvedCalls : undefined,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Analyze method roles based on naming conventions and annotations.
|
|
28
|
+
*/
|
|
29
|
+
function analyzeMethodRoles(types) {
|
|
30
|
+
const functions = [];
|
|
31
|
+
for (const type of types) {
|
|
32
|
+
const classRole = inferClassRole(type);
|
|
33
|
+
for (const method of type.methods) {
|
|
34
|
+
const role = inferMethodRole(method.name, type, classRole);
|
|
35
|
+
const risk = assessMethodRisk(method, type);
|
|
36
|
+
const trustBoundary = determineTrustBoundary(method, type);
|
|
37
|
+
// Only include if we have meaningful analysis
|
|
38
|
+
if (role !== 'utility' || risk !== 'low' || trustBoundary !== 'internal') {
|
|
39
|
+
functions.push({
|
|
40
|
+
method_name: `${type.name}.${method.name}`,
|
|
41
|
+
role,
|
|
42
|
+
risk,
|
|
43
|
+
trust_boundary: trustBoundary,
|
|
44
|
+
summary: generateMethodSummary(method.name, role, type.name),
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return functions;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Infer the role of a class based on naming and annotations.
|
|
53
|
+
*/
|
|
54
|
+
function inferClassRole(type) {
|
|
55
|
+
const name = type.name.toLowerCase();
|
|
56
|
+
const annotations = type.annotations.map(a => a.toLowerCase());
|
|
57
|
+
// Check annotations first
|
|
58
|
+
if (annotations.some(a => a.includes('controller') || a.includes('restcontroller'))) {
|
|
59
|
+
return 'controller';
|
|
60
|
+
}
|
|
61
|
+
if (annotations.some(a => a.includes('service'))) {
|
|
62
|
+
return 'service';
|
|
63
|
+
}
|
|
64
|
+
if (annotations.some(a => a.includes('repository'))) {
|
|
65
|
+
return 'repository';
|
|
66
|
+
}
|
|
67
|
+
// Check naming conventions
|
|
68
|
+
if (name.includes('controller') || name.includes('resource') || name.includes('endpoint')) {
|
|
69
|
+
return 'controller';
|
|
70
|
+
}
|
|
71
|
+
if (name.includes('service') || name.includes('manager') || name.includes('handler')) {
|
|
72
|
+
return 'service';
|
|
73
|
+
}
|
|
74
|
+
if (name.includes('repository') || name.includes('dao') || name.includes('store')) {
|
|
75
|
+
return 'repository';
|
|
76
|
+
}
|
|
77
|
+
return 'utility';
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Infer method role based on naming and context.
|
|
81
|
+
*/
|
|
82
|
+
function inferMethodRole(methodName, type, classRole) {
|
|
83
|
+
const name = methodName.toLowerCase();
|
|
84
|
+
// HTTP handler methods in controllers
|
|
85
|
+
if (classRole === 'controller') {
|
|
86
|
+
const httpMethods = ['get', 'post', 'put', 'delete', 'patch', 'handle', 'do'];
|
|
87
|
+
if (httpMethods.some(m => name.startsWith(m))) {
|
|
88
|
+
return 'controller';
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
// Data access methods
|
|
92
|
+
if (classRole === 'repository' || name.startsWith('find') || name.startsWith('save') ||
|
|
93
|
+
name.startsWith('delete') || name.startsWith('update') || name.startsWith('query')) {
|
|
94
|
+
return 'repository';
|
|
95
|
+
}
|
|
96
|
+
// Business logic methods
|
|
97
|
+
if (classRole === 'service' || name.includes('process') || name.includes('validate') ||
|
|
98
|
+
name.includes('calculate') || name.includes('compute')) {
|
|
99
|
+
return 'service';
|
|
100
|
+
}
|
|
101
|
+
return classRole;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Assess risk level of a method.
|
|
105
|
+
*/
|
|
106
|
+
function assessMethodRisk(method, type) {
|
|
107
|
+
const methodName = method.name.toLowerCase();
|
|
108
|
+
const annotations = [...method.annotations, ...type.annotations].map(a => a.toLowerCase());
|
|
109
|
+
// High risk: authentication, authorization, crypto
|
|
110
|
+
const highRiskPatterns = [
|
|
111
|
+
'auth', 'login', 'password', 'credential', 'token',
|
|
112
|
+
'encrypt', 'decrypt', 'hash', 'sign', 'verify',
|
|
113
|
+
'admin', 'privilege', 'permission', 'role',
|
|
114
|
+
];
|
|
115
|
+
if (highRiskPatterns.some(p => methodName.includes(p))) {
|
|
116
|
+
return 'high';
|
|
117
|
+
}
|
|
118
|
+
// High risk: SQL/command execution
|
|
119
|
+
const dangerousPatterns = ['execute', 'query', 'eval', 'exec', 'run'];
|
|
120
|
+
if (dangerousPatterns.some(p => methodName.includes(p))) {
|
|
121
|
+
return 'high';
|
|
122
|
+
}
|
|
123
|
+
// Medium risk: data processing with user input
|
|
124
|
+
if (annotations.some(a => a.includes('requestparam') || a.includes('requestbody') ||
|
|
125
|
+
a.includes('pathvariable'))) {
|
|
126
|
+
return 'medium';
|
|
127
|
+
}
|
|
128
|
+
// Medium risk: file operations
|
|
129
|
+
const filePatterns = ['file', 'read', 'write', 'upload', 'download', 'stream'];
|
|
130
|
+
if (filePatterns.some(p => methodName.includes(p))) {
|
|
131
|
+
return 'medium';
|
|
132
|
+
}
|
|
133
|
+
return 'low';
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Determine trust boundary for a method.
|
|
137
|
+
*/
|
|
138
|
+
function determineTrustBoundary(method, type) {
|
|
139
|
+
const annotations = [...method.annotations, ...type.annotations];
|
|
140
|
+
// Entry points: HTTP endpoints
|
|
141
|
+
const entryPointAnnotations = [
|
|
142
|
+
'GetMapping', 'PostMapping', 'PutMapping', 'DeleteMapping', 'PatchMapping',
|
|
143
|
+
'RequestMapping', 'GET', 'POST', 'PUT', 'DELETE',
|
|
144
|
+
'Path', 'Consumes', 'Produces',
|
|
145
|
+
];
|
|
146
|
+
if (entryPointAnnotations.some(a => annotations.some(ann => ann.includes(a)))) {
|
|
147
|
+
return 'entry_point';
|
|
148
|
+
}
|
|
149
|
+
// External: calls to external services
|
|
150
|
+
const externalPatterns = ['client', 'remote', 'external', 'api', 'http', 'rest'];
|
|
151
|
+
if (externalPatterns.some(p => method.name.toLowerCase().includes(p))) {
|
|
152
|
+
return 'external';
|
|
153
|
+
}
|
|
154
|
+
// Check if class is a controller (all public methods are entry points)
|
|
155
|
+
if (type.annotations.some(a => a.includes('Controller') || a.includes('RestController'))) {
|
|
156
|
+
if (method.modifiers.includes('public')) {
|
|
157
|
+
return 'entry_point';
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
return 'internal';
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Generate a summary for a method.
|
|
164
|
+
*/
|
|
165
|
+
function generateMethodSummary(methodName, role, className) {
|
|
166
|
+
const summaries = {
|
|
167
|
+
controller: `HTTP endpoint handler in ${className}`,
|
|
168
|
+
service: `Business logic method in ${className}`,
|
|
169
|
+
repository: `Data access method in ${className}`,
|
|
170
|
+
utility: `Utility method in ${className}`,
|
|
171
|
+
};
|
|
172
|
+
return summaries[role] || `Method ${methodName} in ${className}`;
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Find additional sources that heuristics might have missed.
|
|
176
|
+
*/
|
|
177
|
+
function findAdditionalSources(calls, existingSources) {
|
|
178
|
+
const additional = [];
|
|
179
|
+
const existingLines = new Set(existingSources.map(s => s.line));
|
|
180
|
+
// Patterns that might indicate sources
|
|
181
|
+
const sourcePatterns = [
|
|
182
|
+
{ pattern: /read/i, type: 'io_input' },
|
|
183
|
+
{ pattern: /input/i, type: 'io_input' },
|
|
184
|
+
{ pattern: /parse/i, type: 'io_input' },
|
|
185
|
+
{ pattern: /deserialize/i, type: 'io_input' },
|
|
186
|
+
{ pattern: /decode/i, type: 'io_input' },
|
|
187
|
+
{ pattern: /fetch/i, type: 'network_input' },
|
|
188
|
+
{ pattern: /download/i, type: 'network_input' },
|
|
189
|
+
{ pattern: /receive/i, type: 'network_input' },
|
|
190
|
+
];
|
|
191
|
+
for (const call of calls) {
|
|
192
|
+
// Skip if already identified
|
|
193
|
+
if (existingLines.has(call.location.line))
|
|
194
|
+
continue;
|
|
195
|
+
for (const { pattern, type } of sourcePatterns) {
|
|
196
|
+
if (pattern.test(call.method_name)) {
|
|
197
|
+
additional.push({
|
|
198
|
+
type,
|
|
199
|
+
location: `${call.receiver ? call.receiver + '.' : ''}${call.method_name}() in ${call.in_method || 'unknown'}`,
|
|
200
|
+
severity: 'medium',
|
|
201
|
+
line: call.location.line,
|
|
202
|
+
confidence: 0.6, // Lower confidence for heuristic matches
|
|
203
|
+
});
|
|
204
|
+
break;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
return additional;
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Find additional sinks that heuristics might have missed.
|
|
212
|
+
*/
|
|
213
|
+
function findAdditionalSinks(calls, existingSinks) {
|
|
214
|
+
const additional = [];
|
|
215
|
+
const existingLines = new Set(existingSinks.map(s => s.line));
|
|
216
|
+
// Patterns that might indicate sinks
|
|
217
|
+
const sinkPatterns = [
|
|
218
|
+
{ pattern: /write/i, type: 'xss', cwe: 'CWE-79' },
|
|
219
|
+
{ pattern: /print/i, type: 'xss', cwe: 'CWE-79' },
|
|
220
|
+
{ pattern: /render/i, type: 'xss', cwe: 'CWE-79' },
|
|
221
|
+
{ pattern: /redirect/i, type: 'ssrf', cwe: 'CWE-918' },
|
|
222
|
+
{ pattern: /forward/i, type: 'ssrf', cwe: 'CWE-918' },
|
|
223
|
+
{ pattern: /send/i, type: 'ssrf', cwe: 'CWE-918' },
|
|
224
|
+
{ pattern: /log/i, type: 'xss', cwe: 'CWE-117' }, // Log injection
|
|
225
|
+
];
|
|
226
|
+
for (const call of calls) {
|
|
227
|
+
// Skip if already identified
|
|
228
|
+
if (existingLines.has(call.location.line))
|
|
229
|
+
continue;
|
|
230
|
+
// Only consider calls with arguments (potential data flow)
|
|
231
|
+
if (call.arguments.length === 0)
|
|
232
|
+
continue;
|
|
233
|
+
for (const { pattern, type, cwe } of sinkPatterns) {
|
|
234
|
+
if (pattern.test(call.method_name)) {
|
|
235
|
+
additional.push({
|
|
236
|
+
type,
|
|
237
|
+
cwe,
|
|
238
|
+
location: `${call.receiver ? call.receiver + '.' : ''}${call.method_name}() in ${call.in_method || 'unknown'}`,
|
|
239
|
+
line: call.location.line,
|
|
240
|
+
confidence: 0.5, // Lower confidence for heuristic matches
|
|
241
|
+
});
|
|
242
|
+
break;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
return additional;
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* Suggest resolutions for unresolved calls based on heuristics.
|
|
250
|
+
*/
|
|
251
|
+
function suggestCallResolutions(calls) {
|
|
252
|
+
const resolved = [];
|
|
253
|
+
for (let i = 0; i < calls.length; i++) {
|
|
254
|
+
const call = calls[i];
|
|
255
|
+
// Skip already resolved calls
|
|
256
|
+
if (call.resolved)
|
|
257
|
+
continue;
|
|
258
|
+
// Try to resolve based on common patterns
|
|
259
|
+
const suggestion = suggestResolution(call);
|
|
260
|
+
if (suggestion) {
|
|
261
|
+
resolved.push({
|
|
262
|
+
call_id: i,
|
|
263
|
+
resolved_to: suggestion.target,
|
|
264
|
+
confidence: suggestion.confidence,
|
|
265
|
+
reason: suggestion.reason,
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
return resolved;
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* Suggest a resolution for an unresolved call.
|
|
273
|
+
*/
|
|
274
|
+
function suggestResolution(call) {
|
|
275
|
+
// Common Spring/Java patterns
|
|
276
|
+
const commonResolutions = {
|
|
277
|
+
save: { suffix: 'Impl', confidence: 0.7, reason: 'Common repository pattern' },
|
|
278
|
+
find: { suffix: 'Impl', confidence: 0.7, reason: 'Common repository pattern' },
|
|
279
|
+
delete: { suffix: 'Impl', confidence: 0.7, reason: 'Common repository pattern' },
|
|
280
|
+
update: { suffix: 'Impl', confidence: 0.7, reason: 'Common repository pattern' },
|
|
281
|
+
process: { suffix: 'Impl', confidence: 0.6, reason: 'Common service pattern' },
|
|
282
|
+
handle: { suffix: 'Impl', confidence: 0.6, reason: 'Common handler pattern' },
|
|
283
|
+
execute: { suffix: 'Impl', confidence: 0.6, reason: 'Common command pattern' },
|
|
284
|
+
};
|
|
285
|
+
const methodLower = call.method_name.toLowerCase();
|
|
286
|
+
for (const [pattern, resolution] of Object.entries(commonResolutions)) {
|
|
287
|
+
if (methodLower.startsWith(pattern) && call.receiver) {
|
|
288
|
+
return {
|
|
289
|
+
target: `${call.receiver}${resolution.suffix}.${call.method_name}`,
|
|
290
|
+
confidence: resolution.confidence,
|
|
291
|
+
reason: resolution.reason,
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
return null;
|
|
296
|
+
}
|
|
297
|
+
//# sourceMappingURL=enriched.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"enriched.js","sourceRoot":"","sources":["../../src/analysis/enriched.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LLM-based Correlated Predicate Analysis
|
|
3
|
+
*
|
|
4
|
+
* Detects when predicates (conditions) are correlated, meaning:
|
|
5
|
+
* - They use the same variable
|
|
6
|
+
* - One implies the other
|
|
7
|
+
* - They are logically opposite
|
|
8
|
+
*
|
|
9
|
+
* Example:
|
|
10
|
+
* if (choice) { name = getParameter(); } // taint source
|
|
11
|
+
* if (choice) { println(name); } // taint sink
|
|
12
|
+
*
|
|
13
|
+
* Since both conditions use the same 'choice' variable,
|
|
14
|
+
* if choice=true, BOTH branches execute (vulnerable)
|
|
15
|
+
* if choice=false, NEITHER branch executes (safe)
|
|
16
|
+
*
|
|
17
|
+
* A naive analyzer might think name could be tainted when reaching the sink,
|
|
18
|
+
* but correlated predicate analysis reveals the true dataflow.
|
|
19
|
+
*/
|
|
20
|
+
import type { CFG } from 'circle-ir';
|
|
21
|
+
import { type AxLLMClient } from '../llm/ax-client.js';
|
|
22
|
+
/**
|
|
23
|
+
* Predicate location with its condition
|
|
24
|
+
*/
|
|
25
|
+
export interface PredicateLocation {
|
|
26
|
+
line: number;
|
|
27
|
+
condition: string;
|
|
28
|
+
blockId: number;
|
|
29
|
+
trueTargets: number[];
|
|
30
|
+
falseTargets: number[];
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Correlation type between predicates
|
|
34
|
+
*/
|
|
35
|
+
export type CorrelationType = 'same_variable' | 'opposite' | 'implies' | 'mutual_exclusive' | 'independent' | 'unknown';
|
|
36
|
+
/**
|
|
37
|
+
* Correlated predicate group
|
|
38
|
+
*/
|
|
39
|
+
export interface CorrelatedGroup {
|
|
40
|
+
predicates: PredicateLocation[];
|
|
41
|
+
correlation: CorrelationType;
|
|
42
|
+
confidence: number;
|
|
43
|
+
reasoning: string;
|
|
44
|
+
bothTrueReachable: boolean;
|
|
45
|
+
bothFalseReachable: boolean;
|
|
46
|
+
mixedReachable: boolean;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Result of correlated predicate analysis
|
|
50
|
+
*/
|
|
51
|
+
export interface CorrelatedPredicateResult {
|
|
52
|
+
predicates: PredicateLocation[];
|
|
53
|
+
groups: CorrelatedGroup[];
|
|
54
|
+
unreachableLines: Set<number>;
|
|
55
|
+
unreachablePairs: Array<{
|
|
56
|
+
sourceLine: number;
|
|
57
|
+
sinkLine: number;
|
|
58
|
+
reason: string;
|
|
59
|
+
}>;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Extract predicates from CFG
|
|
63
|
+
*/
|
|
64
|
+
export declare function extractPredicates(cfg: CFG, code: string): PredicateLocation[];
|
|
65
|
+
/**
|
|
66
|
+
* Find obviously correlated predicates using simple pattern matching
|
|
67
|
+
*/
|
|
68
|
+
export declare function findSimpleCorrelations(predicates: PredicateLocation[]): CorrelatedGroup[];
|
|
69
|
+
/**
|
|
70
|
+
* Analyze correlated predicates using LLM
|
|
71
|
+
*/
|
|
72
|
+
export declare function analyzeCorrelatedPredicates(code: string, predicates: PredicateLocation[], llmClient?: AxLLMClient): Promise<CorrelatedPredicateResult>;
|
|
73
|
+
/**
|
|
74
|
+
* Check if a source-sink pair is unreachable due to correlated predicates
|
|
75
|
+
*/
|
|
76
|
+
export declare function isPairUnreachableDueToCorrelation(sourceLine: number, sinkLine: number, analysisResult: CorrelatedPredicateResult): {
|
|
77
|
+
unreachable: boolean;
|
|
78
|
+
reason?: string;
|
|
79
|
+
};
|
|
80
|
+
//# sourceMappingURL=llm-correlated-predicates.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"llm-correlated-predicates.d.ts","sourceRoot":"","sources":["../../src/analysis/llm-correlated-predicates.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,EAAE,GAAG,EAAY,MAAM,WAAW,CAAC;AAC/C,OAAO,EAAkB,KAAK,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAEvE;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB;AAED;;GAEG;AACH,MAAM,MAAM,eAAe,GACvB,eAAe,GACf,UAAU,GACV,SAAS,GACT,kBAAkB,GAClB,aAAa,GACb,SAAS,CAAC;AAEd;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,iBAAiB,EAAE,CAAC;IAChC,WAAW,EAAE,eAAe,CAAC;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAElB,iBAAiB,EAAE,OAAO,CAAC;IAC3B,kBAAkB,EAAE,OAAO,CAAC;IAC5B,cAAc,EAAE,OAAO,CAAC;CACzB;AAED;;GAEG;AACH,MAAM,WAAW,yBAAyB;IACxC,UAAU,EAAE,iBAAiB,EAAE,CAAC;IAChC,MAAM,EAAE,eAAe,EAAE,CAAC;IAE1B,gBAAgB,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAE9B,gBAAgB,EAAE,KAAK,CAAC;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACnF;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,GAAG,iBAAiB,EAAE,CAwC7E;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,UAAU,EAAE,iBAAiB,EAAE,GAAG,eAAe,EAAE,CA2DzF;AAiBD;;GAEG;AACH,wBAAsB,2BAA2B,CAC/C,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,iBAAiB,EAAE,EAC/B,SAAS,CAAC,EAAE,WAAW,GACtB,OAAO,CAAC,yBAAyB,CAAC,CAsGpC;AAED;;GAEG;AACH,wBAAgB,iCAAiC,CAC/C,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,EAChB,cAAc,EAAE,yBAAyB,GACxC;IAAE,WAAW,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CAkC3C"}
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LLM-based Correlated Predicate Analysis
|
|
3
|
+
*
|
|
4
|
+
* Detects when predicates (conditions) are correlated, meaning:
|
|
5
|
+
* - They use the same variable
|
|
6
|
+
* - One implies the other
|
|
7
|
+
* - They are logically opposite
|
|
8
|
+
*
|
|
9
|
+
* Example:
|
|
10
|
+
* if (choice) { name = getParameter(); } // taint source
|
|
11
|
+
* if (choice) { println(name); } // taint sink
|
|
12
|
+
*
|
|
13
|
+
* Since both conditions use the same 'choice' variable,
|
|
14
|
+
* if choice=true, BOTH branches execute (vulnerable)
|
|
15
|
+
* if choice=false, NEITHER branch executes (safe)
|
|
16
|
+
*
|
|
17
|
+
* A naive analyzer might think name could be tainted when reaching the sink,
|
|
18
|
+
* but correlated predicate analysis reveals the true dataflow.
|
|
19
|
+
*/
|
|
20
|
+
import { getAxLLMClient } from '../llm/ax-client.js';
|
|
21
|
+
/**
|
|
22
|
+
* Extract predicates from CFG
|
|
23
|
+
*/
|
|
24
|
+
export function extractPredicates(cfg, code) {
|
|
25
|
+
const predicates = [];
|
|
26
|
+
const lines = code.split('\n');
|
|
27
|
+
for (const block of cfg.blocks) {
|
|
28
|
+
if (block.type === 'conditional') {
|
|
29
|
+
// Find the condition in the code
|
|
30
|
+
const startLine = block.start_line;
|
|
31
|
+
const endLine = block.end_line || startLine;
|
|
32
|
+
// Extract condition text
|
|
33
|
+
let condition = '';
|
|
34
|
+
for (let i = startLine - 1; i < endLine && i < lines.length; i++) {
|
|
35
|
+
const line = lines[i];
|
|
36
|
+
// Look for if/while/for conditions
|
|
37
|
+
const match = line.match(/(?:if|while|for)\s*\(([^)]+)\)/);
|
|
38
|
+
if (match) {
|
|
39
|
+
condition = match[1].trim();
|
|
40
|
+
break;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
if (condition) {
|
|
44
|
+
// Find edges from this block
|
|
45
|
+
const edges = cfg.edges.filter(e => e.from === block.id);
|
|
46
|
+
const trueTargets = edges.filter(e => e.type === 'true').map(e => e.to);
|
|
47
|
+
const falseTargets = edges.filter(e => e.type === 'false').map(e => e.to);
|
|
48
|
+
predicates.push({
|
|
49
|
+
line: startLine,
|
|
50
|
+
condition,
|
|
51
|
+
blockId: block.id,
|
|
52
|
+
trueTargets,
|
|
53
|
+
falseTargets,
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return predicates;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Find obviously correlated predicates using simple pattern matching
|
|
62
|
+
*/
|
|
63
|
+
export function findSimpleCorrelations(predicates) {
|
|
64
|
+
const groups = [];
|
|
65
|
+
for (let i = 0; i < predicates.length; i++) {
|
|
66
|
+
for (let j = i + 1; j < predicates.length; j++) {
|
|
67
|
+
const p1 = predicates[i];
|
|
68
|
+
const p2 = predicates[j];
|
|
69
|
+
// Check for same condition
|
|
70
|
+
if (p1.condition === p2.condition) {
|
|
71
|
+
groups.push({
|
|
72
|
+
predicates: [p1, p2],
|
|
73
|
+
correlation: 'same_variable',
|
|
74
|
+
confidence: 1.0,
|
|
75
|
+
reasoning: `Both conditions are identical: "${p1.condition}"`,
|
|
76
|
+
bothTrueReachable: true,
|
|
77
|
+
bothFalseReachable: true,
|
|
78
|
+
mixedReachable: false,
|
|
79
|
+
});
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
// Check for negation
|
|
83
|
+
if (p1.condition === `!${p2.condition}` ||
|
|
84
|
+
`!${p1.condition}` === p2.condition ||
|
|
85
|
+
p1.condition === `!(${p2.condition})` ||
|
|
86
|
+
`!(${p1.condition})` === p2.condition) {
|
|
87
|
+
groups.push({
|
|
88
|
+
predicates: [p1, p2],
|
|
89
|
+
correlation: 'opposite',
|
|
90
|
+
confidence: 1.0,
|
|
91
|
+
reasoning: `Conditions are negations: "${p1.condition}" vs "${p2.condition}"`,
|
|
92
|
+
bothTrueReachable: false,
|
|
93
|
+
bothFalseReachable: false,
|
|
94
|
+
mixedReachable: true,
|
|
95
|
+
});
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
// Check for same variable in condition (basic check)
|
|
99
|
+
const vars1 = extractVariables(p1.condition);
|
|
100
|
+
const vars2 = extractVariables(p2.condition);
|
|
101
|
+
const commonVars = vars1.filter(v => vars2.includes(v));
|
|
102
|
+
if (commonVars.length > 0) {
|
|
103
|
+
groups.push({
|
|
104
|
+
predicates: [p1, p2],
|
|
105
|
+
correlation: 'same_variable',
|
|
106
|
+
confidence: 0.7,
|
|
107
|
+
reasoning: `Both conditions use variable(s): ${commonVars.join(', ')}`,
|
|
108
|
+
bothTrueReachable: true, // Conservative: assume both can be true
|
|
109
|
+
bothFalseReachable: true,
|
|
110
|
+
mixedReachable: true,
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return groups;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Extract variable names from a condition string
|
|
119
|
+
*/
|
|
120
|
+
function extractVariables(condition) {
|
|
121
|
+
// Remove string literals
|
|
122
|
+
const withoutStrings = condition.replace(/"[^"]*"/g, '').replace(/'[^']*'/g, '');
|
|
123
|
+
// Remove numbers
|
|
124
|
+
const withoutNumbers = withoutStrings.replace(/\b\d+\b/g, '');
|
|
125
|
+
// Extract identifiers
|
|
126
|
+
const matches = withoutNumbers.match(/\b[a-zA-Z_][a-zA-Z0-9_]*\b/g) || [];
|
|
127
|
+
// Filter out keywords
|
|
128
|
+
const keywords = new Set(['if', 'else', 'while', 'for', 'true', 'false', 'null', 'new', 'instanceof', 'return']);
|
|
129
|
+
return matches.filter(m => !keywords.has(m));
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Analyze correlated predicates using LLM
|
|
133
|
+
*/
|
|
134
|
+
export async function analyzeCorrelatedPredicates(code, predicates, llmClient) {
|
|
135
|
+
// First, find simple correlations
|
|
136
|
+
const simpleGroups = findSimpleCorrelations(predicates);
|
|
137
|
+
// If we have predicates that might need deeper analysis
|
|
138
|
+
const needsLLMAnalysis = predicates.length > 1 &&
|
|
139
|
+
simpleGroups.length < (predicates.length * (predicates.length - 1)) / 2;
|
|
140
|
+
let llmGroups = [];
|
|
141
|
+
if (needsLLMAnalysis) {
|
|
142
|
+
try {
|
|
143
|
+
const client = llmClient || getAxLLMClient();
|
|
144
|
+
const result = await client.analyzeCorrelatedPredicates({
|
|
145
|
+
code,
|
|
146
|
+
predicateLocations: predicates.map(p => ({
|
|
147
|
+
line: p.line,
|
|
148
|
+
condition: p.condition,
|
|
149
|
+
})),
|
|
150
|
+
});
|
|
151
|
+
// Convert LLM results to our format
|
|
152
|
+
for (const group of result.correlatedGroups) {
|
|
153
|
+
const predIndices = group.predicates || [];
|
|
154
|
+
const groupPredicates = predIndices
|
|
155
|
+
.map(idx => predicates[idx])
|
|
156
|
+
.filter(p => p !== undefined);
|
|
157
|
+
if (groupPredicates.length >= 2) {
|
|
158
|
+
const correlation = group.correlation || 'independent';
|
|
159
|
+
llmGroups.push({
|
|
160
|
+
predicates: groupPredicates,
|
|
161
|
+
correlation,
|
|
162
|
+
confidence: typeof group.confidence === 'number' ? group.confidence : 0.5,
|
|
163
|
+
reasoning: result.reasoning || '',
|
|
164
|
+
bothTrueReachable: correlation !== 'opposite' && correlation !== 'mutual_exclusive',
|
|
165
|
+
bothFalseReachable: correlation !== 'opposite' && correlation !== 'mutual_exclusive',
|
|
166
|
+
mixedReachable: correlation === 'opposite' || correlation === 'independent',
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
catch (error) {
|
|
172
|
+
// Fall back to simple analysis only
|
|
173
|
+
console.warn('LLM correlated predicate analysis failed, using simple analysis');
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
// Merge simple and LLM groups (prefer LLM if available)
|
|
177
|
+
const allGroups = [...simpleGroups];
|
|
178
|
+
for (const llmGroup of llmGroups) {
|
|
179
|
+
// Check if this group already exists in simple groups
|
|
180
|
+
const exists = allGroups.some(g => g.predicates.length === llmGroup.predicates.length &&
|
|
181
|
+
g.predicates.every(p => llmGroup.predicates.some(lp => lp.line === p.line)));
|
|
182
|
+
if (!exists) {
|
|
183
|
+
allGroups.push(llmGroup);
|
|
184
|
+
}
|
|
185
|
+
else {
|
|
186
|
+
// Update existing group with LLM analysis
|
|
187
|
+
const existing = allGroups.find(g => g.predicates.length === llmGroup.predicates.length &&
|
|
188
|
+
g.predicates.every(p => llmGroup.predicates.some(lp => lp.line === p.line)));
|
|
189
|
+
if (existing && llmGroup.confidence > existing.confidence) {
|
|
190
|
+
Object.assign(existing, llmGroup);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
// Determine unreachable lines and pairs
|
|
195
|
+
const unreachableLines = new Set();
|
|
196
|
+
const unreachablePairs = [];
|
|
197
|
+
for (const group of allGroups) {
|
|
198
|
+
if (group.correlation === 'opposite' && group.confidence > 0.8) {
|
|
199
|
+
// If predicates are opposite, code in one true branch can't reach code in other true branch
|
|
200
|
+
const [p1, p2] = group.predicates;
|
|
201
|
+
// Add unreachable pair
|
|
202
|
+
unreachablePairs.push({
|
|
203
|
+
sourceLine: p1.line,
|
|
204
|
+
sinkLine: p2.line,
|
|
205
|
+
reason: `Predicates at lines ${p1.line} and ${p2.line} are opposite: ${p1.condition} vs ${p2.condition}`,
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
if (group.correlation === 'mutual_exclusive' && group.confidence > 0.8) {
|
|
209
|
+
const [p1, p2] = group.predicates;
|
|
210
|
+
unreachablePairs.push({
|
|
211
|
+
sourceLine: p1.line,
|
|
212
|
+
sinkLine: p2.line,
|
|
213
|
+
reason: `Predicates at lines ${p1.line} and ${p2.line} are mutually exclusive`,
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
return {
|
|
218
|
+
predicates,
|
|
219
|
+
groups: allGroups,
|
|
220
|
+
unreachableLines,
|
|
221
|
+
unreachablePairs,
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* Check if a source-sink pair is unreachable due to correlated predicates
|
|
226
|
+
*/
|
|
227
|
+
export function isPairUnreachableDueToCorrelation(sourceLine, sinkLine, analysisResult) {
|
|
228
|
+
// Check direct unreachable pairs
|
|
229
|
+
const pair = analysisResult.unreachablePairs.find(p => (p.sourceLine <= sourceLine && p.sinkLine >= sinkLine) ||
|
|
230
|
+
(p.sourceLine <= sinkLine && p.sinkLine >= sourceLine));
|
|
231
|
+
if (pair) {
|
|
232
|
+
return { unreachable: true, reason: pair.reason };
|
|
233
|
+
}
|
|
234
|
+
// Check if source and sink are in mutually exclusive branches
|
|
235
|
+
for (const group of analysisResult.groups) {
|
|
236
|
+
if (group.correlation !== 'same_variable' && group.correlation !== 'implies') {
|
|
237
|
+
continue;
|
|
238
|
+
}
|
|
239
|
+
// Find predicates that guard source and sink
|
|
240
|
+
// (This is a simplified check - full implementation would need CFG traversal)
|
|
241
|
+
const [p1, p2] = group.predicates;
|
|
242
|
+
// If both predicates guard both source and sink with same condition,
|
|
243
|
+
// they are reachable together (either both execute or neither)
|
|
244
|
+
if (p1.line < sourceLine && p2.line < sinkLine) {
|
|
245
|
+
// Source is after p1, sink is after p2
|
|
246
|
+
// If same_variable correlation, they execute together
|
|
247
|
+
if (group.correlation === 'same_variable' && group.confidence > 0.9) {
|
|
248
|
+
// This is actually reachable together!
|
|
249
|
+
return { unreachable: false };
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
return { unreachable: false };
|
|
254
|
+
}
|
|
255
|
+
//# sourceMappingURL=llm-correlated-predicates.js.map
|