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,341 @@
1
+ ################################################################################
2
+ # AgentCore Admin — App Module (stage-level)
3
+ #
4
+ # The `agentcore-admin` Lambda is the control-plane worker that regular sandbox
5
+ # provisioning depends on: `createTenant` (packages/api) RequestResponse-invokes
6
+ # it to create per-tenant IAM roles + AgentCore Code Interpreters, and it also
7
+ # serves SSM permission-profile CRUD + CloudWatch audit queries. The handler
8
+ # lives at packages/lambda/agentcore-admin.ts and is bundled by
9
+ # scripts/build-lambdas.sh into dist/lambdas/agentcore-admin.zip.
10
+ #
11
+ # Historically this Lambda was built but instantiated NOWHERE — so sandbox
12
+ # provisioning would fail closed at runtime (AGENTCORE_ADMIN_LAMBDA_ARN unset).
13
+ # This module deploys it. It is intentionally a SEPARATE module with a DEDICATED
14
+ # least-privilege role: the handler holds a dangerous control-plane surface
15
+ # (iam:CreateRole, bedrock-agentcore CreateCodeInterpreter) that must never leak
16
+ # onto the ~90-handler shared lambda-api role.
17
+ #
18
+ # THINK-280 capability-private wiring: CAPABILITY_PRIVATE_SUBNET_IDS /
19
+ # CAPABILITY_PRIVATE_SECURITY_GROUP_IDS come from the capability-broker outputs
20
+ # (via the agentcore-code-interpreter module). Both are EMPTY when the broker is
21
+ # disabled (var.enable_capability_broker=false, the default) — the handler then
22
+ # skips capability-private provisioning entirely (capabilityPrivateProvisioning
23
+ # Enabled() returns false). The module therefore ships INERT for the
24
+ # capability-private path while still fixing the regular-provisioning gap.
25
+ ################################################################################
26
+
27
+ terraform {
28
+ required_providers {
29
+ aws = {
30
+ source = "hashicorp/aws"
31
+ version = ">= 5.0"
32
+ }
33
+ random = {
34
+ source = "hashicorp/random"
35
+ version = ">= 3.0"
36
+ }
37
+ }
38
+ }
39
+
40
+ variable "stage" {
41
+ description = "Deployment stage (dev, prod, etc.)."
42
+ type = string
43
+ }
44
+
45
+ variable "region" {
46
+ description = "AWS region."
47
+ type = string
48
+ }
49
+
50
+ variable "account_id" {
51
+ description = "AWS account ID (used to construct IAM resource ARNs)."
52
+ type = string
53
+ }
54
+
55
+ # ---- Lambda artifact sources (mirror lambda-api/remote-artifacts.tf) ----------
56
+ variable "lambda_zips_dir" {
57
+ description = "Local directory of built Lambda zips (source-checkout deploys). Mutually exclusive with lambda_artifact_bucket."
58
+ type = string
59
+ default = ""
60
+ }
61
+
62
+ variable "lambda_artifact_bucket" {
63
+ description = "S3 bucket holding release Lambda zips (enterprise deploys). Mutually exclusive with lambda_zips_dir."
64
+ type = string
65
+ default = ""
66
+ }
67
+
68
+ variable "lambda_artifact_prefix" {
69
+ description = "S3 key prefix for release Lambda zips."
70
+ type = string
71
+ default = ""
72
+ }
73
+
74
+ # ---- Database (handler reads the tenants table via getDb() → DATABASE_URL) -----
75
+ variable "db_username" {
76
+ description = "Database username (used to construct DATABASE_URL)."
77
+ type = string
78
+ default = "thinkwork_admin"
79
+ }
80
+
81
+ variable "db_password" {
82
+ description = "Database password (used to construct DATABASE_URL)."
83
+ type = string
84
+ sensitive = true
85
+ default = ""
86
+ }
87
+
88
+ variable "db_cluster_endpoint" {
89
+ description = "Aurora cluster writer endpoint."
90
+ type = string
91
+ }
92
+
93
+ variable "database_name" {
94
+ description = "Database name."
95
+ type = string
96
+ }
97
+
98
+ variable "graphql_db_secret_arn" {
99
+ description = "ARN of the writer DB credentials secret (granted GetSecretValue so db.ts's secret fallback works)."
100
+ type = string
101
+ }
102
+
103
+ # ---- Capability-private interpreter VPC placement (THINK-280 U4) ---------------
104
+ # Empty when the capability broker is disabled → handler skips capability-private
105
+ # provisioning. Sourced from the broker outputs via the code-interpreter module.
106
+ variable "capability_private_subnet_ids" {
107
+ description = "No-NAT subnets for the capability-private VPC-mode interpreter. Empty when the broker is disabled."
108
+ type = list(string)
109
+ default = []
110
+ }
111
+
112
+ variable "capability_private_security_group_ids" {
113
+ description = "Egress-only SGs for the capability-private interpreter. Empty when the broker is disabled."
114
+ type = list(string)
115
+ default = []
116
+ }
117
+
118
+ ################################################################################
119
+ # Artifact-source gating — identical semantics to lambda-api/remote-artifacts.tf.
120
+ # Exactly one source (local zips OR remote S3) must be set, else the Lambda is
121
+ # not deployed (scaffolded installs with no artifacts).
122
+ ################################################################################
123
+
124
+ locals {
125
+ use_local_zips = trimspace(var.lambda_zips_dir) != ""
126
+ use_remote_lambda_artifacts = trimspace(var.lambda_artifact_bucket) != ""
127
+ lambda_artifact_prefix = trim(trimspace(var.lambda_artifact_prefix), "/")
128
+ artifact_source_count = (local.use_local_zips ? 1 : 0) + (local.use_remote_lambda_artifacts ? 1 : 0)
129
+ deploy = local.artifact_source_count == 1
130
+
131
+ function_name = "thinkwork-${var.stage}-api-agentcore-admin"
132
+
133
+ # DATABASE_URL built exactly as lambda-api's common_env does so getDb()
134
+ # resolves identically. sslmode=no-verify matches the shared pool (Aurora is
135
+ # reachable over TLS without a bundled CA in this stack).
136
+ database_url = "postgresql://${var.db_username}:${urlencode(var.db_password)}@${var.db_cluster_endpoint}:5432/${var.database_name}?sslmode=no-verify"
137
+ }
138
+
139
+ ################################################################################
140
+ # Admin bearer token — random_password → Secrets Manager. The token value is
141
+ # ALSO injected as the Lambda's AGENTCORE_ADMIN_TOKEN env (the handler compares
142
+ # the Bearer header against process.env directly), and handed to graphql-http so
143
+ # its invoke carries the matching credential. The secret is the durable record
144
+ # of truth for operators / rotation.
145
+ ################################################################################
146
+
147
+ resource "random_password" "admin_token" {
148
+ count = local.deploy ? 1 : 0
149
+ # 48 chars, alphanumeric only — safe inside an `Authorization: Bearer` header.
150
+ length = 48
151
+ special = false
152
+ }
153
+
154
+ resource "aws_secretsmanager_secret" "admin_token" {
155
+ count = local.deploy ? 1 : 0
156
+ name = "thinkwork/${var.stage}/agentcore-admin-token"
157
+ description = "Bearer token the agentcore-admin Lambda validates; graphql-http presents it on RequestResponse invokes."
158
+
159
+ tags = {
160
+ Name = "thinkwork-${var.stage}-agentcore-admin-token"
161
+ Stage = var.stage
162
+ Purpose = "agentcore-admin-bearer-token"
163
+ }
164
+ }
165
+
166
+ resource "aws_secretsmanager_secret_version" "admin_token" {
167
+ count = local.deploy ? 1 : 0
168
+ secret_id = aws_secretsmanager_secret.admin_token[0].id
169
+ secret_string = random_password.admin_token[0].result
170
+ }
171
+
172
+ ################################################################################
173
+ # IAM role — DEDICATED, least-privilege. Scoped tightly to the handler's actual
174
+ # AWS SDK calls (see packages/lambda/agentcore-admin.ts).
175
+ ################################################################################
176
+
177
+ resource "aws_iam_role" "admin" {
178
+ count = local.deploy ? 1 : 0
179
+ name = "thinkwork-${var.stage}-agentcore-admin"
180
+
181
+ assume_role_policy = jsonencode({
182
+ Version = "2012-10-17"
183
+ Statement = [{
184
+ Effect = "Allow"
185
+ Principal = { Service = "lambda.amazonaws.com" }
186
+ Action = "sts:AssumeRole"
187
+ }]
188
+ })
189
+
190
+ tags = {
191
+ Name = "thinkwork-${var.stage}-agentcore-admin"
192
+ Stage = var.stage
193
+ Purpose = "agentcore-admin-execution-role"
194
+ }
195
+ }
196
+
197
+ resource "aws_iam_role_policy" "admin" {
198
+ count = local.deploy ? 1 : 0
199
+ name = "agentcore-admin"
200
+ role = aws_iam_role.admin[0].id
201
+
202
+ policy = jsonencode({
203
+ Version = "2012-10-17"
204
+ Statement = [
205
+ # --- Lambda's own log group (basic execution) ---
206
+ {
207
+ Sid = "LambdaOwnLogs"
208
+ Effect = "Allow"
209
+ Action = [
210
+ "logs:CreateLogGroup",
211
+ "logs:CreateLogStream",
212
+ "logs:PutLogEvents",
213
+ ]
214
+ Resource = "arn:aws:logs:${var.region}:${var.account_id}:log-group:/aws/lambda/${local.function_name}:*"
215
+ },
216
+ # --- CloudWatch audit query (queryAuditLogs) ---
217
+ {
218
+ Sid = "AuditLogQuery"
219
+ Effect = "Allow"
220
+ Action = ["logs:FilterLogEvents"]
221
+ Resource = "arn:aws:logs:${var.region}:${var.account_id}:log-group:/thinkwork/${var.stage}/agentcore/agents:*"
222
+ },
223
+ # --- SSM permission-profile CRUD (getPermissions / putPermissions) ---
224
+ {
225
+ Sid = "SsmPermissionProfiles"
226
+ Effect = "Allow"
227
+ Action = [
228
+ "ssm:GetParameter",
229
+ "ssm:PutParameter",
230
+ ]
231
+ Resource = "arn:aws:ssm:${var.region}:${var.account_id}:parameter/thinkwork/${var.stage}/*"
232
+ },
233
+ # --- Per-tenant sandbox IAM roles (provision / deprovision) ---
234
+ # Two name prefixes: computeRoleName → sandbox-tenant-*, and the U4
235
+ # capability-private role → cappriv-tenant-*.
236
+ {
237
+ Sid = "SandboxRoleLifecycle"
238
+ Effect = "Allow"
239
+ Action = [
240
+ "iam:CreateRole",
241
+ "iam:DeleteRole",
242
+ "iam:GetRole",
243
+ "iam:PutRolePolicy",
244
+ "iam:DeleteRolePolicy",
245
+ "iam:TagRole",
246
+ ]
247
+ Resource = [
248
+ "arn:aws:iam::${var.account_id}:role/thinkwork-${var.stage}-sandbox-*",
249
+ "arn:aws:iam::${var.account_id}:role/thinkwork-${var.stage}-cappriv-*",
250
+ ]
251
+ },
252
+ # --- PassRole the sandbox roles to AgentCore (CreateCodeInterpreter) ---
253
+ {
254
+ Sid = "PassSandboxRolesToAgentCore"
255
+ Effect = "Allow"
256
+ Action = ["iam:PassRole"]
257
+ Resource = [
258
+ "arn:aws:iam::${var.account_id}:role/thinkwork-${var.stage}-sandbox-*",
259
+ "arn:aws:iam::${var.account_id}:role/thinkwork-${var.stage}-cappriv-*",
260
+ ]
261
+ Condition = {
262
+ StringEquals = {
263
+ "iam:PassedToService" = "bedrock-agentcore.amazonaws.com"
264
+ }
265
+ }
266
+ },
267
+ # --- AgentCore Code Interpreter control plane ---
268
+ # List/Create/Delete are account-scoped operations without a stable
269
+ # per-resource ARN at plan time; the SDK client is the control plane.
270
+ {
271
+ Sid = "CodeInterpreterControlPlane"
272
+ Effect = "Allow"
273
+ Action = [
274
+ "bedrock-agentcore:CreateCodeInterpreter",
275
+ "bedrock-agentcore:DeleteCodeInterpreter",
276
+ "bedrock-agentcore:ListCodeInterpreters",
277
+ "bedrock-agentcore:GetCodeInterpreter",
278
+ # CreateCodeInterpreter passes inline `tags`, which AgentCore
279
+ # authorizes as a separate bedrock-agentcore:TagResource action on
280
+ # code-interpreter-custom/* — verified empirically (first provision
281
+ # returned AccessDenied on TagResource). UntagResource covers teardown.
282
+ "bedrock-agentcore:TagResource",
283
+ "bedrock-agentcore:UntagResource",
284
+ ]
285
+ Resource = "*"
286
+ },
287
+ # --- Secrets: DB credentials (db.ts secret fallback) + own admin token ---
288
+ {
289
+ Sid = "SecretsRead"
290
+ Effect = "Allow"
291
+ Action = ["secretsmanager:GetSecretValue"]
292
+ Resource = [
293
+ var.graphql_db_secret_arn,
294
+ aws_secretsmanager_secret.admin_token[0].arn,
295
+ ]
296
+ },
297
+ ]
298
+ })
299
+ }
300
+
301
+ ################################################################################
302
+ # Lambda function
303
+ ################################################################################
304
+
305
+ resource "aws_lambda_function" "admin" {
306
+ count = local.deploy ? 1 : 0
307
+
308
+ function_name = local.function_name
309
+ role = aws_iam_role.admin[0].arn
310
+ handler = "index.handler"
311
+ runtime = "nodejs20.x"
312
+ timeout = 60
313
+ memory_size = 256
314
+
315
+ filename = local.use_local_zips ? "${var.lambda_zips_dir}/agentcore-admin.zip" : null
316
+ source_code_hash = local.use_local_zips ? filebase64sha256("${var.lambda_zips_dir}/agentcore-admin.zip") : null
317
+ s3_bucket = local.use_remote_lambda_artifacts ? var.lambda_artifact_bucket : null
318
+ s3_key = local.use_remote_lambda_artifacts ? "${local.lambda_artifact_prefix}/agentcore-admin.zip" : null
319
+
320
+ environment {
321
+ variables = {
322
+ STAGE = var.stage
323
+ AWS_ACCOUNT_ID = var.account_id
324
+ NODE_OPTIONS = "--enable-source-maps"
325
+ DATABASE_URL = local.database_url
326
+ # Bearer token the handler validates. Secret env is the sanctioned home
327
+ # for secrets in this stack (never the SSM runtime-config String doc).
328
+ AGENTCORE_ADMIN_TOKEN = random_password.admin_token[0].result
329
+ # THINK-280 U4 — capability-private interpreter VPC placement. EMPTY when
330
+ # the broker is disabled → the handler skips capability-private entirely.
331
+ CAPABILITY_PRIVATE_SUBNET_IDS = join(",", var.capability_private_subnet_ids)
332
+ CAPABILITY_PRIVATE_SECURITY_GROUP_IDS = join(",", var.capability_private_security_group_ids)
333
+ }
334
+ }
335
+
336
+ tags = {
337
+ Name = local.function_name
338
+ Stage = var.stage
339
+ Purpose = "agentcore-admin"
340
+ }
341
+ }
@@ -0,0 +1,20 @@
1
+ output "lambda_arn" {
2
+ description = "ARN of the agentcore-admin Lambda (AGENTCORE_ADMIN_LAMBDA_ARN for graphql-http). Empty when not deployed."
3
+ value = local.deploy ? aws_lambda_function.admin[0].arn : ""
4
+ }
5
+
6
+ output "lambda_function_name" {
7
+ description = "Function name of the agentcore-admin Lambda. Empty when not deployed."
8
+ value = local.deploy ? aws_lambda_function.admin[0].function_name : ""
9
+ }
10
+
11
+ output "admin_token" {
12
+ description = "Bearer token graphql-http presents on invoke (AGENTCORE_ADMIN_TOKEN). Empty when not deployed."
13
+ value = local.deploy ? random_password.admin_token[0].result : ""
14
+ sensitive = true
15
+ }
16
+
17
+ output "admin_token_secret_arn" {
18
+ description = "ARN of the Secrets Manager secret holding the admin bearer token. Empty when not deployed."
19
+ value = local.deploy ? aws_secretsmanager_secret.admin_token[0].arn : ""
20
+ }
@@ -50,6 +50,23 @@ variable "image_retention_count" {
50
50
  default = 10
51
51
  }
52
52
 
53
+ # THINK-280 U4 — VPC placement for the capability-private interpreter. Sourced
54
+ # (when the capability broker is enabled) from the broker module's no-NAT
55
+ # interpreter subnets + dedicated egress-only SG. Empty by default: the
56
+ # agentcore-admin Lambda skips capability-private provisioning entirely when
57
+ # either list is empty, so the module stays inert with the broker disabled.
58
+ variable "capability_private_subnet_ids" {
59
+ description = "No-NAT private subnets the capability-private VPC-mode interpreter attaches to. Empty when the broker is disabled."
60
+ type = list(string)
61
+ default = []
62
+ }
63
+
64
+ variable "capability_private_security_group_ids" {
65
+ description = "Egress-only security groups (reach only the broker execute-api VPCE) for the capability-private interpreter. Empty when the broker is disabled."
66
+ type = list(string)
67
+ default = []
68
+ }
69
+
53
70
  # Environment catalog. Kept as a locals block (not a variable) because v1
54
71
  # semantics are fixed in the plan — extending requires a reviewable PR,
55
72
  # not a tfvars tweak.
@@ -63,6 +80,14 @@ locals {
63
80
  description = "S3 + DNS + AWS service endpoints only; no public egress."
64
81
  network_mode = "SANDBOX"
65
82
  }
83
+ # THINK-280 U4: VPC-mode interpreter, no NAT. Reaches ONLY the capability
84
+ # broker's private execute-api VPCE (+ DNS). Runtime-selected per invocation
85
+ # (not a template-level opt-in), and only provisioned when the broker is
86
+ # enabled — the agentcore-admin Lambda gates on the VPC subnet/SG env vars.
87
+ "capability-private" = {
88
+ description = "VPC-mode, no NAT; reaches only the capability broker execute-api VPCE."
89
+ network_mode = "VPC"
90
+ }
66
91
  }
67
92
  }
68
93
 
@@ -155,6 +180,27 @@ locals {
155
180
  },
156
181
  ]
157
182
  })
183
+
184
+ # THINK-280 U4: SEPARATE restricted inline policy for the capability-private
185
+ # VPC-mode interpreter role. It deliberately LACKS the tenant sandbox Secrets
186
+ # Manager wildcard (SandboxSecretsRead above), tenant S3, and any database /
187
+ # provider access — the private interpreter reaches providers only through the
188
+ # broker's PoP session (AE5). Logs are the only genuine boot requirement.
189
+ # Consumed by the agentcore-admin Lambda for the capability-private role.
190
+ capability_private_role_inline_policy_template = jsonencode({
191
+ Version = "2012-10-17"
192
+ Statement = [
193
+ {
194
+ Sid = "CapabilityPrivateCloudWatchLogs"
195
+ Effect = "Allow"
196
+ Action = [
197
+ "logs:CreateLogStream",
198
+ "logs:PutLogEvents",
199
+ ]
200
+ Resource = "arn:aws:logs:${var.region}:${var.account_id}:log-group:/aws/bedrock-agentcore/runtimes/*"
201
+ },
202
+ ]
203
+ })
158
204
  }
159
205
 
160
206
  ################################################################################
@@ -191,6 +237,21 @@ output "tenant_role_inline_policy_template" {
191
237
  value = local.tenant_role_inline_policy_template
192
238
  }
193
239
 
240
+ output "capability_private_role_inline_policy_template" {
241
+ description = "THINK-280 U4: JSON inline-policy for the capability-private interpreter role. Logs-only; NO Secrets Manager / S3 / DB access."
242
+ value = local.capability_private_role_inline_policy_template
243
+ }
244
+
245
+ output "capability_private_subnet_ids" {
246
+ description = "No-NAT subnets the capability-private interpreter attaches to (CAPABILITY_PRIVATE_SUBNET_IDS). Empty when the broker is disabled."
247
+ value = var.capability_private_subnet_ids
248
+ }
249
+
250
+ output "capability_private_security_group_ids" {
251
+ description = "Egress-only SGs for the capability-private interpreter (CAPABILITY_PRIVATE_SECURITY_GROUP_IDS). Empty when the broker is disabled."
252
+ value = var.capability_private_security_group_ids
253
+ }
254
+
194
255
  output "stage" {
195
256
  description = "Echo of the stage variable (convenience for downstream modules)."
196
257
  value = var.stage