@datasynx/agentic-ai-cartography 2.10.0 → 2.11.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 CHANGED
@@ -2,8 +2,8 @@
2
2
  import {
3
3
  parseApiArgs,
4
4
  startApi
5
- } from "./chunk-W4Q3TXHR.js";
6
- import "./chunk-YVV6NIT2.js";
5
+ } from "./chunk-PD67MOKR.js";
6
+ import "./chunk-LO6YFS6H.js";
7
7
  import "./chunk-QQOQBE2A.js";
8
8
  import "./chunk-2SZ5QHGH.js";
9
9
 
@@ -20,12 +20,13 @@ import {
20
20
  k8sScanner,
21
21
  keyMetaOf,
22
22
  normalizeTenant,
23
+ redactSecrets,
23
24
  redactValue,
24
25
  resolvePrincipal,
25
26
  sanitizeUntrusted,
26
27
  stableStringify,
27
28
  stripSensitive
28
- } from "./chunk-YVV6NIT2.js";
29
+ } from "./chunk-LO6YFS6H.js";
29
30
  import {
30
31
  EdgeSchema,
31
32
  NODE_TYPES,
@@ -653,9 +654,132 @@ var serviceConfigScanner = {
653
654
  }
654
655
  };
655
656
 
657
+ // src/scanners/terraform.ts
658
+ import { readFileSync } from "fs";
659
+ var TYPE_RULES = [
660
+ [/(db_instance|_rds|sql_database|sql_instance|database_instance|cosmosdb|dynamodb|spanner|bigtable|documentdb|redshift)/, "database_server"],
661
+ [/(elasticache|_redis|memcached|memorystore)/, "cache_server"],
662
+ [/(s3_bucket|storage_bucket|gcs_bucket|storage_account|_blob)/, "database"],
663
+ [/(_sqs|_queue|servicebus_queue)/, "queue"],
664
+ [/(_sns|_topic|pubsub_topic|servicebus_topic)/, "topic"],
665
+ [/(kafka|_msk|event_hub|kinesis)/, "message_broker"],
666
+ [/(_eks|_gke|_aks|kubernetes_cluster|container_cluster)/, "k8s_cluster"],
667
+ [/(ecs_|_container|fargate)/, "container"],
668
+ [/(lambda|cloud_function|cloudfunctions|function_app|cloud_run)/, "web_service"],
669
+ [/(_lb$|load_balancer|_alb|_elb|application_gateway)/, "web_service"],
670
+ [/(api_gateway|apigateway)/, "api_endpoint"],
671
+ [/(_instance|virtual_machine|_vm$|compute_instance)/, "host"]
672
+ ];
673
+ function terraformTypeToNode(tfType) {
674
+ const t = tfType.toLowerCase();
675
+ for (const [re, nt] of TYPE_RULES) if (re.test(t)) return nt;
676
+ return "unknown";
677
+ }
678
+ var IDENTITY_ATTRS = ["id", "arn", "region", "location", "instance_type", "engine", "machine_type"];
679
+ var OWNER_TAGS = ["Owner", "owner", "Team", "team"];
680
+ var SAFE_TAG_KEYS = /* @__PURE__ */ new Set(["Name", "name", "Owner", "owner", "Team", "team", "Env", "env", "Environment", "environment", "Service", "service", "Component", "component", "App", "app", "Project", "project", "Tier", "tier", "Role", "role"]);
681
+ var SECRET_KEY = /pass|secret|token|key|pwd|cred|private/i;
682
+ function attrTags(tags) {
683
+ if (!tags || typeof tags !== "object") return [];
684
+ return Object.entries(tags).filter(([k]) => SAFE_TAG_KEYS.has(k) && !SECRET_KEY.test(k)).map(([k, v]) => `${k}:${redactSecrets(String(v))}`);
685
+ }
686
+ function parseTerraformState(json2) {
687
+ let state;
688
+ try {
689
+ state = JSON.parse(json2);
690
+ } catch {
691
+ return { nodes: [], edges: [] };
692
+ }
693
+ const resources = Array.isArray(state?.resources) ? state.resources : [];
694
+ const nodes = [];
695
+ const edges = [];
696
+ const addrToId = /* @__PURE__ */ new Map();
697
+ for (const raw of resources) {
698
+ const r = raw;
699
+ if (r.mode && r.mode !== "managed") continue;
700
+ if (typeof r.type !== "string" || typeof r.name !== "string") continue;
701
+ const address = `${r.type}.${r.name}`;
702
+ const nt = terraformTypeToNode(r.type);
703
+ const id = `${nt}:terraform:${address}`;
704
+ if (addrToId.has(address)) continue;
705
+ addrToId.set(address, id);
706
+ const inst = Array.isArray(r.instances) ? r.instances[0] : void 0;
707
+ const attrs = inst?.attributes ?? {};
708
+ const identity = { source: "terraform", tfType: r.type };
709
+ for (const k of IDENTITY_ATTRS) if (attrs[k] !== void 0) identity[k] = attrs[k];
710
+ const owner = OWNER_TAGS.map((k) => attrs.tags?.[k]).find((v) => typeof v === "string");
711
+ nodes.push({
712
+ id,
713
+ type: nt,
714
+ name: address,
715
+ discoveredVia: "terraform-state",
716
+ confidence: 0.9,
717
+ // IaC is authoritative declared intent.
718
+ metadata: redactValue(identity),
719
+ tags: attrTags(attrs.tags),
720
+ ...owner ? { owner } : {}
721
+ });
722
+ }
723
+ for (const raw of resources) {
724
+ const r = raw;
725
+ if (r.mode && r.mode !== "managed") continue;
726
+ if (typeof r.type !== "string" || typeof r.name !== "string") continue;
727
+ const srcId = addrToId.get(`${r.type}.${r.name}`);
728
+ if (!srcId) continue;
729
+ const inst = Array.isArray(r.instances) ? r.instances[0] : void 0;
730
+ const deps = Array.isArray(inst?.dependencies) ? inst.dependencies : [];
731
+ for (const dep of deps) {
732
+ if (typeof dep !== "string") continue;
733
+ const tgtId = addrToId.get(dep) ?? addrToId.get(dep.split("[")[0]);
734
+ if (!tgtId || tgtId === srcId) continue;
735
+ edges.push({ sourceId: srcId, targetId: tgtId, relationship: "depends_on", evidence: evidenceLine("config-declared", `terraform depends_on ${dep}`), confidence: 0.85 });
736
+ }
737
+ }
738
+ return { nodes, edges };
739
+ }
740
+ function stateDirs() {
741
+ return [".", "./terraform", "./infra", "./infrastructure", "./deploy", "./terraform/environments"];
742
+ }
743
+ function hintPath(hint) {
744
+ if (!hint) return void 0;
745
+ const m = /(?:^|[\s,])tfstate=([^\s,]+)/.exec(hint);
746
+ return m ? m[1] : void 0;
747
+ }
748
+ function resolveStatePath(ctx) {
749
+ const explicit = hintPath(ctx.hint);
750
+ if (explicit) return explicit;
751
+ const found = (ctx.findFiles ?? findFiles)(stateDirs(), ["*.tfstate"], 4, 20).split(/\r?\n/).map((s) => s.trim()).filter(Boolean);
752
+ return found[0];
753
+ }
754
+ function readStateFile(path) {
755
+ try {
756
+ return readFileSync(path, "utf8");
757
+ } catch {
758
+ return "";
759
+ }
760
+ }
761
+ var terraformScanner = {
762
+ id: "terraform-state",
763
+ title: "Terraform state (IaC)",
764
+ platforms: "all",
765
+ // No shell commands — the state file is read directly via node:fs, so an
766
+ // operator-supplied path can never inject a command (no `cat "${path}"` interpolation).
767
+ detect(ctx) {
768
+ return resolveStatePath(ctx) !== void 0;
769
+ },
770
+ async scan(ctx) {
771
+ const path = resolveStatePath(ctx);
772
+ if (!path) return { nodes: [], edges: [] };
773
+ const json2 = (ctx.readFile ?? readStateFile)(path);
774
+ if (!json2) return { nodes: [], edges: [] };
775
+ const result = parseTerraformState(json2);
776
+ return { ...result, report: `terraform-state: ${result.nodes.length} resources, ${result.edges.length} dependencies from ${path}` };
777
+ }
778
+ };
779
+
656
780
  // src/scanners/registry.ts
657
781
  function defaultRegistry() {
658
- return new ScannerRegistry().register(bookmarksScanner).register(installedAppsScanner).register(portsScanner).register(cloudAwsScanner).register(cloudGcpScanner).register(cloudAzureScanner).register(k8sScanner).register(databasesScanner).register(connectionsScanner).register(serviceConfigScanner);
782
+ return new ScannerRegistry().register(bookmarksScanner).register(installedAppsScanner).register(portsScanner).register(cloudAwsScanner).register(cloudGcpScanner).register(cloudAzureScanner).register(k8sScanner).register(databasesScanner).register(connectionsScanner).register(serviceConfigScanner).register(terraformScanner);
659
783
  }
660
784
 
661
785
  // src/scanners/loader.ts
@@ -1317,7 +1441,7 @@ async function runDrift(db, config, opts = {}) {
1317
1441
 
1318
1442
  // src/orgkey.ts
1319
1443
  import { randomBytes, hkdfSync } from "crypto";
1320
- import { existsSync, mkdirSync, readFileSync, writeFileSync, statSync } from "fs";
1444
+ import { existsSync, mkdirSync, readFileSync as readFileSync2, writeFileSync, statSync } from "fs";
1321
1445
  import { homedir } from "os";
1322
1446
  import { dirname, join } from "path";
1323
1447
  function orgKeyPath(home = homedir()) {
@@ -1333,7 +1457,7 @@ function loadFileSecret(path) {
1333
1457
  }
1334
1458
  } catch {
1335
1459
  }
1336
- const hex = readFileSync(path, "utf8").trim();
1460
+ const hex = readFileSync2(path, "utf8").trim();
1337
1461
  const buf = Buffer.from(hex, "hex");
1338
1462
  if (buf.length === KEY_BYTES) return buf;
1339
1463
  logWarn("org-key file was malformed \u2014 regenerating a fresh org key");
@@ -1676,7 +1800,7 @@ function correlateTopology(nodes, _edges = []) {
1676
1800
 
1677
1801
  // src/mcp/server.ts
1678
1802
  var SERVER_NAME = "cartography";
1679
- var SERVER_VERSION = "2.10.0";
1803
+ var SERVER_VERSION = "2.11.0";
1680
1804
  var SERVICE_TYPES = NODE_TYPE_GROUPS.web;
1681
1805
  var DATA_TYPES = NODE_TYPE_GROUPS.data;
1682
1806
  var lexicalSearch = async (db, sessionId, query, opts) => db.searchNodes(sessionId, query, { types: opts.types, limit: opts.limit }).map((node) => ({ node }));
@@ -3028,4 +3152,4 @@ export {
3028
3152
  parseMcpArgs,
3029
3153
  startMcp
3030
3154
  };
3031
- //# sourceMappingURL=chunk-ASCA3UFM.js.map
3155
+ //# sourceMappingURL=chunk-FFUUNSWP.js.map