kirograph 0.17.0 → 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 -1822
- 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/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/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 +382 -101
- 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 +12 -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 +9 -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 +407 -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 +72 -6
- package/dist/bin/kirograph.js.map +3 -3
- package/dist/compression/tracker.js +80 -0
- package/dist/compression/tracker.js.map +2 -2
- package/dist/config.js +90 -3
- package/dist/config.js.map +2 -2
- package/dist/core/pipeline.js +36 -2
- package/dist/core/pipeline.js.map +2 -2
- package/dist/db/database.js +56 -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 +21 -1
- package/dist/mcp/tool-names.js.map +2 -2
- package/dist/mcp/tools.js +1160 -1
- 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 +2 -1
|
@@ -0,0 +1,255 @@
|
|
|
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 dep_confusion_exports = {};
|
|
20
|
+
__export(dep_confusion_exports, {
|
|
21
|
+
DepConfusionChecker: () => DepConfusionChecker
|
|
22
|
+
});
|
|
23
|
+
module.exports = __toCommonJS(dep_confusion_exports);
|
|
24
|
+
var import_errors = require("../errors");
|
|
25
|
+
const WELL_KNOWN_NPM = [
|
|
26
|
+
"lodash",
|
|
27
|
+
"express",
|
|
28
|
+
"react",
|
|
29
|
+
"axios",
|
|
30
|
+
"webpack",
|
|
31
|
+
"babel",
|
|
32
|
+
"moment",
|
|
33
|
+
"next",
|
|
34
|
+
"vue",
|
|
35
|
+
"angular"
|
|
36
|
+
];
|
|
37
|
+
function levenshtein(a, b) {
|
|
38
|
+
if (a === b) return 0;
|
|
39
|
+
if (a.length === 0) return b.length;
|
|
40
|
+
if (b.length === 0) return a.length;
|
|
41
|
+
const matrix = [];
|
|
42
|
+
for (let i = 0; i <= b.length; i++) matrix[i] = [i];
|
|
43
|
+
for (let j = 0; j <= a.length; j++) matrix[0][j] = j;
|
|
44
|
+
for (let i = 1; i <= b.length; i++) {
|
|
45
|
+
for (let j = 1; j <= a.length; j++) {
|
|
46
|
+
const cost = a[j - 1] === b[i - 1] ? 0 : 1;
|
|
47
|
+
matrix[i][j] = Math.min(
|
|
48
|
+
matrix[i - 1][j] + 1,
|
|
49
|
+
// deletion
|
|
50
|
+
matrix[i][j - 1] + 1,
|
|
51
|
+
// insertion
|
|
52
|
+
matrix[i - 1][j - 1] + cost
|
|
53
|
+
// substitution
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return matrix[b.length][a.length];
|
|
58
|
+
}
|
|
59
|
+
function isTyposquatCandidate(name, wellKnown) {
|
|
60
|
+
const base = name.startsWith("@") ? name.split("/")[1] ?? name : name;
|
|
61
|
+
for (const known of wellKnown) {
|
|
62
|
+
const dist = levenshtein(base.toLowerCase(), known.toLowerCase());
|
|
63
|
+
if (dist > 0 && dist <= 2) return known;
|
|
64
|
+
}
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
const TIMEOUT_MS = 1e4;
|
|
68
|
+
async function checkNpmPublic(name) {
|
|
69
|
+
const controller = new AbortController();
|
|
70
|
+
const timer = setTimeout(() => controller.abort(), TIMEOUT_MS);
|
|
71
|
+
try {
|
|
72
|
+
const encoded = encodeURIComponent(name);
|
|
73
|
+
const resp = await fetch(`https://registry.npmjs.org/${encoded}/latest`, {
|
|
74
|
+
method: "GET",
|
|
75
|
+
signal: controller.signal,
|
|
76
|
+
headers: { "Accept": "application/json" }
|
|
77
|
+
});
|
|
78
|
+
if (!resp.ok) return { exists: false, version: null, publishedAt: null };
|
|
79
|
+
const data = await resp.json();
|
|
80
|
+
const version = data["version"] ?? null;
|
|
81
|
+
const full = await fetch(`https://registry.npmjs.org/${encoded}`, {
|
|
82
|
+
headers: { "Accept": "application/json" }
|
|
83
|
+
});
|
|
84
|
+
let publishedAt = null;
|
|
85
|
+
if (full.ok) {
|
|
86
|
+
const fullData = await full.json();
|
|
87
|
+
const time = fullData["time"] ?? {};
|
|
88
|
+
publishedAt = time["created"] ?? null;
|
|
89
|
+
}
|
|
90
|
+
return { exists: true, version, publishedAt };
|
|
91
|
+
} catch {
|
|
92
|
+
return { exists: false, version: null, publishedAt: null };
|
|
93
|
+
} finally {
|
|
94
|
+
clearTimeout(timer);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
async function checkPypiPublic(name) {
|
|
98
|
+
const controller = new AbortController();
|
|
99
|
+
const timer = setTimeout(() => controller.abort(), TIMEOUT_MS);
|
|
100
|
+
try {
|
|
101
|
+
const resp = await fetch(`https://pypi.org/pypi/${encodeURIComponent(name)}/json`, {
|
|
102
|
+
signal: controller.signal,
|
|
103
|
+
headers: { "Accept": "application/json" }
|
|
104
|
+
});
|
|
105
|
+
if (!resp.ok) return { exists: false, version: null, publishedAt: null };
|
|
106
|
+
const data = await resp.json();
|
|
107
|
+
const info = data["info"];
|
|
108
|
+
const version = info["version"] ?? null;
|
|
109
|
+
return { exists: true, version, publishedAt: null };
|
|
110
|
+
} catch {
|
|
111
|
+
return { exists: false, version: null, publishedAt: null };
|
|
112
|
+
} finally {
|
|
113
|
+
clearTimeout(timer);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
async function checkPublicRegistry(ecosystem, name) {
|
|
117
|
+
const eco = ecosystem.toLowerCase();
|
|
118
|
+
switch (eco) {
|
|
119
|
+
case "npm":
|
|
120
|
+
return checkNpmPublic(name);
|
|
121
|
+
case "pypi":
|
|
122
|
+
case "pip":
|
|
123
|
+
return checkPypiPublic(name);
|
|
124
|
+
default:
|
|
125
|
+
return { exists: false, version: null, publishedAt: null };
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
function detectInternal(packageName, sourceManifests, declaredConstraint) {
|
|
129
|
+
if (declaredConstraint.startsWith("file:") || declaredConstraint.startsWith("./") || declaredConstraint.startsWith("../")) {
|
|
130
|
+
return { isInternal: true, source: "local path" };
|
|
131
|
+
}
|
|
132
|
+
if (declaredConstraint.startsWith("git+") || declaredConstraint.startsWith("git://")) {
|
|
133
|
+
return { isInternal: true, source: "git dependency" };
|
|
134
|
+
}
|
|
135
|
+
for (const manifest of sourceManifests) {
|
|
136
|
+
if (manifest.includes(".kirograph/local") || manifest.includes("local/")) {
|
|
137
|
+
return { isInternal: true, source: "local registry" };
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
const wellKnownScopes = /* @__PURE__ */ new Set([
|
|
141
|
+
"@types",
|
|
142
|
+
"@babel",
|
|
143
|
+
"@jest",
|
|
144
|
+
"@testing-library",
|
|
145
|
+
"@angular",
|
|
146
|
+
"@vue",
|
|
147
|
+
"@react",
|
|
148
|
+
"@emotion",
|
|
149
|
+
"@mui",
|
|
150
|
+
"@chakra-ui",
|
|
151
|
+
"@tailwindcss",
|
|
152
|
+
"@storybook",
|
|
153
|
+
"@vitejs",
|
|
154
|
+
"@rollup",
|
|
155
|
+
"@esbuild",
|
|
156
|
+
"@swc",
|
|
157
|
+
"@aws-sdk",
|
|
158
|
+
"@google-cloud"
|
|
159
|
+
]);
|
|
160
|
+
if (packageName.startsWith("@")) {
|
|
161
|
+
const scope = packageName.split("/")[0];
|
|
162
|
+
if (!wellKnownScopes.has(scope)) {
|
|
163
|
+
return { isInternal: true, source: `private scope ${scope}` };
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
return { isInternal: false, source: "public registry" };
|
|
167
|
+
}
|
|
168
|
+
class DepConfusionChecker {
|
|
169
|
+
constructor(db) {
|
|
170
|
+
this.db = db;
|
|
171
|
+
}
|
|
172
|
+
async check() {
|
|
173
|
+
const rawDb = this.db.getRawDb();
|
|
174
|
+
const rows = rawDb.all(
|
|
175
|
+
`SELECT node_id, package_name, ecosystem, declared_constraint, source_manifests, scope
|
|
176
|
+
FROM sec_dependencies
|
|
177
|
+
WHERE scope = 'production'`
|
|
178
|
+
);
|
|
179
|
+
const findings = [];
|
|
180
|
+
const seen = /* @__PURE__ */ new Set();
|
|
181
|
+
for (const row of rows) {
|
|
182
|
+
const key = `${row.ecosystem}:${row.package_name}`;
|
|
183
|
+
if (seen.has(key)) continue;
|
|
184
|
+
seen.add(key);
|
|
185
|
+
let manifests = [];
|
|
186
|
+
try {
|
|
187
|
+
manifests = JSON.parse(row.source_manifests);
|
|
188
|
+
} catch {
|
|
189
|
+
}
|
|
190
|
+
const { isInternal, source } = detectInternal(
|
|
191
|
+
row.package_name,
|
|
192
|
+
manifests,
|
|
193
|
+
row.declared_constraint
|
|
194
|
+
);
|
|
195
|
+
if (isInternal) {
|
|
196
|
+
let publicInfo = { exists: false, version: null, publishedAt: null };
|
|
197
|
+
try {
|
|
198
|
+
let nameToCheck = row.package_name;
|
|
199
|
+
if (nameToCheck.startsWith("@")) {
|
|
200
|
+
nameToCheck = nameToCheck.split("/")[1] ?? nameToCheck;
|
|
201
|
+
}
|
|
202
|
+
publicInfo = await checkPublicRegistry(row.ecosystem, nameToCheck);
|
|
203
|
+
} catch (err) {
|
|
204
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
205
|
+
(0, import_errors.logWarn)(`[dep-confusion] Registry check failed for ${row.package_name}: ${msg}`);
|
|
206
|
+
}
|
|
207
|
+
if (publicInfo.exists) {
|
|
208
|
+
findings.push({
|
|
209
|
+
packageName: row.package_name,
|
|
210
|
+
ecosystem: row.ecosystem,
|
|
211
|
+
internalSource: source,
|
|
212
|
+
publicExists: true,
|
|
213
|
+
publicVersion: publicInfo.version,
|
|
214
|
+
publicPublishedAt: publicInfo.publishedAt,
|
|
215
|
+
riskLevel: "critical",
|
|
216
|
+
explanation: `Package "${row.package_name}" appears to be an internal dependency (${source}) but a public package with the same name exists in the ${row.ecosystem} registry (version ${publicInfo.version ?? "unknown"}). This is a potential dependency confusion attack vector.`
|
|
217
|
+
});
|
|
218
|
+
continue;
|
|
219
|
+
}
|
|
220
|
+
findings.push({
|
|
221
|
+
packageName: row.package_name,
|
|
222
|
+
ecosystem: row.ecosystem,
|
|
223
|
+
internalSource: source,
|
|
224
|
+
publicExists: false,
|
|
225
|
+
publicVersion: null,
|
|
226
|
+
publicPublishedAt: null,
|
|
227
|
+
riskLevel: "medium",
|
|
228
|
+
explanation: `Package "${row.package_name}" appears to be an internal dependency (${source}). No public package found with the same name, but this should be monitored.`
|
|
229
|
+
});
|
|
230
|
+
continue;
|
|
231
|
+
}
|
|
232
|
+
if (row.ecosystem.toLowerCase() === "npm") {
|
|
233
|
+
const similar = isTyposquatCandidate(row.package_name, WELL_KNOWN_NPM);
|
|
234
|
+
if (similar) {
|
|
235
|
+
findings.push({
|
|
236
|
+
packageName: row.package_name,
|
|
237
|
+
ecosystem: row.ecosystem,
|
|
238
|
+
internalSource: "public registry",
|
|
239
|
+
publicExists: true,
|
|
240
|
+
publicVersion: null,
|
|
241
|
+
publicPublishedAt: null,
|
|
242
|
+
riskLevel: "high",
|
|
243
|
+
explanation: `Package "${row.package_name}" has a name very similar to the well-known package "${similar}" (Levenshtein distance \u2264 2). This may be a typosquatting attempt.`
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
return findings;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
252
|
+
0 && (module.exports = {
|
|
253
|
+
DepConfusionChecker
|
|
254
|
+
});
|
|
255
|
+
//# sourceMappingURL=dep-confusion.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/security/dep-confusion.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Dependency Confusion Checker\n *\n * Detects internal packages whose names exist in public registries\n * (a supply chain attack vector), and flags typosquatting candidates.\n */\n\nimport { logWarn } from '../errors';\nimport type { GraphDatabase } from '../db/database';\n\n// \u2500\u2500 Types \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface DepConfusionFinding {\n packageName: string;\n ecosystem: string;\n internalSource: string; // e.g. \"private registry\" or \"local path\"\n publicExists: boolean;\n publicVersion: string | null;\n publicPublishedAt: string | null;\n riskLevel: 'critical' | 'high' | 'medium';\n explanation: string;\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\n// Well-known packages for typosquatting detection\nconst WELL_KNOWN_NPM: string[] = [\n 'lodash', 'express', 'react', 'axios', 'webpack', 'babel', 'moment',\n 'next', 'vue', 'angular',\n];\n\n// \u2500\u2500 Levenshtein distance (for typosquatting) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction levenshtein(a: string, b: string): number {\n if (a === b) return 0;\n if (a.length === 0) return b.length;\n if (b.length === 0) return a.length;\n\n const matrix: number[][] = [];\n for (let i = 0; i <= b.length; i++) matrix[i] = [i];\n for (let j = 0; j <= a.length; j++) matrix[0]![j] = j;\n\n for (let i = 1; i <= b.length; i++) {\n for (let j = 1; j <= a.length; j++) {\n const cost = a[j - 1] === b[i - 1] ? 0 : 1;\n matrix[i]![j] = Math.min(\n matrix[i - 1]![j]! + 1, // deletion\n matrix[i]![j - 1]! + 1, // insertion\n matrix[i - 1]![j - 1]! + cost, // substitution\n );\n }\n }\n return matrix[b.length]![a.length]!;\n}\n\nfunction isTyposquatCandidate(name: string, wellKnown: string[]): string | null {\n // Strip scoped prefix for comparison\n const base = name.startsWith('@') ? name.split('/')[1] ?? name : name;\n for (const known of wellKnown) {\n const dist = levenshtein(base.toLowerCase(), known.toLowerCase());\n if (dist > 0 && dist <= 2) return known;\n }\n return null;\n}\n\n// \u2500\u2500 Registry HEAD check \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 TIMEOUT_MS = 10_000;\n\ninterface PublicInfo {\n exists: boolean;\n version: string | null;\n publishedAt: string | null;\n}\n\nasync function checkNpmPublic(name: string): Promise<PublicInfo> {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), TIMEOUT_MS);\n try {\n const encoded = encodeURIComponent(name);\n const resp = await fetch(`https://registry.npmjs.org/${encoded}/latest`, {\n method: 'GET',\n signal: controller.signal,\n headers: { 'Accept': 'application/json' },\n });\n if (!resp.ok) return { exists: false, version: null, publishedAt: null };\n const data = await resp.json() as Record<string, unknown>;\n const version = (data['version'] as string) ?? null;\n // Fetch time info\n const full = await fetch(`https://registry.npmjs.org/${encoded}`, {\n headers: { 'Accept': 'application/json' },\n });\n let publishedAt: string | null = null;\n if (full.ok) {\n const fullData = await full.json() as Record<string, unknown>;\n const time = (fullData['time'] as Record<string, string>) ?? {};\n publishedAt = time['created'] ?? null;\n }\n return { exists: true, version, publishedAt };\n } catch {\n return { exists: false, version: null, publishedAt: null };\n } finally {\n clearTimeout(timer);\n }\n}\n\nasync function checkPypiPublic(name: string): Promise<PublicInfo> {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), TIMEOUT_MS);\n try {\n const resp = await fetch(`https://pypi.org/pypi/${encodeURIComponent(name)}/json`, {\n signal: controller.signal,\n headers: { 'Accept': 'application/json' },\n });\n if (!resp.ok) return { exists: false, version: null, publishedAt: null };\n const data = await resp.json() as Record<string, unknown>;\n const info = data['info'] as Record<string, unknown>;\n const version = (info['version'] as string) ?? null;\n return { exists: true, version, publishedAt: null };\n } catch {\n return { exists: false, version: null, publishedAt: null };\n } finally {\n clearTimeout(timer);\n }\n}\n\nasync function checkPublicRegistry(ecosystem: string, name: string): Promise<PublicInfo> {\n const eco = ecosystem.toLowerCase();\n switch (eco) {\n case 'npm': return checkNpmPublic(name);\n case 'pypi':\n case 'pip': return checkPypiPublic(name);\n default:\n // For other ecosystems, we do not have a reliable public lookup\n return { exists: false, version: null, publishedAt: null };\n }\n}\n\n// \u2500\u2500 Internal package detection \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 InternalIndicator {\n isInternal: boolean;\n source: string;\n}\n\nfunction detectInternal(\n packageName: string,\n sourceManifests: string[],\n declaredConstraint: string,\n): InternalIndicator {\n // Local file references\n if (declaredConstraint.startsWith('file:') || declaredConstraint.startsWith('./') || declaredConstraint.startsWith('../')) {\n return { isInternal: true, source: 'local path' };\n }\n if (declaredConstraint.startsWith('git+') || declaredConstraint.startsWith('git://')) {\n return { isInternal: true, source: 'git dependency' };\n }\n\n // Manifest path hints (e.g. a private registry URL)\n for (const manifest of sourceManifests) {\n if (manifest.includes('.kirograph/local') || manifest.includes('local/')) {\n return { isInternal: true, source: 'local registry' };\n }\n }\n\n // Scoped packages with company-like scope names (heuristic)\n // e.g. @mycompany/foo \u2014 not @types, @babel, @jest, etc.\n const wellKnownScopes = new Set([\n '@types', '@babel', '@jest', '@testing-library', '@angular', '@vue',\n '@react', '@emotion', '@mui', '@chakra-ui', '@tailwindcss', '@storybook',\n '@vitejs', '@rollup', '@esbuild', '@swc', '@aws-sdk', '@google-cloud',\n ]);\n\n if (packageName.startsWith('@')) {\n const scope = packageName.split('/')[0]!;\n if (!wellKnownScopes.has(scope)) {\n return { isInternal: true, source: `private scope ${scope}` };\n }\n }\n\n return { isInternal: false, source: 'public registry' };\n}\n\n// \u2500\u2500 DepConfusionChecker \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 DepConfusionChecker {\n constructor(private readonly db: GraphDatabase) {}\n\n async check(): Promise<DepConfusionFinding[]> {\n const rawDb = this.db.getRawDb();\n const rows: Array<{\n node_id: string;\n package_name: string;\n ecosystem: string;\n declared_constraint: string;\n source_manifests: string;\n scope: string;\n }> = rawDb.all(\n `SELECT node_id, package_name, ecosystem, declared_constraint, source_manifests, scope\n FROM sec_dependencies\n WHERE scope = 'production'`,\n );\n\n const findings: DepConfusionFinding[] = [];\n const seen = new Set<string>();\n\n for (const row of rows) {\n const key = `${row.ecosystem}:${row.package_name}`;\n if (seen.has(key)) continue;\n seen.add(key);\n\n let manifests: string[] = [];\n try {\n manifests = JSON.parse(row.source_manifests) as string[];\n } catch {\n // ignore malformed JSON\n }\n\n // \u2500\u2500 1. Internal package confusion \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 const { isInternal, source } = detectInternal(\n row.package_name,\n manifests,\n row.declared_constraint,\n );\n\n if (isInternal) {\n let publicInfo: PublicInfo = { exists: false, version: null, publishedAt: null };\n try {\n // For scoped packages, also check the unscoped name\n let nameToCheck = row.package_name;\n if (nameToCheck.startsWith('@')) {\n nameToCheck = nameToCheck.split('/')[1] ?? nameToCheck;\n }\n publicInfo = await checkPublicRegistry(row.ecosystem, nameToCheck);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n logWarn(`[dep-confusion] Registry check failed for ${row.package_name}: ${msg}`);\n }\n\n if (publicInfo.exists) {\n findings.push({\n packageName: row.package_name,\n ecosystem: row.ecosystem,\n internalSource: source,\n publicExists: true,\n publicVersion: publicInfo.version,\n publicPublishedAt: publicInfo.publishedAt,\n riskLevel: 'critical',\n explanation:\n `Package \"${row.package_name}\" appears to be an internal dependency (${source}) ` +\n `but a public package with the same name exists in the ${row.ecosystem} registry ` +\n `(version ${publicInfo.version ?? 'unknown'}). This is a potential dependency confusion attack vector.`,\n });\n continue;\n }\n\n // Internal package without public counterpart \u2014 medium risk\n findings.push({\n packageName: row.package_name,\n ecosystem: row.ecosystem,\n internalSource: source,\n publicExists: false,\n publicVersion: null,\n publicPublishedAt: null,\n riskLevel: 'medium',\n explanation:\n `Package \"${row.package_name}\" appears to be an internal dependency (${source}). ` +\n `No public package found with the same name, but this should be monitored.`,\n });\n continue;\n }\n\n // \u2500\u2500 2. Typosquatting detection (npm only for now) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n if (row.ecosystem.toLowerCase() === 'npm') {\n const similar = isTyposquatCandidate(row.package_name, WELL_KNOWN_NPM);\n if (similar) {\n findings.push({\n packageName: row.package_name,\n ecosystem: row.ecosystem,\n internalSource: 'public registry',\n publicExists: true,\n publicVersion: null,\n publicPublishedAt: null,\n riskLevel: 'high',\n explanation:\n `Package \"${row.package_name}\" has a name very similar to the well-known package ` +\n `\"${similar}\" (Levenshtein distance \u2264 2). This may be a typosquatting attempt.`,\n });\n }\n }\n }\n\n return findings;\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
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 errors_exports = {};
|
|
20
|
+
__export(errors_exports, {
|
|
21
|
+
ManifestParseError: () => ManifestParseError,
|
|
22
|
+
SecurityError: () => SecurityError,
|
|
23
|
+
VulnDatabaseError: () => VulnDatabaseError
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(errors_exports);
|
|
26
|
+
var import_errors = require("../errors");
|
|
27
|
+
class SecurityError extends import_errors.KiroGraphError {
|
|
28
|
+
constructor(message, context) {
|
|
29
|
+
super(message, "SECURITY_ERROR", context);
|
|
30
|
+
this.name = "SecurityError";
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
class ManifestParseError extends import_errors.KiroGraphError {
|
|
34
|
+
constructor(message, filePath, line) {
|
|
35
|
+
super(message, "MANIFEST_PARSE_ERROR", { filePath, line });
|
|
36
|
+
this.name = "ManifestParseError";
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
class VulnDatabaseError extends import_errors.KiroGraphError {
|
|
40
|
+
constructor(message, database, httpStatus) {
|
|
41
|
+
super(message, "VULN_DATABASE_ERROR", { database, httpStatus });
|
|
42
|
+
this.name = "VulnDatabaseError";
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
46
|
+
0 && (module.exports = {
|
|
47
|
+
ManifestParseError,
|
|
48
|
+
SecurityError,
|
|
49
|
+
VulnDatabaseError
|
|
50
|
+
});
|
|
51
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/security/errors.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * KiroGraph-Sec Error Classes\n *\n * Security-specific error types extending the base KiroGraphError.\n */\n\nimport { KiroGraphError } from '../errors';\n\nexport class SecurityError extends KiroGraphError {\n constructor(message: string, context?: Record<string, unknown>) {\n super(message, 'SECURITY_ERROR', context);\n this.name = 'SecurityError';\n }\n}\n\nexport class ManifestParseError extends KiroGraphError {\n constructor(message: string, filePath: string, line?: number) {\n super(message, 'MANIFEST_PARSE_ERROR', { filePath, line });\n this.name = 'ManifestParseError';\n }\n}\n\nexport class VulnDatabaseError extends KiroGraphError {\n constructor(message: string, database: string, httpStatus?: number) {\n super(message, 'VULN_DATABASE_ERROR', { database, httpStatus });\n this.name = 'VulnDatabaseError';\n }\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAMA,oBAA+B;AAExB,MAAM,sBAAsB,6BAAe;AAAA,EAChD,YAAY,SAAiB,SAAmC;AAC9D,UAAM,SAAS,kBAAkB,OAAO;AACxC,SAAK,OAAO;AAAA,EACd;AACF;AAEO,MAAM,2BAA2B,6BAAe;AAAA,EACrD,YAAY,SAAiB,UAAkB,MAAe;AAC5D,UAAM,SAAS,wBAAwB,EAAE,UAAU,KAAK,CAAC;AACzD,SAAK,OAAO;AAAA,EACd;AACF;AAEO,MAAM,0BAA0B,6BAAe;AAAA,EACpD,YAAY,SAAiB,UAAkB,YAAqB;AAClE,UAAM,SAAS,uBAAuB,EAAE,UAAU,WAAW,CAAC;AAC9D,SAAK,OAAO;AAAA,EACd;AACF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
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 fix_suggestions_exports = {};
|
|
20
|
+
__export(fix_suggestions_exports, {
|
|
21
|
+
buildFixSuggestion: () => buildFixSuggestion,
|
|
22
|
+
formatFixSuggestion: () => formatFixSuggestion
|
|
23
|
+
});
|
|
24
|
+
module.exports = __toCommonJS(fix_suggestions_exports);
|
|
25
|
+
function buildFixSuggestion(ecosystem, packageName, fixedVersion) {
|
|
26
|
+
switch (ecosystem.toLowerCase()) {
|
|
27
|
+
case "npm":
|
|
28
|
+
return `npm install ${packageName}@${fixedVersion}`;
|
|
29
|
+
case "maven": {
|
|
30
|
+
const parts = packageName.split(":");
|
|
31
|
+
if (parts.length === 2) {
|
|
32
|
+
return `Update ${parts[0]}:${parts[1]} to ${fixedVersion} in pom.xml`;
|
|
33
|
+
}
|
|
34
|
+
return `Update ${packageName} to ${fixedVersion} in pom.xml`;
|
|
35
|
+
}
|
|
36
|
+
case "go":
|
|
37
|
+
case "golang":
|
|
38
|
+
return `go get ${packageName}@v${fixedVersion}`;
|
|
39
|
+
case "pypi":
|
|
40
|
+
case "pip":
|
|
41
|
+
return `pip install ${packageName}==${fixedVersion}`;
|
|
42
|
+
case "cargo":
|
|
43
|
+
return `cargo update -p ${packageName} --precise ${fixedVersion}`;
|
|
44
|
+
default:
|
|
45
|
+
return `Upgrade ${packageName} to ${fixedVersion}`;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
function formatFixSuggestion(ecosystem, packageName, fixedVersion) {
|
|
49
|
+
if (!fixedVersion) return "";
|
|
50
|
+
const command = buildFixSuggestion(ecosystem, packageName, fixedVersion);
|
|
51
|
+
return `\u{1F4A1} Fix: ${command}`;
|
|
52
|
+
}
|
|
53
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
54
|
+
0 && (module.exports = {
|
|
55
|
+
buildFixSuggestion,
|
|
56
|
+
formatFixSuggestion
|
|
57
|
+
});
|
|
58
|
+
//# sourceMappingURL=fix-suggestions.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/security/export/fix-suggestions.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Fix Suggestion Builder\n *\n * Generates ecosystem-appropriate upgrade commands for vulnerabilities\n * that have a known fixed version. Reusable by CLI and MCP tools.\n */\n\n/**\n * Build an ecosystem-appropriate fix suggestion command.\n *\n * @param ecosystem - The package ecosystem (npm, maven, go, pypi, cargo)\n * @param packageName - The package name (for maven: groupId:artifactId)\n * @param fixedVersion - The version that fixes the vulnerability\n * @returns A formatted fix command string, or empty string if ecosystem is unknown\n */\nexport function buildFixSuggestion(ecosystem: string, packageName: string, fixedVersion: string): string {\n switch (ecosystem.toLowerCase()) {\n case 'npm':\n return `npm install ${packageName}@${fixedVersion}`;\n case 'maven': {\n // Maven packageName is typically \"groupId:artifactId\"\n const parts = packageName.split(':');\n if (parts.length === 2) {\n return `Update ${parts[0]}:${parts[1]} to ${fixedVersion} in pom.xml`;\n }\n return `Update ${packageName} to ${fixedVersion} in pom.xml`;\n }\n case 'go':\n case 'golang':\n return `go get ${packageName}@v${fixedVersion}`;\n case 'pypi':\n case 'pip':\n return `pip install ${packageName}==${fixedVersion}`;\n case 'cargo':\n return `cargo update -p ${packageName} --precise ${fixedVersion}`;\n default:\n return `Upgrade ${packageName} to ${fixedVersion}`;\n }\n}\n\n/**\n * Format a fix suggestion line for display.\n * Returns the formatted line with the \uD83D\uDCA1 prefix, or empty string if no fixed version.\n */\nexport function formatFixSuggestion(ecosystem: string, packageName: string, fixedVersion: string | null | undefined): string {\n if (!fixedVersion) return '';\n const command = buildFixSuggestion(ecosystem, packageName, fixedVersion);\n return `\uD83D\uDCA1 Fix: ${command}`;\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAeO,SAAS,mBAAmB,WAAmB,aAAqB,cAA8B;AACvG,UAAQ,UAAU,YAAY,GAAG;AAAA,IAC/B,KAAK;AACH,aAAO,eAAe,WAAW,IAAI,YAAY;AAAA,IACnD,KAAK,SAAS;AAEZ,YAAM,QAAQ,YAAY,MAAM,GAAG;AACnC,UAAI,MAAM,WAAW,GAAG;AACtB,eAAO,UAAU,MAAM,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC,OAAO,YAAY;AAAA,MAC1D;AACA,aAAO,UAAU,WAAW,OAAO,YAAY;AAAA,IACjD;AAAA,IACA,KAAK;AAAA,IACL,KAAK;AACH,aAAO,UAAU,WAAW,KAAK,YAAY;AAAA,IAC/C,KAAK;AAAA,IACL,KAAK;AACH,aAAO,eAAe,WAAW,KAAK,YAAY;AAAA,IACpD,KAAK;AACH,aAAO,mBAAmB,WAAW,cAAc,YAAY;AAAA,IACjE;AACE,aAAO,WAAW,WAAW,OAAO,YAAY;AAAA,EACpD;AACF;AAMO,SAAS,oBAAoB,WAAmB,aAAqB,cAAiD;AAC3H,MAAI,CAAC,aAAc,QAAO;AAC1B,QAAM,UAAU,mBAAmB,WAAW,aAAa,YAAY;AACvE,SAAO,kBAAW,OAAO;AAC3B;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var import_vitest = require("vitest");
|
|
3
|
+
var import_fix_suggestions = require("./fix-suggestions");
|
|
4
|
+
(0, import_vitest.describe)("buildFixSuggestion", () => {
|
|
5
|
+
(0, import_vitest.it)("generates npm install command for npm ecosystem", () => {
|
|
6
|
+
(0, import_vitest.expect)((0, import_fix_suggestions.buildFixSuggestion)("npm", "express", "4.18.3")).toBe(
|
|
7
|
+
"npm install express@4.18.3"
|
|
8
|
+
);
|
|
9
|
+
});
|
|
10
|
+
(0, import_vitest.it)("generates maven update instruction for maven ecosystem with groupId:artifactId", () => {
|
|
11
|
+
(0, import_vitest.expect)(
|
|
12
|
+
(0, import_fix_suggestions.buildFixSuggestion)("maven", "org.apache.logging.log4j:log4j-core", "2.17.1")
|
|
13
|
+
).toBe("Update org.apache.logging.log4j:log4j-core to 2.17.1 in pom.xml");
|
|
14
|
+
});
|
|
15
|
+
(0, import_vitest.it)("handles maven package without colon separator", () => {
|
|
16
|
+
(0, import_vitest.expect)((0, import_fix_suggestions.buildFixSuggestion)("maven", "log4j-core", "2.17.1")).toBe(
|
|
17
|
+
"Update log4j-core to 2.17.1 in pom.xml"
|
|
18
|
+
);
|
|
19
|
+
});
|
|
20
|
+
(0, import_vitest.it)("generates go get command for go ecosystem", () => {
|
|
21
|
+
(0, import_vitest.expect)(
|
|
22
|
+
(0, import_fix_suggestions.buildFixSuggestion)("go", "github.com/gin-gonic/gin", "1.9.2")
|
|
23
|
+
).toBe("go get github.com/gin-gonic/gin@v1.9.2");
|
|
24
|
+
});
|
|
25
|
+
(0, import_vitest.it)("generates go get command for golang ecosystem alias", () => {
|
|
26
|
+
(0, import_vitest.expect)(
|
|
27
|
+
(0, import_fix_suggestions.buildFixSuggestion)("golang", "github.com/gin-gonic/gin", "1.9.2")
|
|
28
|
+
).toBe("go get github.com/gin-gonic/gin@v1.9.2");
|
|
29
|
+
});
|
|
30
|
+
(0, import_vitest.it)("generates pip install command for pypi ecosystem", () => {
|
|
31
|
+
(0, import_vitest.expect)((0, import_fix_suggestions.buildFixSuggestion)("pypi", "django", "4.2.1")).toBe(
|
|
32
|
+
"pip install django==4.2.1"
|
|
33
|
+
);
|
|
34
|
+
});
|
|
35
|
+
(0, import_vitest.it)("generates pip install command for pip ecosystem alias", () => {
|
|
36
|
+
(0, import_vitest.expect)((0, import_fix_suggestions.buildFixSuggestion)("pip", "requests", "2.31.0")).toBe(
|
|
37
|
+
"pip install requests==2.31.0"
|
|
38
|
+
);
|
|
39
|
+
});
|
|
40
|
+
(0, import_vitest.it)("generates cargo update command for cargo ecosystem", () => {
|
|
41
|
+
(0, import_vitest.expect)((0, import_fix_suggestions.buildFixSuggestion)("cargo", "serde", "1.0.189")).toBe(
|
|
42
|
+
"cargo update -p serde --precise 1.0.189"
|
|
43
|
+
);
|
|
44
|
+
});
|
|
45
|
+
(0, import_vitest.it)("generates generic upgrade message for unknown ecosystem", () => {
|
|
46
|
+
(0, import_vitest.expect)((0, import_fix_suggestions.buildFixSuggestion)("unknown", "some-pkg", "2.0.0")).toBe(
|
|
47
|
+
"Upgrade some-pkg to 2.0.0"
|
|
48
|
+
);
|
|
49
|
+
});
|
|
50
|
+
(0, import_vitest.it)("is case-insensitive for ecosystem", () => {
|
|
51
|
+
(0, import_vitest.expect)((0, import_fix_suggestions.buildFixSuggestion)("NPM", "express", "4.18.3")).toBe(
|
|
52
|
+
"npm install express@4.18.3"
|
|
53
|
+
);
|
|
54
|
+
(0, import_vitest.expect)((0, import_fix_suggestions.buildFixSuggestion)("Cargo", "serde", "1.0.189")).toBe(
|
|
55
|
+
"cargo update -p serde --precise 1.0.189"
|
|
56
|
+
);
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
(0, import_vitest.describe)("formatFixSuggestion", () => {
|
|
60
|
+
(0, import_vitest.it)("returns formatted line with \u{1F4A1} prefix when fixedVersion is provided", () => {
|
|
61
|
+
const result = (0, import_fix_suggestions.formatFixSuggestion)("npm", "express", "4.18.3");
|
|
62
|
+
(0, import_vitest.expect)(result).toBe("\u{1F4A1} Fix: npm install express@4.18.3");
|
|
63
|
+
});
|
|
64
|
+
(0, import_vitest.it)("returns empty string when fixedVersion is null", () => {
|
|
65
|
+
(0, import_vitest.expect)((0, import_fix_suggestions.formatFixSuggestion)("npm", "express", null)).toBe("");
|
|
66
|
+
});
|
|
67
|
+
(0, import_vitest.it)("returns empty string when fixedVersion is undefined", () => {
|
|
68
|
+
(0, import_vitest.expect)((0, import_fix_suggestions.formatFixSuggestion)("npm", "express", void 0)).toBe("");
|
|
69
|
+
});
|
|
70
|
+
(0, import_vitest.it)("returns empty string when fixedVersion is empty string", () => {
|
|
71
|
+
(0, import_vitest.expect)((0, import_fix_suggestions.formatFixSuggestion)("npm", "express", "")).toBe("");
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
//# sourceMappingURL=fix-suggestions.test.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/security/export/fix-suggestions.test.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Unit tests for fix suggestion builder\n */\nimport { describe, it, expect } from 'vitest';\nimport { buildFixSuggestion, formatFixSuggestion } from './fix-suggestions';\n\ndescribe('buildFixSuggestion', () => {\n it('generates npm install command for npm ecosystem', () => {\n expect(buildFixSuggestion('npm', 'express', '4.18.3')).toBe(\n 'npm install express@4.18.3',\n );\n });\n\n it('generates maven update instruction for maven ecosystem with groupId:artifactId', () => {\n expect(\n buildFixSuggestion('maven', 'org.apache.logging.log4j:log4j-core', '2.17.1'),\n ).toBe('Update org.apache.logging.log4j:log4j-core to 2.17.1 in pom.xml');\n });\n\n it('handles maven package without colon separator', () => {\n expect(buildFixSuggestion('maven', 'log4j-core', '2.17.1')).toBe(\n 'Update log4j-core to 2.17.1 in pom.xml',\n );\n });\n\n it('generates go get command for go ecosystem', () => {\n expect(\n buildFixSuggestion('go', 'github.com/gin-gonic/gin', '1.9.2'),\n ).toBe('go get github.com/gin-gonic/gin@v1.9.2');\n });\n\n it('generates go get command for golang ecosystem alias', () => {\n expect(\n buildFixSuggestion('golang', 'github.com/gin-gonic/gin', '1.9.2'),\n ).toBe('go get github.com/gin-gonic/gin@v1.9.2');\n });\n\n it('generates pip install command for pypi ecosystem', () => {\n expect(buildFixSuggestion('pypi', 'django', '4.2.1')).toBe(\n 'pip install django==4.2.1',\n );\n });\n\n it('generates pip install command for pip ecosystem alias', () => {\n expect(buildFixSuggestion('pip', 'requests', '2.31.0')).toBe(\n 'pip install requests==2.31.0',\n );\n });\n\n it('generates cargo update command for cargo ecosystem', () => {\n expect(buildFixSuggestion('cargo', 'serde', '1.0.189')).toBe(\n 'cargo update -p serde --precise 1.0.189',\n );\n });\n\n it('generates generic upgrade message for unknown ecosystem', () => {\n expect(buildFixSuggestion('unknown', 'some-pkg', '2.0.0')).toBe(\n 'Upgrade some-pkg to 2.0.0',\n );\n });\n\n it('is case-insensitive for ecosystem', () => {\n expect(buildFixSuggestion('NPM', 'express', '4.18.3')).toBe(\n 'npm install express@4.18.3',\n );\n expect(buildFixSuggestion('Cargo', 'serde', '1.0.189')).toBe(\n 'cargo update -p serde --precise 1.0.189',\n );\n });\n});\n\ndescribe('formatFixSuggestion', () => {\n it('returns formatted line with \uD83D\uDCA1 prefix when fixedVersion is provided', () => {\n const result = formatFixSuggestion('npm', 'express', '4.18.3');\n expect(result).toBe('\uD83D\uDCA1 Fix: npm install express@4.18.3');\n });\n\n it('returns empty string when fixedVersion is null', () => {\n expect(formatFixSuggestion('npm', 'express', null)).toBe('');\n });\n\n it('returns empty string when fixedVersion is undefined', () => {\n expect(formatFixSuggestion('npm', 'express', undefined)).toBe('');\n });\n\n it('returns empty string when fixedVersion is empty string', () => {\n expect(formatFixSuggestion('npm', 'express', '')).toBe('');\n });\n});\n"],
|
|
5
|
+
"mappings": ";AAGA,oBAAqC;AACrC,6BAAwD;AAAA,IAExD,wBAAS,sBAAsB,MAAM;AACnC,wBAAG,mDAAmD,MAAM;AAC1D,kCAAO,2CAAmB,OAAO,WAAW,QAAQ,CAAC,EAAE;AAAA,MACrD;AAAA,IACF;AAAA,EACF,CAAC;AAED,wBAAG,kFAAkF,MAAM;AACzF;AAAA,UACE,2CAAmB,SAAS,uCAAuC,QAAQ;AAAA,IAC7E,EAAE,KAAK,iEAAiE;AAAA,EAC1E,CAAC;AAED,wBAAG,iDAAiD,MAAM;AACxD,kCAAO,2CAAmB,SAAS,cAAc,QAAQ,CAAC,EAAE;AAAA,MAC1D;AAAA,IACF;AAAA,EACF,CAAC;AAED,wBAAG,6CAA6C,MAAM;AACpD;AAAA,UACE,2CAAmB,MAAM,4BAA4B,OAAO;AAAA,IAC9D,EAAE,KAAK,wCAAwC;AAAA,EACjD,CAAC;AAED,wBAAG,uDAAuD,MAAM;AAC9D;AAAA,UACE,2CAAmB,UAAU,4BAA4B,OAAO;AAAA,IAClE,EAAE,KAAK,wCAAwC;AAAA,EACjD,CAAC;AAED,wBAAG,oDAAoD,MAAM;AAC3D,kCAAO,2CAAmB,QAAQ,UAAU,OAAO,CAAC,EAAE;AAAA,MACpD;AAAA,IACF;AAAA,EACF,CAAC;AAED,wBAAG,yDAAyD,MAAM;AAChE,kCAAO,2CAAmB,OAAO,YAAY,QAAQ,CAAC,EAAE;AAAA,MACtD;AAAA,IACF;AAAA,EACF,CAAC;AAED,wBAAG,sDAAsD,MAAM;AAC7D,kCAAO,2CAAmB,SAAS,SAAS,SAAS,CAAC,EAAE;AAAA,MACtD;AAAA,IACF;AAAA,EACF,CAAC;AAED,wBAAG,2DAA2D,MAAM;AAClE,kCAAO,2CAAmB,WAAW,YAAY,OAAO,CAAC,EAAE;AAAA,MACzD;AAAA,IACF;AAAA,EACF,CAAC;AAED,wBAAG,qCAAqC,MAAM;AAC5C,kCAAO,2CAAmB,OAAO,WAAW,QAAQ,CAAC,EAAE;AAAA,MACrD;AAAA,IACF;AACA,kCAAO,2CAAmB,SAAS,SAAS,SAAS,CAAC,EAAE;AAAA,MACtD;AAAA,IACF;AAAA,EACF,CAAC;AACH,CAAC;AAAA,IAED,wBAAS,uBAAuB,MAAM;AACpC,wBAAG,8EAAuE,MAAM;AAC9E,UAAM,aAAS,4CAAoB,OAAO,WAAW,QAAQ;AAC7D,8BAAO,MAAM,EAAE,KAAK,2CAAoC;AAAA,EAC1D,CAAC;AAED,wBAAG,kDAAkD,MAAM;AACzD,kCAAO,4CAAoB,OAAO,WAAW,IAAI,CAAC,EAAE,KAAK,EAAE;AAAA,EAC7D,CAAC;AAED,wBAAG,uDAAuD,MAAM;AAC9D,kCAAO,4CAAoB,OAAO,WAAW,MAAS,CAAC,EAAE,KAAK,EAAE;AAAA,EAClE,CAAC;AAED,wBAAG,0DAA0D,MAAM;AACjE,kCAAO,4CAAoB,OAAO,WAAW,EAAE,CAAC,EAAE,KAAK,EAAE;AAAA,EAC3D,CAAC;AACH,CAAC;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|