nexarch 0.12.15 → 0.12.16

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.
@@ -3,7 +3,7 @@ import { execFileSync } from "child_process";
3
3
  import { resolve } from "path";
4
4
  import { callMcpTool } from "../lib/mcp.js";
5
5
  import { parseTerraformStateBuffer, projectTerraformState, inferEnvironmentFromTags, environmentSubtypeFor, } from "../lib/terraform-projection.js";
6
- import { loadTerraformCatalogue, describeCatalogue } from "../lib/terraform-catalogue.js";
6
+ import { loadIacCatalogue, describeCatalogue } from "../lib/iac-catalogue.js";
7
7
  import { discoverRootModules, environmentFromPath } from "../lib/terraform-detect.js";
8
8
  const ENTITY_BATCH = 50;
9
9
  function readResult(raw) {
@@ -321,7 +321,7 @@ export async function ingestInfra(args) {
321
321
  // Fetched once and used for both projection and payload: two different
322
322
  // catalogues within one ingest would produce entities whose attributes and
323
323
  // whose type mapping disagreed about what a resource is.
324
- const catalogueResult = await loadTerraformCatalogue();
324
+ const catalogueResult = await loadIacCatalogue();
325
325
  if (!asJson)
326
326
  console.log(` ${describeCatalogue(catalogueResult)}`);
327
327
  const catalogue = catalogueResult.entries;
@@ -0,0 +1,227 @@
1
+ /**
2
+ * Fallback catalogue for Terraform resource types.
3
+ *
4
+ * GENERATED FILE — DO NOT EDIT BY HAND.
5
+ * Regenerate with: node web/scripts/export-iac-catalogue.mjs
6
+ *
7
+ * The catalogue proper is platform reference data, curated in
8
+ * `iac_catalogue_entry` and served to every tenant, so supporting a new
9
+ * service is a data change rather than a CLI release. This file is what the CLI
10
+ * falls back to when it cannot reach the platform — offline, or a CI runner with
11
+ * no route to the gateway. It is generated from that table so it can never get
12
+ * ahead of it: editing it by hand recreates the two-sources-of-truth problem
13
+ * moving the catalogue out of the CLI was meant to end.
14
+ *
15
+ * 25 entries, exported 2026-08-21.
16
+ */
17
+ export const IAC_CATALOGUE_SEED = [
18
+ {
19
+ resourceType: "azurerm_container_app_environment",
20
+ entityTypeCode: "platform_component",
21
+ entitySubtypeCode: "platform_runtime",
22
+ role: "compute_environment",
23
+ attributes: ["name", "location", "resource_group_name", "default_domain", "infrastructure_subnet_id", "internal_load_balancer_enabled", "static_ip_address", "zone_redundancy_enabled"],
24
+ references: { "infrastructure_subnet_id": "azurerm_subnet" },
25
+ cloudResourceType: "Microsoft.App/managedEnvironments",
26
+ },
27
+ {
28
+ resourceType: "azurerm_service_plan",
29
+ entityTypeCode: "platform_component",
30
+ entitySubtypeCode: "platform_runtime",
31
+ role: "compute_environment",
32
+ attributes: ["name", "location", "resource_group_name", "sku_name", "os_type", "worker_count"],
33
+ cloudResourceType: "Microsoft.Web/serverfarms",
34
+ },
35
+ {
36
+ resourceType: "azurerm_cognitive_account",
37
+ entityTypeCode: "platform_component",
38
+ entitySubtypeCode: "platform_service",
39
+ role: "compute_host",
40
+ attributes: ["name", "location", "resource_group_name", "kind", "sku_name", "endpoint", "custom_subdomain_name", "public_network_access_enabled", "local_auth_enabled"],
41
+ cloudResourceType: "Microsoft.CognitiveServices/accounts",
42
+ },
43
+ {
44
+ resourceType: "azurerm_container_app",
45
+ entityTypeCode: "platform_component",
46
+ entitySubtypeCode: "platform_runtime",
47
+ role: "compute_host",
48
+ bindable: true,
49
+ attributes: ["name", "location", "resource_group_name", "container_app_environment_id", "revision_mode", "workload_profile_name"],
50
+ references: { "container_app_environment_id": "azurerm_container_app_environment" },
51
+ cloudResourceType: "Microsoft.App/containerApps",
52
+ },
53
+ {
54
+ resourceType: "azurerm_container_app_job",
55
+ entityTypeCode: "platform_component",
56
+ entitySubtypeCode: "platform_runtime",
57
+ role: "compute_host",
58
+ bindable: true,
59
+ attributes: ["name", "location", "resource_group_name", "container_app_environment_id", "replica_timeout_in_seconds", "workload_profile_name"],
60
+ references: { "container_app_environment_id": "azurerm_container_app_environment" },
61
+ cloudResourceType: "Microsoft.App/jobs",
62
+ },
63
+ {
64
+ resourceType: "azurerm_linux_web_app",
65
+ entityTypeCode: "platform_component",
66
+ entitySubtypeCode: "platform_runtime",
67
+ role: "compute_host",
68
+ bindable: true,
69
+ attributes: ["name", "location", "resource_group_name", "service_plan_id", "https_only", "default_hostname"],
70
+ references: { "service_plan_id": "azurerm_service_plan" },
71
+ cloudResourceType: "Microsoft.Web/sites",
72
+ },
73
+ {
74
+ resourceType: "azurerm_cosmosdb_account",
75
+ entityTypeCode: "data_store",
76
+ entitySubtypeCode: "store_document",
77
+ role: "data_store",
78
+ attributes: ["name", "location", "resource_group_name", "kind", "offer_type", "public_network_access_enabled", "endpoint"],
79
+ cloudResourceType: "Microsoft.DocumentDB/databaseAccounts",
80
+ },
81
+ {
82
+ resourceType: "azurerm_postgresql_flexible_server",
83
+ entityTypeCode: "data_store",
84
+ entitySubtypeCode: "store_relational",
85
+ role: "data_store",
86
+ attributes: ["name", "location", "resource_group_name", "fqdn", "version", "sku_name", "storage_mb", "storage_tier", "public_network_access_enabled", "delegated_subnet_id", "private_dns_zone_id", "backup_retention_days", "geo_redundant_backup_enabled", "zone"],
87
+ cloudResourceType: "Microsoft.DBforPostgreSQL/flexibleServers",
88
+ },
89
+ {
90
+ resourceType: "azurerm_postgresql_flexible_server_database",
91
+ entityTypeCode: "data_store",
92
+ entitySubtypeCode: "store_relational",
93
+ role: "data_store",
94
+ attributes: ["name", "server_id", "charset", "collation"],
95
+ cloudResourceType: "Microsoft.DBforPostgreSQL/flexibleServers/databases",
96
+ },
97
+ {
98
+ resourceType: "azurerm_storage_account",
99
+ entityTypeCode: "data_store",
100
+ entitySubtypeCode: "store_object",
101
+ role: "data_store",
102
+ attributes: ["name", "location", "resource_group_name", "account_kind", "account_tier", "account_replication_type", "access_tier", "https_traffic_only_enabled", "min_tls_version", "public_network_access_enabled", "allow_nested_items_to_be_public", "shared_access_key_enabled", "primary_blob_endpoint", "primary_location", "secondary_location"],
103
+ cloudResourceType: "Microsoft.Storage/storageAccounts",
104
+ },
105
+ {
106
+ resourceType: "azurerm_storage_container",
107
+ entityTypeCode: "data_store",
108
+ entitySubtypeCode: "store_object",
109
+ role: "data_store",
110
+ attributes: ["name", "container_access_type", "storage_account_id", "has_immutability_policy"],
111
+ cloudResourceType: "Microsoft.Storage/storageAccounts/blobServices/containers",
112
+ },
113
+ {
114
+ resourceType: "azurerm_cdn_frontdoor_endpoint",
115
+ entityTypeCode: "platform_component",
116
+ entitySubtypeCode: "platform_service",
117
+ role: "edge",
118
+ attributes: ["name", "host_name", "enabled", "cdn_frontdoor_profile_id"],
119
+ references: { "cdn_frontdoor_profile_id": "azurerm_cdn_frontdoor_profile" },
120
+ cloudResourceType: "Microsoft.Cdn/profiles/afdEndpoints",
121
+ },
122
+ {
123
+ resourceType: "azurerm_cdn_frontdoor_firewall_policy",
124
+ entityTypeCode: "policy_control",
125
+ role: "edge",
126
+ attributes: ["name", "location", "resource_group_name", "sku_name", "mode", "enabled"],
127
+ cloudResourceType: "Microsoft.Network/frontDoorWebApplicationFirewallPolicies",
128
+ },
129
+ {
130
+ resourceType: "azurerm_cdn_frontdoor_profile",
131
+ entityTypeCode: "platform_component",
132
+ entitySubtypeCode: "platform_service",
133
+ role: "edge",
134
+ attributes: ["name", "location", "resource_group_name", "sku_name", "response_timeout_seconds"],
135
+ cloudResourceType: "Microsoft.Cdn/profiles",
136
+ },
137
+ {
138
+ resourceType: "azurerm_role_assignment",
139
+ entityTypeCode: "policy_control",
140
+ role: "identity",
141
+ attributes: ["name", "principal_id", "principal_type", "role_definition_name", "scope"],
142
+ cloudResourceType: "Microsoft.Authorization/roleAssignments",
143
+ },
144
+ {
145
+ resourceType: "azurerm_user_assigned_identity",
146
+ entityTypeCode: "platform_component",
147
+ entitySubtypeCode: "platform_control_plane",
148
+ role: "identity",
149
+ attributes: ["name", "location", "resource_group_name", "client_id", "principal_id", "tenant_id"],
150
+ cloudResourceType: "Microsoft.ManagedIdentity/userAssignedIdentities",
151
+ },
152
+ {
153
+ resourceType: "azurerm_servicebus_namespace",
154
+ entityTypeCode: "platform_component",
155
+ entitySubtypeCode: "platform_service",
156
+ role: "messaging",
157
+ attributes: ["name", "location", "resource_group_name", "sku", "public_network_access_enabled"],
158
+ cloudResourceType: "Microsoft.ServiceBus/namespaces",
159
+ },
160
+ {
161
+ resourceType: "azurerm_servicebus_queue",
162
+ entityTypeCode: "platform_component",
163
+ entitySubtypeCode: "platform_service",
164
+ role: "messaging",
165
+ attributes: ["name", "namespace_id", "max_delivery_count", "requires_session"],
166
+ references: { "namespace_id": "azurerm_servicebus_namespace" },
167
+ cloudResourceType: "Microsoft.ServiceBus/namespaces/queues",
168
+ },
169
+ {
170
+ resourceType: "azurerm_private_dns_zone",
171
+ entityTypeCode: "platform_component",
172
+ entitySubtypeCode: "platform_service",
173
+ role: "network_boundary",
174
+ attributes: ["name", "resource_group_name", "number_of_record_sets"],
175
+ cloudResourceType: "Microsoft.Network/privateDnsZones",
176
+ },
177
+ {
178
+ resourceType: "azurerm_private_endpoint",
179
+ entityTypeCode: "platform_component",
180
+ entitySubtypeCode: "platform_service",
181
+ role: "network_boundary",
182
+ attributes: ["name", "location", "resource_group_name", "subnet_id"],
183
+ references: { "subnet_id": "azurerm_subnet" },
184
+ cloudResourceType: "Microsoft.Network/privateEndpoints",
185
+ },
186
+ {
187
+ resourceType: "azurerm_subnet",
188
+ entityTypeCode: "platform_component",
189
+ entitySubtypeCode: "platform_service",
190
+ role: "network_boundary",
191
+ attributes: ["name", "resource_group_name", "virtual_network_name", "address_prefixes", "default_outbound_access_enabled", "private_endpoint_network_policies"],
192
+ nameReferences: { "virtual_network_name": "azurerm_virtual_network" },
193
+ cloudResourceType: "Microsoft.Network/virtualNetworks/subnets",
194
+ },
195
+ {
196
+ resourceType: "azurerm_virtual_network",
197
+ entityTypeCode: "platform_component",
198
+ entitySubtypeCode: "platform_service",
199
+ role: "network_boundary",
200
+ attributes: ["name", "location", "resource_group_name", "address_space", "guid"],
201
+ cloudResourceType: "Microsoft.Network/virtualNetworks",
202
+ },
203
+ {
204
+ resourceType: "azurerm_log_analytics_workspace",
205
+ entityTypeCode: "platform_component",
206
+ entitySubtypeCode: "platform_service",
207
+ role: "observability",
208
+ attributes: ["name", "location", "resource_group_name", "sku", "retention_in_days", "workspace_id"],
209
+ cloudResourceType: "Microsoft.OperationalInsights/workspaces",
210
+ },
211
+ {
212
+ resourceType: "azurerm_container_registry",
213
+ entityTypeCode: "platform_component",
214
+ entitySubtypeCode: "platform_service",
215
+ role: "registry",
216
+ attributes: ["name", "location", "resource_group_name", "login_server", "sku", "admin_enabled", "public_network_access_enabled"],
217
+ cloudResourceType: "Microsoft.ContainerRegistry/registries",
218
+ },
219
+ {
220
+ resourceType: "azurerm_key_vault",
221
+ entityTypeCode: "platform_component",
222
+ entitySubtypeCode: "platform_service",
223
+ role: "secret_store",
224
+ attributes: ["name", "location", "resource_group_name", "vault_uri", "sku_name", "enable_rbac_authorization", "rbac_authorization_enabled", "public_network_access_enabled", "purge_protection_enabled", "soft_delete_retention_days"],
225
+ cloudResourceType: "Microsoft.KeyVault/vaults",
226
+ },
227
+ ];
@@ -0,0 +1,41 @@
1
+ import { callMcpTool } from "./mcp.js";
2
+ import { IAC_CATALOGUE_SEED } from "./iac-catalogue-seed.js";
3
+ /**
4
+ * Rejects a payload that would widen what may be read.
5
+ *
6
+ * A served catalogue is a network response, and this one decides what leaves
7
+ * the machine. An entry with no attributes is meaningless — it would project a
8
+ * resource stripped of all evidence — and an entry missing its type mapping
9
+ * cannot be applied at all, so neither is accepted quietly. Terraform's own
10
+ * `sensitive_values` gate still runs behind whatever survives here.
11
+ */
12
+ function usableEntries(payload) {
13
+ return (payload.entries ?? []).filter((entry) => typeof entry?.resourceType === "string" &&
14
+ typeof entry?.entityTypeCode === "string" &&
15
+ Array.isArray(entry?.attributes) &&
16
+ entry.attributes.length > 0 &&
17
+ entry.attributes.every((attribute) => typeof attribute === "string"));
18
+ }
19
+ export async function loadIacCatalogue() {
20
+ try {
21
+ const raw = await callMcpTool("nexarch_get_iac_catalogue", {});
22
+ const payload = JSON.parse(raw.content?.[0]?.text ?? "{}");
23
+ const entries = usableEntries(payload);
24
+ // An empty or unparseable response is not a reason to ingest nothing: the
25
+ // bundled copy is known-good and was generated from this same table.
26
+ if (entries.length === 0) {
27
+ return { entries: IAC_CATALOGUE_SEED, source: "bundled", reason: "the platform returned no usable entries" };
28
+ }
29
+ return { entries, source: "platform", reason: null };
30
+ }
31
+ catch (error) {
32
+ const message = error instanceof Error ? error.message : String(error);
33
+ return { entries: IAC_CATALOGUE_SEED, source: "bundled", reason: message };
34
+ }
35
+ }
36
+ /** One line describing which catalogue was used, so a stale ingest is never silent. */
37
+ export function describeCatalogue(result) {
38
+ if (result.source === "platform")
39
+ return `Catalogue: ${result.entries.length} resource types from the platform.`;
40
+ return `Catalogue: ${result.entries.length} resource types from the bundled copy — ${result.reason}.\n Types added to the platform since this CLI was published will not be recognised.`;
41
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nexarch",
3
- "version": "0.12.15",
3
+ "version": "0.12.16",
4
4
  "description": "Your architecture workspace for AI delivery.",
5
5
  "keywords": [
6
6
  "nexarch",