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
@@ -5,17 +5,18 @@ redacts known-shape OAuth tokens in AgentCore `APPLICATION_LOGS` before they
5
5
  land in the long-term CloudWatch tier. See plan Unit 12 +
6
6
  `docs/brainstorms/2026-04-22-agentcore-code-sandbox-requirements.md` R13.
7
7
 
8
- ## Relationship to the primary scrubber
8
+ ## The only scrubbing layer (THINK-617)
9
9
 
10
- The primary layer is the base-image `sitecustomize.py` stdio wrapper shipped
11
- by [`terraform/modules/app/agentcore-code-interpreter`](../agentcore-code-interpreter/)
12
- (plan Unit 4). That layer redacts by **value** session-scoped token
13
- strings registered by the preamble — and can therefore catch any token the
14
- agent's own preamble has handled.
10
+ The plan's primary layer was a base-image `sitecustomize.py` stdio wrapper
11
+ redacting by **value** (plan Unit 4). It never ran: AgentCore Code Interpreter
12
+ has no custom-image parameter, so the blessed image was unattachable and the
13
+ [`agentcore-code-interpreter`](../agentcore-code-interpreter/) image substrate
14
+ has been retired. Sandboxes run the AWS-managed image, so this filter is the
15
+ only scrubbing in force.
15
16
 
16
- This backstop redacts by **pattern**: it has no access to session values,
17
- only to the bytes that reach CloudWatch. It exists to mitigate *stdio-bypass
18
- classes* named in R13's residual list:
17
+ It redacts by **pattern**: it has no access to session values, only to the
18
+ bytes that reach CloudWatch. It covers the _stdio-bypass_ classes named in
19
+ R13's residual list
19
20
 
20
21
  - `subprocess.run(['env'])`, `subprocess.run(['cat', '/proc/self/environ'])`
21
22
  - `os.write(fd, ...)` at the file-descriptor level
@@ -25,7 +26,7 @@ classes* named in R13's residual list:
25
26
  - Adversarial split-writes that fragment a token across more bytes than the
26
27
  rolling-buffer window
27
28
 
28
- When those bytes carry a token whose *shape* is recognizable, this backstop
29
+ When those bytes carry a token whose _shape_ is recognizable, this backstop
29
30
  catches it. When they don't (bespoke token formats, high-entropy opaque
30
31
  strings with no prefix), only the v2 in-process credential proxy can help.
31
32
 
@@ -5,11 +5,11 @@
5
5
  # (plan Unit 12). Pattern-redacts known-shape OAuth tokens in AgentCore
6
6
  # APPLICATION_LOGS before they land in the long-term CloudWatch tier.
7
7
  #
8
- # **This is not the primary R13 layer.** The primary layer is the base-image
9
- # sitecustomize.py stdio wrapper (plan Unit 4, terraform/modules/app/
10
- # agentcore-code-interpreter) which redacts by *value* using the session-
11
- # scoped token set. That layer can catch any token the preamble registered,
12
- # regardless of shape.
8
+ # **This is the only scrubbing layer that actually runs (THINK-617).** The plan
9
+ # called for a primary value-based layer in a blessed base image's
10
+ # sitecustomize.py (Unit 4), but AgentCore Code Interpreter has no custom-image
11
+ # parameter, so that image was never attachable and has been retired. Sandboxes
12
+ # run the AWS-managed image; only this pattern backstop is in force.
13
13
  #
14
14
  # This backstop redacts by *pattern* — Authorization: Bearer, JWTs, and
15
15
  # known OAuth prefixes (gh[opsru]_, xox[abep]-, ya29.). It does not have
@@ -55,7 +55,7 @@ variable "viewer_request_function_code" {
55
55
  # Response-headers policy (optional, plan-012 U3)
56
56
  #
57
57
  # Two opt-in forms, both backwards compatible — existing callers
58
- # (computer_site, docs_site, www_site) leave both unset and the
58
+ # (computer_site, www_site) leave both unset and the
59
59
  # distribution is created with no response-headers policy attached:
60
60
  #
61
61
  # - Pass `response_headers_policy_id` to attach an existing policy by id.
@@ -3,12 +3,11 @@
3
3
  #
4
4
  # Responsibilities:
5
5
  # 1. ACM certificate in us-east-1 covering apex + www
6
- # (+ optional docs + optional admin + optional app + optional computer).
6
+ # (+ optional admin + optional app + optional computer).
7
7
  # 2. Cloudflare DNS records for ACM DNS validation.
8
8
  # 3. Apex CNAME in Cloudflare → primary CloudFront distribution (DNS-only).
9
9
  # 4. Second CloudFront distribution fronting an S3 website-redirect bucket
10
10
  # that 301s www.<domain> → https://<domain>, plus its Cloudflare CNAME.
11
- # 5. Optional docs.<domain> CNAME → docs CloudFront distribution.
12
11
  # 6. Optional admin.<domain> CNAME → admin CloudFront distribution.
13
12
  # 7. Optional app.<domain> CNAME → end-user app CloudFront distribution.
14
13
  # 8. Optional computer.<domain> → app.<domain> 301 compatibility redirect.
@@ -37,7 +36,6 @@ terraform {
37
36
  locals {
38
37
  apex = var.domain
39
38
  www = "www.${var.domain}"
40
- docs = "docs.${var.domain}"
41
39
  admin = "admin.${var.domain}"
42
40
  app = "app.${var.domain}"
43
41
  computer = "computer.${var.domain}"
@@ -47,7 +45,7 @@ locals {
47
45
  n8n = "n8n.${var.domain}"
48
46
  name_id = replace(var.domain, ".", "-")
49
47
 
50
- # ACM SANs: always include www, conditionally include docs, admin, computer,
48
+ # ACM SANs: always include www, conditionally include admin, computer,
51
49
  # and api. The Computer iframe sandbox and CRM ALB use their own certificates
52
50
  # so adding or rotating those hosts never forces a replacement of this shared
53
51
  # production certificate.
@@ -56,11 +54,16 @@ locals {
56
54
  # depend on the cert, so the cert mustn't depend on those outputs.
57
55
  cert_sans = concat(
58
56
  [local.www],
59
- var.include_docs ? [local.docs] : [],
60
57
  var.include_admin ? [local.admin] : [],
61
58
  var.include_app ? [local.app] : [],
62
59
  var.include_computer ? [local.computer] : [],
63
60
  var.include_api ? [local.api] : [],
61
+ # Retired docs.<domain> SAN, retained on stacks deployed before THINK-702.
62
+ # Shrinking the SAN list forces a create-before-destroy replacement of this
63
+ # shared certificate, which cannot be ordered against the thinkwork module
64
+ # (the two modules feed each other) and fails the plan with a cycle. A dead
65
+ # SAN costs nothing and its validation CNAME stays in place for renewals.
66
+ var.retain_docs_san ? ["docs.${var.domain}"] : [],
64
67
  )
65
68
 
66
69
  # Existing CNAME records stay gated on non-empty targets because their target
@@ -68,7 +71,6 @@ locals {
68
71
  # such as app/computer compatibility/sandbox/crm CNAMEs must gate only on
69
72
  # explicit booleans so Terraform can plan the resource count before the new
70
73
  # load balancer exists.
71
- create_docs_record = var.include_docs && var.docs_cloudfront_domain_name != ""
72
74
  create_admin_record = var.include_admin && var.admin_cloudfront_domain_name != ""
73
75
  create_app_record = var.include_app
74
76
  create_computer_record = var.include_computer
@@ -78,7 +80,7 @@ locals {
78
80
  }
79
81
 
80
82
  ################################################################################
81
- # ACM certificate (us-east-1, covers apex + www [+ docs])
83
+ # ACM certificate (us-east-1, covers apex + www [+ optional subdomains])
82
84
  ################################################################################
83
85
 
84
86
  resource "aws_acm_certificate" "www" {
@@ -244,26 +246,6 @@ resource "cloudflare_record" "www_redirect" {
244
246
  comment = "thinkwork-${var.stage} www → redirect distribution"
245
247
  }
246
248
 
247
- ################################################################################
248
- # docs.<domain> → docs CloudFront distribution (optional)
249
- #
250
- # Created only when the greenfield stack wires docs_cloudfront_domain_name.
251
- # The docs CloudFront alias picks up the same ACM cert via certificate_arn
252
- # on the thinkwork module's docs_site.
253
- ################################################################################
254
-
255
- resource "cloudflare_record" "docs" {
256
- count = local.create_docs_record ? 1 : 0
257
-
258
- zone_id = var.cloudflare_zone_id
259
- name = local.docs
260
- content = var.docs_cloudfront_domain_name
261
- type = "CNAME"
262
- ttl = 300
263
- proxied = false
264
- comment = "thinkwork-${var.stage} docs → CloudFront"
265
- }
266
-
267
249
  ################################################################################
268
250
  # admin.<domain> → admin CloudFront distribution (optional)
269
251
  ################################################################################
@@ -18,20 +18,14 @@ variable "cloudfront_domain_name" {
18
18
  type = string
19
19
  }
20
20
 
21
- variable "include_docs" {
22
- description = "When true, add docs.<domain> to the ACM cert SANs and create a Cloudflare CNAME for it. Separated from docs_cloudfront_domain_name to avoid a Terraform dependency cycle (distribution depends on cert, so the cert can't depend on the distribution output)."
21
+ variable "retain_docs_san" {
22
+ description = "When true, keep the retired docs.<domain> SAN on the shared ACM certificate. Set on stacks deployed before THINK-702 so removing the docs site does not force a certificate replacement (which cycles against the thinkwork module). New stacks leave this false."
23
23
  type = bool
24
24
  default = false
25
25
  }
26
26
 
27
- variable "docs_cloudfront_domain_name" {
28
- description = "CloudFront distribution domain name for the docs site. Used as the target for the docs.<domain> Cloudflare CNAME when include_docs is true."
29
- type = string
30
- default = ""
31
- }
32
-
33
27
  variable "include_admin" {
34
- description = "When true, add admin.<domain> to the ACM cert SANs and create a Cloudflare CNAME for it. Same cycle-avoidance rationale as include_docs."
28
+ description = "When true, add admin.<domain> to the ACM cert SANs and create a Cloudflare CNAME for it. Gated on a plain bool (not a CloudFront output) to keep the dependency graph acyclic."
35
29
  type = bool
36
30
  default = false
37
31
  }
@@ -67,7 +61,7 @@ variable "computer_cloudfront_domain_name" {
67
61
  }
68
62
 
69
63
  variable "include_computer_sandbox" {
70
- description = "When true, add sandbox.<domain> to the ACM cert SANs and create a Cloudflare CNAME for it. Same cycle-avoidance rationale as include_docs."
64
+ description = "When true, add sandbox.<domain> to the ACM cert SANs and create a Cloudflare CNAME for it. Gated on a plain bool (not a CloudFront output) to keep the dependency graph acyclic."
71
65
  type = bool
72
66
  default = false
73
67
  }
@@ -78,6 +78,8 @@ module "database" {
78
78
  | `max_capacity` | number | `2` | Aurora max ACU (aurora-serverless only) |
79
79
  | `rds_instance_class` | string | `"db.t4g.micro"` | RDS instance class (rds-postgres only) |
80
80
  | `rds_allocated_storage` | number | `20` | Storage in GB (rds-postgres only) |
81
+ | `publicly_accessible` | bool | `true` | Public IP on the cluster instance / RDS instance. `false` once every client is inside the VPC (THINK-1082) |
82
+ | `public_ingress_cidrs` | list(string) | `["0.0.0.0/0"]` | CIDR tcp/5432 ingress seeded on a **new** database security group. `[]` = none. Does not revoke a live rule (see below) |
81
83
  | `deletion_protection` | bool | `null` | Auto: `true` for Aurora, `false` for RDS |
82
84
 
83
85
  ## Outputs
@@ -90,3 +92,35 @@ module "database" {
90
92
  | `db_security_group_id` | Security group ID |
91
93
  | `database_url` | Full connection string (sensitive) |
92
94
  | `database_engine` | Which engine is running |
95
+
96
+ ## Closing the public port (THINK-1082)
97
+
98
+ By default the database gets a public endpoint (`publicly_accessible = true`)
99
+ and its security group is seeded with a world-open `0.0.0.0/0 -> 5432` ingress.
100
+ Every client that has no `vpc_config` (the api Lambdas, the deployment runner's
101
+ `psql`) depends on that rule. Revoking it before those clients move inside the
102
+ VPC takes the app down (auth-me -> DB timeout -> 401).
103
+
104
+ Two facts govern the close:
105
+
106
+ 1. The security group has `lifecycle { ignore_changes = [name, ingress] }` so
107
+ app modules can attach standalone `aws_security_group_rule` grants for their
108
+ own security groups (ECS tasks, the runner, the api-lambda group). Because of
109
+ that, setting `public_ingress_cidrs = []` on an existing stage changes what
110
+ Terraform would create and stops it re-seeding the rule, but **does not
111
+ revoke the rule that already exists**. The operator revokes it by hand, once:
112
+
113
+ ```bash
114
+ aws ec2 revoke-security-group-ingress --group-id <thinkwork-<stage>-db-sg> \
115
+ --protocol tcp --port 5432 --cidr 0.0.0.0/0
116
+ ```
117
+
118
+ 2. `publicly_accessible = false` removes the public IP (a modify on the
119
+ instance, applied immediately). Do it in the same step as, or after, the
120
+ ingress close — never before the clients are in the VPC.
121
+
122
+ The RDS Data API (`enable_http_endpoint = true`) keeps working throughout: it
123
+ needs IAM, not a network path, so operator SQL and the Pi session store are
124
+ unaffected. The stage-level order (Lambdas first, runner second, port last) is
125
+ in `modules/app/deployment-control-plane/README.md`, "Closing the database
126
+ port".
@@ -0,0 +1,82 @@
1
+ ################################################################################
2
+ # Aurora Serverless v2 saturation alarms
3
+ #
4
+ # STATISTIC MATTERS HERE. RDS publishes CPUUtilization from 1-second samples,
5
+ # so the `Maximum` statistic over any period reports the single busiest second
6
+ # in that period — on Serverless v2 that reads as ~100% essentially forever
7
+ # and tells you nothing. An operator chasing "the database is pegged" off the
8
+ # Maximum series is chasing an artifact of the sampling rate, not load.
9
+ #
10
+ # Both alarms below therefore use `Average`, which is the statistic that
11
+ # actually tracks sustained saturation:
12
+ # - CPUUtilization — average CPU across the 5-minute period.
13
+ # - ACUUtilization — how much of the configured max_capacity ACU ceiling
14
+ # the cluster is consuming. This is the one that
15
+ # matters for Serverless v2: sustained high ACU means
16
+ # the cluster is near its scaling ceiling and the next
17
+ # load step has nowhere to go.
18
+ #
19
+ # 3 × 5-minute evaluation periods (15 minutes of sustained pressure) so a
20
+ # migration, a backfill, or a burst of agent traffic does not page anyone.
21
+ #
22
+ # alarm_actions are empty by module convention — this module owns no SNS
23
+ # topic, and the app module's only topic is the cost-alert channel (see
24
+ # terraform/modules/app/lambda-api/memory-alarms.tf for the same reasoning).
25
+ # Operators subscribe a topic when a stage needs paging.
26
+ #
27
+ # Aurora-only: ACUUtilization does not exist for the rds-postgres dev/test
28
+ # engine, and the pairing is what makes these useful, so both are gated on
29
+ # local.use_aurora.
30
+ ################################################################################
31
+
32
+ resource "aws_cloudwatch_metric_alarm" "aurora_cpu_utilization_high" {
33
+ count = local.use_aurora ? 1 : 0
34
+
35
+ alarm_name = "thinkwork-${var.stage}-db-cpu-utilization-high"
36
+ alarm_description = "Aurora writer instance averaged >${var.cpu_utilization_alarm_threshold}% CPU for 15 minutes. Statistic is Average by design — the Maximum series is ~100% at all times because RDS samples CPU every second."
37
+
38
+ namespace = "AWS/RDS"
39
+ metric_name = "CPUUtilization"
40
+ statistic = "Average"
41
+
42
+ period = 300
43
+ evaluation_periods = 3
44
+ threshold = var.cpu_utilization_alarm_threshold
45
+ comparison_operator = "GreaterThanThreshold"
46
+ treat_missing_data = "notBreaching"
47
+ alarm_actions = []
48
+
49
+ dimensions = {
50
+ DBInstanceIdentifier = aws_rds_cluster_instance.main[0].identifier
51
+ }
52
+
53
+ tags = {
54
+ Name = "thinkwork-${var.stage}-db-cpu-utilization-high"
55
+ }
56
+ }
57
+
58
+ resource "aws_cloudwatch_metric_alarm" "aurora_acu_utilization_high" {
59
+ count = local.use_aurora ? 1 : 0
60
+
61
+ alarm_description = "Aurora Serverless v2 averaged >${var.acu_utilization_alarm_threshold}% of its max_capacity ACU ceiling for 15 minutes — the cluster is close to having nowhere left to scale. Raise max_capacity or shed load."
62
+ alarm_name = "thinkwork-${var.stage}-db-acu-utilization-high"
63
+
64
+ namespace = "AWS/RDS"
65
+ metric_name = "ACUUtilization"
66
+ statistic = "Average"
67
+
68
+ period = 300
69
+ evaluation_periods = 3
70
+ threshold = var.acu_utilization_alarm_threshold
71
+ comparison_operator = "GreaterThanThreshold"
72
+ treat_missing_data = "notBreaching"
73
+ alarm_actions = []
74
+
75
+ dimensions = {
76
+ DBInstanceIdentifier = aws_rds_cluster_instance.main[0].identifier
77
+ }
78
+
79
+ tags = {
80
+ Name = "thinkwork-${var.stage}-db-acu-utilization-high"
81
+ }
82
+ }
@@ -53,12 +53,20 @@ resource "aws_security_group" "db" {
53
53
  description = "Security group for Thinkwork PostgreSQL database"
54
54
  vpc_id = var.vpc_id
55
55
 
56
- ingress {
57
- from_port = 5432
58
- to_port = 5432
59
- protocol = "tcp"
60
- cidr_blocks = ["0.0.0.0/0"]
61
- description = "PostgreSQL access"
56
+ # THINK-1082: the inline CIDR ingress is now driven by public_ingress_cidrs
57
+ # (default ["0.0.0.0/0"] = today's world-open rule; [] = none). Because
58
+ # ingress is in ignore_changes below, this only shapes a NEW group and stops
59
+ # Terraform from re-seeding the rule — it never revokes a live one.
60
+ dynamic "ingress" {
61
+ for_each = length(var.public_ingress_cidrs) > 0 ? [1] : []
62
+
63
+ content {
64
+ from_port = 5432
65
+ to_port = 5432
66
+ protocol = "tcp"
67
+ cidr_blocks = var.public_ingress_cidrs
68
+ description = "PostgreSQL access"
69
+ }
62
70
  }
63
71
 
64
72
  egress {
@@ -76,7 +84,10 @@ resource "aws_security_group" "db" {
76
84
  # App modules grant their own task security groups database access through
77
85
  # standalone aws_security_group_rule resources. Keep this shared group from
78
86
  # trying to reconcile those externally managed ingress rules during targeted
79
- # managed-app deploys.
87
+ # managed-app deploys. Consequence (THINK-1082): setting
88
+ # public_ingress_cidrs = [] on a live stage does not revoke the existing
89
+ # 0.0.0.0/0 rule — the operator revokes it by hand once the clients are
90
+ # in the VPC (see README.md "Closing the public port").
80
91
  ignore_changes = [name, ingress]
81
92
  }
82
93
  }
@@ -117,15 +128,11 @@ resource "aws_rds_cluster" "main" {
117
128
  deletion_protection = local.deletion_protection
118
129
  storage_encrypted = true
119
130
 
120
- # THINK-229 U1 (R1): the analyst-query-broker Lambda authenticates as
121
- # analyst_reader with per-connect RDS IAM auth tokens instead of a
122
- # stored password. Cluster-level flag; applies without downtime.
123
- # apply_immediately is required: the provider default defers cluster
124
- # modifications to the maintenance window, and if the GRANT rds_iam
125
- # migration (0229) landed inside that pending window the role would
126
- # refuse BOTH password (grant applied) and IAM (flag still pending)
127
- # login. Deploys on this platform are CLI/CI-driven and expect
128
- # immediate semantics.
131
+ # RDS IAM database authentication: roles granted rds_iam log in with
132
+ # per-connect auth tokens instead of a stored password. Cluster-level
133
+ # flag; applies without downtime. apply_immediately is required — the
134
+ # provider default defers cluster modifications to the maintenance
135
+ # window, which can strand a role between the GRANT and the flag.
129
136
  iam_database_authentication_enabled = true
130
137
  apply_immediately = true
131
138
 
@@ -154,7 +161,7 @@ resource "aws_rds_cluster_instance" "main" {
154
161
  engine = aws_rds_cluster.main[0].engine
155
162
  engine_version = aws_rds_cluster.main[0].engine_version
156
163
 
157
- publicly_accessible = true
164
+ publicly_accessible = var.publicly_accessible
158
165
  db_subnet_group_name = aws_db_subnet_group.main[0].name
159
166
 
160
167
  tags = {
@@ -188,13 +195,12 @@ resource "aws_db_instance" "main" {
188
195
  db_subnet_group_name = aws_db_subnet_group.main[0].name
189
196
  vpc_security_group_ids = [aws_security_group.db[0].id]
190
197
 
191
- publicly_accessible = true
198
+ publicly_accessible = var.publicly_accessible
192
199
  skip_final_snapshot = true
193
200
  deletion_protection = local.deletion_protection
194
201
 
195
- # THINK-229 U1 (R1): keep the rds-postgres dev/test engine at parity
196
- # with the Aurora cluster analyst_reader logs in with IAM tokens.
197
- # apply_immediately for the same both-paths-stranded reason as the
202
+ # Keep the rds-postgres dev/test engine at IAM-auth parity with the
203
+ # Aurora cluster. apply_immediately for the same stranding reason as the
198
204
  # Aurora cluster block above.
199
205
  iam_database_authentication_enabled = true
200
206
  apply_immediately = true
@@ -377,39 +383,3 @@ resource "aws_secretsmanager_secret" "compliance_reader" {
377
383
  Role = "compliance_reader"
378
384
  }
379
385
  }
380
-
381
- ################################################################################
382
- # Secrets Manager — Analyst Reader Role Credentials (THINK-228 U2)
383
- #
384
- # Container for the analyst_reader Aurora role used by the analyst
385
- # query-broker Lambda. Terraform owns the SECRET CONTAINER; the operator
386
- # owns the SECRET VALUE (populated by scripts/bootstrap-analyst-roles.sh,
387
- # which also applies drizzle/0227_analyst_reader_role.sql to create the
388
- # matching hardened read-only role).
389
- ################################################################################
390
-
391
- resource "aws_secretsmanager_secret" "analyst_reader" {
392
- count = local.create ? 1 : 0
393
- name = "thinkwork/${var.stage}/analyst/reader-credentials"
394
-
395
- tags = {
396
- Name = "thinkwork-${var.stage}-analyst-reader-credentials"
397
- Role = "analyst_reader"
398
- }
399
- }
400
-
401
- # Broker caller credential for the analyst query broker (THINK-228 U3).
402
- # The connector row (tenant_mcp_servers, seeded by
403
- # scripts/provision-analyst-connector.mts) references this ARN as its
404
- # auth_config.secretRef; the broker Lambda validates incoming Bearer
405
- # tokens against it. Value shape: JSON {token, tenantId} — populated by
406
- # the provisioning script, never by Terraform.
407
- resource "aws_secretsmanager_secret" "analyst_broker" {
408
- count = local.create ? 1 : 0
409
- name = "thinkwork/${var.stage}/analyst/broker-credential"
410
-
411
- tags = {
412
- Name = "thinkwork-${var.stage}-analyst-broker-credential"
413
- Role = "analyst_query_broker"
414
- }
415
- }
@@ -68,12 +68,3 @@ output "compliance_reader_secret_arn" {
68
68
  value = local.create ? aws_secretsmanager_secret.compliance_reader[0].arn : ""
69
69
  }
70
70
 
71
- output "analyst_reader_secret_arn" {
72
- description = "Secrets Manager ARN for the analyst_reader Aurora role (THINK-228 U2). Empty string when create_database = false."
73
- value = local.create ? aws_secretsmanager_secret.analyst_reader[0].arn : ""
74
- }
75
-
76
- output "analyst_broker_secret_arn" {
77
- description = "Secrets Manager ARN for the analyst query-broker caller credential (THINK-228 U3). Empty string when create_database = false."
78
- value = local.create ? aws_secretsmanager_secret.analyst_broker[0].arn : ""
79
- }
@@ -113,6 +113,31 @@ variable "deletion_protection" {
113
113
  default = null
114
114
  }
115
115
 
116
+ # ---------------------------------------------------------------------------
117
+ # Network exposure (THINK-1082). Defaults reproduce today's posture: a public
118
+ # endpoint plus a world-open 0.0.0.0/0 -> 5432 ingress. A stage whose database
119
+ # clients (api Lambdas, deployment runner, ECS tasks) all reach the cluster by
120
+ # security group closes the port by setting public_ingress_cidrs = [] and
121
+ # publicly_accessible = false. NOTE: the DB security group ignores ingress
122
+ # drift (lifecycle.ignore_changes) so that app modules can own their own
123
+ # standalone rules — which means shrinking this list does NOT revoke a rule
124
+ # that already exists on a live group. The operator revokes it by hand once;
125
+ # this variable governs what a fresh group is created with and what
126
+ # Terraform stops re-seeding. See README.md "Closing the public port".
127
+ # ---------------------------------------------------------------------------
128
+
129
+ variable "publicly_accessible" {
130
+ description = "Whether the cluster instance / RDS instance gets a public IP (publicly_accessible). Default true = today's posture. Set false once every client reaches the database inside the VPC by security group."
131
+ type = bool
132
+ default = true
133
+ }
134
+
135
+ variable "public_ingress_cidrs" {
136
+ description = "CIDR blocks seeded as tcp/5432 ingress on the database security group when it is created. Default [\"0.0.0.0/0\"] = today's world-open rule. [] seeds no inline rule (clients are admitted by security-group-sourced rules instead). Because the group ignores ingress drift, changing this on an existing stage does not revoke the live rule — revoke it by hand after the clients are inside the VPC."
137
+ type = list(string)
138
+ default = ["0.0.0.0/0"]
139
+ }
140
+
116
141
  # ---------------------------------------------------------------------------
117
142
  # aws_s3 Aurora extension (optional — set backups_bucket_arn to enable)
118
143
  # ---------------------------------------------------------------------------
@@ -123,6 +148,22 @@ variable "backups_bucket_arn" {
123
148
  default = null
124
149
  }
125
150
 
151
+ # ---------------------------------------------------------------------------
152
+ # CloudWatch saturation alarms (aurora-serverless engine only; see alarms.tf)
153
+ # ---------------------------------------------------------------------------
154
+
155
+ variable "cpu_utilization_alarm_threshold" {
156
+ description = "Average CPUUtilization percentage that, sustained for 3x5min, raises the Aurora CPU alarm. Evaluated against the Average statistic — the Maximum statistic is meaningless on RDS (1-second sampling pins it near 100%)."
157
+ type = number
158
+ default = 70
159
+ }
160
+
161
+ variable "acu_utilization_alarm_threshold" {
162
+ description = "Average ACUUtilization percentage (share of max_capacity consumed) that, sustained for 3x5min, raises the Aurora Serverless v2 scaling-headroom alarm."
163
+ type = number
164
+ default = 85
165
+ }
166
+
126
167
  variable "enable_aws_s3" {
127
168
  description = "Plan-time gate for the aws_s3 Aurora extension IAM role. Set true when Aurora should be allowed to PutObject into backups_bucket_arn. Only effective when database_engine = 'aurora-serverless'. Defaults to false to preserve the prior 'opt-in by passing backups_bucket_arn' shape when this variable is omitted."
128
169
  type = bool
@@ -1,7 +1,7 @@
1
1
  ################################################################################
2
2
  # S3 Buckets — Data Module
3
3
  #
4
- # Creates the primary S3 bucket for skills, artifacts, knowledge base docs,
4
+ # Creates the primary S3 bucket for skills, artifacts,
5
5
  # and email inbound storage. HTTPS-only enforcement + SES inbound policy.
6
6
  ################################################################################
7
7
 
@@ -109,11 +109,10 @@ output "bucket_arn" {
109
109
  value = aws_s3_bucket.main.arn
110
110
  }
111
111
 
112
- # Analyst query-broker result staging (THINK-228 U3). Results larger than
113
- # the inline envelope cap land as CSVs under analyst-staging/<tenantId>/
114
- # with SSE; they are scratch data consumed by the agent sandbox within the
115
- # same delegation, so a short TTL bounds both storage cost and the window
116
- # in which a leaked object key is useful.
112
+ # Janitor for the RETIRED analyst query broker's staged results. The broker
113
+ # is gone, but stages that ran it still hold CSVs under analyst-staging/.
114
+ # Keeping the expiry rule drains them; deleting it would strand that data
115
+ # with no TTL. Safe to remove once every stage's prefix is empty.
117
116
  resource "aws_s3_bucket_lifecycle_configuration" "analyst_staging" {
118
117
  bucket = aws_s3_bucket.main.id
119
118