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,237 @@
|
|
|
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 __copyProps = (to, from, except, desc) => {
|
|
9
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
10
|
+
for (let key of __getOwnPropNames(from))
|
|
11
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
12
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
13
|
+
}
|
|
14
|
+
return to;
|
|
15
|
+
};
|
|
16
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
17
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
18
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
19
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
20
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
21
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
22
|
+
mod
|
|
23
|
+
));
|
|
24
|
+
var import_vitest = require("vitest");
|
|
25
|
+
var fs = __toESM(require("fs"));
|
|
26
|
+
var path = __toESM(require("path"));
|
|
27
|
+
var os = __toESM(require("os"));
|
|
28
|
+
var import_integrator = require("./integrator");
|
|
29
|
+
var import_database = require("../db/database");
|
|
30
|
+
(0, import_vitest.describe)("DependencyGraphIntegrator.cleanup()", () => {
|
|
31
|
+
let db;
|
|
32
|
+
let integrator;
|
|
33
|
+
let tmpDir;
|
|
34
|
+
const projectRoot = "/tmp/test-project";
|
|
35
|
+
(0, import_vitest.beforeEach)(() => {
|
|
36
|
+
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "kirograph-integrator-test-"));
|
|
37
|
+
db = new import_database.GraphDatabase(tmpDir);
|
|
38
|
+
db.applySecuritySchema();
|
|
39
|
+
integrator = new import_integrator.DependencyGraphIntegrator(db, projectRoot);
|
|
40
|
+
});
|
|
41
|
+
(0, import_vitest.afterEach)(() => {
|
|
42
|
+
db.close();
|
|
43
|
+
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
44
|
+
});
|
|
45
|
+
function createDependencyNode(name, ecosystem, sourceManifests, options) {
|
|
46
|
+
const nodeId = `dep:${ecosystem}:${name}`;
|
|
47
|
+
const rawDb = db.getRawDb();
|
|
48
|
+
const node = {
|
|
49
|
+
id: nodeId,
|
|
50
|
+
kind: "dependency",
|
|
51
|
+
name,
|
|
52
|
+
qualifiedName: `${ecosystem}/${name}`,
|
|
53
|
+
filePath: sourceManifests[0] ?? "",
|
|
54
|
+
language: "unknown",
|
|
55
|
+
startLine: 0,
|
|
56
|
+
endLine: 0,
|
|
57
|
+
startColumn: 0,
|
|
58
|
+
endColumn: 0,
|
|
59
|
+
isExported: false,
|
|
60
|
+
isAsync: false,
|
|
61
|
+
isStatic: false,
|
|
62
|
+
isAbstract: false,
|
|
63
|
+
updatedAt: Date.now()
|
|
64
|
+
};
|
|
65
|
+
db.upsertNode(node);
|
|
66
|
+
rawDb.run(
|
|
67
|
+
`INSERT OR REPLACE INTO sec_dependencies
|
|
68
|
+
(node_id, ecosystem, package_name, declared_constraint, resolved_version, scope, source_manifests)
|
|
69
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)`,
|
|
70
|
+
[nodeId, ecosystem, name, "^1.0.0", "1.0.0", "production", JSON.stringify(sourceManifests)]
|
|
71
|
+
);
|
|
72
|
+
if (options?.addDeclaredInEdge !== false) {
|
|
73
|
+
for (const manifest of sourceManifests) {
|
|
74
|
+
const edge = {
|
|
75
|
+
source: nodeId,
|
|
76
|
+
target: manifest,
|
|
77
|
+
kind: "declared_in"
|
|
78
|
+
};
|
|
79
|
+
db.insertEdge(edge);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return nodeId;
|
|
83
|
+
}
|
|
84
|
+
function createEdge(source, target, kind) {
|
|
85
|
+
const edge = {
|
|
86
|
+
source,
|
|
87
|
+
target,
|
|
88
|
+
kind
|
|
89
|
+
};
|
|
90
|
+
db.insertEdge(edge);
|
|
91
|
+
}
|
|
92
|
+
(0, import_vitest.it)("should return zero counts when no dependencies exist", async () => {
|
|
93
|
+
const result = await integrator.cleanup(() => true);
|
|
94
|
+
(0, import_vitest.expect)(result.nodesRemoved).toBe(0);
|
|
95
|
+
(0, import_vitest.expect)(result.edgesRemoved).toBe(0);
|
|
96
|
+
});
|
|
97
|
+
(0, import_vitest.it)("should not remove dependencies whose manifests still exist and have declared_in edges", async () => {
|
|
98
|
+
const manifestPath = "package.json";
|
|
99
|
+
const nodeId = createDependencyNode("express", "npm", [manifestPath]);
|
|
100
|
+
const manifestExists = () => true;
|
|
101
|
+
const result = await integrator.cleanup(manifestExists);
|
|
102
|
+
(0, import_vitest.expect)(result.nodesRemoved).toBe(0);
|
|
103
|
+
(0, import_vitest.expect)(result.edgesRemoved).toBe(0);
|
|
104
|
+
const node = db.getNode(nodeId);
|
|
105
|
+
(0, import_vitest.expect)(node).not.toBeNull();
|
|
106
|
+
});
|
|
107
|
+
(0, import_vitest.it)("should remove dependencies with no declared_in edges", async () => {
|
|
108
|
+
const manifestPath = "package.json";
|
|
109
|
+
const nodeId = createDependencyNode("express", "npm", [manifestPath], {
|
|
110
|
+
addDeclaredInEdge: false
|
|
111
|
+
});
|
|
112
|
+
const manifestExists = () => true;
|
|
113
|
+
const result = await integrator.cleanup(manifestExists);
|
|
114
|
+
(0, import_vitest.expect)(result.nodesRemoved).toBe(1);
|
|
115
|
+
const node = db.getNode(nodeId);
|
|
116
|
+
(0, import_vitest.expect)(node).toBeNull();
|
|
117
|
+
});
|
|
118
|
+
(0, import_vitest.it)("should remove dependencies whose manifests no longer exist on disk", async () => {
|
|
119
|
+
const manifestPath = "package.json";
|
|
120
|
+
const nodeId = createDependencyNode("express", "npm", [manifestPath]);
|
|
121
|
+
const manifestExists = () => false;
|
|
122
|
+
const result = await integrator.cleanup(manifestExists);
|
|
123
|
+
(0, import_vitest.expect)(result.nodesRemoved).toBe(1);
|
|
124
|
+
const node = db.getNode(nodeId);
|
|
125
|
+
(0, import_vitest.expect)(node).toBeNull();
|
|
126
|
+
});
|
|
127
|
+
(0, import_vitest.it)("should remove edges connected to orphaned nodes", async () => {
|
|
128
|
+
const manifestPath = "package.json";
|
|
129
|
+
const depNodeId = createDependencyNode("lodash", "npm", [manifestPath], {
|
|
130
|
+
addDeclaredInEdge: false
|
|
131
|
+
});
|
|
132
|
+
const codeNode = {
|
|
133
|
+
id: "file:src/index.ts:import:lodash",
|
|
134
|
+
kind: "import",
|
|
135
|
+
name: "lodash",
|
|
136
|
+
qualifiedName: "src/index.ts:lodash",
|
|
137
|
+
filePath: "src/index.ts",
|
|
138
|
+
language: "typescript",
|
|
139
|
+
startLine: 1,
|
|
140
|
+
endLine: 1,
|
|
141
|
+
startColumn: 0,
|
|
142
|
+
endColumn: 20,
|
|
143
|
+
updatedAt: Date.now()
|
|
144
|
+
};
|
|
145
|
+
db.upsertNode(codeNode);
|
|
146
|
+
createEdge(codeNode.id, depNodeId, "imports");
|
|
147
|
+
const manifestExists = () => true;
|
|
148
|
+
const result = await integrator.cleanup(manifestExists);
|
|
149
|
+
(0, import_vitest.expect)(result.nodesRemoved).toBe(1);
|
|
150
|
+
(0, import_vitest.expect)(result.edgesRemoved).toBe(1);
|
|
151
|
+
});
|
|
152
|
+
(0, import_vitest.it)("should keep dependency if at least one source manifest exists on disk", async () => {
|
|
153
|
+
const manifests = ["packages/a/package.json", "packages/b/package.json"];
|
|
154
|
+
const nodeId = createDependencyNode("react", "npm", manifests);
|
|
155
|
+
const manifestExists = (p) => p.includes("packages/a/package.json");
|
|
156
|
+
const result = await integrator.cleanup(manifestExists);
|
|
157
|
+
(0, import_vitest.expect)(result.nodesRemoved).toBe(0);
|
|
158
|
+
const node = db.getNode(nodeId);
|
|
159
|
+
(0, import_vitest.expect)(node).not.toBeNull();
|
|
160
|
+
});
|
|
161
|
+
(0, import_vitest.it)("should remove transitive dependencies no longer reachable from direct deps", async () => {
|
|
162
|
+
const manifest = "package.json";
|
|
163
|
+
const directId = createDependencyNode("express", "npm", [manifest]);
|
|
164
|
+
const reachableTransId = createDependencyNode("accepts", "npm", [manifest]);
|
|
165
|
+
createEdge(directId, reachableTransId, "depends_on");
|
|
166
|
+
const orphanedDirectId = createDependencyNode("lodash", "npm", ["old-package.json"], {
|
|
167
|
+
addDeclaredInEdge: false
|
|
168
|
+
});
|
|
169
|
+
const unreachableTransId = createDependencyNode("lodash.merge", "npm", ["old-package.json"], {
|
|
170
|
+
addDeclaredInEdge: false
|
|
171
|
+
});
|
|
172
|
+
createEdge(orphanedDirectId, unreachableTransId, "depends_on");
|
|
173
|
+
const manifestExists = () => true;
|
|
174
|
+
const result = await integrator.cleanup(manifestExists);
|
|
175
|
+
(0, import_vitest.expect)(result.nodesRemoved).toBe(2);
|
|
176
|
+
(0, import_vitest.expect)(db.getNode(directId)).not.toBeNull();
|
|
177
|
+
(0, import_vitest.expect)(db.getNode(reachableTransId)).not.toBeNull();
|
|
178
|
+
(0, import_vitest.expect)(db.getNode(orphanedDirectId)).toBeNull();
|
|
179
|
+
(0, import_vitest.expect)(db.getNode(unreachableTransId)).toBeNull();
|
|
180
|
+
});
|
|
181
|
+
(0, import_vitest.it)("should handle transitive chains correctly \u2014 all reachable from direct dep", async () => {
|
|
182
|
+
const manifest = "package.json";
|
|
183
|
+
const directId = createDependencyNode("express", "npm", [manifest]);
|
|
184
|
+
const bp = createDependencyNode("body-parser", "npm", [manifest]);
|
|
185
|
+
const rb = createDependencyNode("raw-body", "npm", [manifest]);
|
|
186
|
+
const bytes = createDependencyNode("bytes", "npm", [manifest]);
|
|
187
|
+
createEdge(directId, bp, "depends_on");
|
|
188
|
+
createEdge(bp, rb, "depends_on");
|
|
189
|
+
createEdge(rb, bytes, "depends_on");
|
|
190
|
+
const manifestExists = () => true;
|
|
191
|
+
const result = await integrator.cleanup(manifestExists);
|
|
192
|
+
(0, import_vitest.expect)(result.nodesRemoved).toBe(0);
|
|
193
|
+
(0, import_vitest.expect)(result.edgesRemoved).toBe(0);
|
|
194
|
+
});
|
|
195
|
+
(0, import_vitest.it)("should count edges correctly when multiple edges connect to orphaned node", async () => {
|
|
196
|
+
const orphanedManifest = "removed/package.json";
|
|
197
|
+
const depId = createDependencyNode("old-pkg", "npm", [orphanedManifest], {
|
|
198
|
+
addDeclaredInEdge: false
|
|
199
|
+
});
|
|
200
|
+
const codeNode1 = {
|
|
201
|
+
id: "node:a",
|
|
202
|
+
kind: "function",
|
|
203
|
+
name: "funcA",
|
|
204
|
+
qualifiedName: "funcA",
|
|
205
|
+
filePath: "src/a.ts",
|
|
206
|
+
language: "typescript",
|
|
207
|
+
startLine: 1,
|
|
208
|
+
endLine: 5,
|
|
209
|
+
startColumn: 0,
|
|
210
|
+
endColumn: 0,
|
|
211
|
+
updatedAt: Date.now()
|
|
212
|
+
};
|
|
213
|
+
const codeNode2 = {
|
|
214
|
+
id: "node:b",
|
|
215
|
+
kind: "function",
|
|
216
|
+
name: "funcB",
|
|
217
|
+
qualifiedName: "funcB",
|
|
218
|
+
filePath: "src/b.ts",
|
|
219
|
+
language: "typescript",
|
|
220
|
+
startLine: 1,
|
|
221
|
+
endLine: 5,
|
|
222
|
+
startColumn: 0,
|
|
223
|
+
endColumn: 0,
|
|
224
|
+
updatedAt: Date.now()
|
|
225
|
+
};
|
|
226
|
+
db.upsertNode(codeNode1);
|
|
227
|
+
db.upsertNode(codeNode2);
|
|
228
|
+
createEdge(codeNode1.id, depId, "imports");
|
|
229
|
+
createEdge(codeNode2.id, depId, "references");
|
|
230
|
+
createEdge(depId, "some-manifest", "declared_in");
|
|
231
|
+
const manifestExists = () => false;
|
|
232
|
+
const result = await integrator.cleanup(manifestExists);
|
|
233
|
+
(0, import_vitest.expect)(result.nodesRemoved).toBe(1);
|
|
234
|
+
(0, import_vitest.expect)(result.edgesRemoved).toBe(3);
|
|
235
|
+
});
|
|
236
|
+
});
|
|
237
|
+
//# sourceMappingURL=integrator.test.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/security/integrator.test.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Tests for DependencyGraphIntegrator.cleanup()\n *\n * Verifies that orphaned Dependency_Nodes are correctly identified and removed\n * when their source manifests no longer exist on disk or when they have no\n * declared_in edges.\n */\nimport { describe, it, expect, beforeEach, afterEach } from 'vitest';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport * as os from 'os';\nimport { DependencyGraphIntegrator } from './integrator';\nimport { GraphDatabase } from '../db/database';\nimport type { Node, Edge } from '../types';\n\ndescribe('DependencyGraphIntegrator.cleanup()', () => {\n let db: GraphDatabase;\n let integrator: DependencyGraphIntegrator;\n let tmpDir: string;\n const projectRoot = '/tmp/test-project';\n\n beforeEach(() => {\n tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'kirograph-integrator-test-'));\n db = new GraphDatabase(tmpDir);\n db.applySecuritySchema();\n integrator = new DependencyGraphIntegrator(db, projectRoot);\n });\n\n afterEach(() => {\n db.close();\n fs.rmSync(tmpDir, { recursive: true, force: true });\n });\n\n function createDependencyNode(\n name: string,\n ecosystem: string,\n sourceManifests: string[],\n options?: { addDeclaredInEdge?: boolean },\n ): string {\n const nodeId = `dep:${ecosystem}:${name}`;\n const rawDb = db.getRawDb();\n\n const node: Node = {\n id: nodeId,\n kind: 'dependency',\n name,\n qualifiedName: `${ecosystem}/${name}`,\n filePath: sourceManifests[0] ?? '',\n language: 'unknown',\n startLine: 0,\n endLine: 0,\n startColumn: 0,\n endColumn: 0,\n isExported: false,\n isAsync: false,\n isStatic: false,\n isAbstract: false,\n updatedAt: Date.now(),\n };\n\n db.upsertNode(node);\n\n rawDb.run(\n `INSERT OR REPLACE INTO sec_dependencies\n (node_id, ecosystem, package_name, declared_constraint, resolved_version, scope, source_manifests)\n VALUES (?, ?, ?, ?, ?, ?, ?)`,\n [nodeId, ecosystem, name, '^1.0.0', '1.0.0', 'production', JSON.stringify(sourceManifests)],\n );\n\n // Optionally add declared_in edge (simulates a manifest that still declares this dep)\n if (options?.addDeclaredInEdge !== false) {\n for (const manifest of sourceManifests) {\n const edge: Edge = {\n source: nodeId,\n target: manifest,\n kind: 'declared_in',\n };\n db.insertEdge(edge);\n }\n }\n\n return nodeId;\n }\n\n function createEdge(source: string, target: string, kind: string): void {\n const edge: Edge = {\n source,\n target,\n kind: kind as Edge['kind'],\n };\n db.insertEdge(edge);\n }\n\n it('should return zero counts when no dependencies exist', async () => {\n const result = await integrator.cleanup(() => true);\n expect(result.nodesRemoved).toBe(0);\n expect(result.edgesRemoved).toBe(0);\n });\n\n it('should not remove dependencies whose manifests still exist and have declared_in edges', async () => {\n const manifestPath = 'package.json';\n const nodeId = createDependencyNode('express', 'npm', [manifestPath]);\n\n const manifestExists = () => true;\n\n const result = await integrator.cleanup(manifestExists);\n expect(result.nodesRemoved).toBe(0);\n expect(result.edgesRemoved).toBe(0);\n\n const node = db.getNode(nodeId);\n expect(node).not.toBeNull();\n });\n\n it('should remove dependencies with no declared_in edges', async () => {\n const manifestPath = 'package.json';\n const nodeId = createDependencyNode('express', 'npm', [manifestPath], {\n addDeclaredInEdge: false,\n });\n\n const manifestExists = () => true;\n\n const result = await integrator.cleanup(manifestExists);\n expect(result.nodesRemoved).toBe(1);\n\n const node = db.getNode(nodeId);\n expect(node).toBeNull();\n });\n\n it('should remove dependencies whose manifests no longer exist on disk', async () => {\n const manifestPath = 'package.json';\n const nodeId = createDependencyNode('express', 'npm', [manifestPath]);\n\n const manifestExists = () => false;\n\n const result = await integrator.cleanup(manifestExists);\n expect(result.nodesRemoved).toBe(1);\n\n const node = db.getNode(nodeId);\n expect(node).toBeNull();\n });\n\n it('should remove edges connected to orphaned nodes', async () => {\n const manifestPath = 'package.json';\n const depNodeId = createDependencyNode('lodash', 'npm', [manifestPath], {\n addDeclaredInEdge: false,\n });\n\n const codeNode: Node = {\n id: 'file:src/index.ts:import:lodash',\n kind: 'import',\n name: 'lodash',\n qualifiedName: 'src/index.ts:lodash',\n filePath: 'src/index.ts',\n language: 'typescript',\n startLine: 1,\n endLine: 1,\n startColumn: 0,\n endColumn: 20,\n updatedAt: Date.now(),\n };\n db.upsertNode(codeNode);\n createEdge(codeNode.id, depNodeId, 'imports');\n\n const manifestExists = () => true;\n const result = await integrator.cleanup(manifestExists);\n expect(result.nodesRemoved).toBe(1);\n expect(result.edgesRemoved).toBe(1);\n });\n\n it('should keep dependency if at least one source manifest exists on disk', async () => {\n const manifests = ['packages/a/package.json', 'packages/b/package.json'];\n const nodeId = createDependencyNode('react', 'npm', manifests);\n\n const manifestExists = (p: string) => p.includes('packages/a/package.json');\n\n const result = await integrator.cleanup(manifestExists);\n expect(result.nodesRemoved).toBe(0);\n\n const node = db.getNode(nodeId);\n expect(node).not.toBeNull();\n });\n\n it('should remove transitive dependencies no longer reachable from direct deps', async () => {\n const manifest = 'package.json';\n\n // Direct dependency (manifest exists, has declared_in edge)\n const directId = createDependencyNode('express', 'npm', [manifest]);\n\n // Transitive dependency reachable from express\n const reachableTransId = createDependencyNode('accepts', 'npm', [manifest]);\n createEdge(directId, reachableTransId, 'depends_on');\n\n // Orphaned direct dependency (no declared_in edge)\n const orphanedDirectId = createDependencyNode('lodash', 'npm', ['old-package.json'], {\n addDeclaredInEdge: false,\n });\n\n // Transitive dependency ONLY reachable from orphaned direct (no declared_in edge)\n const unreachableTransId = createDependencyNode('lodash.merge', 'npm', ['old-package.json'], {\n addDeclaredInEdge: false,\n });\n createEdge(orphanedDirectId, unreachableTransId, 'depends_on');\n\n const manifestExists = () => true;\n\n const result = await integrator.cleanup(manifestExists);\n\n // lodash and lodash.merge should be removed\n expect(result.nodesRemoved).toBe(2);\n\n // express and accepts should remain\n expect(db.getNode(directId)).not.toBeNull();\n expect(db.getNode(reachableTransId)).not.toBeNull();\n\n // orphaned nodes should be gone\n expect(db.getNode(orphanedDirectId)).toBeNull();\n expect(db.getNode(unreachableTransId)).toBeNull();\n });\n\n it('should handle transitive chains correctly \u2014 all reachable from direct dep', async () => {\n const manifest = 'package.json';\n\n const directId = createDependencyNode('express', 'npm', [manifest]);\n\n // Chain: express \u2192 body-parser \u2192 raw-body \u2192 bytes\n const bp = createDependencyNode('body-parser', 'npm', [manifest]);\n const rb = createDependencyNode('raw-body', 'npm', [manifest]);\n const bytes = createDependencyNode('bytes', 'npm', [manifest]);\n\n createEdge(directId, bp, 'depends_on');\n createEdge(bp, rb, 'depends_on');\n createEdge(rb, bytes, 'depends_on');\n\n const manifestExists = () => true;\n\n const result = await integrator.cleanup(manifestExists);\n\n expect(result.nodesRemoved).toBe(0);\n expect(result.edgesRemoved).toBe(0);\n });\n\n it('should count edges correctly when multiple edges connect to orphaned node', async () => {\n const orphanedManifest = 'removed/package.json';\n const depId = createDependencyNode('old-pkg', 'npm', [orphanedManifest], {\n addDeclaredInEdge: false,\n });\n\n const codeNode1: Node = {\n id: 'node:a',\n kind: 'function',\n name: 'funcA',\n qualifiedName: 'funcA',\n filePath: 'src/a.ts',\n language: 'typescript',\n startLine: 1,\n endLine: 5,\n startColumn: 0,\n endColumn: 0,\n updatedAt: Date.now(),\n };\n const codeNode2: Node = {\n id: 'node:b',\n kind: 'function',\n name: 'funcB',\n qualifiedName: 'funcB',\n filePath: 'src/b.ts',\n language: 'typescript',\n startLine: 1,\n endLine: 5,\n startColumn: 0,\n endColumn: 0,\n updatedAt: Date.now(),\n };\n db.upsertNode(codeNode1);\n db.upsertNode(codeNode2);\n\n createEdge(codeNode1.id, depId, 'imports');\n createEdge(codeNode2.id, depId, 'references');\n createEdge(depId, 'some-manifest', 'declared_in');\n\n // No manifests exist on disk\n const manifestExists = () => false;\n\n const result = await integrator.cleanup(manifestExists);\n expect(result.nodesRemoved).toBe(1);\n // 2 incoming (imports, references) + 1 outgoing (declared_in) = 3\n expect(result.edgesRemoved).toBe(3);\n });\n});\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
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 license_exports = {};
|
|
20
|
+
__export(license_exports, {
|
|
21
|
+
checkLicensePolicy: () => checkLicensePolicy
|
|
22
|
+
});
|
|
23
|
+
module.exports = __toCommonJS(license_exports);
|
|
24
|
+
function matchesPattern(license, pattern) {
|
|
25
|
+
const lowerLicense = license.toLowerCase();
|
|
26
|
+
const lowerPattern = pattern.toLowerCase();
|
|
27
|
+
if (!lowerPattern.includes("*")) {
|
|
28
|
+
return lowerLicense === lowerPattern;
|
|
29
|
+
}
|
|
30
|
+
const regexStr = lowerPattern.replace(/[.+?^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*");
|
|
31
|
+
const regex = new RegExp(`^${regexStr}$`);
|
|
32
|
+
return regex.test(lowerLicense);
|
|
33
|
+
}
|
|
34
|
+
function matchesAny(license, patterns) {
|
|
35
|
+
return patterns.some((p) => matchesPattern(license, p));
|
|
36
|
+
}
|
|
37
|
+
function checkLicensePolicy(deps, policy) {
|
|
38
|
+
const violations = [];
|
|
39
|
+
for (const dep of deps) {
|
|
40
|
+
if (!dep.license) continue;
|
|
41
|
+
const license = dep.license;
|
|
42
|
+
if (policy.deny.length > 0 && matchesAny(license, policy.deny)) {
|
|
43
|
+
violations.push({
|
|
44
|
+
packageName: dep.package_name,
|
|
45
|
+
ecosystem: dep.ecosystem,
|
|
46
|
+
license,
|
|
47
|
+
severity: "deny"
|
|
48
|
+
});
|
|
49
|
+
} else if (policy.warn.length > 0 && matchesAny(license, policy.warn)) {
|
|
50
|
+
violations.push({
|
|
51
|
+
packageName: dep.package_name,
|
|
52
|
+
ecosystem: dep.ecosystem,
|
|
53
|
+
license,
|
|
54
|
+
severity: "warn"
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
violations.sort((a, b) => {
|
|
59
|
+
if (a.severity !== b.severity) {
|
|
60
|
+
return a.severity === "deny" ? -1 : 1;
|
|
61
|
+
}
|
|
62
|
+
return a.packageName.localeCompare(b.packageName);
|
|
63
|
+
});
|
|
64
|
+
return violations;
|
|
65
|
+
}
|
|
66
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
67
|
+
0 && (module.exports = {
|
|
68
|
+
checkLicensePolicy
|
|
69
|
+
});
|
|
70
|
+
//# sourceMappingURL=license.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/security/license.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * License Compliance Checker for KiroGraph-Sec\n *\n * Checks project dependencies against a license policy (deny/warn lists).\n * Supports case-insensitive matching and wildcard patterns (e.g. GPL-* matches\n * GPL-2.0, GPL-3.0-only, etc.).\n */\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 LicenseViolation {\n packageName: string;\n ecosystem: string;\n license: string;\n severity: 'deny' | 'warn';\n}\n\n// \u2500\u2500 Wildcard matching \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Test whether a license string matches a policy pattern.\n * Matching is case-insensitive. The pattern may contain `*` as a wildcard\n * (matches any sequence of characters).\n */\nfunction matchesPattern(license: string, pattern: string): boolean {\n const lowerLicense = license.toLowerCase();\n const lowerPattern = pattern.toLowerCase();\n\n if (!lowerPattern.includes('*')) {\n return lowerLicense === lowerPattern;\n }\n\n // Convert wildcard pattern to regex\n // Escape regex special chars except *, then replace * with .*\n const regexStr = lowerPattern\n .replace(/[.+?^${}()|[\\]\\\\]/g, '\\\\$&')\n .replace(/\\*/g, '.*');\n const regex = new RegExp(`^${regexStr}$`);\n return regex.test(lowerLicense);\n}\n\n/**\n * Test whether a license matches any pattern in the list.\n */\nfunction matchesAny(license: string, patterns: string[]): boolean {\n return patterns.some(p => matchesPattern(license, p));\n}\n\n// \u2500\u2500 Main check function \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Check a list of dependencies against a license policy.\n *\n * Dependencies with no license are skipped (no violation).\n * A license matched in `deny` produces a 'deny' violation.\n * A license matched in `warn` (and not in `deny`) produces a 'warn' violation.\n *\n * @param deps - Array of dependency rows from sec_dependencies\n * @param policy - The license policy with deny and warn lists\n * @returns Array of violations sorted by severity (deny first) then package name\n */\nexport function checkLicensePolicy(\n deps: Array<{ package_name: string; ecosystem: string; license: string | null }>,\n policy: { deny: string[]; warn: string[] },\n): LicenseViolation[] {\n const violations: LicenseViolation[] = [];\n\n for (const dep of deps) {\n if (!dep.license) continue;\n\n const license = dep.license;\n\n if (policy.deny.length > 0 && matchesAny(license, policy.deny)) {\n violations.push({\n packageName: dep.package_name,\n ecosystem: dep.ecosystem,\n license,\n severity: 'deny',\n });\n } else if (policy.warn.length > 0 && matchesAny(license, policy.warn)) {\n violations.push({\n packageName: dep.package_name,\n ecosystem: dep.ecosystem,\n license,\n severity: 'warn',\n });\n }\n }\n\n // Sort: deny first, then warn; within each group sort by package name\n violations.sort((a, b) => {\n if (a.severity !== b.severity) {\n return a.severity === 'deny' ? -1 : 1;\n }\n return a.packageName.localeCompare(b.packageName);\n });\n\n return violations;\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAwBA,SAAS,eAAe,SAAiB,SAA0B;AACjE,QAAM,eAAe,QAAQ,YAAY;AACzC,QAAM,eAAe,QAAQ,YAAY;AAEzC,MAAI,CAAC,aAAa,SAAS,GAAG,GAAG;AAC/B,WAAO,iBAAiB;AAAA,EAC1B;AAIA,QAAM,WAAW,aACd,QAAQ,sBAAsB,MAAM,EACpC,QAAQ,OAAO,IAAI;AACtB,QAAM,QAAQ,IAAI,OAAO,IAAI,QAAQ,GAAG;AACxC,SAAO,MAAM,KAAK,YAAY;AAChC;AAKA,SAAS,WAAW,SAAiB,UAA6B;AAChE,SAAO,SAAS,KAAK,OAAK,eAAe,SAAS,CAAC,CAAC;AACtD;AAeO,SAAS,mBACd,MACA,QACoB;AACpB,QAAM,aAAiC,CAAC;AAExC,aAAW,OAAO,MAAM;AACtB,QAAI,CAAC,IAAI,QAAS;AAElB,UAAM,UAAU,IAAI;AAEpB,QAAI,OAAO,KAAK,SAAS,KAAK,WAAW,SAAS,OAAO,IAAI,GAAG;AAC9D,iBAAW,KAAK;AAAA,QACd,aAAa,IAAI;AAAA,QACjB,WAAW,IAAI;AAAA,QACf;AAAA,QACA,UAAU;AAAA,MACZ,CAAC;AAAA,IACH,WAAW,OAAO,KAAK,SAAS,KAAK,WAAW,SAAS,OAAO,IAAI,GAAG;AACrE,iBAAW,KAAK;AAAA,QACd,aAAa,IAAI;AAAA,QACjB,WAAW,IAAI;AAAA,QACf;AAAA,QACA,UAAU;AAAA,MACZ,CAAC;AAAA,IACH;AAAA,EACF;AAGA,aAAW,KAAK,CAAC,GAAG,MAAM;AACxB,QAAI,EAAE,aAAa,EAAE,UAAU;AAC7B,aAAO,EAAE,aAAa,SAAS,KAAK;AAAA,IACtC;AACA,WAAO,EAAE,YAAY,cAAc,EAAE,WAAW;AAAA,EAClD,CAAC;AAED,SAAO;AACT;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,243 @@
|
|
|
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 adapter_exports = {};
|
|
30
|
+
__export(adapter_exports, {
|
|
31
|
+
SecurityManifestAdapter: () => SecurityManifestAdapter
|
|
32
|
+
});
|
|
33
|
+
module.exports = __toCommonJS(adapter_exports);
|
|
34
|
+
var fs = __toESM(require("fs"));
|
|
35
|
+
var path = __toESM(require("path"));
|
|
36
|
+
var import_manifest = require("../../architecture/manifest/index");
|
|
37
|
+
const SKIP_DIRS = /* @__PURE__ */ new Set([
|
|
38
|
+
"node_modules",
|
|
39
|
+
".git",
|
|
40
|
+
"dist",
|
|
41
|
+
"build",
|
|
42
|
+
"target",
|
|
43
|
+
".gradle",
|
|
44
|
+
"__pycache__",
|
|
45
|
+
".kirograph",
|
|
46
|
+
"vendor",
|
|
47
|
+
".cache",
|
|
48
|
+
"coverage",
|
|
49
|
+
".nyc_output",
|
|
50
|
+
"_build",
|
|
51
|
+
"_opam",
|
|
52
|
+
"elm-stuff",
|
|
53
|
+
"zig-cache",
|
|
54
|
+
"zig-out"
|
|
55
|
+
]);
|
|
56
|
+
class SecurityManifestAdapter {
|
|
57
|
+
constructor(projectRoot) {
|
|
58
|
+
this.plugins = /* @__PURE__ */ new Map();
|
|
59
|
+
/** Standalone plugins have no corresponding architecture parser — they own their own discovery. */
|
|
60
|
+
this.standalonePlugins = /* @__PURE__ */ new Map();
|
|
61
|
+
this.projectRoot = projectRoot;
|
|
62
|
+
this.archParsers = (0, import_manifest.getAllManifestParsers)();
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Register a version extraction plugin for an ecosystem that has a
|
|
66
|
+
* corresponding architecture parser. The plugin's `ecosystem` field
|
|
67
|
+
* must equal the architecture parser's `name` for the lookup to work.
|
|
68
|
+
*/
|
|
69
|
+
registerPlugin(plugin) {
|
|
70
|
+
this.plugins.set(plugin.ecosystem, plugin);
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Register a standalone version extraction plugin for an ecosystem that
|
|
74
|
+
* has NO corresponding architecture parser. The plugin's `manifestFiles`
|
|
75
|
+
* list drives discovery — the adapter will scan for those filenames and
|
|
76
|
+
* invoke the plugin directly when found.
|
|
77
|
+
*/
|
|
78
|
+
registerStandalonePlugin(plugin) {
|
|
79
|
+
this.standalonePlugins.set(plugin.ecosystem, plugin);
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Get all registered version extraction plugins (wrapped + standalone).
|
|
83
|
+
*/
|
|
84
|
+
getPlugins() {
|
|
85
|
+
return [...this.plugins.values(), ...this.standalonePlugins.values()];
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Get the architecture parsers being wrapped.
|
|
89
|
+
*/
|
|
90
|
+
getArchParsers() {
|
|
91
|
+
return this.archParsers;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Discover all manifest files in the project tree.
|
|
95
|
+
* Includes files known to architecture parsers AND files from standalone plugins.
|
|
96
|
+
* Returns absolute paths.
|
|
97
|
+
*/
|
|
98
|
+
discoverManifests() {
|
|
99
|
+
return this._findManifests(this.projectRoot);
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Run full discovery and extraction:
|
|
103
|
+
* 1. Discover manifest files (reusing architecture's SKIP_DIRS logic)
|
|
104
|
+
* 2. For each manifest, find the matching architecture parser
|
|
105
|
+
* 3. If a version extraction plugin is registered for that ecosystem,
|
|
106
|
+
* use it to extract detailed version/scope information
|
|
107
|
+
* 4. Otherwise, fall back to basic extraction from the architecture parser's
|
|
108
|
+
* ArchPackage.externalDeps (names only, no version info)
|
|
109
|
+
*/
|
|
110
|
+
async extractAll() {
|
|
111
|
+
const manifestPaths = this.discoverManifests();
|
|
112
|
+
const allDeps = [];
|
|
113
|
+
const warnings = [];
|
|
114
|
+
const errors = [];
|
|
115
|
+
let manifestsParsed = 0;
|
|
116
|
+
for (const manifestPath of manifestPaths) {
|
|
117
|
+
const archParser = this.archParsers.find((p) => p.canParse(manifestPath));
|
|
118
|
+
if (!archParser) continue;
|
|
119
|
+
const relManifest = path.relative(this.projectRoot, manifestPath).replace(/\\/g, "/");
|
|
120
|
+
const plugin = this.plugins.get(archParser.name);
|
|
121
|
+
if (plugin && plugin.canExtract(manifestPath)) {
|
|
122
|
+
try {
|
|
123
|
+
const deps = await plugin.extract(manifestPath, this.projectRoot);
|
|
124
|
+
allDeps.push(...deps);
|
|
125
|
+
manifestsParsed++;
|
|
126
|
+
} catch (err) {
|
|
127
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
128
|
+
errors.push({ file: relManifest, message });
|
|
129
|
+
}
|
|
130
|
+
} else {
|
|
131
|
+
try {
|
|
132
|
+
const packages = await archParser.parse(manifestPath, this.projectRoot);
|
|
133
|
+
const deps = this._fallbackExtract(packages, archParser.name, relManifest);
|
|
134
|
+
allDeps.push(...deps);
|
|
135
|
+
manifestsParsed++;
|
|
136
|
+
if (!plugin) {
|
|
137
|
+
warnings.push({
|
|
138
|
+
file: relManifest,
|
|
139
|
+
message: `No version extraction plugin registered for ecosystem '${archParser.name}'; dependency names extracted without version constraints`
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
} catch (err) {
|
|
143
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
144
|
+
errors.push({ file: relManifest, message });
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return {
|
|
149
|
+
dependenciesCreated: allDeps.length,
|
|
150
|
+
manifestsParsed,
|
|
151
|
+
warnings,
|
|
152
|
+
errors
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Extract dependencies for a single manifest file.
|
|
157
|
+
* Tries standalone plugins first (when there is no arch parser), then
|
|
158
|
+
* wrapped plugins, then falls back to arch parser output.
|
|
159
|
+
*/
|
|
160
|
+
async extractFromManifest(manifestPath) {
|
|
161
|
+
const archParser = this.archParsers.find((p) => p.canParse(manifestPath));
|
|
162
|
+
if (!archParser) {
|
|
163
|
+
const standalonePlugin = [...this.standalonePlugins.values()].find((p) => p.canExtract(manifestPath));
|
|
164
|
+
if (standalonePlugin) {
|
|
165
|
+
return standalonePlugin.extract(manifestPath, this.projectRoot);
|
|
166
|
+
}
|
|
167
|
+
return [];
|
|
168
|
+
}
|
|
169
|
+
const plugin = this.plugins.get(archParser.name);
|
|
170
|
+
if (plugin && plugin.canExtract(manifestPath)) {
|
|
171
|
+
return plugin.extract(manifestPath, this.projectRoot);
|
|
172
|
+
}
|
|
173
|
+
const packages = await archParser.parse(manifestPath, this.projectRoot);
|
|
174
|
+
const relManifest = path.relative(this.projectRoot, manifestPath).replace(/\\/g, "/");
|
|
175
|
+
return this._fallbackExtract(packages, archParser.name, relManifest);
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Get the ecosystem name for a given manifest file path.
|
|
179
|
+
* Returns undefined if no parser handles this file.
|
|
180
|
+
*/
|
|
181
|
+
getEcosystem(manifestPath) {
|
|
182
|
+
const parser = this.archParsers.find((p) => p.canParse(manifestPath));
|
|
183
|
+
return parser?.name;
|
|
184
|
+
}
|
|
185
|
+
// ── Private helpers ───────────────────────────────────────────────────────
|
|
186
|
+
/**
|
|
187
|
+
* Fallback extraction: converts ArchPackage.externalDeps (names only) into
|
|
188
|
+
* ParsedDependency records with empty version constraints and default scope.
|
|
189
|
+
*/
|
|
190
|
+
_fallbackExtract(packages, ecosystem, sourceManifest) {
|
|
191
|
+
const deps = [];
|
|
192
|
+
for (const pkg of packages) {
|
|
193
|
+
if (!pkg.externalDeps) continue;
|
|
194
|
+
for (const depName of pkg.externalDeps) {
|
|
195
|
+
deps.push({
|
|
196
|
+
name: depName,
|
|
197
|
+
declaredConstraint: "*",
|
|
198
|
+
scope: "production",
|
|
199
|
+
ecosystem,
|
|
200
|
+
sourceManifest
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
return deps;
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Walk the project directory tree looking for manifest files.
|
|
208
|
+
* Mirrors the architecture module's _findManifests() logic, respecting SKIP_DIRS.
|
|
209
|
+
* Includes manifest filenames from standalone plugins in addition to arch parsers.
|
|
210
|
+
*/
|
|
211
|
+
_findManifests(dir, results = []) {
|
|
212
|
+
const manifestFilenames = /* @__PURE__ */ new Set([
|
|
213
|
+
...this.archParsers.flatMap((p) => p.manifestFiles),
|
|
214
|
+
...Array.from(this.standalonePlugins.values()).flatMap((p) => p.manifestFiles)
|
|
215
|
+
]);
|
|
216
|
+
return this._walkDir(dir, manifestFilenames, results);
|
|
217
|
+
}
|
|
218
|
+
_walkDir(dir, manifestFilenames, results) {
|
|
219
|
+
let entries;
|
|
220
|
+
try {
|
|
221
|
+
entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
222
|
+
} catch {
|
|
223
|
+
return results;
|
|
224
|
+
}
|
|
225
|
+
for (const entry of entries) {
|
|
226
|
+
if (entry.isDirectory()) {
|
|
227
|
+
if (!SKIP_DIRS.has(entry.name)) {
|
|
228
|
+
this._walkDir(path.join(dir, entry.name), manifestFilenames, results);
|
|
229
|
+
}
|
|
230
|
+
} else if (entry.isFile()) {
|
|
231
|
+
if (manifestFilenames.has(entry.name) || entry.name.endsWith(".csproj")) {
|
|
232
|
+
results.push(path.join(dir, entry.name));
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
return results;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
240
|
+
0 && (module.exports = {
|
|
241
|
+
SecurityManifestAdapter
|
|
242
|
+
});
|
|
243
|
+
//# sourceMappingURL=adapter.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/security/manifest/adapter.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * SecurityManifestAdapter\n *\n * Wraps the existing architecture manifest parsers (11 parsers: npm, cargo, go,\n * gradle, maven, csproj, python, scala, elm, ocaml) to additionally extract\n * version constraints and dependency scopes that the architecture module does\n * not capture.\n *\n * The architecture parsers discover manifest files and extract package names into\n * `ArchPackage.externalDeps`. This adapter reuses that discovery infrastructure\n * and layers version/scope extraction on top via ecosystem-specific plugins.\n */\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport { getAllManifestParsers } from '../../architecture/manifest/index';\nimport type { ManifestParser as ArchManifestParser, ArchPackage } from '../../architecture/types';\nimport type { ParsedDependency, ManifestParseResult } from '../types';\n\n// \u2500\u2500 Plugin Interface \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * A version extraction plugin provides ecosystem-specific logic to extract\n * version constraints and scopes from manifest files. Each plugin corresponds\n * to one or more architecture parsers and enhances their output with security-\n * relevant metadata.\n */\nexport interface VersionExtractionPlugin {\n /** Ecosystem identifier matching the architecture parser name (e.g. 'npm', 'maven', 'go') */\n ecosystem: string;\n /** Manifest filenames this plugin handles (should match the architecture parser's manifestFiles) */\n manifestFiles: string[];\n /** Returns true if this plugin can handle the given manifest file path */\n canExtract(manifestPath: string): boolean;\n /**\n * Extract version constraints and scopes from a manifest file.\n * This is called AFTER the architecture parser has already discovered the manifest.\n * The plugin receives the manifest path and project root, and returns detailed\n * dependency information including versions and scopes.\n */\n extract(manifestPath: string, projectRoot: string): Promise<ParsedDependency[]>;\n}\n\n// \u2500\u2500 Directories to skip (mirrors architecture module's SKIP_DIRS) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nconst SKIP_DIRS = new Set([\n 'node_modules', '.git', 'dist', 'build', 'target', '.gradle', '__pycache__',\n '.kirograph', 'vendor', '.cache', 'coverage', '.nyc_output', '_build', '_opam',\n 'elm-stuff', 'zig-cache', 'zig-out',\n]);\n\n// \u2500\u2500 SecurityManifestAdapter \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 SecurityManifestAdapter {\n private readonly archParsers: ArchManifestParser[];\n private readonly plugins: Map<string, VersionExtractionPlugin> = new Map();\n /** Standalone plugins have no corresponding architecture parser \u2014 they own their own discovery. */\n private readonly standalonePlugins: Map<string, VersionExtractionPlugin> = new Map();\n private readonly projectRoot: string;\n\n constructor(projectRoot: string) {\n this.projectRoot = projectRoot;\n this.archParsers = getAllManifestParsers();\n }\n\n /**\n * Register a version extraction plugin for an ecosystem that has a\n * corresponding architecture parser. The plugin's `ecosystem` field\n * must equal the architecture parser's `name` for the lookup to work.\n */\n registerPlugin(plugin: VersionExtractionPlugin): void {\n this.plugins.set(plugin.ecosystem, plugin);\n }\n\n /**\n * Register a standalone version extraction plugin for an ecosystem that\n * has NO corresponding architecture parser. The plugin's `manifestFiles`\n * list drives discovery \u2014 the adapter will scan for those filenames and\n * invoke the plugin directly when found.\n */\n registerStandalonePlugin(plugin: VersionExtractionPlugin): void {\n this.standalonePlugins.set(plugin.ecosystem, plugin);\n }\n\n /**\n * Get all registered version extraction plugins (wrapped + standalone).\n */\n getPlugins(): VersionExtractionPlugin[] {\n return [...this.plugins.values(), ...this.standalonePlugins.values()];\n }\n\n /**\n * Get the architecture parsers being wrapped.\n */\n getArchParsers(): ArchManifestParser[] {\n return this.archParsers;\n }\n\n /**\n * Discover all manifest files in the project tree.\n * Includes files known to architecture parsers AND files from standalone plugins.\n * Returns absolute paths.\n */\n discoverManifests(): string[] {\n return this._findManifests(this.projectRoot);\n }\n\n /**\n * Run full discovery and extraction:\n * 1. Discover manifest files (reusing architecture's SKIP_DIRS logic)\n * 2. For each manifest, find the matching architecture parser\n * 3. If a version extraction plugin is registered for that ecosystem,\n * use it to extract detailed version/scope information\n * 4. Otherwise, fall back to basic extraction from the architecture parser's\n * ArchPackage.externalDeps (names only, no version info)\n */\n async extractAll(): Promise<ManifestParseResult> {\n const manifestPaths = this.discoverManifests();\n const allDeps: ParsedDependency[] = [];\n const warnings: Array<{ file: string; line?: number; message: string }> = [];\n const errors: Array<{ file: string; message: string }> = [];\n let manifestsParsed = 0;\n\n for (const manifestPath of manifestPaths) {\n const archParser = this.archParsers.find(p => p.canParse(manifestPath));\n if (!archParser) continue;\n\n const relManifest = path.relative(this.projectRoot, manifestPath).replace(/\\\\/g, '/');\n const plugin = this.plugins.get(archParser.name);\n\n if (plugin && plugin.canExtract(manifestPath)) {\n // Use the version extraction plugin for detailed parsing\n try {\n const deps = await plugin.extract(manifestPath, this.projectRoot);\n allDeps.push(...deps);\n manifestsParsed++;\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n errors.push({ file: relManifest, message });\n }\n } else {\n // Fallback: use architecture parser output (names only, no versions)\n try {\n const packages = await archParser.parse(manifestPath, this.projectRoot);\n const deps = this._fallbackExtract(packages, archParser.name, relManifest);\n allDeps.push(...deps);\n manifestsParsed++;\n\n if (!plugin) {\n warnings.push({\n file: relManifest,\n message: `No version extraction plugin registered for ecosystem '${archParser.name}'; dependency names extracted without version constraints`,\n });\n }\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n errors.push({ file: relManifest, message });\n }\n }\n }\n\n return {\n dependenciesCreated: allDeps.length,\n manifestsParsed,\n warnings,\n errors,\n };\n }\n\n /**\n * Extract dependencies for a single manifest file.\n * Tries standalone plugins first (when there is no arch parser), then\n * wrapped plugins, then falls back to arch parser output.\n */\n async extractFromManifest(manifestPath: string): Promise<ParsedDependency[]> {\n const archParser = this.archParsers.find(p => p.canParse(manifestPath));\n\n if (!archParser) {\n // No arch parser \u2014 try standalone plugins\n const standalonePlugin = [...this.standalonePlugins.values()]\n .find(p => p.canExtract(manifestPath));\n if (standalonePlugin) {\n return standalonePlugin.extract(manifestPath, this.projectRoot);\n }\n return [];\n }\n\n const plugin = this.plugins.get(archParser.name);\n\n if (plugin && plugin.canExtract(manifestPath)) {\n return plugin.extract(manifestPath, this.projectRoot);\n }\n\n // Fallback: architecture parser output (names only)\n const packages = await archParser.parse(manifestPath, this.projectRoot);\n const relManifest = path.relative(this.projectRoot, manifestPath).replace(/\\\\/g, '/');\n return this._fallbackExtract(packages, archParser.name, relManifest);\n }\n\n /**\n * Get the ecosystem name for a given manifest file path.\n * Returns undefined if no parser handles this file.\n */\n getEcosystem(manifestPath: string): string | undefined {\n const parser = this.archParsers.find(p => p.canParse(manifestPath));\n return parser?.name;\n }\n\n // \u2500\u2500 Private helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n /**\n * Fallback extraction: converts ArchPackage.externalDeps (names only) into\n * ParsedDependency records with empty version constraints and default scope.\n */\n private _fallbackExtract(\n packages: ArchPackage[],\n ecosystem: string,\n sourceManifest: string,\n ): ParsedDependency[] {\n const deps: ParsedDependency[] = [];\n for (const pkg of packages) {\n if (!pkg.externalDeps) continue;\n for (const depName of pkg.externalDeps) {\n deps.push({\n name: depName,\n declaredConstraint: '*',\n scope: 'production',\n ecosystem,\n sourceManifest,\n });\n }\n }\n return deps;\n }\n\n /**\n * Walk the project directory tree looking for manifest files.\n * Mirrors the architecture module's _findManifests() logic, respecting SKIP_DIRS.\n * Includes manifest filenames from standalone plugins in addition to arch parsers.\n */\n private _findManifests(dir: string, results: string[] = []): string[] {\n const manifestFilenames = new Set([\n ...this.archParsers.flatMap(p => p.manifestFiles),\n ...Array.from(this.standalonePlugins.values()).flatMap(p => p.manifestFiles),\n ]);\n\n return this._walkDir(dir, manifestFilenames, results);\n }\n\n private _walkDir(dir: string, manifestFilenames: Set<string>, results: string[]): string[] {\n let entries: fs.Dirent[];\n try {\n entries = fs.readdirSync(dir, { withFileTypes: true });\n } catch {\n return results;\n }\n\n for (const entry of entries) {\n if (entry.isDirectory()) {\n if (!SKIP_DIRS.has(entry.name)) {\n this._walkDir(path.join(dir, entry.name), manifestFilenames, results);\n }\n } else if (entry.isFile()) {\n if (manifestFilenames.has(entry.name) || entry.name.endsWith('.csproj')) {\n results.push(path.join(dir, entry.name));\n }\n }\n }\n\n return results;\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|