codebase-onboarder 0.5.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 +196 -47
- 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 +449 -0
- package/cli/explorer/advanced.js.map +1 -0
- package/cli/explorer/app.d.ts +1 -0
- package/cli/explorer/app.js +396 -229
- 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 +400 -162
- 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 +73 -0
- package/cli/explorer/github.js.map +1 -0
- package/cli/explorer/graphs.d.ts +7 -0
- package/cli/explorer/graphs.js +173 -0
- 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 +184 -95
- package/cli/explorer/session.js.map +1 -0
- package/cli/explorer/views.d.ts +19 -0
- package/cli/explorer/views.js +496 -412
- package/cli/explorer/views.js.map +1 -0
- package/cli/explorer/wrap.d.ts +1 -0
- package/cli/explorer/wrap.js +33 -0
- package/cli/explorer/wrap.js.map +1 -0
- package/cli/main.d.ts +1 -0
- package/cli/main.js +235 -138
- 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 +55 -35
- 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 +165 -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 +60 -0
- 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 -37
- 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 +79 -0
- 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
package/server/tools/parse.js
CHANGED
|
@@ -12,159 +12,157 @@
|
|
|
12
12
|
// `severity` is one of the built-in five. `source` is 'builtin' or 'external'
|
|
13
13
|
// and `tool` names which engine answered, so the UI can say "found by Semgrep"
|
|
14
14
|
// rather than letting a finding appear from nowhere.
|
|
15
|
-
|
|
16
15
|
export const SEVERITY_ORDER = ['info', 'low', 'medium', 'high', 'critical'];
|
|
17
|
-
|
|
18
16
|
export function normalizeSeverity(raw) {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
17
|
+
const s = String(raw || '').toLowerCase();
|
|
18
|
+
if (s === 'critical' || s === 'error')
|
|
19
|
+
return s === 'error' ? 'high' : 'critical';
|
|
20
|
+
if (s === 'high')
|
|
21
|
+
return 'high';
|
|
22
|
+
if (s === 'medium' || s === 'warning' || s === 'warn' || s === 'moderate')
|
|
23
|
+
return 'medium';
|
|
24
|
+
if (s === 'low' || s === 'note')
|
|
25
|
+
return 'low';
|
|
26
|
+
return 'info';
|
|
25
27
|
}
|
|
26
|
-
|
|
27
28
|
function clipExcerpt(text) {
|
|
28
|
-
|
|
29
|
+
return String(text ?? '').replace(/\s+/g, ' ').trim().slice(0, 90);
|
|
29
30
|
}
|
|
30
|
-
|
|
31
31
|
// ---- Semgrep / Opengrep ----------------------------------------------------
|
|
32
32
|
// `semgrep --json` → { results: [ { check_id, path, start:{line}, extra:
|
|
33
33
|
// { severity, message, lines, metadata:{category} } } ] }. Opengrep is the same
|
|
34
34
|
// JSON. `rel` strips the scan root so paths match the repo-relative form the
|
|
35
35
|
// rest of the app uses.
|
|
36
36
|
export function parseSemgrep(json, rel) {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
37
|
+
const results = Array.isArray(json && json.results) ? json.results : [];
|
|
38
|
+
const findings = [];
|
|
39
|
+
for (const r of results) {
|
|
40
|
+
const extra = r.extra || {};
|
|
41
|
+
findings.push({
|
|
42
|
+
rule: String(r.check_id || 'semgrep-rule'),
|
|
43
|
+
severity: normalizeSeverity(extra.severity),
|
|
44
|
+
category: (extra.metadata && extra.metadata.category) || 'security',
|
|
45
|
+
message: clipExcerpt(extra.message || r.check_id),
|
|
46
|
+
path: rel(r.path),
|
|
47
|
+
line: r.start && r.start.line ? r.start.line : 1,
|
|
48
|
+
excerpt: clipExcerpt(extra.lines),
|
|
49
|
+
source: 'external',
|
|
50
|
+
tool: 'semgrep',
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
return findings;
|
|
54
54
|
}
|
|
55
|
-
|
|
56
55
|
// ---- Gitleaks ---------------------------------------------------------------
|
|
57
56
|
// `gitleaks --report-format json` → an array of secrets: [ { RuleID,
|
|
58
57
|
// Description, File, StartLine, Match, Secret } ]. The finding reports *that* a
|
|
59
58
|
// secret exists, never the secret — `Secret` is read for nothing.
|
|
60
59
|
export function parseGitleaks(json, rel) {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
60
|
+
const list = Array.isArray(json) ? json : [];
|
|
61
|
+
const findings = [];
|
|
62
|
+
for (const r of list) {
|
|
63
|
+
findings.push({
|
|
64
|
+
rule: 'secret:' + (r.RuleID || 'unknown'),
|
|
65
|
+
severity: 'critical',
|
|
66
|
+
category: 'secret',
|
|
67
|
+
message: clipExcerpt(r.Description || 'A secret is committed to the source.'),
|
|
68
|
+
path: rel(r.File),
|
|
69
|
+
line: r.StartLine || 1,
|
|
70
|
+
excerpt: 'committed credential (value redacted)',
|
|
71
|
+
source: 'external',
|
|
72
|
+
tool: 'gitleaks',
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
return findings;
|
|
77
76
|
}
|
|
78
|
-
|
|
79
77
|
// ---- Knip -------------------------------------------------------------------
|
|
80
78
|
// `knip --reporter json` groups dead code by kind: { files:[], dependencies:[],
|
|
81
79
|
// unused:[{name,file,line}], ... }. Each becomes a finding so the dead-code
|
|
82
80
|
// pass can be read in one list; the kind is the rule.
|
|
83
81
|
export function parseKnip(json, rel) {
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
return findings;
|
|
82
|
+
const findings = [];
|
|
83
|
+
const push = (rule, category, severity, path, line, message) => {
|
|
84
|
+
findings.push({ rule, category, severity, message, path: rel(path), line: line || 1, excerpt: '', source: 'external', tool: 'knip' });
|
|
85
|
+
};
|
|
86
|
+
for (const file of (json && json.files) || []) {
|
|
87
|
+
push('knip:unused-file', 'dead-file', 'medium', file, 1, 'This file is never imported anywhere.');
|
|
88
|
+
}
|
|
89
|
+
for (const dep of (json && json.dependencies) || []) {
|
|
90
|
+
push('knip:unused-dependency', 'dead-dependency', 'low', dep, 1, `Dependency "${dep}" is declared but never imported.`);
|
|
91
|
+
}
|
|
92
|
+
for (const u of (json && json.unused) || []) {
|
|
93
|
+
push('knip:unused-export', 'dead-export', 'low', u.file, u.line, `Export "${u.name}" is never used.`);
|
|
94
|
+
}
|
|
95
|
+
for (const u of (json && json.unresolved) || []) {
|
|
96
|
+
push('knip:unresolved', 'dead-import', 'medium', u.file, u.line, `Import "${u.name}" does not resolve to anything.`);
|
|
97
|
+
}
|
|
98
|
+
return findings;
|
|
102
99
|
}
|
|
103
|
-
|
|
104
100
|
// ---- Vulture ----------------------------------------------------------------
|
|
105
101
|
// `vulture` prints lines like `src/util.py:42: unused function 'helper' (60%
|
|
106
102
|
// confidence)`. There is no stable JSON, so we parse the text — which is why the
|
|
107
103
|
// parser is a pure function over a string, and why the line shape is pinned by
|
|
108
104
|
// a test rather than by reading the binary's source.
|
|
109
105
|
const VULTURE_RE = /^(.+?):(\d+):\s+(.+?)\s+\((\d+)% confidence\)/;
|
|
110
|
-
|
|
111
106
|
export function parseVulture(text, rel) {
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
107
|
+
const findings = [];
|
|
108
|
+
for (const line of String(text || '').split('\n')) {
|
|
109
|
+
const m = line.match(VULTURE_RE);
|
|
110
|
+
if (!m)
|
|
111
|
+
continue;
|
|
112
|
+
const confidence = Number(m[4]);
|
|
113
|
+
if (confidence < 60)
|
|
114
|
+
continue; // below vulture's own floor, it is guessing
|
|
115
|
+
findings.push({
|
|
116
|
+
rule: 'vulture:' + (m[3].split(' ')[0] || 'unused'),
|
|
117
|
+
severity: confidence >= 90 ? 'medium' : 'low',
|
|
118
|
+
category: 'dead-code',
|
|
119
|
+
message: clipExcerpt(m[3]) + ` (${confidence}% confident)`,
|
|
120
|
+
path: rel(m[1]),
|
|
121
|
+
line: Number(m[2]) || 1,
|
|
122
|
+
excerpt: '',
|
|
123
|
+
source: 'external',
|
|
124
|
+
tool: 'vulture',
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
return findings;
|
|
131
128
|
}
|
|
132
|
-
|
|
133
129
|
// ---- Depcheck ---------------------------------------------------------------
|
|
134
130
|
// `depcheck --json` → { dependencies:[], devDependencies:[], missing:{} }.
|
|
135
131
|
export function parseDepcheck(json) {
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
132
|
+
const findings = [];
|
|
133
|
+
const push = (name, dev) => findings.push({
|
|
134
|
+
rule: 'depcheck:unused',
|
|
135
|
+
severity: 'low',
|
|
136
|
+
category: 'dead-dependency',
|
|
137
|
+
message: `Package "${name}" is declared in package.json but never imported.`,
|
|
138
|
+
path: 'package.json',
|
|
139
|
+
line: 1,
|
|
140
|
+
excerpt: '',
|
|
141
|
+
source: 'external',
|
|
142
|
+
tool: 'depcheck',
|
|
143
|
+
dev,
|
|
144
|
+
});
|
|
145
|
+
for (const name of (json && json.dependencies) || [])
|
|
146
|
+
push(name, false);
|
|
147
|
+
for (const name of (json && json.devDependencies) || [])
|
|
148
|
+
push(name, true);
|
|
149
|
+
return findings;
|
|
152
150
|
}
|
|
153
|
-
|
|
154
151
|
// Merge the external passes into one list, keeping the built-in scan's findings
|
|
155
152
|
// untouched. Dedup on (path, line, rule): two engines that flag the same line
|
|
156
153
|
// for the same reason are one problem, not two.
|
|
157
154
|
export function mergeFindings(...lists) {
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
155
|
+
const seen = new Set();
|
|
156
|
+
const out = [];
|
|
157
|
+
for (const list of lists) {
|
|
158
|
+
for (const f of list || []) {
|
|
159
|
+
const key = `${f.path}:${f.line}:${f.rule}`;
|
|
160
|
+
if (seen.has(key))
|
|
161
|
+
continue;
|
|
162
|
+
seen.add(key);
|
|
163
|
+
out.push(f);
|
|
164
|
+
}
|
|
166
165
|
}
|
|
167
|
-
|
|
168
|
-
return out;
|
|
166
|
+
return out;
|
|
169
167
|
}
|
|
170
|
-
|
|
168
|
+
//# sourceMappingURL=parse.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse.js","sourceRoot":"","sources":["../../src/server/tools/parse.ts"],"names":[],"mappings":"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","sourcesContent":["// Parsing the dialects. Every analyzer speaks its own JSON (or SARIF); the UI\n// speaks one. This file is the translation layer, and it is pure — it takes a\n// string a tool printed and returns findings, so it can be tested in Node with\n// fixtures and needs no process, no filesystem, no PATH.\n//\n// The single target shape is the one the built-in scanner already emits\n// (`shared/analyzer/security.js`), so the existing security view needs no new\n// kind of row:\n//\n// { rule, severity, category, message, line, excerpt, source, tool }\n//\n// `severity` is one of the built-in five. `source` is 'builtin' or 'external'\n// and `tool` names which engine answered, so the UI can say \"found by Semgrep\"\n// rather than letting a finding appear from nowhere.\n\nexport const SEVERITY_ORDER = ['info', 'low', 'medium', 'high', 'critical'];\n\nexport function normalizeSeverity(raw) {\n const s = String(raw || '').toLowerCase();\n if (s === 'critical' || s === 'error') return s === 'error' ? 'high' : 'critical';\n if (s === 'high') return 'high';\n if (s === 'medium' || s === 'warning' || s === 'warn' || s === 'moderate') return 'medium';\n if (s === 'low' || s === 'note') return 'low';\n return 'info';\n}\n\nfunction clipExcerpt(text) {\n return String(text ?? '').replace(/\\s+/g, ' ').trim().slice(0, 90);\n}\n\n// ---- Semgrep / Opengrep ----------------------------------------------------\n// `semgrep --json` → { results: [ { check_id, path, start:{line}, extra:\n// { severity, message, lines, metadata:{category} } } ] }. Opengrep is the same\n// JSON. `rel` strips the scan root so paths match the repo-relative form the\n// rest of the app uses.\nexport function parseSemgrep(json, rel) {\n const results = Array.isArray(json && json.results) ? json.results : [];\n const findings = [];\n for (const r of results) {\n const extra = r.extra || {};\n findings.push({\n rule: String(r.check_id || 'semgrep-rule'),\n severity: normalizeSeverity(extra.severity),\n category: (extra.metadata && extra.metadata.category) || 'security',\n message: clipExcerpt(extra.message || r.check_id),\n path: rel(r.path),\n line: r.start && r.start.line ? r.start.line : 1,\n excerpt: clipExcerpt(extra.lines),\n source: 'external',\n tool: 'semgrep',\n });\n }\n return findings;\n}\n\n// ---- Gitleaks ---------------------------------------------------------------\n// `gitleaks --report-format json` → an array of secrets: [ { RuleID,\n// Description, File, StartLine, Match, Secret } ]. The finding reports *that* a\n// secret exists, never the secret — `Secret` is read for nothing.\nexport function parseGitleaks(json, rel) {\n const list = Array.isArray(json) ? json : [];\n const findings = [];\n for (const r of list) {\n findings.push({\n rule: 'secret:' + (r.RuleID || 'unknown'),\n severity: 'critical',\n category: 'secret',\n message: clipExcerpt(r.Description || 'A secret is committed to the source.'),\n path: rel(r.File),\n line: r.StartLine || 1,\n excerpt: 'committed credential (value redacted)',\n source: 'external',\n tool: 'gitleaks',\n });\n }\n return findings;\n}\n\n// ---- Knip -------------------------------------------------------------------\n// `knip --reporter json` groups dead code by kind: { files:[], dependencies:[],\n// unused:[{name,file,line}], ... }. Each becomes a finding so the dead-code\n// pass can be read in one list; the kind is the rule.\nexport function parseKnip(json, rel) {\n const findings = [];\n const push = (rule, category, severity, path, line, message) => {\n findings.push({ rule, category, severity, message, path: rel(path), line: line || 1, excerpt: '', source: 'external', tool: 'knip' });\n };\n\n for (const file of (json && json.files) || []) {\n push('knip:unused-file', 'dead-file', 'medium', file, 1, 'This file is never imported anywhere.');\n }\n for (const dep of (json && json.dependencies) || []) {\n push('knip:unused-dependency', 'dead-dependency', 'low', dep, 1, `Dependency \"${dep}\" is declared but never imported.`);\n }\n for (const u of (json && json.unused) || []) {\n push('knip:unused-export', 'dead-export', 'low', u.file, u.line, `Export \"${u.name}\" is never used.`);\n }\n for (const u of (json && json.unresolved) || []) {\n push('knip:unresolved', 'dead-import', 'medium', u.file, u.line, `Import \"${u.name}\" does not resolve to anything.`);\n }\n return findings;\n}\n\n// ---- Vulture ----------------------------------------------------------------\n// `vulture` prints lines like `src/util.py:42: unused function 'helper' (60%\n// confidence)`. There is no stable JSON, so we parse the text — which is why the\n// parser is a pure function over a string, and why the line shape is pinned by\n// a test rather than by reading the binary's source.\nconst VULTURE_RE = /^(.+?):(\\d+):\\s+(.+?)\\s+\\((\\d+)% confidence\\)/;\n\nexport function parseVulture(text, rel) {\n const findings = [];\n for (const line of String(text || '').split('\\n')) {\n const m = line.match(VULTURE_RE);\n if (!m) continue;\n const confidence = Number(m[4]);\n if (confidence < 60) continue; // below vulture's own floor, it is guessing\n findings.push({\n rule: 'vulture:' + (m[3].split(' ')[0] || 'unused'),\n severity: confidence >= 90 ? 'medium' : 'low',\n category: 'dead-code',\n message: clipExcerpt(m[3]) + ` (${confidence}% confident)`,\n path: rel(m[1]),\n line: Number(m[2]) || 1,\n excerpt: '',\n source: 'external',\n tool: 'vulture',\n });\n }\n return findings;\n}\n\n// ---- Depcheck ---------------------------------------------------------------\n// `depcheck --json` → { dependencies:[], devDependencies:[], missing:{} }.\nexport function parseDepcheck(json) {\n const findings = [];\n const push = (name, dev) => findings.push({\n rule: 'depcheck:unused',\n severity: 'low',\n category: 'dead-dependency',\n message: `Package \"${name}\" is declared in package.json but never imported.`,\n path: 'package.json',\n line: 1,\n excerpt: '',\n source: 'external',\n tool: 'depcheck',\n dev,\n });\n for (const name of (json && json.dependencies) || []) push(name, false);\n for (const name of (json && json.devDependencies) || []) push(name, true);\n return findings;\n}\n\n// Merge the external passes into one list, keeping the built-in scan's findings\n// untouched. Dedup on (path, line, rule): two engines that flag the same line\n// for the same reason are one problem, not two.\nexport function mergeFindings(...lists) {\n const seen = new Set();\n const out = [];\n for (const list of lists) {\n for (const f of list || []) {\n const key = `${f.path}:${f.line}:${f.rule}`;\n if (seen.has(key)) continue;\n seen.add(key);\n out.push(f);\n }\n }\n return out;\n}\n\n"]}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare function onboarderBinDir(home?: string): string;
|
|
2
|
+
export declare function candidateNames(cmd: any, platform?: NodeJS.Platform, pathext?: string): any[];
|
|
3
|
+
export declare function extraSearchDirs(platform?: NodeJS.Platform, home?: string): string[];
|
|
4
|
+
export declare function splitPath(pathValue: any, platform?: NodeJS.Platform): string[];
|
|
5
|
+
export declare function findOnPath(cmd: any, options?: Record<string, any>): string;
|
|
6
|
+
export declare function spawnArgv(argv: any, platform?: NodeJS.Platform): {
|
|
7
|
+
command: any;
|
|
8
|
+
args: any;
|
|
9
|
+
};
|
package/server/tools/platform.js
CHANGED
|
@@ -12,80 +12,82 @@
|
|
|
12
12
|
// Silicon is the classic case — and the folder Onboarder's own installer
|
|
13
13
|
// drops downloaded binaries into, so a tool installed from the GUI is found
|
|
14
14
|
// on the next status check without a server restart.
|
|
15
|
-
|
|
16
15
|
import fs from 'node:fs';
|
|
17
16
|
import os from 'node:os';
|
|
18
17
|
import path from 'node:path';
|
|
19
|
-
|
|
20
18
|
// Where `install.js` puts binaries it downloads itself (gitleaks on Linux and
|
|
21
19
|
// Windows). One fixed place, under the user's home, never the scanned repo.
|
|
22
20
|
export function onboarderBinDir(home = os.homedir()) {
|
|
23
|
-
|
|
21
|
+
return path.join(home, '.onboarder', 'bin');
|
|
24
22
|
}
|
|
25
|
-
|
|
26
23
|
// The names a command can go by on disk. Windows resolves `npm` to the first
|
|
27
24
|
// of `npm.exe`, `npm.cmd`, … on PATHEXT; POSIX looks for the name as-is.
|
|
28
25
|
export function candidateNames(cmd, platform = process.platform, pathext = '') {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
26
|
+
if (platform !== 'win32')
|
|
27
|
+
return [cmd];
|
|
28
|
+
const exts = (pathext || process.env.PATHEXT || '.EXE;.CMD;.BAT;.COM')
|
|
29
|
+
.split(';').map((e) => e.trim()).filter(Boolean);
|
|
30
|
+
const lower = cmd.toLowerCase();
|
|
31
|
+
if (exts.some((e) => lower.endsWith(e.toLowerCase())))
|
|
32
|
+
return [cmd];
|
|
33
|
+
return [cmd, ...exts.map((e) => cmd + e.toLowerCase())];
|
|
35
34
|
}
|
|
36
|
-
|
|
37
35
|
// Directories worth checking beyond PATH itself. The Homebrew pair matters on
|
|
38
36
|
// a Mac launched from Spotlight rather than a shell; the Onboarder bin dir is
|
|
39
37
|
// where the GUI installer puts self-downloaded tools.
|
|
40
38
|
export function extraSearchDirs(platform = process.platform, home = os.homedir()) {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
if (
|
|
47
|
-
|
|
48
|
-
|
|
39
|
+
const dirs = [onboarderBinDir(home)];
|
|
40
|
+
if (platform === 'darwin')
|
|
41
|
+
dirs.push('/opt/homebrew/bin', '/usr/local/bin');
|
|
42
|
+
if (platform === 'linux')
|
|
43
|
+
dirs.push('/usr/local/bin', path.join(home, '.local', 'bin'));
|
|
44
|
+
if (platform === 'win32') {
|
|
45
|
+
const local = process.env.LOCALAPPDATA;
|
|
46
|
+
if (local)
|
|
47
|
+
dirs.push(path.join(local, 'Programs', 'Gitleaks'));
|
|
48
|
+
}
|
|
49
|
+
return dirs;
|
|
49
50
|
}
|
|
50
|
-
|
|
51
51
|
// Split a PATH string the way the platform does. Exported for tests.
|
|
52
52
|
export function splitPath(pathValue, platform = process.platform) {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
53
|
+
return String(pathValue || '')
|
|
54
|
+
.split(platform === 'win32' ? ';' : ':')
|
|
55
|
+
.map((d) => d.trim())
|
|
56
|
+
.filter(Boolean);
|
|
57
57
|
}
|
|
58
|
-
|
|
59
58
|
// Find `cmd` on PATH (plus the extra dirs). Returns the absolute path, or
|
|
60
59
|
// null. Pure apart from the `exists` probe, which defaults to the disk and is
|
|
61
60
|
// injectable so the tests never touch a real filesystem layout.
|
|
62
61
|
export function findOnPath(cmd, options = {}) {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
62
|
+
const platform = options.platform || process.platform;
|
|
63
|
+
const envPath = options.envPath !== undefined ? options.envPath : process.env.PATH;
|
|
64
|
+
const pathext = options.pathext !== undefined ? options.pathext : process.env.PATHEXT;
|
|
65
|
+
const exists = options.exists || ((p) => fs.existsSync(p));
|
|
66
|
+
const home = options.home || os.homedir();
|
|
67
|
+
const dirs = [...splitPath(envPath, platform), ...extraSearchDirs(platform, home)];
|
|
68
|
+
for (const dir of dirs) {
|
|
69
|
+
for (const name of candidateNames(cmd, platform, pathext)) {
|
|
70
|
+
const full = path.join(dir, name);
|
|
71
|
+
try {
|
|
72
|
+
if (exists(full))
|
|
73
|
+
return full;
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
/* an unreadable dir is just not where the tool lives */
|
|
77
|
+
}
|
|
78
|
+
}
|
|
78
79
|
}
|
|
79
|
-
|
|
80
|
-
return null;
|
|
80
|
+
return null;
|
|
81
81
|
}
|
|
82
|
-
|
|
83
82
|
// A `.cmd`/`.bat` shim cannot be spawned directly on Windows (Node refuses
|
|
84
83
|
// with EINVAL): it needs cmd.exe. `spawnArgv` rewrites the argv for that case
|
|
85
84
|
// and leaves everything else untouched, so callers keep passing plain arrays.
|
|
86
85
|
export function spawnArgv(argv, platform = process.platform) {
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
86
|
+
if (platform !== 'win32')
|
|
87
|
+
return { command: argv[0], args: argv.slice(1) };
|
|
88
|
+
if (!/\.(cmd|bat)$/i.test(argv[0] || ''))
|
|
89
|
+
return { command: argv[0], args: argv.slice(1) };
|
|
90
|
+
const quoted = argv.map((a) => `"${String(a).replace(/"/g, '\\"')}"`).join(' ');
|
|
91
|
+
return { command: 'cmd.exe', args: ['/d', '/s', '/c', quoted] };
|
|
91
92
|
}
|
|
93
|
+
//# sourceMappingURL=platform.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"platform.js","sourceRoot":"","sources":["../../src/server/tools/platform.ts"],"names":[],"mappings":"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","sourcesContent":["// Cross-platform binary lookup.\n//\n// The engine used to ask the Unix `which` command where a tool lives. That is\n// the right answer on macOS and Linux and *no* answer on Windows, where the\n// command is `where` and an npm-installed tool is a `npm.cmd` shim, not an\n// ELF file. Doing the lookup by hand — split PATH, try the PATHEXT suffixes\n// on Windows — keeps one code path for all three platforms, keeps it testable\n// (`exists` is injectable), and removes a spawned process from detection.\n//\n// `findOnPath` also checks a couple of well-known directories that are on a\n// user's interactive PATH but often not on the server's — Homebrew on Apple\n// Silicon is the classic case — and the folder Onboarder's own installer\n// drops downloaded binaries into, so a tool installed from the GUI is found\n// on the next status check without a server restart.\n\nimport fs from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\n\n// Where `install.js` puts binaries it downloads itself (gitleaks on Linux and\n// Windows). One fixed place, under the user's home, never the scanned repo.\nexport function onboarderBinDir(home = os.homedir()) {\n return path.join(home, '.onboarder', 'bin');\n}\n\n// The names a command can go by on disk. Windows resolves `npm` to the first\n// of `npm.exe`, `npm.cmd`, … on PATHEXT; POSIX looks for the name as-is.\nexport function candidateNames(cmd, platform = process.platform, pathext = '') {\n if (platform !== 'win32') return [cmd];\n const exts = (pathext || process.env.PATHEXT || '.EXE;.CMD;.BAT;.COM')\n .split(';').map((e) => e.trim()).filter(Boolean);\n const lower = cmd.toLowerCase();\n if (exts.some((e) => lower.endsWith(e.toLowerCase()))) return [cmd];\n return [cmd, ...exts.map((e) => cmd + e.toLowerCase())];\n}\n\n// Directories worth checking beyond PATH itself. The Homebrew pair matters on\n// a Mac launched from Spotlight rather than a shell; the Onboarder bin dir is\n// where the GUI installer puts self-downloaded tools.\nexport function extraSearchDirs(platform = process.platform, home = os.homedir()) {\n const dirs = [onboarderBinDir(home)];\n if (platform === 'darwin') dirs.push('/opt/homebrew/bin', '/usr/local/bin');\n if (platform === 'linux') dirs.push('/usr/local/bin', path.join(home, '.local', 'bin'));\n if (platform === 'win32') {\n const local = process.env.LOCALAPPDATA;\n if (local) dirs.push(path.join(local, 'Programs', 'Gitleaks'));\n }\n return dirs;\n}\n\n// Split a PATH string the way the platform does. Exported for tests.\nexport function splitPath(pathValue, platform = process.platform) {\n return String(pathValue || '')\n .split(platform === 'win32' ? ';' : ':')\n .map((d) => d.trim())\n .filter(Boolean);\n}\n\n// Find `cmd` on PATH (plus the extra dirs). Returns the absolute path, or\n// null. Pure apart from the `exists` probe, which defaults to the disk and is\n// injectable so the tests never touch a real filesystem layout.\nexport function findOnPath(cmd, options: Record<string, any> = {}) {\n const platform = options.platform || process.platform;\n const envPath = options.envPath !== undefined ? options.envPath : process.env.PATH;\n const pathext = options.pathext !== undefined ? options.pathext : process.env.PATHEXT;\n const exists = options.exists || ((p) => fs.existsSync(p));\n const home = options.home || os.homedir();\n\n const dirs = [...splitPath(envPath, platform), ...extraSearchDirs(platform, home)];\n for (const dir of dirs) {\n for (const name of candidateNames(cmd, platform, pathext)) {\n const full = path.join(dir, name);\n try {\n if (exists(full)) return full;\n } catch {\n /* an unreadable dir is just not where the tool lives */\n }\n }\n }\n return null;\n}\n\n// A `.cmd`/`.bat` shim cannot be spawned directly on Windows (Node refuses\n// with EINVAL): it needs cmd.exe. `spawnArgv` rewrites the argv for that case\n// and leaves everything else untouched, so callers keep passing plain arrays.\nexport function spawnArgv(argv, platform = process.platform) {\n if (platform !== 'win32') return { command: argv[0], args: argv.slice(1) };\n if (!/\\.(cmd|bat)$/i.test(argv[0] || '')) return { command: argv[0], args: argv.slice(1) };\n const quoted = argv.map((a) => `\"${String(a).replace(/\"/g, '\\\\\"')}\"`).join(' ');\n return { command: 'cmd.exe', args: ['/d', '/s', '/c', quoted] };\n}\n"]}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
export declare const TOOL_DEFS: ({
|
|
2
|
+
id: string;
|
|
3
|
+
label: string;
|
|
4
|
+
kind: string;
|
|
5
|
+
purpose: string;
|
|
6
|
+
commands: ({
|
|
7
|
+
kind: string;
|
|
8
|
+
bin: string;
|
|
9
|
+
pkg?: undefined;
|
|
10
|
+
} | {
|
|
11
|
+
kind: string;
|
|
12
|
+
pkg: string;
|
|
13
|
+
bin: string;
|
|
14
|
+
})[];
|
|
15
|
+
install: string[];
|
|
16
|
+
options: {
|
|
17
|
+
key: string;
|
|
18
|
+
label: string;
|
|
19
|
+
type: string;
|
|
20
|
+
values: string[];
|
|
21
|
+
default: string;
|
|
22
|
+
hint: string;
|
|
23
|
+
}[];
|
|
24
|
+
argv: (root: any, options?: Record<string, any>) => any[];
|
|
25
|
+
parse: (text: any, root: any) => any[];
|
|
26
|
+
usesReportFile?: undefined;
|
|
27
|
+
textOutput?: undefined;
|
|
28
|
+
cwd?: undefined;
|
|
29
|
+
} | {
|
|
30
|
+
id: string;
|
|
31
|
+
label: string;
|
|
32
|
+
kind: string;
|
|
33
|
+
purpose: string;
|
|
34
|
+
commands: {
|
|
35
|
+
kind: string;
|
|
36
|
+
bin: string;
|
|
37
|
+
}[];
|
|
38
|
+
install: string[];
|
|
39
|
+
options: {
|
|
40
|
+
key: string;
|
|
41
|
+
label: string;
|
|
42
|
+
type: string;
|
|
43
|
+
default: boolean;
|
|
44
|
+
hint: string;
|
|
45
|
+
}[];
|
|
46
|
+
usesReportFile: boolean;
|
|
47
|
+
argv: (root: any, options?: Record<string, any>, ctx?: Record<string, any>) => any[];
|
|
48
|
+
parse: (text: any, root: any) => any[];
|
|
49
|
+
textOutput?: undefined;
|
|
50
|
+
cwd?: undefined;
|
|
51
|
+
} | {
|
|
52
|
+
usesReportFile?: undefined;
|
|
53
|
+
id: string;
|
|
54
|
+
label: string;
|
|
55
|
+
kind: string;
|
|
56
|
+
purpose: string;
|
|
57
|
+
commands: ({
|
|
58
|
+
pkg?: undefined;
|
|
59
|
+
kind: string;
|
|
60
|
+
bin: string;
|
|
61
|
+
} | {
|
|
62
|
+
bin?: undefined;
|
|
63
|
+
kind: string;
|
|
64
|
+
pkg: string;
|
|
65
|
+
})[];
|
|
66
|
+
install: string[];
|
|
67
|
+
options: {
|
|
68
|
+
key: string;
|
|
69
|
+
label: string;
|
|
70
|
+
type: string;
|
|
71
|
+
values: string[];
|
|
72
|
+
default: any[];
|
|
73
|
+
hint: string;
|
|
74
|
+
}[];
|
|
75
|
+
argv: (root: any, options?: Record<string, any>) => any[];
|
|
76
|
+
parse: (text: any, root: any) => any[];
|
|
77
|
+
textOutput?: undefined;
|
|
78
|
+
cwd?: undefined;
|
|
79
|
+
} | {
|
|
80
|
+
usesReportFile?: undefined;
|
|
81
|
+
id: string;
|
|
82
|
+
label: string;
|
|
83
|
+
kind: string;
|
|
84
|
+
purpose: string;
|
|
85
|
+
commands: ({
|
|
86
|
+
pkg?: undefined;
|
|
87
|
+
kind: string;
|
|
88
|
+
bin: string;
|
|
89
|
+
} | {
|
|
90
|
+
kind: string;
|
|
91
|
+
pkg: string;
|
|
92
|
+
bin: string;
|
|
93
|
+
})[];
|
|
94
|
+
install: string[];
|
|
95
|
+
options: {
|
|
96
|
+
key: string;
|
|
97
|
+
label: string;
|
|
98
|
+
type: string;
|
|
99
|
+
min: number;
|
|
100
|
+
max: number;
|
|
101
|
+
default: number;
|
|
102
|
+
hint: string;
|
|
103
|
+
}[];
|
|
104
|
+
argv: (root: any, options?: Record<string, any>) => any[];
|
|
105
|
+
parse: (text: any, root: any) => any[];
|
|
106
|
+
textOutput: boolean;
|
|
107
|
+
cwd?: undefined;
|
|
108
|
+
} | {
|
|
109
|
+
usesReportFile?: undefined;
|
|
110
|
+
textOutput?: undefined;
|
|
111
|
+
id: string;
|
|
112
|
+
label: string;
|
|
113
|
+
kind: string;
|
|
114
|
+
purpose: string;
|
|
115
|
+
commands: ({
|
|
116
|
+
pkg?: undefined;
|
|
117
|
+
kind: string;
|
|
118
|
+
bin: string;
|
|
119
|
+
} | {
|
|
120
|
+
bin?: undefined;
|
|
121
|
+
kind: string;
|
|
122
|
+
pkg: string;
|
|
123
|
+
})[];
|
|
124
|
+
install: string[];
|
|
125
|
+
options: {
|
|
126
|
+
key: string;
|
|
127
|
+
label: string;
|
|
128
|
+
type: string;
|
|
129
|
+
default: boolean;
|
|
130
|
+
hint: string;
|
|
131
|
+
}[];
|
|
132
|
+
argv: (root: any, options?: Record<string, any>) => string[];
|
|
133
|
+
cwd: boolean;
|
|
134
|
+
parse: (text: any) => any[];
|
|
135
|
+
})[];
|
|
136
|
+
export declare function sanitizeOptions(def: any, raw: any): Record<string, any>;
|
|
137
|
+
export declare function defaultOptions(def: any): Record<string, any>;
|