kirograph 0.16.1 → 0.19.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/LICENSE +1 -1
- package/README.md +103 -1605
- package/dist/architecture/layers/dart.js +112 -0
- package/dist/architecture/layers/dart.js.map +7 -0
- package/dist/architecture/layers/index.js +3 -1
- package/dist/architecture/layers/index.js.map +2 -2
- package/dist/bin/banner.js +74 -6
- package/dist/bin/banner.js.map +2 -2
- package/dist/bin/commands/affected.js +40 -5
- package/dist/bin/commands/affected.js.map +2 -2
- package/dist/bin/commands/attack-surface.js +157 -0
- package/dist/bin/commands/attack-surface.js.map +7 -0
- package/dist/bin/commands/benchmark.js +206 -0
- package/dist/bin/commands/benchmark.js.map +7 -0
- package/dist/bin/commands/budget.js +70 -0
- package/dist/bin/commands/budget.js.map +7 -0
- package/dist/bin/commands/communities.js +77 -0
- package/dist/bin/commands/communities.js.map +7 -0
- package/dist/bin/commands/data.js +665 -0
- package/dist/bin/commands/data.js.map +7 -0
- package/dist/bin/commands/dep-confusion.js +119 -0
- package/dist/bin/commands/dep-confusion.js.map +7 -0
- package/dist/bin/commands/export.js +304 -10
- package/dist/bin/commands/export.js.map +2 -2
- package/dist/bin/commands/flows.js +97 -0
- package/dist/bin/commands/flows.js.map +7 -0
- package/dist/bin/commands/help.js +386 -100
- package/dist/bin/commands/help.js.map +2 -2
- package/dist/bin/commands/install.js +90 -8
- package/dist/bin/commands/install.js.map +2 -2
- package/dist/bin/commands/licenses.js +201 -0
- package/dist/bin/commands/licenses.js.map +7 -0
- package/dist/bin/commands/reachability.js +160 -0
- package/dist/bin/commands/reachability.js.map +7 -0
- package/dist/bin/commands/read.js +100 -0
- package/dist/bin/commands/read.js.map +7 -0
- package/dist/bin/commands/refactor.js +116 -0
- package/dist/bin/commands/refactor.js.map +7 -0
- package/dist/bin/commands/remediation.js +133 -0
- package/dist/bin/commands/remediation.js.map +7 -0
- package/dist/bin/commands/sbom.js +76 -0
- package/dist/bin/commands/sbom.js.map +7 -0
- package/dist/bin/commands/security-ci-report.js +267 -0
- package/dist/bin/commands/security-ci-report.js.map +7 -0
- package/dist/bin/commands/security-export.js +1349 -0
- package/dist/bin/commands/security-export.js.map +7 -0
- package/dist/bin/commands/security-flows.js +126 -0
- package/dist/bin/commands/security-flows.js.map +7 -0
- package/dist/bin/commands/security-secrets.js +170 -0
- package/dist/bin/commands/security-secrets.js.map +7 -0
- package/dist/bin/commands/security.js +193 -0
- package/dist/bin/commands/security.js.map +7 -0
- package/dist/bin/commands/staleness.js +144 -0
- package/dist/bin/commands/staleness.js.map +7 -0
- package/dist/bin/commands/status.js +102 -2
- package/dist/bin/commands/status.js.map +2 -2
- package/dist/bin/commands/supply-chain.js +138 -0
- package/dist/bin/commands/supply-chain.js.map +7 -0
- package/dist/bin/commands/uninit.js +109 -60
- package/dist/bin/commands/uninit.js.map +2 -2
- package/dist/bin/commands/vex.js +76 -0
- package/dist/bin/commands/vex.js.map +7 -0
- package/dist/bin/commands/vuln-suppress.js +95 -0
- package/dist/bin/commands/vuln-suppress.js.map +7 -0
- package/dist/bin/commands/vulns.js +382 -0
- package/dist/bin/commands/vulns.js.map +7 -0
- package/dist/bin/installer/auto-detect.js +125 -0
- package/dist/bin/installer/auto-detect.js.map +7 -0
- package/dist/bin/installer/cli-agent.js +28 -5
- package/dist/bin/installer/cli-agent.js.map +2 -2
- package/dist/bin/installer/common.js +47 -0
- package/dist/bin/installer/common.js.map +2 -2
- package/dist/bin/installer/config-prompt.js +39 -1
- package/dist/bin/installer/config-prompt.js.map +2 -2
- package/dist/bin/installer/detect.js +309 -0
- package/dist/bin/installer/detect.js.map +7 -0
- package/dist/bin/installer/index.js +36 -1
- package/dist/bin/installer/index.js.map +2 -2
- package/dist/bin/installer/instructions.js +195 -3
- package/dist/bin/installer/instructions.js.map +2 -2
- package/dist/bin/installer/steering.js +440 -0
- package/dist/bin/installer/steering.js.map +2 -2
- package/dist/bin/installer/targets/aider.js +3 -3
- package/dist/bin/installer/targets/aider.js.map +2 -2
- package/dist/bin/installer/targets/amp.js +3 -3
- package/dist/bin/installer/targets/amp.js.map +2 -2
- package/dist/bin/installer/targets/antigravity.js +35 -6
- package/dist/bin/installer/targets/antigravity.js.map +2 -2
- package/dist/bin/installer/targets/augment.js +3 -3
- package/dist/bin/installer/targets/augment.js.map +2 -2
- package/dist/bin/installer/targets/claude.js +49 -5
- package/dist/bin/installer/targets/claude.js.map +2 -2
- package/dist/bin/installer/targets/cline.js +32 -6
- package/dist/bin/installer/targets/cline.js.map +2 -2
- package/dist/bin/installer/targets/codex.js +64 -12
- package/dist/bin/installer/targets/codex.js.map +2 -2
- package/dist/bin/installer/targets/continue.js +2 -2
- package/dist/bin/installer/targets/continue.js.map +2 -2
- package/dist/bin/installer/targets/copilot-cli.js +101 -0
- package/dist/bin/installer/targets/copilot-cli.js.map +7 -0
- package/dist/bin/installer/targets/copilot.js +31 -5
- package/dist/bin/installer/targets/copilot.js.map +2 -2
- package/dist/bin/installer/targets/cursor.js +4 -4
- package/dist/bin/installer/targets/cursor.js.map +2 -2
- package/dist/bin/installer/targets/devin.js +2 -2
- package/dist/bin/installer/targets/devin.js.map +2 -2
- package/dist/bin/installer/targets/gemini-cli.js +2 -2
- package/dist/bin/installer/targets/gemini-cli.js.map +2 -2
- package/dist/bin/installer/targets/generic.js +2 -14
- package/dist/bin/installer/targets/generic.js.map +2 -2
- package/dist/bin/installer/targets/goose.js +3 -3
- package/dist/bin/installer/targets/goose.js.map +2 -2
- package/dist/bin/installer/targets/index.js +250 -0
- package/dist/bin/installer/targets/index.js.map +2 -2
- package/dist/bin/installer/targets/junie.js +2 -2
- package/dist/bin/installer/targets/junie.js.map +2 -2
- package/dist/bin/installer/targets/kilo.js +2 -2
- package/dist/bin/installer/targets/kilo.js.map +2 -2
- package/dist/bin/installer/targets/kiro.js +3 -3
- package/dist/bin/installer/targets/kiro.js.map +2 -2
- package/dist/bin/installer/targets/opencode.js +2 -2
- package/dist/bin/installer/targets/opencode.js.map +2 -2
- package/dist/bin/installer/targets/openhands.js +3 -3
- package/dist/bin/installer/targets/openhands.js.map +2 -2
- package/dist/bin/installer/targets/qoder.js +91 -0
- package/dist/bin/installer/targets/qoder.js.map +7 -0
- package/dist/bin/installer/targets/qwen.js +96 -0
- package/dist/bin/installer/targets/qwen.js.map +7 -0
- package/dist/bin/installer/targets/replit.js +3 -3
- package/dist/bin/installer/targets/replit.js.map +2 -2
- package/dist/bin/installer/targets/roo.js +2 -2
- package/dist/bin/installer/targets/roo.js.map +2 -2
- package/dist/bin/installer/targets/tabnine.js +3 -3
- package/dist/bin/installer/targets/tabnine.js.map +2 -2
- package/dist/bin/installer/targets/trae.js +5 -5
- package/dist/bin/installer/targets/trae.js.map +2 -2
- package/dist/bin/installer/targets/warp.js +2 -2
- package/dist/bin/installer/targets/warp.js.map +2 -2
- package/dist/bin/installer/targets/windsurf.js +35 -6
- package/dist/bin/installer/targets/windsurf.js.map +2 -2
- package/dist/bin/kirograph.js +74 -6
- package/dist/bin/kirograph.js.map +3 -3
- package/dist/bin/progress.js +30 -0
- package/dist/bin/progress.js.map +2 -2
- package/dist/compression/naive-cost.js +25 -0
- package/dist/compression/naive-cost.js.map +2 -2
- package/dist/compression/tracker.js +91 -2
- package/dist/compression/tracker.js.map +2 -2
- package/dist/compression/types.js.map +1 -1
- package/dist/config.js +126 -3
- package/dist/config.js.map +2 -2
- package/dist/core/pipeline.js +92 -4
- package/dist/core/pipeline.js.map +2 -2
- package/dist/data/filters.js +105 -0
- package/dist/data/filters.js.map +7 -0
- package/dist/data/indexer.js +225 -0
- package/dist/data/indexer.js.map +7 -0
- package/dist/data/linker.js +150 -0
- package/dist/data/linker.js.map +7 -0
- package/dist/data/lint.js +109 -0
- package/dist/data/lint.js.map +7 -0
- package/dist/data/parsers/csv.js +132 -0
- package/dist/data/parsers/csv.js.map +7 -0
- package/dist/data/parsers/excel.js +88 -0
- package/dist/data/parsers/excel.js.map +7 -0
- package/dist/data/parsers/index.js +79 -0
- package/dist/data/parsers/index.js.map +7 -0
- package/dist/data/parsers/json-array.js +89 -0
- package/dist/data/parsers/json-array.js.map +7 -0
- package/dist/data/parsers/jsonl.js +84 -0
- package/dist/data/parsers/jsonl.js.map +7 -0
- package/dist/data/parsers/parquet.js +95 -0
- package/dist/data/parsers/parquet.js.map +7 -0
- package/dist/data/profiler.js +182 -0
- package/dist/data/profiler.js.map +7 -0
- package/dist/data/queries.js +512 -0
- package/dist/data/queries.js.map +7 -0
- package/dist/data/types.js +17 -0
- package/dist/data/types.js.map +7 -0
- package/dist/db/data-schema.sql +61 -0
- package/dist/db/database.js +67 -5
- package/dist/db/database.js.map +2 -2
- package/dist/db/memory-schema.sql +5 -1
- package/dist/db/schema.sql +3 -1
- package/dist/db/security-schema.sql +72 -0
- package/dist/extraction/extractor.js +81 -0
- package/dist/extraction/extractor.js.map +2 -2
- package/dist/extraction/grammars.js +32 -8
- package/dist/extraction/grammars.js.map +2 -2
- package/dist/extraction/languages.js +43 -1
- package/dist/extraction/languages.js.map +2 -2
- package/dist/extraction/notebook.js +300 -0
- package/dist/extraction/notebook.js.map +7 -0
- package/dist/extraction/wasm/tree-sitter-astro.wasm +0 -0
- package/dist/extraction/wasm/tree-sitter-gdscript.wasm +0 -0
- package/dist/extraction/wasm/tree-sitter-julia.wasm +0 -0
- package/dist/extraction/wasm/tree-sitter-nix.wasm +0 -0
- package/dist/extraction/wasm/tree-sitter-perl.wasm +0 -0
- package/dist/extraction/wasm/tree-sitter-powershell.wasm +0 -0
- package/dist/extraction/wasm/tree-sitter-r.wasm +0 -0
- package/dist/extraction/wasm/tree-sitter-sql.wasm +0 -0
- package/dist/extraction/wasm/tree-sitter-verilog.wasm +0 -0
- package/dist/frameworks/flutter.js +130 -0
- package/dist/frameworks/flutter.js.map +7 -0
- package/dist/frameworks/index.js +7 -1
- package/dist/frameworks/index.js.map +3 -3
- package/dist/graph/communities.js +317 -0
- package/dist/graph/communities.js.map +7 -0
- package/dist/graph/flows.js +138 -0
- package/dist/graph/flows.js.map +7 -0
- package/dist/graph/refactor.js +155 -0
- package/dist/graph/refactor.js.map +7 -0
- package/dist/index.js +1 -1
- package/dist/index.js.map +2 -2
- package/dist/mcp/cache.js +172 -0
- package/dist/mcp/cache.js.map +7 -0
- package/dist/mcp/read-modes.js +295 -0
- package/dist/mcp/read-modes.js.map +7 -0
- package/dist/mcp/server.js +2 -1
- package/dist/mcp/server.js.map +2 -2
- package/dist/mcp/tool-names.js +29 -1
- package/dist/mcp/tool-names.js.map +2 -2
- package/dist/mcp/tools.js +1588 -6
- package/dist/mcp/tools.js.map +3 -3
- package/dist/memory/database.js +32 -2
- package/dist/memory/database.js.map +2 -2
- package/dist/memory/types.js.map +1 -1
- package/dist/resolution/bridges/android-rn.js +298 -0
- package/dist/resolution/bridges/android-rn.js.map +7 -0
- package/dist/resolution/bridges/expo-modules.js +155 -0
- package/dist/resolution/bridges/expo-modules.js.map +7 -0
- package/dist/resolution/bridges/flutter-channel.js +385 -0
- package/dist/resolution/bridges/flutter-channel.js.map +7 -0
- package/dist/resolution/bridges/index.js +80 -0
- package/dist/resolution/bridges/index.js.map +7 -0
- package/dist/resolution/bridges/native-events.js +188 -0
- package/dist/resolution/bridges/native-events.js.map +7 -0
- package/dist/resolution/bridges/native-views.js +244 -0
- package/dist/resolution/bridges/native-views.js.map +7 -0
- package/dist/resolution/bridges/react-native.js +161 -0
- package/dist/resolution/bridges/react-native.js.map +7 -0
- package/dist/resolution/bridges/swift-objc.js +227 -0
- package/dist/resolution/bridges/swift-objc.js.map +7 -0
- package/dist/resolution/bridges/turbomodules.js +216 -0
- package/dist/resolution/bridges/turbomodules.js.map +7 -0
- package/dist/resolution/index.js +61 -2
- package/dist/resolution/index.js.map +2 -2
- package/dist/security/attack-surface.js +164 -0
- package/dist/security/attack-surface.js.map +7 -0
- package/dist/security/context-warnings.js +123 -0
- package/dist/security/context-warnings.js.map +7 -0
- package/dist/security/context-warnings.test.js +300 -0
- package/dist/security/context-warnings.test.js.map +7 -0
- package/dist/security/data-flows.js +228 -0
- package/dist/security/data-flows.js.map +7 -0
- package/dist/security/dep-confusion.js +255 -0
- package/dist/security/dep-confusion.js.map +7 -0
- package/dist/security/errors.js +51 -0
- package/dist/security/errors.js.map +7 -0
- package/dist/security/export/fix-suggestions.js +58 -0
- package/dist/security/export/fix-suggestions.js.map +7 -0
- package/dist/security/export/fix-suggestions.test.js +74 -0
- package/dist/security/export/fix-suggestions.test.js.map +7 -0
- package/dist/security/export/sbom.js +230 -0
- package/dist/security/export/sbom.js.map +7 -0
- package/dist/security/export/sbom.test.js +288 -0
- package/dist/security/export/sbom.test.js.map +7 -0
- package/dist/security/export/serialization.js +142 -0
- package/dist/security/export/serialization.js.map +7 -0
- package/dist/security/export/serialization.test.js +310 -0
- package/dist/security/export/serialization.test.js.map +7 -0
- package/dist/security/export/vex.js +220 -0
- package/dist/security/export/vex.js.map +7 -0
- package/dist/security/export/vex.test.js +278 -0
- package/dist/security/export/vex.test.js.map +7 -0
- package/dist/security/index.js +67 -0
- package/dist/security/index.js.map +7 -0
- package/dist/security/integrator-transitives.test.js +359 -0
- package/dist/security/integrator-transitives.test.js.map +7 -0
- package/dist/security/integrator.js +491 -0
- package/dist/security/integrator.js.map +7 -0
- package/dist/security/integrator.test.js +237 -0
- package/dist/security/integrator.test.js.map +7 -0
- package/dist/security/license.js +70 -0
- package/dist/security/license.js.map +7 -0
- package/dist/security/manifest/adapter.js +243 -0
- package/dist/security/manifest/adapter.js.map +7 -0
- package/dist/security/manifest/adapter.test.js +272 -0
- package/dist/security/manifest/adapter.test.js.map +7 -0
- package/dist/security/manifest/parser.js +376 -0
- package/dist/security/manifest/parser.js.map +7 -0
- package/dist/security/manifest/parser.test.js +110 -0
- package/dist/security/manifest/parser.test.js.map +7 -0
- package/dist/security/manifest/plugins/cargo.js +233 -0
- package/dist/security/manifest/plugins/cargo.js.map +7 -0
- package/dist/security/manifest/plugins/cargo.test.js +304 -0
- package/dist/security/manifest/plugins/cargo.test.js.map +7 -0
- package/dist/security/manifest/plugins/composer.js +152 -0
- package/dist/security/manifest/plugins/composer.js.map +7 -0
- package/dist/security/manifest/plugins/go.js +146 -0
- package/dist/security/manifest/plugins/go.js.map +7 -0
- package/dist/security/manifest/plugins/go.test.js +341 -0
- package/dist/security/manifest/plugins/go.test.js.map +7 -0
- package/dist/security/manifest/plugins/gradle.js +159 -0
- package/dist/security/manifest/plugins/gradle.js.map +7 -0
- package/dist/security/manifest/plugins/hex.js +159 -0
- package/dist/security/manifest/plugins/hex.js.map +7 -0
- package/dist/security/manifest/plugins/maven.js +128 -0
- package/dist/security/manifest/plugins/maven.js.map +7 -0
- package/dist/security/manifest/plugins/maven.test.js +389 -0
- package/dist/security/manifest/plugins/maven.test.js.map +7 -0
- package/dist/security/manifest/plugins/npm.js +284 -0
- package/dist/security/manifest/plugins/npm.js.map +7 -0
- package/dist/security/manifest/plugins/npm.test.js +298 -0
- package/dist/security/manifest/plugins/npm.test.js.map +7 -0
- package/dist/security/manifest/plugins/nuget.js +186 -0
- package/dist/security/manifest/plugins/nuget.js.map +7 -0
- package/dist/security/manifest/plugins/pip.js +123 -0
- package/dist/security/manifest/plugins/pip.js.map +7 -0
- package/dist/security/manifest/plugins/pip.test.js +208 -0
- package/dist/security/manifest/plugins/pip.test.js.map +7 -0
- package/dist/security/manifest/plugins/pubspec.js +212 -0
- package/dist/security/manifest/plugins/pubspec.js.map +7 -0
- package/dist/security/manifest/plugins/pyproject.js +261 -0
- package/dist/security/manifest/plugins/pyproject.js.map +7 -0
- package/dist/security/manifest/plugins/rubygems.js +185 -0
- package/dist/security/manifest/plugins/rubygems.js.map +7 -0
- package/dist/security/manifest/plugins/swift.js +200 -0
- package/dist/security/manifest/plugins/swift.js.map +7 -0
- package/dist/security/owasp.js +104 -0
- package/dist/security/owasp.js.map +7 -0
- package/dist/security/pipeline.js +125 -0
- package/dist/security/pipeline.js.map +7 -0
- package/dist/security/reachability.js +276 -0
- package/dist/security/reachability.js.map +7 -0
- package/dist/security/reachability.test.js +394 -0
- package/dist/security/reachability.test.js.map +7 -0
- package/dist/security/remediation.js +126 -0
- package/dist/security/remediation.js.map +7 -0
- package/dist/security/secrets.js +176 -0
- package/dist/security/secrets.js.map +7 -0
- package/dist/security/staleness.js +231 -0
- package/dist/security/staleness.js.map +7 -0
- package/dist/security/supply-chain.js +301 -0
- package/dist/security/supply-chain.js.map +7 -0
- package/dist/security/suppressions.js +106 -0
- package/dist/security/suppressions.js.map +7 -0
- package/dist/security/types.js +17 -0
- package/dist/security/types.js.map +7 -0
- package/dist/security/vuln/client.js +355 -0
- package/dist/security/vuln/client.js.map +7 -0
- package/dist/security/vuln/client.test.js +288 -0
- package/dist/security/vuln/client.test.js.map +7 -0
- package/dist/security/vuln/epss-client.js +95 -0
- package/dist/security/vuln/epss-client.js.map +7 -0
- package/dist/security/vuln/index.js +29 -0
- package/dist/security/vuln/index.js.map +7 -0
- package/dist/security/vuln/osv-adapter.js +321 -0
- package/dist/security/vuln/osv-adapter.js.map +7 -0
- package/dist/security/vuln/osv-adapter.test.js +391 -0
- package/dist/security/vuln/osv-adapter.test.js.map +7 -0
- package/dist/security/vuln/types.js +17 -0
- package/dist/security/vuln/types.js.map +7 -0
- package/dist/types.js.map +2 -2
- package/package.json +5 -2
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var osv_adapter_exports = {};
|
|
20
|
+
__export(osv_adapter_exports, {
|
|
21
|
+
OsvAdapter: () => OsvAdapter
|
|
22
|
+
});
|
|
23
|
+
module.exports = __toCommonJS(osv_adapter_exports);
|
|
24
|
+
var import_errors = require("../errors");
|
|
25
|
+
var import_errors2 = require("../../errors");
|
|
26
|
+
const ECOSYSTEM_MAP = {
|
|
27
|
+
npm: "npm",
|
|
28
|
+
maven: "Maven",
|
|
29
|
+
go: "Go",
|
|
30
|
+
pypi: "PyPI",
|
|
31
|
+
cargo: "crates.io",
|
|
32
|
+
pyproject: "PyPI",
|
|
33
|
+
// pyproject.toml (Poetry/Hatch/PDM/PEP 621)
|
|
34
|
+
nuget: "NuGet",
|
|
35
|
+
gradle: "Maven",
|
|
36
|
+
// Gradle projects use Maven Central
|
|
37
|
+
rubygems: "RubyGems",
|
|
38
|
+
composer: "Packagist",
|
|
39
|
+
swift: "SwiftURL",
|
|
40
|
+
pub: "Pub",
|
|
41
|
+
hex: "Hex"
|
|
42
|
+
};
|
|
43
|
+
const OSV_API_URL = "https://api.osv.dev/v1/query";
|
|
44
|
+
const OSV_BATCH_API_URL = "https://api.osv.dev/v1/querybatch";
|
|
45
|
+
const DEFAULT_TIMEOUT_MS = 3e4;
|
|
46
|
+
const OSV_BATCH_MAX_QUERIES = 1e3;
|
|
47
|
+
const MAX_SUMMARY_LENGTH = 500;
|
|
48
|
+
class OsvAdapter {
|
|
49
|
+
constructor(options) {
|
|
50
|
+
this.name = "OSV";
|
|
51
|
+
this.apiUrl = options?.apiUrl ?? OSV_API_URL;
|
|
52
|
+
this.batchApiUrl = options?.batchApiUrl ?? OSV_BATCH_API_URL;
|
|
53
|
+
this.timeoutMs = options?.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Batch query up to OSV_BATCH_MAX_QUERIES packages in a single HTTP request.
|
|
57
|
+
* Results are returned in the same order as the input queries.
|
|
58
|
+
* Queries for unsupported ecosystems produce empty results without an HTTP call.
|
|
59
|
+
*/
|
|
60
|
+
async queryBatch(queries, signal) {
|
|
61
|
+
if (queries.length === 0) return [];
|
|
62
|
+
const osvQueries = [];
|
|
63
|
+
const indexMap = [];
|
|
64
|
+
for (const q of queries) {
|
|
65
|
+
const osvEcosystem = ECOSYSTEM_MAP[q.ecosystem.toLowerCase()];
|
|
66
|
+
if (!osvEcosystem) {
|
|
67
|
+
(0, import_errors2.logWarn)(`OSV adapter: unsupported ecosystem "${q.ecosystem}", skipping batch entry`);
|
|
68
|
+
indexMap.push(null);
|
|
69
|
+
} else {
|
|
70
|
+
indexMap.push(osvQueries.length);
|
|
71
|
+
osvQueries.push({
|
|
72
|
+
package: { name: q.packageName, ecosystem: osvEcosystem },
|
|
73
|
+
version: q.version
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
if (osvQueries.length === 0) {
|
|
78
|
+
return queries.map(() => []);
|
|
79
|
+
}
|
|
80
|
+
const timeoutController = new AbortController();
|
|
81
|
+
const timeoutId = setTimeout(() => timeoutController.abort(), this.timeoutMs);
|
|
82
|
+
const combinedSignal = signal ? combineAbortSignals(signal, timeoutController.signal) : timeoutController.signal;
|
|
83
|
+
let batchResults;
|
|
84
|
+
try {
|
|
85
|
+
const response = await fetch(this.batchApiUrl, {
|
|
86
|
+
method: "POST",
|
|
87
|
+
headers: { "Content-Type": "application/json" },
|
|
88
|
+
body: JSON.stringify({ queries: osvQueries }),
|
|
89
|
+
signal: combinedSignal
|
|
90
|
+
});
|
|
91
|
+
if (!response.ok) {
|
|
92
|
+
throw new import_errors.VulnDatabaseError(
|
|
93
|
+
`OSV batch API returned HTTP ${response.status}: ${response.statusText}`,
|
|
94
|
+
"OSV",
|
|
95
|
+
response.status
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
const data = await response.json();
|
|
99
|
+
batchResults = data.results ?? [];
|
|
100
|
+
} catch (error) {
|
|
101
|
+
if (error instanceof import_errors.VulnDatabaseError) throw error;
|
|
102
|
+
if (isAbortError(error)) {
|
|
103
|
+
const msg2 = timeoutController.signal.aborted ? `OSV batch query timed out after ${this.timeoutMs}ms (${osvQueries.length} packages)` : `OSV batch query aborted`;
|
|
104
|
+
(0, import_errors2.logError)(msg2);
|
|
105
|
+
throw new import_errors.VulnDatabaseError(msg2, "OSV");
|
|
106
|
+
}
|
|
107
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
108
|
+
(0, import_errors2.logError)(`OSV batch query failed: ${msg}`);
|
|
109
|
+
throw new import_errors.VulnDatabaseError(`Network error in OSV batch query: ${msg}`, "OSV");
|
|
110
|
+
} finally {
|
|
111
|
+
clearTimeout(timeoutId);
|
|
112
|
+
}
|
|
113
|
+
return queries.map((_, i) => {
|
|
114
|
+
const osvIdx = indexMap[i];
|
|
115
|
+
if (osvIdx === null) return [];
|
|
116
|
+
const resultEntry = batchResults[osvIdx];
|
|
117
|
+
if (!resultEntry) return [];
|
|
118
|
+
return this.parseResponse({ vulns: resultEntry.vulns });
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
async query(ecosystem, packageName, version, signal) {
|
|
122
|
+
const osvEcosystem = ECOSYSTEM_MAP[ecosystem.toLowerCase()];
|
|
123
|
+
if (!osvEcosystem) {
|
|
124
|
+
(0, import_errors2.logWarn)(`OSV adapter: unsupported ecosystem "${ecosystem}", skipping query`);
|
|
125
|
+
return [];
|
|
126
|
+
}
|
|
127
|
+
const body = JSON.stringify({
|
|
128
|
+
package: {
|
|
129
|
+
name: packageName,
|
|
130
|
+
ecosystem: osvEcosystem
|
|
131
|
+
},
|
|
132
|
+
version
|
|
133
|
+
});
|
|
134
|
+
const timeoutController = new AbortController();
|
|
135
|
+
const timeoutId = setTimeout(() => timeoutController.abort(), this.timeoutMs);
|
|
136
|
+
const combinedSignal = signal ? combineAbortSignals(signal, timeoutController.signal) : timeoutController.signal;
|
|
137
|
+
try {
|
|
138
|
+
const response = await fetch(this.apiUrl, {
|
|
139
|
+
method: "POST",
|
|
140
|
+
headers: { "Content-Type": "application/json" },
|
|
141
|
+
body,
|
|
142
|
+
signal: combinedSignal
|
|
143
|
+
});
|
|
144
|
+
if (!response.ok) {
|
|
145
|
+
throw new import_errors.VulnDatabaseError(
|
|
146
|
+
`OSV API returned HTTP ${response.status}: ${response.statusText}`,
|
|
147
|
+
"OSV",
|
|
148
|
+
response.status
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
const data = await response.json();
|
|
152
|
+
return this.parseResponse(data);
|
|
153
|
+
} catch (error) {
|
|
154
|
+
if (error instanceof import_errors.VulnDatabaseError) {
|
|
155
|
+
throw error;
|
|
156
|
+
}
|
|
157
|
+
if (isAbortError(error)) {
|
|
158
|
+
const isTimeout = timeoutController.signal.aborted;
|
|
159
|
+
const message = isTimeout ? `OSV query timed out after ${this.timeoutMs}ms for ${packageName}@${version}` : `OSV query aborted for ${packageName}@${version}`;
|
|
160
|
+
(0, import_errors2.logError)(message);
|
|
161
|
+
throw new import_errors.VulnDatabaseError(message, "OSV");
|
|
162
|
+
}
|
|
163
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
164
|
+
(0, import_errors2.logError)(`OSV query failed for ${packageName}@${version}: ${errorMessage}`);
|
|
165
|
+
throw new import_errors.VulnDatabaseError(
|
|
166
|
+
`Network error querying OSV for ${packageName}@${version}: ${errorMessage}`,
|
|
167
|
+
"OSV"
|
|
168
|
+
);
|
|
169
|
+
} finally {
|
|
170
|
+
clearTimeout(timeoutId);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Parse the OSV API response into CVERecord objects.
|
|
175
|
+
*/
|
|
176
|
+
parseResponse(data) {
|
|
177
|
+
if (!data.vulns || data.vulns.length === 0) {
|
|
178
|
+
return [];
|
|
179
|
+
}
|
|
180
|
+
const records = [];
|
|
181
|
+
for (const vuln of data.vulns) {
|
|
182
|
+
const cveId = this.extractCveId(vuln);
|
|
183
|
+
if (!cveId) {
|
|
184
|
+
continue;
|
|
185
|
+
}
|
|
186
|
+
const severity = this.extractSeverity(vuln);
|
|
187
|
+
const { ranges, fixedVersion } = this.extractAffectedRanges(vuln);
|
|
188
|
+
const summary = this.extractSummary(vuln);
|
|
189
|
+
records.push({
|
|
190
|
+
id: cveId,
|
|
191
|
+
severity,
|
|
192
|
+
affectedVersionRanges: ranges,
|
|
193
|
+
fixedVersion,
|
|
194
|
+
summary
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
return records;
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Extract CVE ID from the vulnerability's aliases or use the OSV ID.
|
|
201
|
+
* Prefers CVE-* identifiers from the aliases array.
|
|
202
|
+
*/
|
|
203
|
+
extractCveId(vuln) {
|
|
204
|
+
if (vuln.aliases) {
|
|
205
|
+
const cveAlias = vuln.aliases.find((alias) => alias.startsWith("CVE-"));
|
|
206
|
+
if (cveAlias) {
|
|
207
|
+
return cveAlias;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
return vuln.id;
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Extract CVSS v3.1 base score from the severity array.
|
|
214
|
+
* Returns 0 if no CVSS score is available.
|
|
215
|
+
*/
|
|
216
|
+
extractSeverity(vuln) {
|
|
217
|
+
if (!vuln.severity || vuln.severity.length === 0) {
|
|
218
|
+
return 0;
|
|
219
|
+
}
|
|
220
|
+
for (const sev of vuln.severity) {
|
|
221
|
+
if (sev.type === "CVSS_V3") {
|
|
222
|
+
const score = this.parseCvssScore(sev.score);
|
|
223
|
+
if (score !== null) {
|
|
224
|
+
return score;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
for (const sev of vuln.severity) {
|
|
229
|
+
const score = this.parseCvssScore(sev.score);
|
|
230
|
+
if (score !== null) {
|
|
231
|
+
return score;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
return 0;
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Parse a CVSS vector string or numeric score.
|
|
238
|
+
* CVSS vectors look like: "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H"
|
|
239
|
+
* The base score is not directly in the vector — we extract it if it's a plain number,
|
|
240
|
+
* or return null if we can't parse it.
|
|
241
|
+
*/
|
|
242
|
+
parseCvssScore(scoreStr) {
|
|
243
|
+
const num = parseFloat(scoreStr);
|
|
244
|
+
if (!isNaN(num) && num >= 0 && num <= 10) {
|
|
245
|
+
return num;
|
|
246
|
+
}
|
|
247
|
+
return null;
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Extract affected version ranges and the first fixed version from the vulnerability.
|
|
251
|
+
*/
|
|
252
|
+
extractAffectedRanges(vuln) {
|
|
253
|
+
const ranges = [];
|
|
254
|
+
let fixedVersion;
|
|
255
|
+
if (!vuln.affected) {
|
|
256
|
+
return { ranges, fixedVersion };
|
|
257
|
+
}
|
|
258
|
+
for (const affected of vuln.affected) {
|
|
259
|
+
if (!affected.ranges) {
|
|
260
|
+
continue;
|
|
261
|
+
}
|
|
262
|
+
for (const range of affected.ranges) {
|
|
263
|
+
if (!range.events || range.events.length === 0) {
|
|
264
|
+
continue;
|
|
265
|
+
}
|
|
266
|
+
const versionRange = {};
|
|
267
|
+
for (const event of range.events) {
|
|
268
|
+
if (event.introduced) {
|
|
269
|
+
versionRange.introduced = event.introduced;
|
|
270
|
+
}
|
|
271
|
+
if (event.fixed) {
|
|
272
|
+
versionRange.fixed = event.fixed;
|
|
273
|
+
if (!fixedVersion) {
|
|
274
|
+
fixedVersion = event.fixed;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
if (event.last_affected) {
|
|
278
|
+
versionRange.lastAffected = event.last_affected;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
if (versionRange.introduced || versionRange.fixed || versionRange.lastAffected) {
|
|
282
|
+
ranges.push(versionRange);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
return { ranges, fixedVersion };
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* Extract and truncate the summary from the vulnerability.
|
|
290
|
+
* Prefers the summary field, falls back to details.
|
|
291
|
+
*/
|
|
292
|
+
extractSummary(vuln) {
|
|
293
|
+
const text = vuln.summary || vuln.details || "";
|
|
294
|
+
if (text.length <= MAX_SUMMARY_LENGTH) {
|
|
295
|
+
return text;
|
|
296
|
+
}
|
|
297
|
+
return text.slice(0, MAX_SUMMARY_LENGTH - 3) + "...";
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
function combineAbortSignals(...signals) {
|
|
301
|
+
const controller = new AbortController();
|
|
302
|
+
for (const signal of signals) {
|
|
303
|
+
if (signal.aborted) {
|
|
304
|
+
controller.abort(signal.reason);
|
|
305
|
+
return controller.signal;
|
|
306
|
+
}
|
|
307
|
+
signal.addEventListener("abort", () => controller.abort(signal.reason), { once: true });
|
|
308
|
+
}
|
|
309
|
+
return controller.signal;
|
|
310
|
+
}
|
|
311
|
+
function isAbortError(error) {
|
|
312
|
+
if (error instanceof Error) {
|
|
313
|
+
return error.name === "AbortError" || error.name === "TimeoutError";
|
|
314
|
+
}
|
|
315
|
+
return false;
|
|
316
|
+
}
|
|
317
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
318
|
+
0 && (module.exports = {
|
|
319
|
+
OsvAdapter
|
|
320
|
+
});
|
|
321
|
+
//# sourceMappingURL=osv-adapter.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/security/vuln/osv-adapter.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * OSV API Adapter\n *\n * Queries the OSV (Open Source Vulnerabilities) database for known CVEs\n * affecting project dependencies. Implements the VulnDatabaseAdapter interface.\n */\n\nimport { CVERecord, VersionRange } from '../types';\nimport type { VulnDatabaseAdapter, BatchQuery } from './types';\nimport { VulnDatabaseError } from '../errors';\nimport { logWarn, logError } from '../../errors';\n\nexport type { VulnDatabaseAdapter, BatchQuery };\n\n// \u2500\u2500 Ecosystem Mapping \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nconst ECOSYSTEM_MAP: Record<string, string> = {\n npm: 'npm',\n maven: 'Maven',\n go: 'Go',\n pypi: 'PyPI',\n cargo: 'crates.io',\n pyproject: 'PyPI', // pyproject.toml (Poetry/Hatch/PDM/PEP 621)\n nuget: 'NuGet',\n gradle: 'Maven', // Gradle projects use Maven Central\n rubygems: 'RubyGems',\n composer: 'Packagist',\n swift: 'SwiftURL',\n pub: 'Pub',\n hex: 'Hex',\n};\n\n// \u2500\u2500 OSV Request/Response Types \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\ninterface OsvSeverity {\n type: string;\n score: string;\n}\n\ninterface OsvAffectedRange {\n type: string;\n events: Array<{ introduced?: string; fixed?: string; last_affected?: string }>;\n}\n\ninterface OsvAffected {\n package?: { name?: string; ecosystem?: string };\n ranges?: OsvAffectedRange[];\n versions?: string[];\n}\n\ninterface OsvVulnerability {\n id: string;\n aliases?: string[];\n summary?: string;\n details?: string;\n severity?: OsvSeverity[];\n affected?: OsvAffected[];\n}\n\ninterface OsvQueryResponse {\n vulns?: OsvVulnerability[];\n}\n\ninterface OsvBatchQueryItem {\n package: { name: string; ecosystem: string };\n version: string;\n}\n\ninterface OsvBatchResponse {\n results: Array<{ vulns?: OsvVulnerability[] }>;\n}\n\n// \u2500\u2500 Constants \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nconst OSV_API_URL = 'https://api.osv.dev/v1/query';\nconst OSV_BATCH_API_URL = 'https://api.osv.dev/v1/querybatch';\nconst DEFAULT_TIMEOUT_MS = 30_000;\nconst OSV_BATCH_MAX_QUERIES = 1000;\nconst MAX_SUMMARY_LENGTH = 500;\n\n// \u2500\u2500 OsvAdapter Implementation \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport class OsvAdapter implements VulnDatabaseAdapter {\n public readonly name = 'OSV';\n\n private readonly apiUrl: string;\n private readonly batchApiUrl: string;\n private readonly timeoutMs: number;\n\n constructor(options?: { apiUrl?: string; batchApiUrl?: string; timeoutMs?: number }) {\n this.apiUrl = options?.apiUrl ?? OSV_API_URL;\n this.batchApiUrl = options?.batchApiUrl ?? OSV_BATCH_API_URL;\n this.timeoutMs = options?.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n }\n\n /**\n * Batch query up to OSV_BATCH_MAX_QUERIES packages in a single HTTP request.\n * Results are returned in the same order as the input queries.\n * Queries for unsupported ecosystems produce empty results without an HTTP call.\n */\n async queryBatch(\n queries: BatchQuery[],\n signal?: AbortSignal,\n ): Promise<Array<CVERecord[]>> {\n if (queries.length === 0) return [];\n\n // Map each query to its OSV ecosystem \u2014 track indices of unsupported ones\n const osvQueries: OsvBatchQueryItem[] = [];\n const indexMap: Array<number | null> = []; // index into osvQueries, or null if unsupported\n\n for (const q of queries) {\n const osvEcosystem = ECOSYSTEM_MAP[q.ecosystem.toLowerCase()];\n if (!osvEcosystem) {\n logWarn(`OSV adapter: unsupported ecosystem \"${q.ecosystem}\", skipping batch entry`);\n indexMap.push(null);\n } else {\n indexMap.push(osvQueries.length);\n osvQueries.push({\n package: { name: q.packageName, ecosystem: osvEcosystem },\n version: q.version,\n });\n }\n }\n\n if (osvQueries.length === 0) {\n return queries.map(() => []);\n }\n\n const timeoutController = new AbortController();\n const timeoutId = setTimeout(() => timeoutController.abort(), this.timeoutMs);\n const combinedSignal = signal\n ? combineAbortSignals(signal, timeoutController.signal)\n : timeoutController.signal;\n\n let batchResults: Array<{ vulns?: OsvVulnerability[] }>;\n\n try {\n const response = await fetch(this.batchApiUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ queries: osvQueries }),\n signal: combinedSignal,\n });\n\n if (!response.ok) {\n throw new VulnDatabaseError(\n `OSV batch API returned HTTP ${response.status}: ${response.statusText}`,\n 'OSV',\n response.status,\n );\n }\n\n const data = (await response.json()) as OsvBatchResponse;\n batchResults = data.results ?? [];\n } catch (error: unknown) {\n if (error instanceof VulnDatabaseError) throw error;\n if (isAbortError(error)) {\n const msg = timeoutController.signal.aborted\n ? `OSV batch query timed out after ${this.timeoutMs}ms (${osvQueries.length} packages)`\n : `OSV batch query aborted`;\n logError(msg);\n throw new VulnDatabaseError(msg, 'OSV');\n }\n const msg = error instanceof Error ? error.message : String(error);\n logError(`OSV batch query failed: ${msg}`);\n throw new VulnDatabaseError(`Network error in OSV batch query: ${msg}`, 'OSV');\n } finally {\n clearTimeout(timeoutId);\n }\n\n // Rebuild full results array aligned with input queries\n return queries.map((_, i) => {\n const osvIdx = indexMap[i];\n if (osvIdx === null) return [];\n const resultEntry = batchResults[osvIdx];\n if (!resultEntry) return [];\n return this.parseResponse({ vulns: resultEntry.vulns });\n });\n }\n\n async query(\n ecosystem: string,\n packageName: string,\n version: string,\n signal?: AbortSignal,\n ): Promise<CVERecord[]> {\n const osvEcosystem = ECOSYSTEM_MAP[ecosystem.toLowerCase()];\n if (!osvEcosystem) {\n logWarn(`OSV adapter: unsupported ecosystem \"${ecosystem}\", skipping query`);\n return [];\n }\n\n const body = JSON.stringify({\n package: {\n name: packageName,\n ecosystem: osvEcosystem,\n },\n version,\n });\n\n // Create a timeout abort signal and combine with any external signal\n const timeoutController = new AbortController();\n const timeoutId = setTimeout(() => timeoutController.abort(), this.timeoutMs);\n\n const combinedSignal = signal\n ? combineAbortSignals(signal, timeoutController.signal)\n : timeoutController.signal;\n\n try {\n const response = await fetch(this.apiUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body,\n signal: combinedSignal,\n });\n\n if (!response.ok) {\n throw new VulnDatabaseError(\n `OSV API returned HTTP ${response.status}: ${response.statusText}`,\n 'OSV',\n response.status,\n );\n }\n\n const data = (await response.json()) as OsvQueryResponse;\n return this.parseResponse(data);\n } catch (error: unknown) {\n if (error instanceof VulnDatabaseError) {\n throw error;\n }\n\n if (isAbortError(error)) {\n const isTimeout = timeoutController.signal.aborted;\n const message = isTimeout\n ? `OSV query timed out after ${this.timeoutMs}ms for ${packageName}@${version}`\n : `OSV query aborted for ${packageName}@${version}`;\n logError(message);\n throw new VulnDatabaseError(message, 'OSV');\n }\n\n const errorMessage = error instanceof Error ? error.message : String(error);\n logError(`OSV query failed for ${packageName}@${version}: ${errorMessage}`);\n throw new VulnDatabaseError(\n `Network error querying OSV for ${packageName}@${version}: ${errorMessage}`,\n 'OSV',\n );\n } finally {\n clearTimeout(timeoutId);\n }\n }\n\n /**\n * Parse the OSV API response into CVERecord objects.\n */\n private parseResponse(data: OsvQueryResponse): CVERecord[] {\n if (!data.vulns || data.vulns.length === 0) {\n return [];\n }\n\n const records: CVERecord[] = [];\n\n for (const vuln of data.vulns) {\n const cveId = this.extractCveId(vuln);\n if (!cveId) {\n // Skip vulnerabilities without a CVE identifier\n continue;\n }\n\n const severity = this.extractSeverity(vuln);\n const { ranges, fixedVersion } = this.extractAffectedRanges(vuln);\n const summary = this.extractSummary(vuln);\n\n records.push({\n id: cveId,\n severity,\n affectedVersionRanges: ranges,\n fixedVersion,\n summary,\n });\n }\n\n return records;\n }\n\n /**\n * Extract CVE ID from the vulnerability's aliases or use the OSV ID.\n * Prefers CVE-* identifiers from the aliases array.\n */\n private extractCveId(vuln: OsvVulnerability): string | undefined {\n // Look for a CVE alias first\n if (vuln.aliases) {\n const cveAlias = vuln.aliases.find((alias) => alias.startsWith('CVE-'));\n if (cveAlias) {\n return cveAlias;\n }\n }\n\n // Fall back to the OSV ID (e.g., GHSA-xxxx-xxxx-xxxx)\n return vuln.id;\n }\n\n /**\n * Extract CVSS v3.1 base score from the severity array.\n * Returns 0 if no CVSS score is available.\n */\n private extractSeverity(vuln: OsvVulnerability): number {\n if (!vuln.severity || vuln.severity.length === 0) {\n return 0;\n }\n\n for (const sev of vuln.severity) {\n if (sev.type === 'CVSS_V3') {\n const score = this.parseCvssScore(sev.score);\n if (score !== null) {\n return score;\n }\n }\n }\n\n // Try any severity type as fallback\n for (const sev of vuln.severity) {\n const score = this.parseCvssScore(sev.score);\n if (score !== null) {\n return score;\n }\n }\n\n return 0;\n }\n\n /**\n * Parse a CVSS vector string or numeric score.\n * CVSS vectors look like: \"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H\"\n * The base score is not directly in the vector \u2014 we extract it if it's a plain number,\n * or return null if we can't parse it.\n */\n private parseCvssScore(scoreStr: string): number | null {\n // If it's a plain number\n const num = parseFloat(scoreStr);\n if (!isNaN(num) && num >= 0 && num <= 10) {\n return num;\n }\n\n // CVSS vector strings don't contain the base score directly.\n // OSV sometimes provides the score as a plain number in the score field.\n return null;\n }\n\n /**\n * Extract affected version ranges and the first fixed version from the vulnerability.\n */\n private extractAffectedRanges(vuln: OsvVulnerability): {\n ranges: VersionRange[];\n fixedVersion?: string;\n } {\n const ranges: VersionRange[] = [];\n let fixedVersion: string | undefined;\n\n if (!vuln.affected) {\n return { ranges, fixedVersion };\n }\n\n for (const affected of vuln.affected) {\n if (!affected.ranges) {\n continue;\n }\n\n for (const range of affected.ranges) {\n if (!range.events || range.events.length === 0) {\n continue;\n }\n\n const versionRange: VersionRange = {};\n\n for (const event of range.events) {\n if (event.introduced) {\n versionRange.introduced = event.introduced;\n }\n if (event.fixed) {\n versionRange.fixed = event.fixed;\n // Capture the first fixed version we encounter\n if (!fixedVersion) {\n fixedVersion = event.fixed;\n }\n }\n if (event.last_affected) {\n versionRange.lastAffected = event.last_affected;\n }\n }\n\n // Only add ranges that have at least one meaningful field\n if (versionRange.introduced || versionRange.fixed || versionRange.lastAffected) {\n ranges.push(versionRange);\n }\n }\n }\n\n return { ranges, fixedVersion };\n }\n\n /**\n * Extract and truncate the summary from the vulnerability.\n * Prefers the summary field, falls back to details.\n */\n private extractSummary(vuln: OsvVulnerability): string {\n const text = vuln.summary || vuln.details || '';\n if (text.length <= MAX_SUMMARY_LENGTH) {\n return text;\n }\n return text.slice(0, MAX_SUMMARY_LENGTH - 3) + '...';\n }\n}\n\n// \u2500\u2500 Utility Functions \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Combine multiple AbortSignals into one that aborts when any of them aborts.\n */\nfunction combineAbortSignals(...signals: AbortSignal[]): AbortSignal {\n const controller = new AbortController();\n\n for (const signal of signals) {\n if (signal.aborted) {\n controller.abort(signal.reason);\n return controller.signal;\n }\n\n signal.addEventListener('abort', () => controller.abort(signal.reason), { once: true });\n }\n\n return controller.signal;\n}\n\n/**\n * Check if an error is an abort/timeout error.\n */\nfunction isAbortError(error: unknown): boolean {\n if (error instanceof Error) {\n return error.name === 'AbortError' || error.name === 'TimeoutError';\n }\n return false;\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["import_errors", "msg"]
|
|
7
|
+
}
|