thinkwork-cli 0.13.0 → 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 (178) hide show
  1. package/dist/{api-client-JUBCQQDF.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-STY44FQO.js → chunk-Z2F6RJFR.js} +12 -18
  15. package/dist/cli.js +72564 -18884
  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 +106 -38
  38. package/dist/drizzle/0230_analyst_rls.sql +192 -66
  39. package/dist/drizzle/0232_memory_source_thin_ledger.sql +176 -0
  40. package/dist/drizzle/0232_message_source_event_id.sql +9 -0
  41. package/dist/drizzle/0233_msteams_install_and_links.sql +151 -0
  42. package/dist/drizzle/0233_workflow_memory_stage_tokens.sql +20 -0
  43. package/dist/drizzle/0234_memory_claim_lifecycle.sql +160 -0
  44. package/dist/drizzle/0235_workflow_token_execution_claim.sql +34 -0
  45. package/dist/drizzle/0236_memory_retraction_fencing.sql +50 -0
  46. package/dist/drizzle/0237_memory_claims_active_value_uidx.sql +172 -0
  47. package/dist/drizzle/0238_memory_erase_generation_fence.sql +97 -0
  48. package/dist/drizzle/0239_canonical_entity_identity.sql +257 -0
  49. package/dist/drizzle/0240_memory_personal_scope.sql +45 -0
  50. package/dist/drizzle/0241_knowledge_base_document_manifest.sql +67 -0
  51. package/dist/drizzle/0242_search_queries.sql +28 -0
  52. package/dist/drizzle/0243_section_sources_thread_refs.sql +12 -0
  53. package/dist/drizzle/0244_system_automations_and_memory_stage_overrides.sql +45 -0
  54. package/dist/drizzle/0245_wiki_page_render.sql +21 -0
  55. package/dist/drizzle/0246_automation_workflow_ownership.sql +30 -0
  56. package/dist/drizzle/0247_capability_runtime.sql +402 -0
  57. package/dist/drizzle/0248_capability_private_interpreter.sql +13 -0
  58. package/dist/drizzle/0249_capability_headless_execution_evidence.sql +40 -0
  59. package/dist/drizzle/0250_kg_schema_extraction.sql +576 -0
  60. package/dist/drizzle/0251_agents_json_render_ui.sql +25 -0
  61. package/dist/drizzle/0251_brain_stragglers.sql +263 -0
  62. package/dist/drizzle/0252_drop_kg_and_straggler_compat_views.sql +100 -0
  63. package/dist/drizzle/0253_drop_brain_substrate.sql +93 -0
  64. package/dist/drizzle/0254_capability_autonomous_admission.sql +29 -0
  65. package/dist/drizzle/0255_capability_autonomous_approval_mode.sql +16 -0
  66. package/dist/drizzle/0256_agent_profile_manifest_authority.sql +18 -0
  67. package/dist/drizzle/0257_agents_runtime_allow_harness.sql +24 -0
  68. package/dist/drizzle/0257_capability_approvals.sql +53 -0
  69. package/dist/drizzle/0258_pending_tool_approvals.sql +84 -0
  70. package/dist/drizzle/0259_tenant_capability_registry_trust.sql +19 -0
  71. package/dist/drizzle/0260_scheduled_jobs_run_as_user.sql +20 -0
  72. package/dist/drizzle/0261_managed_harness_multiplayer.sql +313 -0
  73. package/dist/drizzle/0261_native_auth_control_plane.sql +328 -0
  74. package/dist/drizzle/0262_auth_subscription_tickets.sql +59 -0
  75. package/dist/drizzle/0262_parallel_harness_threads.sql +9 -0
  76. package/dist/drizzle/0263_agentcore_runtime_identifier.sql +69 -0
  77. package/dist/drizzle/0263_drop_workos_auth_runtime.sql +236 -0
  78. package/dist/drizzle/0264_auth_enrollment_attempt_limits.sql +15 -0
  79. package/dist/drizzle/0264_harness_tool_execution_ledger.sql +113 -0
  80. package/dist/drizzle/0265_eval_runs_requester_identity.sql +28 -0
  81. package/dist/drizzle/0265_require_fully_valid_auth_publication.sql +27 -0
  82. package/dist/drizzle/0266_auth_identity_recovery_grants.sql +9 -0
  83. package/dist/drizzle/0266_eval_profiles_runtime_type.sql +12 -0
  84. package/dist/drizzle/0267_ontology_candidate_rejections.sql +53 -0
  85. package/dist/drizzle/0268_identity_crosswalk_routing.sql +182 -0
  86. package/dist/drizzle/0269_ontology_system_map.sql +31 -0
  87. package/dist/event-streams-7JNLJEEL.js +894 -0
  88. package/dist/event-streams-KDF5RWR6.js +1515 -0
  89. package/dist/loadSso-DJVB7BXE.js +576 -0
  90. package/dist/loadSso-JAMNA3WY.js +583 -0
  91. package/dist/plugins/catalog/package.json +1 -2
  92. package/dist/plugins/catalog/src/__tests__/build-catalog.test.ts +0 -1
  93. package/dist/plugins/catalog/src/__tests__/contracts.test.ts +0 -69
  94. package/dist/plugins/catalog/src/__tests__/plugin-package.test.ts +0 -2
  95. package/dist/plugins/catalog/src/__tests__/plugin-registry.test.ts +0 -5
  96. package/dist/plugins/catalog/src/contracts.ts +2 -179
  97. package/dist/plugins/catalog/src/registry/generated-first-party.ts +0 -6
  98. package/dist/signin-UGDWTGS4.js +821 -0
  99. package/dist/sso-oidc-Q4VXANXY.js +837 -0
  100. package/dist/sts-CWLSE3GH.js +1241 -0
  101. package/dist/sts-DNZLNVOV.js +1245 -0
  102. package/dist/terraform/examples/greenfield/main.tf +247 -50
  103. package/dist/terraform/examples/greenfield/terraform.tfvars.example +15 -1
  104. package/dist/terraform/modules/app/agentcore-admin/main.tf +341 -0
  105. package/dist/terraform/modules/app/agentcore-admin/outputs.tf +20 -0
  106. package/dist/terraform/modules/app/agentcore-code-interpreter/main.tf +61 -0
  107. package/dist/terraform/modules/app/agentcore-gateway/main.tf +305 -0
  108. package/dist/terraform/modules/app/agentcore-gateway/outputs.tf +44 -0
  109. package/dist/terraform/modules/app/agentcore-gateway/scripts/delete_gateway.sh +93 -0
  110. package/dist/terraform/modules/app/agentcore-gateway/scripts/read_gateway.sh +33 -0
  111. package/dist/terraform/modules/app/agentcore-gateway/scripts/reconcile_gateway.sh +543 -0
  112. package/dist/terraform/modules/app/agentcore-gateway/variables.tf +70 -0
  113. package/dist/terraform/modules/app/agentcore-harness/main.tf +330 -0
  114. package/dist/terraform/modules/app/agentcore-harness/outputs.tf +72 -0
  115. package/dist/terraform/modules/app/agentcore-harness/scripts/delete_harness.sh +5 -0
  116. package/dist/terraform/modules/app/agentcore-harness/scripts/harness-lifecycle.mjs +430 -0
  117. package/dist/terraform/modules/app/agentcore-harness/scripts/harness-readback.mjs +180 -0
  118. package/dist/terraform/modules/app/agentcore-harness/scripts/harness-tool-contract.mjs +193 -0
  119. package/dist/terraform/modules/app/agentcore-harness/scripts/prune_harness.sh +5 -0
  120. package/dist/terraform/modules/app/agentcore-harness/scripts/read_harness.sh +5 -0
  121. package/dist/terraform/modules/app/agentcore-harness/scripts/reconcile_harness.sh +5 -0
  122. package/dist/terraform/modules/app/agentcore-harness/variables.tf +96 -0
  123. package/dist/terraform/modules/app/agentcore-identity/main.tf +173 -0
  124. package/dist/terraform/modules/app/agentcore-identity/outputs.tf +51 -0
  125. package/dist/terraform/modules/app/agentcore-identity/scripts/bootstrap_twenty_oauth_client.sh +122 -0
  126. package/dist/terraform/modules/app/agentcore-identity/scripts/delete_identity.sh +25 -0
  127. package/dist/terraform/modules/app/agentcore-identity/scripts/delete_twenty_identity.sh +16 -0
  128. package/dist/terraform/modules/app/agentcore-identity/scripts/read_identity.sh +40 -0
  129. package/dist/terraform/modules/app/agentcore-identity/scripts/reconcile_identity.sh +73 -0
  130. package/dist/terraform/modules/app/agentcore-identity/scripts/reconcile_twenty_identity.sh +74 -0
  131. package/dist/terraform/modules/app/agentcore-identity/scripts/reconcile_twenty_provider.mjs +61 -0
  132. package/dist/terraform/modules/app/agentcore-identity/variables.tf +54 -0
  133. package/dist/terraform/modules/app/agentcore-pi/main.tf +7 -0
  134. package/dist/terraform/modules/app/appsync-subscriptions/main.tf +127 -21
  135. package/dist/terraform/modules/app/appsync-subscriptions/outputs.tf +0 -6
  136. package/dist/terraform/modules/app/appsync-subscriptions/variables.tf +5 -0
  137. package/dist/terraform/modules/app/capability-broker/main.tf +393 -0
  138. package/dist/terraform/modules/app/capability-broker/outputs.tf +54 -0
  139. package/dist/terraform/modules/app/capability-broker/variables.tf +98 -0
  140. package/dist/terraform/modules/app/deployment-control-plane/runner.py +1011 -31
  141. package/dist/terraform/modules/app/deployment-control-plane/test_runner_bundle.py +655 -2
  142. package/dist/terraform/modules/app/lambda-api/agentcore-harness-alarms.tf +88 -0
  143. package/dist/terraform/modules/app/lambda-api/agentcore-identity-alarms.tf +91 -0
  144. package/dist/terraform/modules/app/lambda-api/capability-search-alarms.tf +60 -0
  145. package/dist/terraform/modules/app/lambda-api/handlers.tf +606 -37
  146. package/dist/terraform/modules/app/lambda-api/iam-grouped.tf +192 -21
  147. package/dist/terraform/modules/app/lambda-api/main.tf +35 -0
  148. package/dist/terraform/modules/app/lambda-api/mcp-oauth.tf +181 -4
  149. package/dist/terraform/modules/app/lambda-api/memory-alarms.tf +92 -0
  150. package/dist/terraform/modules/app/lambda-api/msteams-app-secrets.tf +46 -0
  151. package/dist/terraform/modules/app/lambda-api/outputs.tf +35 -0
  152. package/dist/terraform/modules/app/lambda-api/runtime-config.tf +3 -21
  153. package/dist/terraform/modules/app/lambda-api/variables.tf +188 -3
  154. package/dist/terraform/modules/app/workflow-interpreter-stepfunctions/alarms.tf +47 -0
  155. package/dist/terraform/modules/app/workflow-interpreter-stepfunctions/main.tf +43 -2
  156. package/dist/terraform/modules/foundation/cognito/main.tf +319 -73
  157. package/dist/terraform/modules/foundation/cognito/outputs.tf +42 -0
  158. package/dist/terraform/modules/foundation/cognito/variables.tf +124 -2
  159. package/dist/terraform/modules/foundation/vpc/outputs.tf +5 -0
  160. package/dist/terraform/modules/thinkwork/main.tf +396 -26
  161. package/dist/terraform/modules/thinkwork/outputs.tf +188 -5
  162. package/dist/terraform/modules/thinkwork/variables.tf +154 -5
  163. package/dist/terraform/schema.graphql +69 -36
  164. package/dist/workspace-defaults/files/TOOLS.md +39 -0
  165. package/dist/workspace-defaults/files/USER.md +1 -0
  166. package/dist/workspace-defaults/files/agents/analyst/INSTRUCTIONS.md +18 -0
  167. package/dist/workspace-defaults/files/agents/coding/INSTRUCTIONS.md +11 -0
  168. package/dist/workspace-defaults/files/agents/research/INSTRUCTIONS.md +12 -0
  169. package/dist/workspace-defaults/files/agents/reviewer/INSTRUCTIONS.md +15 -0
  170. package/dist/workspace-defaults/files/skills/document-composer/SKILL.md +6 -2
  171. package/package.json +6 -3
  172. package/dist/plugins/workos-auth/package.json +0 -22
  173. package/dist/plugins/workos-auth/src/index.ts +0 -30
  174. package/dist/plugins/workos-auth/src/manifest.ts +0 -40
  175. package/dist/plugins/workos-auth/src/provider-contract.ts +0 -39
  176. package/dist/plugins/workos-auth/test/manifest.test.ts +0 -94
  177. package/dist/plugins/workos-auth/tsconfig.json +0 -8
  178. /package/dist/workspace-defaults/files/{AGENTS.md → INSTRUCTIONS.md} +0 -0
@@ -7,14 +7,23 @@
7
7
  ################################################################################
8
8
 
9
9
  locals {
10
- create = var.create_cognito
11
- create_pre_signup = local.create && var.pre_signup_lambda_zip != ""
12
- create_custom_auth = local.create && var.custom_auth_lambda_zip != ""
13
-
14
- user_pool_id = local.create ? aws_cognito_user_pool.main[0].id : var.existing_user_pool_id
15
- user_pool_arn = local.create ? aws_cognito_user_pool.main[0].arn : var.existing_user_pool_arn
16
- admin_client_id = local.create ? aws_cognito_user_pool_client.admin[0].id : var.existing_admin_client_id
17
- mobile_client_id = local.create ? aws_cognito_user_pool_client.mobile[0].id : var.existing_mobile_client_id
10
+ create = var.create_cognito
11
+ create_pre_signup = local.create && var.pre_signup_lambda_zip != ""
12
+ create_pre_token_generation = local.create && trimspace(var.pre_token_generation_lambda_s3_bucket) != "" && trimspace(var.pre_token_generation_lambda_s3_key) != ""
13
+ workos_rollback_enabled = var.auth_retirement_phase != "retired"
14
+ use_local_custom_auth_artifact = trimspace(var.custom_auth_lambda_zip) != ""
15
+ use_remote_custom_auth_artifact = trimspace(var.custom_auth_lambda_s3_bucket) != ""
16
+ custom_auth_artifact_count = (local.use_local_custom_auth_artifact ? 1 : 0) + (local.use_remote_custom_auth_artifact ? 1 : 0)
17
+ create_custom_auth = local.create && local.workos_rollback_enabled && local.custom_auth_artifact_count == 1
18
+
19
+ user_pool_id = local.create ? aws_cognito_user_pool.main[0].id : var.existing_user_pool_id
20
+ user_pool_arn = local.create ? aws_cognito_user_pool.main[0].arn : var.existing_user_pool_arn
21
+ admin_client_id = local.create ? (
22
+ local.workos_rollback_enabled ? aws_cognito_user_pool_client.admin[0].id : aws_cognito_user_pool_client.auth_route["web:local"].id
23
+ ) : var.existing_admin_client_id
24
+ mobile_client_id = local.create ? (
25
+ local.workos_rollback_enabled ? aws_cognito_user_pool_client.mobile[0].id : aws_cognito_user_pool_client.auth_route["mobile:local"].id
26
+ ) : var.existing_mobile_client_id
18
27
  identity_pool_id = local.create ? aws_cognito_identity_pool.main[0].id : var.existing_identity_pool_id
19
28
  oidc_identity_providers = {
20
29
  for provider in var.oidc_identity_providers : provider.provider_name => provider
@@ -22,6 +31,106 @@ locals {
22
31
  saml_identity_providers = {
23
32
  for provider in var.saml_identity_providers : provider.provider_name => provider
24
33
  }
34
+ auth_client_families = {
35
+ web = {
36
+ callback_urls = [for url in var.admin_callback_urls : url if !strcontains(url, ":42010/")]
37
+ logout_urls = var.admin_logout_urls
38
+ refresh_token_days = 30
39
+ }
40
+ mobile = {
41
+ callback_urls = var.mobile_callback_urls
42
+ logout_urls = var.mobile_logout_urls
43
+ refresh_token_days = 90
44
+ }
45
+ desktop = {
46
+ callback_urls = var.desktop_callback_urls
47
+ logout_urls = var.desktop_callback_urls
48
+ refresh_token_days = 30
49
+ }
50
+ cli = {
51
+ callback_urls = var.cli_callback_urls
52
+ logout_urls = var.cli_logout_urls
53
+ refresh_token_days = 30
54
+ }
55
+ }
56
+ static_auth_routes = merge(
57
+ {
58
+ for family, config in local.auth_client_families : "${family}:local" => {
59
+ route_key = "local"
60
+ client_family = family
61
+ provider_names = ["COGNITO"]
62
+ explicit_auth_flows = ["ALLOW_USER_PASSWORD_AUTH", "ALLOW_USER_SRP_AUTH", "ALLOW_REFRESH_TOKEN_AUTH"]
63
+ callback_urls = config.callback_urls
64
+ logout_urls = config.logout_urls
65
+ refresh_token_days = config.refresh_token_days
66
+ }
67
+ },
68
+ var.google_oauth_client_id != "" ? {
69
+ for family, config in local.auth_client_families : "${family}:google" => {
70
+ route_key = "google"
71
+ client_family = family
72
+ provider_names = ["Google"]
73
+ explicit_auth_flows = ["ALLOW_REFRESH_TOKEN_AUTH"]
74
+ callback_urls = config.callback_urls
75
+ logout_urls = config.logout_urls
76
+ refresh_token_days = config.refresh_token_days
77
+ }
78
+ } : {},
79
+ var.microsoft_oauth_client_id != "" ? {
80
+ for family, config in local.auth_client_families : "${family}:microsoft" => {
81
+ route_key = "microsoft"
82
+ client_family = family
83
+ provider_names = ["MicrosoftOrganizations"]
84
+ explicit_auth_flows = ["ALLOW_REFRESH_TOKEN_AUTH"]
85
+ callback_urls = config.callback_urls
86
+ logout_urls = config.logout_urls
87
+ refresh_token_days = config.refresh_token_days
88
+ }
89
+ } : {},
90
+ )
91
+ tenant_auth_routes = merge({}, [
92
+ for connection in var.tenant_entra_connections : {
93
+ for family, config in local.auth_client_families : "${family}:entra:${lower(connection.tenant_id)}" => {
94
+ route_key = "entra-${replace(lower(connection.tenant_id), "-", "")}"
95
+ client_family = family
96
+ provider_names = [connection.provider_name]
97
+ explicit_auth_flows = ["ALLOW_REFRESH_TOKEN_AUTH"]
98
+ callback_urls = config.callback_urls
99
+ logout_urls = config.logout_urls
100
+ refresh_token_days = config.refresh_token_days
101
+ }
102
+ }
103
+ ]...)
104
+ auth_routes = merge(local.static_auth_routes, local.tenant_auth_routes)
105
+ }
106
+
107
+ resource "terraform_data" "custom_auth_artifact_validation" {
108
+ input = {
109
+ phase = var.auth_retirement_phase
110
+ artifact_count = local.custom_auth_artifact_count
111
+ }
112
+
113
+ lifecycle {
114
+ precondition {
115
+ condition = local.custom_auth_artifact_count <= 1
116
+ error_message = "Set only one Cognito custom-auth Lambda artifact source: custom_auth_lambda_zip or custom_auth_lambda_s3_bucket/custom_auth_lambda_s3_key."
117
+ }
118
+
119
+ precondition {
120
+ condition = !local.use_remote_custom_auth_artifact || trimspace(var.custom_auth_lambda_s3_key) != ""
121
+ error_message = "custom_auth_lambda_s3_key must be set when custom_auth_lambda_s3_bucket is set."
122
+ }
123
+
124
+ precondition {
125
+ condition = !local.create_custom_auth || var.api_auth_secret != ""
126
+ error_message = "The WorkOS rollback custom-auth Lambda requires api_auth_secret until auth_retirement_phase is retired."
127
+ }
128
+
129
+ precondition {
130
+ condition = var.microsoft_oauth_client_id == "" || var.microsoft_oauth_tenant != ""
131
+ error_message = "microsoft_oauth_tenant is required when microsoft_oauth_client_id is configured because Cognito requires an exact tenant issuer."
132
+ }
133
+ }
25
134
  }
26
135
 
27
136
  data "aws_caller_identity" "current" {}
@@ -50,26 +159,6 @@ resource "aws_iam_role_policy_attachment" "pre_signup_basic" {
50
159
  policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
51
160
  }
52
161
 
53
- resource "aws_iam_role_policy" "pre_signup_cognito" {
54
- count = local.create_pre_signup ? 1 : 0
55
- name = "cognito-access"
56
- role = aws_iam_role.pre_signup[0].id
57
-
58
- policy = jsonencode({
59
- Version = "2012-10-17"
60
- Statement = [{
61
- Effect = "Allow"
62
- Action = [
63
- "cognito-idp:ListUsers",
64
- "cognito-idp:AdminLinkProviderForUser",
65
- "cognito-idp:AdminCreateUser",
66
- "cognito-idp:AdminSetUserPassword"
67
- ]
68
- Resource = aws_cognito_user_pool.main[0].arn
69
- }]
70
- })
71
- }
72
-
73
162
  resource "aws_lambda_function" "pre_signup" {
74
163
  count = local.create_pre_signup ? 1 : 0
75
164
  function_name = "thinkwork-${var.stage}-cognito-pre-signup"
@@ -92,12 +181,62 @@ resource "aws_lambda_permission" "cognito_pre_signup" {
92
181
  }
93
182
 
94
183
  ################################################################################
95
- # Custom Auth Challenge Lambda
184
+ # Pre Token Generation Client Cutoff Lambda
185
+ ################################################################################
186
+
187
+ resource "aws_iam_role" "pre_token_generation" {
188
+ count = local.create_pre_token_generation ? 1 : 0
189
+ name = "thinkwork-${var.stage}-cognito-pre-token-role"
190
+
191
+ assume_role_policy = jsonencode({
192
+ Version = "2012-10-17"
193
+ Statement = [{
194
+ Effect = "Allow"
195
+ Principal = { Service = "lambda.amazonaws.com" }
196
+ Action = "sts:AssumeRole"
197
+ }]
198
+ })
199
+ }
200
+
201
+ resource "aws_iam_role_policy_attachment" "pre_token_generation_basic" {
202
+ count = local.create_pre_token_generation ? 1 : 0
203
+ role = aws_iam_role.pre_token_generation[0].name
204
+ policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
205
+ }
206
+
207
+ resource "aws_lambda_function" "pre_token_generation" {
208
+ count = local.create_pre_token_generation ? 1 : 0
209
+ function_name = "thinkwork-${var.stage}-cognito-pre-token-client-deny"
210
+ s3_bucket = var.pre_token_generation_lambda_s3_bucket
211
+ s3_key = var.pre_token_generation_lambda_s3_key
212
+ handler = "index.handler"
213
+ runtime = "nodejs20.x"
214
+ timeout = 5
215
+ role = aws_iam_role.pre_token_generation[0].arn
216
+
217
+ environment {
218
+ variables = {
219
+ COGNITO_DENIED_APP_CLIENT_IDS = join(",", var.denied_app_client_ids)
220
+ }
221
+ }
222
+ }
223
+
224
+ resource "aws_lambda_permission" "cognito_pre_token_generation" {
225
+ count = local.create_pre_token_generation ? 1 : 0
226
+ statement_id = "AllowCognitoInvoke"
227
+ action = "lambda:InvokeFunction"
228
+ function_name = aws_lambda_function.pre_token_generation[0].function_name
229
+ principal = "cognito-idp.amazonaws.com"
230
+ source_arn = aws_cognito_user_pool.main[0].arn
231
+ }
232
+
233
+ ################################################################################
234
+ # Legacy WorkOS Custom Auth Challenge Lambda (rollback runtime only)
96
235
  ################################################################################
97
236
 
98
237
  resource "aws_iam_role" "custom_auth" {
99
238
  count = local.create_custom_auth ? 1 : 0
100
- name = "thinkwork-${var.stage}-cognito-custom-auth-role"
239
+ name = local.use_remote_custom_auth_artifact ? "thinkwork-${var.stage}-cognito-custom-auth-release-role" : "thinkwork-${var.stage}-cognito-custom-auth-role"
101
240
 
102
241
  assume_role_policy = jsonencode({
103
242
  Version = "2012-10-17"
@@ -117,8 +256,10 @@ resource "aws_iam_role_policy_attachment" "custom_auth_basic" {
117
256
 
118
257
  resource "aws_lambda_function" "custom_auth" {
119
258
  count = local.create_custom_auth ? 1 : 0
120
- function_name = "thinkwork-${var.stage}-cognito-custom-auth"
121
- filename = var.custom_auth_lambda_zip
259
+ function_name = local.use_remote_custom_auth_artifact ? "thinkwork-${var.stage}-cognito-custom-auth-release" : "thinkwork-${var.stage}-cognito-custom-auth"
260
+ filename = local.use_local_custom_auth_artifact ? var.custom_auth_lambda_zip : null
261
+ s3_bucket = local.use_remote_custom_auth_artifact ? var.custom_auth_lambda_s3_bucket : null
262
+ s3_key = local.use_remote_custom_auth_artifact ? var.custom_auth_lambda_s3_key : null
122
263
  handler = "index.handler"
123
264
  runtime = "nodejs20.x"
124
265
  timeout = 10
@@ -130,14 +271,7 @@ resource "aws_lambda_function" "custom_auth" {
130
271
  }
131
272
  }
132
273
 
133
- source_code_hash = filebase64sha256(var.custom_auth_lambda_zip)
134
-
135
- lifecycle {
136
- precondition {
137
- condition = var.api_auth_secret != ""
138
- error_message = "custom_auth_lambda_zip requires api_auth_secret so Cognito custom-auth challenges can be verified."
139
- }
140
- }
274
+ source_code_hash = local.use_local_custom_auth_artifact ? filebase64sha256(var.custom_auth_lambda_zip) : null
141
275
  }
142
276
 
143
277
  resource "aws_lambda_permission" "cognito_custom_auth" {
@@ -189,6 +323,30 @@ resource "aws_cognito_user_pool" "main" {
189
323
  }
190
324
  }
191
325
 
326
+ schema {
327
+ name = "entra_tenant_id"
328
+ attribute_data_type = "String"
329
+ required = false
330
+ mutable = true
331
+
332
+ string_attribute_constraints {
333
+ min_length = 0
334
+ max_length = 36
335
+ }
336
+ }
337
+
338
+ schema {
339
+ name = "entra_object_id"
340
+ attribute_data_type = "String"
341
+ required = false
342
+ mutable = true
343
+
344
+ string_attribute_constraints {
345
+ min_length = 0
346
+ max_length = 36
347
+ }
348
+ }
349
+
192
350
  schema {
193
351
  name = "tenant_id"
194
352
  attribute_data_type = "String"
@@ -218,12 +376,19 @@ resource "aws_cognito_user_pool" "main" {
218
376
  }
219
377
 
220
378
  dynamic "lambda_config" {
221
- for_each = local.create_pre_signup || local.create_custom_auth ? [1] : []
379
+ for_each = local.create_pre_signup || local.create_pre_token_generation || local.create_custom_auth ? [1] : []
222
380
  content {
223
381
  pre_sign_up = local.create_pre_signup ? aws_lambda_function.pre_signup[0].arn : null
224
382
  define_auth_challenge = local.create_custom_auth ? aws_lambda_function.custom_auth[0].arn : null
225
383
  create_auth_challenge = local.create_custom_auth ? aws_lambda_function.custom_auth[0].arn : null
226
384
  verify_auth_challenge_response = local.create_custom_auth ? aws_lambda_function.custom_auth[0].arn : null
385
+ dynamic "pre_token_generation_config" {
386
+ for_each = local.create_pre_token_generation ? [1] : []
387
+ content {
388
+ lambda_arn = aws_lambda_function.pre_token_generation[0].arn
389
+ lambda_version = "V2_0"
390
+ }
391
+ }
227
392
  }
228
393
  }
229
394
 
@@ -274,21 +439,108 @@ resource "aws_cognito_identity_provider" "google" {
274
439
  }
275
440
 
276
441
  attribute_mapping = {
277
- email = "email"
278
- name = "name"
279
- username = "sub"
442
+ email = "email"
443
+ email_verified = "email_verified"
444
+ name = "name"
445
+ username = "sub"
446
+ }
447
+ }
448
+
449
+ resource "aws_cognito_identity_provider" "microsoft_organizations" {
450
+ count = local.create && var.microsoft_oauth_client_id != "" ? 1 : 0
451
+ user_pool_id = aws_cognito_user_pool.main[0].id
452
+ provider_name = "MicrosoftOrganizations"
453
+ provider_type = "OIDC"
454
+
455
+ provider_details = {
456
+ client_id = var.microsoft_oauth_client_id
457
+ client_secret = var.microsoft_oauth_client_secret
458
+ authorize_scopes = "openid email profile"
459
+ oidc_issuer = "https://login.microsoftonline.com/${lower(var.microsoft_oauth_tenant)}/v2.0"
460
+ attributes_request_method = "GET"
461
+ }
462
+
463
+ attribute_mapping = {
464
+ # Entra v2 does not guarantee an `email` claim for every work/school
465
+ # account. `preferred_username` is the supported sign-in hint and keeps
466
+ # Cognito's required email attribute populated as a stable normalized
467
+ # correlation value. ThinkWork only consults it after
468
+ # Cognito validates this exact Entra route; ongoing admission uses the
469
+ # immutable Cognito issuer/subject binding created by that first login.
470
+ email = "preferred_username"
471
+ name = "name"
472
+ username = "sub"
473
+ "custom:entra_tenant_id" = "tid"
474
+ "custom:entra_object_id" = "oid"
280
475
  }
281
476
  }
282
477
 
283
478
  locals {
284
479
  identity_providers = concat(
285
480
  var.google_oauth_client_id != "" ? ["Google"] : [],
481
+ var.microsoft_oauth_client_id != "" ? ["MicrosoftOrganizations"] : [],
286
482
  keys(local.oidc_identity_providers),
287
483
  keys(local.saml_identity_providers),
288
484
  ["COGNITO"]
289
485
  )
290
486
  }
291
487
 
488
+ ################################################################################
489
+ # Route-specific public app clients
490
+ ################################################################################
491
+
492
+ resource "aws_cognito_user_pool_client" "auth_route" {
493
+ for_each = local.create ? local.auth_routes : {}
494
+
495
+ name = "Thinkwork-${title(each.value.client_family)}-${title(each.value.route_key)}"
496
+ user_pool_id = aws_cognito_user_pool.main[0].id
497
+
498
+ generate_secret = false
499
+ allowed_oauth_flows_user_pool_client = true
500
+ allowed_oauth_flows = ["code"]
501
+ allowed_oauth_scopes = ["openid", "email", "profile"]
502
+ explicit_auth_flows = each.value.explicit_auth_flows
503
+ supported_identity_providers = each.value.provider_names
504
+ callback_urls = distinct(each.value.callback_urls)
505
+ logout_urls = distinct(each.value.logout_urls)
506
+ enable_token_revocation = true
507
+ prevent_user_existence_errors = "ENABLED"
508
+ access_token_validity = 1
509
+ id_token_validity = 1
510
+ refresh_token_validity = each.value.refresh_token_days
511
+
512
+ token_validity_units {
513
+ access_token = "hours"
514
+ id_token = "hours"
515
+ refresh_token = "days"
516
+ }
517
+
518
+ read_attributes = [
519
+ "email",
520
+ "email_verified",
521
+ "name",
522
+ "custom:tenant_id",
523
+ "custom:entra_tenant_id",
524
+ "custom:entra_object_id",
525
+ ]
526
+
527
+ write_attributes = [
528
+ "email",
529
+ "email_verified",
530
+ "name",
531
+ "custom:tenant_id",
532
+ "custom:entra_tenant_id",
533
+ "custom:entra_object_id",
534
+ ]
535
+
536
+ depends_on = [
537
+ aws_cognito_identity_provider.google,
538
+ aws_cognito_identity_provider.microsoft_organizations,
539
+ aws_cognito_identity_provider.oidc,
540
+ aws_cognito_identity_provider.saml,
541
+ ]
542
+ }
543
+
292
544
  resource "aws_cognito_identity_provider" "oidc" {
293
545
  for_each = local.create ? local.oidc_identity_providers : {}
294
546
 
@@ -339,8 +591,8 @@ resource "aws_cognito_identity_provider" "saml" {
339
591
  ################################################################################
340
592
 
341
593
  resource "aws_cognito_user_pool_client" "admin" {
342
- count = local.create ? 1 : 0
343
- name = "ThinkworkAdmin"
594
+ count = local.create && local.workos_rollback_enabled ? 1 : 0
595
+ name = "ThinkworkAdminLegacy"
344
596
  user_pool_id = aws_cognito_user_pool.main[0].id
345
597
 
346
598
  allowed_oauth_flows_user_pool_client = true
@@ -356,8 +608,8 @@ resource "aws_cognito_user_pool_client" "admin" {
356
608
 
357
609
  supported_identity_providers = local.identity_providers
358
610
 
359
- callback_urls = distinct(concat(var.admin_callback_urls, var.desktop_callback_urls))
360
- logout_urls = distinct(concat(var.admin_logout_urls, var.desktop_callback_urls))
611
+ callback_urls = distinct(concat(var.admin_callback_urls, var.desktop_callback_urls, var.cli_callback_urls))
612
+ logout_urls = distinct(concat(var.admin_logout_urls, var.desktop_callback_urls, var.cli_logout_urls))
361
613
 
362
614
  access_token_validity = 1
363
615
  id_token_validity = 1
@@ -394,8 +646,8 @@ resource "aws_cognito_user_pool_client" "admin" {
394
646
  ################################################################################
395
647
 
396
648
  resource "aws_cognito_user_pool_client" "mobile" {
397
- count = local.create ? 1 : 0
398
- name = "ThinkworkMobile"
649
+ count = local.create && local.workos_rollback_enabled ? 1 : 0
650
+ name = "ThinkworkMobileLegacy"
399
651
  user_pool_id = aws_cognito_user_pool.main[0].id
400
652
 
401
653
  explicit_auth_flows = [
@@ -453,16 +705,25 @@ resource "aws_cognito_identity_pool" "main" {
453
705
  identity_pool_name = var.identity_pool_name != "" ? var.identity_pool_name : "thinkwork-${var.stage}-identity-pool"
454
706
  allow_unauthenticated_identities = false
455
707
 
456
- cognito_identity_providers {
457
- client_id = aws_cognito_user_pool_client.admin[0].id
458
- provider_name = "cognito-idp.${var.region}.amazonaws.com/${aws_cognito_user_pool.main[0].id}"
459
- server_side_token_check = false
708
+ dynamic "cognito_identity_providers" {
709
+ for_each = local.workos_rollback_enabled ? {
710
+ admin = aws_cognito_user_pool_client.admin[0].id
711
+ mobile = aws_cognito_user_pool_client.mobile[0].id
712
+ } : {}
713
+ content {
714
+ client_id = cognito_identity_providers.value
715
+ provider_name = "cognito-idp.${var.region}.amazonaws.com/${aws_cognito_user_pool.main[0].id}"
716
+ server_side_token_check = false
717
+ }
460
718
  }
461
719
 
462
- cognito_identity_providers {
463
- client_id = aws_cognito_user_pool_client.mobile[0].id
464
- provider_name = "cognito-idp.${var.region}.amazonaws.com/${aws_cognito_user_pool.main[0].id}"
465
- server_side_token_check = false
720
+ dynamic "cognito_identity_providers" {
721
+ for_each = aws_cognito_user_pool_client.auth_route
722
+ content {
723
+ client_id = cognito_identity_providers.value.id
724
+ provider_name = "cognito-idp.${var.region}.amazonaws.com/${aws_cognito_user_pool.main[0].id}"
725
+ server_side_token_check = true
726
+ }
466
727
  }
467
728
 
468
729
  tags = {
@@ -496,21 +757,6 @@ resource "aws_iam_role" "authenticated" {
496
757
  })
497
758
  }
498
759
 
499
- resource "aws_iam_role_policy" "authenticated_appsync" {
500
- count = local.create ? 1 : 0
501
- name = "appsync-access"
502
- role = aws_iam_role.authenticated[0].id
503
-
504
- policy = jsonencode({
505
- Version = "2012-10-17"
506
- Statement = [{
507
- Effect = "Allow"
508
- Action = "appsync:GraphQL"
509
- Resource = "*"
510
- }]
511
- })
512
- }
513
-
514
760
  resource "aws_cognito_identity_pool_roles_attachment" "main" {
515
761
  count = local.create ? 1 : 0
516
762
  identity_pool_id = aws_cognito_identity_pool.main[0].id
@@ -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
+ }