@datasynx/agentic-ai-cartography 2.3.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 +3 -3
- package/dist/{chunk-7QEBFMN4.js → chunk-GA4427LB.js} +147 -18
- package/dist/chunk-GA4427LB.js.map +1 -0
- package/dist/{chunk-7VZH5PFV.js → chunk-NQXZUWOI.js} +42 -12
- package/dist/chunk-NQXZUWOI.js.map +1 -0
- package/dist/{chunk-WCR47QA2.js → chunk-QQOQBE2A.js} +16 -5
- package/dist/chunk-QQOQBE2A.js.map +1 -0
- package/dist/{chunk-B2AKONVW.js → chunk-RYQ4KQCK.js} +253 -56
- package/dist/chunk-RYQ4KQCK.js.map +1 -0
- package/dist/cli.js +89 -10
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +502 -75
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +390 -11
- package/dist/index.d.ts +390 -11
- package/dist/index.js +475 -73
- 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-7VZH5PFV.js.map +0 -1
- package/dist/chunk-B2AKONVW.js.map +0 -1
- package/dist/chunk-WCR47QA2.js.map +0 -1
- /package/dist/{types-TJWXAQ2L.js.map → types-5L3AGZLG.js.map} +0 -0
package/dist/api-bin.js
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
import {
|
|
3
3
|
parseApiArgs,
|
|
4
4
|
startApi
|
|
5
|
-
} from "./chunk-
|
|
6
|
-
import "./chunk-
|
|
7
|
-
import "./chunk-
|
|
5
|
+
} from "./chunk-NQXZUWOI.js";
|
|
6
|
+
import "./chunk-GA4427LB.js";
|
|
7
|
+
import "./chunk-QQOQBE2A.js";
|
|
8
8
|
import "./chunk-2SZ5QHGH.js";
|
|
9
9
|
|
|
10
10
|
// src/api-bin.ts
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
NODE_TYPES,
|
|
8
8
|
NODE_TYPE_GROUPS,
|
|
9
9
|
SharingLevelSchema
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-QQOQBE2A.js";
|
|
11
11
|
import {
|
|
12
12
|
HOME,
|
|
13
13
|
IS_LINUX,
|
|
@@ -744,8 +744,17 @@ function stripSensitive(target) {
|
|
|
744
744
|
const stripped = `${url.hostname}${url.port ? ":" + url.port : ""}`;
|
|
745
745
|
return stripped || raw;
|
|
746
746
|
} catch {
|
|
747
|
-
|
|
748
|
-
|
|
747
|
+
let s = raw;
|
|
748
|
+
const slash = s.indexOf("/");
|
|
749
|
+
if (slash >= 0) s = s.slice(0, slash);
|
|
750
|
+
const q = s.indexOf("?");
|
|
751
|
+
if (q >= 0) s = s.slice(0, q);
|
|
752
|
+
const at = s.indexOf("@");
|
|
753
|
+
if (at >= 0) {
|
|
754
|
+
const colon = s.lastIndexOf(":");
|
|
755
|
+
if (colon > at) s = s.slice(0, at) + ":" + s.slice(colon + 1);
|
|
756
|
+
}
|
|
757
|
+
return s || raw;
|
|
749
758
|
}
|
|
750
759
|
}
|
|
751
760
|
var SCAN_ARG_PATTERNS = {
|
|
@@ -763,7 +772,7 @@ function assertSafeScanArg(kind, value) {
|
|
|
763
772
|
return value;
|
|
764
773
|
}
|
|
765
774
|
function redactSecrets(value) {
|
|
766
|
-
return value.replace(/([a-z][a-z0-9+.-]
|
|
775
|
+
return value.replace(/([a-z][a-z0-9+.-]{0,63}:\/\/[^:@/\s]{1,256}):[^@/\s]{1,256}@/gi, "$1:***@");
|
|
767
776
|
}
|
|
768
777
|
function redactValue(value) {
|
|
769
778
|
if (typeof value === "string") return redactSecrets(value);
|
|
@@ -1765,7 +1774,10 @@ CREATE TABLE IF NOT EXISTS activity_events (
|
|
|
1765
1774
|
duration_ms INTEGER,
|
|
1766
1775
|
command TEXT,
|
|
1767
1776
|
result_bytes INTEGER,
|
|
1768
|
-
tenant TEXT NOT NULL DEFAULT 'local'
|
|
1777
|
+
tenant TEXT NOT NULL DEFAULT 'local',
|
|
1778
|
+
actor_subject TEXT,
|
|
1779
|
+
actor_role TEXT,
|
|
1780
|
+
actor_tenant TEXT
|
|
1769
1781
|
);
|
|
1770
1782
|
|
|
1771
1783
|
CREATE TABLE IF NOT EXISTS tasks (
|
|
@@ -1874,6 +1886,16 @@ CREATE INDEX IF NOT EXISTS idx_nodes_tenant_content ON nodes(tenant, content_has
|
|
|
1874
1886
|
CREATE INDEX IF NOT EXISTS idx_contrib_org ON node_contributors(organization, global_id);
|
|
1875
1887
|
CREATE INDEX IF NOT EXISTS idx_nodes_owner ON nodes(session_id, owner);
|
|
1876
1888
|
`;
|
|
1889
|
+
var AUTH_SCHEMA = `
|
|
1890
|
+
CREATE TABLE IF NOT EXISTS auth_credentials (
|
|
1891
|
+
token_hash TEXT PRIMARY KEY,
|
|
1892
|
+
subject TEXT NOT NULL,
|
|
1893
|
+
tenant TEXT NOT NULL DEFAULT 'local',
|
|
1894
|
+
role TEXT NOT NULL,
|
|
1895
|
+
created_at TEXT NOT NULL
|
|
1896
|
+
);
|
|
1897
|
+
CREATE INDEX IF NOT EXISTS idx_auth_subject ON auth_credentials(subject);
|
|
1898
|
+
`;
|
|
1877
1899
|
var CartographyDB = class {
|
|
1878
1900
|
db;
|
|
1879
1901
|
/** 3.6 anomaly settings; defaults apply when no `anomaly` config is supplied. */
|
|
@@ -1893,7 +1915,8 @@ var CartographyDB = class {
|
|
|
1893
1915
|
const version = this.db.pragma("user_version", { simple: true });
|
|
1894
1916
|
if (version === 0) {
|
|
1895
1917
|
this.db.exec(SCHEMA);
|
|
1896
|
-
this.db.
|
|
1918
|
+
this.db.exec(AUTH_SCHEMA);
|
|
1919
|
+
this.db.pragma("user_version = 15");
|
|
1897
1920
|
return;
|
|
1898
1921
|
} else if (version === 1) {
|
|
1899
1922
|
const cols = this.db.prepare("PRAGMA table_info(nodes)").all().map((c) => c.name);
|
|
@@ -2079,6 +2102,18 @@ var CartographyDB = class {
|
|
|
2079
2102
|
}
|
|
2080
2103
|
this.db.pragma("user_version = 14");
|
|
2081
2104
|
}
|
|
2105
|
+
const v14 = this.db.pragma("user_version", { simple: true });
|
|
2106
|
+
if (v14 < 15) {
|
|
2107
|
+
this.db.exec(AUTH_SCHEMA);
|
|
2108
|
+
const ev = this.db.prepare("PRAGMA table_info(activity_events)").all();
|
|
2109
|
+
if (ev.length > 0) {
|
|
2110
|
+
const cols = ev.map((c) => c.name);
|
|
2111
|
+
if (!cols.includes("actor_subject")) this.db.exec("ALTER TABLE activity_events ADD COLUMN actor_subject TEXT");
|
|
2112
|
+
if (!cols.includes("actor_role")) this.db.exec("ALTER TABLE activity_events ADD COLUMN actor_role TEXT");
|
|
2113
|
+
if (!cols.includes("actor_tenant")) this.db.exec("ALTER TABLE activity_events ADD COLUMN actor_tenant TEXT");
|
|
2114
|
+
}
|
|
2115
|
+
this.db.pragma("user_version = 15");
|
|
2116
|
+
}
|
|
2082
2117
|
}
|
|
2083
2118
|
close() {
|
|
2084
2119
|
this.db.pragma("optimize");
|
|
@@ -2509,13 +2544,13 @@ var CartographyDB = class {
|
|
|
2509
2544
|
});
|
|
2510
2545
|
}
|
|
2511
2546
|
// ── Events ──────────────────────────────
|
|
2512
|
-
insertEvent(sessionId, event, taskId) {
|
|
2547
|
+
insertEvent(sessionId, event, taskId, actor) {
|
|
2513
2548
|
const id = crypto.randomUUID();
|
|
2514
2549
|
const tenant = this.tenantOf(sessionId);
|
|
2515
2550
|
this.db.prepare(`
|
|
2516
2551
|
INSERT INTO activity_events
|
|
2517
|
-
(id, session_id, task_id, timestamp, event_type, process, pid, target, target_type, port, command, result_bytes, tenant)
|
|
2518
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
2552
|
+
(id, session_id, task_id, timestamp, event_type, process, pid, target, target_type, port, command, result_bytes, tenant, actor_subject, actor_role, actor_tenant)
|
|
2553
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
2519
2554
|
`).run(
|
|
2520
2555
|
id,
|
|
2521
2556
|
sessionId,
|
|
@@ -2529,9 +2564,52 @@ var CartographyDB = class {
|
|
|
2529
2564
|
event.port ?? null,
|
|
2530
2565
|
event.command ?? null,
|
|
2531
2566
|
event.resultBytes ?? null,
|
|
2532
|
-
tenant
|
|
2567
|
+
tenant,
|
|
2568
|
+
actor?.subject ?? null,
|
|
2569
|
+
actor?.role ?? null,
|
|
2570
|
+
actor?.tenant ?? null
|
|
2533
2571
|
);
|
|
2534
2572
|
}
|
|
2573
|
+
// ── RBAC credential store (4.5) ─────────────
|
|
2574
|
+
/** Number of stored credentials. `0` ⇒ no RBAC configured (fall back to shared/loopback). */
|
|
2575
|
+
countCredentials() {
|
|
2576
|
+
return this.db.prepare("SELECT COUNT(*) AS n FROM auth_credentials").get().n;
|
|
2577
|
+
}
|
|
2578
|
+
/** Look up a credential by its sha256 token hash. */
|
|
2579
|
+
findCredentialByHash(tokenHash) {
|
|
2580
|
+
const r = this.db.prepare("SELECT * FROM auth_credentials WHERE token_hash = ?").get(tokenHash);
|
|
2581
|
+
if (!r) return void 0;
|
|
2582
|
+
return {
|
|
2583
|
+
tokenHash: r["token_hash"],
|
|
2584
|
+
subject: r["subject"],
|
|
2585
|
+
tenant: r["tenant"],
|
|
2586
|
+
role: r["role"],
|
|
2587
|
+
createdAt: r["created_at"]
|
|
2588
|
+
};
|
|
2589
|
+
}
|
|
2590
|
+
/** Upsert a credential (idempotent on the token hash). Stores only the hash, never the raw token. */
|
|
2591
|
+
addCredential(rec) {
|
|
2592
|
+
this.db.prepare(`
|
|
2593
|
+
INSERT INTO auth_credentials (token_hash, subject, tenant, role, created_at)
|
|
2594
|
+
VALUES (?, ?, ?, ?, ?)
|
|
2595
|
+
ON CONFLICT(token_hash) DO UPDATE SET subject = excluded.subject, tenant = excluded.tenant, role = excluded.role
|
|
2596
|
+
`).run(rec.tokenHash, rec.subject, rec.tenant, rec.role, (/* @__PURE__ */ new Date()).toISOString());
|
|
2597
|
+
}
|
|
2598
|
+
/** List all credentials (token hashes only — the raw token is unrecoverable). */
|
|
2599
|
+
listCredentials() {
|
|
2600
|
+
const rows = this.db.prepare("SELECT * FROM auth_credentials ORDER BY created_at").all();
|
|
2601
|
+
return rows.map((r) => ({
|
|
2602
|
+
tokenHash: r["token_hash"],
|
|
2603
|
+
subject: r["subject"],
|
|
2604
|
+
tenant: r["tenant"],
|
|
2605
|
+
role: r["role"],
|
|
2606
|
+
createdAt: r["created_at"]
|
|
2607
|
+
}));
|
|
2608
|
+
}
|
|
2609
|
+
/** Revoke every credential for a subject. Returns the number removed. */
|
|
2610
|
+
revokeCredentialsBySubject(subject) {
|
|
2611
|
+
return this.db.prepare("DELETE FROM auth_credentials WHERE subject = ?").run(subject).changes;
|
|
2612
|
+
}
|
|
2535
2613
|
getEvents(sessionId, since) {
|
|
2536
2614
|
const rows = since ? this.db.prepare("SELECT * FROM activity_events WHERE session_id = ? AND timestamp > ? ORDER BY timestamp").all(sessionId, since) : this.db.prepare("SELECT * FROM activity_events WHERE session_id = ? ORDER BY timestamp").all(sessionId);
|
|
2537
2615
|
return rows.map((r) => {
|
|
@@ -3208,6 +3286,9 @@ var CartographyDB = class {
|
|
|
3208
3286
|
}
|
|
3209
3287
|
};
|
|
3210
3288
|
|
|
3289
|
+
// src/auth/identity.ts
|
|
3290
|
+
import { createHash as createHash2 } from "crypto";
|
|
3291
|
+
|
|
3211
3292
|
// src/api/auth.ts
|
|
3212
3293
|
var LOOPBACK_HOSTS = /* @__PURE__ */ new Set(["127.0.0.1", "localhost", "::1", "[::1]"]);
|
|
3213
3294
|
function isLoopbackHost(host) {
|
|
@@ -3228,11 +3309,6 @@ function bearerToken(header) {
|
|
|
3228
3309
|
const token = rest.trimStart();
|
|
3229
3310
|
return token.length > 0 ? token : void 0;
|
|
3230
3311
|
}
|
|
3231
|
-
function checkBearer(authorizationHeader, token) {
|
|
3232
|
-
if (!token) return true;
|
|
3233
|
-
const provided = bearerToken(authorizationHeader);
|
|
3234
|
-
return provided !== void 0 && timingSafeEqual(provided, token);
|
|
3235
|
-
}
|
|
3236
3312
|
function assertSafeBind(opts) {
|
|
3237
3313
|
if (isLoopbackHost(opts.host)) return;
|
|
3238
3314
|
if (opts.allowedHosts === void 0) {
|
|
@@ -3250,6 +3326,54 @@ function defaultAllowedHosts(host, port) {
|
|
|
3250
3326
|
return [`${host}:${port}`, `localhost:${port}`, `127.0.0.1:${port}`];
|
|
3251
3327
|
}
|
|
3252
3328
|
|
|
3329
|
+
// src/auth/identity.ts
|
|
3330
|
+
function hashToken(token) {
|
|
3331
|
+
return createHash2("sha256").update(token, "utf8").digest("hex");
|
|
3332
|
+
}
|
|
3333
|
+
var SqliteCredentialStore = class {
|
|
3334
|
+
constructor(db) {
|
|
3335
|
+
this.db = db;
|
|
3336
|
+
}
|
|
3337
|
+
count() {
|
|
3338
|
+
return this.db.countCredentials();
|
|
3339
|
+
}
|
|
3340
|
+
findByHash(tokenHash) {
|
|
3341
|
+
return this.db.findCredentialByHash(tokenHash);
|
|
3342
|
+
}
|
|
3343
|
+
};
|
|
3344
|
+
function resolvePrincipal(presentedToken, opts) {
|
|
3345
|
+
const tenant = opts.defaultTenant ?? DEFAULT_TENANT;
|
|
3346
|
+
if (opts.store && opts.store.count() > 0) {
|
|
3347
|
+
if (!presentedToken) return void 0;
|
|
3348
|
+
const rec = opts.store.findByHash(hashToken(presentedToken));
|
|
3349
|
+
return rec ? { subject: rec.subject, tenant: rec.tenant, role: rec.role } : void 0;
|
|
3350
|
+
}
|
|
3351
|
+
if (opts.sharedToken) {
|
|
3352
|
+
if (!presentedToken || !timingSafeEqual(presentedToken, opts.sharedToken)) return void 0;
|
|
3353
|
+
return { subject: "shared-token", tenant, role: "admin" };
|
|
3354
|
+
}
|
|
3355
|
+
if (opts.required) return void 0;
|
|
3356
|
+
return { subject: "anonymous", tenant, role: "admin" };
|
|
3357
|
+
}
|
|
3358
|
+
|
|
3359
|
+
// src/auth/rbac.ts
|
|
3360
|
+
var ROLE_RANK = { viewer: 1, operator: 2, admin: 3 };
|
|
3361
|
+
var ACTION_MIN_ROLE = { read: "viewer", discovery: "operator", admin: "admin" };
|
|
3362
|
+
function can(role, action) {
|
|
3363
|
+
return ROLE_RANK[role] >= ROLE_RANK[ACTION_MIN_ROLE[action]];
|
|
3364
|
+
}
|
|
3365
|
+
var AuthorizationError = class extends Error {
|
|
3366
|
+
constructor(action, role) {
|
|
3367
|
+
super(`forbidden: role '${role}' may not perform '${action}'`);
|
|
3368
|
+
this.action = action;
|
|
3369
|
+
this.role = role;
|
|
3370
|
+
this.name = "AuthorizationError";
|
|
3371
|
+
}
|
|
3372
|
+
};
|
|
3373
|
+
function authorize(principal, action) {
|
|
3374
|
+
if (!can(principal.role, action)) throw new AuthorizationError(action, principal.role);
|
|
3375
|
+
}
|
|
3376
|
+
|
|
3253
3377
|
export {
|
|
3254
3378
|
sanitizeUntrusted,
|
|
3255
3379
|
cloudAwsScanner,
|
|
@@ -3271,8 +3395,13 @@ export {
|
|
|
3271
3395
|
globalId,
|
|
3272
3396
|
deriveSessionName,
|
|
3273
3397
|
CartographyDB,
|
|
3274
|
-
|
|
3398
|
+
bearerToken,
|
|
3275
3399
|
assertSafeBind,
|
|
3276
|
-
defaultAllowedHosts
|
|
3400
|
+
defaultAllowedHosts,
|
|
3401
|
+
hashToken,
|
|
3402
|
+
SqliteCredentialStore,
|
|
3403
|
+
resolvePrincipal,
|
|
3404
|
+
AuthorizationError,
|
|
3405
|
+
authorize
|
|
3277
3406
|
};
|
|
3278
|
-
//# sourceMappingURL=chunk-
|
|
3407
|
+
//# sourceMappingURL=chunk-GA4427LB.js.map
|