kirograph 0.19.0 → 0.20.1
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 +10 -8
- package/dist/architecture/layers/dart.d.ts +10 -0
- package/dist/architecture/layers/dart.d.ts.map +1 -0
- package/dist/architecture/layers/elixir.d.ts +6 -0
- package/dist/architecture/layers/elixir.d.ts.map +1 -0
- package/dist/architecture/layers/index.d.ts.map +1 -1
- package/dist/architecture/layers/ocaml.d.ts +6 -0
- package/dist/architecture/layers/ocaml.d.ts.map +1 -0
- package/dist/architecture/layers/scala.d.ts +6 -0
- package/dist/architecture/layers/scala.d.ts.map +1 -0
- package/dist/architecture/layers/solidity.d.ts +6 -0
- package/dist/architecture/layers/solidity.d.ts.map +1 -0
- package/dist/architecture/layers/vue.d.ts +6 -0
- package/dist/architecture/layers/vue.d.ts.map +1 -0
- package/dist/architecture/manifest/elm.d.ts +3 -0
- package/dist/architecture/manifest/elm.d.ts.map +1 -0
- package/dist/architecture/manifest/index.d.ts.map +1 -1
- package/dist/architecture/manifest/ocaml.d.ts +3 -0
- package/dist/architecture/manifest/ocaml.d.ts.map +1 -0
- package/dist/architecture/manifest/scala.d.ts +3 -0
- package/dist/architecture/manifest/scala.d.ts.map +1 -0
- package/dist/bin/banner.d.ts.map +1 -1
- package/dist/bin/commands/affected.d.ts.map +1 -1
- package/dist/bin/commands/attack-surface.d.ts +3 -0
- package/dist/bin/commands/attack-surface.d.ts.map +1 -0
- package/dist/bin/commands/attack-surface.js +7 -0
- package/dist/bin/commands/attack-surface.js.map +2 -2
- package/dist/bin/commands/benchmark.d.ts +9 -0
- package/dist/bin/commands/benchmark.d.ts.map +1 -0
- package/dist/bin/commands/budget.d.ts +6 -0
- package/dist/bin/commands/budget.d.ts.map +1 -0
- package/dist/bin/commands/caveman.d.ts +7 -0
- package/dist/bin/commands/caveman.d.ts.map +1 -0
- package/dist/bin/commands/communities.d.ts +3 -0
- package/dist/bin/commands/communities.d.ts.map +1 -0
- package/dist/bin/commands/compression.d.ts +7 -0
- package/dist/bin/commands/compression.d.ts.map +1 -0
- package/dist/bin/commands/context.d.ts.map +1 -1
- package/dist/bin/commands/data.d.ts +3 -0
- package/dist/bin/commands/data.d.ts.map +1 -0
- package/dist/bin/commands/dead-code.d.ts +3 -0
- package/dist/bin/commands/dead-code.d.ts.map +1 -0
- package/dist/bin/commands/dep-confusion.d.ts +3 -0
- package/dist/bin/commands/dep-confusion.d.ts.map +1 -0
- package/dist/bin/commands/docs.d.ts +3 -0
- package/dist/bin/commands/docs.d.ts.map +1 -0
- package/dist/bin/commands/exec.d.ts +11 -0
- package/dist/bin/commands/exec.d.ts.map +1 -0
- package/dist/bin/commands/export.d.ts +3 -0
- package/dist/bin/commands/export.d.ts.map +1 -0
- package/dist/bin/commands/flows.d.ts +3 -0
- package/dist/bin/commands/flows.d.ts.map +1 -0
- package/dist/bin/commands/gain.d.ts +6 -0
- package/dist/bin/commands/gain.d.ts.map +1 -0
- package/dist/bin/commands/help.d.ts +7 -0
- package/dist/bin/commands/help.d.ts.map +1 -1
- package/dist/bin/commands/help.js +20 -3
- package/dist/bin/commands/help.js.map +2 -2
- package/dist/bin/commands/hotspots.d.ts +3 -0
- package/dist/bin/commands/hotspots.d.ts.map +1 -0
- package/dist/bin/commands/hotspots.js +94 -1
- package/dist/bin/commands/hotspots.js.map +3 -3
- package/dist/bin/commands/install.d.ts.map +1 -1
- package/dist/bin/commands/install.js +3 -3
- package/dist/bin/commands/install.js.map +2 -2
- package/dist/bin/commands/licenses.d.ts +3 -0
- package/dist/bin/commands/licenses.d.ts.map +1 -0
- package/dist/bin/commands/memory.d.ts +16 -0
- package/dist/bin/commands/memory.d.ts.map +1 -0
- package/dist/bin/commands/memory.js +151 -4
- package/dist/bin/commands/memory.js.map +2 -2
- package/dist/bin/commands/path.d.ts +3 -0
- package/dist/bin/commands/path.d.ts.map +1 -0
- package/dist/bin/commands/pattern.d.ts +3 -0
- package/dist/bin/commands/pattern.d.ts.map +1 -0
- package/dist/bin/commands/pattern.js +592 -0
- package/dist/bin/commands/pattern.js.map +7 -0
- package/dist/bin/commands/query.d.ts.map +1 -1
- package/dist/bin/commands/reachability.d.ts +3 -0
- package/dist/bin/commands/reachability.d.ts.map +1 -0
- package/dist/bin/commands/read.d.ts +6 -0
- package/dist/bin/commands/read.d.ts.map +1 -0
- package/dist/bin/commands/refactor.d.ts +3 -0
- package/dist/bin/commands/refactor.d.ts.map +1 -0
- package/dist/bin/commands/remediation.d.ts +3 -0
- package/dist/bin/commands/remediation.d.ts.map +1 -0
- package/dist/bin/commands/sbom.d.ts +3 -0
- package/dist/bin/commands/sbom.d.ts.map +1 -0
- package/dist/bin/commands/security-ci-report.d.ts +9 -0
- package/dist/bin/commands/security-ci-report.d.ts.map +1 -0
- package/dist/bin/commands/security-export.d.ts +2 -0
- package/dist/bin/commands/security-export.d.ts.map +1 -0
- package/dist/bin/commands/security-flows.d.ts +3 -0
- package/dist/bin/commands/security-flows.d.ts.map +1 -0
- package/dist/bin/commands/security-secrets.d.ts +3 -0
- package/dist/bin/commands/security-secrets.d.ts.map +1 -0
- package/dist/bin/commands/security.d.ts +3 -0
- package/dist/bin/commands/security.d.ts.map +1 -0
- package/dist/bin/commands/security.js +15 -0
- package/dist/bin/commands/security.js.map +2 -2
- package/dist/bin/commands/snapshot.d.ts +3 -0
- package/dist/bin/commands/snapshot.d.ts.map +1 -0
- package/dist/bin/commands/staleness.d.ts +3 -0
- package/dist/bin/commands/staleness.d.ts.map +1 -0
- package/dist/bin/commands/status.d.ts.map +1 -1
- package/dist/bin/commands/status.js +27 -0
- package/dist/bin/commands/status.js.map +2 -2
- package/dist/bin/commands/supply-chain.d.ts +3 -0
- package/dist/bin/commands/supply-chain.d.ts.map +1 -0
- package/dist/bin/commands/surprising.d.ts +3 -0
- package/dist/bin/commands/surprising.d.ts.map +1 -0
- package/dist/bin/commands/sync.d.ts.map +1 -1
- package/dist/bin/commands/uninit.d.ts.map +1 -1
- package/dist/bin/commands/utils.d.ts +5 -0
- package/dist/bin/commands/utils.d.ts.map +1 -1
- package/dist/bin/commands/vex.d.ts +3 -0
- package/dist/bin/commands/vex.d.ts.map +1 -0
- package/dist/bin/commands/vuln-suppress.d.ts +3 -0
- package/dist/bin/commands/vuln-suppress.d.ts.map +1 -0
- package/dist/bin/commands/vulns.d.ts +3 -0
- package/dist/bin/commands/vulns.d.ts.map +1 -0
- package/dist/bin/installer/archive.d.ts +47 -0
- package/dist/bin/installer/archive.d.ts.map +1 -0
- package/dist/bin/installer/auto-detect.d.ts +16 -0
- package/dist/bin/installer/auto-detect.d.ts.map +1 -0
- package/dist/bin/installer/caveman.d.ts +12 -0
- package/dist/bin/installer/caveman.d.ts.map +1 -0
- package/dist/bin/installer/cli-agent.d.ts +7 -2
- package/dist/bin/installer/cli-agent.d.ts.map +1 -1
- package/dist/bin/installer/cli-agent.js +6 -2
- package/dist/bin/installer/cli-agent.js.map +2 -2
- package/dist/bin/installer/common.d.ts +36 -0
- package/dist/bin/installer/common.d.ts.map +1 -0
- package/dist/bin/installer/common.js +2 -1
- package/dist/bin/installer/common.js.map +2 -2
- package/dist/bin/installer/config-prompt.d.ts +1 -1
- package/dist/bin/installer/config-prompt.d.ts.map +1 -1
- package/dist/bin/installer/config-prompt.js +74 -2
- package/dist/bin/installer/config-prompt.js.map +2 -2
- package/dist/bin/installer/dashboard.d.ts.map +1 -1
- package/dist/bin/installer/detect.d.ts +30 -0
- package/dist/bin/installer/detect.d.ts.map +1 -0
- package/dist/bin/installer/hooks.d.ts +4 -1
- package/dist/bin/installer/hooks.d.ts.map +1 -1
- package/dist/bin/installer/hooks.js +34 -0
- package/dist/bin/installer/hooks.js.map +2 -2
- package/dist/bin/installer/index.d.ts +5 -4
- package/dist/bin/installer/index.d.ts.map +1 -1
- package/dist/bin/installer/index.js +67 -8
- package/dist/bin/installer/index.js.map +2 -2
- package/dist/bin/installer/instructions.d.ts +14 -0
- package/dist/bin/installer/instructions.d.ts.map +1 -0
- package/dist/bin/installer/instructions.js +15 -1
- package/dist/bin/installer/instructions.js.map +2 -2
- package/dist/bin/installer/mcp.d.ts.map +1 -1
- package/dist/bin/installer/prompts.d.ts +17 -0
- package/dist/bin/installer/prompts.d.ts.map +1 -1
- package/dist/bin/installer/qdrant-dashboard.d.ts.map +1 -1
- package/dist/bin/installer/steering.d.ts +14 -2
- package/dist/bin/installer/steering.d.ts.map +1 -1
- package/dist/bin/installer/steering.js +81 -0
- package/dist/bin/installer/steering.js.map +2 -2
- package/dist/bin/installer/targets/aider.d.ts +6 -0
- package/dist/bin/installer/targets/aider.d.ts.map +1 -0
- package/dist/bin/installer/targets/aider.js +3 -3
- package/dist/bin/installer/targets/aider.js.map +2 -2
- package/dist/bin/installer/targets/amp.d.ts +6 -0
- package/dist/bin/installer/targets/amp.d.ts.map +1 -0
- package/dist/bin/installer/targets/amp.js +3 -3
- package/dist/bin/installer/targets/amp.js.map +2 -2
- package/dist/bin/installer/targets/antigravity.d.ts +13 -0
- package/dist/bin/installer/targets/antigravity.d.ts.map +1 -0
- package/dist/bin/installer/targets/antigravity.js +2 -2
- package/dist/bin/installer/targets/antigravity.js.map +2 -2
- package/dist/bin/installer/targets/augment.d.ts +6 -0
- package/dist/bin/installer/targets/augment.d.ts.map +1 -0
- package/dist/bin/installer/targets/augment.js +3 -3
- package/dist/bin/installer/targets/augment.js.map +2 -2
- package/dist/bin/installer/targets/claude.d.ts +6 -0
- package/dist/bin/installer/targets/claude.d.ts.map +1 -0
- package/dist/bin/installer/targets/claude.js +2 -2
- package/dist/bin/installer/targets/claude.js.map +2 -2
- package/dist/bin/installer/targets/cline.d.ts +13 -0
- package/dist/bin/installer/targets/cline.d.ts.map +1 -0
- package/dist/bin/installer/targets/cline.js +2 -2
- package/dist/bin/installer/targets/cline.js.map +2 -2
- package/dist/bin/installer/targets/codex.d.ts +6 -0
- package/dist/bin/installer/targets/codex.d.ts.map +1 -0
- package/dist/bin/installer/targets/codex.js +2 -2
- package/dist/bin/installer/targets/codex.js.map +2 -2
- package/dist/bin/installer/targets/continue.d.ts +12 -0
- package/dist/bin/installer/targets/continue.d.ts.map +1 -0
- package/dist/bin/installer/targets/continue.js +2 -2
- package/dist/bin/installer/targets/continue.js.map +2 -2
- package/dist/bin/installer/targets/copilot-cli.d.ts +12 -0
- package/dist/bin/installer/targets/copilot-cli.d.ts.map +1 -0
- package/dist/bin/installer/targets/copilot-cli.js +2 -2
- package/dist/bin/installer/targets/copilot-cli.js.map +2 -2
- package/dist/bin/installer/targets/copilot.d.ts +6 -0
- package/dist/bin/installer/targets/copilot.d.ts.map +1 -0
- package/dist/bin/installer/targets/copilot.js +2 -2
- package/dist/bin/installer/targets/copilot.js.map +2 -2
- package/dist/bin/installer/targets/cursor.d.ts +6 -0
- package/dist/bin/installer/targets/cursor.d.ts.map +1 -0
- package/dist/bin/installer/targets/cursor.js +2 -2
- package/dist/bin/installer/targets/cursor.js.map +2 -2
- package/dist/bin/installer/targets/devin.d.ts +13 -0
- package/dist/bin/installer/targets/devin.d.ts.map +1 -0
- package/dist/bin/installer/targets/devin.js +2 -2
- package/dist/bin/installer/targets/devin.js.map +2 -2
- package/dist/bin/installer/targets/gemini-cli.d.ts +16 -0
- package/dist/bin/installer/targets/gemini-cli.d.ts.map +1 -0
- package/dist/bin/installer/targets/gemini-cli.js +2 -2
- package/dist/bin/installer/targets/gemini-cli.js.map +2 -2
- package/dist/bin/installer/targets/generic.d.ts +59 -0
- package/dist/bin/installer/targets/generic.d.ts.map +1 -0
- package/dist/bin/installer/targets/generic.js +2 -2
- package/dist/bin/installer/targets/generic.js.map +2 -2
- package/dist/bin/installer/targets/goose.d.ts +6 -0
- package/dist/bin/installer/targets/goose.d.ts.map +1 -0
- package/dist/bin/installer/targets/goose.js +3 -3
- package/dist/bin/installer/targets/goose.js.map +2 -2
- package/dist/bin/installer/targets/index.d.ts +11 -0
- package/dist/bin/installer/targets/index.d.ts.map +1 -0
- package/dist/bin/installer/targets/index.js.map +1 -1
- package/dist/bin/installer/targets/junie.d.ts +13 -0
- package/dist/bin/installer/targets/junie.d.ts.map +1 -0
- package/dist/bin/installer/targets/junie.js +2 -2
- package/dist/bin/installer/targets/junie.js.map +2 -2
- package/dist/bin/installer/targets/kilo.d.ts +12 -0
- package/dist/bin/installer/targets/kilo.d.ts.map +1 -0
- package/dist/bin/installer/targets/kilo.js +2 -2
- package/dist/bin/installer/targets/kilo.js.map +2 -2
- package/dist/bin/installer/targets/kiro.d.ts +5 -0
- package/dist/bin/installer/targets/kiro.d.ts.map +1 -0
- package/dist/bin/installer/targets/kiro.js +4 -4
- package/dist/bin/installer/targets/kiro.js.map +2 -2
- package/dist/bin/installer/targets/opencode.d.ts +13 -0
- package/dist/bin/installer/targets/opencode.d.ts.map +1 -0
- package/dist/bin/installer/targets/opencode.js +2 -2
- package/dist/bin/installer/targets/opencode.js.map +2 -2
- package/dist/bin/installer/targets/openhands.d.ts +6 -0
- package/dist/bin/installer/targets/openhands.d.ts.map +1 -0
- package/dist/bin/installer/targets/openhands.js +3 -3
- package/dist/bin/installer/targets/openhands.js.map +2 -2
- package/dist/bin/installer/targets/qoder.d.ts +12 -0
- package/dist/bin/installer/targets/qoder.d.ts.map +1 -0
- package/dist/bin/installer/targets/qoder.js +2 -2
- package/dist/bin/installer/targets/qoder.js.map +2 -2
- package/dist/bin/installer/targets/qwen.d.ts +12 -0
- package/dist/bin/installer/targets/qwen.d.ts.map +1 -0
- package/dist/bin/installer/targets/qwen.js +2 -2
- package/dist/bin/installer/targets/qwen.js.map +2 -2
- package/dist/bin/installer/targets/replit.d.ts +6 -0
- package/dist/bin/installer/targets/replit.d.ts.map +1 -0
- package/dist/bin/installer/targets/replit.js +3 -3
- package/dist/bin/installer/targets/replit.js.map +2 -2
- package/dist/bin/installer/targets/roo.d.ts +13 -0
- package/dist/bin/installer/targets/roo.d.ts.map +1 -0
- package/dist/bin/installer/targets/roo.js +2 -2
- package/dist/bin/installer/targets/roo.js.map +2 -2
- package/dist/bin/installer/targets/tabnine.d.ts +6 -0
- package/dist/bin/installer/targets/tabnine.d.ts.map +1 -0
- package/dist/bin/installer/targets/tabnine.js +3 -3
- package/dist/bin/installer/targets/tabnine.js.map +2 -2
- package/dist/bin/installer/targets/trae.d.ts +6 -0
- package/dist/bin/installer/targets/trae.d.ts.map +1 -0
- package/dist/bin/installer/targets/trae.js +3 -3
- package/dist/bin/installer/targets/trae.js.map +2 -2
- package/dist/bin/installer/targets/warp.d.ts +12 -0
- package/dist/bin/installer/targets/warp.d.ts.map +1 -0
- package/dist/bin/installer/targets/warp.js +2 -2
- package/dist/bin/installer/targets/warp.js.map +2 -2
- package/dist/bin/installer/targets/windsurf.d.ts +13 -0
- package/dist/bin/installer/targets/windsurf.d.ts.map +1 -0
- package/dist/bin/installer/targets/windsurf.js +2 -2
- package/dist/bin/installer/targets/windsurf.js.map +2 -2
- package/dist/bin/kirograph.js +3 -1
- package/dist/bin/kirograph.js.map +3 -3
- package/dist/bin/progress.d.ts +16 -1
- package/dist/bin/progress.d.ts.map +1 -1
- package/dist/compression/filters/aws.d.ts +9 -0
- package/dist/compression/filters/aws.d.ts.map +1 -0
- package/dist/compression/filters/docker.d.ts +6 -0
- package/dist/compression/filters/docker.d.ts.map +1 -0
- package/dist/compression/filters/files.d.ts +6 -0
- package/dist/compression/filters/files.d.ts.map +1 -0
- package/dist/compression/filters/generic.d.ts +7 -0
- package/dist/compression/filters/generic.d.ts.map +1 -0
- package/dist/compression/filters/git.d.ts +6 -0
- package/dist/compression/filters/git.d.ts.map +1 -0
- package/dist/compression/filters/github.d.ts +6 -0
- package/dist/compression/filters/github.d.ts.map +1 -0
- package/dist/compression/filters/lint.d.ts +6 -0
- package/dist/compression/filters/lint.d.ts.map +1 -0
- package/dist/compression/filters/misc.d.ts +6 -0
- package/dist/compression/filters/misc.d.ts.map +1 -0
- package/dist/compression/filters/package.d.ts +6 -0
- package/dist/compression/filters/package.d.ts.map +1 -0
- package/dist/compression/filters/test.d.ts +6 -0
- package/dist/compression/filters/test.d.ts.map +1 -0
- package/dist/compression/index.d.ts +29 -0
- package/dist/compression/index.d.ts.map +1 -0
- package/dist/compression/naive-cost.d.ts +26 -0
- package/dist/compression/naive-cost.d.ts.map +1 -0
- package/dist/compression/tracker.d.ts +155 -0
- package/dist/compression/tracker.d.ts.map +1 -0
- package/dist/compression/types.d.ts +49 -0
- package/dist/compression/types.d.ts.map +1 -0
- package/dist/config.d.ts +90 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +55 -1
- package/dist/config.js.map +2 -2
- package/dist/core/lock-manager.d.ts +2 -0
- package/dist/core/lock-manager.d.ts.map +1 -1
- package/dist/core/pipeline.d.ts +4 -1
- package/dist/core/pipeline.d.ts.map +1 -1
- package/dist/core/pipeline.js +42 -0
- package/dist/core/pipeline.js.map +2 -2
- package/dist/core/snapshot.d.ts +58 -0
- package/dist/core/snapshot.d.ts.map +1 -0
- package/dist/data/filters.d.ts +23 -0
- package/dist/data/filters.d.ts.map +1 -0
- package/dist/data/indexer.d.ts +25 -0
- package/dist/data/indexer.d.ts.map +1 -0
- package/dist/data/linker.d.ts +37 -0
- package/dist/data/linker.d.ts.map +1 -0
- package/dist/data/lint.d.ts +27 -0
- package/dist/data/lint.d.ts.map +1 -0
- package/dist/data/parsers/csv.d.ts +11 -0
- package/dist/data/parsers/csv.d.ts.map +1 -0
- package/dist/data/parsers/excel.d.ts +10 -0
- package/dist/data/parsers/excel.d.ts.map +1 -0
- package/dist/data/parsers/index.d.ts +28 -0
- package/dist/data/parsers/index.d.ts.map +1 -0
- package/dist/data/parsers/json-array.d.ts +9 -0
- package/dist/data/parsers/json-array.d.ts.map +1 -0
- package/dist/data/parsers/jsonl.d.ts +9 -0
- package/dist/data/parsers/jsonl.d.ts.map +1 -0
- package/dist/data/parsers/parquet.d.ts +10 -0
- package/dist/data/parsers/parquet.d.ts.map +1 -0
- package/dist/data/profiler.d.ts +29 -0
- package/dist/data/profiler.d.ts.map +1 -0
- package/dist/data/queries.d.ts +95 -0
- package/dist/data/queries.d.ts.map +1 -0
- package/dist/data/types.d.ts +103 -0
- package/dist/data/types.d.ts.map +1 -0
- package/dist/db/database.d.ts +57 -0
- package/dist/db/database.d.ts.map +1 -1
- package/dist/db/database.js +19 -0
- package/dist/db/database.js.map +2 -2
- package/dist/db/patterns-schema.sql +23 -0
- package/dist/docs/formats/asciidoc.d.ts +9 -0
- package/dist/docs/formats/asciidoc.d.ts.map +1 -0
- package/dist/docs/formats/html.d.ts +10 -0
- package/dist/docs/formats/html.d.ts.map +1 -0
- package/dist/docs/formats/index.d.ts +31 -0
- package/dist/docs/formats/index.d.ts.map +1 -0
- package/dist/docs/formats/markdown.d.ts +11 -0
- package/dist/docs/formats/markdown.d.ts.map +1 -0
- package/dist/docs/formats/openapi.d.ts +17 -0
- package/dist/docs/formats/openapi.d.ts.map +1 -0
- package/dist/docs/formats/org.d.ts +9 -0
- package/dist/docs/formats/org.d.ts.map +1 -0
- package/dist/docs/formats/plaintext.d.ts +11 -0
- package/dist/docs/formats/plaintext.d.ts.map +1 -0
- package/dist/docs/formats/rdoc.d.ts +10 -0
- package/dist/docs/formats/rdoc.d.ts.map +1 -0
- package/dist/docs/formats/rst.d.ts +11 -0
- package/dist/docs/formats/rst.d.ts.map +1 -0
- package/dist/docs/indexer.d.ts +49 -0
- package/dist/docs/indexer.d.ts.map +1 -0
- package/dist/docs/linker.d.ts +30 -0
- package/dist/docs/linker.d.ts.map +1 -0
- package/dist/docs/lint.d.ts +27 -0
- package/dist/docs/lint.d.ts.map +1 -0
- package/dist/docs/queries.d.ts +78 -0
- package/dist/docs/queries.d.ts.map +1 -0
- package/dist/docs/section-id.d.ts +48 -0
- package/dist/docs/section-id.d.ts.map +1 -0
- package/dist/docs/summarizer.d.ts +13 -0
- package/dist/docs/summarizer.d.ts.map +1 -0
- package/dist/docs/types.d.ts +71 -0
- package/dist/docs/types.d.ts.map +1 -0
- package/dist/docs/vectors.d.ts +54 -0
- package/dist/docs/vectors.d.ts.map +1 -0
- package/dist/extraction/extractor.d.ts +1 -1
- package/dist/extraction/extractor.d.ts.map +1 -1
- package/dist/extraction/extractor.js +26 -3
- package/dist/extraction/extractor.js.map +2 -2
- package/dist/extraction/grammars.d.ts +6 -0
- package/dist/extraction/grammars.d.ts.map +1 -1
- package/dist/extraction/grammars.js +1 -0
- package/dist/extraction/grammars.js.map +2 -2
- package/dist/extraction/languages.d.ts.map +1 -1
- package/dist/extraction/languages.js +5 -1
- package/dist/extraction/languages.js.map +2 -2
- package/dist/extraction/notebook.d.ts +14 -0
- package/dist/extraction/notebook.d.ts.map +1 -0
- package/dist/frameworks/amplify.d.ts +9 -0
- package/dist/frameworks/amplify.d.ts.map +1 -0
- package/dist/frameworks/angular.d.ts +9 -0
- package/dist/frameworks/angular.d.ts.map +1 -0
- package/dist/frameworks/ansible.d.ts +8 -0
- package/dist/frameworks/ansible.d.ts.map +1 -0
- package/dist/frameworks/cloudformation.d.ts +9 -0
- package/dist/frameworks/cloudformation.d.ts.map +1 -0
- package/dist/frameworks/docker.d.ts +9 -0
- package/dist/frameworks/docker.d.ts.map +1 -0
- package/dist/frameworks/elixir.d.ts +6 -0
- package/dist/frameworks/elixir.d.ts.map +1 -0
- package/dist/frameworks/flutter.d.ts +12 -0
- package/dist/frameworks/flutter.d.ts.map +1 -0
- package/dist/frameworks/iac.d.ts +10 -0
- package/dist/frameworks/iac.d.ts.map +1 -0
- package/dist/frameworks/index.d.ts +14 -0
- package/dist/frameworks/index.d.ts.map +1 -1
- package/dist/frameworks/kubernetes.d.ts +9 -0
- package/dist/frameworks/kubernetes.d.ts.map +1 -0
- package/dist/frameworks/pulumi.d.ts +9 -0
- package/dist/frameworks/pulumi.d.ts.map +1 -0
- package/dist/frameworks/scala.d.ts +6 -0
- package/dist/frameworks/scala.d.ts.map +1 -0
- package/dist/frameworks/solidity.d.ts +6 -0
- package/dist/frameworks/solidity.d.ts.map +1 -0
- package/dist/frameworks/terraform.d.ts +14 -0
- package/dist/frameworks/terraform.d.ts.map +1 -0
- package/dist/frameworks/vue.d.ts +7 -0
- package/dist/frameworks/vue.d.ts.map +1 -0
- package/dist/graph/communities.d.ts +43 -0
- package/dist/graph/communities.d.ts.map +1 -0
- package/dist/graph/flows.d.ts +55 -0
- package/dist/graph/flows.d.ts.map +1 -0
- package/dist/graph/refactor.d.ts +43 -0
- package/dist/graph/refactor.d.ts.map +1 -0
- package/dist/index.d.ts +36 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/mcp/cache.d.ts +69 -0
- package/dist/mcp/cache.d.ts.map +1 -0
- package/dist/mcp/read-modes.d.ts +31 -0
- package/dist/mcp/read-modes.d.ts.map +1 -0
- package/dist/mcp/server.d.ts +1 -0
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +15 -2
- package/dist/mcp/server.js.map +2 -2
- package/dist/mcp/tool-names.d.ts +2 -0
- package/dist/mcp/tool-names.d.ts.map +1 -0
- package/dist/mcp/tool-names.js +4 -1
- package/dist/mcp/tool-names.js.map +2 -2
- package/dist/mcp/tools.d.ts +12 -0
- package/dist/mcp/tools.d.ts.map +1 -1
- package/dist/mcp/tools.js +397 -0
- package/dist/mcp/tools.js.map +2 -2
- package/dist/memory/compress.d.ts +19 -0
- package/dist/memory/compress.d.ts.map +1 -0
- package/dist/memory/database.d.ts +92 -0
- package/dist/memory/database.d.ts.map +1 -0
- package/dist/memory/database.js +38 -0
- package/dist/memory/database.js.map +2 -2
- package/dist/memory/index.d.ts +71 -0
- package/dist/memory/index.d.ts.map +1 -0
- package/dist/memory/index.js +12 -2
- package/dist/memory/index.js.map +2 -2
- package/dist/memory/symbols.d.ts +21 -0
- package/dist/memory/symbols.d.ts.map +1 -0
- package/dist/memory/types.d.ts +78 -0
- package/dist/memory/types.d.ts.map +1 -0
- package/dist/memory/types.js.map +1 -1
- package/dist/memory/vectors.d.ts +43 -0
- package/dist/memory/vectors.d.ts.map +1 -0
- package/dist/patterns/graph.d.ts +16 -0
- package/dist/patterns/graph.d.ts.map +1 -0
- package/dist/patterns/graph.js +45 -0
- package/dist/patterns/graph.js.map +7 -0
- package/dist/patterns/index.d.ts +4 -0
- package/dist/patterns/index.d.ts.map +1 -0
- package/dist/patterns/index.js +39 -0
- package/dist/patterns/index.js.map +7 -0
- package/dist/patterns/indexer.d.ts +15 -0
- package/dist/patterns/indexer.d.ts.map +1 -0
- package/dist/patterns/indexer.js +97 -0
- package/dist/patterns/indexer.js.map +7 -0
- package/dist/patterns/library/code-eval-elixir.yaml +11 -0
- package/dist/patterns/library/command-injection-c.yaml +11 -0
- package/dist/patterns/library/command-injection-go.yaml +29 -0
- package/dist/patterns/library/command-injection-kotlin.yaml +10 -0
- package/dist/patterns/library/command-injection-php.yaml +11 -0
- package/dist/patterns/library/command-injection-ruby.yaml +11 -0
- package/dist/patterns/library/command-injection-rust.yaml +11 -0
- package/dist/patterns/library/dangerous-eval-bash.yaml +11 -0
- package/dist/patterns/library/dangerous-eval-js.yaml +14 -0
- package/dist/patterns/library/dangerous-eval-php.yaml +11 -0
- package/dist/patterns/library/dangerous-eval-ruby.yaml +11 -0
- package/dist/patterns/library/dangerous-exec-py.yaml +13 -0
- package/dist/patterns/library/dangerous-reflection-java.yaml +8 -0
- package/dist/patterns/library/dynamic-load-lua.yaml +10 -0
- package/dist/patterns/library/os-cmd-elixir.yaml +16 -0
- package/dist/patterns/library/os-execute-lua.yaml +10 -0
- package/dist/patterns/library/path-traversal-go.yaml +11 -0
- package/dist/patterns/library/path-traversal-py.yaml +12 -0
- package/dist/patterns/library/path-traversal-readfile-js.yaml +14 -0
- package/dist/patterns/library/process-launch-swift.yaml +11 -0
- package/dist/patterns/library/process-run-dart.yaml +15 -0
- package/dist/patterns/library/prototype-pollution-js.yaml +12 -0
- package/dist/patterns/library/source-injection-bash.yaml +11 -0
- package/dist/patterns/library/sql-injection-concat-js.yaml +12 -0
- package/dist/patterns/library/sql-injection-dart.yaml +9 -0
- package/dist/patterns/library/sql-injection-java.yaml +13 -0
- package/dist/patterns/library/sql-injection-kotlin.yaml +11 -0
- package/dist/patterns/library/sql-injection-php.yaml +9 -0
- package/dist/patterns/library/sql-injection-py.yaml +12 -0
- package/dist/patterns/library/sql-injection-swift.yaml +11 -0
- package/dist/patterns/library/sql-injection-template-js.yaml +13 -0
- package/dist/patterns/library/subshell-injection-ruby.yaml +8 -0
- package/dist/patterns/library/unsafe-block-rust.yaml +8 -0
- package/dist/patterns/library/unsafe-string-c.yaml +11 -0
- package/dist/patterns/library/weak-crypto-md5-js.yaml +13 -0
- package/dist/patterns/library/weak-crypto-py.yaml +13 -0
- package/dist/patterns/loader.d.ts +18 -0
- package/dist/patterns/loader.d.ts.map +1 -0
- package/dist/patterns/loader.js +277 -0
- package/dist/patterns/loader.js.map +7 -0
- package/dist/patterns/runner.d.ts +42 -0
- package/dist/patterns/runner.d.ts.map +1 -0
- package/dist/patterns/runner.js +295 -0
- package/dist/patterns/runner.js.map +7 -0
- package/dist/patterns/types.d.ts +27 -0
- package/dist/patterns/types.d.ts.map +1 -0
- package/dist/patterns/types.js +34 -0
- package/dist/patterns/types.js.map +7 -0
- package/dist/resolution/bridges/android-rn.d.ts +13 -0
- package/dist/resolution/bridges/android-rn.d.ts.map +1 -0
- package/dist/resolution/bridges/expo-modules.d.ts +10 -0
- package/dist/resolution/bridges/expo-modules.d.ts.map +1 -0
- package/dist/resolution/bridges/flutter-channel.d.ts +14 -0
- package/dist/resolution/bridges/flutter-channel.d.ts.map +1 -0
- package/dist/resolution/bridges/index.d.ts +40 -0
- package/dist/resolution/bridges/index.d.ts.map +1 -0
- package/dist/resolution/bridges/native-events.d.ts +10 -0
- package/dist/resolution/bridges/native-events.d.ts.map +1 -0
- package/dist/resolution/bridges/native-views.d.ts +13 -0
- package/dist/resolution/bridges/native-views.d.ts.map +1 -0
- package/dist/resolution/bridges/react-native.d.ts +9 -0
- package/dist/resolution/bridges/react-native.d.ts.map +1 -0
- package/dist/resolution/bridges/swift-objc.d.ts +14 -0
- package/dist/resolution/bridges/swift-objc.d.ts.map +1 -0
- package/dist/resolution/bridges/turbomodules.d.ts +10 -0
- package/dist/resolution/bridges/turbomodules.d.ts.map +1 -0
- package/dist/resolution/index.d.ts +28 -3
- package/dist/resolution/index.d.ts.map +1 -1
- package/dist/security/attack-surface.d.ts +46 -0
- package/dist/security/attack-surface.d.ts.map +1 -0
- package/dist/security/attack-surface.js +43 -1
- package/dist/security/attack-surface.js.map +2 -2
- package/dist/security/context-warnings.d.ts +40 -0
- package/dist/security/context-warnings.d.ts.map +1 -0
- package/dist/security/data-flows.d.ts +33 -0
- package/dist/security/data-flows.d.ts.map +1 -0
- package/dist/security/data-flows.js +65 -7
- package/dist/security/data-flows.js.map +2 -2
- package/dist/security/dep-confusion.d.ts +23 -0
- package/dist/security/dep-confusion.d.ts.map +1 -0
- package/dist/security/errors.d.ts +16 -0
- package/dist/security/errors.d.ts.map +1 -0
- package/dist/security/export/fix-suggestions.d.ts +21 -0
- package/dist/security/export/fix-suggestions.d.ts.map +1 -0
- package/dist/security/export/sbom.d.ts +33 -0
- package/dist/security/export/sbom.d.ts.map +1 -0
- package/dist/security/export/serialization.d.ts +62 -0
- package/dist/security/export/serialization.d.ts.map +1 -0
- package/dist/security/export/vex.d.ts +58 -0
- package/dist/security/export/vex.d.ts.map +1 -0
- package/dist/security/index.d.ts +21 -0
- package/dist/security/index.d.ts.map +1 -0
- package/dist/security/integrator.d.ts +63 -0
- package/dist/security/integrator.d.ts.map +1 -0
- package/dist/security/integrator.js +8 -8
- package/dist/security/integrator.js.map +2 -2
- package/dist/security/license.d.ts +33 -0
- package/dist/security/license.d.ts.map +1 -0
- package/dist/security/manifest/adapter.d.ts +92 -0
- package/dist/security/manifest/adapter.d.ts.map +1 -0
- package/dist/security/manifest/parser.d.ts +73 -0
- package/dist/security/manifest/parser.d.ts.map +1 -0
- package/dist/security/manifest/plugins/cargo.d.ts +11 -0
- package/dist/security/manifest/plugins/cargo.d.ts.map +1 -0
- package/dist/security/manifest/plugins/composer.d.ts +11 -0
- package/dist/security/manifest/plugins/composer.d.ts.map +1 -0
- package/dist/security/manifest/plugins/go.d.ts +12 -0
- package/dist/security/manifest/plugins/go.d.ts.map +1 -0
- package/dist/security/manifest/plugins/gradle.d.ts +12 -0
- package/dist/security/manifest/plugins/gradle.d.ts.map +1 -0
- package/dist/security/manifest/plugins/hex.d.ts +11 -0
- package/dist/security/manifest/plugins/hex.d.ts.map +1 -0
- package/dist/security/manifest/plugins/maven.d.ts +11 -0
- package/dist/security/manifest/plugins/maven.d.ts.map +1 -0
- package/dist/security/manifest/plugins/npm.d.ts +11 -0
- package/dist/security/manifest/plugins/npm.d.ts.map +1 -0
- package/dist/security/manifest/plugins/nuget.d.ts +12 -0
- package/dist/security/manifest/plugins/nuget.d.ts.map +1 -0
- package/dist/security/manifest/plugins/pip.d.ts +11 -0
- package/dist/security/manifest/plugins/pip.d.ts.map +1 -0
- package/dist/security/manifest/plugins/pubspec.d.ts +11 -0
- package/dist/security/manifest/plugins/pubspec.d.ts.map +1 -0
- package/dist/security/manifest/plugins/pyproject.d.ts +3 -0
- package/dist/security/manifest/plugins/pyproject.d.ts.map +1 -0
- package/dist/security/manifest/plugins/rubygems.d.ts +11 -0
- package/dist/security/manifest/plugins/rubygems.d.ts.map +1 -0
- package/dist/security/manifest/plugins/swift.d.ts +11 -0
- package/dist/security/manifest/plugins/swift.d.ts.map +1 -0
- package/dist/security/owasp.d.ts +16 -0
- package/dist/security/owasp.d.ts.map +1 -0
- package/dist/security/pipeline.d.ts +37 -0
- package/dist/security/pipeline.d.ts.map +1 -0
- package/dist/security/reachability.d.ts +67 -0
- package/dist/security/reachability.d.ts.map +1 -0
- package/dist/security/remediation.d.ts +51 -0
- package/dist/security/remediation.d.ts.map +1 -0
- package/dist/security/secrets.d.ts +38 -0
- package/dist/security/secrets.d.ts.map +1 -0
- package/dist/security/staleness.d.ts +43 -0
- package/dist/security/staleness.d.ts.map +1 -0
- package/dist/security/supply-chain.d.ts +34 -0
- package/dist/security/supply-chain.d.ts.map +1 -0
- package/dist/security/suppressions.d.ts +18 -0
- package/dist/security/suppressions.d.ts.map +1 -0
- package/dist/security/types.d.ts +144 -0
- package/dist/security/types.d.ts.map +1 -0
- package/dist/security/vuln/client.d.ts +90 -0
- package/dist/security/vuln/client.d.ts.map +1 -0
- package/dist/security/vuln/client.js.map +2 -2
- package/dist/security/vuln/epss-client.d.ts +26 -0
- package/dist/security/vuln/epss-client.d.ts.map +1 -0
- package/dist/security/vuln/index.d.ts +6 -0
- package/dist/security/vuln/index.d.ts.map +1 -0
- package/dist/security/vuln/osv-adapter.d.ts +58 -0
- package/dist/security/vuln/osv-adapter.d.ts.map +1 -0
- package/dist/security/vuln/types.d.ts +29 -0
- package/dist/security/vuln/types.d.ts.map +1 -0
- package/dist/sync/index.d.ts +4 -2
- package/dist/sync/index.d.ts.map +1 -1
- package/dist/types.d.ts +10 -4
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +2 -2
- package/dist/vectors/index.d.ts +11 -3
- package/dist/vectors/index.d.ts.map +1 -1
- package/dist/vectors/qdrant-index.d.ts +10 -3
- package/dist/vectors/qdrant-index.d.ts.map +1 -1
- package/dist/vectors/turboquant-index.js +261 -0
- package/dist/vectors/turboquant-index.js.map +7 -0
- package/dist/vectors/typesense-index.d.ts.map +1 -1
- package/dist/watchmen/index.js +83 -0
- package/dist/watchmen/index.js.map +7 -0
- package/dist/watchmen/synthesize.js +475 -0
- package/dist/watchmen/synthesize.js.map +7 -0
- package/package.json +24 -2
- package/dist/security/context-warnings.test.js +0 -300
- package/dist/security/context-warnings.test.js.map +0 -7
- package/dist/security/export/fix-suggestions.test.js +0 -74
- package/dist/security/export/fix-suggestions.test.js.map +0 -7
- package/dist/security/export/sbom.test.js +0 -288
- package/dist/security/export/sbom.test.js.map +0 -7
- package/dist/security/export/serialization.test.js +0 -310
- package/dist/security/export/serialization.test.js.map +0 -7
- package/dist/security/export/vex.test.js +0 -278
- package/dist/security/export/vex.test.js.map +0 -7
- package/dist/security/integrator-transitives.test.js +0 -359
- package/dist/security/integrator-transitives.test.js.map +0 -7
- package/dist/security/integrator.test.js +0 -237
- package/dist/security/integrator.test.js.map +0 -7
- package/dist/security/manifest/adapter.test.js +0 -272
- package/dist/security/manifest/adapter.test.js.map +0 -7
- package/dist/security/manifest/parser.test.js +0 -110
- package/dist/security/manifest/parser.test.js.map +0 -7
- package/dist/security/manifest/plugins/cargo.test.js +0 -304
- package/dist/security/manifest/plugins/cargo.test.js.map +0 -7
- package/dist/security/manifest/plugins/go.test.js +0 -341
- package/dist/security/manifest/plugins/go.test.js.map +0 -7
- package/dist/security/manifest/plugins/maven.test.js +0 -389
- package/dist/security/manifest/plugins/maven.test.js.map +0 -7
- package/dist/security/manifest/plugins/npm.test.js +0 -298
- package/dist/security/manifest/plugins/npm.test.js.map +0 -7
- package/dist/security/manifest/plugins/pip.test.js +0 -208
- package/dist/security/manifest/plugins/pip.test.js.map +0 -7
- package/dist/security/reachability.test.js +0 -394
- package/dist/security/reachability.test.js.map +0 -7
- package/dist/security/vuln/client.test.js +0 -288
- package/dist/security/vuln/client.test.js.map +0 -7
- package/dist/security/vuln/osv-adapter.test.js +0 -391
- package/dist/security/vuln/osv-adapter.test.js.map +0 -7
|
@@ -6,22 +6,26 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import type { GraphDatabase } from '../db/database';
|
|
8
8
|
import type { KiroGraphConfig } from '../config';
|
|
9
|
+
import { type BridgeResolutionResult } from './bridges';
|
|
9
10
|
export interface ResolutionResult {
|
|
10
11
|
resolved: number;
|
|
11
12
|
unresolved: number;
|
|
12
13
|
total: number;
|
|
13
14
|
durationMs: number;
|
|
15
|
+
bridgeResult?: BridgeResolutionResult;
|
|
14
16
|
}
|
|
15
17
|
export declare class ReferenceResolver {
|
|
16
18
|
private db;
|
|
17
19
|
private config;
|
|
20
|
+
private projectRoot;
|
|
18
21
|
private nameCache;
|
|
19
22
|
private qualifiedNameCache;
|
|
20
23
|
private kindCache;
|
|
21
24
|
private lowerNameCache;
|
|
22
25
|
private nodeByIdCache;
|
|
26
|
+
private namespacePrefixCache;
|
|
23
27
|
private cacheWarmed;
|
|
24
|
-
constructor(db: GraphDatabase, config: KiroGraphConfig);
|
|
28
|
+
constructor(db: GraphDatabase, config: KiroGraphConfig, projectRoot?: string);
|
|
25
29
|
/**
|
|
26
30
|
* Pre-load all nodes into Maps for O(1) lookup.
|
|
27
31
|
* Must be called before resolveUnresolvedRefs() for best performance.
|
|
@@ -44,13 +48,34 @@ export declare class ReferenceResolver {
|
|
|
44
48
|
*/
|
|
45
49
|
invalidateFile(filePath: string): void;
|
|
46
50
|
/**
|
|
47
|
-
* Resolve
|
|
48
|
-
*
|
|
51
|
+
* Resolve an import path to a node ID.
|
|
52
|
+
*
|
|
53
|
+
* Handles three cases:
|
|
54
|
+
* 1. Relative paths (JS/TS/Go/…) — resolved via the file tree.
|
|
55
|
+
* 2. Fully-qualified type imports (Java `import com.example.Foo`) — exact qualifiedName lookup,
|
|
56
|
+
* then name+namespace-prefix match.
|
|
57
|
+
* 3. Namespace-level imports (C# `using MyApp.Services`) — namespace node lookup, then
|
|
58
|
+
* namespace prefix cache (O(1)) to find any class in that namespace.
|
|
49
59
|
*/
|
|
50
60
|
private _resolveImportPath;
|
|
61
|
+
/**
|
|
62
|
+
* Resolve a bare type name to a node ID.
|
|
63
|
+
* Used for extends/implements refs where we have only the unqualified type name.
|
|
64
|
+
* Prefers class/interface/trait/protocol nodes over other kinds.
|
|
65
|
+
*/
|
|
66
|
+
private _resolveTypeName;
|
|
51
67
|
/**
|
|
52
68
|
* Convert a raw DB row to a Node object.
|
|
53
69
|
*/
|
|
54
70
|
private _rowToNode;
|
|
71
|
+
/**
|
|
72
|
+
* Run cross-language bridge resolvers to synthesize edges between
|
|
73
|
+
* symbols in different languages (Swift ↔ ObjC, JS ↔ Native, etc.).
|
|
74
|
+
*/
|
|
75
|
+
private _runBridgeResolvers;
|
|
76
|
+
/**
|
|
77
|
+
* Build a ResolutionContext for bridge resolvers using the warm caches.
|
|
78
|
+
*/
|
|
79
|
+
private _buildBridgeContext;
|
|
55
80
|
}
|
|
56
81
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/resolution/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AACpD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/resolution/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AACpD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAGjD,OAAO,EAAsB,KAAK,sBAAsB,EAAE,MAAM,WAAW,CAAC;AAI5E,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,sBAAsB,CAAC;CACvC;AAID,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,EAAE,CAAgB;IAC1B,OAAO,CAAC,MAAM,CAAkB;IAChC,OAAO,CAAC,WAAW,CAAS;IAG5B,OAAO,CAAC,SAAS,CAAkC;IACnD,OAAO,CAAC,kBAAkB,CAAgC;IAC1D,OAAO,CAAC,SAAS,CAAoC;IACrD,OAAO,CAAC,cAAc,CAAkC;IACxD,OAAO,CAAC,aAAa,CAAgC;IAErD,OAAO,CAAC,oBAAoB,CAAkC;IAE9D,OAAO,CAAC,WAAW,CAAS;gBAEhB,EAAE,EAAE,aAAa,EAAE,MAAM,EAAE,eAAe,EAAE,WAAW,CAAC,EAAE,MAAM;IAM5E;;;OAGG;IACH,UAAU,IAAI,IAAI;IA2DlB;;;;OAIG;IACG,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,gBAAgB,CAAC;IA6BlG;;;OAGG;IACG,qBAAqB,CAAC,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC;IA+InG;;;OAGG;IACH,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IA6DtC;;;;;;;;;OASG;IACH,OAAO,CAAC,kBAAkB;IA0D1B;;;;OAIG;IACH,OAAO,CAAC,gBAAgB;IAcxB;;OAEG;IACH,OAAO,CAAC,UAAU;IA2BlB;;;OAGG;IACH,OAAO,CAAC,mBAAmB;IAK3B;;OAEG;IACH,OAAO,CAAC,mBAAmB;CAyC5B"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* KiroGraph-Sec Attack Surface Analyzer
|
|
3
|
+
*
|
|
4
|
+
* Maps all route nodes in the knowledge graph to their reachable vulnerable
|
|
5
|
+
* dependencies, computing exposure levels and risk scores per route.
|
|
6
|
+
*/
|
|
7
|
+
import type { GraphDatabase } from '../db/database';
|
|
8
|
+
export interface AttackSurfaceEntry {
|
|
9
|
+
route: string;
|
|
10
|
+
nodeId: string;
|
|
11
|
+
filePath: string;
|
|
12
|
+
isAuthenticated: boolean;
|
|
13
|
+
exposureLevel: 'public' | 'authenticated' | 'internal' | 'unknown';
|
|
14
|
+
vulnerableDeps: Array<{
|
|
15
|
+
cveId: string;
|
|
16
|
+
packageName: string;
|
|
17
|
+
severity: number | null;
|
|
18
|
+
epssScore: number | null;
|
|
19
|
+
riskScore: number | null;
|
|
20
|
+
verdict: string | null;
|
|
21
|
+
hopCount: number;
|
|
22
|
+
}>;
|
|
23
|
+
patternMatches: Array<{
|
|
24
|
+
patternId: string;
|
|
25
|
+
severity: string;
|
|
26
|
+
line: number;
|
|
27
|
+
symbolNodeId: string;
|
|
28
|
+
symbolName: string;
|
|
29
|
+
}>;
|
|
30
|
+
patternRiskLevel: 'none' | 'low' | 'medium' | 'high' | 'critical';
|
|
31
|
+
riskScore: number;
|
|
32
|
+
}
|
|
33
|
+
export interface AttackSurfaceResult {
|
|
34
|
+
totalRoutes: number;
|
|
35
|
+
publicRoutes: number;
|
|
36
|
+
authenticatedRoutes: number;
|
|
37
|
+
routesWithVulns: number;
|
|
38
|
+
criticalPaths: AttackSurfaceEntry[];
|
|
39
|
+
allRoutes: AttackSurfaceEntry[];
|
|
40
|
+
}
|
|
41
|
+
export declare class AttackSurfaceAnalyzer {
|
|
42
|
+
private readonly db;
|
|
43
|
+
constructor(db: GraphDatabase);
|
|
44
|
+
analyze(): Promise<AttackSurfaceResult>;
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=attack-surface.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"attack-surface.d.ts","sourceRoot":"","sources":["../../src/security/attack-surface.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAsBpD,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,OAAO,CAAC;IACzB,aAAa,EAAE,QAAQ,GAAG,eAAe,GAAG,UAAU,GAAG,SAAS,CAAC;IACnE,cAAc,EAAE,KAAK,CAAC;QACpB,KAAK,EAAE,MAAM,CAAC;QACd,WAAW,EAAE,MAAM,CAAC;QACpB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;QACxB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;QACzB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;QACzB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;QACvB,QAAQ,EAAE,MAAM,CAAC;KAClB,CAAC,CAAC;IACH,cAAc,EAAE,KAAK,CAAC;QACpB,SAAS,EAAE,MAAM,CAAC;QAClB,QAAQ,EAAE,MAAM,CAAC;QACjB,IAAI,EAAE,MAAM,CAAC;QACb,YAAY,EAAE,MAAM,CAAC;QACrB,UAAU,EAAE,MAAM,CAAC;KACpB,CAAC,CAAC;IACH,gBAAgB,EAAE,MAAM,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,UAAU,CAAC;IAClE,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,mBAAmB;IAClC,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,eAAe,EAAE,MAAM,CAAC;IACxB,aAAa,EAAE,kBAAkB,EAAE,CAAC;IACpC,SAAS,EAAE,kBAAkB,EAAE,CAAC;CACjC;AAED,qBAAa,qBAAqB;IACpB,OAAO,CAAC,QAAQ,CAAC,EAAE;gBAAF,EAAE,EAAE,aAAa;IAExC,OAAO,IAAI,OAAO,CAAC,mBAAmB,CAAC;CAgN9C"}
|
|
@@ -95,6 +95,38 @@ class AttackSurfaceAnalyzer {
|
|
|
95
95
|
});
|
|
96
96
|
}
|
|
97
97
|
}
|
|
98
|
+
const routeNodeId = route.id;
|
|
99
|
+
let patternRows = [];
|
|
100
|
+
try {
|
|
101
|
+
patternRows = rawDb.all(
|
|
102
|
+
`WITH RECURSIVE reachable(node_id, depth) AS (
|
|
103
|
+
SELECT target, 1 FROM edges WHERE source = ? AND kind IN ('calls', 'imports', 'references')
|
|
104
|
+
UNION
|
|
105
|
+
SELECT e.target, r.depth + 1
|
|
106
|
+
FROM edges e
|
|
107
|
+
JOIN reachable r ON e.source = r.node_id
|
|
108
|
+
WHERE r.depth < 5 AND e.kind IN ('calls', 'imports', 'references')
|
|
109
|
+
)
|
|
110
|
+
SELECT DISTINCT pm.symbol_node_id, n.name as symbol_name, pm.pattern_id, pm.severity, pm.line
|
|
111
|
+
FROM reachable r
|
|
112
|
+
JOIN pattern_matches pm ON pm.symbol_node_id = r.node_id
|
|
113
|
+
JOIN nodes n ON n.id = pm.symbol_node_id
|
|
114
|
+
WHERE pm.symbol_node_id IS NOT NULL
|
|
115
|
+
ORDER BY CASE pm.severity WHEN 'critical' THEN 4 WHEN 'high' THEN 3 WHEN 'medium' THEN 2 ELSE 1 END DESC
|
|
116
|
+
LIMIT 10`,
|
|
117
|
+
[routeNodeId]
|
|
118
|
+
);
|
|
119
|
+
} catch {
|
|
120
|
+
patternRows = [];
|
|
121
|
+
}
|
|
122
|
+
const patternMatches = patternRows.map((r) => ({
|
|
123
|
+
patternId: r.pattern_id,
|
|
124
|
+
severity: r.severity,
|
|
125
|
+
line: r.line,
|
|
126
|
+
symbolNodeId: r.symbol_node_id,
|
|
127
|
+
symbolName: r.symbol_name
|
|
128
|
+
}));
|
|
129
|
+
const patternRiskLevel = patternMatches.length === 0 ? "none" : patternMatches[0].severity;
|
|
98
130
|
const pathNodeNames = rawDb.all(
|
|
99
131
|
`WITH RECURSIVE reachable(node_id, depth) AS (
|
|
100
132
|
SELECT target, 1 FROM edges WHERE source = ? AND kind IN ('calls', 'imports', 'references')
|
|
@@ -126,10 +158,18 @@ class AttackSurfaceAnalyzer {
|
|
|
126
158
|
exposureLevel = "unknown";
|
|
127
159
|
}
|
|
128
160
|
const affectedVulns = vulnerableDeps.filter((v) => v.verdict === "affected" || v.verdict === "under_investigation");
|
|
129
|
-
const
|
|
161
|
+
const baseRiskScore = affectedVulns.reduce((max, v) => {
|
|
130
162
|
if (v.riskScore != null && v.riskScore > max) return v.riskScore;
|
|
131
163
|
return max;
|
|
132
164
|
}, 0);
|
|
165
|
+
const patternBonus = {
|
|
166
|
+
none: 0,
|
|
167
|
+
low: 0.3,
|
|
168
|
+
medium: 0.6,
|
|
169
|
+
high: 0.8,
|
|
170
|
+
critical: 1
|
|
171
|
+
};
|
|
172
|
+
const riskScore = Math.min(10, baseRiskScore + (patternBonus[patternRiskLevel] ?? 0));
|
|
133
173
|
entries.push({
|
|
134
174
|
route: route.name ?? route.id,
|
|
135
175
|
nodeId: route.id,
|
|
@@ -137,6 +177,8 @@ class AttackSurfaceAnalyzer {
|
|
|
137
177
|
isAuthenticated,
|
|
138
178
|
exposureLevel,
|
|
139
179
|
vulnerableDeps,
|
|
180
|
+
patternMatches,
|
|
181
|
+
patternRiskLevel,
|
|
140
182
|
riskScore
|
|
141
183
|
});
|
|
142
184
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/security/attack-surface.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * KiroGraph-Sec Attack Surface Analyzer\n *\n * Maps all route nodes in the knowledge graph to their reachable vulnerable\n * dependencies, computing exposure levels and risk scores per route.\n */\n\nimport type { GraphDatabase } from '../db/database';\n\n/** Auth-related name patterns for heuristic isAuthenticated detection. */\nconst AUTH_PATTERNS = [\n 'auth',\n 'authenticate',\n 'middleware',\n 'guard',\n 'protect',\n 'requirelogin',\n 'isloggedin',\n 'verifytoken',\n 'checkauth',\n 'ensureauth',\n] as const;\n\n/** Route path patterns that indicate a public-facing API. */\nconst PUBLIC_ROUTE_PATTERNS = ['/api/', '/v1/', '/v2/', '/v3/', '/graphql', '/rest/'];\n\n/** Route path patterns that indicate an internal/admin route. */\nconst INTERNAL_ROUTE_PATTERNS = ['/internal/', '/admin/'];\n\nexport interface AttackSurfaceEntry {\n route: string;\n nodeId: string;\n filePath: string;\n isAuthenticated: boolean;\n exposureLevel: 'public' | 'authenticated' | 'internal' | 'unknown';\n vulnerableDeps: Array<{\n cveId: string;\n packageName: string;\n severity: number | null;\n epssScore: number | null;\n riskScore: number | null;\n verdict: string | null;\n hopCount: number;\n }>;\n riskScore: number;\n}\n\nexport interface AttackSurfaceResult {\n totalRoutes: number;\n publicRoutes: number;\n authenticatedRoutes: number;\n routesWithVulns: number;\n criticalPaths: AttackSurfaceEntry[];\n allRoutes: AttackSurfaceEntry[];\n}\n\nexport class AttackSurfaceAnalyzer {\n constructor(private readonly db: GraphDatabase) {}\n\n async analyze(): Promise<AttackSurfaceResult> {\n const rawDb = this.db.getRawDb();\n\n // Step 1: Query all route nodes\n const routeRows: Array<{ id: string; name: string; file_path: string }> = rawDb.all(\n `SELECT id, name, file_path FROM nodes WHERE kind = 'route'`,\n );\n\n if (routeRows.length === 0) {\n return {\n totalRoutes: 0,\n publicRoutes: 0,\n authenticatedRoutes: 0,\n routesWithVulns: 0,\n criticalPaths: [],\n allRoutes: [],\n };\n }\n\n const entries: AttackSurfaceEntry[] = [];\n\n for (const route of routeRows) {\n // Step 2: BFS via SQL to find reachable dependency nodes (max 5 hops)\n const reachableDeps: Array<{\n node_id: string;\n package_name: string;\n hop_count: number;\n }> = rawDb.all(\n `WITH RECURSIVE reachable(node_id, depth) AS (\n SELECT target, 1 FROM edges WHERE source = ? AND kind IN ('calls', 'imports', 'references')\n UNION\n SELECT e.target, r.depth + 1\n FROM edges e\n JOIN reachable r ON e.source = r.node_id\n WHERE r.depth < 5 AND e.kind IN ('calls', 'imports', 'references')\n )\n SELECT d.node_id, d.package_name, MIN(r.depth) as hop_count\n FROM reachable r\n JOIN sec_dependencies d ON d.node_id = r.node_id\n GROUP BY d.node_id, d.package_name`,\n [route.id],\n );\n\n // Step 3: For each reachable dep, find affected/under_investigation vulns\n const vulnerableDeps: AttackSurfaceEntry['vulnerableDeps'] = [];\n\n for (const dep of reachableDeps) {\n const vulnRows: Array<{\n cve_id: string;\n package_name: string;\n severity_score: number | null;\n epss_score: number | null;\n risk_score: number | null;\n verdict: string | null;\n }> = rawDb.all(\n `SELECT v.cve_id, d.package_name, v.severity_score, v.epss_score, v.risk_score, r.verdict\n FROM sec_vulnerabilities v\n JOIN edges e ON e.target = v.node_id AND e.kind = 'has_vulnerability'\n JOIN sec_dependencies d ON d.node_id = e.source\n LEFT JOIN sec_reachability r ON r.vulnerability_node_id = v.node_id\n WHERE d.node_id = ?\n AND (r.verdict IN ('affected', 'under_investigation') OR r.verdict IS NULL)`,\n [dep.node_id],\n );\n\n for (const vuln of vulnRows) {\n vulnerableDeps.push({\n cveId: vuln.cve_id,\n packageName: vuln.package_name ?? dep.package_name,\n severity: vuln.severity_score,\n epssScore: vuln.epss_score,\n riskScore: vuln.risk_score,\n verdict: vuln.verdict,\n hopCount: dep.hop_count,\n });\n }\n }\n\n // Step 4: Heuristic \u2014 isAuthenticated via path node names\n const pathNodeNames: Array<{ name: string }> = rawDb.all(\n `WITH RECURSIVE reachable(node_id, depth) AS (\n SELECT target, 1 FROM edges WHERE source = ? AND kind IN ('calls', 'imports', 'references')\n UNION\n SELECT e.target, r.depth + 1\n FROM edges e\n JOIN reachable r ON e.source = r.node_id\n WHERE r.depth < 5 AND e.kind IN ('calls', 'imports', 'references')\n )\n SELECT DISTINCT n.name\n FROM reachable r\n JOIN nodes n ON n.id = r.node_id\n WHERE n.name IS NOT NULL`,\n [route.id],\n );\n\n const isAuthenticated = pathNodeNames.some(row => {\n const lowerName = (row.name ?? '').toLowerCase();\n return AUTH_PATTERNS.some(pattern => lowerName.includes(pattern));\n });\n\n // Step 5: Determine exposure level\n const routeName = (route.name ?? '').toLowerCase();\n let exposureLevel: AttackSurfaceEntry['exposureLevel'];\n\n if (INTERNAL_ROUTE_PATTERNS.some(p => routeName.includes(p))) {\n exposureLevel = 'internal';\n } else if (isAuthenticated) {\n exposureLevel = 'authenticated';\n } else if (PUBLIC_ROUTE_PATTERNS.some(p => routeName.includes(p))) {\n exposureLevel = 'public';\n } else {\n exposureLevel = 'unknown';\n }\n\n // Step 6: riskScore = max risk_score of reachable affected vulns\n const affectedVulns = vulnerableDeps.filter(v => v.verdict === 'affected' || v.verdict === 'under_investigation');\n const
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAUA,MAAM,gBAAgB;AAAA,EACpB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAGA,MAAM,wBAAwB,CAAC,SAAS,QAAQ,QAAQ,QAAQ,YAAY,QAAQ;AAGpF,MAAM,0BAA0B,CAAC,cAAc,SAAS;
|
|
4
|
+
"sourcesContent": ["/**\n * KiroGraph-Sec Attack Surface Analyzer\n *\n * Maps all route nodes in the knowledge graph to their reachable vulnerable\n * dependencies, computing exposure levels and risk scores per route.\n */\n\nimport type { GraphDatabase } from '../db/database';\n\n/** Auth-related name patterns for heuristic isAuthenticated detection. */\nconst AUTH_PATTERNS = [\n 'auth',\n 'authenticate',\n 'middleware',\n 'guard',\n 'protect',\n 'requirelogin',\n 'isloggedin',\n 'verifytoken',\n 'checkauth',\n 'ensureauth',\n] as const;\n\n/** Route path patterns that indicate a public-facing API. */\nconst PUBLIC_ROUTE_PATTERNS = ['/api/', '/v1/', '/v2/', '/v3/', '/graphql', '/rest/'];\n\n/** Route path patterns that indicate an internal/admin route. */\nconst INTERNAL_ROUTE_PATTERNS = ['/internal/', '/admin/'];\n\nexport interface AttackSurfaceEntry {\n route: string;\n nodeId: string;\n filePath: string;\n isAuthenticated: boolean;\n exposureLevel: 'public' | 'authenticated' | 'internal' | 'unknown';\n vulnerableDeps: Array<{\n cveId: string;\n packageName: string;\n severity: number | null;\n epssScore: number | null;\n riskScore: number | null;\n verdict: string | null;\n hopCount: number;\n }>;\n patternMatches: Array<{\n patternId: string;\n severity: string;\n line: number;\n symbolNodeId: string;\n symbolName: string;\n }>;\n patternRiskLevel: 'none' | 'low' | 'medium' | 'high' | 'critical';\n riskScore: number;\n}\n\nexport interface AttackSurfaceResult {\n totalRoutes: number;\n publicRoutes: number;\n authenticatedRoutes: number;\n routesWithVulns: number;\n criticalPaths: AttackSurfaceEntry[];\n allRoutes: AttackSurfaceEntry[];\n}\n\nexport class AttackSurfaceAnalyzer {\n constructor(private readonly db: GraphDatabase) {}\n\n async analyze(): Promise<AttackSurfaceResult> {\n const rawDb = this.db.getRawDb();\n\n // Step 1: Query all route nodes\n const routeRows: Array<{ id: string; name: string; file_path: string }> = rawDb.all(\n `SELECT id, name, file_path FROM nodes WHERE kind = 'route'`,\n );\n\n if (routeRows.length === 0) {\n return {\n totalRoutes: 0,\n publicRoutes: 0,\n authenticatedRoutes: 0,\n routesWithVulns: 0,\n criticalPaths: [],\n allRoutes: [],\n };\n }\n\n const entries: AttackSurfaceEntry[] = [];\n\n for (const route of routeRows) {\n // Step 2: BFS via SQL to find reachable dependency nodes (max 5 hops)\n const reachableDeps: Array<{\n node_id: string;\n package_name: string;\n hop_count: number;\n }> = rawDb.all(\n `WITH RECURSIVE reachable(node_id, depth) AS (\n SELECT target, 1 FROM edges WHERE source = ? AND kind IN ('calls', 'imports', 'references')\n UNION\n SELECT e.target, r.depth + 1\n FROM edges e\n JOIN reachable r ON e.source = r.node_id\n WHERE r.depth < 5 AND e.kind IN ('calls', 'imports', 'references')\n )\n SELECT d.node_id, d.package_name, MIN(r.depth) as hop_count\n FROM reachable r\n JOIN sec_dependencies d ON d.node_id = r.node_id\n GROUP BY d.node_id, d.package_name`,\n [route.id],\n );\n\n // Step 3: For each reachable dep, find affected/under_investigation vulns\n const vulnerableDeps: AttackSurfaceEntry['vulnerableDeps'] = [];\n\n for (const dep of reachableDeps) {\n const vulnRows: Array<{\n cve_id: string;\n package_name: string;\n severity_score: number | null;\n epss_score: number | null;\n risk_score: number | null;\n verdict: string | null;\n }> = rawDb.all(\n `SELECT v.cve_id, d.package_name, v.severity_score, v.epss_score, v.risk_score, r.verdict\n FROM sec_vulnerabilities v\n JOIN edges e ON e.target = v.node_id AND e.kind = 'has_vulnerability'\n JOIN sec_dependencies d ON d.node_id = e.source\n LEFT JOIN sec_reachability r ON r.vulnerability_node_id = v.node_id\n WHERE d.node_id = ?\n AND (r.verdict IN ('affected', 'under_investigation') OR r.verdict IS NULL)`,\n [dep.node_id],\n );\n\n for (const vuln of vulnRows) {\n vulnerableDeps.push({\n cveId: vuln.cve_id,\n packageName: vuln.package_name ?? dep.package_name,\n severity: vuln.severity_score,\n epssScore: vuln.epss_score,\n riskScore: vuln.risk_score,\n verdict: vuln.verdict,\n hopCount: dep.hop_count,\n });\n }\n }\n\n // Step 3b: Find pattern matches on the call path (table may not exist)\n const routeNodeId = route.id;\n let patternRows: Array<{\n symbol_node_id: string;\n symbol_name: string;\n pattern_id: string;\n severity: string;\n line: number;\n }> = [];\n try {\n patternRows = rawDb.all(\n `WITH RECURSIVE reachable(node_id, depth) AS (\n SELECT target, 1 FROM edges WHERE source = ? AND kind IN ('calls', 'imports', 'references')\n UNION\n SELECT e.target, r.depth + 1\n FROM edges e\n JOIN reachable r ON e.source = r.node_id\n WHERE r.depth < 5 AND e.kind IN ('calls', 'imports', 'references')\n )\n SELECT DISTINCT pm.symbol_node_id, n.name as symbol_name, pm.pattern_id, pm.severity, pm.line\n FROM reachable r\n JOIN pattern_matches pm ON pm.symbol_node_id = r.node_id\n JOIN nodes n ON n.id = pm.symbol_node_id\n WHERE pm.symbol_node_id IS NOT NULL\n ORDER BY CASE pm.severity WHEN 'critical' THEN 4 WHEN 'high' THEN 3 WHEN 'medium' THEN 2 ELSE 1 END DESC\n LIMIT 10`,\n [routeNodeId],\n );\n } catch {\n // pattern_matches table does not exist yet \u2014 degrade silently\n patternRows = [];\n }\n\n const patternMatches: AttackSurfaceEntry['patternMatches'] = patternRows.map(r => ({\n patternId: r.pattern_id,\n severity: r.severity,\n line: r.line,\n symbolNodeId: r.symbol_node_id,\n symbolName: r.symbol_name,\n }));\n\n const patternRiskLevel: AttackSurfaceEntry['patternRiskLevel'] =\n patternMatches.length === 0\n ? 'none'\n : (patternMatches[0].severity as AttackSurfaceEntry['patternRiskLevel']);\n\n // Step 4: Heuristic \u2014 isAuthenticated via path node names\n const pathNodeNames: Array<{ name: string }> = rawDb.all(\n `WITH RECURSIVE reachable(node_id, depth) AS (\n SELECT target, 1 FROM edges WHERE source = ? AND kind IN ('calls', 'imports', 'references')\n UNION\n SELECT e.target, r.depth + 1\n FROM edges e\n JOIN reachable r ON e.source = r.node_id\n WHERE r.depth < 5 AND e.kind IN ('calls', 'imports', 'references')\n )\n SELECT DISTINCT n.name\n FROM reachable r\n JOIN nodes n ON n.id = r.node_id\n WHERE n.name IS NOT NULL`,\n [route.id],\n );\n\n const isAuthenticated = pathNodeNames.some(row => {\n const lowerName = (row.name ?? '').toLowerCase();\n return AUTH_PATTERNS.some(pattern => lowerName.includes(pattern));\n });\n\n // Step 5: Determine exposure level\n const routeName = (route.name ?? '').toLowerCase();\n let exposureLevel: AttackSurfaceEntry['exposureLevel'];\n\n if (INTERNAL_ROUTE_PATTERNS.some(p => routeName.includes(p))) {\n exposureLevel = 'internal';\n } else if (isAuthenticated) {\n exposureLevel = 'authenticated';\n } else if (PUBLIC_ROUTE_PATTERNS.some(p => routeName.includes(p))) {\n exposureLevel = 'public';\n } else {\n exposureLevel = 'unknown';\n }\n\n // Step 6: riskScore = max risk_score of reachable affected vulns, plus pattern bonus\n const affectedVulns = vulnerableDeps.filter(v => v.verdict === 'affected' || v.verdict === 'under_investigation');\n const baseRiskScore = affectedVulns.reduce((max, v) => {\n if (v.riskScore != null && v.riskScore > max) return v.riskScore;\n return max;\n }, 0);\n\n const patternBonus: Record<AttackSurfaceEntry['patternRiskLevel'], number> = {\n none: 0, low: 0.3, medium: 0.6, high: 0.8, critical: 1.0,\n };\n const riskScore = Math.min(10, baseRiskScore + (patternBonus[patternRiskLevel] ?? 0));\n\n entries.push({\n route: route.name ?? route.id,\n nodeId: route.id,\n filePath: route.file_path ?? '',\n isAuthenticated,\n exposureLevel,\n vulnerableDeps,\n patternMatches,\n patternRiskLevel,\n riskScore,\n });\n }\n\n // Compute summary stats\n const publicRoutes = entries.filter(e => e.exposureLevel === 'public').length;\n const authenticatedRoutes = entries.filter(\n e => e.exposureLevel === 'authenticated' || e.exposureLevel === 'internal',\n ).length;\n const routesWithVulns = entries.filter(e => e.vulnerableDeps.length > 0).length;\n\n // Critical paths: routes with affected/under_investigation vulns, sorted by riskScore desc\n const criticalPaths = entries\n .filter(e => e.vulnerableDeps.length > 0)\n .sort((a, b) => b.riskScore - a.riskScore);\n\n const allRoutes = entries.sort((a, b) => b.riskScore - a.riskScore);\n\n return {\n totalRoutes: entries.length,\n publicRoutes,\n authenticatedRoutes,\n routesWithVulns,\n criticalPaths,\n allRoutes,\n };\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Security Context Warnings
|
|
3
|
+
*
|
|
4
|
+
* Queries pre-computed reachability data to find vulnerabilities
|
|
5
|
+
* reachable from symbols included in a context response.
|
|
6
|
+
* Used by kirograph_context to append security warnings.
|
|
7
|
+
*/
|
|
8
|
+
export interface SecurityWarning {
|
|
9
|
+
cveId: string;
|
|
10
|
+
severityScore: number | null;
|
|
11
|
+
epssScore: number | null;
|
|
12
|
+
epssPercentile: number | null;
|
|
13
|
+
packageName: string;
|
|
14
|
+
ecosystem: string;
|
|
15
|
+
fixedVersion: string | null;
|
|
16
|
+
entryPoints: string[];
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Query the pre-computed reachability data to find vulnerabilities
|
|
20
|
+
* reachable from the given node IDs.
|
|
21
|
+
*
|
|
22
|
+
* This is a lightweight query joining sec_reachability + sec_vulnerabilities + sec_dependencies
|
|
23
|
+
* where the reachability paths include any of the context nodes. No graph traversal needed
|
|
24
|
+
* since reachability is pre-computed by the SecurityPipeline.
|
|
25
|
+
*
|
|
26
|
+
* @param rawDb - The raw SQLite database handle
|
|
27
|
+
* @param nodeIds - Node IDs from the context response (entry points + related symbols)
|
|
28
|
+
* @returns Array of SecurityWarning objects for affected vulnerabilities
|
|
29
|
+
*/
|
|
30
|
+
export declare function getSecurityWarningsForNodes(rawDb: any, nodeIds: string[]): SecurityWarning[];
|
|
31
|
+
/**
|
|
32
|
+
* Format security warnings into a text section for the context output.
|
|
33
|
+
* Shows max 3 vulnerabilities with a note about remaining ones.
|
|
34
|
+
*
|
|
35
|
+
* @param warnings - Array of SecurityWarning objects
|
|
36
|
+
* @param nodeNames - Map of node IDs to human-readable names (for entry point display)
|
|
37
|
+
* @returns Formatted string section, or empty string if no warnings
|
|
38
|
+
*/
|
|
39
|
+
export declare function formatSecurityWarnings(warnings: SecurityWarning[], nodeNames: Map<string, string>): string;
|
|
40
|
+
//# sourceMappingURL=context-warnings.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context-warnings.d.ts","sourceRoot":"","sources":["../../src/security/context-warnings.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,eAAe,EAAE,CA6F5F;AAED;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,eAAe,EAAE,EAAE,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,CAmC1G"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* KiroGraph SAST-lite: Dangerous Data Flow Detection
|
|
3
|
+
*
|
|
4
|
+
* Detects dangerous patterns by analysing call edges in the graph database.
|
|
5
|
+
* Uses symbol names and callee chains rather than full AST traversal.
|
|
6
|
+
*/
|
|
7
|
+
import type { GraphDatabase } from '../db/database';
|
|
8
|
+
import type { OwaspCategory } from './owasp';
|
|
9
|
+
export interface DataFlowFinding {
|
|
10
|
+
type: 'sql-injection' | 'path-traversal' | 'xss' | 'dangerous-eval' | 'unsafe-deserialize' | 'hardcoded-crypto';
|
|
11
|
+
severity: 'critical' | 'high' | 'medium';
|
|
12
|
+
owaspCategory: OwaspCategory;
|
|
13
|
+
filePath: string;
|
|
14
|
+
line: number;
|
|
15
|
+
symbol: string;
|
|
16
|
+
description: string;
|
|
17
|
+
recommendation: string;
|
|
18
|
+
}
|
|
19
|
+
export declare class DataFlowAnalyzer {
|
|
20
|
+
private readonly db;
|
|
21
|
+
constructor(db: GraphDatabase);
|
|
22
|
+
analyze(): Promise<DataFlowFinding[]>;
|
|
23
|
+
private analyzeFromPatternMatches;
|
|
24
|
+
private _patternIdToType;
|
|
25
|
+
private _findEnclosingSymbol;
|
|
26
|
+
private _getRecommendation;
|
|
27
|
+
private _detectDangerousEval;
|
|
28
|
+
private _detectUnsafeDeserialize;
|
|
29
|
+
private _detectHardcodedCrypto;
|
|
30
|
+
private _detectSqlInjection;
|
|
31
|
+
private _detectPathTraversal;
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=data-flows.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"data-flows.d.ts","sourceRoot":"","sources":["../../src/security/data-flows.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AACpD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAI7C,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,eAAe,GAAG,gBAAgB,GAAG,KAAK,GAAG,gBAAgB,GAAG,oBAAoB,GAAG,kBAAkB,CAAC;IAChH,QAAQ,EAAE,UAAU,GAAG,MAAM,GAAG,QAAQ,CAAC;IACzC,aAAa,EAAE,aAAa,CAAC;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;CACxB;AAyBD,qBAAa,gBAAgB;IACf,OAAO,CAAC,QAAQ,CAAC,EAAE;gBAAF,EAAE,EAAE,aAAa;IAExC,OAAO,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC;IAwB3C,OAAO,CAAC,yBAAyB;IA8BjC,OAAO,CAAC,gBAAgB;IASxB,OAAO,CAAC,oBAAoB;IAQ5B,OAAO,CAAC,kBAAkB;IAc1B,OAAO,CAAC,oBAAoB;IAyB5B,OAAO,CAAC,wBAAwB;IA8BhC,OAAO,CAAC,sBAAsB;IA0C9B,OAAO,CAAC,mBAAmB;IAoE3B,OAAO,CAAC,oBAAoB;CA8C7B"}
|
|
@@ -21,19 +21,77 @@ __export(data_flows_exports, {
|
|
|
21
21
|
DataFlowAnalyzer: () => DataFlowAnalyzer
|
|
22
22
|
});
|
|
23
23
|
module.exports = __toCommonJS(data_flows_exports);
|
|
24
|
+
function hasPatternsData(rawDb) {
|
|
25
|
+
try {
|
|
26
|
+
const result = rawDb.get("SELECT COUNT(*) as cnt FROM pattern_matches");
|
|
27
|
+
return (result?.cnt ?? 0) > 0;
|
|
28
|
+
} catch {
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
24
32
|
class DataFlowAnalyzer {
|
|
25
33
|
constructor(db) {
|
|
26
34
|
this.db = db;
|
|
27
35
|
}
|
|
28
36
|
async analyze() {
|
|
29
37
|
const rawDb = this.db.getRawDb();
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
38
|
+
const sqlFindings = [
|
|
39
|
+
...this._detectDangerousEval(rawDb),
|
|
40
|
+
...this._detectUnsafeDeserialize(rawDb),
|
|
41
|
+
...this._detectHardcodedCrypto(rawDb),
|
|
42
|
+
...this._detectSqlInjection(rawDb),
|
|
43
|
+
...this._detectPathTraversal(rawDb)
|
|
44
|
+
];
|
|
45
|
+
if (hasPatternsData(rawDb)) {
|
|
46
|
+
const astFindings = this.analyzeFromPatternMatches(rawDb);
|
|
47
|
+
const astKeys = new Set(astFindings.map((f) => `${f.filePath}:${f.line}`));
|
|
48
|
+
const filteredSql = sqlFindings.filter((f) => !astKeys.has(`${f.filePath}:${f.line}`));
|
|
49
|
+
return [...astFindings, ...filteredSql];
|
|
50
|
+
}
|
|
51
|
+
return sqlFindings;
|
|
52
|
+
}
|
|
53
|
+
analyzeFromPatternMatches(rawDb) {
|
|
54
|
+
const rows = rawDb.all("SELECT file_path, pattern_id, line, col, match_text, severity, owasp_category, language FROM pattern_matches");
|
|
55
|
+
return rows.map((row) => {
|
|
56
|
+
const type = this._patternIdToType(row.pattern_id);
|
|
57
|
+
const symbol = this._findEnclosingSymbol(rawDb, row.file_path, row.line);
|
|
58
|
+
return {
|
|
59
|
+
type,
|
|
60
|
+
severity: row.severity,
|
|
61
|
+
owaspCategory: row.owasp_category,
|
|
62
|
+
filePath: row.file_path,
|
|
63
|
+
line: row.line,
|
|
64
|
+
symbol: symbol ?? row.pattern_id,
|
|
65
|
+
description: `[AST pattern: ${row.pattern_id}] ${row.match_text.slice(0, 100)}`,
|
|
66
|
+
recommendation: this._getRecommendation(type)
|
|
67
|
+
};
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
_patternIdToType(patternId) {
|
|
71
|
+
if (patternId.startsWith("sql-injection")) return "sql-injection";
|
|
72
|
+
if (patternId.startsWith("dangerous-eval") || patternId.startsWith("dangerous-exec")) return "dangerous-eval";
|
|
73
|
+
if (patternId.startsWith("path-traversal")) return "path-traversal";
|
|
74
|
+
if (patternId.startsWith("prototype-pollution")) return "unsafe-deserialize";
|
|
75
|
+
if (patternId.startsWith("weak-crypto")) return "hardcoded-crypto";
|
|
76
|
+
return "dangerous-eval";
|
|
77
|
+
}
|
|
78
|
+
_findEnclosingSymbol(rawDb, filePath, line) {
|
|
79
|
+
const row = rawDb.get(
|
|
80
|
+
`SELECT name FROM nodes WHERE file_path = ? AND start_line <= ? AND end_line >= ? AND kind IN ('function', 'method', 'class') ORDER BY (end_line - start_line) ASC LIMIT 1`,
|
|
81
|
+
[filePath, line, line]
|
|
82
|
+
);
|
|
83
|
+
return row?.name ?? null;
|
|
84
|
+
}
|
|
85
|
+
_getRecommendation(type) {
|
|
86
|
+
const recs = {
|
|
87
|
+
"sql-injection": "Use parameterized queries. Never concatenate user input into SQL strings.",
|
|
88
|
+
"dangerous-eval": "Remove eval()/exec(). Use structured alternatives.",
|
|
89
|
+
"path-traversal": "Use path.resolve() and verify result is within an allowed base directory.",
|
|
90
|
+
"unsafe-deserialize": "Validate object keys before merge. Avoid untrusted deserialization.",
|
|
91
|
+
"hardcoded-crypto": "Use SHA-256+ for hashing. Use bcrypt/argon2 for passwords.",
|
|
92
|
+
"xss": "Sanitize output. Use a trusted template engine with auto-escaping."
|
|
93
|
+
};
|
|
94
|
+
return recs[type] ?? "Review and fix this security issue.";
|
|
37
95
|
}
|
|
38
96
|
// ── Detection: dangerous eval / exec ────────────────────────────────────────
|
|
39
97
|
_detectDangerousEval(rawDb) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/security/data-flows.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * KiroGraph SAST-lite: Dangerous Data Flow Detection\n *\n * Detects dangerous patterns by analysing call edges in the graph database.\n * Uses symbol names and callee chains rather than full AST traversal.\n */\n\nimport type { GraphDatabase } from '../db/database';\nimport type { OwaspCategory } from './owasp';\n\n// \u2500\u2500 Types \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface DataFlowFinding {\n type: 'sql-injection' | 'path-traversal' | 'xss' | 'dangerous-eval' | 'unsafe-deserialize' | 'hardcoded-crypto';\n severity: 'critical' | 'high' | 'medium';\n owaspCategory: OwaspCategory;\n filePath: string;\n line: number;\n symbol: string;\n description: string;\n recommendation: string;\n}\n\n// \u2500\u2500 Internal row type returned by the DB queries \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\ninterface CallEdgeRow {\n caller: string;\n file_path: string;\n start_line: number;\n callee: string;\n}\n\n// \u2500\u2500 DataFlowAnalyzer \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport class DataFlowAnalyzer {\n constructor(private readonly db: GraphDatabase) {}\n\n async analyze(): Promise<DataFlowFinding[]> {\n const rawDb = this.db.getRawDb();\n const findings: DataFlowFinding[] = [];\n\n findings.push(...this._detectDangerousEval(rawDb));\n findings.push(...this._detectUnsafeDeserialize(rawDb));\n findings.push(...this._detectHardcodedCrypto(rawDb));\n findings.push(...this._detectSqlInjection(rawDb));\n findings.push(...this._detectPathTraversal(rawDb));\n\n return findings;\n }\n\n // \u2500\u2500 Detection: dangerous eval / exec \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n private _detectDangerousEval(rawDb: any): DataFlowFinding[] {\n const rows: CallEdgeRow[] = rawDb.all(`\n SELECT n.name as caller, n.file_path, n.start_line, n2.name as callee\n FROM edges e\n JOIN nodes n ON n.id = e.source\n JOIN nodes n2 ON n2.id = e.target\n WHERE e.kind = 'calls'\n AND n2.name IN ('eval', 'Function', 'execSync', 'exec', 'spawn', 'spawnSync', 'execFileSync', 'execFile')\n AND n.file_path != ''\n `);\n\n return rows.map((row) => ({\n type: 'dangerous-eval' as const,\n severity: 'critical' as const,\n owaspCategory: 'A03' as const,\n filePath: row.file_path,\n line: row.start_line,\n symbol: row.caller,\n description: `Function '${row.caller}' calls '${row.callee}', which can execute arbitrary code or OS commands.`,\n recommendation: `Avoid '${row.callee}'. Use structured APIs or allowlists for dynamic execution. Validate and sanitize all inputs.`,\n }));\n }\n\n // \u2500\u2500 Detection: unsafe deserialization \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n private _detectUnsafeDeserialize(rawDb: any): DataFlowFinding[] {\n const rows: CallEdgeRow[] = rawDb.all(`\n SELECT n.name as caller, n.file_path, n.start_line, n2.name as callee\n FROM edges e\n JOIN nodes n ON n.id = e.source\n JOIN nodes n2 ON n2.id = e.target\n WHERE e.kind = 'calls'\n AND (\n n2.name IN ('unserialize', 'deserialize', 'fromJson', 'loads')\n OR n2.name LIKE '%pickle%'\n OR n2.name LIKE '%marshal%'\n OR n2.name = 'yaml.load'\n )\n AND n.file_path != ''\n `);\n\n return rows.map((row) => ({\n type: 'unsafe-deserialize' as const,\n severity: 'high' as const,\n owaspCategory: 'A08' as const,\n filePath: row.file_path,\n line: row.start_line,\n symbol: row.caller,\n description: `Function '${row.caller}' calls '${row.callee}', which may deserialize untrusted data unsafely.`,\n recommendation: `Validate data before deserialization. Use safe alternatives (e.g. yaml.safe_load, JSON schema validation). Never deserialize data from untrusted sources.`,\n }));\n }\n\n // \u2500\u2500 Detection: hardcoded weak crypto \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n private _detectHardcodedCrypto(rawDb: any): DataFlowFinding[] {\n const rows: CallEdgeRow[] = rawDb.all(`\n SELECT n.name as caller, n.file_path, n.start_line, n2.name as callee\n FROM edges e\n JOIN nodes n ON n.id = e.source\n JOIN nodes n2 ON n2.id = e.target\n WHERE e.kind = 'calls'\n AND (\n n2.name LIKE '%md5%'\n OR n2.name LIKE '%sha1%'\n OR n2.name LIKE '%des%'\n OR n2.name LIKE '%rc4%'\n OR n2.name LIKE '%blowfish%'\n )\n AND (\n n.name LIKE '%crypto%'\n OR n.name LIKE '%hash%'\n OR n.name LIKE '%cipher%'\n OR n.name LIKE '%encrypt%'\n OR n.name LIKE '%digest%'\n OR n.file_path LIKE '%crypto%'\n OR n.file_path LIKE '%hash%'\n OR n.file_path LIKE '%cipher%'\n OR n.file_path LIKE '%auth%'\n )\n AND n.file_path != ''\n `);\n\n return rows.map((row) => ({\n type: 'hardcoded-crypto' as const,\n severity: 'medium' as const,\n owaspCategory: 'A02' as const,\n filePath: row.file_path,\n line: row.start_line,\n symbol: row.caller,\n description: `Function '${row.caller}' uses weak or deprecated cryptographic algorithm '${row.callee}'.`,\n recommendation: `Replace with a strong algorithm: SHA-256 or SHA-3 for hashing, AES-256-GCM for symmetric encryption. Avoid MD5 and SHA-1 for security purposes.`,\n }));\n }\n\n // \u2500\u2500 Detection: SQL injection \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n private _detectSqlInjection(rawDb: any): DataFlowFinding[] {\n // Find functions that:\n // (a) call a known DB query function\n // (b) AND whose name suggests user-input handling (controller/route/request context)\n const rows: CallEdgeRow[] = rawDb.all(`\n SELECT n.name as caller, n.file_path, n.start_line, n2.name as callee\n FROM edges e\n JOIN nodes n ON n.id = e.source\n JOIN nodes n2 ON n2.id = e.target\n WHERE e.kind = 'calls'\n AND n2.name IN ('query', 'execute', 'exec', 'raw', 'runQuery', 'executeQuery', 'runSql', 'executeSql')\n AND (\n n.name LIKE '%handle%'\n OR n.name LIKE '%controller%'\n OR n.name LIKE '%route%'\n OR n.name LIKE '%request%'\n OR n.name LIKE '%req%'\n OR n.name LIKE '%endpoint%'\n OR n.name LIKE '%action%'\n OR n.name LIKE '%handler%'\n )\n AND n.file_path != ''\n `);\n\n // Only report entries that do NOT also have a sanitize/escape call in the same scope\n const sanitizeCallers: Set<string> = new Set<string>(\n (rawDb.all(`\n SELECT DISTINCT n.id\n FROM edges e\n JOIN nodes n ON n.id = e.source\n JOIN nodes n2 ON n2.id = e.target\n WHERE e.kind = 'calls'\n AND (\n n2.name LIKE '%sanitize%'\n OR n2.name LIKE '%escape%'\n OR n2.name LIKE '%parameteriz%'\n OR n2.name LIKE '%prepared%'\n OR n2.name LIKE '%placeholder%'\n )\n `) as Array<{ id: string }>).map((r) => r.id),\n );\n\n // Cross-reference: look up caller node IDs to filter sanitized callers\n const callerIds: Map<string, string> = new Map(\n (rawDb.all(`\n SELECT id, name FROM nodes WHERE kind IN ('function', 'method', 'arrow_function')\n `) as Array<{ id: string; name: string }>).map((r) => [r.name, r.id]),\n );\n\n return rows\n .filter((row) => {\n const callerId = callerIds.get(row.caller);\n return !callerId || !sanitizeCallers.has(callerId);\n })\n .map((row) => ({\n type: 'sql-injection' as const,\n severity: 'critical' as const,\n owaspCategory: 'A03' as const,\n filePath: row.file_path,\n line: row.start_line,\n symbol: row.caller,\n description: `Controller/handler '${row.caller}' calls database function '${row.callee}' without apparent input sanitization.`,\n recommendation: `Use parameterized queries or prepared statements. Never concatenate user input into SQL strings. Consider an ORM with query builders.`,\n }));\n }\n\n // \u2500\u2500 Detection: path traversal \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n private _detectPathTraversal(rawDb: any): DataFlowFinding[] {\n // Find functions that call file I/O operations and look like they handle requests.\n // Exclusions:\n // - Internal analysis/infrastructure paths (mcp, resolution, security, extraction, graph, architecture)\n // - 'open' is excluded from file ops because KiroGraph.open() (DB) triggers false positives\n // - Class names ending in 'Handler' or 'Server' are excluded (too broad \u2014 use more specific patterns)\n const rows: CallEdgeRow[] = rawDb.all(`\n SELECT n.name as caller, n.file_path, n.start_line, n2.name as callee\n FROM edges e\n JOIN nodes n ON n.id = e.source\n JOIN nodes n2 ON n2.id = e.target\n WHERE e.kind = 'calls'\n AND n2.name IN ('readFile', 'readFileSync', 'writeFile', 'writeFileSync', 'createReadStream', 'createWriteStream', 'openSync', 'unlink', 'unlinkSync')\n AND (\n n.name LIKE '%controller%'\n OR n.name LIKE '%route%'\n OR n.name LIKE '%request%'\n OR n.name LIKE '%download%'\n OR n.name LIKE '%upload%'\n OR n.name LIKE '%get%file%'\n OR n.name LIKE '%fetch%file%'\n OR n.name LIKE '%serve%file%'\n OR n.name LIKE '%handle%file%'\n )\n AND n.file_path != ''\n AND n.file_path NOT LIKE '%/mcp/%'\n AND n.file_path NOT LIKE '%/resolution/%'\n AND n.file_path NOT LIKE '%/security/%'\n AND n.file_path NOT LIKE '%/extraction/%'\n AND n.file_path NOT LIKE '%/graph/%'\n AND n.file_path NOT LIKE '%/architecture/%'\n AND n.file_path NOT LIKE '%/frameworks/%'\n AND n.file_path NOT LIKE '%/bridges/%'\n `);\n\n return rows.map((row) => ({\n type: 'path-traversal' as const,\n severity: 'high' as const,\n owaspCategory: 'A01' as const,\n filePath: row.file_path,\n line: row.start_line,\n symbol: row.caller,\n description: `Handler '${row.caller}' calls file operation '${row.callee}'. Path may be influenced by user input, enabling directory traversal.`,\n recommendation: `Validate and normalize file paths. Use path.resolve() and verify the result is inside an allowed base directory. Reject paths containing '..'.`,\n }));\n }\n}\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;
|
|
4
|
+
"sourcesContent": ["/**\n * KiroGraph SAST-lite: Dangerous Data Flow Detection\n *\n * Detects dangerous patterns by analysing call edges in the graph database.\n * Uses symbol names and callee chains rather than full AST traversal.\n */\n\nimport type { GraphDatabase } from '../db/database';\nimport type { OwaspCategory } from './owasp';\n\n// \u2500\u2500 Types \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface DataFlowFinding {\n type: 'sql-injection' | 'path-traversal' | 'xss' | 'dangerous-eval' | 'unsafe-deserialize' | 'hardcoded-crypto';\n severity: 'critical' | 'high' | 'medium';\n owaspCategory: OwaspCategory;\n filePath: string;\n line: number;\n symbol: string;\n description: string;\n recommendation: string;\n}\n\n// \u2500\u2500 Internal row type returned by the DB queries \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\ninterface CallEdgeRow {\n caller: string;\n file_path: string;\n start_line: number;\n callee: string;\n}\n\n// \u2500\u2500 hasPatternsData helper \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction hasPatternsData(rawDb: any): boolean {\n try {\n const result = rawDb.get(\"SELECT COUNT(*) as cnt FROM pattern_matches\") as { cnt: number } | undefined;\n return (result?.cnt ?? 0) > 0;\n } catch {\n // Table doesn't exist (enablePatterns never ran)\n return false;\n }\n}\n\n// \u2500\u2500 DataFlowAnalyzer \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport class DataFlowAnalyzer {\n constructor(private readonly db: GraphDatabase) {}\n\n async analyze(): Promise<DataFlowFinding[]> {\n const rawDb = (this.db as any).getRawDb();\n\n // Always run existing SQL heuristics (unchanged behavior)\n const sqlFindings = [\n ...this._detectDangerousEval(rawDb),\n ...this._detectUnsafeDeserialize(rawDb),\n ...this._detectHardcodedCrypto(rawDb),\n ...this._detectSqlInjection(rawDb),\n ...this._detectPathTraversal(rawDb),\n ];\n\n // When pattern_matches has data, merge AST findings (more precise)\n if (hasPatternsData(rawDb)) {\n const astFindings = this.analyzeFromPatternMatches(rawDb);\n // Deduplicate: AST entry wins over SQL entry at same (filePath, line)\n const astKeys = new Set(astFindings.map(f => `${f.filePath}:${f.line}`));\n const filteredSql = sqlFindings.filter(f => !astKeys.has(`${f.filePath}:${f.line}`));\n return [...astFindings, ...filteredSql];\n }\n\n return sqlFindings;\n }\n\n private analyzeFromPatternMatches(rawDb: any): DataFlowFinding[] {\n const rows: Array<{\n file_path: string;\n pattern_id: string;\n line: number;\n col: number;\n match_text: string;\n severity: string;\n owasp_category: string;\n language: string;\n }> = rawDb.all('SELECT file_path, pattern_id, line, col, match_text, severity, owasp_category, language FROM pattern_matches');\n\n return rows.map(row => {\n // Map pattern_id prefix to DataFlowFinding type\n const type = this._patternIdToType(row.pattern_id);\n // Look up nearest enclosing symbol\n const symbol = this._findEnclosingSymbol(rawDb, row.file_path, row.line);\n return {\n type,\n severity: row.severity as DataFlowFinding['severity'],\n owaspCategory: row.owasp_category as DataFlowFinding['owaspCategory'],\n filePath: row.file_path,\n line: row.line,\n symbol: symbol ?? row.pattern_id,\n description: `[AST pattern: ${row.pattern_id}] ${row.match_text.slice(0, 100)}`,\n recommendation: this._getRecommendation(type),\n };\n });\n }\n\n private _patternIdToType(patternId: string): DataFlowFinding['type'] {\n if (patternId.startsWith('sql-injection')) return 'sql-injection';\n if (patternId.startsWith('dangerous-eval') || patternId.startsWith('dangerous-exec')) return 'dangerous-eval';\n if (patternId.startsWith('path-traversal')) return 'path-traversal';\n if (patternId.startsWith('prototype-pollution')) return 'unsafe-deserialize';\n if (patternId.startsWith('weak-crypto')) return 'hardcoded-crypto';\n return 'dangerous-eval'; // fallback\n }\n\n private _findEnclosingSymbol(rawDb: any, filePath: string, line: number): string | null {\n const row = rawDb.get(\n `SELECT name FROM nodes WHERE file_path = ? AND start_line <= ? AND end_line >= ? AND kind IN ('function', 'method', 'class') ORDER BY (end_line - start_line) ASC LIMIT 1`,\n [filePath, line, line]\n ) as { name: string } | undefined;\n return row?.name ?? null;\n }\n\n private _getRecommendation(type: DataFlowFinding['type']): string {\n const recs: Record<DataFlowFinding['type'], string> = {\n 'sql-injection': 'Use parameterized queries. Never concatenate user input into SQL strings.',\n 'dangerous-eval': 'Remove eval()/exec(). Use structured alternatives.',\n 'path-traversal': 'Use path.resolve() and verify result is within an allowed base directory.',\n 'unsafe-deserialize': 'Validate object keys before merge. Avoid untrusted deserialization.',\n 'hardcoded-crypto': 'Use SHA-256+ for hashing. Use bcrypt/argon2 for passwords.',\n 'xss': 'Sanitize output. Use a trusted template engine with auto-escaping.',\n };\n return recs[type] ?? 'Review and fix this security issue.';\n }\n\n // \u2500\u2500 Detection: dangerous eval / exec \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n private _detectDangerousEval(rawDb: any): DataFlowFinding[] {\n const rows: CallEdgeRow[] = rawDb.all(`\n SELECT n.name as caller, n.file_path, n.start_line, n2.name as callee\n FROM edges e\n JOIN nodes n ON n.id = e.source\n JOIN nodes n2 ON n2.id = e.target\n WHERE e.kind = 'calls'\n AND n2.name IN ('eval', 'Function', 'execSync', 'exec', 'spawn', 'spawnSync', 'execFileSync', 'execFile')\n AND n.file_path != ''\n `);\n\n return rows.map((row) => ({\n type: 'dangerous-eval' as const,\n severity: 'critical' as const,\n owaspCategory: 'A03' as const,\n filePath: row.file_path,\n line: row.start_line,\n symbol: row.caller,\n description: `Function '${row.caller}' calls '${row.callee}', which can execute arbitrary code or OS commands.`,\n recommendation: `Avoid '${row.callee}'. Use structured APIs or allowlists for dynamic execution. Validate and sanitize all inputs.`,\n }));\n }\n\n // \u2500\u2500 Detection: unsafe deserialization \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n private _detectUnsafeDeserialize(rawDb: any): DataFlowFinding[] {\n const rows: CallEdgeRow[] = rawDb.all(`\n SELECT n.name as caller, n.file_path, n.start_line, n2.name as callee\n FROM edges e\n JOIN nodes n ON n.id = e.source\n JOIN nodes n2 ON n2.id = e.target\n WHERE e.kind = 'calls'\n AND (\n n2.name IN ('unserialize', 'deserialize', 'fromJson', 'loads')\n OR n2.name LIKE '%pickle%'\n OR n2.name LIKE '%marshal%'\n OR n2.name = 'yaml.load'\n )\n AND n.file_path != ''\n `);\n\n return rows.map((row) => ({\n type: 'unsafe-deserialize' as const,\n severity: 'high' as const,\n owaspCategory: 'A08' as const,\n filePath: row.file_path,\n line: row.start_line,\n symbol: row.caller,\n description: `Function '${row.caller}' calls '${row.callee}', which may deserialize untrusted data unsafely.`,\n recommendation: `Validate data before deserialization. Use safe alternatives (e.g. yaml.safe_load, JSON schema validation). Never deserialize data from untrusted sources.`,\n }));\n }\n\n // \u2500\u2500 Detection: hardcoded weak crypto \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n private _detectHardcodedCrypto(rawDb: any): DataFlowFinding[] {\n const rows: CallEdgeRow[] = rawDb.all(`\n SELECT n.name as caller, n.file_path, n.start_line, n2.name as callee\n FROM edges e\n JOIN nodes n ON n.id = e.source\n JOIN nodes n2 ON n2.id = e.target\n WHERE e.kind = 'calls'\n AND (\n n2.name LIKE '%md5%'\n OR n2.name LIKE '%sha1%'\n OR n2.name LIKE '%des%'\n OR n2.name LIKE '%rc4%'\n OR n2.name LIKE '%blowfish%'\n )\n AND (\n n.name LIKE '%crypto%'\n OR n.name LIKE '%hash%'\n OR n.name LIKE '%cipher%'\n OR n.name LIKE '%encrypt%'\n OR n.name LIKE '%digest%'\n OR n.file_path LIKE '%crypto%'\n OR n.file_path LIKE '%hash%'\n OR n.file_path LIKE '%cipher%'\n OR n.file_path LIKE '%auth%'\n )\n AND n.file_path != ''\n `);\n\n return rows.map((row) => ({\n type: 'hardcoded-crypto' as const,\n severity: 'medium' as const,\n owaspCategory: 'A02' as const,\n filePath: row.file_path,\n line: row.start_line,\n symbol: row.caller,\n description: `Function '${row.caller}' uses weak or deprecated cryptographic algorithm '${row.callee}'.`,\n recommendation: `Replace with a strong algorithm: SHA-256 or SHA-3 for hashing, AES-256-GCM for symmetric encryption. Avoid MD5 and SHA-1 for security purposes.`,\n }));\n }\n\n // \u2500\u2500 Detection: SQL injection \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n private _detectSqlInjection(rawDb: any): DataFlowFinding[] {\n // Find functions that:\n // (a) call a known DB query function\n // (b) AND whose name suggests user-input handling (controller/route/request context)\n const rows: CallEdgeRow[] = rawDb.all(`\n SELECT n.name as caller, n.file_path, n.start_line, n2.name as callee\n FROM edges e\n JOIN nodes n ON n.id = e.source\n JOIN nodes n2 ON n2.id = e.target\n WHERE e.kind = 'calls'\n AND n2.name IN ('query', 'execute', 'exec', 'raw', 'runQuery', 'executeQuery', 'runSql', 'executeSql')\n AND (\n n.name LIKE '%handle%'\n OR n.name LIKE '%controller%'\n OR n.name LIKE '%route%'\n OR n.name LIKE '%request%'\n OR n.name LIKE '%req%'\n OR n.name LIKE '%endpoint%'\n OR n.name LIKE '%action%'\n OR n.name LIKE '%handler%'\n )\n AND n.file_path != ''\n `);\n\n // Only report entries that do NOT also have a sanitize/escape call in the same scope\n const sanitizeCallers: Set<string> = new Set<string>(\n (rawDb.all(`\n SELECT DISTINCT n.id\n FROM edges e\n JOIN nodes n ON n.id = e.source\n JOIN nodes n2 ON n2.id = e.target\n WHERE e.kind = 'calls'\n AND (\n n2.name LIKE '%sanitize%'\n OR n2.name LIKE '%escape%'\n OR n2.name LIKE '%parameteriz%'\n OR n2.name LIKE '%prepared%'\n OR n2.name LIKE '%placeholder%'\n )\n `) as Array<{ id: string }>).map((r) => r.id),\n );\n\n // Cross-reference: look up caller node IDs to filter sanitized callers\n const callerIds: Map<string, string> = new Map(\n (rawDb.all(`\n SELECT id, name FROM nodes WHERE kind IN ('function', 'method', 'arrow_function')\n `) as Array<{ id: string; name: string }>).map((r) => [r.name, r.id]),\n );\n\n return rows\n .filter((row) => {\n const callerId = callerIds.get(row.caller);\n return !callerId || !sanitizeCallers.has(callerId);\n })\n .map((row) => ({\n type: 'sql-injection' as const,\n severity: 'critical' as const,\n owaspCategory: 'A03' as const,\n filePath: row.file_path,\n line: row.start_line,\n symbol: row.caller,\n description: `Controller/handler '${row.caller}' calls database function '${row.callee}' without apparent input sanitization.`,\n recommendation: `Use parameterized queries or prepared statements. Never concatenate user input into SQL strings. Consider an ORM with query builders.`,\n }));\n }\n\n // \u2500\u2500 Detection: path traversal \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n private _detectPathTraversal(rawDb: any): DataFlowFinding[] {\n // Find functions that call file I/O operations and look like they handle requests.\n // Exclusions:\n // - Internal analysis/infrastructure paths (mcp, resolution, security, extraction, graph, architecture)\n // - 'open' is excluded from file ops because KiroGraph.open() (DB) triggers false positives\n // - Class names ending in 'Handler' or 'Server' are excluded (too broad \u2014 use more specific patterns)\n const rows: CallEdgeRow[] = rawDb.all(`\n SELECT n.name as caller, n.file_path, n.start_line, n2.name as callee\n FROM edges e\n JOIN nodes n ON n.id = e.source\n JOIN nodes n2 ON n2.id = e.target\n WHERE e.kind = 'calls'\n AND n2.name IN ('readFile', 'readFileSync', 'writeFile', 'writeFileSync', 'createReadStream', 'createWriteStream', 'openSync', 'unlink', 'unlinkSync')\n AND (\n n.name LIKE '%controller%'\n OR n.name LIKE '%route%'\n OR n.name LIKE '%request%'\n OR n.name LIKE '%download%'\n OR n.name LIKE '%upload%'\n OR n.name LIKE '%get%file%'\n OR n.name LIKE '%fetch%file%'\n OR n.name LIKE '%serve%file%'\n OR n.name LIKE '%handle%file%'\n )\n AND n.file_path != ''\n AND n.file_path NOT LIKE '%/mcp/%'\n AND n.file_path NOT LIKE '%/resolution/%'\n AND n.file_path NOT LIKE '%/security/%'\n AND n.file_path NOT LIKE '%/extraction/%'\n AND n.file_path NOT LIKE '%/graph/%'\n AND n.file_path NOT LIKE '%/architecture/%'\n AND n.file_path NOT LIKE '%/frameworks/%'\n AND n.file_path NOT LIKE '%/bridges/%'\n `);\n\n return rows.map((row) => ({\n type: 'path-traversal' as const,\n severity: 'high' as const,\n owaspCategory: 'A01' as const,\n filePath: row.file_path,\n line: row.start_line,\n symbol: row.caller,\n description: `Handler '${row.caller}' calls file operation '${row.callee}'. Path may be influenced by user input, enabling directory traversal.`,\n recommendation: `Validate and normalize file paths. Use path.resolve() and verify the result is inside an allowed base directory. Reject paths containing '..'.`,\n }));\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dependency Confusion Checker
|
|
3
|
+
*
|
|
4
|
+
* Detects internal packages whose names exist in public registries
|
|
5
|
+
* (a supply chain attack vector), and flags typosquatting candidates.
|
|
6
|
+
*/
|
|
7
|
+
import type { GraphDatabase } from '../db/database';
|
|
8
|
+
export interface DepConfusionFinding {
|
|
9
|
+
packageName: string;
|
|
10
|
+
ecosystem: string;
|
|
11
|
+
internalSource: string;
|
|
12
|
+
publicExists: boolean;
|
|
13
|
+
publicVersion: string | null;
|
|
14
|
+
publicPublishedAt: string | null;
|
|
15
|
+
riskLevel: 'critical' | 'high' | 'medium';
|
|
16
|
+
explanation: string;
|
|
17
|
+
}
|
|
18
|
+
export declare class DepConfusionChecker {
|
|
19
|
+
private readonly db;
|
|
20
|
+
constructor(db: GraphDatabase);
|
|
21
|
+
check(): Promise<DepConfusionFinding[]>;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=dep-confusion.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dep-confusion.d.ts","sourceRoot":"","sources":["../../src/security/dep-confusion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAIpD,MAAM,WAAW,mBAAmB;IAClC,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,OAAO,CAAC;IACtB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,SAAS,EAAE,UAAU,GAAG,MAAM,GAAG,QAAQ,CAAC;IAC1C,WAAW,EAAE,MAAM,CAAC;CACrB;AAoKD,qBAAa,mBAAmB;IAClB,OAAO,CAAC,QAAQ,CAAC,EAAE;gBAAF,EAAE,EAAE,aAAa;IAExC,KAAK,IAAI,OAAO,CAAC,mBAAmB,EAAE,CAAC;CA0G9C"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* KiroGraph-Sec Error Classes
|
|
3
|
+
*
|
|
4
|
+
* Security-specific error types extending the base KiroGraphError.
|
|
5
|
+
*/
|
|
6
|
+
import { KiroGraphError } from '../errors';
|
|
7
|
+
export declare class SecurityError extends KiroGraphError {
|
|
8
|
+
constructor(message: string, context?: Record<string, unknown>);
|
|
9
|
+
}
|
|
10
|
+
export declare class ManifestParseError extends KiroGraphError {
|
|
11
|
+
constructor(message: string, filePath: string, line?: number);
|
|
12
|
+
}
|
|
13
|
+
export declare class VulnDatabaseError extends KiroGraphError {
|
|
14
|
+
constructor(message: string, database: string, httpStatus?: number);
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/security/errors.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAE3C,qBAAa,aAAc,SAAQ,cAAc;gBACnC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;CAI/D;AAED,qBAAa,kBAAmB,SAAQ,cAAc;gBACxC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM;CAI7D;AAED,qBAAa,iBAAkB,SAAQ,cAAc;gBACvC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM;CAInE"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fix Suggestion Builder
|
|
3
|
+
*
|
|
4
|
+
* Generates ecosystem-appropriate upgrade commands for vulnerabilities
|
|
5
|
+
* that have a known fixed version. Reusable by CLI and MCP tools.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Build an ecosystem-appropriate fix suggestion command.
|
|
9
|
+
*
|
|
10
|
+
* @param ecosystem - The package ecosystem (npm, maven, go, pypi, cargo)
|
|
11
|
+
* @param packageName - The package name (for maven: groupId:artifactId)
|
|
12
|
+
* @param fixedVersion - The version that fixes the vulnerability
|
|
13
|
+
* @returns A formatted fix command string, or empty string if ecosystem is unknown
|
|
14
|
+
*/
|
|
15
|
+
export declare function buildFixSuggestion(ecosystem: string, packageName: string, fixedVersion: string): string;
|
|
16
|
+
/**
|
|
17
|
+
* Format a fix suggestion line for display.
|
|
18
|
+
* Returns the formatted line with the 💡 prefix, or empty string if no fixed version.
|
|
19
|
+
*/
|
|
20
|
+
export declare function formatFixSuggestion(ecosystem: string, packageName: string, fixedVersion: string | null | undefined): string;
|
|
21
|
+
//# sourceMappingURL=fix-suggestions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fix-suggestions.d.ts","sourceRoot":"","sources":["../../../src/security/export/fix-suggestions.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM,CAuBvG;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAI3H"}
|