thinkwork-cli 0.13.1 → 1.0.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.
Files changed (262) hide show
  1. package/README.md +3 -14
  2. package/dist/{api-client-4DZ266J5.js → api-client-4P4JZOBX.js} +3 -1
  3. package/dist/bowser-6Z6JFAIR.js +2822 -0
  4. package/dist/{chunk-Y2WHJECR.js → chunk-4OMDWYZQ.js} +5 -44
  5. package/dist/chunk-AD2NIWB5.js +6516 -0
  6. package/dist/chunk-DV3MRBR5.js +43 -0
  7. package/dist/chunk-EI5ZX7CN.js +522 -0
  8. package/dist/chunk-EUJ7X6YD.js +126 -0
  9. package/dist/chunk-GG5WKBOX.js +436 -0
  10. package/dist/chunk-I64EZSU5.js +358 -0
  11. package/dist/chunk-KMIJ5KGT.js +128 -0
  12. package/dist/chunk-MWQ7RO76.js +137 -0
  13. package/dist/chunk-OCPHU34C.js +996 -0
  14. package/dist/chunk-OLUQ4U2Z.js +1728 -0
  15. package/dist/chunk-XYM7PE2A.js +2264 -0
  16. package/dist/chunk-YQCYD6NE.js +3299 -0
  17. package/dist/cli.js +49156 -31257
  18. package/dist/commands/enterprise/templates/deploy-repo/scripts/apply-release.mjs +0 -1
  19. package/dist/commands/enterprise/templates/deploy-repo/scripts/smoke.mjs +0 -1
  20. package/dist/commands/enterprise/templates/deploy-repo/terraform/main.tf +0 -14
  21. package/dist/dist-es-2OTNTL4N.js +315 -0
  22. package/dist/dist-es-2XVAH4BQ.js +14726 -0
  23. package/dist/dist-es-3DPDUJAH.js +2000 -0
  24. package/dist/dist-es-BNZTBBVC.js +176 -0
  25. package/dist/dist-es-CD2RBDAC.js +88 -0
  26. package/dist/dist-es-I4FW57PS.js +88 -0
  27. package/dist/dist-es-KL7Y5NB2.js +377 -0
  28. package/dist/dist-es-KVFWJNDY.js +318 -0
  29. package/dist/dist-es-PS73DWNL.js +70 -0
  30. package/dist/dist-es-S3NZQFGT.js +170 -0
  31. package/dist/dist-es-SGCA4P32.js +48 -0
  32. package/dist/dist-es-WBM6J4RA.js +70 -0
  33. package/dist/dist-es-ZGVADYIF.js +485 -0
  34. package/dist/dist-es-ZKC2QKD2.js +377 -0
  35. package/dist/drizzle/0076_scheduled_jobs_marco_backfill.sql +2 -1
  36. package/dist/drizzle/0079_seed_tenant_customize_catalog.sql +1 -0
  37. package/dist/drizzle/0090_brain_schema_extraction.sql +10 -0
  38. package/dist/drizzle/0132_drop_computer_tables.sql +3 -0
  39. package/dist/drizzle/0160_compliance_event_types_plugins.sql +2 -0
  40. package/dist/drizzle/0214_think137_drop_judge_evidence_roi.sql +1 -0
  41. package/dist/drizzle/0216_drop_agent_loop_versions_goal_worker_policy.sql +1 -0
  42. package/dist/drizzle/0227_analyst_reader_role.sql +17 -20
  43. package/dist/drizzle/0230_analyst_rls.sql +28 -36
  44. package/dist/drizzle/0250_kg_schema_extraction.sql +27 -0
  45. package/dist/drizzle/0251_brain_stragglers.sql +21 -0
  46. package/dist/drizzle/0253_drop_brain_substrate.sql +2 -0
  47. package/dist/drizzle/0257_agents_runtime_allow_harness.sql +24 -0
  48. package/dist/drizzle/0261_native_auth_control_plane.sql +332 -0
  49. package/dist/drizzle/0262_auth_subscription_tickets.sql +59 -0
  50. package/dist/drizzle/0263_agentcore_runtime_identifier.sql +69 -0
  51. package/dist/drizzle/0263_drop_workos_auth_runtime.sql +236 -0
  52. package/dist/drizzle/0264_auth_enrollment_attempt_limits.sql +15 -0
  53. package/dist/drizzle/0265_eval_runs_requester_identity.sql +28 -0
  54. package/dist/drizzle/0265_require_fully_valid_auth_publication.sql +27 -0
  55. package/dist/drizzle/0266_auth_identity_recovery_grants.sql +9 -0
  56. package/dist/drizzle/0266_eval_profiles_runtime_type.sql +12 -0
  57. package/dist/drizzle/0267_ontology_candidate_rejections.sql +53 -0
  58. package/dist/drizzle/0268_identity_crosswalk_routing.sql +182 -0
  59. package/dist/drizzle/0269_ontology_system_map.sql +31 -0
  60. package/dist/drizzle/0270_tool_execution_ledger.sql +115 -0
  61. package/dist/drizzle/0271_ontology_twin_declarations.sql +47 -0
  62. package/dist/drizzle/0272_identity_graph_projection_cursor.sql +23 -0
  63. package/dist/drizzle/0273_twin_materialization_suggestions.sql +29 -0
  64. package/dist/drizzle/0274_tenant_mcp_twin_keys.sql +59 -0
  65. package/dist/drizzle/0275_identity_bulk_rebuild_fence.sql +30 -0
  66. package/dist/drizzle/0276_tool_execution_ledger_allow_cascade_delete.sql +18 -0
  67. package/dist/drizzle/0277_knowledge_base_sources.sql +107 -0
  68. package/dist/drizzle/0278_kb_page_transcription.sql +55 -0
  69. package/dist/drizzle/0279_mcp_servers_off_plugin_provenance.sql +93 -0
  70. package/dist/drizzle/0280_work_item_external_refs_drop_plane_provider.sql +46 -0
  71. package/dist/drizzle/0281_tenant_mcp_twin_keys_expiry_suffix.sql +9 -0
  72. package/dist/drizzle/0282_tenant_mcp_twin_keys_grants.sql +24 -0
  73. package/dist/drizzle/0283_agents_agentcore_runtime_dispatch.sql +13 -0
  74. package/dist/drizzle/0284_user_brain_claims.sql +69 -0
  75. package/dist/drizzle/0285_tenant_mcp_twin_keys_trusted_subsystem.sql +30 -0
  76. package/dist/drizzle/0286_brain_analytics_key.sql +26 -0
  77. package/dist/drizzle/0287_brain_subject.sql +25 -0
  78. package/dist/drizzle/0288_multi_lane_identities.sql +25 -0
  79. package/dist/event-streams-7JNLJEEL.js +894 -0
  80. package/dist/event-streams-KDF5RWR6.js +1515 -0
  81. package/dist/loadSso-ETCXTR4I.js +576 -0
  82. package/dist/loadSso-UBD7KUHE.js +583 -0
  83. package/dist/plugins/README.md +2 -2
  84. package/dist/plugins/catalog/package.json +1 -5
  85. package/dist/plugins/catalog/src/__tests__/build-catalog.test.ts +6 -4
  86. package/dist/plugins/catalog/src/__tests__/catalog.test.ts +21 -21
  87. package/dist/plugins/catalog/src/__tests__/contracts.test.ts +102 -94
  88. package/dist/plugins/catalog/src/__tests__/plugin-package.test.ts +7 -8
  89. package/dist/plugins/catalog/src/__tests__/plugin-registry.test.ts +0 -20
  90. package/dist/plugins/catalog/src/contracts.ts +17 -179
  91. package/dist/plugins/catalog/src/registry/generated-first-party.ts +0 -24
  92. package/dist/plugins/n8n/test/integrated-app-contract.test.ts +1 -1
  93. package/dist/plugins/twenty/package.json +2 -1
  94. package/dist/plugins/twenty/scripts/LAMBDA_DEPLOY.md +114 -0
  95. package/dist/plugins/twenty/scripts/build-lambda.sh +29 -0
  96. package/dist/plugins/twenty/scripts/configure-product-views.ts +195 -0
  97. package/dist/plugins/twenty/scripts/lambda-handler.ts +49 -0
  98. package/dist/plugins/twenty/scripts/lib/__tests__/load-attachments.test.ts +38 -0
  99. package/dist/plugins/twenty/scripts/lib/__tests__/load-records.test.ts +145 -2
  100. package/dist/plugins/twenty/scripts/lib/__tests__/mappers.test.ts +397 -151
  101. package/dist/plugins/twenty/scripts/lib/__tests__/members-ensure.test.ts +28 -129
  102. package/dist/plugins/twenty/scripts/lib/__tests__/provision-members-db.test.ts +10 -0
  103. package/dist/plugins/twenty/scripts/lib/__tests__/schema-ensure.test.ts +13 -8
  104. package/dist/plugins/twenty/scripts/lib/lastmile-reader.ts +222 -2
  105. package/dist/plugins/twenty/scripts/lib/load-attachments.ts +29 -0
  106. package/dist/plugins/twenty/scripts/lib/load-records.ts +160 -43
  107. package/dist/plugins/twenty/scripts/lib/mappers.ts +368 -152
  108. package/dist/plugins/twenty/scripts/lib/members-ensure.ts +43 -268
  109. package/dist/plugins/twenty/scripts/lib/provision-members-db.ts +57 -0
  110. package/dist/plugins/twenty/scripts/lib/schema-ensure.ts +136 -31
  111. package/dist/plugins/twenty/scripts/migrate-lastmile.ts +254 -152
  112. package/dist/plugins/twenty/scripts/provision-twenty-members.ts +44 -1
  113. package/dist/plugins/twenty/scripts/purge-lastmile-import.ts +178 -0
  114. package/dist/plugins/twenty/scripts/restructure-products.ts +312 -0
  115. package/dist/plugins/twenty/scripts/retag-stage-values.ts +362 -0
  116. package/dist/plugins/twenty/test/manifest.test.ts +2 -4
  117. package/dist/scripts/post-deploy.sh +79 -1
  118. package/dist/signin-5QZNRSOO.js +821 -0
  119. package/dist/sso-oidc-XK673P54.js +837 -0
  120. package/dist/sts-OXI2UALF.js +1113 -0
  121. package/dist/sts-SQW4NBK3.js +1117 -0
  122. package/dist/terraform/examples/greenfield/main.tf +391 -176
  123. package/dist/terraform/examples/greenfield/terraform.tfvars.example +26 -8
  124. package/dist/terraform/modules/app/agentcore-admin/main.tf +47 -0
  125. package/dist/terraform/modules/app/agentcore-code-interpreter/README.md +39 -47
  126. package/dist/terraform/modules/app/agentcore-code-interpreter/main.tf +13 -66
  127. package/dist/terraform/modules/app/agentcore-identity/main.tf +253 -0
  128. package/dist/terraform/modules/app/agentcore-identity/outputs.tf +51 -0
  129. package/dist/terraform/modules/app/agentcore-identity/scripts/bootstrap_twenty_oauth_client.sh +239 -0
  130. package/dist/terraform/modules/app/agentcore-identity/scripts/delete_identity.sh +22 -0
  131. package/dist/terraform/modules/app/agentcore-identity/scripts/delete_twenty_identity.sh +16 -0
  132. package/dist/terraform/modules/app/agentcore-identity/scripts/delete_workload_identity.sh +19 -0
  133. package/dist/terraform/modules/app/agentcore-identity/scripts/ensure_workload_identity.sh +29 -0
  134. package/dist/terraform/modules/app/agentcore-identity/scripts/read_identity.sh +55 -0
  135. package/dist/terraform/modules/app/agentcore-identity/scripts/reconcile_identity.sh +73 -0
  136. package/dist/terraform/modules/app/agentcore-identity/scripts/reconcile_twenty_identity.sh +45 -0
  137. package/dist/terraform/modules/app/agentcore-identity/scripts/reconcile_twenty_provider.mjs +123 -0
  138. package/dist/terraform/modules/app/agentcore-identity/tests/tainted-marker/after.tf +15 -0
  139. package/dist/terraform/modules/app/agentcore-identity/tests/tainted-marker/before.tf +7 -0
  140. package/dist/terraform/modules/app/agentcore-identity/tests/tainted-marker/identity-after.tf +8 -0
  141. package/dist/terraform/modules/app/agentcore-identity/tests/tainted-marker/identity-before.tf +9 -0
  142. package/dist/terraform/modules/app/agentcore-identity/tests/tainted-marker/thinkwork-after.tf +3 -0
  143. package/dist/terraform/modules/app/agentcore-identity/tests/tainted-marker/thinkwork-before.tf +3 -0
  144. package/dist/terraform/modules/app/agentcore-identity/variables.tf +60 -0
  145. package/dist/terraform/modules/app/agentcore-memory/README.md +46 -9
  146. package/dist/terraform/modules/app/agentcore-memory/main.tf +27 -10
  147. package/dist/terraform/modules/app/agentcore-memory/scripts/create_or_find_memory.sh +156 -24
  148. package/dist/terraform/modules/app/agentcore-pi/README.md +1 -3
  149. package/dist/terraform/modules/app/agentcore-pi/main.tf +42 -52
  150. package/dist/terraform/modules/app/agentcore-pi/outputs.tf +3 -3
  151. package/dist/terraform/modules/app/agentcore-pi/scripts/reconcile_pi_runtime.mjs +175 -0
  152. package/dist/terraform/modules/app/agentcore-pi/variables.tf +35 -28
  153. package/dist/terraform/modules/app/agentcore-platform/main.tf +68 -0
  154. package/dist/terraform/modules/app/agentcore-runtime/main.tf +4 -20
  155. package/dist/terraform/modules/app/appsync-subscriptions/main.tf +127 -21
  156. package/dist/terraform/modules/app/appsync-subscriptions/outputs.tf +0 -6
  157. package/dist/terraform/modules/app/appsync-subscriptions/variables.tf +5 -0
  158. package/dist/terraform/modules/app/capability-broker/main.tf +2 -2
  159. package/dist/terraform/modules/app/capability-broker/variables.tf +11 -0
  160. package/dist/terraform/modules/app/deployment-control-plane/README.md +264 -0
  161. package/dist/terraform/modules/app/deployment-control-plane/buildspec.yml +4 -1
  162. package/dist/terraform/modules/app/deployment-control-plane/main.tf +94 -0
  163. package/dist/terraform/modules/app/deployment-control-plane/outputs.tf +5 -0
  164. package/dist/terraform/modules/app/deployment-control-plane/runner.py +3689 -233
  165. package/dist/terraform/modules/app/deployment-control-plane/test_runner_bundle.py +2579 -140
  166. package/dist/terraform/modules/app/deployment-control-plane/variables.tf +33 -0
  167. package/dist/terraform/modules/app/lambda-api/auth-state.tf +72 -0
  168. package/dist/terraform/modules/app/lambda-api/chat-latency-observability.tf +466 -0
  169. package/dist/terraform/modules/app/lambda-api/dispatch-dlq.tf +55 -0
  170. package/dist/terraform/modules/app/lambda-api/handlers.tf +531 -619
  171. package/dist/terraform/modules/app/lambda-api/iam-grouped.tf +350 -241
  172. package/dist/terraform/modules/app/lambda-api/main.tf +75 -13
  173. package/dist/terraform/modules/app/lambda-api/memory-alarms.tf +3 -28
  174. package/dist/terraform/modules/app/lambda-api/oauth-secrets.tf +1 -2
  175. package/dist/terraform/modules/app/lambda-api/outputs.tf +17 -10
  176. package/dist/terraform/modules/app/lambda-api/runtime-config.tf +3 -21
  177. package/dist/terraform/modules/app/lambda-api/turn-assertion.tf +45 -0
  178. package/dist/terraform/modules/app/lambda-api/variables.tf +307 -121
  179. package/dist/{plugins/n8n/terraform → terraform/modules/app}/n8n/README.md +1 -1
  180. package/dist/{plugins/n8n/terraform → terraform/modules/app}/n8n/main.tf +18 -18
  181. package/dist/terraform/modules/app/sandbox-log-scrubber/README.md +11 -10
  182. package/dist/terraform/modules/app/sandbox-log-scrubber/main.tf +5 -5
  183. package/dist/terraform/modules/app/static-site/main.tf +1 -1
  184. package/dist/terraform/modules/app/www-dns/main.tf +9 -27
  185. package/dist/terraform/modules/app/www-dns/variables.tf +4 -10
  186. package/dist/terraform/modules/data/aurora-postgres/README.md +34 -0
  187. package/dist/terraform/modules/data/aurora-postgres/alarms.tf +82 -0
  188. package/dist/terraform/modules/data/aurora-postgres/main.tf +27 -57
  189. package/dist/terraform/modules/data/aurora-postgres/outputs.tf +0 -9
  190. package/dist/terraform/modules/data/aurora-postgres/variables.tf +41 -0
  191. package/dist/terraform/modules/data/s3-buckets/main.tf +5 -6
  192. package/dist/terraform/modules/foundation/cognito/main.tf +367 -72
  193. package/dist/terraform/modules/foundation/cognito/outputs.tf +47 -0
  194. package/dist/terraform/modules/foundation/cognito/variables.tf +131 -9
  195. package/dist/terraform/modules/thinkwork/README.md +5 -1
  196. package/dist/terraform/modules/thinkwork/main.tf +459 -234
  197. package/dist/terraform/modules/thinkwork/outputs.tf +44 -62
  198. package/dist/terraform/modules/thinkwork/variables.tf +353 -89
  199. package/dist/terraform/schema.graphql +69 -36
  200. package/dist/workspace-defaults/files/INSTRUCTIONS.md +9 -11
  201. package/dist/workspace-defaults/files/MEMORY_GUIDE.md +38 -35
  202. package/dist/workspace-defaults/files/ROUTER.md +1 -1
  203. package/dist/workspace-defaults/files/TOOLS.md +9 -39
  204. package/dist/workspace-defaults/files/USER.md +1 -0
  205. package/dist/workspace-defaults/files/agents/analyst/INSTRUCTIONS.md +6 -3
  206. package/dist/workspace-defaults/files/catalog-skills/brain-brief-builder/SKILL.md +165 -0
  207. package/dist/workspace-defaults/files/catalog-skills/n8n-workflow-operator/SKILL.md +75 -0
  208. package/dist/workspace-defaults/files/catalog-skills/n8n-workflow-operator/references/mcp-tooling.md +40 -0
  209. package/dist/workspace-defaults/files/catalog-skills/n8n-workflow-operator/references/validation-and-handoff.md +40 -0
  210. package/dist/workspace-defaults/files/catalog-skills/n8n-workflow-operator/references/workflow-authoring.md +46 -0
  211. package/dist/workspace-defaults/files/skills/artifact-builder/references/crm-dashboard.md +1 -1
  212. package/dist/workspace-defaults/files/skills/document-composer/SKILL.md +22 -3
  213. package/package.json +3 -2
  214. package/dist/drizzle/0261_thread_turns_origin_turn_index.sql +0 -11
  215. package/dist/plugins/company-data/README.md +0 -49
  216. package/dist/plugins/company-data/package.json +0 -21
  217. package/dist/plugins/company-data/src/index.ts +0 -30
  218. package/dist/plugins/company-data/src/manifest.ts +0 -26
  219. package/dist/plugins/company-data/test/manifest.test.ts +0 -116
  220. package/dist/plugins/company-data/tsconfig.json +0 -8
  221. package/dist/plugins/company-etl/README.md +0 -46
  222. package/dist/plugins/company-etl/package.json +0 -21
  223. package/dist/plugins/company-etl/src/index.ts +0 -29
  224. package/dist/plugins/company-etl/src/manifest.ts +0 -26
  225. package/dist/plugins/company-etl/test/manifest.test.ts +0 -108
  226. package/dist/plugins/company-etl/tsconfig.json +0 -8
  227. package/dist/plugins/lastmile/README.md +0 -50
  228. package/dist/plugins/lastmile/package.json +0 -23
  229. package/dist/plugins/lastmile/smoke/lastmile-plugin-smoke.mjs +0 -661
  230. package/dist/plugins/lastmile/src/api/tasks-adapter.ts +0 -572
  231. package/dist/plugins/lastmile/src/discovery.fixture.ts +0 -64
  232. package/dist/plugins/lastmile/src/index.ts +0 -46
  233. package/dist/plugins/lastmile/src/manifest.ts +0 -139
  234. package/dist/plugins/lastmile/test/api/tasks-adapter.test.ts +0 -266
  235. package/dist/plugins/lastmile/test/discovery.test.ts +0 -88
  236. package/dist/plugins/lastmile/tsconfig.json +0 -8
  237. package/dist/plugins/n8n/smoke/n8n-managed-app-smoke.mjs +0 -409
  238. package/dist/plugins/twenty/smoke/twenty-managed-app-smoke.mjs +0 -359
  239. package/dist/plugins/workos-auth/package.json +0 -22
  240. package/dist/plugins/workos-auth/src/index.ts +0 -30
  241. package/dist/plugins/workos-auth/src/manifest.ts +0 -40
  242. package/dist/plugins/workos-auth/src/provider-contract.ts +0 -39
  243. package/dist/plugins/workos-auth/test/manifest.test.ts +0 -94
  244. package/dist/plugins/workos-auth/tsconfig.json +0 -8
  245. package/dist/terraform/modules/app/agentcore-code-interpreter/Dockerfile.sandbox-base +0 -61
  246. package/dist/terraform/modules/app/agentcore-code-interpreter/sandbox/sitecustomize.py +0 -227
  247. package/dist/terraform/modules/app/agentcore-code-interpreter/sandbox/test_sitecustomize.py +0 -277
  248. package/dist/terraform/modules/app/agentcore-code-interpreter/scripts/build_and_push_sandbox_base.sh +0 -70
  249. package/dist/terraform/modules/app/agentcore-harness/main.tf +0 -101
  250. package/dist/terraform/modules/app/agentcore-harness/outputs.tf +0 -9
  251. package/dist/terraform/modules/app/agentcore-harness/variables.tf +0 -25
  252. package/dist/terraform/modules/app/hindsight-memory/README.md +0 -89
  253. package/dist/terraform/modules/app/hindsight-memory/main.tf +0 -411
  254. package/dist/terraform/modules/data/bedrock-knowledge-base/main.tf +0 -102
  255. /package/dist/{plugins/n8n/terraform → terraform/modules/app}/n8n/outputs.tf +0 -0
  256. /package/dist/{plugins/n8n/terraform → terraform/modules/app}/n8n/scripts/sync-database.py +0 -0
  257. /package/dist/{plugins/n8n/terraform → terraform/modules/app}/n8n/scripts/test_sync_database.py +0 -0
  258. /package/dist/{plugins/n8n/terraform → terraform/modules/app}/n8n/variables.tf +0 -0
  259. /package/dist/{plugins/twenty/terraform → terraform/modules/app}/twenty/README.md +0 -0
  260. /package/dist/{plugins/twenty/terraform → terraform/modules/app}/twenty/main.tf +0 -0
  261. /package/dist/{plugins/twenty/terraform → terraform/modules/app}/twenty/outputs.tf +0 -0
  262. /package/dist/{plugins/twenty/terraform → terraform/modules/app}/twenty/variables.tf +0 -0
@@ -53,11 +53,6 @@ locals {
53
53
  : module.vpc.private_subnet_ids
54
54
  )
55
55
 
56
- # Hindsight is the canonical user/Space memory provider for full ThinkWork
57
- # installs. AgentCore managed memory remains available as an explicit
58
- # low-cost/development opt-out. We still honor var.memory_engine == "hindsight"
59
- # so existing tfvars keep working even when enable_hindsight was not set.
60
- hindsight_enabled = var.enable_hindsight || var.memory_engine == "hindsight"
61
56
  twenty_provisioned = var.twenty_provisioned
62
57
  twenty_runtime_enabled = var.twenty_provisioned && var.twenty_runtime_enabled
63
58
  twenty_domain = var.twenty_domain != "" ? var.twenty_domain : (var.www_domain != "" ? "crm.${var.www_domain}" : "")
@@ -83,8 +78,28 @@ locals {
83
78
  module.vpc.private_route_table_ids,
84
79
  module.vpc.public_route_table_ids,
85
80
  )
86
- okf_wiki_private_endpoints_enabled = var.okf_wiki_efs_enabled && var.okf_wiki_create_vpc_endpoints
87
- okf_wiki_interface_endpoint_services = toset(concat(
81
+ # THINK-589 PR 1 (deprecate-to-no-op): the OKF wiki EFS feature is dead.
82
+ # Every EFS consumer below (client/EFS security groups, NFS rule, mount
83
+ # targets, access points, Pi/hydrator wiring) is hard-conditioned off via
84
+ # this local regardless of the deprecated okf_wiki_* inputs. The EFS
85
+ # filesystem itself and the NAT gateway are intentionally NOT conditioned
86
+ # off: destroying the filesystem is PR 2's gated delete, and the NAT is
87
+ # shared VPC egress that live non-OKF workloads ride.
88
+ #
89
+ # The VPC interface endpoints were re-homed out of the OKF lane on
90
+ # 2026-08-28 (the vpc_interface_* resources below — they were only ever
91
+ # "okf-wiki" by accident of being created by the first VPC-attached
92
+ # workload). They still ride the okf_wiki_* enable gates for stage
93
+ # compatibility; the SERVICE SET and ENI count are now per-stage inputs.
94
+ okf_wiki_efs_consumers_active = false
95
+ vpc_interface_endpoints_enabled = var.okf_wiki_efs_enabled && var.okf_wiki_create_vpc_endpoints
96
+ # Legacy full set — what every stage had before the cost review. An
97
+ # interface endpoint with private DNS does not grant reachability (the
98
+ # private subnets are NAT-routed and the Lambda SGs allow 443 out); it only
99
+ # keeps the call on AWS's network, at ~$7.30/mo per ENI regardless of
100
+ # traffic. Stages that care about posture keep the data-touching ones
101
+ # (secretsmanager, rds-data, bedrock-runtime) and let the rest ride the NAT.
102
+ vpc_interface_endpoint_services_legacy = toset(concat(
88
103
  [
89
104
  "bedrock",
90
105
  "bedrock-agentcore",
@@ -106,18 +121,17 @@ locals {
106
121
  "bedrock-runtime",
107
122
  ],
108
123
  ))
109
-
110
- # Canonical long-term memory engine for this deployment. Exactly one engine
111
- # is active per deployment for recall/inspect/export. Empty selects
112
- # Hindsight for full installs; callers can explicitly choose AgentCore for
113
- # low-cost/development deployments. Legacy value "managed" maps to
114
- # "agentcore".
115
- resolved_memory_engine = (
116
- var.memory_engine == "hindsight" || var.memory_engine == "agentcore"
117
- ? var.memory_engine
118
- : var.memory_engine == "managed"
119
- ? "agentcore"
120
- : local.hindsight_enabled ? "hindsight" : "agentcore"
124
+ vpc_interface_endpoint_services = (
125
+ var.vpc_interface_endpoint_services != null
126
+ ? toset(var.vpc_interface_endpoint_services)
127
+ : local.vpc_interface_endpoint_services_legacy
128
+ )
129
+ # Single-AZ: one ENI in the lowest sorted subnet. Callers in the other AZ
130
+ # cross AZs at $0.01/GB — nothing at these volumes next to a second ENI.
131
+ vpc_interface_endpoint_subnet_ids = (
132
+ var.vpc_interface_endpoint_single_az
133
+ ? slice(sort(local.okf_wiki_subnet_ids), 0, min(1, length(local.okf_wiki_subnet_ids)))
134
+ : local.okf_wiki_subnet_ids
121
135
  )
122
136
 
123
137
  # Customer-domain namespace (<name>.thinkwork.ai). The zone is created as
@@ -487,14 +501,16 @@ resource "terraform_data" "n8n_runtime_state_guardrails" {
487
501
  }
488
502
  }
489
503
  }
490
- # Egress-only SG for the VPC-attached analyst data-path Lambdas
491
- # (analyst_lambda_vpc_egress). Their whole point is a stable NAT egress IP for
492
- # external database allowlists; they accept no inbound traffic.
493
- resource "aws_security_group" "analyst_egress_lambda" {
494
- count = var.analyst_lambda_vpc_egress ? 1 : 0
495
-
496
- name_prefix = "thinkwork-${var.stage}-analyst-egress-"
497
- description = "Egress for VPC-attached analyst data-path Lambdas"
504
+ # Company Brain U5: general egress for the VPC-attached identity-graph-
505
+ # projector (twin-query retired to the platform service THINK-339 U15).
506
+ # Pairs with the etl neptune stack's
507
+ # client SG (8182-only) — this one covers Aurora (5432), Secrets/S3/Lambda
508
+ # APIs (443) through the NAT-routed private subnets.
509
+ resource "aws_security_group" "twin_lambda_egress" {
510
+ #checkov:skip=CKV2_AWS_5: attached to the twin Lambdas via lambda-api's neptune vpc_config
511
+ count = var.neptune_client_security_group_id != "" ? 1 : 0
512
+ name = "thinkwork-${var.stage}-twin-lambda-egress"
513
+ description = "Twin Lambdas - general egress (Aurora, AWS APIs)"
498
514
  vpc_id = module.vpc.vpc_id
499
515
 
500
516
  egress {
@@ -503,20 +519,10 @@ resource "aws_security_group" "analyst_egress_lambda" {
503
519
  protocol = "-1"
504
520
  cidr_blocks = ["0.0.0.0/0"]
505
521
  }
506
-
507
- tags = { Name = "thinkwork-${var.stage}-analyst-egress-lambda-sg" }
508
-
509
- lifecycle {
510
- create_before_destroy = true
511
- precondition {
512
- condition = length(module.vpc.private_subnet_ids) > 0
513
- error_message = "analyst_lambda_vpc_egress requires private (NAT-routed) subnets — a Lambda in a public subnet has no internet egress."
514
- }
515
- }
516
522
  }
517
523
 
518
524
  resource "aws_security_group" "okf_wiki_lambda" {
519
- count = var.okf_wiki_efs_enabled ? 1 : 0
525
+ count = local.okf_wiki_efs_consumers_active ? 1 : 0 # THINK-589: always off
520
526
 
521
527
  name_prefix = "thinkwork-${var.stage}-okf-wiki-lambda-"
522
528
  description = "OKF wiki EFS clients for hydrator and Pi"
@@ -534,7 +540,7 @@ resource "aws_security_group" "okf_wiki_lambda" {
534
540
  }
535
541
 
536
542
  resource "aws_security_group" "okf_wiki_efs" {
537
- count = var.okf_wiki_efs_enabled ? 1 : 0
543
+ count = local.okf_wiki_efs_consumers_active ? 1 : 0 # THINK-589: always off
538
544
 
539
545
  name_prefix = "thinkwork-${var.stage}-okf-wiki-efs-"
540
546
  description = "NFS ingress for OKF wiki current-view EFS"
@@ -544,74 +550,83 @@ resource "aws_security_group" "okf_wiki_efs" {
544
550
  lifecycle { create_before_destroy = true }
545
551
  }
546
552
 
547
- resource "aws_security_group" "okf_wiki_vpc_endpoint" {
548
- count = var.okf_wiki_efs_enabled && var.okf_wiki_create_vpc_endpoints ? 1 : 0
553
+ # Re-homed from okf_wiki_vpc_endpoint (2026-08-28). name_prefix AND
554
+ # description keep their historical values on purpose: either change replaces
555
+ # the SG, which every live endpoint references — the Name tag carries the new
556
+ # identity instead.
557
+ resource "aws_security_group" "vpc_interface_endpoint" {
558
+ count = local.vpc_interface_endpoints_enabled ? 1 : 0
549
559
 
550
560
  name_prefix = "thinkwork-${var.stage}-okf-wiki-vpce-"
551
561
  description = "HTTPS endpoints for OKF wiki VPC-attached Lambdas"
552
562
  vpc_id = module.vpc.vpc_id
553
563
 
554
- tags = { Name = "thinkwork-${var.stage}-okf-wiki-vpce-sg" }
564
+ tags = { Name = "thinkwork-${var.stage}-vpce-sg" }
555
565
  lifecycle { create_before_destroy = true }
556
566
  }
557
567
 
558
568
  resource "aws_security_group_rule" "okf_wiki_vpce_from_lambda" {
559
- count = local.okf_wiki_private_endpoints_enabled ? 1 : 0
569
+ # THINK-589: always off the OKF client SG no longer exists; VPC workloads
570
+ # reach the endpoints via vpc_interface_endpoint_from_vpc (VPC CIDR).
571
+ count = local.okf_wiki_efs_consumers_active ? 1 : 0
560
572
 
561
573
  type = "ingress"
562
574
  from_port = 443
563
575
  to_port = 443
564
576
  protocol = "tcp"
565
577
  source_security_group_id = aws_security_group.okf_wiki_lambda[0].id
566
- security_group_id = aws_security_group.okf_wiki_vpc_endpoint[0].id
578
+ security_group_id = aws_security_group.vpc_interface_endpoint[0].id
567
579
  }
568
580
  # Interface endpoints with private DNS capture the WHOLE VPC's traffic to the
569
581
  # covered AWS APIs (logs, ssm, sts, bedrock, ...): every workload in the VPC
570
582
  # resolves those hostnames to the endpoint's private IP, so per-source-SG
571
- # rules silently black-hole anything not enumerated — harness cycle-7's
572
- # Hindsight tasks died on "cannot find the CloudWatch log group ... connection
573
- # issue" because only the Lambda SG was admitted. Allow the VPC CIDR.
574
- resource "aws_security_group_rule" "okf_wiki_vpce_from_vpc" {
575
- count = local.okf_wiki_private_endpoints_enabled ? 1 : 0
583
+ # rules silently black-hole anything not enumerated — harness cycle-7's ECS
584
+ # tasks died on "cannot find the CloudWatch log group ... connection issue"
585
+ # because only the Lambda SG was admitted. Allow the VPC CIDR.
586
+ resource "aws_security_group_rule" "vpc_interface_endpoint_from_vpc" {
587
+ count = local.vpc_interface_endpoints_enabled ? 1 : 0
576
588
 
577
589
  type = "ingress"
578
590
  from_port = 443
579
591
  to_port = 443
580
592
  protocol = "tcp"
581
593
  cidr_blocks = [module.vpc.vpc_cidr_block]
582
- security_group_id = aws_security_group.okf_wiki_vpc_endpoint[0].id
594
+ security_group_id = aws_security_group.vpc_interface_endpoint[0].id
583
595
  description = "All VPC workloads (private-DNS endpoints capture the whole VPC)"
584
596
  }
585
597
 
586
- resource "aws_security_group_rule" "okf_wiki_vpce_from_twenty" {
587
- count = local.okf_wiki_private_endpoints_enabled && local.twenty_provisioned ? 1 : 0
598
+ resource "aws_security_group_rule" "vpc_interface_endpoint_from_twenty" {
599
+ count = local.vpc_interface_endpoints_enabled && local.twenty_provisioned ? 1 : 0
588
600
 
589
601
  type = "ingress"
590
602
  from_port = 443
591
603
  to_port = 443
592
604
  protocol = "tcp"
593
605
  source_security_group_id = module.twenty[0].twenty_security_group_id
594
- security_group_id = aws_security_group.okf_wiki_vpc_endpoint[0].id
606
+ security_group_id = aws_security_group.vpc_interface_endpoint[0].id
595
607
  }
596
608
 
597
- resource "aws_vpc_endpoint" "okf_wiki_interface" {
598
- for_each = local.okf_wiki_private_endpoints_enabled ? local.okf_wiki_interface_endpoint_services : toset([])
609
+ resource "aws_vpc_endpoint" "vpc_interface" {
610
+ for_each = local.vpc_interface_endpoints_enabled ? local.vpc_interface_endpoint_services : toset([])
599
611
 
600
612
  vpc_id = module.vpc.vpc_id
601
613
  service_name = "com.amazonaws.${var.region}.${each.key}"
602
614
  vpc_endpoint_type = "Interface"
603
- subnet_ids = local.okf_wiki_subnet_ids
604
- security_group_ids = [aws_security_group.okf_wiki_vpc_endpoint[0].id]
615
+ subnet_ids = local.vpc_interface_endpoint_subnet_ids
616
+ security_group_ids = [aws_security_group.vpc_interface_endpoint[0].id]
605
617
  private_dns_enabled = true
606
618
 
607
619
  tags = {
608
- Name = "thinkwork-${var.stage}-okf-wiki-${each.key}-vpce"
609
- Purpose = "okf-wiki-private-egress"
620
+ Name = "thinkwork-${var.stage}-vpce-${each.key}"
621
+ Purpose = "vpc-private-egress"
610
622
  }
611
623
  }
612
624
 
613
- resource "aws_vpc_endpoint" "okf_wiki_s3" {
614
- count = local.okf_wiki_private_endpoints_enabled && length(local.okf_wiki_route_table_ids) > 0 ? 1 : 0
625
+ # Gateway endpoint: free, no ENIs — never part of the diet. The Brain stack
626
+ # mirrors these tags on the shared mcpherson endpoint (its accounts tfvars);
627
+ # change them in lockstep.
628
+ resource "aws_vpc_endpoint" "vpc_s3" {
629
+ count = local.vpc_interface_endpoints_enabled && length(local.okf_wiki_route_table_ids) > 0 ? 1 : 0
615
630
 
616
631
  vpc_id = module.vpc.vpc_id
617
632
  service_name = "com.amazonaws.${var.region}.s3"
@@ -619,12 +634,37 @@ resource "aws_vpc_endpoint" "okf_wiki_s3" {
619
634
  route_table_ids = local.okf_wiki_route_table_ids
620
635
 
621
636
  tags = {
622
- Name = "thinkwork-${var.stage}-okf-wiki-s3-vpce"
623
- Purpose = "okf-wiki-private-egress"
637
+ Name = "thinkwork-${var.stage}-vpce-s3"
638
+ Purpose = "vpc-private-egress"
624
639
  }
625
640
  }
641
+
642
+ # 2026-08-28 re-home: the endpoint group was created by (and named after)
643
+ # the dead OKF wiki lane. Same AWS resources, new addresses — a VPC endpoint
644
+ # Terraform destroys and recreates is a live outage for everything routing
645
+ # through it.
646
+ moved {
647
+ from = aws_security_group.okf_wiki_vpc_endpoint
648
+ to = aws_security_group.vpc_interface_endpoint
649
+ }
650
+ moved {
651
+ from = aws_security_group_rule.okf_wiki_vpce_from_vpc
652
+ to = aws_security_group_rule.vpc_interface_endpoint_from_vpc
653
+ }
654
+ moved {
655
+ from = aws_security_group_rule.okf_wiki_vpce_from_twenty
656
+ to = aws_security_group_rule.vpc_interface_endpoint_from_twenty
657
+ }
658
+ moved {
659
+ from = aws_vpc_endpoint.okf_wiki_interface
660
+ to = aws_vpc_endpoint.vpc_interface
661
+ }
662
+ moved {
663
+ from = aws_vpc_endpoint.okf_wiki_s3
664
+ to = aws_vpc_endpoint.vpc_s3
665
+ }
626
666
  resource "aws_security_group_rule" "okf_wiki_efs_from_lambda" {
627
- count = var.okf_wiki_efs_enabled ? 1 : 0
667
+ count = local.okf_wiki_efs_consumers_active ? 1 : 0 # THINK-589: always off
628
668
 
629
669
  type = "ingress"
630
670
  from_port = 2049
@@ -634,6 +674,10 @@ resource "aws_security_group_rule" "okf_wiki_efs_from_lambda" {
634
674
  security_group_id = aws_security_group.okf_wiki_efs[0].id
635
675
  }
636
676
 
677
+ # THINK-589 PR 1: deliberately NOT conditioned off — flipping this count to 0
678
+ # would DESTROY the filesystem (and its data) on the next apply. All consumers
679
+ # (mount targets, access points, Lambda mounts, IAM) are detached below; the
680
+ # filesystem delete happens in PR 2 behind the destructive-step gates.
637
681
  resource "aws_efs_file_system" "okf_wiki" {
638
682
  count = var.okf_wiki_efs_enabled ? 1 : 0
639
683
 
@@ -651,7 +695,7 @@ resource "aws_efs_file_system" "okf_wiki" {
651
695
  }
652
696
 
653
697
  resource "aws_efs_mount_target" "okf_wiki" {
654
- count = var.okf_wiki_efs_enabled ? length(local.okf_wiki_subnet_ids) : 0
698
+ count = local.okf_wiki_efs_consumers_active ? length(local.okf_wiki_subnet_ids) : 0 # THINK-589: always off
655
699
 
656
700
  file_system_id = aws_efs_file_system.okf_wiki[0].id
657
701
  subnet_id = local.okf_wiki_subnet_ids[count.index]
@@ -659,7 +703,7 @@ resource "aws_efs_mount_target" "okf_wiki" {
659
703
  }
660
704
 
661
705
  resource "aws_efs_access_point" "okf_wiki_refresh" {
662
- count = var.okf_wiki_efs_enabled ? 1 : 0
706
+ count = local.okf_wiki_efs_consumers_active ? 1 : 0 # THINK-589: always off
663
707
 
664
708
  file_system_id = aws_efs_file_system.okf_wiki[0].id
665
709
 
@@ -684,7 +728,7 @@ resource "aws_efs_access_point" "okf_wiki_refresh" {
684
728
  }
685
729
 
686
730
  resource "aws_efs_access_point" "okf_wiki_pi_read" {
687
- count = var.okf_wiki_efs_enabled ? 1 : 0
731
+ count = local.okf_wiki_efs_consumers_active ? 1 : 0 # THINK-589: always off
688
732
 
689
733
  file_system_id = aws_efs_file_system.okf_wiki[0].id
690
734
 
@@ -722,7 +766,16 @@ module "vpc" {
722
766
  existing_private_subnet_ids = var.existing_private_subnet_ids
723
767
  existing_public_route_table_ids = var.existing_public_route_table_ids
724
768
  existing_private_route_table_ids = var.existing_private_route_table_ids
725
- enable_nat_gateway = var.okf_wiki_efs_enabled && var.okf_wiki_create_nat_gateway
769
+ # THINK-589 PR 1: NAT egress historically rode the OKF EFS flags but is
770
+ # shared VPC plumbing — Neptune twin Lambdas (and any other VPC-attached
771
+ # workload) depend on the NAT-routed private subnets. Left gated as before
772
+ # so PR 1 changes no networking; PR 2 re-homes this onto the surviving VPC
773
+ # consumers (the lambda_vpc_access precedent in lambda-api/main.tf).
774
+ # THINK-1082: a VPC-attached deployment runner has no public IP and needs
775
+ # NAT egress (GitHub release manifest, apt/pip, STS/S3/Secrets Manager).
776
+ # THINK-1082: VPC-attached api Lambdas / Pi have no public IP either (AWS
777
+ # APIs, Bedrock, Slack, GitHub, model providers).
778
+ enable_nat_gateway = (var.okf_wiki_efs_enabled && var.okf_wiki_create_nat_gateway) || var.deployment_runner_in_vpc || var.api_lambdas_in_vpc
726
779
  }
727
780
 
728
781
  module "kms" {
@@ -736,30 +789,35 @@ module "cognito" {
736
789
  stage = var.stage
737
790
  region = var.region
738
791
 
739
- create_cognito = var.create_cognito
740
- existing_user_pool_id = var.existing_user_pool_id
741
- existing_user_pool_arn = var.existing_user_pool_arn
742
- existing_admin_client_id = var.existing_admin_client_id
743
- existing_mobile_client_id = var.existing_mobile_client_id
744
- existing_identity_pool_id = var.existing_identity_pool_id
745
-
746
- google_oauth_client_id = var.google_oauth_client_id
747
- google_oauth_client_secret = var.google_oauth_client_secret
748
- oidc_identity_providers = var.oidc_identity_providers
749
- saml_identity_providers = var.saml_identity_providers
750
- pre_signup_lambda_zip = var.pre_signup_lambda_zip
751
- custom_auth_lambda_zip = var.cognito_custom_auth_lambda_zip
752
- # Remote custom auth is part of the pinned enterprise release bundle. Keep
753
- # the shared artifact bucket inert for direct module consumers that have not
754
- # opted into required release artifacts; local zip configuration remains an
755
- # independent explicit opt-in below.
756
- custom_auth_lambda_s3_bucket = var.require_lambda_artifacts ? var.lambda_artifact_bucket : ""
757
- custom_auth_lambda_s3_key = var.require_lambda_artifacts && var.lambda_artifact_bucket != "" ? "${trim(trimspace(var.lambda_artifact_prefix), "/")}/cognito-custom-auth.zip" : ""
758
- api_auth_secret = var.api_auth_secret
759
- email_source_arn = var.cognito_email_source_arn
760
- from_email_address = var.cognito_from_email_address
761
- reply_to_email_address = var.cognito_reply_to_email_address
762
- invite_email_subject = var.cognito_invite_email_subject
792
+ create_cognito = var.create_cognito
793
+ existing_user_pool_id = var.existing_user_pool_id
794
+ existing_user_pool_arn = var.existing_user_pool_arn
795
+ existing_admin_client_id = var.existing_admin_client_id
796
+ existing_mobile_client_id = var.existing_mobile_client_id
797
+ existing_identity_pool_id = var.existing_identity_pool_id
798
+ existing_auth_route_clients = var.existing_auth_route_clients
799
+
800
+ google_oauth_client_id = var.google_oauth_client_id
801
+ google_oauth_client_secret = var.google_oauth_client_secret
802
+ microsoft_oauth_client_id = var.microsoft_oauth_client_id
803
+ microsoft_oauth_client_secret = var.microsoft_oauth_client_secret
804
+ microsoft_oauth_tenant = var.microsoft_oauth_tenant
805
+ tenant_entra_connections = var.tenant_entra_connections
806
+ oidc_identity_providers = var.oidc_identity_providers
807
+ saml_identity_providers = var.saml_identity_providers
808
+ pre_signup_lambda_zip = var.pre_signup_lambda_zip
809
+ auth_retirement_phase = var.auth_retirement_phase
810
+ custom_auth_lambda_zip = var.cognito_custom_auth_lambda_zip
811
+ custom_auth_lambda_s3_bucket = var.require_lambda_artifacts ? var.lambda_artifact_bucket : ""
812
+ custom_auth_lambda_s3_key = var.require_lambda_artifacts && var.lambda_artifact_bucket != "" ? "${trim(trimspace(var.lambda_artifact_prefix), "/")}/cognito-custom-auth.zip" : ""
813
+ api_auth_secret = var.api_auth_secret
814
+ pre_token_generation_lambda_s3_bucket = var.require_lambda_artifacts ? var.lambda_artifact_bucket : ""
815
+ pre_token_generation_lambda_s3_key = var.require_lambda_artifacts && var.lambda_artifact_bucket != "" ? "${trim(trimspace(var.lambda_artifact_prefix), "/")}/cognito-pre-token-client-deny.zip" : ""
816
+ denied_app_client_ids = var.cognito_denied_app_client_ids
817
+ email_source_arn = var.cognito_email_source_arn
818
+ from_email_address = var.cognito_from_email_address
819
+ reply_to_email_address = var.cognito_reply_to_email_address
820
+ invite_email_subject = var.cognito_invite_email_subject
763
821
  invite_email_message = (
764
822
  var.cognito_invite_email_message != ""
765
823
  ? var.cognito_invite_email_message
@@ -782,16 +840,38 @@ module "cognito" {
782
840
  # entry — login works on both domains. Flipping
783
841
  # customer_domain_legacy_retired REMOVES the legacy (non-customer-domain)
784
842
  # app entries — the CloudFront default domain, the legacy app/computer
785
- # domains — as a reviewable Terraform change. Explicit caller-supplied,
786
- # localhost dev, and desktop entries are never retired here.
843
+ # domains — as a reviewable Terraform change. Explicit caller-supplied and
844
+ # localhost dev entries are never retired here.
787
845
  admin_callback_urls = distinct(concat(
788
846
  var.admin_callback_urls,
789
847
  local.customer_domain_legacy_retired ? [] : ["https://${module.computer_site.distribution_domain}", "https://${module.computer_site.distribution_domain}/auth/callback"],
790
848
  local.customer_domain_legacy_retired ? [] : (local.legacy_end_user_app_domain != "" ? ["https://${local.legacy_end_user_app_domain}", "https://${local.legacy_end_user_app_domain}/auth/callback"] : []),
791
849
  local.customer_domain_web_enabled ? ["https://${var.customer_domain}", "https://${var.customer_domain}/auth/callback"] : [],
792
850
  local.customer_domain_legacy_retired ? [] : (var.computer_domain != "" ? ["https://${var.computer_domain}", "https://${var.computer_domain}/auth/callback"] : []),
793
- ["http://localhost:5180", "http://localhost:5180/auth/callback"],
794
- var.desktop_callback_urls
851
+ [
852
+ "http://localhost:5180",
853
+ "http://localhost:5180/auth/callback",
854
+ "http://127.0.0.1:5180",
855
+ "http://127.0.0.1:5180/auth/callback",
856
+ ],
857
+ # Hosted Company Brain console origins (dev only): the console's CloudFront
858
+ # distribution and the future custom domain must be able to complete OAuth
859
+ # against the dev web-family clients. Dev-scoped so customer stacks don't
860
+ # carry dev console origins in their pools.
861
+ var.stage == "dev" ? [
862
+ "https://d3q9a98mhsakjf.cloudfront.net",
863
+ "https://d3q9a98mhsakjf.cloudfront.net/auth/callback",
864
+ "https://brain.thinkwork.ai",
865
+ "https://brain.thinkwork.ai/auth/callback",
866
+ ] : [],
867
+ # Operator-supplied web-family callback origins. Customer stacks host the
868
+ # Company Brain console in their OWN account (separate repo/CloudFront), so
869
+ # the product stack can't derive those URLs — they arrive here from the
870
+ # deployment runner (runner-secrets `adminCallbackUrls`). Empty by default;
871
+ # both bare and /auth/callback entries should be supplied by the caller.
872
+ # This is what keeps the console origins from being stripped on every
873
+ # controller apply (dev has the hardcoded block above; customers use this).
874
+ var.additional_admin_callback_urls,
795
875
  ))
796
876
  admin_logout_urls = distinct(concat(
797
877
  var.admin_logout_urls,
@@ -799,12 +879,28 @@ module "cognito" {
799
879
  local.customer_domain_legacy_retired ? [] : (local.legacy_end_user_app_domain != "" ? ["https://${local.legacy_end_user_app_domain}"] : []),
800
880
  local.customer_domain_web_enabled ? ["https://${var.customer_domain}"] : [],
801
881
  local.customer_domain_legacy_retired ? [] : (var.computer_domain != "" ? ["https://${var.computer_domain}"] : []),
802
- ["http://localhost:5180"],
803
- var.desktop_callback_urls
882
+ ["http://localhost:5180", "http://127.0.0.1:5180"],
883
+ # Hosted Company Brain console origins (dev only) — see admin_callback_urls.
884
+ var.stage == "dev" ? [
885
+ "https://d3q9a98mhsakjf.cloudfront.net",
886
+ "https://d3q9a98mhsakjf.cloudfront.net/auth/callback",
887
+ "https://brain.thinkwork.ai",
888
+ "https://brain.thinkwork.ai/auth/callback",
889
+ ] : [],
890
+ # Operator-supplied web-family logout origins — see admin_callback_urls.
891
+ var.additional_admin_logout_urls,
804
892
  ))
805
- desktop_callback_urls = var.desktop_callback_urls
806
- mobile_callback_urls = var.mobile_callback_urls
807
- mobile_logout_urls = var.mobile_logout_urls
893
+ cli_callback_urls = var.cli_callback_urls
894
+ cli_logout_urls = var.cli_logout_urls
895
+ mobile_callback_urls = var.mobile_callback_urls
896
+ mobile_logout_urls = var.mobile_logout_urls
897
+
898
+ # Company Brain console client (U13 — ship-inert, default off). The console's
899
+ # CloudFront URL must be in console_callback_urls BEFORE first login
900
+ # (redirect_mismatch otherwise).
901
+ console_client_enabled = var.console_client_enabled
902
+ console_callback_urls = var.console_callback_urls
903
+ console_logout_urls = var.console_logout_urls
808
904
  }
809
905
 
810
906
  module "dns" {
@@ -894,6 +990,12 @@ module "database" {
894
990
  subnet_ids = module.vpc.public_subnet_ids
895
991
  db_password = var.db_password
896
992
 
993
+ # THINK-1082: network exposure. Defaults = today's public endpoint + world-
994
+ # open 5432. Closed per stage only after the Lambdas and the runner are in
995
+ # the VPC (api_lambdas_in_vpc / deployment_runner_in_vpc).
996
+ publicly_accessible = var.db_publicly_accessible
997
+ public_ingress_cidrs = var.db_public_ingress_cidrs
998
+
897
999
  database_name = var.database_name
898
1000
  database_engine = var.database_engine
899
1001
 
@@ -907,13 +1009,54 @@ module "database" {
907
1009
  enable_aws_s3 = var.database_engine == "aurora-serverless"
908
1010
  }
909
1011
 
910
- module "bedrock_kb" {
911
- source = "../data/bedrock-knowledge-base"
1012
+ ################################################################################
1013
+ # API Lambdas inside the VPC (THINK-1082)
1014
+ #
1015
+ # Off by default (ship-inert). When on, every database-connected Lambda of the
1016
+ # agent (lambda-api handlers, agentcore-admin, agentcore-pi, the capability
1017
+ # broker) attaches to the private subnets with this security group, and the
1018
+ # database security group grants it tcp/5432 — the same standalone-rule
1019
+ # pattern the ECS modules and the deployment runner use, so the grant survives
1020
+ # the aurora-postgres module's `ignore_changes = [ingress]`. With this live the
1021
+ # world-open 0.0.0.0/0 -> 5432 rule can be revoked without taking the app down.
1022
+ ################################################################################
912
1023
 
913
- stage = var.stage
914
- account_id = var.account_id
915
- region = var.region
916
- bucket_name = module.s3.bucket_name
1024
+ resource "aws_security_group" "api_lambda" {
1025
+ count = var.api_lambdas_in_vpc ? 1 : 0
1026
+
1027
+ name = "thinkwork-${var.stage}-api-lambda-sg"
1028
+ description = "ThinkWork API Lambdas (VPC) for ${var.stage}."
1029
+ vpc_id = module.vpc.vpc_id
1030
+
1031
+ egress {
1032
+ from_port = 0
1033
+ to_port = 0
1034
+ protocol = "-1"
1035
+ cidr_blocks = ["0.0.0.0/0"]
1036
+ }
1037
+
1038
+ tags = {
1039
+ Name = "thinkwork-${var.stage}-api-lambda-sg"
1040
+ Stage = var.stage
1041
+ Purpose = "api-lambda"
1042
+ }
1043
+ }
1044
+
1045
+ resource "aws_security_group_rule" "db_from_api_lambda" {
1046
+ count = var.api_lambdas_in_vpc ? 1 : 0
1047
+
1048
+ type = "ingress"
1049
+ description = "ThinkWork API Lambdas (VPC)"
1050
+ from_port = 5432
1051
+ to_port = 5432
1052
+ protocol = "tcp"
1053
+ security_group_id = module.database.db_security_group_id
1054
+ source_security_group_id = aws_security_group.api_lambda[0].id
1055
+ }
1056
+
1057
+ locals {
1058
+ api_lambda_vpc_subnet_ids = var.api_lambdas_in_vpc ? module.vpc.private_subnet_ids : []
1059
+ api_lambda_vpc_security_group_ids = var.api_lambdas_in_vpc ? [aws_security_group.api_lambda[0].id] : []
917
1060
  }
918
1061
 
919
1062
  ################################################################################
@@ -930,6 +1073,7 @@ module "appsync" {
930
1073
 
931
1074
  stage = var.stage
932
1075
  region = var.region
1076
+ account_id = var.account_id
933
1077
  user_pool_id = module.cognito.user_pool_id
934
1078
  subscription_schema = local.subscription_schema
935
1079
  }
@@ -964,6 +1108,13 @@ module "deployment_control_plane" {
964
1108
 
965
1109
  log_retention_days = var.deployment_control_plane_log_retention_days
966
1110
  create_secret_placeholders = var.deployment_control_plane_create_secret_placeholders
1111
+
1112
+ # THINK-1082: runner inside the VPC — DB access by security group, not a
1113
+ # world-open port. The NAT this needs is switched on module.vpc above.
1114
+ runner_in_vpc = var.deployment_runner_in_vpc
1115
+ vpc_id = module.vpc.vpc_id
1116
+ subnet_ids = module.vpc.private_subnet_ids
1117
+ db_security_group_id = module.database.db_security_group_id
967
1118
  }
968
1119
 
969
1120
  # ── Capability signing keypair (THINK-173 KTD-3) ──────────────────────────
@@ -988,15 +1139,40 @@ resource "aws_secretsmanager_secret_version" "capability_signing_key" {
988
1139
  secret_string = tls_private_key.capability_signing.private_key_pem
989
1140
  }
990
1141
 
1142
+ # AppSync subscription tickets use a separate key and domain from capability
1143
+ # envelopes. The authorizer receives only the public key; ticket issuance
1144
+ # resolves the private key by secret name at runtime.
1145
+ resource "tls_private_key" "subscription_ticket_signing" {
1146
+ algorithm = "ED25519"
1147
+ }
1148
+
1149
+ resource "aws_secretsmanager_secret" "subscription_ticket_signing_key" {
1150
+ name = "thinkwork/${var.stage}/subscription-ticket-signing-key"
1151
+ description = "Ed25519 private key signing one-use AppSync subscription tickets."
1152
+ }
1153
+
1154
+ resource "aws_secretsmanager_secret_version" "subscription_ticket_signing_key" {
1155
+ secret_id = aws_secretsmanager_secret.subscription_ticket_signing_key.id
1156
+ secret_string = tls_private_key.subscription_ticket_signing.private_key_pem
1157
+ }
1158
+
991
1159
  module "api" {
992
1160
  source = "../app/lambda-api"
993
1161
 
994
1162
  capability_signing_public_key = tls_private_key.capability_signing.public_key_pem
995
1163
  capability_signing_private_key_secret = aws_secretsmanager_secret.capability_signing_key.name
1164
+ subscription_ticket_signing_key_id = "${var.stage}-subscription-v1"
1165
+ subscription_ticket_public_keys = jsonencode([{
1166
+ keyId = "${var.stage}-subscription-v1"
1167
+ publicKey = tls_private_key.subscription_ticket_signing.public_key_pem
1168
+ }])
1169
+ subscription_ticket_private_key_secret = aws_secretsmanager_secret.subscription_ticket_signing_key.name
996
1170
 
997
- stage = var.stage
998
- account_id = var.account_id
999
- region = var.region
1171
+ stage = var.stage
1172
+ account_id = var.account_id
1173
+ region = var.region
1174
+ auth_retirement_phase = var.auth_retirement_phase
1175
+ auth_migration_recovery_deadline = var.auth_migration_recovery_deadline
1000
1176
 
1001
1177
  lambda_artifact_bucket = var.lambda_artifact_bucket
1002
1178
  lambda_artifact_prefix = var.lambda_artifact_prefix
@@ -1038,26 +1214,20 @@ module "api" {
1038
1214
  compliance_reader_secret_arn = module.database.compliance_reader_secret_arn
1039
1215
  compliance_anchor_object_lock_retention_days = var.compliance_anchor_retention_days
1040
1216
 
1041
- # THINK-228 — analyst query broker: hardened reader role credentials +
1042
- # the broker caller credential the seeded connector row references.
1043
1217
  # THINK-246 — artifact email delivery sender: customer stages send from
1044
1218
  # their own verified domain (noreply@<customer_domain>); dev keeps the
1045
1219
  # code fallback via the empty default.
1046
1220
  artifact_delivery_from_email = var.customer_domain != "" ? "noreply@${var.customer_domain}" : ""
1047
1221
 
1048
- analyst_reader_secret_arn = module.database.analyst_reader_secret_arn
1049
- analyst_broker_secret_arn = module.database.analyst_broker_secret_arn
1050
- # THINK-229 U1 — keys the broker's rds-db:connect grant and switches the
1051
- # reader connection to per-connect RDS IAM auth tokens.
1052
- analyst_db_cluster_resource_id = module.database.cluster_resource_id
1053
- analyst_policy_source = var.analyst_policy_source
1054
-
1055
1222
  # Governed autonomy — per-tenant self-extension opt-in allowlist (default off).
1056
- capability_self_extension_tenants = var.capability_self_extension_tenants
1057
1223
 
1058
- # THINK-311 U4keys the Harness invoker grants in the grouped ai policy
1059
- # (empty string when the harness module is disabled = grants omitted).
1060
- agentcore_harness_execution_role_arn = module.agentcore_harness.execution_role_arn
1224
+ # THINK-316 U2request path receives only Harness invocation. Terraform
1225
+ # owns provisioning/version/endpoint control, avoiding a module cycle and
1226
+ # keeping PassRole/create/update/list out of chat Lambdas.
1227
+ # THINK-324: the managed-harness/proof plane is retired; its handlers,
1228
+ # KMS plane, and Gateway are gone. The proof flag survives only as a
1229
+ # declared variable so existing -var passthroughs stay valid.
1230
+ enable_agentcore_multiplayer_proof = false
1061
1231
 
1062
1232
  # Phase 3 U8b — KMS key + Object Lock mode forwarded as
1063
1233
  # COMPLIANCE_ANCHOR_KMS_KEY_ARN and COMPLIANCE_ANCHOR_OBJECT_LOCK_MODE
@@ -1079,19 +1249,23 @@ module "api" {
1079
1249
  bucket_arn = module.s3.bucket_arn
1080
1250
 
1081
1251
  plugin_catalog_github_token_secret_arn = var.plugin_catalog_github_token_secret_arn
1252
+ brain_m2m_platform_agent_secret_arn = var.brain_m2m_platform_agent_secret_arn
1253
+ brain_ops_api_url = var.brain_ops_api_url
1254
+ brain_ops_m2m_secret_arn = var.brain_ops_m2m_secret_arn
1082
1255
 
1083
1256
  brain_artifacts_kms_key_arn = module.kms.key_arn
1084
1257
 
1085
- user_pool_id = module.cognito.user_pool_id
1086
- user_pool_arn = module.cognito.user_pool_arn
1087
- admin_client_id = module.cognito.admin_client_id
1088
- mobile_client_id = module.cognito.mobile_client_id
1258
+ user_pool_id = module.cognito.user_pool_id
1259
+ user_pool_arn = module.cognito.user_pool_arn
1260
+ admin_client_id = module.cognito.admin_client_id
1261
+ mobile_client_id = module.cognito.mobile_client_id
1262
+ # R16: console client id joins the COGNITO_APP_CLIENT_IDS allowlist when
1263
+ # enabled ("" otherwise — the lambda-api module compacts it away).
1264
+ console_client_id = var.console_client_enabled ? module.cognito.console_client_id : ""
1089
1265
  cognito_auth_domain = module.cognito.auth_domain
1090
1266
 
1267
+ appsync_api_id = module.appsync.graphql_api_id
1091
1268
  appsync_api_url = module.appsync.graphql_api_url
1092
- appsync_api_key = module.appsync.graphql_api_key
1093
-
1094
- kb_service_role_arn = module.bedrock_kb.kb_service_role_arn
1095
1269
 
1096
1270
  lambda_zips_dir = var.lambda_zips_dir
1097
1271
  api_auth_secret = var.api_auth_secret
@@ -1100,33 +1274,51 @@ module "api" {
1100
1274
  agentcore_pi_function_name = module.agentcore_pi.agentcore_pi_function_name
1101
1275
  agentcore_pi_function_arn = module.agentcore_pi.agentcore_pi_function_arn
1102
1276
  enable_agentcore_pi_invoke_policy = true
1103
- hindsight_endpoint = local.hindsight_enabled ? module.hindsight[0].hindsight_endpoint : ""
1104
- hindsight_database_name = var.hindsight_database_name
1105
1277
  agentcore_memory_id = module.agentcore_memory.memory_id
1106
- memory_engine = local.resolved_memory_engine
1107
- okf_efs_subnet_ids = var.okf_wiki_efs_enabled ? local.okf_wiki_subnet_ids : []
1108
- okf_efs_security_group_ids = var.okf_wiki_efs_enabled ? [aws_security_group.okf_wiki_lambda[0].id] : []
1109
- analyst_egress_subnet_ids = var.analyst_lambda_vpc_egress ? module.vpc.private_subnet_ids : []
1110
- analyst_egress_security_group_ids = var.analyst_lambda_vpc_egress ? [aws_security_group.analyst_egress_lambda[0].id] : []
1111
- okf_efs_mount_target_ids = var.okf_wiki_efs_enabled ? aws_efs_mount_target.okf_wiki[*].id : []
1112
- okf_efs_file_system_arn = var.okf_wiki_efs_enabled ? aws_efs_file_system.okf_wiki[0].arn : ""
1113
- okf_efs_refresh_access_point_arn = var.okf_wiki_efs_enabled ? aws_efs_access_point.okf_wiki_refresh[0].arn : ""
1114
- twenty_provisioned = local.twenty_provisioned
1115
- twenty_runtime_enabled = local.twenty_runtime_enabled
1116
- twenty_url = local.twenty_provisioned ? module.twenty[0].twenty_url : ""
1117
- twenty_alb_arn = local.twenty_provisioned ? module.twenty[0].twenty_alb_arn : ""
1118
- twenty_target_group_arn = local.twenty_provisioned ? module.twenty[0].twenty_target_group_arn : ""
1119
- twenty_cluster_arn = local.twenty_provisioned ? module.twenty[0].twenty_cluster_arn : ""
1120
- twenty_server_service_name = local.twenty_provisioned ? module.twenty[0].twenty_server_service_name : ""
1121
- twenty_worker_service_name = local.twenty_provisioned ? module.twenty[0].twenty_worker_service_name : ""
1122
- twenty_server_log_group_name = local.twenty_provisioned ? module.twenty[0].twenty_server_log_group_name : ""
1123
- twenty_worker_log_group_name = local.twenty_provisioned ? module.twenty[0].twenty_worker_log_group_name : ""
1124
- admin_url = local.end_user_app_url
1125
- docs_url = "https://${module.docs_site.distribution_domain}"
1126
- www_url = var.www_domain != "" ? "https://${var.www_domain}" : "https://${module.www_site.distribution_domain}"
1127
- stripe_price_ids_json = var.stripe_price_ids_json
1128
- appsync_realtime_url = module.appsync.graphql_realtime_url
1129
- ecr_repository_url = module.agentcore_platform.ecr_repository_url
1278
+ # THINK-589: OKF EFS inputs are deprecated no-ops — always pass empty.
1279
+ okf_efs_subnet_ids = []
1280
+ okf_efs_security_group_ids = []
1281
+ # Company Brain U5: projector VPC attach only when the neptune-client SG
1282
+ # is configured (the twin's Neptune cluster lives in this same VPC). The
1283
+ # client SG only opens 8182→Neptune, so twin Lambdas ALSO attach the
1284
+ # egress SG below without it a VPC-attached Lambda cannot reach
1285
+ # Aurora/Secrets/S3 and every DB connection times out (seen live on the
1286
+ # first dev rebuild invoke).
1287
+ lambda_max_memory_mb = var.lambda_max_memory_mb
1288
+ neptune_endpoint = var.neptune_endpoint
1289
+ brain_mcp_url = var.brain_mcp_url
1290
+ neptune_cluster_resource_id = var.neptune_cluster_resource_id
1291
+ neptune_subnet_ids = var.neptune_client_security_group_id != "" ? module.vpc.private_subnet_ids : []
1292
+ neptune_security_group_ids = var.neptune_client_security_group_id != "" ? [var.neptune_client_security_group_id, aws_security_group.twin_lambda_egress[0].id] : []
1293
+ # THINK-1082: every handler inside the VPC behind the api-lambda SG (merged
1294
+ # with the Neptune SGs on the projector). NAT is switched on module.vpc.
1295
+ lambdas_in_vpc = var.api_lambdas_in_vpc
1296
+ vpc_subnet_ids = local.api_lambda_vpc_subnet_ids
1297
+ vpc_security_group_ids = local.api_lambda_vpc_security_group_ids
1298
+ # Bulk-rebuild lane (THINK-331): loader staging bucket + cluster loader
1299
+ # role, both default-empty (ship inert, KTD-9).
1300
+ neptune_load_bucket = var.neptune_load_bucket
1301
+ neptune_loader_role_arn = var.neptune_loader_role_arn
1302
+ # Company Brain U7: twin tool seam flag (KTD-5 rollout posture).
1303
+ # THINK-589: OKF EFS inputs are deprecated no-ops — always pass empty.
1304
+ okf_efs_mount_target_ids = []
1305
+ okf_efs_file_system_arn = ""
1306
+ okf_efs_refresh_access_point_arn = ""
1307
+ twenty_provisioned = local.twenty_provisioned
1308
+ twenty_runtime_enabled = local.twenty_runtime_enabled
1309
+ twenty_url = local.twenty_provisioned ? module.twenty[0].twenty_url : ""
1310
+ twenty_alb_arn = local.twenty_provisioned ? module.twenty[0].twenty_alb_arn : ""
1311
+ twenty_target_group_arn = local.twenty_provisioned ? module.twenty[0].twenty_target_group_arn : ""
1312
+ twenty_cluster_arn = local.twenty_provisioned ? module.twenty[0].twenty_cluster_arn : ""
1313
+ twenty_server_service_name = local.twenty_provisioned ? module.twenty[0].twenty_server_service_name : ""
1314
+ twenty_worker_service_name = local.twenty_provisioned ? module.twenty[0].twenty_worker_service_name : ""
1315
+ twenty_server_log_group_name = local.twenty_provisioned ? module.twenty[0].twenty_server_log_group_name : ""
1316
+ twenty_worker_log_group_name = local.twenty_provisioned ? module.twenty[0].twenty_worker_log_group_name : ""
1317
+ admin_url = local.end_user_app_url
1318
+ www_url = var.www_domain != "" ? "https://${var.www_domain}" : "https://${module.www_site.distribution_domain}"
1319
+ stripe_price_ids_json = var.stripe_price_ids_json
1320
+ appsync_realtime_url = module.appsync.graphql_realtime_url
1321
+ ecr_repository_url = module.agentcore_platform.ecr_repository_url
1130
1322
  # Static truth for count gating: agentcore_platform's ECR repo is
1131
1323
  # unconditional, but its URL attribute is unknown until apply. The runner
1132
1324
  # additionally needs its image tag seeded (CI does this for repo-managed
@@ -1146,22 +1338,19 @@ module "api" {
1146
1338
  enable_slack_workspace_app = var.enable_slack_workspace_app
1147
1339
  enable_msteams_app = var.enable_msteams_app
1148
1340
  agentcore_code_interpreter_id = var.agentcore_code_interpreter_id
1149
- wiki_compile_model_id = var.wiki_compile_model_id
1150
1341
  brain_source_agent_model_id = var.brain_source_agent_model_id
1151
1342
  wiki_aggregation_pass_enabled = var.wiki_aggregation_pass_enabled
1152
1343
  wiki_source = var.wiki_source
1153
- knowledge_graph_observations_ingest_enabled = var.knowledge_graph_observations_ingest_enabled
1344
+ identity_drift_match_enabled = var.identity_drift_match_enabled
1154
1345
  wiki_deterministic_linking_enabled = var.wiki_deterministic_linking_enabled
1155
- google_places_api_key = var.google_places_api_key
1156
1346
  enable_workspace_orchestration = var.enable_workspace_orchestration
1347
+ agentcore_session_scope = var.agentcore_session_scope
1157
1348
  requester_idle_memory_learning_enabled = var.requester_idle_memory_learning_enabled
1158
1349
  requester_memory_dreaming_enabled = var.requester_memory_dreaming_enabled
1159
1350
  requester_memory_dreaming_schedule_expression = var.requester_memory_dreaming_schedule_expression
1160
1351
  requester_memory_dreaming_model_id = var.requester_memory_dreaming_model_id
1161
1352
  brain_dream_state_enabled = var.brain_dream_state_enabled
1162
1353
  brain_dream_state_schedule_expression = var.brain_dream_state_schedule_expression
1163
- retry_dispatcher_enabled = var.retry_dispatcher_enabled
1164
- stall_threshold_minutes = var.stall_threshold_minutes
1165
1354
  # Per-user OAuth client credentials — fed to Secrets Manager in
1166
1355
  # app/lambda-api/oauth-secrets.tf. Reuses the same google_oauth_client_*
1167
1356
  # tfvars that already flow to the Cognito federated-signin module.
@@ -1170,6 +1359,19 @@ module "api" {
1170
1359
  redirect_success_url = var.redirect_success_url
1171
1360
  platform_operator_emails = var.platform_operator_emails
1172
1361
 
1362
+ # THINK-583 U3 — warm chat path (KTD5: these two handlers only).
1363
+ chat_agent_invoke_provisioned_concurrency = var.chat_agent_invoke_provisioned_concurrency
1364
+ workspace_renderer_provisioned_concurrency = var.workspace_renderer_provisioned_concurrency
1365
+ agentcore_runtime_dispatch_enabled = var.agentcore_runtime_dispatch_enabled
1366
+
1367
+ # THINK-915 — chat turn-latency observability.
1368
+ enable_chat_turn_latency_observability = var.enable_chat_turn_latency_observability
1369
+ enable_chat_turn_latency_metric_filters = var.enable_chat_turn_latency_metric_filters
1370
+ chat_turn_latency_metric_namespace = var.chat_turn_latency_metric_namespace
1371
+ chat_turn_runtime_log_group_name = var.chat_turn_runtime_log_group_name
1372
+ chat_turn_p95_alarm_threshold_ms = var.chat_turn_p95_alarm_threshold_ms
1373
+ chat_turn_latency_alarm_actions = var.chat_turn_latency_alarm_actions
1374
+
1173
1375
  mcp_custom_domain = var.mcp_custom_domain
1174
1376
  mcp_custom_domain_ready = var.mcp_custom_domain_ready
1175
1377
 
@@ -1184,6 +1386,8 @@ module "api" {
1184
1386
  capability_broker_audience = module.capability_broker.broker_audience
1185
1387
  capability_broker_api_id = module.capability_broker.private_api_id
1186
1388
  capability_broker_vpce_dns = module.capability_broker.execute_api_vpce_dns_name
1389
+ # THINK-643 — "postgres" (default) leaves the auth-state table unprovisioned.
1390
+ auth_state_store = var.auth_state_store
1187
1391
 
1188
1392
  depends_on = [module.cognito]
1189
1393
  }
@@ -1207,7 +1411,8 @@ module "agentcore_memory" {
1207
1411
  module "agentcore_platform" {
1208
1412
  source = "../app/agentcore-platform"
1209
1413
 
1210
- stage = var.stage
1414
+ stage = var.stage
1415
+ release_mirror_principal_arns = var.release_image_mirror_principal_arns
1211
1416
  }
1212
1417
 
1213
1418
  ################################################################################
@@ -1229,10 +1434,7 @@ module "agentcore_pi" {
1229
1434
  source_image_uri = var.agentcore_pi_source_image_uri
1230
1435
  async_dlq_arn = module.agentcore_platform.agentcore_async_dlq_arn
1231
1436
 
1232
- hindsight_endpoint = local.hindsight_enabled ? module.hindsight[0].hindsight_endpoint : ""
1233
- hindsight_database_name = var.hindsight_database_name
1234
1437
  agentcore_memory_id = module.agentcore_memory.memory_id
1235
- memory_engine = local.resolved_memory_engine
1236
1438
  requester_idle_memory_learning_enabled = var.requester_idle_memory_learning_enabled
1237
1439
 
1238
1440
  api_endpoint = module.api.api_endpoint
@@ -1244,32 +1446,60 @@ module "agentcore_pi" {
1244
1446
  db_cluster_arn = module.database.db_cluster_arn
1245
1447
  db_secret_arn = module.database.graphql_db_secret_arn
1246
1448
 
1247
- okf_efs_enabled = var.okf_wiki_efs_enabled
1248
- okf_efs_subnet_ids = var.okf_wiki_efs_enabled ? local.okf_wiki_subnet_ids : []
1249
- okf_efs_security_group_ids = var.okf_wiki_efs_enabled ? [aws_security_group.okf_wiki_lambda[0].id] : []
1250
- okf_efs_file_system_arn = var.okf_wiki_efs_enabled ? aws_efs_file_system.okf_wiki[0].arn : ""
1251
- okf_efs_read_access_point_arn = var.okf_wiki_efs_enabled ? aws_efs_access_point.okf_wiki_pi_read[0].arn : ""
1252
- }
1253
-
1254
- # AgentCore Harness trial (THINK-311 U4) ship-inert, pure IAM. Provisions
1255
- # the Harness microVM execution role; the api Lambda's Harness invoker grants
1256
- # ride the grouped ai policy in lambda-api (keyed off this module's role-ARN
1257
- # output). No handler creates or invokes a Harness until U5.
1258
- module "agentcore_harness" {
1259
- source = "../app/agentcore-harness"
1260
-
1261
- enabled = var.enable_agentcore_harness
1262
- stage = var.stage
1263
- region = var.region
1264
- account_id = var.account_id
1265
- bucket_name = module.s3.bucket_name
1449
+ # THINK-589: OKF EFS inputs are deprecated no-ops — always pass disabled.
1450
+ okf_efs_enabled = false
1451
+ okf_efs_subnet_ids = []
1452
+ okf_efs_security_group_ids = []
1453
+ okf_efs_file_system_arn = ""
1454
+ okf_efs_read_access_point_arn = ""
1455
+
1456
+ # THINK-1082: network-only VPC attachment alongside the api handlers.
1457
+ in_vpc = var.api_lambdas_in_vpc
1458
+ vpc_subnet_ids = local.api_lambda_vpc_subnet_ids
1459
+ vpc_security_group_ids = local.api_lambda_vpc_security_group_ids
1460
+ }
1461
+
1462
+ # THINK-316 U1 proof-only Identity and Gateway plane. These resources use the
1463
+ # regional execute-api URL because the dev account rejects public Lambda
1464
+ # Function URLs and a custom domain may be unavailable in a fresh stage.
1465
+ module "agentcore_proof_identity" {
1466
+ source = "../app/agentcore-identity"
1467
+
1468
+ # THINK-324: the proof plane is retired — permanently off. The module's
1469
+ # proof half (workload-identity lifecycle + proof credential provider) no
1470
+ # longer reconciles; delete_identity.sh retains the shared workload
1471
+ # identity for the Twenty half below.
1472
+ enabled = false
1473
+ # THINK-324 — the Twenty user-federation identity (shared workload
1474
+ # identity + twenty-crm credential provider + DCR client secret) survives
1475
+ # the proof plane's retirement: it stays enabled wherever a Twenty
1476
+ # instance is provisioned, and — while the proof flag is still on — on
1477
+ # proof stages too, so flipping the proof flag off later destroys only
1478
+ # proof resources. After the harness retirement removes the proof flag,
1479
+ # this reduces to twenty_provisioned alone.
1480
+ twenty_enabled = local.twenty_provisioned || var.enable_agentcore_multiplayer_proof
1481
+ stage = var.stage
1482
+ region = var.region
1483
+ account_id = var.account_id
1484
+ oauth_issuer = ""
1485
+ oauth_client_id = "thinkwork-${var.stage}-agentcore-proof"
1486
+ oauth_client_secret = ""
1487
+ user_federation_return_urls = [
1488
+ "${module.api.api_endpoint}/api/skills/mcp-oauth/agentcore/complete",
1489
+ ]
1490
+ # The identity module's issuer/resource defaults are dev's CRM domain;
1491
+ # every stage must point at its own Twenty instance or the credential
1492
+ # provider is reconciled with a foreign issuer (observed live on tei-e2e:
1493
+ # Connect-AgentCore 404'd against crm.thinkwork.ai).
1494
+ twenty_oauth_issuer = local.twenty_public_url != "" ? trimsuffix(local.twenty_public_url, "/") : "https://crm.thinkwork.ai"
1495
+ twenty_oauth_resource = local.twenty_public_url != "" ? "${trimsuffix(local.twenty_public_url, "/")}/mcp" : "https://crm.thinkwork.ai/mcp"
1266
1496
  }
1267
1497
 
1268
1498
  # Capability Broker (THINK-280 U3) — ship-inert, gated by
1269
1499
  # var.enable_capability_broker (default false). When off, this module creates
1270
1500
  # nothing; the broker Lambda code also fails closed. Owns a DEDICATED
1271
1501
  # execute-api VPCE with private DNS disabled — never folded into
1272
- # okf_wiki_interface_endpoint_services (THINK-144).
1502
+ # vpc_interface_endpoint_services (THINK-144).
1273
1503
  module "capability_broker" {
1274
1504
  source = "../app/capability-broker"
1275
1505
 
@@ -1288,6 +1518,10 @@ module "capability_broker" {
1288
1518
  db_password = var.db_password
1289
1519
  database_name = var.database_name
1290
1520
 
1521
+ # THINK-1082: the broker is already VPC-attached; give it the api-lambda SG
1522
+ # so it keeps its DB path once the public 5432 rule closes.
1523
+ additional_security_group_ids = local.api_lambda_vpc_security_group_ids
1524
+
1291
1525
  lambda_zips_dir = var.lambda_zips_dir
1292
1526
  lambda_artifact_bucket = var.lambda_artifact_bucket
1293
1527
  lambda_artifact_prefix = var.lambda_artifact_prefix
@@ -1334,6 +1568,11 @@ module "agentcore_admin" {
1334
1568
 
1335
1569
  capability_private_subnet_ids = module.agentcore_code_interpreter.capability_private_subnet_ids
1336
1570
  capability_private_security_group_ids = module.agentcore_code_interpreter.capability_private_security_group_ids
1571
+
1572
+ # THINK-1082: the admin handler opens DATABASE_URL — same VPC lane.
1573
+ in_vpc = var.api_lambdas_in_vpc
1574
+ vpc_subnet_ids = local.api_lambda_vpc_subnet_ids
1575
+ vpc_security_group_ids = local.api_lambda_vpc_security_group_ids
1337
1576
  }
1338
1577
 
1339
1578
  # Runtime identity rename: the former dedicated Flue module is now the Pi
@@ -1459,25 +1698,9 @@ module "workflow_interpreter_stepfunctions" {
1459
1698
  execution_callback_lambda_arn = module.api.workflow_execution_callback_fn_arn
1460
1699
  }
1461
1700
 
1462
- module "hindsight" {
1463
- count = local.hindsight_enabled ? 1 : 0
1464
- source = "../app/hindsight-memory"
1465
-
1466
- stage = var.stage
1467
- vpc_id = module.vpc.vpc_id
1468
- subnet_ids = module.vpc.public_subnet_ids
1469
- db_security_group_id = module.database.db_security_group_id
1470
- database_url = module.database.database_url
1471
- database_name = var.hindsight_database_name
1472
- image_tag = var.hindsight_image_tag
1473
-
1474
- enable_auto_consolidation = var.hindsight_enable_auto_consolidation
1475
- consolidation_dedup_threshold = var.hindsight_consolidation_dedup_threshold
1476
- observations_mission = var.hindsight_observations_mission
1477
- }
1478
1701
  module "twenty" {
1479
1702
  count = local.twenty_provisioned ? 1 : 0
1480
- source = "../../../plugins/twenty/terraform/twenty"
1703
+ source = "../app/twenty"
1481
1704
 
1482
1705
  stage = var.stage
1483
1706
  vpc_id = module.vpc.vpc_id
@@ -1515,7 +1738,7 @@ module "twenty" {
1515
1738
 
1516
1739
  module "n8n" {
1517
1740
  count = local.n8n_provisioned ? 1 : 0
1518
- source = "../../../plugins/n8n/terraform/n8n"
1741
+ source = "../app/n8n"
1519
1742
 
1520
1743
  stage = var.stage
1521
1744
  vpc_id = module.vpc.vpc_id
@@ -1595,14 +1818,38 @@ locals {
1595
1818
  # Host CSP for the Computer SPA (plan-012 U10 / contract v1 §CSP profile).
1596
1819
  # Generated apps always execute in the sandbox iframe shell, so the parent
1597
1820
  # origin never needs blob: script/worker execution for transformed modules.
1598
- computer_host_script_src = "'self'"
1599
- computer_host_worker_src = "'self'"
1600
- computer_host_frame_src = local.computer_sandbox_enabled ? "https://${var.computer_sandbox_domain}" : "'none'"
1821
+ #
1822
+ # 'wasm-unsafe-eval' permits WebAssembly compilation only (not JS eval) —
1823
+ # the in-app knowledge document viewer (Zrimo) renders Office files with
1824
+ # client-side WASM.
1825
+ computer_host_script_src = "'self' 'wasm-unsafe-eval'"
1826
+ # blob: workers are how Zrimo (knowledge document viewer) spawns its
1827
+ # render workers. With script-src carrying no blob:/eval, only
1828
+ # first-party page code can mint a blob worker, and blob workers
1829
+ # inherit this document's CSP — the U10 blob-execution escape hatch
1830
+ # (generated-app script on the host origin) stays closed.
1831
+ computer_host_worker_src = "'self' blob:"
1832
+ # frame-src carries the sandbox shell plus the cited-knowledge-document
1833
+ # frames: browser-native formats (pdf/txt/md) render in an iframe on the
1834
+ # signed /kb/doc link — a *.thinkwork.ai brain host that 302s to the
1835
+ # customer's evidence bucket presign, and CSP re-checks every redirect
1836
+ # hop, so both origins must be allowed (mirroring what connect-src
1837
+ # already trusts for the Zrimo fetch path).
1838
+ computer_host_frame_src = join(" ", compact([
1839
+ local.computer_sandbox_enabled ? "https://${var.computer_sandbox_domain}" : "",
1840
+ "https://*.thinkwork.ai",
1841
+ "https://*.s3.${var.region}.amazonaws.com",
1842
+ "https://s3.${var.region}.amazonaws.com",
1843
+ ]))
1601
1844
  computer_host_frame_ancestors = join(" ", compact([
1602
1845
  "'self'",
1603
1846
  ]))
1604
1847
 
1605
- computer_host_csp = "default-src 'self'; script-src ${local.computer_host_script_src}; style-src 'self' 'unsafe-inline'; worker-src ${local.computer_host_worker_src}; frame-src ${local.computer_host_frame_src}; connect-src 'self' https://*.execute-api.${var.region}.amazonaws.com https://*.appsync-api.${var.region}.amazonaws.com wss://*.appsync-realtime-api.${var.region}.amazonaws.com https://cognito-idp.${var.region}.amazonaws.com https://*.auth.${var.region}.amazoncognito.com https://*.s3.${var.region}.amazonaws.com https://s3.${var.region}.amazonaws.com; img-src 'self' data: blob: ${local.computer_sandbox_map_img_src}; font-src 'self' data:; object-src 'none'; base-uri 'self'; frame-ancestors ${local.computer_host_frame_ancestors};"
1848
+ # connect-src includes https://*.thinkwork.ai for the knowledge document
1849
+ # viewer: signed /kb/doc citation links live on brain MCP hosts
1850
+ # (mcp.brain.<customer>.thinkwork.ai), and a tenant may register another
1851
+ # stage's brain, so the host cannot be pinned per-stage.
1852
+ computer_host_csp = "default-src 'self'; script-src ${local.computer_host_script_src}; style-src 'self' 'unsafe-inline'; worker-src ${local.computer_host_worker_src}; frame-src ${local.computer_host_frame_src}; connect-src 'self' https://*.thinkwork.ai https://*.execute-api.${var.region}.amazonaws.com https://*.appsync-api.${var.region}.amazonaws.com wss://*.appsync-realtime-api.${var.region}.amazonaws.com https://cognito-idp.${var.region}.amazonaws.com https://*.auth.${var.region}.amazoncognito.com https://*.s3.${var.region}.amazonaws.com https://s3.${var.region}.amazonaws.com; img-src 'self' data: blob: ${local.computer_sandbox_map_img_src}; font-src 'self' data:; object-src 'none'; base-uri 'self'; frame-ancestors ${local.computer_host_frame_ancestors};"
1606
1853
  }
1607
1854
 
1608
1855
  module "computer_site" {
@@ -1704,7 +1951,7 @@ module "customer_domain" {
1704
1951
  # https://*.tile.openstreetmap.org https://api.mapbox.com;
1705
1952
  # font-src 'self' data:; connect-src 'none';
1706
1953
  # frame-src https://www.openstreetmap.org; object-src 'none';
1707
- # base-uri 'self'; frame-ancestors <web parents + desktop custom protocols>;
1954
+ # base-uri 'self'; frame-ancestors <web parents>;
1708
1955
  #
1709
1956
  # Provisioning is gated on var.computer_sandbox_domain — leave empty in
1710
1957
  # stages that haven't allocated the subdomain yet.
@@ -1713,18 +1960,10 @@ module "customer_domain" {
1713
1960
  locals {
1714
1961
  computer_sandbox_enabled = var.computer_sandbox_domain != ""
1715
1962
 
1716
- computer_sandbox_desktop_parent_origins = [
1717
- "thinkwork://app",
1718
- "thinkwork-dev://app",
1719
- "thinkwork-canary://app",
1720
- ]
1721
- computer_sandbox_allowed_parent_origin_list = distinct(concat(
1722
- [
1723
- for origin in split(",", replace(var.computer_sandbox_allowed_parent_origins, " ", "")) :
1724
- origin if origin != ""
1725
- ],
1726
- local.computer_sandbox_desktop_parent_origins
1727
- ))
1963
+ computer_sandbox_allowed_parent_origin_list = distinct([
1964
+ for origin in split(",", replace(var.computer_sandbox_allowed_parent_origins, " ", "")) :
1965
+ origin if origin != ""
1966
+ ])
1728
1967
  computer_sandbox_allowed_parent_origins_effective = join(",", local.computer_sandbox_allowed_parent_origin_list)
1729
1968
  computer_sandbox_frame_ancestors = local.computer_sandbox_enabled && length(local.computer_sandbox_allowed_parent_origin_list) > 0 ? join(" ", local.computer_sandbox_allowed_parent_origin_list) : "'none'"
1730
1969
 
@@ -1776,20 +2015,6 @@ module "computer_sandbox_site" {
1776
2015
  }
1777
2016
  }
1778
2017
 
1779
- ################################################################################
1780
- # Docs Static Site
1781
- ################################################################################
1782
-
1783
- module "docs_site" {
1784
- source = "../app/static-site"
1785
-
1786
- stage = var.stage
1787
- site_name = "docs"
1788
- bucket_name = "thinkwork-${var.stage}-${var.account_id}-docs"
1789
- custom_domain = var.docs_domain
1790
- certificate_arn = var.docs_certificate_arn
1791
- }
1792
-
1793
2018
  ################################################################################
1794
2019
  # Public Website (www)
1795
2020
  ################################################################################