thinkwork-cli 0.13.1 → 0.13.2

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 (130) hide show
  1. package/dist/{api-client-4DZ266J5.js → api-client-JYZXYQJR.js} +3 -1
  2. package/dist/bowser-6Z6JFAIR.js +2822 -0
  3. package/dist/chunk-DV3MRBR5.js +43 -0
  4. package/dist/chunk-DVPBI5HM.js +1728 -0
  5. package/dist/chunk-EI5ZX7CN.js +522 -0
  6. package/dist/chunk-EUJ7X6YD.js +126 -0
  7. package/dist/chunk-GG5WKBOX.js +436 -0
  8. package/dist/chunk-I64EZSU5.js +358 -0
  9. package/dist/chunk-ILZKG5WV.js +6151 -0
  10. package/dist/chunk-KMIJ5KGT.js +128 -0
  11. package/dist/chunk-OCPHU34C.js +996 -0
  12. package/dist/chunk-QOERT44A.js +3286 -0
  13. package/dist/chunk-XYM7PE2A.js +2264 -0
  14. package/dist/{chunk-Y2WHJECR.js → chunk-Z2F6RJFR.js} +1 -39
  15. package/dist/cli.js +43080 -13150
  16. package/dist/dist-es-CRV46D5B.js +315 -0
  17. package/dist/dist-es-DCY4IC3Y.js +2000 -0
  18. package/dist/dist-es-ENBUC3JP.js +14726 -0
  19. package/dist/dist-es-G54LBMRN.js +48 -0
  20. package/dist/dist-es-G7PTG75M.js +176 -0
  21. package/dist/dist-es-GKDBE7E6.js +88 -0
  22. package/dist/dist-es-HY3535OI.js +70 -0
  23. package/dist/dist-es-KL7Y5NB2.js +377 -0
  24. package/dist/dist-es-LDE437AM.js +170 -0
  25. package/dist/dist-es-P26FWFLT.js +485 -0
  26. package/dist/dist-es-Q57SZXZ7.js +70 -0
  27. package/dist/dist-es-R7FGL2IB.js +88 -0
  28. package/dist/dist-es-USORBXZ5.js +318 -0
  29. package/dist/dist-es-ZKC2QKD2.js +377 -0
  30. package/dist/drizzle/0076_scheduled_jobs_marco_backfill.sql +2 -1
  31. package/dist/drizzle/0079_seed_tenant_customize_catalog.sql +1 -0
  32. package/dist/drizzle/0090_brain_schema_extraction.sql +10 -0
  33. package/dist/drizzle/0132_drop_computer_tables.sql +3 -0
  34. package/dist/drizzle/0160_compliance_event_types_plugins.sql +2 -0
  35. package/dist/drizzle/0214_think137_drop_judge_evidence_roi.sql +1 -0
  36. package/dist/drizzle/0216_drop_agent_loop_versions_goal_worker_policy.sql +1 -0
  37. package/dist/drizzle/0227_analyst_reader_role.sql +6 -0
  38. package/dist/drizzle/0230_analyst_rls.sql +9 -0
  39. package/dist/drizzle/0250_kg_schema_extraction.sql +27 -0
  40. package/dist/drizzle/0251_brain_stragglers.sql +21 -0
  41. package/dist/drizzle/0253_drop_brain_substrate.sql +2 -0
  42. package/dist/drizzle/0257_agents_runtime_allow_harness.sql +24 -0
  43. package/dist/drizzle/0261_managed_harness_multiplayer.sql +313 -0
  44. package/dist/drizzle/0261_native_auth_control_plane.sql +328 -0
  45. package/dist/drizzle/0262_auth_subscription_tickets.sql +59 -0
  46. package/dist/drizzle/0262_parallel_harness_threads.sql +9 -0
  47. package/dist/drizzle/0263_agentcore_runtime_identifier.sql +69 -0
  48. package/dist/drizzle/0263_drop_workos_auth_runtime.sql +236 -0
  49. package/dist/drizzle/0264_auth_enrollment_attempt_limits.sql +15 -0
  50. package/dist/drizzle/0264_harness_tool_execution_ledger.sql +113 -0
  51. package/dist/drizzle/0265_eval_runs_requester_identity.sql +28 -0
  52. package/dist/drizzle/0265_require_fully_valid_auth_publication.sql +27 -0
  53. package/dist/drizzle/0266_auth_identity_recovery_grants.sql +9 -0
  54. package/dist/drizzle/0266_eval_profiles_runtime_type.sql +12 -0
  55. package/dist/drizzle/0267_ontology_candidate_rejections.sql +53 -0
  56. package/dist/drizzle/0268_identity_crosswalk_routing.sql +182 -0
  57. package/dist/drizzle/0269_ontology_system_map.sql +31 -0
  58. package/dist/event-streams-7JNLJEEL.js +894 -0
  59. package/dist/event-streams-KDF5RWR6.js +1515 -0
  60. package/dist/loadSso-DJVB7BXE.js +576 -0
  61. package/dist/loadSso-JAMNA3WY.js +583 -0
  62. package/dist/plugins/catalog/package.json +1 -2
  63. package/dist/plugins/catalog/src/__tests__/build-catalog.test.ts +0 -1
  64. package/dist/plugins/catalog/src/__tests__/contracts.test.ts +0 -69
  65. package/dist/plugins/catalog/src/__tests__/plugin-package.test.ts +0 -2
  66. package/dist/plugins/catalog/src/__tests__/plugin-registry.test.ts +0 -5
  67. package/dist/plugins/catalog/src/contracts.ts +2 -179
  68. package/dist/plugins/catalog/src/registry/generated-first-party.ts +0 -6
  69. package/dist/signin-UGDWTGS4.js +821 -0
  70. package/dist/sso-oidc-Q4VXANXY.js +837 -0
  71. package/dist/sts-CWLSE3GH.js +1241 -0
  72. package/dist/sts-DNZLNVOV.js +1245 -0
  73. package/dist/terraform/examples/greenfield/main.tf +223 -66
  74. package/dist/terraform/examples/greenfield/terraform.tfvars.example +15 -1
  75. package/dist/terraform/modules/app/agentcore-gateway/main.tf +305 -0
  76. package/dist/terraform/modules/app/agentcore-gateway/outputs.tf +44 -0
  77. package/dist/terraform/modules/app/agentcore-gateway/scripts/delete_gateway.sh +93 -0
  78. package/dist/terraform/modules/app/agentcore-gateway/scripts/read_gateway.sh +33 -0
  79. package/dist/terraform/modules/app/agentcore-gateway/scripts/reconcile_gateway.sh +543 -0
  80. package/dist/terraform/modules/app/agentcore-gateway/variables.tf +70 -0
  81. package/dist/terraform/modules/app/agentcore-harness/main.tf +237 -8
  82. package/dist/terraform/modules/app/agentcore-harness/outputs.tf +63 -0
  83. package/dist/terraform/modules/app/agentcore-harness/scripts/delete_harness.sh +5 -0
  84. package/dist/terraform/modules/app/agentcore-harness/scripts/harness-lifecycle.mjs +430 -0
  85. package/dist/terraform/modules/app/agentcore-harness/scripts/harness-readback.mjs +180 -0
  86. package/dist/terraform/modules/app/agentcore-harness/scripts/harness-tool-contract.mjs +193 -0
  87. package/dist/terraform/modules/app/agentcore-harness/scripts/prune_harness.sh +5 -0
  88. package/dist/terraform/modules/app/agentcore-harness/scripts/read_harness.sh +5 -0
  89. package/dist/terraform/modules/app/agentcore-harness/scripts/reconcile_harness.sh +5 -0
  90. package/dist/terraform/modules/app/agentcore-harness/variables.tf +72 -1
  91. package/dist/terraform/modules/app/agentcore-identity/main.tf +173 -0
  92. package/dist/terraform/modules/app/agentcore-identity/outputs.tf +51 -0
  93. package/dist/terraform/modules/app/agentcore-identity/scripts/bootstrap_twenty_oauth_client.sh +122 -0
  94. package/dist/terraform/modules/app/agentcore-identity/scripts/delete_identity.sh +25 -0
  95. package/dist/terraform/modules/app/agentcore-identity/scripts/delete_twenty_identity.sh +16 -0
  96. package/dist/terraform/modules/app/agentcore-identity/scripts/read_identity.sh +40 -0
  97. package/dist/terraform/modules/app/agentcore-identity/scripts/reconcile_identity.sh +73 -0
  98. package/dist/terraform/modules/app/agentcore-identity/scripts/reconcile_twenty_identity.sh +74 -0
  99. package/dist/terraform/modules/app/agentcore-identity/scripts/reconcile_twenty_provider.mjs +61 -0
  100. package/dist/terraform/modules/app/agentcore-identity/variables.tf +54 -0
  101. package/dist/terraform/modules/app/appsync-subscriptions/main.tf +127 -21
  102. package/dist/terraform/modules/app/appsync-subscriptions/outputs.tf +0 -6
  103. package/dist/terraform/modules/app/appsync-subscriptions/variables.tf +5 -0
  104. package/dist/terraform/modules/app/deployment-control-plane/runner.py +966 -27
  105. package/dist/terraform/modules/app/deployment-control-plane/test_runner_bundle.py +581 -22
  106. package/dist/terraform/modules/app/lambda-api/agentcore-harness-alarms.tf +88 -0
  107. package/dist/terraform/modules/app/lambda-api/agentcore-identity-alarms.tf +91 -0
  108. package/dist/terraform/modules/app/lambda-api/handlers.tf +298 -74
  109. package/dist/terraform/modules/app/lambda-api/iam-grouped.tf +99 -54
  110. package/dist/terraform/modules/app/lambda-api/main.tf +24 -0
  111. package/dist/terraform/modules/app/lambda-api/mcp-oauth.tf +181 -4
  112. package/dist/terraform/modules/app/lambda-api/outputs.tf +35 -0
  113. package/dist/terraform/modules/app/lambda-api/runtime-config.tf +3 -21
  114. package/dist/terraform/modules/app/lambda-api/variables.tf +109 -16
  115. package/dist/terraform/modules/foundation/cognito/main.tf +294 -72
  116. package/dist/terraform/modules/foundation/cognito/outputs.tf +42 -0
  117. package/dist/terraform/modules/foundation/cognito/variables.tf +114 -4
  118. package/dist/terraform/modules/thinkwork/main.tf +269 -46
  119. package/dist/terraform/modules/thinkwork/outputs.tf +136 -8
  120. package/dist/terraform/modules/thinkwork/variables.tf +124 -17
  121. package/dist/terraform/schema.graphql +69 -36
  122. package/dist/workspace-defaults/files/USER.md +1 -0
  123. package/package.json +3 -2
  124. package/dist/drizzle/0261_thread_turns_origin_turn_index.sql +0 -11
  125. package/dist/plugins/workos-auth/package.json +0 -22
  126. package/dist/plugins/workos-auth/src/index.ts +0 -30
  127. package/dist/plugins/workos-auth/src/manifest.ts +0 -40
  128. package/dist/plugins/workos-auth/src/provider-contract.ts +0 -39
  129. package/dist/plugins/workos-auth/test/manifest.test.ts +0 -94
  130. package/dist/plugins/workos-auth/tsconfig.json +0 -8
@@ -32,3 +32,45 @@ output "identity_provider_names" {
32
32
  description = "Supported Cognito identity providers for created app clients."
33
33
  value = local.identity_providers
34
34
  }
35
+
36
+ output "auth_route_clients" {
37
+ description = "Safe app-client-to-route manifest. Contains no upstream provider secrets."
38
+ value = local.create ? {
39
+ for key, client in aws_cognito_user_pool_client.auth_route : key => {
40
+ client_id = client.id
41
+ route_key = local.auth_routes[key].route_key
42
+ client_family = local.auth_routes[key].client_family
43
+ provider_names = local.auth_routes[key].provider_names
44
+ explicit_auth_flows = local.auth_routes[key].explicit_auth_flows
45
+ callback_urls = distinct(local.auth_routes[key].callback_urls)
46
+ logout_urls = distinct(local.auth_routes[key].logout_urls)
47
+ lifecycle_state = "native"
48
+ }
49
+ } : var.existing_auth_route_clients
50
+ }
51
+
52
+ output "auth_retirement_phase" {
53
+ description = "Applied authentication retirement phase used for safe controller upgrades."
54
+ value = var.auth_retirement_phase
55
+ }
56
+
57
+ output "web_local_client_id" {
58
+ description = "Local-password-only Cognito app client for the web client family."
59
+ value = local.create ? aws_cognito_user_pool_client.auth_route["web:local"].id : try(
60
+ var.existing_auth_route_clients["web:local"].client_id,
61
+ null,
62
+ )
63
+ }
64
+
65
+ output "mobile_local_client_id" {
66
+ description = "Local-password-only Cognito app client for the mobile client family."
67
+ value = local.create ? aws_cognito_user_pool_client.auth_route["mobile:local"].id : try(
68
+ var.existing_auth_route_clients["mobile:local"].client_id,
69
+ null,
70
+ )
71
+ }
72
+
73
+ output "microsoft_identity_provider_name" {
74
+ description = "Default tenant-specific Microsoft Cognito provider name, or null when not configured."
75
+ value = var.microsoft_oauth_client_id != "" ? "MicrosoftOrganizations" : null
76
+ }
@@ -128,6 +128,51 @@ variable "google_oauth_client_secret" {
128
128
  default = ""
129
129
  }
130
130
 
131
+ variable "microsoft_oauth_client_id" {
132
+ description = "Microsoft Entra application client ID for the default tenant-specific OIDC route"
133
+ type = string
134
+ default = ""
135
+ }
136
+
137
+ variable "microsoft_oauth_client_secret" {
138
+ description = "Microsoft Entra application client secret for the default tenant-specific OIDC route"
139
+ type = string
140
+ sensitive = true
141
+ default = ""
142
+ }
143
+
144
+ variable "microsoft_oauth_tenant" {
145
+ description = "Microsoft Entra directory GUID used to build the exact OIDC issuer for the default Microsoft route"
146
+ type = string
147
+ default = ""
148
+
149
+ validation {
150
+ condition = var.microsoft_oauth_tenant == "" || can(regex("^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$", var.microsoft_oauth_tenant))
151
+ error_message = "microsoft_oauth_tenant must be an Entra directory GUID."
152
+ }
153
+ }
154
+
155
+ variable "tenant_entra_connections" {
156
+ description = "Safe metadata for tenant-specific Entra OIDC providers reconciled before Terraform creates their route clients. Contains no upstream secret values."
157
+ type = list(object({
158
+ connection_key = string
159
+ tenant_id = string
160
+ provider_name = string
161
+ display_name = string
162
+ }))
163
+ default = []
164
+
165
+ validation {
166
+ condition = alltrue([
167
+ for connection in var.tenant_entra_connections :
168
+ can(regex("^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$", connection.tenant_id)) &&
169
+ can(regex("^Entra_[a-f0-9]{16}_[a-f0-9]{8}$", connection.provider_name)) &&
170
+ connection.connection_key != "" && connection.display_name != ""
171
+ ])
172
+ error_message = "Every tenant Entra connection must use a GUID tenant_id, a deterministic Entra_<tenant>_<hash> provider name, and non-empty safe labels."
173
+ }
174
+ }
175
+
131
176
  variable "oidc_identity_providers" {
132
177
  description = "Additional Cognito OIDC identity providers. Secrets should be sourced from Secrets Manager/SSM by the caller, not committed to tfvars."
133
178
  type = list(object({
@@ -170,26 +215,55 @@ variable "pre_signup_lambda_zip" {
170
215
  default = ""
171
216
  }
172
217
 
218
+ variable "auth_retirement_phase" {
219
+ description = "Native-auth migration phase. Fresh deployments default to retired; coexistence/cutover are explicit upgrade-only rollback states."
220
+ type = string
221
+ default = "retired"
222
+
223
+ validation {
224
+ condition = contains(["coexistence", "cutover", "retired"], var.auth_retirement_phase)
225
+ error_message = "auth_retirement_phase must be coexistence, cutover, or retired."
226
+ }
227
+ }
228
+
173
229
  variable "custom_auth_lambda_zip" {
174
- description = "Path to the Cognito custom-auth challenge Lambda zip file"
230
+ description = "Local Cognito custom-auth rollback Lambda artifact used only before the retired phase."
175
231
  type = string
176
232
  default = ""
177
233
  }
178
234
 
179
235
  variable "custom_auth_lambda_s3_bucket" {
180
- description = "S3 bucket containing the Cognito custom-auth challenge Lambda release artifact"
236
+ description = "S3 bucket containing the Cognito custom-auth rollback Lambda artifact."
181
237
  type = string
182
238
  default = ""
183
239
  }
184
240
 
185
241
  variable "custom_auth_lambda_s3_key" {
186
- description = "S3 key for the Cognito custom-auth challenge Lambda release artifact"
242
+ description = "S3 key for the Cognito custom-auth rollback Lambda artifact."
243
+ type = string
244
+ default = ""
245
+ }
246
+
247
+ variable "pre_token_generation_lambda_s3_bucket" {
248
+ description = "S3 bucket containing the Cognito pre-token client-deny Lambda release artifact"
187
249
  type = string
188
250
  default = ""
189
251
  }
190
252
 
253
+ variable "pre_token_generation_lambda_s3_key" {
254
+ description = "S3 key for the Cognito pre-token client-deny Lambda release artifact"
255
+ type = string
256
+ default = ""
257
+ }
258
+
259
+ variable "denied_app_client_ids" {
260
+ description = "Cognito app clients denied new and refresh token issuance during auth cutover"
261
+ type = list(string)
262
+ default = []
263
+ }
264
+
191
265
  variable "api_auth_secret" {
192
- description = "Shared signing secret used by the custom-auth challenge Lambda"
266
+ description = "Shared signing secret used by the pre-retirement custom-auth rollback Lambda"
193
267
  type = string
194
268
  sensitive = true
195
269
  default = ""
@@ -205,6 +279,8 @@ variable "admin_callback_urls" {
205
279
  default = [
206
280
  "http://localhost:5174",
207
281
  "http://localhost:5174/auth/callback",
282
+ "http://127.0.0.1:5174",
283
+ "http://127.0.0.1:5174/auth/callback",
208
284
  "http://127.0.0.1:42010/callback",
209
285
  "http://localhost:42010/callback",
210
286
  ]
@@ -215,6 +291,7 @@ variable "admin_logout_urls" {
215
291
  type = list(string)
216
292
  default = [
217
293
  "http://localhost:5174",
294
+ "http://127.0.0.1:5174",
218
295
  ]
219
296
  }
220
297
 
@@ -228,6 +305,39 @@ variable "desktop_callback_urls" {
228
305
  ]
229
306
  }
230
307
 
308
+ variable "cli_callback_urls" {
309
+ description = "OAuth loopback callbacks reserved for the CLI client family."
310
+ type = list(string)
311
+ default = [
312
+ "http://127.0.0.1:42010/callback",
313
+ "http://localhost:42010/callback",
314
+ ]
315
+ }
316
+
317
+ variable "cli_logout_urls" {
318
+ description = "OAuth loopback logout destinations reserved for the CLI client family."
319
+ type = list(string)
320
+ default = [
321
+ "http://127.0.0.1:42010/callback",
322
+ "http://localhost:42010/callback",
323
+ ]
324
+ }
325
+
326
+ variable "existing_auth_route_clients" {
327
+ description = "Safe route-client manifest when using a BYO Cognito pool. Keys use <family>:<route>."
328
+ type = map(object({
329
+ client_id = string
330
+ route_key = string
331
+ client_family = string
332
+ provider_names = list(string)
333
+ explicit_auth_flows = list(string)
334
+ callback_urls = list(string)
335
+ logout_urls = list(string)
336
+ lifecycle_state = string
337
+ }))
338
+ default = {}
339
+ }
340
+
231
341
  variable "mobile_callback_urls" {
232
342
  description = "OAuth callback URLs for the mobile client. Host apps that embed the SDK register their own deep-link here. Proper per-host app client isolation is 0.3.0 work — this is the stopgap capture of the drift from the CLI-applied URIs."
233
343
  type = list(string)
@@ -736,30 +736,35 @@ module "cognito" {
736
736
  stage = var.stage
737
737
  region = var.region
738
738
 
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
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
+ existing_auth_route_clients = var.existing_auth_route_clients
746
+
747
+ google_oauth_client_id = var.google_oauth_client_id
748
+ google_oauth_client_secret = var.google_oauth_client_secret
749
+ microsoft_oauth_client_id = var.microsoft_oauth_client_id
750
+ microsoft_oauth_client_secret = var.microsoft_oauth_client_secret
751
+ microsoft_oauth_tenant = var.microsoft_oauth_tenant
752
+ tenant_entra_connections = var.tenant_entra_connections
753
+ oidc_identity_providers = var.oidc_identity_providers
754
+ saml_identity_providers = var.saml_identity_providers
755
+ pre_signup_lambda_zip = var.pre_signup_lambda_zip
756
+ auth_retirement_phase = var.auth_retirement_phase
757
+ custom_auth_lambda_zip = var.cognito_custom_auth_lambda_zip
758
+ custom_auth_lambda_s3_bucket = var.require_lambda_artifacts ? var.lambda_artifact_bucket : ""
759
+ custom_auth_lambda_s3_key = var.require_lambda_artifacts && var.lambda_artifact_bucket != "" ? "${trim(trimspace(var.lambda_artifact_prefix), "/")}/cognito-custom-auth.zip" : ""
760
+ api_auth_secret = var.api_auth_secret
761
+ pre_token_generation_lambda_s3_bucket = var.require_lambda_artifacts ? var.lambda_artifact_bucket : ""
762
+ 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" : ""
763
+ denied_app_client_ids = var.cognito_denied_app_client_ids
764
+ email_source_arn = var.cognito_email_source_arn
765
+ from_email_address = var.cognito_from_email_address
766
+ reply_to_email_address = var.cognito_reply_to_email_address
767
+ invite_email_subject = var.cognito_invite_email_subject
763
768
  invite_email_message = (
764
769
  var.cognito_invite_email_message != ""
765
770
  ? var.cognito_invite_email_message
@@ -790,8 +795,12 @@ module "cognito" {
790
795
  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
796
  local.customer_domain_web_enabled ? ["https://${var.customer_domain}", "https://${var.customer_domain}/auth/callback"] : [],
792
797
  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
798
+ [
799
+ "http://localhost:5180",
800
+ "http://localhost:5180/auth/callback",
801
+ "http://127.0.0.1:5180",
802
+ "http://127.0.0.1:5180/auth/callback",
803
+ ]
795
804
  ))
796
805
  admin_logout_urls = distinct(concat(
797
806
  var.admin_logout_urls,
@@ -799,10 +808,11 @@ module "cognito" {
799
808
  local.customer_domain_legacy_retired ? [] : (local.legacy_end_user_app_domain != "" ? ["https://${local.legacy_end_user_app_domain}"] : []),
800
809
  local.customer_domain_web_enabled ? ["https://${var.customer_domain}"] : [],
801
810
  local.customer_domain_legacy_retired ? [] : (var.computer_domain != "" ? ["https://${var.computer_domain}"] : []),
802
- ["http://localhost:5180"],
803
- var.desktop_callback_urls
811
+ ["http://localhost:5180", "http://127.0.0.1:5180"]
804
812
  ))
805
813
  desktop_callback_urls = var.desktop_callback_urls
814
+ cli_callback_urls = var.cli_callback_urls
815
+ cli_logout_urls = var.cli_logout_urls
806
816
  mobile_callback_urls = var.mobile_callback_urls
807
817
  mobile_logout_urls = var.mobile_logout_urls
808
818
  }
@@ -930,6 +940,7 @@ module "appsync" {
930
940
 
931
941
  stage = var.stage
932
942
  region = var.region
943
+ account_id = var.account_id
933
944
  user_pool_id = module.cognito.user_pool_id
934
945
  subscription_schema = local.subscription_schema
935
946
  }
@@ -978,6 +989,23 @@ resource "tls_private_key" "capability_signing" {
978
989
  algorithm = "ED25519"
979
990
  }
980
991
 
992
+ resource "random_password" "agentcore_proof_oauth_client_secret" {
993
+ count = var.enable_agentcore_multiplayer_proof ? 1 : 0
994
+ length = 48
995
+ special = false
996
+ }
997
+
998
+ check "agentcore_multiplayer_proof_requires_harness" {
999
+ assert {
1000
+ condition = !var.enable_agentcore_multiplayer_proof || (
1001
+ var.enable_agentcore_harness &&
1002
+ can(regex("^[a-z0-9][a-z0-9-]{0,47}$", var.agentcore_multiplayer_proof_tenant_slug)) &&
1003
+ length(distinct(compact([for owner in split(",", var.agentcore_multiplayer_proof_owner_allowlist) : trimspace(owner)]))) >= 2
1004
+ )
1005
+ error_message = "enable_agentcore_multiplayer_proof requires enable_agentcore_harness, an explicit lowercase tenant slug, and at least two explicit distinct proof owner subjects."
1006
+ }
1007
+ }
1008
+
981
1009
  resource "aws_secretsmanager_secret" "capability_signing_key" {
982
1010
  name = "thinkwork/${var.stage}/capability-signing-key"
983
1011
  description = "Ed25519 private key (PKCS8 PEM) signing capability sidecars and manifests (THINK-173)."
@@ -988,15 +1016,40 @@ resource "aws_secretsmanager_secret_version" "capability_signing_key" {
988
1016
  secret_string = tls_private_key.capability_signing.private_key_pem
989
1017
  }
990
1018
 
1019
+ # AppSync subscription tickets use a separate key and domain from capability
1020
+ # envelopes. The authorizer receives only the public key; ticket issuance
1021
+ # resolves the private key by secret name at runtime.
1022
+ resource "tls_private_key" "subscription_ticket_signing" {
1023
+ algorithm = "ED25519"
1024
+ }
1025
+
1026
+ resource "aws_secretsmanager_secret" "subscription_ticket_signing_key" {
1027
+ name = "thinkwork/${var.stage}/subscription-ticket-signing-key"
1028
+ description = "Ed25519 private key signing one-use AppSync subscription tickets."
1029
+ }
1030
+
1031
+ resource "aws_secretsmanager_secret_version" "subscription_ticket_signing_key" {
1032
+ secret_id = aws_secretsmanager_secret.subscription_ticket_signing_key.id
1033
+ secret_string = tls_private_key.subscription_ticket_signing.private_key_pem
1034
+ }
1035
+
991
1036
  module "api" {
992
1037
  source = "../app/lambda-api"
993
1038
 
994
1039
  capability_signing_public_key = tls_private_key.capability_signing.public_key_pem
995
1040
  capability_signing_private_key_secret = aws_secretsmanager_secret.capability_signing_key.name
1041
+ subscription_ticket_signing_key_id = "${var.stage}-subscription-v1"
1042
+ subscription_ticket_public_keys = jsonencode([{
1043
+ keyId = "${var.stage}-subscription-v1"
1044
+ publicKey = tls_private_key.subscription_ticket_signing.public_key_pem
1045
+ }])
1046
+ subscription_ticket_private_key_secret = aws_secretsmanager_secret.subscription_ticket_signing_key.name
996
1047
 
997
- stage = var.stage
998
- account_id = var.account_id
999
- region = var.region
1048
+ stage = var.stage
1049
+ account_id = var.account_id
1050
+ region = var.region
1051
+ auth_retirement_phase = var.auth_retirement_phase
1052
+ auth_migration_recovery_deadline = var.auth_migration_recovery_deadline
1000
1053
 
1001
1054
  lambda_artifact_bucket = var.lambda_artifact_bucket
1002
1055
  lambda_artifact_prefix = var.lambda_artifact_prefix
@@ -1055,9 +1108,20 @@ module "api" {
1055
1108
  # Governed autonomy — per-tenant self-extension opt-in allowlist (default off).
1056
1109
  capability_self_extension_tenants = var.capability_self_extension_tenants
1057
1110
 
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
1111
+ # THINK-316 U2request path receives only Harness invocation. Terraform
1112
+ # owns provisioning/version/endpoint control, avoiding a module cycle and
1113
+ # keeping PassRole/create/update/list out of chat Lambdas.
1114
+ enable_agentcore_harness_invocation = var.enable_agentcore_multiplayer_proof
1115
+
1116
+ # THINK-316 U1 — proof-only assertion/provider handlers remain absent unless
1117
+ # explicitly enabled. The generated secret stays in Terraform sensitive
1118
+ # state and is passed only to the two narrow boundary Lambdas and Identity.
1119
+ enable_agentcore_multiplayer_proof = var.enable_agentcore_multiplayer_proof
1120
+ agentcore_turn_assertion_key_versions = var.agentcore_turn_assertion_key_versions
1121
+ agentcore_turn_assertion_active_key_version = var.agentcore_turn_assertion_active_key_version
1122
+ agentcore_proof_oauth_client_id = "thinkwork-${var.stage}-agentcore-proof"
1123
+ agentcore_proof_oauth_client_secret = var.enable_agentcore_multiplayer_proof ? random_password.agentcore_proof_oauth_client_secret[0].result : ""
1124
+ agentcore_proof_owner_allowlist = var.agentcore_multiplayer_proof_owner_allowlist
1061
1125
 
1062
1126
  # Phase 3 U8b — KMS key + Object Lock mode forwarded as
1063
1127
  # COMPLIANCE_ANCHOR_KMS_KEY_ARN and COMPLIANCE_ANCHOR_OBJECT_LOCK_MODE
@@ -1088,8 +1152,8 @@ module "api" {
1088
1152
  mobile_client_id = module.cognito.mobile_client_id
1089
1153
  cognito_auth_domain = module.cognito.auth_domain
1090
1154
 
1155
+ appsync_api_id = module.appsync.graphql_api_id
1091
1156
  appsync_api_url = module.appsync.graphql_api_url
1092
- appsync_api_key = module.appsync.graphql_api_key
1093
1157
 
1094
1158
  kb_service_role_arn = module.bedrock_kb.kb_service_role_arn
1095
1159
 
@@ -1151,6 +1215,7 @@ module "api" {
1151
1215
  wiki_aggregation_pass_enabled = var.wiki_aggregation_pass_enabled
1152
1216
  wiki_source = var.wiki_source
1153
1217
  knowledge_graph_observations_ingest_enabled = var.knowledge_graph_observations_ingest_enabled
1218
+ ontology_scan_sweep_enabled = var.ontology_scan_sweep_enabled
1154
1219
  wiki_deterministic_linking_enabled = var.wiki_deterministic_linking_enabled
1155
1220
  google_places_api_key = var.google_places_api_key
1156
1221
  enable_workspace_orchestration = var.enable_workspace_orchestration
@@ -1160,8 +1225,6 @@ module "api" {
1160
1225
  requester_memory_dreaming_model_id = var.requester_memory_dreaming_model_id
1161
1226
  brain_dream_state_enabled = var.brain_dream_state_enabled
1162
1227
  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
1228
  # Per-user OAuth client credentials — fed to Secrets Manager in
1166
1229
  # app/lambda-api/oauth-secrets.tf. Reuses the same google_oauth_client_*
1167
1230
  # tfvars that already flow to the Cognito federated-signin module.
@@ -1251,18 +1314,178 @@ module "agentcore_pi" {
1251
1314
  okf_efs_read_access_point_arn = var.okf_wiki_efs_enabled ? aws_efs_access_point.okf_wiki_pi_read[0].arn : ""
1252
1315
  }
1253
1316
 
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.
1317
+ # AgentCore Harness execution role and managed tenant/profile runtime. The
1318
+ # public root inputs retain their rollout-era names until the example-stack
1319
+ # compatibility window closes; this module boundary uses managed semantics.
1258
1320
  module "agentcore_harness" {
1259
1321
  source = "../app/agentcore-harness"
1260
1322
 
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
1323
+ enabled = var.enable_agentcore_harness
1324
+ managed_runtime_enabled = var.enable_agentcore_multiplayer_proof
1325
+ stage = var.stage
1326
+ region = var.region
1327
+ account_id = var.account_id
1328
+ bucket_name = module.s3.bucket_name
1329
+ tenant_slug = var.agentcore_multiplayer_proof_tenant_slug
1330
+ discovery_url = "${module.api.agentcore_turn_assertion_issuer}/.well-known/openid-configuration"
1331
+ harness_audience = module.api.agentcore_harness_audience
1332
+ gateway_arn = module.agentcore_proof_gateway.gateway_arn
1333
+ oauth_credential_provider_arn = module.agentcore_proof_identity.credential_provider_arn
1334
+ oauth_credential_secret_arn = module.agentcore_proof_identity.credential_secret_arn
1335
+ oauth_return_url = module.agentcore_proof_identity.oauth_return_url
1336
+ }
1337
+
1338
+ # The Harness depends on the public issuer/API, so feeding its generated ARN
1339
+ # back into the api module would create a Terraform cycle. Publish the
1340
+ # non-secret, attested readiness contract under deterministic SSM keys; the
1341
+ # runner and DeploymentStatus resolver read it server-side. No browser token,
1342
+ # participant id, credential, prompt, or private result is stored here. Keep
1343
+ # the original address during the migration so deployed runners never lose
1344
+ # their profile between releases.
1345
+ locals {
1346
+ agentcore_harness_profile_value = jsonencode({
1347
+ tenantSlug = var.agentcore_multiplayer_proof_tenant_slug
1348
+ trustProfile = "default"
1349
+ harnessArn = module.agentcore_harness.managed_harness_arn
1350
+ endpointArn = module.agentcore_harness.managed_endpoint_arn
1351
+ endpointName = module.agentcore_harness.managed_endpoint_name
1352
+ expectedVersion = module.agentcore_harness.managed_target_version
1353
+ liveVersion = module.agentcore_harness.managed_live_version
1354
+ modelId = module.agentcore_harness.managed_model_id
1355
+ status = module.agentcore_harness.managed_status
1356
+ configurationFingerprint = module.agentcore_harness.managed_configuration_fingerprint
1357
+ authorizerAudience = module.api.agentcore_harness_audience
1358
+ sessionStrategy = "fresh"
1359
+ gatewayArn = module.agentcore_proof_gateway.gateway_arn
1360
+ gatewayUrl = module.agentcore_proof_gateway.gateway_url
1361
+ gatewayTargetName = module.agentcore_proof_gateway.target_name
1362
+ identityWorkloadName = module.agentcore_proof_identity.workload_identity_name
1363
+ identityCredentialProviderName = module.agentcore_proof_identity.credential_provider_name
1364
+ identityCredentialProviderArn = module.agentcore_proof_identity.credential_provider_arn
1365
+ invocationToolsContract = "control-plane-attested-full-override-v1"
1366
+ invocationToolsFingerprint = module.agentcore_harness.managed_invocation_tools_fingerprint
1367
+ invocationTools = jsondecode(module.agentcore_harness.managed_invocation_tools_json)
1368
+ strategyDecisionRule = "reuse_only_if_correct_and_20_percent_benefit"
1369
+ capacityEnvelope = {
1370
+ activeSessions = 100
1371
+ newSessionsPerSecond = 10
1372
+ minimumHeadroom = 0.50
1373
+ }
1374
+ })
1375
+ }
1376
+
1377
+ resource "aws_ssm_parameter" "agentcore_harness_proof_profile" {
1378
+ count = var.enable_agentcore_multiplayer_proof ? 1 : 0
1379
+
1380
+ name = "/thinkwork/${var.stage}/agentcore-harness-proof-profile"
1381
+ type = "String"
1382
+ # The exact immutable Harness tool schemas sit close to Standard's 4 KiB
1383
+ # ceiling. Intelligent-Tiering stays Standard while possible and safely
1384
+ # promotes only when a legitimate governed schema requires more room.
1385
+ tier = "Intelligent-Tiering"
1386
+ value = local.agentcore_harness_profile_value
1387
+
1388
+ lifecycle {
1389
+ precondition {
1390
+ # Base64 expands every three UTF-8 bytes to four ASCII characters. A
1391
+ # conservative 10,920-character ceiling admits at most 8,190 bytes and
1392
+ # cannot cross SSM's 8 KiB Advanced parameter limit.
1393
+ condition = length(base64encode(local.agentcore_harness_profile_value)) <= 10920
1394
+ error_message = "The AgentCore Harness managed profile exceeds SSM's 8 KiB parameter limit."
1395
+ }
1396
+ }
1397
+
1398
+ tags = {
1399
+ Name = "thinkwork-${var.stage}-agentcore-harness-proof-profile"
1400
+ "thinkwork:proof" = "THINK-316"
1401
+ "thinkwork:tenant" = var.agentcore_multiplayer_proof_tenant_slug
1402
+ "thinkwork:profile" = "default"
1403
+ "thinkwork:visibility" = "server-only-nonsecret"
1404
+ }
1405
+ }
1406
+
1407
+ # Managed per-tenant profile address. Runtime lookup reads this first and only
1408
+ # falls back to the original single-tenant key during the migration window.
1409
+ # Adding the scoped key is non-destructive and lets later tenants receive their
1410
+ # own attested profile without changing Lambda configuration or hot-path
1411
+ # control-plane resources.
1412
+ resource "aws_ssm_parameter" "agentcore_harness_profile" {
1413
+ count = var.enable_agentcore_multiplayer_proof ? 1 : 0
1414
+
1415
+ name = "/thinkwork/${var.stage}/agentcore-harness-profiles/${var.agentcore_multiplayer_proof_tenant_slug}"
1416
+ type = aws_ssm_parameter.agentcore_harness_proof_profile[0].type
1417
+ tier = "Intelligent-Tiering"
1418
+ value = aws_ssm_parameter.agentcore_harness_proof_profile[0].value
1419
+
1420
+ tags = {
1421
+ Name = "thinkwork-${var.stage}-agentcore-harness-profile-${var.agentcore_multiplayer_proof_tenant_slug}"
1422
+ "thinkwork:managed-by" = "terraform"
1423
+ "thinkwork:tenant" = var.agentcore_multiplayer_proof_tenant_slug
1424
+ "thinkwork:profile" = "default"
1425
+ "thinkwork:visibility" = "server-only-nonsecret"
1426
+ }
1427
+ }
1428
+
1429
+ # Publish the new immutable endpoint/profile first, then reclaim older
1430
+ # endpoint versions. Retain the active endpoint plus exactly one prior endpoint
1431
+ # for guarded rollback; the dedicated Harness owns no unrelated endpoints.
1432
+ resource "terraform_data" "agentcore_harness_endpoint_retention" {
1433
+ count = var.enable_agentcore_multiplayer_proof ? 1 : 0
1434
+
1435
+ triggers_replace = {
1436
+ active_endpoint = module.agentcore_harness.managed_endpoint_name
1437
+ profile_digest = module.agentcore_harness.managed_configuration_fingerprint
1438
+ }
1439
+
1440
+ provisioner "local-exec" {
1441
+ command = "bash ${path.module}/../app/agentcore-harness/scripts/prune_harness.sh"
1442
+ environment = {
1443
+ AWS_REGION = var.region
1444
+ HARNESS_ID = module.agentcore_harness.managed_harness_id
1445
+ ACTIVE_ENDPOINT_NAME = module.agentcore_harness.managed_endpoint_name
1446
+ ENDPOINT_PREFIX = "ThinkworkProofV"
1447
+ LEGACY_ENDPOINT_NAME = "ThinkworkProof"
1448
+ }
1449
+ }
1450
+
1451
+ depends_on = [
1452
+ aws_ssm_parameter.agentcore_harness_proof_profile,
1453
+ aws_ssm_parameter.agentcore_harness_profile,
1454
+ ]
1455
+ }
1456
+
1457
+ # THINK-316 U1 proof-only Identity and Gateway plane. These resources use the
1458
+ # regional execute-api URL because the dev account rejects public Lambda
1459
+ # Function URLs and a custom domain may be unavailable in a fresh stage.
1460
+ module "agentcore_proof_identity" {
1461
+ source = "../app/agentcore-identity"
1462
+
1463
+ enabled = var.enable_agentcore_multiplayer_proof
1464
+ stage = var.stage
1465
+ region = var.region
1466
+ account_id = var.account_id
1467
+ oauth_issuer = module.api.agentcore_proof_oauth_issuer
1468
+ oauth_client_id = "thinkwork-${var.stage}-agentcore-proof"
1469
+ oauth_client_secret = var.enable_agentcore_multiplayer_proof ? random_password.agentcore_proof_oauth_client_secret[0].result : ""
1470
+ user_federation_return_urls = [
1471
+ "${module.api.api_endpoint}/api/skills/mcp-oauth/agentcore/complete",
1472
+ ]
1473
+ }
1474
+
1475
+ module "agentcore_proof_gateway" {
1476
+ source = "../app/agentcore-gateway"
1477
+
1478
+ enabled = var.enable_agentcore_multiplayer_proof
1479
+ stage = var.stage
1480
+ region = var.region
1481
+ account_id = var.account_id
1482
+ discovery_url = "${module.api.agentcore_turn_assertion_issuer}/.well-known/openid-configuration"
1483
+ gateway_audience = module.api.agentcore_gateway_audience
1484
+ target_base_url = module.api.agentcore_proof_target_base_url
1485
+ oauth_credential_provider_arn = module.agentcore_proof_identity.credential_provider_arn
1486
+ oauth_credential_secret_arn = module.agentcore_proof_identity.credential_secret_arn
1487
+ oauth_return_url = module.agentcore_proof_identity.oauth_return_url
1488
+ proof_owner_allowlist = var.agentcore_multiplayer_proof_owner_allowlist
1266
1489
  }
1267
1490
 
1268
1491
  # Capability Broker (THINK-280 U3) — ship-inert, gated by