@datasynx/agentic-ai-cartography 2.3.0 → 2.4.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/dist/api-bin.js +3 -3
- package/dist/{chunk-B2AKONVW.js → chunk-B4QWX7CP.js} +201 -48
- package/dist/chunk-B4QWX7CP.js.map +1 -0
- package/dist/{chunk-7VZH5PFV.js → chunk-L4OSL7I6.js} +3 -3
- package/dist/{chunk-WCR47QA2.js → chunk-QQOQBE2A.js} +16 -5
- package/dist/chunk-QQOQBE2A.js.map +1 -0
- package/dist/{chunk-7QEBFMN4.js → chunk-X5JA2UDT.js} +14 -5
- package/dist/chunk-X5JA2UDT.js.map +1 -0
- package/dist/cli.js +5 -5
- package/dist/index.cjs +241 -50
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +168 -9
- package/dist/index.d.ts +168 -9
- package/dist/index.js +232 -50
- package/dist/index.js.map +1 -1
- package/dist/mcp-bin.js +3 -3
- package/dist/{types-TJWXAQ2L.js → types-5L3AGZLG.js} +2 -2
- package/package.json +1 -1
- package/server.json +2 -2
- package/dist/chunk-7QEBFMN4.js.map +0 -1
- package/dist/chunk-B2AKONVW.js.map +0 -1
- package/dist/chunk-WCR47QA2.js.map +0 -1
- /package/dist/{chunk-7VZH5PFV.js.map → chunk-L4OSL7I6.js.map} +0 -0
- /package/dist/{types-TJWXAQ2L.js.map → types-5L3AGZLG.js.map} +0 -0
package/dist/cli.js
CHANGED
|
@@ -11,10 +11,10 @@ import {
|
|
|
11
11
|
runDrift,
|
|
12
12
|
runLocalDiscovery,
|
|
13
13
|
startMcp
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-B4QWX7CP.js";
|
|
15
15
|
import {
|
|
16
16
|
startApi
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-L4OSL7I6.js";
|
|
18
18
|
import {
|
|
19
19
|
CartographyDB,
|
|
20
20
|
buildCartographyToolHandlers,
|
|
@@ -25,7 +25,7 @@ import {
|
|
|
25
25
|
redactValue,
|
|
26
26
|
stableStringify,
|
|
27
27
|
stripSensitive
|
|
28
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-X5JA2UDT.js";
|
|
29
29
|
import {
|
|
30
30
|
ConfigFileSchema,
|
|
31
31
|
CostEntrySchema,
|
|
@@ -36,7 +36,7 @@ import {
|
|
|
36
36
|
SharingLevelSchema,
|
|
37
37
|
centralDbFromEnv,
|
|
38
38
|
defaultConfig
|
|
39
|
-
} from "./chunk-
|
|
39
|
+
} from "./chunk-QQOQBE2A.js";
|
|
40
40
|
import {
|
|
41
41
|
IS_MAC,
|
|
42
42
|
IS_WIN,
|
|
@@ -4508,7 +4508,7 @@ ${infraSummary.substring(0, 12e3)}`;
|
|
|
4508
4508
|
`);
|
|
4509
4509
|
return;
|
|
4510
4510
|
}
|
|
4511
|
-
const { NODE_TYPES } = await import("./types-
|
|
4511
|
+
const { NODE_TYPES } = await import("./types-5L3AGZLG.js");
|
|
4512
4512
|
if (!process.stdin.isTTY) {
|
|
4513
4513
|
w(red("\n \u2717 Interactive mode requires a terminal (use --file for non-interactive)\n\n"));
|
|
4514
4514
|
process.exitCode = 1;
|
package/dist/index.cjs
CHANGED
|
@@ -46,14 +46,17 @@ __export(src_exports, {
|
|
|
46
46
|
INGEST_SCHEMA_VERSION: () => INGEST_SCHEMA_VERSION,
|
|
47
47
|
IngestEnvelopeSchema: () => IngestEnvelopeSchema,
|
|
48
48
|
InvalidTenantError: () => InvalidTenantError,
|
|
49
|
+
JiraSink: () => JiraSink,
|
|
49
50
|
LOOPBACK_HOSTS: () => LOOPBACK_HOSTS2,
|
|
50
51
|
MCP_BIN: () => MCP_BIN,
|
|
51
52
|
NotFoundError: () => NotFoundError,
|
|
52
53
|
PACKAGE_NAME: () => PACKAGE_NAME,
|
|
54
|
+
PAGERDUTY_ENQUEUE_URL: () => PAGERDUTY_ENQUEUE_URL,
|
|
53
55
|
PERSONAL: () => PERSONAL,
|
|
54
56
|
PORT_MAP: () => PORT_MAP,
|
|
55
57
|
PRIVATE_IP: () => PRIVATE_IP,
|
|
56
58
|
PUSH_SCHEMA_VERSION: () => PUSH_SCHEMA_VERSION,
|
|
59
|
+
PagerDutySink: () => PagerDutySink,
|
|
57
60
|
ProviderRegistry: () => ProviderRegistry,
|
|
58
61
|
RELATION_TO_DIRECTION: () => RELATION_TO_DIRECTION,
|
|
59
62
|
RuleCheckSchema: () => RuleCheckSchema,
|
|
@@ -65,6 +68,7 @@ __export(src_exports, {
|
|
|
65
68
|
ScannerRegistry: () => ScannerRegistry,
|
|
66
69
|
ScannerShape: () => ScannerShape,
|
|
67
70
|
SharingLevelSchema: () => SharingLevelSchema,
|
|
71
|
+
SlackSink: () => SlackSink,
|
|
68
72
|
SqliteQueryBackend: () => SqliteQueryBackend,
|
|
69
73
|
SqliteStoreBackend: () => SqliteStoreBackend,
|
|
70
74
|
StdoutSink: () => StdoutSink,
|
|
@@ -149,6 +153,9 @@ __export(src_exports, {
|
|
|
149
153
|
filterBySeverity: () => filterBySeverity,
|
|
150
154
|
findAnonViolations: () => findAnonViolations,
|
|
151
155
|
formatComplianceText: () => formatComplianceText,
|
|
156
|
+
formatJira: () => formatJira,
|
|
157
|
+
formatPagerDuty: () => formatPagerDuty,
|
|
158
|
+
formatSlack: () => formatSlack,
|
|
152
159
|
generateDependencyMermaid: () => generateDependencyMermaid,
|
|
153
160
|
generateDiffMermaid: () => generateDiffMermaid,
|
|
154
161
|
generateTopologyMermaid: () => generateTopologyMermaid,
|
|
@@ -171,6 +178,7 @@ __export(src_exports, {
|
|
|
171
178
|
isPersonalHost: () => isPersonalHost,
|
|
172
179
|
isReadOnlyCommand: () => isReadOnlyCommand,
|
|
173
180
|
isRemembered: () => isRemembered,
|
|
181
|
+
isSecureWebhookUrl: () => isSecureWebhookUrl,
|
|
174
182
|
k8sScanner: () => k8sScanner,
|
|
175
183
|
keyMetaOf: () => keyMetaOf,
|
|
176
184
|
layoutClusters: () => layoutClusters,
|
|
@@ -209,6 +217,7 @@ __export(src_exports, {
|
|
|
209
217
|
pixelToHex: () => pixelToHex,
|
|
210
218
|
planInstall: () => planInstall,
|
|
211
219
|
portsScanner: () => portsScanner,
|
|
220
|
+
postJson: () => postJson,
|
|
212
221
|
previewShare: () => previewShare,
|
|
213
222
|
pseudonymize: () => pseudonymize,
|
|
214
223
|
pseudonymizeFragment: () => pseudonymizeFragment,
|
|
@@ -417,15 +426,26 @@ var SECURITY_METADATA_KEYS = [
|
|
|
417
426
|
var DriftConfigSchema = import_zod.z.object({
|
|
418
427
|
minSeverity: import_zod.z.enum(SEVERITIES).default("info"),
|
|
419
428
|
sinks: import_zod.z.array(import_zod.z.object({
|
|
420
|
-
type: import_zod.z.enum(["stdout", "webhook"]),
|
|
429
|
+
type: import_zod.z.enum(["stdout", "webhook", "slack", "pagerduty", "jira"]),
|
|
421
430
|
url: import_zod.z.string().url().optional(),
|
|
422
431
|
token: import_zod.z.string().optional(),
|
|
423
|
-
timeoutMs: import_zod.z.number().int().positive().optional()
|
|
432
|
+
timeoutMs: import_zod.z.number().int().positive().optional(),
|
|
433
|
+
routingKey: import_zod.z.string().optional(),
|
|
434
|
+
email: import_zod.z.string().optional(),
|
|
435
|
+
project: import_zod.z.string().optional(),
|
|
436
|
+
issueType: import_zod.z.string().optional()
|
|
424
437
|
})).default([{ type: "stdout" }])
|
|
425
438
|
}).superRefine((cfg, ctx) => {
|
|
426
439
|
for (const [i, s] of cfg.sinks.entries()) {
|
|
427
|
-
|
|
428
|
-
ctx.addIssue({ code: "custom", path: ["sinks", i, "url"], message:
|
|
440
|
+
const requireUrl = (msg) => {
|
|
441
|
+
if (!s.url) ctx.addIssue({ code: "custom", path: ["sinks", i, "url"], message: msg });
|
|
442
|
+
};
|
|
443
|
+
if (s.type === "webhook") requireUrl("webhook sink requires a url");
|
|
444
|
+
if (s.type === "slack") requireUrl("slack sink requires a webhook url");
|
|
445
|
+
if (s.type === "jira") {
|
|
446
|
+
requireUrl("jira sink requires a base url");
|
|
447
|
+
if (!s.email) ctx.addIssue({ code: "custom", path: ["sinks", i, "email"], message: "jira sink requires an email" });
|
|
448
|
+
if (!s.project) ctx.addIssue({ code: "custom", path: ["sinks", i, "project"], message: "jira sink requires a project key" });
|
|
429
449
|
}
|
|
430
450
|
}
|
|
431
451
|
});
|
|
@@ -2039,8 +2059,17 @@ function stripSensitive(target) {
|
|
|
2039
2059
|
const stripped = `${url.hostname}${url.port ? ":" + url.port : ""}`;
|
|
2040
2060
|
return stripped || raw;
|
|
2041
2061
|
} catch {
|
|
2042
|
-
|
|
2043
|
-
|
|
2062
|
+
let s = raw;
|
|
2063
|
+
const slash = s.indexOf("/");
|
|
2064
|
+
if (slash >= 0) s = s.slice(0, slash);
|
|
2065
|
+
const q = s.indexOf("?");
|
|
2066
|
+
if (q >= 0) s = s.slice(0, q);
|
|
2067
|
+
const at = s.indexOf("@");
|
|
2068
|
+
if (at >= 0) {
|
|
2069
|
+
const colon = s.lastIndexOf(":");
|
|
2070
|
+
if (colon > at) s = s.slice(0, at) + ":" + s.slice(colon + 1);
|
|
2071
|
+
}
|
|
2072
|
+
return s || raw;
|
|
2044
2073
|
}
|
|
2045
2074
|
}
|
|
2046
2075
|
var SCAN_ARG_PATTERNS = {
|
|
@@ -2058,7 +2087,7 @@ function assertSafeScanArg(kind, value) {
|
|
|
2058
2087
|
return value;
|
|
2059
2088
|
}
|
|
2060
2089
|
function redactSecrets(value) {
|
|
2061
|
-
return value.replace(/([a-z][a-z0-9+.-]
|
|
2090
|
+
return value.replace(/([a-z][a-z0-9+.-]{0,63}:\/\/[^:@/\s]{1,256}):[^@/\s]{1,256}@/gi, "$1:***@");
|
|
2062
2091
|
}
|
|
2063
2092
|
function redactValue(value) {
|
|
2064
2093
|
if (typeof value === "string") return redactSecrets(value);
|
|
@@ -5156,6 +5185,41 @@ var StdoutSink = class {
|
|
|
5156
5185
|
|
|
5157
5186
|
// src/sinks/webhook.ts
|
|
5158
5187
|
var LOOPBACK_HOSTS = /* @__PURE__ */ new Set(["localhost", "127.0.0.1", "[::1]", "::1"]);
|
|
5188
|
+
async function postJson(opts) {
|
|
5189
|
+
const doFetch = opts.fetchImpl ?? (typeof fetch === "function" ? fetch : void 0);
|
|
5190
|
+
if (!doFetch) {
|
|
5191
|
+
logWarn("sink unavailable: global fetch missing", { sink: opts.sinkName });
|
|
5192
|
+
return;
|
|
5193
|
+
}
|
|
5194
|
+
if (!opts.url) {
|
|
5195
|
+
logWarn("sink unavailable: no url configured", { sink: opts.sinkName });
|
|
5196
|
+
return;
|
|
5197
|
+
}
|
|
5198
|
+
if (!isSecureWebhookUrl(opts.url)) {
|
|
5199
|
+
logWarn("sink refused: insecure scheme (use https:// or a loopback host)", {
|
|
5200
|
+
sink: opts.sinkName,
|
|
5201
|
+
host: stripSensitive(opts.url)
|
|
5202
|
+
});
|
|
5203
|
+
return;
|
|
5204
|
+
}
|
|
5205
|
+
try {
|
|
5206
|
+
const res = await doFetch(opts.url, {
|
|
5207
|
+
method: "POST",
|
|
5208
|
+
headers: { "content-type": "application/json", ...opts.headers ?? {} },
|
|
5209
|
+
body: JSON.stringify(opts.body),
|
|
5210
|
+
signal: AbortSignal.timeout(opts.timeoutMs ?? 1e4)
|
|
5211
|
+
});
|
|
5212
|
+
if (!res.ok) {
|
|
5213
|
+
logError("sink delivery failed", { sink: opts.sinkName, host: stripSensitive(opts.url), status: res.status });
|
|
5214
|
+
}
|
|
5215
|
+
} catch (err) {
|
|
5216
|
+
logError("sink delivery failed", {
|
|
5217
|
+
sink: opts.sinkName,
|
|
5218
|
+
host: stripSensitive(opts.url),
|
|
5219
|
+
reason: err instanceof Error ? err.message : String(err)
|
|
5220
|
+
});
|
|
5221
|
+
}
|
|
5222
|
+
}
|
|
5159
5223
|
function isSecureWebhookUrl(url, env = process.env) {
|
|
5160
5224
|
if (env.CARTOGRAPHY_ALLOW_INSECURE_SYNC === "1") return true;
|
|
5161
5225
|
let parsed;
|
|
@@ -5174,59 +5238,177 @@ var WebhookSink = class {
|
|
|
5174
5238
|
}
|
|
5175
5239
|
name = "webhook";
|
|
5176
5240
|
async emit(alert) {
|
|
5177
|
-
if (typeof fetch !== "function") {
|
|
5178
|
-
logWarn("webhook sink unavailable: global fetch missing", { sink: this.name });
|
|
5179
|
-
return;
|
|
5180
|
-
}
|
|
5181
5241
|
const { url, token, timeoutMs } = this.opts;
|
|
5182
|
-
|
|
5183
|
-
|
|
5184
|
-
|
|
5185
|
-
|
|
5186
|
-
|
|
5187
|
-
|
|
5188
|
-
|
|
5189
|
-
|
|
5190
|
-
|
|
5191
|
-
|
|
5192
|
-
|
|
5193
|
-
|
|
5194
|
-
|
|
5195
|
-
|
|
5196
|
-
|
|
5197
|
-
|
|
5198
|
-
|
|
5199
|
-
|
|
5200
|
-
|
|
5201
|
-
|
|
5202
|
-
|
|
5203
|
-
|
|
5204
|
-
|
|
5242
|
+
await postJson({
|
|
5243
|
+
url,
|
|
5244
|
+
body: redactValue(alert),
|
|
5245
|
+
...token ? { headers: { authorization: `Bearer ${token}` } } : {},
|
|
5246
|
+
...timeoutMs !== void 0 ? { timeoutMs } : {},
|
|
5247
|
+
sinkName: this.name
|
|
5248
|
+
});
|
|
5249
|
+
}
|
|
5250
|
+
};
|
|
5251
|
+
|
|
5252
|
+
// src/sinks/providers.ts
|
|
5253
|
+
var MAX_ITEMS2 = 20;
|
|
5254
|
+
var SEVERITY_EMOJI = { info: "\u{1F7E2}", warning: "\u{1F7E1}", critical: "\u{1F534}" };
|
|
5255
|
+
function headline(alert) {
|
|
5256
|
+
const s = alert.summary;
|
|
5257
|
+
return `${s.nodesAdded}+ / ${s.nodesRemoved}- / ${s.nodesChanged}~ nodes, ${s.edgesAdded}+ / ${s.edgesRemoved}- edges`;
|
|
5258
|
+
}
|
|
5259
|
+
function itemLine(it) {
|
|
5260
|
+
const sec = it.securityFields?.length ? ` [security: ${it.securityFields.join(", ")}]` : "";
|
|
5261
|
+
const fields = it.changedFields?.length ? ` (${it.changedFields.join(", ")})` : "";
|
|
5262
|
+
return `${it.severity.toUpperCase()} \xB7 ${it.kind} \xB7 ${it.label}${fields}${sec}`;
|
|
5263
|
+
}
|
|
5264
|
+
function bodyText(alert) {
|
|
5265
|
+
const lines = alert.items.slice(0, MAX_ITEMS2).map(itemLine);
|
|
5266
|
+
const more = alert.items.length > MAX_ITEMS2 ? [`\u2026and ${alert.items.length - MAX_ITEMS2} more`] : [];
|
|
5267
|
+
return [headline(alert), "", ...lines, ...more].join("\n");
|
|
5268
|
+
}
|
|
5269
|
+
function formatSlack(alert) {
|
|
5270
|
+
const title = `${SEVERITY_EMOJI[alert.severity]} Topology drift \u2014 ${alert.severity}`;
|
|
5271
|
+
return {
|
|
5272
|
+
text: `${title}: ${headline(alert)}`,
|
|
5273
|
+
blocks: [
|
|
5274
|
+
{ type: "header", text: { type: "plain_text", text: title, emoji: true } },
|
|
5275
|
+
{ type: "section", text: { type: "mrkdwn", text: "```" + bodyText(alert) + "```" } },
|
|
5276
|
+
{ type: "context", elements: [{ type: "mrkdwn", text: `base ${alert.base.sessionId} \u2192 current ${alert.current.sessionId} \xB7 ${alert.generatedAt}` }] }
|
|
5277
|
+
]
|
|
5278
|
+
};
|
|
5279
|
+
}
|
|
5280
|
+
var PD_SEVERITY = {
|
|
5281
|
+
info: "info",
|
|
5282
|
+
warning: "warning",
|
|
5283
|
+
critical: "critical"
|
|
5284
|
+
};
|
|
5285
|
+
function formatPagerDuty(alert, routingKey) {
|
|
5286
|
+
return {
|
|
5287
|
+
routing_key: routingKey,
|
|
5288
|
+
event_action: "trigger",
|
|
5289
|
+
// Stable per base→current pair so repeated alerts for the same delta de-duplicate.
|
|
5290
|
+
dedup_key: `cartograph-drift:${alert.base.sessionId}:${alert.current.sessionId}`,
|
|
5291
|
+
payload: {
|
|
5292
|
+
summary: `Cartograph topology drift (${alert.severity}): ${headline(alert)}`,
|
|
5293
|
+
source: "cartograph",
|
|
5294
|
+
severity: PD_SEVERITY[alert.severity],
|
|
5295
|
+
timestamp: alert.generatedAt,
|
|
5296
|
+
custom_details: {
|
|
5297
|
+
summary: alert.summary,
|
|
5298
|
+
items: alert.items.slice(0, MAX_ITEMS2).map((it) => ({
|
|
5299
|
+
kind: it.kind,
|
|
5300
|
+
ref: it.ref,
|
|
5301
|
+
severity: it.severity,
|
|
5302
|
+
...it.changedFields ? { changedFields: it.changedFields } : {},
|
|
5303
|
+
...it.securityFields ? { securityFields: it.securityFields } : {}
|
|
5304
|
+
}))
|
|
5205
5305
|
}
|
|
5206
|
-
} catch (err) {
|
|
5207
|
-
logError("webhook sink failed", {
|
|
5208
|
-
sink: this.name,
|
|
5209
|
-
host: stripSensitive(url),
|
|
5210
|
-
reason: err instanceof Error ? err.message : String(err)
|
|
5211
|
-
});
|
|
5212
5306
|
}
|
|
5307
|
+
};
|
|
5308
|
+
}
|
|
5309
|
+
function formatJira(alert, opts) {
|
|
5310
|
+
return {
|
|
5311
|
+
fields: {
|
|
5312
|
+
project: { key: opts.project },
|
|
5313
|
+
issuetype: { name: opts.issueType ?? "Task" },
|
|
5314
|
+
summary: `Cartograph topology drift (${alert.severity}): ${headline(alert)}`,
|
|
5315
|
+
description: bodyText(alert) + `
|
|
5316
|
+
|
|
5317
|
+
base ${alert.base.sessionId} \u2192 current ${alert.current.sessionId}
|
|
5318
|
+
generated ${alert.generatedAt}`
|
|
5319
|
+
}
|
|
5320
|
+
};
|
|
5321
|
+
}
|
|
5322
|
+
|
|
5323
|
+
// src/sinks/provider-sink.ts
|
|
5324
|
+
var PAGERDUTY_ENQUEUE_URL = "https://events.pagerduty.com/v2/enqueue";
|
|
5325
|
+
function deliver(name, url, body, opts, headers) {
|
|
5326
|
+
return postJson({
|
|
5327
|
+
url,
|
|
5328
|
+
body,
|
|
5329
|
+
sinkName: name,
|
|
5330
|
+
...headers ? { headers } : {},
|
|
5331
|
+
...opts.timeoutMs !== void 0 ? { timeoutMs: opts.timeoutMs } : {},
|
|
5332
|
+
...opts.fetchImpl ? { fetchImpl: opts.fetchImpl } : {}
|
|
5333
|
+
});
|
|
5334
|
+
}
|
|
5335
|
+
var SlackSink = class {
|
|
5336
|
+
constructor(opts) {
|
|
5337
|
+
this.opts = opts;
|
|
5338
|
+
}
|
|
5339
|
+
name = "slack";
|
|
5340
|
+
async emit(alert) {
|
|
5341
|
+
await deliver(this.name, this.opts.url, formatSlack(redactValue(alert)), this.opts);
|
|
5342
|
+
}
|
|
5343
|
+
};
|
|
5344
|
+
var PagerDutySink = class {
|
|
5345
|
+
constructor(opts) {
|
|
5346
|
+
this.opts = opts;
|
|
5347
|
+
}
|
|
5348
|
+
name = "pagerduty";
|
|
5349
|
+
async emit(alert) {
|
|
5350
|
+
const body = formatPagerDuty(redactValue(alert), this.opts.routingKey);
|
|
5351
|
+
await deliver(this.name, this.opts.url || PAGERDUTY_ENQUEUE_URL, body, this.opts);
|
|
5352
|
+
}
|
|
5353
|
+
};
|
|
5354
|
+
var JiraSink = class {
|
|
5355
|
+
constructor(opts) {
|
|
5356
|
+
this.opts = opts;
|
|
5357
|
+
}
|
|
5358
|
+
name = "jira";
|
|
5359
|
+
async emit(alert) {
|
|
5360
|
+
const body = formatJira(redactValue(alert), {
|
|
5361
|
+
project: this.opts.project,
|
|
5362
|
+
...this.opts.issueType ? { issueType: this.opts.issueType } : {}
|
|
5363
|
+
});
|
|
5364
|
+
const auth = Buffer.from(`${this.opts.email}:${this.opts.token}`).toString("base64");
|
|
5365
|
+
const base = this.opts.url.replace(/\/+$/, "");
|
|
5366
|
+
await deliver(this.name, `${base}/rest/api/2/issue`, body, this.opts, { authorization: `Basic ${auth}` });
|
|
5213
5367
|
}
|
|
5214
5368
|
};
|
|
5215
5369
|
|
|
5216
5370
|
// src/sinks/index.ts
|
|
5217
5371
|
function buildSinks(drift) {
|
|
5218
5372
|
const configs = drift?.sinks && drift.sinks.length > 0 ? drift.sinks : [{ type: "stdout" }];
|
|
5373
|
+
const envSecret = process.env.CARTOGRAPHY_DRIFT_TOKEN;
|
|
5219
5374
|
const sinks = [];
|
|
5220
5375
|
for (const s of configs) {
|
|
5221
|
-
|
|
5222
|
-
|
|
5223
|
-
|
|
5224
|
-
|
|
5225
|
-
|
|
5226
|
-
|
|
5227
|
-
|
|
5228
|
-
|
|
5229
|
-
|
|
5376
|
+
const timeoutMs = s.timeoutMs;
|
|
5377
|
+
switch (s.type) {
|
|
5378
|
+
case "webhook":
|
|
5379
|
+
if (!s.url) {
|
|
5380
|
+
logWarn("drift sink skipped: webhook requires a url", { sink: s.type });
|
|
5381
|
+
break;
|
|
5382
|
+
}
|
|
5383
|
+
sinks.push(new WebhookSink({ url: s.url, token: s.token ?? envSecret, timeoutMs }));
|
|
5384
|
+
break;
|
|
5385
|
+
case "slack":
|
|
5386
|
+
if (!s.url) {
|
|
5387
|
+
logWarn("drift sink skipped: slack requires a webhook url", { sink: s.type });
|
|
5388
|
+
break;
|
|
5389
|
+
}
|
|
5390
|
+
sinks.push(new SlackSink({ url: s.url, timeoutMs }));
|
|
5391
|
+
break;
|
|
5392
|
+
case "pagerduty": {
|
|
5393
|
+
const routingKey = s.routingKey ?? s.token ?? envSecret;
|
|
5394
|
+
if (!routingKey) {
|
|
5395
|
+
logWarn("drift sink skipped: pagerduty requires a routingKey (or CARTOGRAPHY_DRIFT_TOKEN)", { sink: s.type });
|
|
5396
|
+
break;
|
|
5397
|
+
}
|
|
5398
|
+
sinks.push(new PagerDutySink({ url: s.url ?? PAGERDUTY_ENQUEUE_URL, routingKey, timeoutMs }));
|
|
5399
|
+
break;
|
|
5400
|
+
}
|
|
5401
|
+
case "jira": {
|
|
5402
|
+
const token = s.token ?? envSecret;
|
|
5403
|
+
if (!s.url || !s.email || !s.project || !token) {
|
|
5404
|
+
logWarn("drift sink skipped: jira requires url, email, project and a token", { sink: s.type });
|
|
5405
|
+
break;
|
|
5406
|
+
}
|
|
5407
|
+
sinks.push(new JiraSink({ url: s.url, email: s.email, token, project: s.project, issueType: s.issueType, timeoutMs }));
|
|
5408
|
+
break;
|
|
5409
|
+
}
|
|
5410
|
+
default:
|
|
5411
|
+
sinks.push(new StdoutSink());
|
|
5230
5412
|
}
|
|
5231
5413
|
}
|
|
5232
5414
|
return sinks.length > 0 ? sinks : [new StdoutSink()];
|
|
@@ -5635,7 +5817,7 @@ async function resolveNlQuery(db, sessionId, search, raw, opts) {
|
|
|
5635
5817
|
|
|
5636
5818
|
// src/mcp/server.ts
|
|
5637
5819
|
var SERVER_NAME = "cartography";
|
|
5638
|
-
var SERVER_VERSION = "2.
|
|
5820
|
+
var SERVER_VERSION = "2.4.0";
|
|
5639
5821
|
var SERVICE_TYPES = NODE_TYPE_GROUPS.web;
|
|
5640
5822
|
var DATA_TYPES = NODE_TYPE_GROUPS.data;
|
|
5641
5823
|
var lexicalSearch = async (db, sessionId, query, opts) => db.searchNodes(sessionId, query, { types: opts.types, limit: opts.limit }).map((node) => ({ node }));
|
|
@@ -11393,14 +11575,17 @@ function checkClaudePrerequisites() {
|
|
|
11393
11575
|
INGEST_SCHEMA_VERSION,
|
|
11394
11576
|
IngestEnvelopeSchema,
|
|
11395
11577
|
InvalidTenantError,
|
|
11578
|
+
JiraSink,
|
|
11396
11579
|
LOOPBACK_HOSTS,
|
|
11397
11580
|
MCP_BIN,
|
|
11398
11581
|
NotFoundError,
|
|
11399
11582
|
PACKAGE_NAME,
|
|
11583
|
+
PAGERDUTY_ENQUEUE_URL,
|
|
11400
11584
|
PERSONAL,
|
|
11401
11585
|
PORT_MAP,
|
|
11402
11586
|
PRIVATE_IP,
|
|
11403
11587
|
PUSH_SCHEMA_VERSION,
|
|
11588
|
+
PagerDutySink,
|
|
11404
11589
|
ProviderRegistry,
|
|
11405
11590
|
RELATION_TO_DIRECTION,
|
|
11406
11591
|
RuleCheckSchema,
|
|
@@ -11412,6 +11597,7 @@ function checkClaudePrerequisites() {
|
|
|
11412
11597
|
ScannerRegistry,
|
|
11413
11598
|
ScannerShape,
|
|
11414
11599
|
SharingLevelSchema,
|
|
11600
|
+
SlackSink,
|
|
11415
11601
|
SqliteQueryBackend,
|
|
11416
11602
|
SqliteStoreBackend,
|
|
11417
11603
|
StdoutSink,
|
|
@@ -11496,6 +11682,9 @@ function checkClaudePrerequisites() {
|
|
|
11496
11682
|
filterBySeverity,
|
|
11497
11683
|
findAnonViolations,
|
|
11498
11684
|
formatComplianceText,
|
|
11685
|
+
formatJira,
|
|
11686
|
+
formatPagerDuty,
|
|
11687
|
+
formatSlack,
|
|
11499
11688
|
generateDependencyMermaid,
|
|
11500
11689
|
generateDiffMermaid,
|
|
11501
11690
|
generateTopologyMermaid,
|
|
@@ -11518,6 +11707,7 @@ function checkClaudePrerequisites() {
|
|
|
11518
11707
|
isPersonalHost,
|
|
11519
11708
|
isReadOnlyCommand,
|
|
11520
11709
|
isRemembered,
|
|
11710
|
+
isSecureWebhookUrl,
|
|
11521
11711
|
k8sScanner,
|
|
11522
11712
|
keyMetaOf,
|
|
11523
11713
|
layoutClusters,
|
|
@@ -11556,6 +11746,7 @@ function checkClaudePrerequisites() {
|
|
|
11556
11746
|
pixelToHex,
|
|
11557
11747
|
planInstall,
|
|
11558
11748
|
portsScanner,
|
|
11749
|
+
postJson,
|
|
11559
11750
|
previewShare,
|
|
11560
11751
|
pseudonymize,
|
|
11561
11752
|
pseudonymizeFragment,
|