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,159 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
var hex_exports = {};
|
|
30
|
+
__export(hex_exports, {
|
|
31
|
+
parseHexManifest: () => parseHexManifest
|
|
32
|
+
});
|
|
33
|
+
module.exports = __toCommonJS(hex_exports);
|
|
34
|
+
var fs = __toESM(require("fs"));
|
|
35
|
+
var path = __toESM(require("path"));
|
|
36
|
+
var import_errors = require("../../../errors");
|
|
37
|
+
async function parseHexManifest(manifestPath, projectRoot) {
|
|
38
|
+
const manifestDir = path.dirname(manifestPath);
|
|
39
|
+
const relativeManifest = path.relative(projectRoot, manifestPath).replace(/\\/g, "/");
|
|
40
|
+
let content;
|
|
41
|
+
try {
|
|
42
|
+
content = fs.readFileSync(manifestPath, "utf8");
|
|
43
|
+
} catch (err) {
|
|
44
|
+
(0, import_errors.logWarn)(`[sec:hex] Failed to read ${relativeManifest}: ${err instanceof Error ? err.message : String(err)}`);
|
|
45
|
+
return [];
|
|
46
|
+
}
|
|
47
|
+
const resolvedVersions = loadResolvedVersions(manifestDir);
|
|
48
|
+
const rawDeps = extractDepsFromMixExs(content, relativeManifest);
|
|
49
|
+
const dependencies = [];
|
|
50
|
+
for (const dep of rawDeps) {
|
|
51
|
+
const resolvedVersion = resolvedVersions.get(dep.name);
|
|
52
|
+
dependencies.push({
|
|
53
|
+
name: dep.name,
|
|
54
|
+
declaredConstraint: dep.constraint,
|
|
55
|
+
resolvedVersion,
|
|
56
|
+
scope: dep.scope,
|
|
57
|
+
ecosystem: "hex",
|
|
58
|
+
sourceManifest: relativeManifest
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
return dependencies;
|
|
62
|
+
}
|
|
63
|
+
function extractDepsFromMixExs(content, relativeManifest) {
|
|
64
|
+
const deps = [];
|
|
65
|
+
const depsBody = extractDepsFunctionBody(content, relativeManifest);
|
|
66
|
+
if (!depsBody) {
|
|
67
|
+
(0, import_errors.logWarn)(`[sec:hex] Could not locate deps function in ${relativeManifest}`);
|
|
68
|
+
return [];
|
|
69
|
+
}
|
|
70
|
+
const tuplePattern = /\{:([a-zA-Z0-9_]+)\s*,([^}]*)\}/g;
|
|
71
|
+
let match;
|
|
72
|
+
while ((match = tuplePattern.exec(depsBody)) !== null) {
|
|
73
|
+
const name = match[1];
|
|
74
|
+
const tupleBody = match[2];
|
|
75
|
+
if (isGitOrPathDep(tupleBody)) continue;
|
|
76
|
+
const version = extractVersionFromTuple(tupleBody);
|
|
77
|
+
if (!version) {
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
const scope = extractScopeFromTuple(tupleBody);
|
|
81
|
+
deps.push({ name, constraint: version, scope });
|
|
82
|
+
}
|
|
83
|
+
return deps;
|
|
84
|
+
}
|
|
85
|
+
function extractDepsFunctionBody(content, relativeManifest) {
|
|
86
|
+
const funcMatch = content.match(/def[p]?\s+deps\s+do([\s\S]*?)^ end/m);
|
|
87
|
+
if (funcMatch) {
|
|
88
|
+
return funcMatch[1];
|
|
89
|
+
}
|
|
90
|
+
const inlineMatch = content.match(/def[p]?\s+deps,\s*do:\s*\[([\s\S]*?)\]/);
|
|
91
|
+
if (inlineMatch) {
|
|
92
|
+
return inlineMatch[1];
|
|
93
|
+
}
|
|
94
|
+
const listMatch = content.match(/def[p]?\s+deps\s+do\s*\[([\s\S]*?)\]\s*end/);
|
|
95
|
+
if (listMatch) {
|
|
96
|
+
return listMatch[1];
|
|
97
|
+
}
|
|
98
|
+
(0, import_errors.logWarn)(`[sec:hex] No deps function found in ${relativeManifest} \u2014 trying full file scan`);
|
|
99
|
+
return content;
|
|
100
|
+
}
|
|
101
|
+
function isGitOrPathDep(tupleBody) {
|
|
102
|
+
return /\bgit:\s*"/.test(tupleBody) || /\bpath:\s*"/.test(tupleBody);
|
|
103
|
+
}
|
|
104
|
+
function extractVersionFromTuple(tupleBody) {
|
|
105
|
+
const versionMatch = tupleBody.match(/^\s*"([^"]+)"/);
|
|
106
|
+
if (versionMatch) {
|
|
107
|
+
return versionMatch[1].trim();
|
|
108
|
+
}
|
|
109
|
+
return null;
|
|
110
|
+
}
|
|
111
|
+
function extractScopeFromTuple(tupleBody) {
|
|
112
|
+
const onlyMatch = tupleBody.match(/\bonly\s*:\s*(.+?)(?:,\s*\w+:|$)/s);
|
|
113
|
+
if (!onlyMatch) return "production";
|
|
114
|
+
const onlyValue = onlyMatch[1].trim();
|
|
115
|
+
if (onlyValue.startsWith("[")) {
|
|
116
|
+
const atoms = onlyValue.match(/:(\w+)/g) || [];
|
|
117
|
+
const values = atoms.map((a) => a.slice(1));
|
|
118
|
+
if (values.some((v) => v === "dev" || v === "test")) {
|
|
119
|
+
return "development";
|
|
120
|
+
}
|
|
121
|
+
return "production";
|
|
122
|
+
}
|
|
123
|
+
const atom = onlyValue.match(/^:(\w+)/);
|
|
124
|
+
if (atom) {
|
|
125
|
+
if (atom[1] === "dev" || atom[1] === "test") return "development";
|
|
126
|
+
return "production";
|
|
127
|
+
}
|
|
128
|
+
return "production";
|
|
129
|
+
}
|
|
130
|
+
function loadResolvedVersions(manifestDir) {
|
|
131
|
+
const map = /* @__PURE__ */ new Map();
|
|
132
|
+
const lockPath = path.join(manifestDir, "mix.lock");
|
|
133
|
+
if (!fs.existsSync(lockPath)) {
|
|
134
|
+
return map;
|
|
135
|
+
}
|
|
136
|
+
try {
|
|
137
|
+
const lockContent = fs.readFileSync(lockPath, "utf8");
|
|
138
|
+
extractFromMixLock(lockContent, map);
|
|
139
|
+
} catch (err) {
|
|
140
|
+
(0, import_errors.logWarn)(`[sec:hex] Failed to parse mix.lock: ${err instanceof Error ? err.message : String(err)}`);
|
|
141
|
+
}
|
|
142
|
+
return map;
|
|
143
|
+
}
|
|
144
|
+
function extractFromMixLock(content, map) {
|
|
145
|
+
const lockEntryPattern = /^\s*"([^"]+)"\s*=>\s*\{:hex\s*,\s*:[a-zA-Z0-9_]+\s*,\s*"([^"]+)"/gm;
|
|
146
|
+
let match;
|
|
147
|
+
while ((match = lockEntryPattern.exec(content)) !== null) {
|
|
148
|
+
const name = match[1];
|
|
149
|
+
const version = match[2];
|
|
150
|
+
if (!map.has(name)) {
|
|
151
|
+
map.set(name, version);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
156
|
+
0 && (module.exports = {
|
|
157
|
+
parseHexManifest
|
|
158
|
+
});
|
|
159
|
+
//# sourceMappingURL=hex.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/security/manifest/plugins/hex.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Elixir/Hex Version Extraction Plugin for KiroGraph-Sec\n *\n * Parses mix.exs manifests to extract Elixir package declarations with\n * version constraints, scopes, and resolved versions from mix.lock.\n *\n * Handles:\n * - `{:package_name, \"~> 1.0\"}` \u2014 standard version constraint\n * - `{:package_name, \">= 1.0.0\"}` \u2014 range constraint\n * - `{:package_name, \"1.0.0\"}` \u2014 exact version\n * - `{:package_name, \"~> 1.0\", only: [:dev, :test]}` \u2192 'development' scope\n * - `{:package_name, \"~> 1.0\", only: :dev}` \u2192 'development' scope\n * - Skips git and path dependencies\n */\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport type { ParsedDependency } from '../../types';\nimport { logWarn } from '../../../errors';\n\n/**\n * Resolved version map: package name \u2192 resolved version string.\n * Built from mix.lock.\n */\ntype ResolvedVersionMap = Map<string, string>;\n\n/**\n * Parse a mix.exs manifest and extract package declarations with\n * version constraints, scopes, and resolved versions from mix.lock.\n *\n * @param manifestPath - Absolute path to the mix.exs file\n * @param projectRoot - Absolute path to the project root directory\n * @returns Array of parsed dependencies with version and scope information\n */\nexport async function parseHexManifest(\n manifestPath: string,\n projectRoot: string,\n): Promise<ParsedDependency[]> {\n const manifestDir = path.dirname(manifestPath);\n const relativeManifest = path.relative(projectRoot, manifestPath).replace(/\\\\/g, '/');\n\n // Read the mix.exs content\n let content: string;\n try {\n content = fs.readFileSync(manifestPath, 'utf8');\n } catch (err) {\n logWarn(`[sec:hex] Failed to read ${relativeManifest}: ${err instanceof Error ? err.message : String(err)}`);\n return [];\n }\n\n // Attempt to load resolved versions from mix.lock\n const resolvedVersions = loadResolvedVersions(manifestDir);\n\n // Extract dependencies from the deps function\n const rawDeps = extractDepsFromMixExs(content, relativeManifest);\n const dependencies: ParsedDependency[] = [];\n\n for (const dep of rawDeps) {\n const resolvedVersion = resolvedVersions.get(dep.name);\n dependencies.push({\n name: dep.name,\n declaredConstraint: dep.constraint,\n resolvedVersion,\n scope: dep.scope,\n ecosystem: 'hex',\n sourceManifest: relativeManifest,\n });\n }\n\n return dependencies;\n}\n\n/**\n * A raw dependency entry extracted from mix.exs.\n */\ninterface RawDependency {\n name: string;\n constraint: string;\n scope: ParsedDependency['scope'];\n}\n\n/**\n * Extract dependencies from mix.exs content.\n *\n * Locates the `defp deps do` function and parses each dependency tuple.\n * Also handles `def deps do` (public deps function).\n *\n * Each dep tuple may span multiple lines, so we work with the full\n * content after extracting the deps list body.\n */\nfunction extractDepsFromMixExs(content: string, relativeManifest: string): RawDependency[] {\n const deps: RawDependency[] = [];\n\n // Find the deps function body \u2014 match `defp deps do` or `def deps do`\n // and extract up to the matching `end`\n const depsBody = extractDepsFunctionBody(content, relativeManifest);\n if (!depsBody) {\n logWarn(`[sec:hex] Could not locate deps function in ${relativeManifest}`);\n return [];\n }\n\n // Match individual dependency tuples: {:name, \"version\", ...optional...}\n // The tuple may contain nested content, so we match balanced braces roughly\n const tuplePattern = /\\{:([a-zA-Z0-9_]+)\\s*,([^}]*)\\}/g;\n let match: RegExpExecArray | null;\n\n while ((match = tuplePattern.exec(depsBody)) !== null) {\n const name = match[1];\n const tupleBody = match[2];\n\n // Skip git/path dependencies\n if (isGitOrPathDep(tupleBody)) continue;\n\n const version = extractVersionFromTuple(tupleBody);\n if (!version) {\n // Might be a non-version dep (e.g. manager: :rebar3) \u2014 skip silently\n continue;\n }\n\n const scope = extractScopeFromTuple(tupleBody);\n deps.push({ name, constraint: version, scope });\n }\n\n return deps;\n}\n\n/**\n * Extract the body of the `deps` function from mix.exs.\n * Returns the content between the `[` and closing `]` of the deps list,\n * or null if the deps function cannot be located.\n */\nfunction extractDepsFunctionBody(content: string, relativeManifest: string): string | null {\n // Match `defp deps do` or `def deps do` followed by content and `end`\n const funcMatch = content.match(/def[p]?\\s+deps\\s+do([\\s\\S]*?)^ end/m);\n if (funcMatch) {\n return funcMatch[1];\n }\n\n // Alternative: `defp deps,` with a list returned directly (single-expression)\n // e.g. `def deps, do: [...]`\n const inlineMatch = content.match(/def[p]?\\s+deps,\\s*do:\\s*\\[([\\s\\S]*?)\\]/);\n if (inlineMatch) {\n return inlineMatch[1];\n }\n\n // Also try matching a `[...]` list inside the function\n const listMatch = content.match(/def[p]?\\s+deps\\s+do\\s*\\[([\\s\\S]*?)\\]\\s*end/);\n if (listMatch) {\n return listMatch[1];\n }\n\n logWarn(`[sec:hex] No deps function found in ${relativeManifest} \u2014 trying full file scan`);\n // Last resort: scan entire file for dep tuples (less accurate but better than nothing)\n return content;\n}\n\n/**\n * Determine if a dependency tuple body represents a git or path dependency.\n * These lack a standard version string and should be skipped.\n */\nfunction isGitOrPathDep(tupleBody: string): boolean {\n return /\\bgit:\\s*\"/.test(tupleBody) || /\\bpath:\\s*\"/.test(tupleBody);\n}\n\n/**\n * Extract the version constraint string from a dependency tuple body.\n * The first string literal in the tuple body is taken as the version.\n *\n * Returns null if no version string is found (e.g. pure option tuples).\n */\nfunction extractVersionFromTuple(tupleBody: string): string | null {\n // Match the first quoted string in the tuple body\n const versionMatch = tupleBody.match(/^\\s*\"([^\"]+)\"/);\n if (versionMatch) {\n return versionMatch[1].trim();\n }\n return null;\n}\n\n/**\n * Extract the scope from a dependency tuple body by inspecting the `only:` option.\n *\n * `only: [:dev, :test]` \u2192 'development'\n * `only: :dev` \u2192 'development'\n * `only: :test` \u2192 'development'\n * `only: :prod` \u2192 'production'\n * No `only:` option \u2192 'production'\n */\nfunction extractScopeFromTuple(tupleBody: string): ParsedDependency['scope'] {\n const onlyMatch = tupleBody.match(/\\bonly\\s*:\\s*(.+?)(?:,\\s*\\w+:|$)/s);\n if (!onlyMatch) return 'production';\n\n const onlyValue = onlyMatch[1].trim();\n\n // List form: [:dev, :test] or [:test, :dev, ...]\n if (onlyValue.startsWith('[')) {\n const atoms = onlyValue.match(/:(\\w+)/g) || [];\n const values = atoms.map((a) => a.slice(1));\n if (values.some((v) => v === 'dev' || v === 'test')) {\n return 'development';\n }\n return 'production';\n }\n\n // Atom form: :dev or :test or :prod\n const atom = onlyValue.match(/^:(\\w+)/);\n if (atom) {\n if (atom[1] === 'dev' || atom[1] === 'test') return 'development';\n return 'production';\n }\n\n return 'production';\n}\n\n/**\n * Attempt to load resolved versions from mix.lock in the given directory.\n * Returns an empty map if mix.lock is not available.\n *\n * mix.lock format:\n * ```elixir\n * %{\n * \"package\" => {:hex, :package_name, \"1.2.3\", \"hash\", ...},\n * \"another\" => {:hex, :another, \"2.0.0\", ...},\n * }\n * ```\n */\nfunction loadResolvedVersions(manifestDir: string): ResolvedVersionMap {\n const map: ResolvedVersionMap = new Map();\n\n const lockPath = path.join(manifestDir, 'mix.lock');\n if (!fs.existsSync(lockPath)) {\n return map;\n }\n\n try {\n const lockContent = fs.readFileSync(lockPath, 'utf8');\n extractFromMixLock(lockContent, map);\n } catch (err) {\n logWarn(`[sec:hex] Failed to parse mix.lock: ${err instanceof Error ? err.message : String(err)}`);\n }\n\n return map;\n}\n\n/**\n * Extract resolved versions from mix.lock content.\n *\n * mix.lock lines follow the pattern:\n * ` \"package_name\" => {:hex, :package_atom, \"1.2.3\", \"checksum\", [...]},`\n *\n * We extract the outer quoted key and the third positional element (version string).\n */\nfunction extractFromMixLock(content: string, map: ResolvedVersionMap): void {\n // Match: \"name\" => {:hex, :name_atom, \"version\", ...\n const lockEntryPattern = /^\\s*\"([^\"]+)\"\\s*=>\\s*\\{:hex\\s*,\\s*:[a-zA-Z0-9_]+\\s*,\\s*\"([^\"]+)\"/gm;\n let match: RegExpExecArray | null;\n\n while ((match = lockEntryPattern.exec(content)) !== null) {\n const name = match[1];\n const version = match[2];\n if (!map.has(name)) {\n map.set(name, version);\n }\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
var maven_exports = {};
|
|
30
|
+
__export(maven_exports, {
|
|
31
|
+
parseMavenManifest: () => parseMavenManifest
|
|
32
|
+
});
|
|
33
|
+
module.exports = __toCommonJS(maven_exports);
|
|
34
|
+
var fs = __toESM(require("fs"));
|
|
35
|
+
var path = __toESM(require("path"));
|
|
36
|
+
var import_errors = require("../../../errors");
|
|
37
|
+
function mapMavenScope(mavenScope) {
|
|
38
|
+
if (!mavenScope || mavenScope.trim() === "") {
|
|
39
|
+
return "production";
|
|
40
|
+
}
|
|
41
|
+
const normalized = mavenScope.trim().toLowerCase();
|
|
42
|
+
switch (normalized) {
|
|
43
|
+
case "compile":
|
|
44
|
+
case "runtime":
|
|
45
|
+
return "production";
|
|
46
|
+
case "test":
|
|
47
|
+
return "development";
|
|
48
|
+
case "provided":
|
|
49
|
+
case "system":
|
|
50
|
+
return "optional";
|
|
51
|
+
default:
|
|
52
|
+
return "production";
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
function extractXmlElement(xml, tagName) {
|
|
56
|
+
const regex = new RegExp(`<${tagName}>([^<]*)</${tagName}>`);
|
|
57
|
+
const match = xml.match(regex);
|
|
58
|
+
return match ? match[1].trim() : void 0;
|
|
59
|
+
}
|
|
60
|
+
async function parseMavenManifest(manifestPath, projectRoot) {
|
|
61
|
+
const relativeManifest = path.relative(projectRoot, manifestPath).replace(/\\/g, "/");
|
|
62
|
+
let content;
|
|
63
|
+
try {
|
|
64
|
+
content = fs.readFileSync(manifestPath, "utf8");
|
|
65
|
+
} catch (err) {
|
|
66
|
+
(0, import_errors.logWarn)(`[sec:maven] Failed to read ${relativeManifest}: ${err instanceof Error ? err.message : String(err)}`);
|
|
67
|
+
return [];
|
|
68
|
+
}
|
|
69
|
+
if (!content.includes("<project")) {
|
|
70
|
+
(0, import_errors.logWarn)(`[sec:maven] Invalid pom.xml structure at ${relativeManifest} \u2014 missing <project> element`);
|
|
71
|
+
return [];
|
|
72
|
+
}
|
|
73
|
+
const license = extractMavenLicense(content);
|
|
74
|
+
const dependencies = [];
|
|
75
|
+
const dependencyBlocks = content.matchAll(/<dependency>([\s\S]*?)<\/dependency>/g);
|
|
76
|
+
for (const block of dependencyBlocks) {
|
|
77
|
+
const depXml = block[1];
|
|
78
|
+
const groupId = extractXmlElement(depXml, "groupId");
|
|
79
|
+
const artifactId = extractXmlElement(depXml, "artifactId");
|
|
80
|
+
const version = extractXmlElement(depXml, "version");
|
|
81
|
+
const scope = extractXmlElement(depXml, "scope");
|
|
82
|
+
if (!groupId || groupId.trim() === "") {
|
|
83
|
+
(0, import_errors.logWarn)(`[sec:maven] Missing groupId in dependency at ${relativeManifest} \u2014 skipping`);
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
if (!artifactId || artifactId.trim() === "") {
|
|
87
|
+
(0, import_errors.logWarn)(`[sec:maven] Missing artifactId in dependency at ${relativeManifest} \u2014 skipping`);
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
if (groupId.includes("${") || artifactId.includes("${")) {
|
|
91
|
+
(0, import_errors.logWarn)(`[sec:maven] Unresolved property in dependency ${groupId}:${artifactId} at ${relativeManifest} \u2014 skipping`);
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
const name = `${groupId}:${artifactId}`;
|
|
95
|
+
let declaredConstraint;
|
|
96
|
+
if (version && version.trim() !== "" && !version.includes("${")) {
|
|
97
|
+
declaredConstraint = version.trim();
|
|
98
|
+
} else {
|
|
99
|
+
declaredConstraint = version && !version.includes("${") ? version.trim() : "";
|
|
100
|
+
}
|
|
101
|
+
const mappedScope = mapMavenScope(scope);
|
|
102
|
+
dependencies.push({
|
|
103
|
+
name,
|
|
104
|
+
declaredConstraint,
|
|
105
|
+
resolvedVersion: declaredConstraint || void 0,
|
|
106
|
+
scope: mappedScope,
|
|
107
|
+
ecosystem: "maven",
|
|
108
|
+
sourceManifest: relativeManifest,
|
|
109
|
+
...license !== void 0 ? { license } : {}
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
return dependencies;
|
|
113
|
+
}
|
|
114
|
+
function extractMavenLicense(content) {
|
|
115
|
+
const licensesMatch = content.match(/<licenses\b[^>]*>([\s\S]*?)<\/licenses>/i);
|
|
116
|
+
if (!licensesMatch) return void 0;
|
|
117
|
+
const licenseBlock = licensesMatch[1];
|
|
118
|
+
const nameMatch = licenseBlock.match(/<name>([^<]+)<\/name>/i);
|
|
119
|
+
if (nameMatch && nameMatch[1].trim() !== "") {
|
|
120
|
+
return nameMatch[1].trim();
|
|
121
|
+
}
|
|
122
|
+
return void 0;
|
|
123
|
+
}
|
|
124
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
125
|
+
0 && (module.exports = {
|
|
126
|
+
parseMavenManifest
|
|
127
|
+
});
|
|
128
|
+
//# sourceMappingURL=maven.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/security/manifest/plugins/maven.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Maven Version Extraction Plugin for KiroGraph-Sec\n *\n * Extends the existing architecture maven parser to extract version constraints,\n * dependency scopes, and groupId/artifactId for security analysis.\n *\n * Reuses `mavenParser` from `src/architecture/manifest/maven.ts` for discovery and\n * basic parsing, then layers on version/scope extraction from pom.xml.\n */\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport type { ParsedDependency } from '../../types';\nimport { logWarn } from '../../../errors';\n\n/**\n * Maven scope to ParsedDependency scope mapping.\n *\n * - compile (default), runtime \u2192 production\n * - test \u2192 development\n * - provided, system \u2192 optional\n */\nfunction mapMavenScope(mavenScope: string | undefined): ParsedDependency['scope'] {\n if (!mavenScope || mavenScope.trim() === '') {\n return 'production';\n }\n\n const normalized = mavenScope.trim().toLowerCase();\n switch (normalized) {\n case 'compile':\n case 'runtime':\n return 'production';\n case 'test':\n return 'development';\n case 'provided':\n case 'system':\n return 'optional';\n default:\n // Unknown scope defaults to production\n return 'production';\n }\n}\n\n/**\n * Extract text content from an XML element by tag name within a given XML fragment.\n * Returns undefined if the element is not found.\n */\nfunction extractXmlElement(xml: string, tagName: string): string | undefined {\n const regex = new RegExp(`<${tagName}>([^<]*)</${tagName}>`);\n const match = xml.match(regex);\n return match ? match[1].trim() : undefined;\n}\n\n/**\n * Parse a Maven pom.xml manifest and extract dependency declarations\n * with groupId, artifactId, version constraints, and scopes.\n *\n * @param manifestPath - Absolute path to the pom.xml file\n * @param projectRoot - Absolute path to the project root directory\n * @returns Array of parsed dependencies with version and scope information\n */\nexport async function parseMavenManifest(\n manifestPath: string,\n projectRoot: string,\n): Promise<ParsedDependency[]> {\n const relativeManifest = path.relative(projectRoot, manifestPath).replace(/\\\\/g, '/');\n\n // Read the pom.xml content\n let content: string;\n try {\n content = fs.readFileSync(manifestPath, 'utf8');\n } catch (err) {\n logWarn(`[sec:maven] Failed to read ${relativeManifest}: ${err instanceof Error ? err.message : String(err)}`);\n return [];\n }\n\n // Validate basic XML structure\n if (!content.includes('<project')) {\n logWarn(`[sec:maven] Invalid pom.xml structure at ${relativeManifest} \u2014 missing <project> element`);\n return [];\n }\n\n // Extract the project-level license\n const license = extractMavenLicense(content);\n\n // Extract all <dependency> blocks from the <dependencies> sections\n const dependencies: ParsedDependency[] = [];\n\n // Match all <dependency>...</dependency> blocks\n const dependencyBlocks = content.matchAll(/<dependency>([\\s\\S]*?)<\\/dependency>/g);\n\n for (const block of dependencyBlocks) {\n const depXml = block[1];\n\n const groupId = extractXmlElement(depXml, 'groupId');\n const artifactId = extractXmlElement(depXml, 'artifactId');\n const version = extractXmlElement(depXml, 'version');\n const scope = extractXmlElement(depXml, 'scope');\n\n // Validate required fields\n if (!groupId || groupId.trim() === '') {\n logWarn(`[sec:maven] Missing groupId in dependency at ${relativeManifest} \u2014 skipping`);\n continue;\n }\n\n if (!artifactId || artifactId.trim() === '') {\n logWarn(`[sec:maven] Missing artifactId in dependency at ${relativeManifest} \u2014 skipping`);\n continue;\n }\n\n // Skip dependencies with unresolved Maven properties (e.g. ${project.version})\n if (groupId.includes('${') || artifactId.includes('${')) {\n logWarn(`[sec:maven] Unresolved property in dependency ${groupId}:${artifactId} at ${relativeManifest} \u2014 skipping`);\n continue;\n }\n\n // Build the dependency name as groupId:artifactId (Maven convention)\n const name = `${groupId}:${artifactId}`;\n\n // Version constraint \u2014 may be absent (managed by parent POM or BOM)\n let declaredConstraint: string;\n if (version && version.trim() !== '' && !version.includes('${')) {\n declaredConstraint = version.trim();\n } else {\n // No version or unresolved property \u2014 use empty string to indicate managed externally\n declaredConstraint = version && !version.includes('${') ? version.trim() : '';\n }\n\n const mappedScope = mapMavenScope(scope);\n\n dependencies.push({\n name,\n declaredConstraint,\n resolvedVersion: declaredConstraint || undefined,\n scope: mappedScope,\n ecosystem: 'maven',\n sourceManifest: relativeManifest,\n ...(license !== undefined ? { license } : {}),\n });\n }\n\n return dependencies;\n}\n\n/**\n * Extract the first license name from a pom.xml <licenses> block.\n * Looks for: <licenses><license><name>...</name></license></licenses>\n */\nfunction extractMavenLicense(content: string): string | undefined {\n const licensesMatch = content.match(/<licenses\\b[^>]*>([\\s\\S]*?)<\\/licenses>/i);\n if (!licensesMatch) return undefined;\n const licenseBlock = licensesMatch[1];\n const nameMatch = licenseBlock.match(/<name>([^<]+)<\\/name>/i);\n if (nameMatch && nameMatch[1].trim() !== '') {\n return nameMatch[1].trim();\n }\n return undefined;\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|