@datasynx/agentic-ai-cartography 2.4.0 → 2.5.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 +2 -2
- package/dist/{chunk-X5JA2UDT.js → chunk-GA4427LB.js} +134 -14
- package/dist/chunk-GA4427LB.js.map +1 -0
- package/dist/{chunk-L4OSL7I6.js → chunk-NQXZUWOI.js} +41 -11
- package/dist/chunk-NQXZUWOI.js.map +1 -0
- package/dist/{chunk-B4QWX7CP.js → chunk-RYQ4KQCK.js} +55 -11
- package/dist/chunk-RYQ4KQCK.js.map +1 -0
- package/dist/cli.js +87 -8
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +262 -26
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +223 -3
- package/dist/index.d.ts +223 -3
- package/dist/index.js +244 -24
- package/dist/index.js.map +1 -1
- package/dist/mcp-bin.js +2 -2
- package/package.json +1 -1
- package/server.json +2 -2
- package/dist/chunk-B4QWX7CP.js.map +0 -1
- package/dist/chunk-L4OSL7I6.js.map +0 -1
- package/dist/chunk-X5JA2UDT.js.map +0 -1
package/dist/cli.js
CHANGED
|
@@ -11,21 +11,22 @@ import {
|
|
|
11
11
|
runDrift,
|
|
12
12
|
runLocalDiscovery,
|
|
13
13
|
startMcp
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-RYQ4KQCK.js";
|
|
15
15
|
import {
|
|
16
16
|
startApi
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-NQXZUWOI.js";
|
|
18
18
|
import {
|
|
19
19
|
CartographyDB,
|
|
20
20
|
buildCartographyToolHandlers,
|
|
21
21
|
createCartographyTools,
|
|
22
22
|
deriveSessionName,
|
|
23
23
|
diffTopology,
|
|
24
|
+
hashToken,
|
|
24
25
|
normalizeTenant,
|
|
25
26
|
redactValue,
|
|
26
27
|
stableStringify,
|
|
27
28
|
stripSensitive
|
|
28
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-GA4427LB.js";
|
|
29
30
|
import {
|
|
30
31
|
ConfigFileSchema,
|
|
31
32
|
CostEntrySchema,
|
|
@@ -52,6 +53,7 @@ import {
|
|
|
52
53
|
} from "./chunk-2SZ5QHGH.js";
|
|
53
54
|
|
|
54
55
|
// src/cli.ts
|
|
56
|
+
import { randomBytes } from "crypto";
|
|
55
57
|
import { Command } from "commander";
|
|
56
58
|
|
|
57
59
|
// src/preflight.ts
|
|
@@ -114,6 +116,30 @@ function checkClaudePrerequisites() {
|
|
|
114
116
|
}
|
|
115
117
|
}
|
|
116
118
|
|
|
119
|
+
// src/auth/types.ts
|
|
120
|
+
import { z } from "zod";
|
|
121
|
+
var ROLES = ["viewer", "operator", "admin"];
|
|
122
|
+
var RoleSchema = z.enum(ROLES);
|
|
123
|
+
var ACTIONS = ["read", "discovery", "admin"];
|
|
124
|
+
var ActionSchema = z.enum(ACTIONS);
|
|
125
|
+
var PrincipalSchema = z.object({
|
|
126
|
+
subject: z.string().min(1),
|
|
127
|
+
tenant: z.string().min(1),
|
|
128
|
+
role: RoleSchema
|
|
129
|
+
});
|
|
130
|
+
var CredentialConfigSchema = z.object({
|
|
131
|
+
token: z.string().min(1),
|
|
132
|
+
subject: z.string().min(1),
|
|
133
|
+
tenant: z.string().optional(),
|
|
134
|
+
role: RoleSchema.default("viewer")
|
|
135
|
+
});
|
|
136
|
+
var AuthConfigSchema = z.object({
|
|
137
|
+
/** Seed credentials (merged into the SQLite store on startup). */
|
|
138
|
+
credentials: z.array(CredentialConfigSchema).optional(),
|
|
139
|
+
/** Reject unauthenticated requests even on loopback (default: loopback dev stays open). */
|
|
140
|
+
required: z.boolean().optional()
|
|
141
|
+
});
|
|
142
|
+
|
|
117
143
|
// src/providers/types.ts
|
|
118
144
|
var ProviderRegistry = class {
|
|
119
145
|
factories = /* @__PURE__ */ new Map();
|
|
@@ -274,13 +300,13 @@ function createClaudeProvider() {
|
|
|
274
300
|
}
|
|
275
301
|
|
|
276
302
|
// src/providers/shell.ts
|
|
277
|
-
import { z } from "zod";
|
|
303
|
+
import { z as z2 } from "zod";
|
|
278
304
|
function createBashTool() {
|
|
279
305
|
const shell = IS_WIN ? "powershell" : "posix";
|
|
280
306
|
return {
|
|
281
307
|
name: "Bash",
|
|
282
308
|
description: "Run a read-only shell command (inspect ports, processes, config). Mutating or destructive commands are blocked by the read-only allowlist.",
|
|
283
|
-
inputShape: { command:
|
|
309
|
+
inputShape: { command: z2.string().describe("The read-only shell command to run") },
|
|
284
310
|
annotations: { readOnlyHint: true, openWorldHint: true },
|
|
285
311
|
handler: async (args) => {
|
|
286
312
|
const command = String(args["command"] ?? "").trim();
|
|
@@ -4961,7 +4987,7 @@ ${infraSummary.substring(0, 12e3)}`;
|
|
|
4961
4987
|
db.close();
|
|
4962
4988
|
}
|
|
4963
4989
|
});
|
|
4964
|
-
program.command("mcp").description("Run the Model Context Protocol server (stdio by default) \u2014 the primary interface for AI agents").option("--http", "Use Streamable HTTP transport instead of stdio", false).option("--port <n>", "HTTP port", "3737").option("--host <h>", "HTTP host", "127.0.0.1").option("--allowed-hosts <list>", "Comma-separated Host allowlist (required for non-loopback --host)").option("--token <secret>", "Bearer token required on HTTP requests (or CARTOGRAPHY_HTTP_TOKEN); mandatory for non-loopback --host").option("--db <path>", "DB path").option("--session <id>", 'Session to serve (id or "latest")', "latest").option("--tenant <id>", "Tenant/organization whose topology to serve (alias: --org; default: local)").option("--org <id>", "Alias for --tenant").option("--no-semantic", "Disable semantic (vector) search").option("--plugins <list>", "Comma-separated scanner plugin package names to load (opt-in; or CARTOGRAPHY_PLUGINS)").option("--server-mode", "Run as a central collector: enable the authenticated POST /ingest write route + org-wide summary (implies --http; opt-in)", false).option("--anon-mode <mode>", "On ingest, reject|strip un-anonymized identifying fragments (server-mode)", "reject").action(async (opts) => {
|
|
4990
|
+
program.command("mcp").description("Run the Model Context Protocol server (stdio by default) \u2014 the primary interface for AI agents").option("--http", "Use Streamable HTTP transport instead of stdio", false).option("--port <n>", "HTTP port", "3737").option("--host <h>", "HTTP host", "127.0.0.1").option("--allowed-hosts <list>", "Comma-separated Host allowlist (required for non-loopback --host)").option("--token <secret>", "Bearer token required on HTTP requests (or CARTOGRAPHY_HTTP_TOKEN); mandatory for non-loopback --host").option("--db <path>", "DB path").option("--session <id>", 'Session to serve (id or "latest")', "latest").option("--tenant <id>", "Tenant/organization whose topology to serve (alias: --org; default: local)").option("--org <id>", "Alias for --tenant").option("--no-semantic", "Disable semantic (vector) search").option("--plugins <list>", "Comma-separated scanner plugin package names to load (opt-in; or CARTOGRAPHY_PLUGINS)").option("--server-mode", "Run as a central collector: enable the authenticated POST /ingest write route + org-wide summary (implies --http; opt-in)", false).option("--anon-mode <mode>", "On ingest, reject|strip un-anonymized identifying fragments (server-mode)", "reject").option("--auth-required", "Reject unauthenticated requests even on loopback (RBAC required mode)", false).action(async (opts) => {
|
|
4965
4991
|
try {
|
|
4966
4992
|
const anonMode = opts.anonMode;
|
|
4967
4993
|
if (anonMode !== "reject" && anonMode !== "strip") {
|
|
@@ -4983,7 +5009,8 @@ error: --anon-mode must be 'reject' or 'strip' (got '${anonMode}')
|
|
|
4983
5009
|
semantic: opts.semantic,
|
|
4984
5010
|
plugins: opts.plugins ? String(opts.plugins).split(",").map((p) => p.trim()).filter(Boolean) : void 0,
|
|
4985
5011
|
serverMode: opts.serverMode === true,
|
|
4986
|
-
anonMode
|
|
5012
|
+
anonMode,
|
|
5013
|
+
authRequired: opts.authRequired === true
|
|
4987
5014
|
});
|
|
4988
5015
|
} catch (err) {
|
|
4989
5016
|
process.stderr.write(`
|
|
@@ -4992,9 +5019,10 @@ error: ${err instanceof Error ? err.message : String(err)}
|
|
|
4992
5019
|
process.exitCode = 1;
|
|
4993
5020
|
}
|
|
4994
5021
|
});
|
|
4995
|
-
program.command("api").description("Run the read-only REST/GraphQL API server over the topology store (4.2)").option("--http", "Use HTTP transport (default; kept for symmetry with mcp)", true).option("--port <n>", "HTTP port", "3737").option("--host <h>", "HTTP host", "127.0.0.1").option("--allowed-hosts <list>", "Comma-separated Host allowlist (required for non-loopback --host)").option("--allowed-origins <list>", "Comma-separated CORS Origin allowlist (default: same-origin only)").option("--token <secret>", "Bearer token required on requests (or CARTOGRAPHY_HTTP_TOKEN); mandatory for non-loopback --host").option("--db <path>", "DB path").option("--session <id>", 'Session to serve (id or "latest")', "latest").option("--tenant <id>", "Default tenant whose topology to serve (alias: --org; default: local)").option("--org <id>", "Alias for --tenant").option("--no-graphql", "Disable the /graphql endpoint (REST only)").action(async (opts) => {
|
|
5022
|
+
program.command("api").description("Run the read-only REST/GraphQL API server over the topology store (4.2)").option("--http", "Use HTTP transport (default; kept for symmetry with mcp)", true).option("--port <n>", "HTTP port", "3737").option("--host <h>", "HTTP host", "127.0.0.1").option("--allowed-hosts <list>", "Comma-separated Host allowlist (required for non-loopback --host)").option("--allowed-origins <list>", "Comma-separated CORS Origin allowlist (default: same-origin only)").option("--token <secret>", "Bearer token required on requests (or CARTOGRAPHY_HTTP_TOKEN); mandatory for non-loopback --host").option("--db <path>", "DB path").option("--session <id>", 'Session to serve (id or "latest")', "latest").option("--tenant <id>", "Default tenant whose topology to serve (alias: --org; default: local)").option("--org <id>", "Alias for --tenant").option("--no-graphql", "Disable the /graphql endpoint (REST only)").option("--auth-required", "Reject unauthenticated requests even on loopback (RBAC required mode)", false).action(async (opts) => {
|
|
4996
5023
|
try {
|
|
4997
5024
|
await startApi({
|
|
5025
|
+
authRequired: opts.authRequired === true,
|
|
4998
5026
|
port: parseInt(opts.port, 10),
|
|
4999
5027
|
host: opts.host,
|
|
5000
5028
|
allowedHosts: opts.allowedHosts ? String(opts.allowedHosts).split(",").map((h) => h.trim()).filter(Boolean) : void 0,
|
|
@@ -5012,6 +5040,57 @@ error: ${err instanceof Error ? err.message : String(err)}
|
|
|
5012
5040
|
process.exitCode = 1;
|
|
5013
5041
|
}
|
|
5014
5042
|
});
|
|
5043
|
+
const authCmd = program.command("auth").description("Manage RBAC credentials for the HTTP surfaces (MCP transport + API server, 4.5)");
|
|
5044
|
+
authCmd.command("add <subject>").description("Create a credential and print its bearer token ONCE (only the hash is stored)").option("--role <role>", "viewer | operator | admin", "viewer").option("--tenant <id>", "Tenant the credential is scoped to (default: local)").option("--token <secret>", "Use this token instead of generating one").option("--db <path>", "DB path").action((subject, opts) => {
|
|
5045
|
+
const role = RoleSchema.safeParse(opts.role);
|
|
5046
|
+
if (!role.success) {
|
|
5047
|
+
process.stderr.write(`
|
|
5048
|
+
error: --role must be one of viewer|operator|admin (got '${opts.role}')
|
|
5049
|
+
`);
|
|
5050
|
+
process.exitCode = 1;
|
|
5051
|
+
return;
|
|
5052
|
+
}
|
|
5053
|
+
const db = new CartographyDB(opts.db ?? defaultConfig().dbPath);
|
|
5054
|
+
try {
|
|
5055
|
+
const token = opts.token ?? randomBytes(24).toString("base64url");
|
|
5056
|
+
const tenant = normalizeTenant(opts.tenant);
|
|
5057
|
+
db.addCredential({ tokenHash: hashToken(token), subject, tenant, role: role.data });
|
|
5058
|
+
process.stderr.write(`
|
|
5059
|
+
\u2713 credential added: subject=${subject} role=${role.data} tenant=${tenant}
|
|
5060
|
+
`);
|
|
5061
|
+
process.stderr.write(` Bearer token (shown once \u2014 store it now):
|
|
5062
|
+
|
|
5063
|
+
`);
|
|
5064
|
+
process.stdout.write(token + "\n");
|
|
5065
|
+
} finally {
|
|
5066
|
+
db.close();
|
|
5067
|
+
}
|
|
5068
|
+
});
|
|
5069
|
+
authCmd.command("list").description("List credentials (subjects/roles/tenants \u2014 token hashes only, never the raw token)").option("--db <path>", "DB path").action((opts) => {
|
|
5070
|
+
const db = new CartographyDB(opts.db ?? defaultConfig().dbPath);
|
|
5071
|
+
try {
|
|
5072
|
+
const creds = db.listCredentials();
|
|
5073
|
+
if (creds.length === 0) {
|
|
5074
|
+
process.stderr.write("No credentials configured (open/shared-token mode).\n");
|
|
5075
|
+
return;
|
|
5076
|
+
}
|
|
5077
|
+
for (const c of creds) process.stdout.write(`${c.subject} ${c.role} ${c.tenant} ${c.createdAt}
|
|
5078
|
+
`);
|
|
5079
|
+
} finally {
|
|
5080
|
+
db.close();
|
|
5081
|
+
}
|
|
5082
|
+
});
|
|
5083
|
+
authCmd.command("revoke <subject>").description("Revoke all credentials for a subject").option("--db <path>", "DB path").action((subject, opts) => {
|
|
5084
|
+
const db = new CartographyDB(opts.db ?? defaultConfig().dbPath);
|
|
5085
|
+
try {
|
|
5086
|
+
const n = db.revokeCredentialsBySubject(subject);
|
|
5087
|
+
process.stderr.write(n > 0 ? `\u2713 revoked ${n} credential(s) for ${subject}
|
|
5088
|
+
` : `no credentials found for ${subject}
|
|
5089
|
+
`);
|
|
5090
|
+
} finally {
|
|
5091
|
+
db.close();
|
|
5092
|
+
}
|
|
5093
|
+
});
|
|
5015
5094
|
const o = (s) => process.stderr.write(s);
|
|
5016
5095
|
o("\n");
|
|
5017
5096
|
o(cyan(" ____ _ ____ ") + "\n");
|