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
@@ -0,0 +1,305 @@
1
+ ################################################################################
2
+ # THINK-316 U1 — AgentCore Gateway + Cedar proof boundary
3
+ #
4
+ # AgentCore Gateway and Policy do not yet have complete Terraform resources.
5
+ # The module therefore owns their lifecycle with idempotent AWS CLI scripts,
6
+ # matching the repo's existing AgentCore Memory pattern. All resources are
7
+ # proof-only and opt in; destroy removes policy -> target -> gateway -> engine.
8
+ ################################################################################
9
+
10
+ terraform {
11
+ required_providers {
12
+ external = {
13
+ source = "hashicorp/external"
14
+ version = ">= 2.3.0"
15
+ }
16
+ }
17
+ }
18
+
19
+ locals {
20
+ gateway_name = "thinkwork-${var.stage}-multiplayer-proof"
21
+ target_name = "Thinkwork${replace(title(replace(var.stage, "-", " ")), " ", "")}OwnerProof"
22
+ # Policy resources accept only letters, digits, and underscores and must
23
+ # begin with a letter. Gateway names have a separate, hyphen-friendly API.
24
+ policy_engine_name = "Thinkwork${replace(title(replace(var.stage, "-", " ")), " ", "")}MultiplayerProof"
25
+ policy_name = "Thinkwork${replace(title(replace(var.stage, "-", " ")), " ", "")}OwnerIsolation"
26
+ # The reconciler owns the Gateway target schemas and Cedar boundary. Hash
27
+ # the executable itself so contract-only edits cannot leave AWS stale.
28
+ reconciler_hash = filesha256("${path.module}/scripts/reconcile_gateway.sh")
29
+ configuration_hash = nonsensitive(sha256(jsonencode({
30
+ discovery_url = var.discovery_url
31
+ audience = var.gateway_audience
32
+ target_url = var.target_base_url
33
+ provider_arn = var.oauth_credential_provider_arn
34
+ secret_arn = var.oauth_credential_secret_arn
35
+ return_url = var.oauth_return_url
36
+ owners = var.proof_owner_allowlist
37
+ capability_contract = "mcp-list-call-sandbox-builtin-platform-v7-user-questions"
38
+ # URL-mode OAuth elicitation requires the 2025-11-25 protocol and cannot
39
+ # be added to an existing Gateway, so changing this contract must replace
40
+ # the script-owned Gateway lifecycle.
41
+ protocol_versions = ["2025-03-26", "2025-11-25"]
42
+ reconciler = local.reconciler_hash
43
+ })))
44
+ }
45
+
46
+ resource "aws_iam_role" "gateway_execution" {
47
+ count = var.enabled ? 1 : 0
48
+ name = "thinkwork-${var.stage}-agentcore-proof-gateway-role"
49
+
50
+ assume_role_policy = jsonencode({
51
+ Version = "2012-10-17"
52
+ Statement = [{
53
+ Sid = "AllowAgentCoreGateway"
54
+ Effect = "Allow"
55
+ Principal = { Service = "bedrock-agentcore.amazonaws.com" }
56
+ Action = "sts:AssumeRole"
57
+ Condition = {
58
+ StringEquals = { "aws:SourceAccount" = var.account_id }
59
+ ArnLike = { "aws:SourceArn" = "arn:aws:bedrock-agentcore:${var.region}:${var.account_id}:*" }
60
+ }
61
+ }]
62
+ })
63
+ }
64
+
65
+ resource "aws_iam_role_policy" "gateway_execution" {
66
+ count = var.enabled ? 1 : 0
67
+ name = "thinkwork-${var.stage}-agentcore-proof-gateway"
68
+ role = aws_iam_role.gateway_execution[0].id
69
+
70
+ # U1 bootstraps service-generated Gateway/Policy ids, so the dedicated
71
+ # proof role uses type-scoped wildcards for those two resource families.
72
+ # Identity and Secrets access are already scoped to exact returned ARNs;
73
+ # U9 replaces the bootstrap wildcards with the selected resource ids.
74
+ policy = jsonencode({
75
+ Version = "2012-10-17"
76
+ Statement = [
77
+ {
78
+ Sid = "PolicyEngineConfiguration"
79
+ Effect = "Allow"
80
+ Action = ["bedrock-agentcore:GetPolicyEngine"]
81
+ Resource = "arn:aws:bedrock-agentcore:${var.region}:${var.account_id}:policy-engine/*"
82
+ },
83
+ {
84
+ Sid = "PolicyAuthorization"
85
+ Effect = "Allow"
86
+ Action = [
87
+ "bedrock-agentcore:AuthorizeAction",
88
+ "bedrock-agentcore:PartiallyAuthorizeActions",
89
+ ]
90
+ Resource = [
91
+ "arn:aws:bedrock-agentcore:${var.region}:${var.account_id}:policy-engine/*",
92
+ "arn:aws:bedrock-agentcore:${var.region}:${var.account_id}:gateway/*",
93
+ ]
94
+ },
95
+ {
96
+ Sid = "GatewayWorkloadToken"
97
+ Effect = "Allow"
98
+ # A CUSTOM_JWT Gateway uses the JWT-specific exchange action at
99
+ # runtime even though the current outbound-auth guide shows only the
100
+ # generic workload-token action in its example role.
101
+ Action = [
102
+ "bedrock-agentcore:GetWorkloadAccessToken",
103
+ "bedrock-agentcore:GetWorkloadAccessTokenForJWT",
104
+ ]
105
+ Resource = [
106
+ "arn:aws:bedrock-agentcore:${var.region}:${var.account_id}:workload-identity-directory/default",
107
+ "arn:aws:bedrock-agentcore:${var.region}:${var.account_id}:workload-identity-directory/default/workload-identity/${local.gateway_name}-*",
108
+ ]
109
+ },
110
+ {
111
+ Sid = "ExactOauthCredential"
112
+ Effect = "Allow"
113
+ Action = ["bedrock-agentcore:GetResourceOauth2Token"]
114
+ # Identity evaluates the request against the directory, concrete
115
+ # Gateway-managed workload identity, token vault, and provider. All
116
+ # four resource families must be present for resource-scoped access.
117
+ Resource = [
118
+ "arn:aws:bedrock-agentcore:${var.region}:${var.account_id}:workload-identity-directory/default",
119
+ "arn:aws:bedrock-agentcore:${var.region}:${var.account_id}:workload-identity-directory/default/workload-identity/${local.gateway_name}-*",
120
+ "arn:aws:bedrock-agentcore:${var.region}:${var.account_id}:token-vault/default",
121
+ var.oauth_credential_provider_arn,
122
+ ]
123
+ },
124
+ {
125
+ Sid = "ExactOauthSecret"
126
+ Effect = "Allow"
127
+ Action = ["secretsmanager:GetSecretValue"]
128
+ Resource = var.oauth_credential_secret_arn
129
+ },
130
+ ]
131
+ })
132
+ }
133
+
134
+ # Keep the stable Gateway/target/policy identity separate from configuration
135
+ # reconciliation. A terraform_data replacement runs destroy provisioners, so
136
+ # coupling the configuration hash to this resource used to tear down the live
137
+ # Gateway before recreating it on every ordinary contract update.
138
+ moved {
139
+ from = terraform_data.gateway_lifecycle
140
+ to = terraform_data.gateway_identity
141
+ }
142
+
143
+ resource "terraform_data" "gateway_identity" {
144
+ count = var.enabled ? 1 : 0
145
+
146
+ input = {
147
+ region = var.region
148
+ gateway_name = local.gateway_name
149
+ target_name = local.target_name
150
+ policy_engine_name = local.policy_engine_name
151
+ policy_name = local.policy_name
152
+ }
153
+
154
+ # The moved predecessor stored the full configuration hash in
155
+ # triggers_replace. Ignore that retired state-only attribute during the
156
+ # one-time split so Terraform can move the live identity without running its
157
+ # destroy provisioner. The dedicated configuration resource below owns all
158
+ # subsequent reconciliation revisions.
159
+ lifecycle {
160
+ ignore_changes = [triggers_replace]
161
+ }
162
+
163
+ # A brand-new identity must exist before the external data source reads it.
164
+ # The configuration resource performs the same idempotent reconciliation a
165
+ # second time on initial creation, then becomes the sole revision trigger.
166
+ provisioner "local-exec" {
167
+ command = "bash ${path.module}/scripts/reconcile_gateway.sh"
168
+ environment = {
169
+ AWS_REGION = var.region
170
+ GATEWAY_NAME = local.gateway_name
171
+ GATEWAY_ROLE_ARN = aws_iam_role.gateway_execution[0].arn
172
+ GATEWAY_DISCOVERY_URL = var.discovery_url
173
+ GATEWAY_AUDIENCE = var.gateway_audience
174
+ TARGET_NAME = local.target_name
175
+ TARGET_BASE_URL = trimsuffix(var.target_base_url, "/")
176
+ OAUTH_CREDENTIAL_PROVIDER_ARN = var.oauth_credential_provider_arn
177
+ OAUTH_RETURN_URL = var.oauth_return_url
178
+ POLICY_ENGINE_NAME = local.policy_engine_name
179
+ POLICY_NAME = local.policy_name
180
+ PROOF_OWNER_ALLOWLIST = var.proof_owner_allowlist
181
+ }
182
+ }
183
+
184
+ provisioner "local-exec" {
185
+ when = destroy
186
+ command = "bash ${path.module}/scripts/delete_gateway.sh"
187
+ environment = {
188
+ AWS_REGION = self.input.region
189
+ GATEWAY_NAME = self.input.gateway_name
190
+ TARGET_NAME = self.input.target_name
191
+ POLICY_ENGINE_NAME = self.input.policy_engine_name
192
+ POLICY_NAME = self.input.policy_name
193
+ }
194
+ }
195
+
196
+ depends_on = [aws_iam_role_policy.gateway_execution]
197
+ }
198
+
199
+ # Configuration revisions reconcile the stable identity in place. This
200
+ # terraform_data instance intentionally has no destroy provisioner: replacing
201
+ # it is only a signal to rerun the idempotent reconciler, never permission to
202
+ # delete a Gateway, target, policy, or engine.
203
+ resource "terraform_data" "gateway_configuration" {
204
+ count = var.enabled ? 1 : 0
205
+
206
+ input = local.configuration_hash
207
+ triggers_replace = [local.configuration_hash]
208
+
209
+ provisioner "local-exec" {
210
+ command = "bash ${path.module}/scripts/reconcile_gateway.sh"
211
+ environment = {
212
+ AWS_REGION = var.region
213
+ GATEWAY_NAME = local.gateway_name
214
+ GATEWAY_ROLE_ARN = aws_iam_role.gateway_execution[0].arn
215
+ GATEWAY_DISCOVERY_URL = var.discovery_url
216
+ GATEWAY_AUDIENCE = var.gateway_audience
217
+ TARGET_NAME = local.target_name
218
+ TARGET_BASE_URL = trimsuffix(var.target_base_url, "/")
219
+ OAUTH_CREDENTIAL_PROVIDER_ARN = var.oauth_credential_provider_arn
220
+ OAUTH_RETURN_URL = var.oauth_return_url
221
+ POLICY_ENGINE_NAME = local.policy_engine_name
222
+ POLICY_NAME = local.policy_name
223
+ PROOF_OWNER_ALLOWLIST = var.proof_owner_allowlist
224
+ }
225
+ }
226
+
227
+ depends_on = [terraform_data.gateway_identity]
228
+ }
229
+
230
+ data "external" "gateway_state" {
231
+ count = var.enabled ? 1 : 0
232
+ # Identity creation reconciles the Gateway before this read. Do not depend
233
+ # on the revision signal: doing so defers this read on every config update,
234
+ # makes the stable Gateway id unknown during planning, and falsely forces
235
+ # all CloudWatch delivery resources to replace.
236
+ depends_on = [terraform_data.gateway_identity]
237
+ program = ["bash", "${path.module}/scripts/read_gateway.sh"]
238
+
239
+ query = {
240
+ region = var.region
241
+ gateway_name = local.gateway_name
242
+ target_name = local.target_name
243
+ policy_engine_name = local.policy_engine_name
244
+ policy_name = local.policy_name
245
+ }
246
+ }
247
+
248
+ ################################################################################
249
+ # Gateway audit evidence
250
+ #
251
+ # AgentCore does not create an application-log destination for Gateways by
252
+ # default. Policy decisions are enforced inside the managed Gateway, so the
253
+ # target Lambda cannot truthfully invent a Cedar decision id. Deliver the
254
+ # service-owned Gateway records instead; certification correlates those records
255
+ # with the target-side append-only ledger and the canonical turn.
256
+ ################################################################################
257
+
258
+ resource "aws_cloudwatch_log_group" "gateway_application" {
259
+ count = var.enabled ? 1 : 0
260
+ name = "/aws/vendedlogs/bedrock-agentcore/gateway/APPLICATION_LOGS/${data.external.gateway_state[0].result.gateway_id}"
261
+ retention_in_days = var.observability_retention_days
262
+
263
+ tags = {
264
+ Stage = var.stage
265
+ Purpose = "agentcore-gateway-policy-audit"
266
+ }
267
+ }
268
+
269
+ resource "aws_cloudwatch_log_delivery_source" "gateway_application" {
270
+ count = var.enabled ? 1 : 0
271
+ name = "thinkwork-${var.stage}-agentcore-gateway-application"
272
+ log_type = "APPLICATION_LOGS"
273
+ resource_arn = data.external.gateway_state[0].result.gateway_arn
274
+
275
+ tags = {
276
+ Stage = var.stage
277
+ Purpose = "agentcore-gateway-policy-audit"
278
+ }
279
+ }
280
+
281
+ resource "aws_cloudwatch_log_delivery_destination" "gateway_application" {
282
+ count = var.enabled ? 1 : 0
283
+ name = "thinkwork-${var.stage}-agentcore-gateway-cloudwatch"
284
+ output_format = "json"
285
+
286
+ delivery_destination_configuration {
287
+ destination_resource_arn = aws_cloudwatch_log_group.gateway_application[0].arn
288
+ }
289
+
290
+ tags = {
291
+ Stage = var.stage
292
+ Purpose = "agentcore-gateway-policy-audit"
293
+ }
294
+ }
295
+
296
+ resource "aws_cloudwatch_log_delivery" "gateway_application" {
297
+ count = var.enabled ? 1 : 0
298
+ delivery_source_name = aws_cloudwatch_log_delivery_source.gateway_application[0].name
299
+ delivery_destination_arn = aws_cloudwatch_log_delivery_destination.gateway_application[0].arn
300
+
301
+ tags = {
302
+ Stage = var.stage
303
+ Purpose = "agentcore-gateway-policy-audit"
304
+ }
305
+ }
@@ -0,0 +1,44 @@
1
+ output "gateway_id" {
2
+ description = "AgentCore Gateway id. Empty when disabled."
3
+ value = var.enabled ? data.external.gateway_state[0].result.gateway_id : ""
4
+ }
5
+
6
+ output "gateway_arn" {
7
+ description = "AgentCore Gateway ARN. Empty when disabled."
8
+ value = var.enabled ? data.external.gateway_state[0].result.gateway_arn : ""
9
+ }
10
+
11
+ output "gateway_url" {
12
+ description = "AgentCore Gateway MCP endpoint. Empty when disabled."
13
+ value = var.enabled ? data.external.gateway_state[0].result.gateway_url : ""
14
+ }
15
+
16
+ output "target_id" {
17
+ description = "Controlled OpenAPI target id. Empty when disabled."
18
+ value = var.enabled ? data.external.gateway_state[0].result.target_id : ""
19
+ }
20
+
21
+ output "target_name" {
22
+ description = "Controlled OpenAPI target name."
23
+ value = var.enabled ? local.target_name : ""
24
+ }
25
+
26
+ output "policy_engine_id" {
27
+ description = "Policy engine id. Empty when disabled."
28
+ value = var.enabled ? data.external.gateway_state[0].result.policy_engine_id : ""
29
+ }
30
+
31
+ output "policy_id" {
32
+ description = "Owner-isolation Cedar policy id. Empty when disabled."
33
+ value = var.enabled ? data.external.gateway_state[0].result.policy_id : ""
34
+ }
35
+
36
+ output "execution_role_arn" {
37
+ description = "Dedicated proof Gateway execution role ARN. Empty when disabled."
38
+ value = var.enabled ? aws_iam_role.gateway_execution[0].arn : ""
39
+ }
40
+
41
+ output "application_log_group_name" {
42
+ description = "CloudWatch log group receiving AgentCore Gateway application and policy records."
43
+ value = var.enabled ? aws_cloudwatch_log_group.gateway_application[0].name : ""
44
+ }
@@ -0,0 +1,93 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ : "${AWS_REGION:?AWS_REGION is required}"
5
+ : "${GATEWAY_NAME:?GATEWAY_NAME is required}"
6
+ : "${TARGET_NAME:?TARGET_NAME is required}"
7
+ : "${POLICY_ENGINE_NAME:?POLICY_ENGINE_NAME is required}"
8
+ : "${POLICY_NAME:?POLICY_NAME is required}"
9
+
10
+ delete_error_file="$(mktemp)"
11
+ trap 'rm -f "$delete_error_file"' EXIT
12
+
13
+ is_not_found() {
14
+ grep -Eqi 'ResourceNotFoundException|not[ -]?found|does not exist' "$delete_error_file"
15
+ }
16
+
17
+ delete_or_absent() {
18
+ : >"$delete_error_file"
19
+ if "$@" >/dev/null 2>"$delete_error_file"; then
20
+ return 0
21
+ fi
22
+ if is_not_found; then
23
+ return 0
24
+ fi
25
+ printf 'AgentCore delete failed: %s\n' "$(<"$delete_error_file")" >&2
26
+ return 1
27
+ }
28
+
29
+ wait_absent() {
30
+ local label="$1"
31
+ shift
32
+ for _ in $(seq 1 90); do
33
+ : >"$delete_error_file"
34
+ if "$@" >/dev/null 2>"$delete_error_file"; then
35
+ sleep 2
36
+ continue
37
+ fi
38
+ if is_not_found; then
39
+ return 0
40
+ fi
41
+ sleep 2
42
+ done
43
+ : >"$delete_error_file"
44
+ if "$@" >/dev/null 2>"$delete_error_file"; then
45
+ printf 'Timed out waiting for %s deletion.\n' "$label" >&2
46
+ return 1
47
+ fi
48
+ if is_not_found; then
49
+ return 0
50
+ fi
51
+ printf 'Unable to verify %s deletion: %s\n' "$label" "$(<"$delete_error_file")" >&2
52
+ return 1
53
+ }
54
+
55
+ gateway_json="$(aws bedrock-agentcore-control list-gateways --region "$AWS_REGION" --output json)"
56
+ gateway_id="$(jq -r --arg name "$GATEWAY_NAME" 'first((.items // .gateways // [])[] | select(.name == $name) | .gatewayId) // empty' <<<"$gateway_json")"
57
+ engine_json="$(aws bedrock-agentcore-control list-policy-engines --region "$AWS_REGION" --output json)"
58
+ engine_id="$(jq -r --arg name "$POLICY_ENGINE_NAME" 'first((.policyEngines // .items // [])[] | select(.name == $name) | .policyEngineId) // empty' <<<"$engine_json")"
59
+
60
+ if [[ -n "$engine_id" ]]; then
61
+ policy_json="$(aws bedrock-agentcore-control list-policies --region "$AWS_REGION" --policy-engine-id "$engine_id" --output json)"
62
+ policy_id="$(jq -r --arg name "$POLICY_NAME" 'first((.policies // .items // [])[] | select(.name == $name) | .policyId) // empty' <<<"$policy_json")"
63
+ if [[ -n "$policy_id" ]]; then
64
+ delete_or_absent aws bedrock-agentcore-control delete-policy --region "$AWS_REGION" \
65
+ --policy-engine-id "$engine_id" --policy-id "$policy_id"
66
+ wait_absent "policy $policy_id" aws bedrock-agentcore-control get-policy --region "$AWS_REGION" \
67
+ --policy-engine-id "$engine_id" --policy-id "$policy_id"
68
+ fi
69
+ fi
70
+
71
+ if [[ -n "$gateway_id" ]]; then
72
+ target_json="$(aws bedrock-agentcore-control list-gateway-targets --region "$AWS_REGION" --gateway-identifier "$gateway_id" --output json)"
73
+ target_id="$(jq -r --arg name "$TARGET_NAME" 'first((.items // .targets // [])[] | select(.name == $name) | .targetId) // empty' <<<"$target_json")"
74
+ if [[ -n "$target_id" ]]; then
75
+ delete_or_absent aws bedrock-agentcore-control delete-gateway-target --region "$AWS_REGION" \
76
+ --gateway-identifier "$gateway_id" --target-id "$target_id"
77
+ wait_absent "gateway target $target_id" aws bedrock-agentcore-control get-gateway-target --region "$AWS_REGION" \
78
+ --gateway-identifier "$gateway_id" --target-id "$target_id"
79
+ fi
80
+ delete_or_absent aws bedrock-agentcore-control delete-gateway --region "$AWS_REGION" \
81
+ --gateway-identifier "$gateway_id"
82
+ wait_absent "gateway $gateway_id" aws bedrock-agentcore-control get-gateway --region "$AWS_REGION" \
83
+ --gateway-identifier "$gateway_id"
84
+ fi
85
+
86
+ if [[ -n "$engine_id" ]]; then
87
+ delete_or_absent aws bedrock-agentcore-control delete-policy-engine --region "$AWS_REGION" \
88
+ --policy-engine-id "$engine_id"
89
+ wait_absent "policy engine $engine_id" aws bedrock-agentcore-control get-policy-engine --region "$AWS_REGION" \
90
+ --policy-engine-id "$engine_id"
91
+ fi
92
+
93
+ printf 'AgentCore Gateway proof resources deleted or absent.\n'
@@ -0,0 +1,33 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ input="$(cat)"
5
+ region="$(jq -r '.region // empty' <<<"$input")"
6
+ gateway_name="$(jq -r '.gateway_name // empty' <<<"$input")"
7
+ target_name="$(jq -r '.target_name // empty' <<<"$input")"
8
+ engine_name="$(jq -r '.policy_engine_name // empty' <<<"$input")"
9
+ policy_name="$(jq -r '.policy_name // empty' <<<"$input")"
10
+ [[ -n "$region" && -n "$gateway_name" && -n "$target_name" && -n "$engine_name" && -n "$policy_name" ]]
11
+
12
+ gateway_id="$(aws bedrock-agentcore-control list-gateways --region "$region" --output json \
13
+ | jq -r --arg name "$gateway_name" '(.items // .gateways // [])[] | select(.name == $name) | .gatewayId' | head -n 1)"
14
+ engine_id="$(aws bedrock-agentcore-control list-policy-engines --region "$region" --output json \
15
+ | jq -r --arg name "$engine_name" '(.policyEngines // .items // [])[] | select(.name == $name) | .policyEngineId' | head -n 1)"
16
+ [[ -n "$gateway_id" && -n "$engine_id" ]]
17
+
18
+ gateway="$(aws bedrock-agentcore-control get-gateway --region "$region" --gateway-identifier "$gateway_id" --output json)"
19
+ target_id="$(aws bedrock-agentcore-control list-gateway-targets --region "$region" --gateway-identifier "$gateway_id" --output json \
20
+ | jq -r --arg name "$target_name" '(.items // .targets // [])[] | select(.name == $name) | .targetId' | head -n 1)"
21
+ policy_id="$(aws bedrock-agentcore-control list-policies --region "$region" --policy-engine-id "$engine_id" --output json \
22
+ | jq -r --arg name "$policy_name" '(.policies // .items // [])[] | select(.name == $name) | .policyId' | head -n 1)"
23
+
24
+ jq -n \
25
+ --arg gateway_id "$gateway_id" \
26
+ --arg gateway_arn "$(jq -r '.gatewayArn // empty' <<<"$gateway")" \
27
+ --arg gateway_url "$(jq -r '.gatewayUrl // .url // empty' <<<"$gateway")" \
28
+ --arg target_id "$target_id" \
29
+ --arg policy_engine_id "$engine_id" \
30
+ --arg policy_id "$policy_id" \
31
+ 'if ($gateway_arn == "" or $gateway_url == "" or $target_id == "" or $policy_id == "")
32
+ then error("AgentCore Gateway readback omitted required identifiers")
33
+ else {$gateway_id, $gateway_arn, $gateway_url, $target_id, $policy_engine_id, $policy_id} end'