codebase-onboarder 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +174 -46
- package/bin/build-if-source.js +23 -0
- package/cli/commands.d.ts +26 -0
- package/cli/commands.js +836 -811
- package/cli/commands.js.map +1 -0
- package/cli/explorer/advanced.d.ts +14 -0
- package/cli/explorer/advanced.js +321 -329
- package/cli/explorer/advanced.js.map +1 -0
- package/cli/explorer/app.d.ts +1 -0
- package/cli/explorer/app.js +384 -313
- package/cli/explorer/app.js.map +1 -0
- package/cli/explorer/assistant.d.ts +9 -0
- package/cli/explorer/assistant.js +58 -0
- package/cli/explorer/assistant.js.map +1 -0
- package/cli/explorer/commands.d.ts +17 -0
- package/cli/explorer/commands.js +368 -302
- package/cli/explorer/commands.js.map +1 -0
- package/cli/explorer/featureViews.d.ts +124 -0
- package/cli/explorer/featureViews.js +179 -0
- package/cli/explorer/featureViews.js.map +1 -0
- package/cli/explorer/github.d.ts +21 -0
- package/cli/explorer/github.js +42 -44
- package/cli/explorer/github.js.map +1 -0
- package/cli/explorer/graphs.d.ts +7 -0
- package/cli/explorer/graphs.js +90 -95
- package/cli/explorer/graphs.js.map +1 -0
- package/cli/explorer/picker.d.ts +22 -0
- package/cli/explorer/picker.js +150 -0
- package/cli/explorer/picker.js.map +1 -0
- package/cli/explorer/report.d.ts +85 -0
- package/cli/explorer/report.js +60 -0
- package/cli/explorer/report.js.map +1 -0
- package/cli/explorer/session.d.ts +449 -0
- package/cli/explorer/session.js +143 -144
- package/cli/explorer/session.js.map +1 -0
- package/cli/explorer/views.d.ts +19 -0
- package/cli/explorer/views.js +465 -482
- package/cli/explorer/views.js.map +1 -0
- package/cli/explorer/wrap.d.ts +1 -0
- package/cli/explorer/wrap.js +28 -44
- package/cli/explorer/wrap.js.map +1 -0
- package/cli/main.d.ts +1 -0
- package/cli/main.js +214 -161
- package/cli/main.js.map +1 -0
- package/cli/prompt.d.ts +5 -0
- package/cli/prompt.js +84 -80
- package/cli/prompt.js.map +1 -0
- package/cli/scanOptions.d.ts +2 -0
- package/cli/scanOptions.js +11 -0
- package/cli/scanOptions.js.map +1 -0
- package/cli/ui.d.ts +33 -0
- package/cli/ui.js +35 -44
- package/cli/ui.js.map +1 -0
- package/cli/wizard.d.ts +187 -0
- package/cli/wizard.js +304 -284
- package/cli/wizard.js.map +1 -0
- package/package.json +15 -4
- package/public/app.d.ts +1 -0
- package/public/app.js +1057 -1009
- package/public/app.js.map +1 -0
- package/public/browser.d.ts +68 -0
- package/public/browser.js +2 -0
- package/public/browser.js.map +1 -0
- package/public/index.html +30 -13
- package/public/js/about.d.ts +6 -0
- package/public/js/about.js +152 -172
- package/public/js/about.js.map +1 -0
- package/public/js/aiDraft.d.ts +3 -0
- package/public/js/aiDraft.js +116 -124
- package/public/js/aiDraft.js.map +1 -0
- package/public/js/analysisPanel.d.ts +7 -0
- package/public/js/analysisPanel.js +166 -166
- package/public/js/analysisPanel.js.map +1 -0
- package/public/js/analysisReport.d.ts +38 -0
- package/public/js/analysisReport.js +105 -110
- package/public/js/analysisReport.js.map +1 -0
- package/public/js/api.d.ts +26 -0
- package/public/js/api.js +176 -167
- package/public/js/api.js.map +1 -0
- package/public/js/atlas.d.ts +6 -0
- package/public/js/atlas.js +50 -58
- package/public/js/atlas.js.map +1 -0
- package/public/js/blameView.d.ts +2 -0
- package/public/js/blameView.js +36 -37
- package/public/js/blameView.js.map +1 -0
- package/public/js/codeTab.d.ts +3 -0
- package/public/js/codeTab.js +175 -180
- package/public/js/codeTab.js.map +1 -0
- package/public/js/codeViewer.d.ts +5 -0
- package/public/js/codeViewer.js +162 -150
- package/public/js/codeViewer.js.map +1 -0
- package/public/js/components/FileChip.d.ts +9 -0
- package/public/js/components/FileChip.js +45 -49
- package/public/js/components/FileChip.js.map +1 -0
- package/public/js/components/MetricSparkline.d.ts +7 -0
- package/public/js/components/MetricSparkline.js +35 -44
- package/public/js/components/MetricSparkline.js.map +1 -0
- package/public/js/components/RiskBadge.d.ts +9 -0
- package/public/js/components/RiskBadge.js +55 -63
- package/public/js/components/RiskBadge.js.map +1 -0
- package/public/js/deepAnalysisView.d.ts +99 -0
- package/public/js/deepAnalysisView.js +282 -302
- package/public/js/deepAnalysisView.js.map +1 -0
- package/public/js/diagramPane.d.ts +8 -0
- package/public/js/diagramPane.js +133 -135
- package/public/js/diagramPane.js.map +1 -0
- package/public/js/diffView.d.ts +6 -0
- package/public/js/diffView.js +222 -209
- package/public/js/diffView.js.map +1 -0
- package/public/js/docsView.d.ts +2 -0
- package/public/js/docsView.js +441 -442
- package/public/js/docsView.js.map +1 -0
- package/public/js/dom.d.ts +189 -0
- package/public/js/dom.js +5 -0
- package/public/js/dom.js.map +1 -0
- package/public/js/fileSourceBrowser.d.ts +5 -0
- package/public/js/fileSourceBrowser.js +33 -41
- package/public/js/fileSourceBrowser.js.map +1 -0
- package/public/js/flameGraph.d.ts +5 -0
- package/public/js/flameGraph.js +62 -72
- package/public/js/flameGraph.js.map +1 -0
- package/public/js/forceGraph.d.ts +10 -0
- package/public/js/forceGraph.js +581 -556
- package/public/js/forceGraph.js.map +1 -0
- package/public/js/heatmap.d.ts +4 -0
- package/public/js/heatmap.js +142 -164
- package/public/js/heatmap.js.map +1 -0
- package/public/js/highlight.d.ts +2 -0
- package/public/js/highlight.js +116 -107
- package/public/js/highlight.js.map +1 -0
- package/public/js/html.d.ts +2 -0
- package/public/js/html.js +14 -44
- package/public/js/html.js.map +1 -0
- package/public/js/insightsView.d.ts +5 -0
- package/public/js/insightsView.js +93 -111
- package/public/js/insightsView.js.map +1 -0
- package/public/js/inspector.d.ts +37 -0
- package/public/js/inspector.js +416 -445
- package/public/js/inspector.js.map +1 -0
- package/public/js/llm.d.ts +113 -0
- package/public/js/llm.js +233 -272
- package/public/js/llm.js.map +1 -0
- package/public/js/mapView.d.ts +3 -0
- package/public/js/mapView.js +121 -120
- package/public/js/mapView.js.map +1 -0
- package/public/js/markdown.d.ts +3 -0
- package/public/js/markdown.js +84 -91
- package/public/js/markdown.js.map +1 -0
- package/public/js/mindmap.d.ts +32 -0
- package/public/js/mindmap.js +244 -259
- package/public/js/mindmap.js.map +1 -0
- package/public/js/mobilePanels.d.ts +5 -0
- package/public/js/mobilePanels.js +50 -0
- package/public/js/mobilePanels.js.map +1 -0
- package/public/js/repoFiles.d.ts +12 -0
- package/public/js/repoFiles.js +28 -27
- package/public/js/repoFiles.js.map +1 -0
- package/public/js/reviewView.d.ts +28 -0
- package/public/js/reviewView.js +256 -0
- package/public/js/reviewView.js.map +1 -0
- package/public/js/sbomView.d.ts +3 -0
- package/public/js/sbomView.js +59 -67
- package/public/js/sbomView.js.map +1 -0
- package/public/js/scanCache.d.ts +16 -0
- package/public/js/scanCache.js +67 -65
- package/public/js/scanCache.js.map +1 -0
- package/public/js/search.d.ts +7 -0
- package/public/js/search.js +868 -800
- package/public/js/search.js.map +1 -0
- package/public/js/searchLocal.d.ts +42 -0
- package/public/js/searchLocal.js +87 -0
- package/public/js/searchLocal.js.map +1 -0
- package/public/js/serverSettings.d.ts +5 -0
- package/public/js/serverSettings.js +153 -164
- package/public/js/serverSettings.js.map +1 -0
- package/public/js/state.d.ts +798 -0
- package/public/js/state.js +114 -122
- package/public/js/state.js.map +1 -0
- package/public/js/tour.d.ts +6 -0
- package/public/js/tour.js +5 -7
- package/public/js/tour.js.map +1 -0
- package/public/js/transitions.d.ts +2 -0
- package/public/js/transitions.js +9 -10
- package/public/js/transitions.js.map +1 -0
- package/public/js/tree.d.ts +12 -0
- package/public/js/tree.js +157 -154
- package/public/js/tree.js.map +1 -0
- package/public/js/workflowsView.d.ts +3 -0
- package/public/js/workflowsView.js +15 -22
- package/public/js/workflowsView.js.map +1 -0
- package/public/search.css +495 -0
- package/public/styles.css +163 -346
- package/public/workbench.css +166 -0
- package/server/apiAuth.d.ts +3 -0
- package/server/apiAuth.js +18 -20
- package/server/apiAuth.js.map +1 -0
- package/server/apiDiff.d.ts +2 -0
- package/server/apiDiff.js +20 -18
- package/server/apiDiff.js.map +1 -0
- package/server/apiDocs.d.ts +2 -0
- package/server/apiDocs.js +38 -40
- package/server/apiDocs.js.map +1 -0
- package/server/apiFile.d.ts +1 -0
- package/server/apiFile.js +14 -17
- package/server/apiFile.js.map +1 -0
- package/server/apiGitBlame.d.ts +2 -0
- package/server/apiGitBlame.js +50 -51
- package/server/apiGitBlame.js.map +1 -0
- package/server/apiMcp.d.ts +4 -0
- package/server/apiMcp.js +64 -66
- package/server/apiMcp.js.map +1 -0
- package/server/apiReview.d.ts +2 -0
- package/server/apiReview.js +45 -0
- package/server/apiReview.js.map +1 -0
- package/server/apiScan.d.ts +5 -0
- package/server/apiScan.js +90 -71
- package/server/apiScan.js.map +1 -0
- package/server/apiSearch.d.ts +33 -0
- package/server/apiSearch.js +184 -200
- package/server/apiSearch.js.map +1 -0
- package/server/apiSettings.d.ts +4 -0
- package/server/apiSettings.js +84 -85
- package/server/apiSettings.js.map +1 -0
- package/server/apiTools.d.ts +3 -0
- package/server/apiTools.js +55 -56
- package/server/apiTools.js.map +1 -0
- package/server/auth.d.ts +5 -0
- package/server/auth.js +54 -51
- package/server/auth.js.map +1 -0
- package/server/config.d.ts +42 -0
- package/server/config.js +189 -194
- package/server/config.js.map +1 -0
- package/server/daemon.d.ts +12 -0
- package/server/daemon.js +124 -114
- package/server/daemon.js.map +1 -0
- package/server/fileSourceNode.d.ts +2 -0
- package/server/fileSourceNode.js +34 -36
- package/server/fileSourceNode.js.map +1 -0
- package/server/gitClone.d.ts +9 -0
- package/server/gitClone.js +59 -61
- package/server/gitClone.js.map +1 -0
- package/server/gitDiff.d.ts +36 -0
- package/server/gitDiff.js +271 -169
- package/server/gitDiff.js.map +1 -0
- package/server/gitHistory.d.ts +12 -0
- package/server/gitHistory.js +80 -80
- package/server/gitHistory.js.map +1 -0
- package/server/gitRemote.d.ts +12 -0
- package/server/gitRemote.js +37 -38
- package/server/gitRemote.js.map +1 -0
- package/server/htmlText.d.ts +4 -0
- package/server/htmlText.js +16 -23
- package/server/htmlText.js.map +1 -0
- package/server/http.d.ts +5 -0
- package/server/http.js +27 -30
- package/server/http.js.map +1 -0
- package/server/httpGuards.d.ts +2 -0
- package/server/httpGuards.js +47 -43
- package/server/httpGuards.js.map +1 -0
- package/server/https.d.ts +34 -0
- package/server/https.js +121 -111
- package/server/https.js.map +1 -0
- package/server/index.d.ts +40 -0
- package/server/index.js +139 -147
- package/server/index.js.map +1 -0
- package/server/layout.d.ts +26 -0
- package/server/layout.js +59 -64
- package/server/layout.js.map +1 -0
- package/server/llmProxy.d.ts +3 -0
- package/server/llmProxy.js +137 -135
- package/server/llmProxy.js.map +1 -0
- package/server/logger.d.ts +38 -0
- package/server/logger.js +198 -211
- package/server/logger.js.map +1 -0
- package/server/mcp/analysis.d.ts +29 -0
- package/server/mcp/analysis.js +99 -120
- package/server/mcp/analysis.js.map +1 -0
- package/server/mcp/http.d.ts +9 -0
- package/server/mcp/http.js +128 -137
- package/server/mcp/http.js.map +1 -0
- package/server/mcp/runner.d.ts +68 -0
- package/server/mcp/runner.js +208 -218
- package/server/mcp/runner.js.map +1 -0
- package/server/mcp/server.d.ts +29 -0
- package/server/mcp/server.js +166 -179
- package/server/mcp/server.js.map +1 -0
- package/server/mcp/standalone.d.ts +1 -0
- package/server/mcp/standalone.js +8 -10
- package/server/mcp/standalone.js.map +1 -0
- package/server/mcp/tools.d.ts +2020 -0
- package/server/mcp/tools.js +523 -574
- package/server/mcp/tools.js.map +1 -0
- package/server/paths.d.ts +3 -0
- package/server/paths.js +17 -15
- package/server/paths.js.map +1 -0
- package/server/pidfile.d.ts +9 -0
- package/server/pidfile.js +43 -45
- package/server/pidfile.js.map +1 -0
- package/server/review.d.ts +5 -0
- package/server/review.js +35 -0
- package/server/review.js.map +1 -0
- package/server/router.d.ts +33 -0
- package/server/router.js +191 -197
- package/server/router.js.map +1 -0
- package/server/scanRequest.d.ts +3 -0
- package/server/scanRequest.js +36 -0
- package/server/scanRequest.js.map +1 -0
- package/server/searchIndex.d.ts +17 -0
- package/server/searchIndex.js +83 -80
- package/server/searchIndex.js.map +1 -0
- package/server/sessions.d.ts +14 -0
- package/server/sessions.js +62 -70
- package/server/sessions.js.map +1 -0
- package/server/startup.d.ts +118 -0
- package/server/startup.js +143 -148
- package/server/startup.js.map +1 -0
- package/server/static.d.ts +6 -0
- package/server/static.js +28 -31
- package/server/static.js.map +1 -0
- package/server/tools/install.d.ts +4 -0
- package/server/tools/install.js +176 -185
- package/server/tools/install.js.map +1 -0
- package/server/tools/parse.d.ts +8 -0
- package/server/tools/parse.js +112 -114
- package/server/tools/parse.js.map +1 -0
- package/server/tools/platform.d.ts +9 -0
- package/server/tools/platform.js +49 -47
- package/server/tools/platform.js.map +1 -0
- package/server/tools/registry.d.ts +137 -0
- package/server/tools/registry.js +173 -172
- package/server/tools/registry.js.map +1 -0
- package/server/tools/scan.d.ts +34 -0
- package/server/tools/scan.js +89 -98
- package/server/tools/scan.js.map +1 -0
- package/server/tools.d.ts +34 -0
- package/server/tools.js +94 -107
- package/server/tools.js.map +1 -0
- package/server/tunnel.d.ts +29 -0
- package/server/tunnel.js +61 -66
- package/server/tunnel.js.map +1 -0
- package/shared/analyzer/docs.d.ts +16 -0
- package/shared/analyzer/docs.js +99 -93
- package/shared/analyzer/docs.js.map +1 -0
- package/shared/analyzer/explainLocal.d.ts +4 -0
- package/shared/analyzer/explainLocal.js +122 -142
- package/shared/analyzer/explainLocal.js.map +1 -0
- package/shared/analyzer/github.d.ts +37 -0
- package/shared/analyzer/github.js +41 -43
- package/shared/analyzer/github.js.map +1 -0
- package/shared/analyzer/graph.d.ts +41 -0
- package/shared/analyzer/graph.js +393 -400
- package/shared/analyzer/graph.js.map +1 -0
- package/shared/analyzer/health.d.ts +33 -0
- package/shared/analyzer/health.js +197 -193
- package/shared/analyzer/health.js.map +1 -0
- package/shared/analyzer/history.d.ts +29 -0
- package/shared/analyzer/history.js +110 -111
- package/shared/analyzer/history.js.map +1 -0
- package/shared/analyzer/jsonConfig.d.ts +2 -0
- package/shared/analyzer/jsonConfig.js +61 -0
- package/shared/analyzer/jsonConfig.js.map +1 -0
- package/shared/analyzer/languages/csharp.d.ts +26 -0
- package/shared/analyzer/languages/csharp.js +83 -88
- package/shared/analyzer/languages/csharp.js.map +1 -0
- package/shared/analyzer/languages/generic.d.ts +23 -0
- package/shared/analyzer/languages/generic.js +94 -105
- package/shared/analyzer/languages/generic.js.map +1 -0
- package/shared/analyzer/languages/go.d.ts +24 -0
- package/shared/analyzer/languages/go.js +45 -54
- package/shared/analyzer/languages/go.js.map +1 -0
- package/shared/analyzer/languages/index.d.ts +6 -0
- package/shared/analyzer/languages/index.js +19 -20
- package/shared/analyzer/languages/index.js.map +1 -0
- package/shared/analyzer/languages/java.d.ts +20 -0
- package/shared/analyzer/languages/java.js +73 -78
- package/shared/analyzer/languages/java.js.map +1 -0
- package/shared/analyzer/languages/javascript.d.ts +12 -0
- package/shared/analyzer/languages/javascript.js +258 -209
- package/shared/analyzer/languages/javascript.js.map +1 -0
- package/shared/analyzer/languages/python.d.ts +23 -0
- package/shared/analyzer/languages/python.js +92 -100
- package/shared/analyzer/languages/python.js.map +1 -0
- package/shared/analyzer/languages/rust.d.ts +17 -0
- package/shared/analyzer/languages/rust.js +96 -98
- package/shared/analyzer/languages/rust.js.map +1 -0
- package/shared/analyzer/languages/typescript.d.ts +11 -0
- package/shared/analyzer/languages/typescript.js +117 -116
- package/shared/analyzer/languages/typescript.js.map +1 -0
- package/shared/analyzer/licenses.d.ts +18 -0
- package/shared/analyzer/licenses.js +130 -133
- package/shared/analyzer/licenses.js.map +1 -0
- package/shared/analyzer/metrics.d.ts +20 -0
- package/shared/analyzer/metrics.js +112 -104
- package/shared/analyzer/metrics.js.map +1 -0
- package/shared/analyzer/pathUtil.d.ts +10 -0
- package/shared/analyzer/pathUtil.js +29 -35
- package/shared/analyzer/pathUtil.js.map +1 -0
- package/shared/analyzer/patterns.d.ts +11 -0
- package/shared/analyzer/patterns.js +231 -253
- package/shared/analyzer/patterns.js.map +1 -0
- package/shared/analyzer/scan.d.ts +62 -0
- package/shared/analyzer/scan.js +451 -442
- package/shared/analyzer/scan.js.map +1 -0
- package/shared/analyzer/scanControl.d.ts +11 -0
- package/shared/analyzer/scanControl.js +62 -0
- package/shared/analyzer/scanControl.js.map +1 -0
- package/shared/analyzer/security.d.ts +18 -0
- package/shared/analyzer/security.js +159 -159
- package/shared/analyzer/security.js.map +1 -0
- package/shared/analyzer/services.d.ts +5 -0
- package/shared/analyzer/services.js +141 -138
- package/shared/analyzer/services.js.map +1 -0
- package/shared/analyzer/stack.d.ts +6 -0
- package/shared/analyzer/stack.js +134 -141
- package/shared/analyzer/stack.js.map +1 -0
- package/shared/analyzer/tour.d.ts +2 -0
- package/shared/analyzer/tour.js +45 -53
- package/shared/analyzer/tour.js.map +1 -0
- package/shared/analyzer/util.d.ts +8 -0
- package/shared/analyzer/util.js +130 -76
- package/shared/analyzer/util.js.map +1 -0
- package/shared/analyzer/workflows.d.ts +8 -0
- package/shared/analyzer/workflows.js +139 -134
- package/shared/analyzer/workflows.js.map +1 -0
- package/shared/contracts.d.ts +250 -0
- package/shared/contracts.js +2 -0
- package/shared/contracts.js.map +1 -0
- package/shared/diagram/aiFacts.d.ts +35 -0
- package/shared/diagram/aiFacts.js +102 -105
- package/shared/diagram/aiFacts.js.map +1 -0
- package/shared/diagram/aiMermaid.d.ts +5 -0
- package/shared/diagram/aiMermaid.js +46 -45
- package/shared/diagram/aiMermaid.js.map +1 -0
- package/shared/diagram/atlas.d.ts +16 -0
- package/shared/diagram/atlas.js +51 -60
- package/shared/diagram/atlas.js.map +1 -0
- package/shared/diagram/mermaid.d.ts +43 -0
- package/shared/diagram/mermaid.js +348 -370
- package/shared/diagram/mermaid.js.map +1 -0
- package/shared/review/contracts.d.ts +95 -0
- package/shared/review/contracts.js +2 -0
- package/shared/review/contracts.js.map +1 -0
- package/shared/review/review.d.ts +10 -0
- package/shared/review/review.js +184 -0
- package/shared/review/review.js.map +1 -0
- package/shared/search/query.d.ts +32 -0
- package/shared/search/query.js +395 -388
- package/shared/search/query.js.map +1 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scan.js","sourceRoot":"","sources":["../../src/shared/analyzer/scan.ts"],"names":[],"mappings":"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","sourcesContent":["import { parseJsonConfig } from './jsonConfig.js';\nimport type { FileSource, ScanOptions, ImportEdge, ScannedFile, ScannedFolder, LanguageAnalyzer } from '../contracts.js';\nimport { DEFAULT_LIMITS, normalizeScanOptions, throwIfAborted, abortable, utf8ByteLength } from './scanControl.js';\nexport { DEFAULT_LIMITS } from './scanControl.js';\n// The scanner: walks a FileSource, dispatches per-language analyzers,\n// resolves imports into edges, and hands back one big plain-data result.\n//\n// FileSource interface (both adapters implement it):\n// list(dir) -> [{ name, path, type: 'file'|'dir' }]\n// read(path) -> string\n// Paths are repo-relative, POSIX style ('' is the root).\n\nimport { languageFor } from './languages/index.js';\nimport { dirOf, baseName, extOf } from './pathUtil.js';\nimport { codeStats, complexityOf } from './metrics.js';\nimport { analyzeSecurityFile } from './security.js';\nimport { analyzeLicenses } from './licenses.js';\nimport { analyzeWorkflows } from './workflows.js';\nimport { detectManifest } from './services.js';\n\nconst SKIP_DIRS = new Set([\n 'node_modules', '.git', '.hg', '.svn', 'dist', 'build', 'out', '.next',\n '.nuxt', 'target', 'vendor', '__pycache__', '.venv', 'venv', 'env',\n '.idea', '.vscode', 'coverage', '.cache', '.turbo', 'tmp', 'temp',\n 'DerivedData', 'Pods', '.gradle', 'bin', 'obj',\n]);\n\nconst SKIP_FILES = new Set([\n 'package-lock.json', 'yarn.lock', 'pnpm-lock.yaml', 'composer.lock',\n 'Gemfile.lock', 'Cargo.lock', 'poetry.lock', '.DS_Store',\n]);\n\nconst SKIP_EXTS = new Set([\n '.png', '.jpg', '.jpeg', '.gif', '.webp', '.ico', '.icns', '.svg',\n '.woff', '.woff2', '.ttf', '.otf', '.eot', '.mp4', '.mov', '.mp3',\n '.wav', '.zip', '.gz', '.tar', '.rar', '.7z', '.pdf', '.jar', '.war',\n '.class', '.o', '.a', '.so', '.dylib', '.dll', '.exe', '.pyc', '.wasm',\n '.min.js', '.min.css', '.map', '.lock', '.bin', '.db', '.sqlite',\n]);\n\n\nfunction shouldSkipFile(name) {\n if (SKIP_FILES.has(name)) return true;\n if (SKIP_EXTS.has(extOf(name))) return true;\n // extOf() only sees the final suffix, so name the common bundle shapes here.\n return /\\.min\\.(js|css)$/i.test(name);\n}\n\nexport async function scanRepo(source: FileSource, options: ScanOptions = {}) {\n const limits = normalizeScanOptions(options);\n const signal = options.signal;\n throwIfAborted(signal);\n const onProgress = options.onProgress || ((..._args: unknown[]) => {});\n const startedAt = Date.now();\n\n const ignore = await abortable(buildIgnoreMatcher(source), signal);\n\n // Every way a file or directory can drop out of the scan, counted apart.\n // One integer for all of them hid the difference between \"we ignored a\n // lockfile\" and \"we could not read your source\" — and only one of those is\n // something the reader needs to know about.\n const skips = {\n ignored: 0, // matched a .gitignore rule\n vendorDir: 0, // node_modules, dist, .git, any dotfolder\n notSource: 0, // images, lockfiles, minified bundles\n listFailed: 0, // the directory would not list\n notCode: 0, // no analyzer for this extension (README.md, .yml, …)\n readFailed: 0, // the file would not read\n tooLarge: 0, // over maxFileSize\n analyzeFailed: 0, // the language analyzer threw\n };\n\n // ---- Walk --------------------------------------------------------------\n const allFiles: string[] = [];\n let truncated = null;\n const queue = [''];\n walk: while (queue.length) {\n throwIfAborted(signal);\n const dir = queue.shift();\n let entries;\n try {\n entries = await abortable(source.list(dir), signal);\n } catch {\n throwIfAborted(signal);\n skips.listFailed++;\n continue;\n }\n for (const entry of entries) {\n if (allFiles.length >= limits.maxFiles) {\n // Stop the entire walk, not just this directory. A plain `break` here\n // left every already-queued directory to be listed anyway, so the cap\n // was both slower and less predictable than it looked.\n truncated = { atFiles: allFiles.length, dirsQueued: queue.length };\n break walk;\n }\n if (ignore(entry.path)) {\n skips.ignored++;\n continue;\n }\n if (entry.type === 'dir') {\n if (SKIP_DIRS.has(entry.name) || entry.name.startsWith('.')) {\n skips.vendorDir++;\n continue;\n }\n queue.push(entry.path);\n } else {\n if (shouldSkipFile(entry.name)) {\n skips.notSource++;\n continue;\n }\n allFiles.push(entry.path);\n }\n }\n onProgress({ phase: 'walk', found: allFiles.length });\n }\n allFiles.sort();\n\n const fileSet = new Set(allFiles);\n const dirSet = new Set(['']);\n for (const p of allFiles) {\n let d = dirOf(p);\n while (true) {\n if (dirSet.has(d)) break;\n dirSet.add(d);\n d = dirOf(d);\n }\n }\n const has = (p) => fileSet.has(p);\n const hasDir = (d) => dirSet.has(d);\n const nameIndex = new Map();\n for (const p of allFiles) {\n const n = baseName(p);\n if (!nameIndex.has(n)) nameIndex.set(n, p);\n }\n const findByName = (n) => nameIndex.get(n) || null;\n\n // Find a directory whose path *ends with* a run of segments. This is what C#\n // needs and Java does not: a C# file's folder mirrors the namespace, but the\n // root namespace (the company or project name) is normally not a directory,\n // so `namespace Acme.Services` lives in `src/Services/`. Matching on a path\n // suffix is the only thing that finds it — stripping the whole namespace, the\n // Java approach, matches nothing and silently drops every import.\n //\n // Keyed by the last three segments, which is enough to tell\n // `Acme/Models/Entities` apart from a bare `Entities` elsewhere while staying\n // O(1) per lookup. A collision at the shortest key keeps the first match, and\n // callers query longest-first, so the most specific answer is tried first.\n const dirByTail = new Map();\n for (const d of dirSet) {\n if (!d) continue;\n const segments = d.split('/');\n for (let take = 1; take <= 3 && take <= segments.length; take += 1) {\n const key = segments.slice(segments.length - take).join('/');\n if (!dirByTail.has(key)) dirByTail.set(key, d);\n }\n }\n const findDirEndingWith = (suffix) => (suffix ? dirByTail.get(suffix) || null : null);\n\n const context = {\n hasDir,\n findDirEndingWith,\n findByName,\n modulePath: await abortable(readModulePath(source), signal),\n tsPaths: await abortable(readTsConfigPaths(source), signal),\n };\n\n // ---- Parse ---------------------------------------------------------------\n // Reads run a window ahead of the analysis; the analysis stays strictly in\n // path order. Waiting for one `read` to land before starting the next was the\n // largest wall-clock cost of a scan and the one with the least to show for\n // it — every adapter behind `FileSource` is I/O, and neither `node:fs` nor the\n // File System Access API cares how many requests are outstanding.\n //\n // Order matters more than it looks: `files`, `edges` and every skip count\n // have to come out identical no matter how the reads interleave, or two scans\n // of one repo would disagree. So the window only prefetches — the loop below\n // consumes it one file at a time, in the order `allFiles` was sorted into.\n //\n // The language is resolved here and kept. The resolve phase needs the same\n // answer per file and used to ask `languageFor` for it a second time.\n const files: ScannedFile[] = [];\n const langOf = new Map<string, LanguageAnalyzer>();\n let parsed = 0;\n const codeFiles = [];\n for (const path of allFiles) {\n const lang = languageFor(path);\n if (!lang) {\n skips.notCode++;\n continue;\n }\n langOf.set(path, lang);\n codeFiles.push(path);\n }\n\n for await (const { path, text, failed } of readAhead(source, codeFiles, limits.readConcurrency, signal)) {\n throwIfAborted(signal);\n if (failed) {\n skips.readFailed++;\n continue;\n }\n const size = utf8ByteLength(text);\n if (size > limits.maxFileSize) {\n skips.tooLarge++;\n continue;\n }\n const lang = langOf.get(path);\n let analysis;\n try {\n analysis = lang.analyze(text, path);\n } catch {\n skips.analyzeFailed++;\n continue;\n }\n const cs = codeStats(text, lang.id);\n const findings = analyzeSecurityFile(text, lang.id);\n const docRatio = cs.code + cs.comment > 0 ? Math.round((cs.comment / (cs.code + cs.comment)) * 100) : 0;\n files.push({\n path,\n dir: dirOf(path),\n name: baseName(path),\n ext: extOf(path),\n lang: lang.id,\n size,\n loc: cs.code,\n comment: cs.comment,\n blank: cs.blank,\n lines: cs.lines,\n docRatio,\n complexity: complexityOf(text, lang.id),\n findings: findings.length ? findings : undefined,\n ...analysis,\n });\n parsed++;\n if (parsed % 25 === 0) onProgress({ phase: 'parse', done: parsed, total: codeFiles.length });\n }\n onProgress({ phase: 'parse', done: parsed, total: codeFiles.length });\n // ---- Resolve imports into edges -------------------------------------------\n const edges: ImportEdge[] = [];\n const edgeKeys = new Map(); // key -> edge\n const externals = new Map(); // package name -> Set of files\n\n // What share of the imports we found did we manage to place? A regex-based\n // analyzer owes its reader this number more than any other: it is the\n // engine's own estimate of how much of the graph is missing.\n const tally = { total: 0, internal: 0, external: 0, unresolved: 0 };\n const unresolvedSpecs = new Map(); // spec -> { count, from }\n\n // A resolver may answer with a *directory* instead of a file: Go's import is a\n // package, and a C# `using Acme.Models;` names a namespace whose classes we\n // cannot know from the import alone. Every file in that directory is a\n // target. Indexed once here rather than scanned per import — a Go repo with\n // 1,000 files and 8,000 imports was doing eight million comparisons for it.\n //\n // Language-neutral on purpose: this used to be `goFilesByDir`, built only from\n // Go files, which meant no other language could use the mechanism that already\n // existed for exactly this problem.\n const filesByDir = new Map();\n for (const f of files) {\n const bucket = filesByDir.get(f.dir);\n if (bucket) bucket.push(f.path);\n else filesByDir.set(f.dir, [f.path]);\n }\n\n let resolved = 0;\n for (const file of files) {\n throwIfAborted(signal);\n if (resolved++ % 25 === 0) onProgress({ phase: 'resolve', done: resolved, total: files.length });\n const lang = langOf.get(file.path);\n for (const imp of file.imports) {\n tally.total++;\n const res = lang.resolveImport(imp.spec, file.path, has, context, imp);\n if (res.path) {\n tally.internal++;\n addEdge(edges, edgeKeys, file.path, res.path, 'imports', imp.symbols);\n } else if (res.packageDir) {\n tally.internal++;\n // A directory import means \"everything in there\". addEdge de-duplicates,\n // so a package with fifty files yields fifty honest edges rather than\n // one edge standing in for all of them.\n for (const target of filesByDir.get(res.packageDir) || []) {\n addEdge(edges, edgeKeys, file.path, target, 'imports', imp.symbols);\n }\n } else if (res.external) {\n tally.external++;\n if (!externals.has(res.external)) externals.set(res.external, new Set());\n externals.get(res.external).add(file.path);\n } else {\n // Every resolver ends with `return { unresolved: spec }`. This branch\n // is where that used to disappear for want of an `else` — the import\n // was counted nowhere and the graph simply came up short in silence.\n tally.unresolved++;\n const spec = res.unresolved || imp.spec;\n const seen = unresolvedSpecs.get(spec);\n if (seen) seen.count++;\n else unresolvedSpecs.set(spec, { spec, count: 1, from: file.path });\n }\n }\n }\n\n // Resolved-or-correctly-external over everything we saw. An external package\n // counts as a success: the resolver knew what it was looking at.\n const confidence = tally.total\n ? Math.round(((tally.internal + tally.external) / tally.total) * 100)\n : 100;\n const worstUnresolved = [...unresolvedSpecs.values()]\n .sort((a, b) => b.count - a.count || a.spec.localeCompare(b.spec))\n .slice(0, 12);\n\n const externalList = [...externals.entries()]\n .map(([name, usedBySet]) => ({ name, usedBy: [...usedBySet].sort() }))\n .sort((a, b) => b.usedBy.length - a.usedBy.length || a.name.localeCompare(b.name));\n\n // Folder rollups with full size/LOC/documentation breakdown\n const filesPerDir = new Map();\n const folderData = new Map<string, ScannedFolder>();\n for (const p of allFiles) {\n const d = dirOf(p);\n filesPerDir.set(d, (filesPerDir.get(d) || 0) + 1);\n }\n for (const path of dirSet) {\n if (!path) continue;\n folderData.set(path, {\n path,\n name: baseName(path),\n depth: path.split('/').length,\n fileCount: filesPerDir.get(path) || 0,\n loc: 0,\n comment: 0,\n blank: 0,\n size: 0,\n langs: {},\n hasReadme: false,\n });\n }\n for (const p of allFiles) {\n const d = dirOf(p);\n const bn = baseName(p).toLowerCase();\n if (bn.startsWith('readme.') || bn === 'readme') {\n const entry = folderData.get(d);\n if (entry) entry.hasReadme = true;\n }\n }\n for (const f of files) {\n const entry = folderData.get(f.dir);\n if (entry) {\n entry.loc += f.loc || 0;\n entry.comment += f.comment || 0;\n entry.blank += f.blank || 0;\n entry.size += f.size || 0;\n entry.langs[f.lang] = (entry.langs[f.lang] || 0) + (f.loc || 0);\n }\n }\n const folders = [...folderData.values()]\n .map((f) => ({\n ...f,\n docRatio: f.loc + f.comment > 0 ? Math.round((f.comment / (f.loc + f.comment)) * 100) : 0,\n }))\n .sort((a, b) => a.path.localeCompare(b.path));\n\n const skippedTotal = Object.values(skips).reduce((a, b) => a + b, 0);\n\n const stats = {\n filesTotal: allFiles.length,\n filesParsed: parsed,\n skipped: skippedTotal,\n skips,\n truncated,\n edgeCount: edges.length,\n imports: {\n total: tally.total,\n internal: tally.internal,\n external: tally.external,\n unresolved: tally.unresolved,\n confidence,\n worst: worstUnresolved,\n },\n tookMs: Date.now() - startedAt,\n languages: countBy(files, (f) => f.lang),\n languageLoc: files.reduce<Record<string, number>>((acc, f) => {\n acc[f.lang] = (acc[f.lang] || 0) + (f.loc || 0);\n return acc;\n }, {}),\n };\n\n const [workflows, licenseReport] = await abortable(Promise.all([\n analyzeWorkflows(source).catch(() => []),\n detectManifest(source).then((manifest) => analyzeLicenses(source, manifest)).catch(() => null),\n ]), signal);\n throwIfAborted(signal);\n onProgress({ phase: 'complete', files: parsed, edges: edges.length });\n\n const result = {\n root: source.root || '(unknown)',\n name: source.name || baseName(source.root || '') || 'repo',\n scannedAt: new Date().toISOString(),\n stats,\n allFiles,\n files,\n edges,\n externals: externalList,\n folders,\n workflows: workflows || [],\n sbom: licenseReport?.sbom || [],\n license: licenseReport?.projectLicense || { id: 'UNKNOWN', name: 'Unknown' },\n licenseReport: licenseReport || undefined,\n };\n return result as typeof result & { tempId?: string; gitUrl?: string };\n}\n\nfunction addEdge(edges, edgeKeys, from, to, kind, symbols = []) {\n if (from === to) return;\n const key = from + '->' + to;\n const existing = edgeKeys.get(key);\n if (existing) {\n if (symbols && symbols.length) {\n existing.symbols = Array.from(new Set([...(existing.symbols || []), ...symbols]));\n }\n return;\n }\n const edge = { from, to, kind, symbols: symbols ? symbols.slice() : [] };\n edgeKeys.set(key, edge);\n edges.push(edge);\n}\n\n// How many reads may be in flight at once. Small on purpose: a file is read\n// whole before its size can be checked (a `FileSource` has no `stat`), so this\n// is also a multiplier on peak memory. Eight is enough to keep a disk or the\n// browser's file layer busy without holding a heap of large files at once.\nconst READ_AHEAD = 8;\n\n// Yields `{ path, text, failed }` for each path, in the order given, while\n// keeping up to READ_AHEAD reads in flight. Failures are yielded rather than\n// thrown so the caller can count them and keep going — one unreadable file\n// should not end a scan.\nasync function* readAhead(source: FileSource, paths: string[], width = READ_AHEAD, signal?: ScanOptions['signal']) {\n const read = (path) =>\n Promise.resolve()\n .then(() => { throwIfAborted(signal); return source.read(path); })\n .then((text) => ({ path, text, failed: false }), () => ({ path, text: '', failed: true }));\n\n const inFlight: Array<Promise<{ path: string; text: string; failed: boolean }>> = [];\n let next = 0;\n while (next < paths.length && inFlight.length < width) inFlight.push(read(paths[next++]));\n\n while (inFlight.length) {\n throwIfAborted(signal);\n // Refill only after this read settles: refilling before awaiting it made\n // the configured window run one extra read. The next read still starts\n // before this file is analyzed, while the total stays within the limit.\n const settled = await abortable(inFlight.shift(), signal);\n throwIfAborted(signal);\n if (next < paths.length) inFlight.push(read(paths[next++]));\n yield settled;\n }\n}\n\nfunction countBy<T>(items: T[], fn: (item: T) => string): Record<string, number> {\n const out: Record<string, number> = {};\n for (const item of items) {\n const k = fn(item);\n out[k] = (out[k] || 0) + 1;\n }\n return out;\n}\n\nasync function readModulePath(source) {\n try {\n const text = await source.read('go.mod');\n const m = text.match(/^module\\s+(\\S+)/m);\n return m ? m[1] : '';\n } catch {\n return '';\n }\n}\n\n// Simplified .gitignore: plain names, dir/, *.ext, /anchored. No negation —\n// documented limitation.\nasync function buildIgnoreMatcher(source) {\n let text = '';\n try {\n text = await source.read('.gitignore');\n } catch {\n return () => false;\n }\n const rules = [];\n for (let line of text.split('\\n')) {\n line = line.trim();\n if (!line || line.startsWith('#') || line.startsWith('!')) continue;\n const anchored = line.startsWith('/');\n const pattern = line.replace(/^\\//, '').replace(/\\/$/, '');\n if (!pattern) continue;\n const re = new RegExp(\n (anchored ? '^' : '(^|/)') +\n pattern.split(/(\\*\\*|\\*)/).map((part) =>\n part === '**' ? '.*' : part === '*' ? '[^/]*' : escapeRe(part)\n ).join('') +\n '($|/)'\n );\n rules.push({ re });\n }\n return (path) => rules.some((r) => r.re.test(path));\n}\n\nfunction escapeRe(s) {\n return s.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\nasync function readTsConfigPaths(source) {\n for (const name of ['tsconfig.json', 'jsconfig.json']) {\n try {\n const text = await source.read(name);\n const json = parseJsonConfig(text) as { compilerOptions?: { baseUrl?: string; paths?: Record<string, string[]>; rootDir?: string; outDir?: string } };\n const compilerOptions = json.compilerOptions || {};\n const baseUrl = compilerOptions.baseUrl ? compilerOptions.baseUrl.replace(/^\\.?\\//, '').replace(/\\/$/, '') : '';\n const paths = compilerOptions.paths || {};\n const sourceRoot = compilerOptions.rootDir?.replace(/^\\.?\\//, '').replace(/\\/$/, '');\n const outputRoot = compilerOptions.outDir?.replace(/^\\.?\\//, '').replace(/\\/$/, '').replace(/^\\.$/, '');\n if (Object.keys(paths).length || baseUrl || sourceRoot) {\n return { baseUrl, paths, sourceRoot, outputRoot };\n }\n } catch {}\n }\n return null;\n}\n"]}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { ScanLimits, ScanOptions, ScanSignal } from '../contracts.js';
|
|
2
|
+
export declare const DEFAULT_LIMITS: Readonly<ScanLimits>;
|
|
3
|
+
export declare function normalizeScanOptions(options?: ScanOptions): ScanLimits;
|
|
4
|
+
export declare class ScanAbortedError extends Error {
|
|
5
|
+
constructor();
|
|
6
|
+
}
|
|
7
|
+
export declare function throwIfAborted(signal?: ScanSignal): void;
|
|
8
|
+
/** Stops waiting promptly, while still observing the underlying I/O promise. */
|
|
9
|
+
export declare function abortable<T>(promise: Promise<T>, signal?: ScanSignal): Promise<T>;
|
|
10
|
+
/** Exact UTF-8 size, including replacement bytes for unpaired surrogates. */
|
|
11
|
+
export declare function utf8ByteLength(text: string): number;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
export const DEFAULT_LIMITS = Object.freeze({
|
|
2
|
+
maxFiles: 4000,
|
|
3
|
+
maxFileSize: 200 * 1024,
|
|
4
|
+
readConcurrency: 8,
|
|
5
|
+
});
|
|
6
|
+
export function normalizeScanOptions(options = {}) {
|
|
7
|
+
const whole = (key, maximum) => {
|
|
8
|
+
const value = options[key] ?? DEFAULT_LIMITS[key];
|
|
9
|
+
if (!Number.isInteger(value) || value < 1 || value > maximum) {
|
|
10
|
+
throw new RangeError(`${key} must be a whole number from 1 to ${maximum}.`);
|
|
11
|
+
}
|
|
12
|
+
return value;
|
|
13
|
+
};
|
|
14
|
+
return {
|
|
15
|
+
maxFiles: whole('maxFiles', 100_000),
|
|
16
|
+
maxFileSize: whole('maxFileSize', 10 * 1024 * 1024),
|
|
17
|
+
readConcurrency: whole('readConcurrency', 32),
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
export class ScanAbortedError extends Error {
|
|
21
|
+
constructor() {
|
|
22
|
+
super('The scan was cancelled.');
|
|
23
|
+
this.name = 'AbortError';
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
export function throwIfAborted(signal) {
|
|
27
|
+
if (signal?.aborted)
|
|
28
|
+
throw new ScanAbortedError();
|
|
29
|
+
}
|
|
30
|
+
/** Stops waiting promptly, while still observing the underlying I/O promise. */
|
|
31
|
+
export function abortable(promise, signal) {
|
|
32
|
+
if (!signal)
|
|
33
|
+
return promise;
|
|
34
|
+
return new Promise((resolve, reject) => {
|
|
35
|
+
const aborted = () => { cleanup(); reject(new ScanAbortedError()); };
|
|
36
|
+
const cleanup = () => signal.removeEventListener('abort', aborted);
|
|
37
|
+
signal.addEventListener('abort', aborted, { once: true });
|
|
38
|
+
promise.then((value) => { cleanup(); resolve(value); }, (error) => { cleanup(); reject(error); });
|
|
39
|
+
if (signal.aborted)
|
|
40
|
+
aborted();
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
/** Exact UTF-8 size, including replacement bytes for unpaired surrogates. */
|
|
44
|
+
export function utf8ByteLength(text) {
|
|
45
|
+
let bytes = 0;
|
|
46
|
+
for (let i = 0; i < text.length; i++) {
|
|
47
|
+
const unit = text.charCodeAt(i);
|
|
48
|
+
if (unit < 0x80)
|
|
49
|
+
bytes += 1;
|
|
50
|
+
else if (unit < 0x800)
|
|
51
|
+
bytes += 2;
|
|
52
|
+
else if (unit >= 0xd800 && unit <= 0xdbff && i + 1 < text.length &&
|
|
53
|
+
text.charCodeAt(i + 1) >= 0xdc00 && text.charCodeAt(i + 1) <= 0xdfff) {
|
|
54
|
+
bytes += 4;
|
|
55
|
+
i++;
|
|
56
|
+
}
|
|
57
|
+
else
|
|
58
|
+
bytes += 3;
|
|
59
|
+
}
|
|
60
|
+
return bytes;
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=scanControl.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scanControl.js","sourceRoot":"","sources":["../../src/shared/analyzer/scanControl.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ScanLimits, ScanOptions, ScanSignal } from '../contracts.js';\n\nexport const DEFAULT_LIMITS: Readonly<ScanLimits> = Object.freeze({\n maxFiles: 4000,\n maxFileSize: 200 * 1024,\n readConcurrency: 8,\n});\n\nexport function normalizeScanOptions(options: ScanOptions = {}): ScanLimits {\n const whole = (key: keyof ScanLimits, maximum: number): number => {\n const value = options[key] ?? DEFAULT_LIMITS[key];\n if (!Number.isInteger(value) || value < 1 || value > maximum) {\n throw new RangeError(`${key} must be a whole number from 1 to ${maximum}.`);\n }\n return value;\n };\n return {\n maxFiles: whole('maxFiles', 100_000),\n maxFileSize: whole('maxFileSize', 10 * 1024 * 1024),\n readConcurrency: whole('readConcurrency', 32),\n };\n}\n\nexport class ScanAbortedError extends Error {\n constructor() {\n super('The scan was cancelled.');\n this.name = 'AbortError';\n }\n}\n\nexport function throwIfAborted(signal?: ScanSignal): void {\n if (signal?.aborted) throw new ScanAbortedError();\n}\n\n/** Stops waiting promptly, while still observing the underlying I/O promise. */\nexport function abortable<T>(promise: Promise<T>, signal?: ScanSignal): Promise<T> {\n if (!signal) return promise;\n return new Promise<T>((resolve, reject) => {\n const aborted = (): void => { cleanup(); reject(new ScanAbortedError()); };\n const cleanup = (): void => signal.removeEventListener('abort', aborted);\n signal.addEventListener('abort', aborted, { once: true });\n promise.then(\n (value) => { cleanup(); resolve(value); },\n (error: unknown) => { cleanup(); reject(error); },\n );\n if (signal.aborted) aborted();\n });\n}\n\n/** Exact UTF-8 size, including replacement bytes for unpaired surrogates. */\nexport function utf8ByteLength(text: string): number {\n let bytes = 0;\n for (let i = 0; i < text.length; i++) {\n const unit = text.charCodeAt(i);\n if (unit < 0x80) bytes += 1;\n else if (unit < 0x800) bytes += 2;\n else if (unit >= 0xd800 && unit <= 0xdbff && i + 1 < text.length &&\n text.charCodeAt(i + 1) >= 0xdc00 && text.charCodeAt(i + 1) <= 0xdfff) {\n bytes += 4;\n i++;\n } else bytes += 3;\n }\n return bytes;\n}\n"]}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export declare const SEVERITIES: string[];
|
|
2
|
+
export declare const sevRank: (s: any) => number;
|
|
3
|
+
export declare function analyzeSecurityFile(source: any, lang: any): any[];
|
|
4
|
+
export declare function summarizeSecurity(scan: any): {
|
|
5
|
+
counts: {
|
|
6
|
+
critical: number;
|
|
7
|
+
high: number;
|
|
8
|
+
medium: number;
|
|
9
|
+
low: number;
|
|
10
|
+
info: number;
|
|
11
|
+
};
|
|
12
|
+
byCat: Record<string, any>;
|
|
13
|
+
files: any[];
|
|
14
|
+
score: number;
|
|
15
|
+
grade: string;
|
|
16
|
+
total: any;
|
|
17
|
+
};
|
|
18
|
+
export declare function mergeFindingsIntoScan(scan: any, external: any): number;
|
|
@@ -2,186 +2,186 @@
|
|
|
2
2
|
// runs entirely locally, no external binary. Rules are regex/line based,
|
|
3
3
|
// language-scoped, each with a severity and a category. Per-file findings are
|
|
4
4
|
// attached during the scan; summarizeSecurity rolls them into a repo grade.
|
|
5
|
-
|
|
6
5
|
import { lineCounter } from './util.js';
|
|
7
|
-
|
|
8
6
|
export const SEVERITIES = ['info', 'low', 'medium', 'high', 'critical'];
|
|
9
7
|
export const sevRank = (s) => SEVERITIES.indexOf(s);
|
|
10
|
-
|
|
11
8
|
// Each rule: id, severity, category, message, rx. `byLine` rules test each
|
|
12
9
|
// line (and report the line number); others test the whole source once.
|
|
13
10
|
const RULES = [
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
11
|
+
{ id: 'hardcoded-secret', severity: 'critical', category: 'secret',
|
|
12
|
+
message: 'Hardcoded credential — move it to env/config.',
|
|
13
|
+
rx: /\b(api[_-]?key|apikey|secret|client[_-]?secret|password|passwd|access[_-]?token|auth[_-]?token|private[_-]?key)\b\s*[:=]\s*['"`][^'"`\s]{8,}['"`]/i, byLine: true },
|
|
14
|
+
{ id: 'aws-key', severity: 'critical', category: 'secret',
|
|
15
|
+
message: 'Looks like an AWS access key id.',
|
|
16
|
+
rx: /\b(AKIA|ASIA)[0-9A-Z]{16}\b/, byLine: true },
|
|
17
|
+
{ id: 'private-key-block', severity: 'critical', category: 'secret',
|
|
18
|
+
message: 'A private key is committed to the source.',
|
|
19
|
+
rx: /-----BEGIN (RSA|EC|DSA|OPENSSH|PGP) PRIVATE KEY-----/ },
|
|
20
|
+
{ id: 'eval', severity: 'high', category: 'injection', langs: ['javascript'],
|
|
21
|
+
message: 'eval() executes strings as code — classic injection sink.',
|
|
22
|
+
rx: /\beval\s*\(/, byLine: true },
|
|
23
|
+
{ id: 'new-function', severity: 'high', category: 'injection', langs: ['javascript'],
|
|
24
|
+
message: 'new Function() is eval in a trench coat.',
|
|
25
|
+
rx: /\bnew Function\s*\(/, byLine: true },
|
|
26
|
+
{ id: 'child-exec', severity: 'high', category: 'injection', langs: ['javascript'],
|
|
27
|
+
message: 'Shelling out — if any argument is user input, this is command injection.',
|
|
28
|
+
rx: /\b(child_process\.(exec|spawn)|execSync|spawnSync)\s*\(/, byLine: true },
|
|
29
|
+
{ id: 'os-system', severity: 'high', category: 'injection', langs: ['python'],
|
|
30
|
+
message: 'os.system / shell=True runs a shell — sanitize any input reaching it.',
|
|
31
|
+
rx: /\bos\.system\s*\(|shell\s*=\s*True/, byLine: true },
|
|
32
|
+
{ id: 'sql-concat', severity: 'high', category: 'injection',
|
|
33
|
+
message: 'SQL built by string concatenation/formatting — use parameterized queries.',
|
|
34
|
+
rx: /\b(execute|query|exec|raw)\s*\(\s*[^)]*(\+|\$\{|\.format\(|f["'])/, byLine: true },
|
|
35
|
+
{ id: 'innerhtml', severity: 'medium', category: 'xss', langs: ['javascript'],
|
|
36
|
+
message: 'Writing raw HTML — if the value is user-controlled, this is XSS.',
|
|
37
|
+
rx: /\b(innerHTML|outerHTML)\s*=|dangerouslySetInnerHTML|document\.write\s*\(/, byLine: true,
|
|
38
|
+
ignore: /\b(innerHTML|outerHTML)\s*=\s*(['"`])\2\s*;?\s*$/ },
|
|
39
|
+
{ id: 'weak-hash', severity: 'medium', category: 'crypto',
|
|
40
|
+
message: 'MD5/SHA-1 are broken — use SHA-256+, and bcrypt/argon2 for passwords.',
|
|
41
|
+
rx: /\b(md5|sha1)\s*\(|createHash\(\s*['"](md5|sha1)['"]/, byLine: true },
|
|
42
|
+
{ id: 'math-random', severity: 'low', category: 'crypto', langs: ['javascript'],
|
|
43
|
+
message: 'Math.random() is not cryptographically secure.',
|
|
44
|
+
rx: /\bMath\.random\s*\(/, byLine: true },
|
|
45
|
+
{ id: 'insecure-deser', severity: 'high', category: 'deserialization',
|
|
46
|
+
message: 'Insecure deserialization — untrusted data here is remote code execution.',
|
|
47
|
+
rx: /\b(pickle\.loads?|yaml\.load\s*\((?![^)]*SafeLoader)|unserialize\s*\(|ObjectInputStream)/, byLine: true },
|
|
48
|
+
{ id: 'open-redirect', severity: 'medium', category: 'redirect',
|
|
49
|
+
message: 'Redirect target comes from the request — open-redirect risk.',
|
|
50
|
+
rx: /\b(res\.redirect|redirect)\s*\(\s*(req\.|request\.)/, byLine: true },
|
|
51
|
+
{ id: 'localhost-url', severity: 'low', category: 'config',
|
|
52
|
+
message: 'Hardcoded localhost/127.0.0.1 — will break outside this machine.',
|
|
53
|
+
rx: /['"`](https?:\/\/(localhost|127\.0\.0\.1)|localhost:\d|127\.0\.0\.1)/, byLine: true },
|
|
54
|
+
{ id: 'debugger', severity: 'low', category: 'debug', langs: ['javascript'],
|
|
55
|
+
message: 'A debugger statement is left in.',
|
|
56
|
+
rx: /\bdebugger\s*;?/, byLine: true },
|
|
57
|
+
{ id: 'console-log', severity: 'info', category: 'debug', langs: ['javascript'],
|
|
58
|
+
message: 'console.log — fine locally, noise in production.',
|
|
59
|
+
rx: /\bconsole\.(log|debug|info)\s*\(/, byLine: true },
|
|
60
|
+
{ id: 'print-stmt', severity: 'info', category: 'debug', langs: ['python'],
|
|
61
|
+
message: 'print() — use the logger in production code.',
|
|
62
|
+
rx: /^\s*print\s*\(/, byLine: true },
|
|
63
|
+
{ id: 'todo', severity: 'info', category: 'quality',
|
|
64
|
+
message: 'TODO/FIXME left in the source.',
|
|
65
|
+
rx: /\b(TODO|FIXME|XXX|HACK)\b/, byLine: true },
|
|
66
|
+
{ id: 'loose-eq', severity: 'low', category: 'quality', langs: ['javascript'],
|
|
67
|
+
message: 'Loose equality (==) coerces types — prefer ===.',
|
|
68
|
+
rx: /[^=!<>]==[^=]/, byLine: true },
|
|
69
|
+
{ id: 'var-keyword', severity: 'low', category: 'quality', langs: ['javascript'],
|
|
70
|
+
message: 'var is function-scoped and hoisted — prefer let/const.',
|
|
71
|
+
rx: /\bvar\s+[A-Za-z_$]/, byLine: true },
|
|
72
|
+
{ id: 'empty-catch', severity: 'medium', category: 'quality',
|
|
73
|
+
message: 'Swallowed exception — errors vanish silently here.',
|
|
74
|
+
rx: /(catch\s*\([^)]*\)\s*\{\s*\}|except\s*\w*\s*:\s*pass\b)/, byLine: true },
|
|
75
|
+
// JSON Web Tokens start with a base64-encoded header that is always
|
|
76
|
+
// `eyJ…` ("{"). A line that contains one and treats it as a literal
|
|
77
|
+
// string — rather than reading it from a vault — is the same shape of
|
|
78
|
+
// mistake as a hardcoded API key. Three base64 segments separated by
|
|
79
|
+
// dots is the JWT signature; we only require the first segment to keep
|
|
80
|
+
// the rule cheap.
|
|
81
|
+
{ id: 'jwt-secret', severity: 'critical', category: 'secret',
|
|
82
|
+
message: 'Looks like a hardcoded JWT — treat it like a credential, not a string.',
|
|
83
|
+
rx: /['"`](eyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,})['"`]/, byLine: true },
|
|
84
|
+
// The `os-system` rule already catches `os.system` and `shell=True` on
|
|
85
|
+
// subprocess calls, but `subprocess.Popen(..., shell=True)` and
|
|
86
|
+
// `subprocess.run(..., shell=True)` are the modern Python way to do
|
|
87
|
+
// the same thing, and a regex on `shell=True` alone matches both
|
|
88
|
+
// without the false-positive rate. A separate rule for Popen keeps the
|
|
89
|
+
// message specific and the langs filter honest.
|
|
90
|
+
{ id: 'subprocess-shell', severity: 'high', category: 'injection', langs: ['python'],
|
|
91
|
+
message: 'subprocess.* with shell=True runs a shell — sanitize any input reaching it.',
|
|
92
|
+
rx: /\bsubprocess\.(Popen|run|call|check_output|check_call)\s*\([^)]*shell\s*=\s*True/, byLine: true },
|
|
93
|
+
// Go's `http.ListenAndServe` defaults to binding all interfaces when
|
|
94
|
+
// given a `":port"` address (the colon makes it a wildcard), and a
|
|
95
|
+
// literal `0.0.0.0` does the same. That is fine inside a container with
|
|
96
|
+
// a tight network policy and a bug everywhere else: the dev box, the
|
|
97
|
+
// staging cluster, the CI runner, the laptop on coffee-shop Wi-Fi. The
|
|
98
|
+
// rule does not distinguish "0.0.0.0" from "127.0.0.1" because the
|
|
99
|
+
// safer pattern is always `127.0.0.1:<port>`, so the finding is a
|
|
100
|
+
// nudge rather than an alarm.
|
|
101
|
+
{ id: 'go-public-listen', severity: 'medium', category: 'config', langs: ['go'],
|
|
102
|
+
message: 'Go listener binds all interfaces (":port" or "0.0.0.0") — bind 127.0.0.1 explicitly.',
|
|
103
|
+
rx: /(ListenAndServe|Listen|TLS\s*\.\s*Listen|ListenAndServeTLS)\s*\(\s*["'](:[0-9]+|0\.0\.0\.0(?::[0-9]+)?|::)["']/, byLine: true },
|
|
107
104
|
];
|
|
108
|
-
|
|
109
105
|
// Findings for one file, run at scan time while the source is in hand.
|
|
110
106
|
export function analyzeSecurityFile(source, lang) {
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
107
|
+
const findings = [];
|
|
108
|
+
const text = String(source);
|
|
109
|
+
const lines = text.split('\n');
|
|
110
|
+
// Whole-file rules report a byte offset and need it as a line number. Built
|
|
111
|
+
// once and lazily: most files trip none of these rules and never build it.
|
|
112
|
+
const lineAt = lineCounter(text);
|
|
113
|
+
for (const rule of RULES) {
|
|
114
|
+
if (rule.langs && !rule.langs.includes(lang))
|
|
115
|
+
continue;
|
|
116
|
+
if (rule.byLine) {
|
|
117
|
+
for (let i = 0; i < lines.length; i++) {
|
|
118
|
+
if (rule.ignore && rule.ignore.test(lines[i]))
|
|
119
|
+
continue;
|
|
120
|
+
const m = lines[i].match(rule.rx);
|
|
121
|
+
if (m) {
|
|
122
|
+
findings.push({ rule: rule.id, severity: rule.severity, category: rule.category, message: rule.message, line: i + 1, excerpt: lines[i].trim().slice(0, 90) });
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
const m = text.match(rule.rx);
|
|
128
|
+
if (m) {
|
|
129
|
+
findings.push({ rule: rule.id, severity: rule.severity, category: rule.category, message: rule.message, line: lineAt(m.index), excerpt: (m[0] || '').slice(0, 90) });
|
|
130
|
+
}
|
|
125
131
|
}
|
|
126
|
-
}
|
|
127
|
-
} else {
|
|
128
|
-
const m = text.match(rule.rx);
|
|
129
|
-
if (m) {
|
|
130
|
-
findings.push({ rule: rule.id, severity: rule.severity, category: rule.category, message: rule.message, line: lineAt(m.index), excerpt: (m[0] || '').slice(0, 90) });
|
|
131
|
-
}
|
|
132
132
|
}
|
|
133
|
-
|
|
134
|
-
return findings;
|
|
133
|
+
return findings;
|
|
135
134
|
}
|
|
136
|
-
|
|
137
135
|
// Repo-level roll-up: counts by severity and category, the files carrying
|
|
138
136
|
// findings (worst-first), and a 0–100 score + grade.
|
|
139
137
|
export function summarizeSecurity(scan) {
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
138
|
+
const counts = { critical: 0, high: 0, medium: 0, low: 0, info: 0 };
|
|
139
|
+
const byCat = {};
|
|
140
|
+
const files = [];
|
|
141
|
+
for (const f of scan.files) {
|
|
142
|
+
const finds = f.findings || [];
|
|
143
|
+
if (!finds.length)
|
|
144
|
+
continue;
|
|
145
|
+
let worst = 'info';
|
|
146
|
+
for (const x of finds) {
|
|
147
|
+
counts[x.severity]++;
|
|
148
|
+
byCat[x.category] = (byCat[x.category] || 0) + 1;
|
|
149
|
+
if (sevRank(x.severity) > sevRank(worst))
|
|
150
|
+
worst = x.severity;
|
|
151
|
+
}
|
|
152
|
+
files.push({ path: f.path, name: f.name, findings: finds, worst, count: finds.length });
|
|
151
153
|
}
|
|
152
|
-
files.
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
score = Math.max(0, Math.round(score));
|
|
162
|
-
const grade = score >= 90 ? 'A' : score >= 75 ? 'B' : score >= 60 ? 'C' : score >= 45 ? 'D' : 'F';
|
|
163
|
-
|
|
164
|
-
return { counts, byCat, files, score, grade, total: files.reduce((s, f) => s + f.count, 0) };
|
|
154
|
+
files.sort((a, b) => sevRank(b.worst) - sevRank(a.worst) || b.count - a.count);
|
|
155
|
+
let score = 100;
|
|
156
|
+
score -= counts.critical * 15;
|
|
157
|
+
score -= counts.high * 6;
|
|
158
|
+
score -= counts.medium * 2;
|
|
159
|
+
score -= Math.min(10, counts.low);
|
|
160
|
+
score = Math.max(0, Math.round(score));
|
|
161
|
+
const grade = score >= 90 ? 'A' : score >= 75 ? 'B' : score >= 60 ? 'C' : score >= 45 ? 'D' : 'F';
|
|
162
|
+
return { counts, byCat, files, score, grade, total: files.reduce((s, f) => s + f.count, 0) };
|
|
165
163
|
}
|
|
166
|
-
|
|
167
164
|
// Fold an external engine's findings into the scan, in place, so the security
|
|
168
165
|
// view — which reads `scan.files[].findings` and re-summarizes — sees one list.
|
|
169
166
|
// Dedup is on (path, line, rule): two engines flagging the same line for the
|
|
170
167
|
// same reason are one problem. This is the shared, pure half of the merge; the
|
|
171
168
|
// fetching and spawning live on the server.
|
|
172
169
|
export function mergeFindingsIntoScan(scan, external) {
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
const
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
170
|
+
if (!scan || !Array.isArray(external) || !external.length)
|
|
171
|
+
return 0;
|
|
172
|
+
const byPath = new Map(scan.files.map((f) => [f.path, f]));
|
|
173
|
+
let added = 0;
|
|
174
|
+
for (const finding of external) {
|
|
175
|
+
const file = byPath.get(finding.path);
|
|
176
|
+
if (!file)
|
|
177
|
+
continue; // a path the scanner never accepted is not ours to show
|
|
178
|
+
const list = file.findings || (file.findings = []);
|
|
179
|
+
const dupe = list.some((x) => x.line === finding.line && x.rule === finding.rule);
|
|
180
|
+
if (dupe)
|
|
181
|
+
continue;
|
|
182
|
+
list.push(finding);
|
|
183
|
+
added++;
|
|
184
|
+
}
|
|
185
|
+
return added;
|
|
186
186
|
}
|
|
187
|
-
|
|
187
|
+
//# sourceMappingURL=security.js.map
|