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,543 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ for required in AWS_REGION GATEWAY_NAME GATEWAY_ROLE_ARN GATEWAY_DISCOVERY_URL \
5
+ GATEWAY_AUDIENCE TARGET_NAME TARGET_BASE_URL OAUTH_CREDENTIAL_PROVIDER_ARN \
6
+ OAUTH_RETURN_URL POLICY_ENGINE_NAME POLICY_NAME PROOF_OWNER_ALLOWLIST; do
7
+ [[ -n "${!required:-}" ]] || { printf '%s is required\n' "$required" >&2; exit 1; }
8
+ done
9
+
10
+ tmp_dir="$(mktemp -d)"
11
+ trap 'rm -rf "$tmp_dir"' EXIT
12
+
13
+ # API Gateway routes and Lambdas are reconciled in a sibling Terraform module.
14
+ # The URL string alone does not create an apply-time dependency on those route
15
+ # instances, so wait for the public discovery document before asking AgentCore
16
+ # to validate CUSTOM_JWT. This keeps parallel applies deterministic.
17
+ discovery_ready=false
18
+ for _ in $(seq 1 60); do
19
+ if curl --fail --silent --show-error --max-time 5 \
20
+ "$GATEWAY_DISCOVERY_URL" \
21
+ | jq -e --arg issuer "${GATEWAY_DISCOVERY_URL%/.well-known/openid-configuration}" \
22
+ '.issuer == $issuer and (.jwks_uri | type == "string")' >/dev/null; then
23
+ discovery_ready=true
24
+ break
25
+ fi
26
+ sleep 5
27
+ done
28
+ [[ "$discovery_ready" == "true" ]] || {
29
+ printf 'Gateway discovery document did not become ready within five minutes\n' >&2
30
+ exit 1
31
+ }
32
+
33
+ list_id_by_name() {
34
+ local command="$1" collection="$2" id_key="$3" name="$4"
35
+ aws bedrock-agentcore-control "$command" --region "$AWS_REGION" --output json \
36
+ | jq -r --arg collection "$collection" --arg id_key "$id_key" --arg name "$name" \
37
+ '(.[$collection] // .items // [])[] | select(.name == $name) | .[$id_key]' \
38
+ | head -n 1
39
+ }
40
+
41
+ wait_status() {
42
+ local command="$1" id_flag="$2" id="$3" success="$4"
43
+ local status="" attempts=0
44
+ while (( attempts < 90 )); do
45
+ status="$(aws bedrock-agentcore-control "$command" --region "$AWS_REGION" \
46
+ "$id_flag" "$id" --query status --output text 2>/dev/null || true)"
47
+ [[ "$status" == "$success" ]] && return 0
48
+ case "$status" in
49
+ FAILED|CREATE_FAILED|UPDATE_UNSUCCESSFUL|SYNCHRONIZE_UNSUCCESSFUL)
50
+ printf '%s %s entered terminal status %s\n' "$command" "$id" "$status" >&2
51
+ return 1
52
+ ;;
53
+ esac
54
+ sleep 2
55
+ attempts=$((attempts + 1))
56
+ done
57
+ printf '%s %s did not reach %s (last=%s)\n' "$command" "$id" "$success" "$status" >&2
58
+ return 1
59
+ }
60
+
61
+ wait_policy_status() {
62
+ local engine_id="$1" policy_id="$2" status="" attempts=0
63
+ while (( attempts < 90 )); do
64
+ status="$(aws bedrock-agentcore-control get-policy --region "$AWS_REGION" \
65
+ --policy-engine-id "$engine_id" --policy-id "$policy_id" \
66
+ --query status --output text 2>/dev/null || true)"
67
+ [[ "$status" == "ACTIVE" ]] && return 0
68
+ case "$status" in
69
+ CREATE_FAILED|UPDATE_FAILED|FAILED)
70
+ printf 'policy %s entered terminal status %s\n' "$policy_id" "$status" >&2
71
+ return 1
72
+ ;;
73
+ esac
74
+ sleep 2
75
+ attempts=$((attempts + 1))
76
+ done
77
+ printf 'policy %s did not reach ACTIVE (last=%s)\n' "$policy_id" "$status" >&2
78
+ return 1
79
+ }
80
+
81
+ policy_engine_id="$(list_id_by_name list-policy-engines policyEngines policyEngineId "$POLICY_ENGINE_NAME")"
82
+ if [[ -z "$policy_engine_id" ]]; then
83
+ policy_engine_id="$(aws bedrock-agentcore-control create-policy-engine \
84
+ --region "$AWS_REGION" \
85
+ --name "$POLICY_ENGINE_NAME" \
86
+ --description "THINK-316 exact-user Gateway proof policy" \
87
+ --tags '{"purpose":"think-316-proof","managed-by":"terraform"}' \
88
+ --query policyEngineId --output text)"
89
+ fi
90
+ wait_status get-policy-engine --policy-engine-id "$policy_engine_id" ACTIVE
91
+ policy_engine_arn="$(aws bedrock-agentcore-control get-policy-engine \
92
+ --region "$AWS_REGION" --policy-engine-id "$policy_engine_id" \
93
+ --query policyEngineArn --output text)"
94
+
95
+ jq -n \
96
+ --arg name "$GATEWAY_NAME" \
97
+ --arg roleArn "$GATEWAY_ROLE_ARN" \
98
+ --arg discoveryUrl "$GATEWAY_DISCOVERY_URL" \
99
+ --arg audience "$GATEWAY_AUDIENCE" \
100
+ --arg policyArn "$policy_engine_arn" \
101
+ '{
102
+ name: $name,
103
+ description: "THINK-316 exact-user multiplayer proof Gateway",
104
+ exceptionLevel: "DEBUG",
105
+ roleArn: $roleArn,
106
+ protocolType: "MCP",
107
+ protocolConfiguration: {mcp: {
108
+ supportedVersions: ["2025-03-26", "2025-11-25"],
109
+ sessionConfiguration: {sessionTimeoutInSeconds: 900},
110
+ streamingConfiguration: {enableResponseStreaming: true}
111
+ }},
112
+ authorizerType: "CUSTOM_JWT",
113
+ authorizerConfiguration: {customJWTAuthorizer: {
114
+ discoveryUrl: $discoveryUrl,
115
+ allowedAudience: [$audience],
116
+ allowedScopes: ["gateway:invoke"]
117
+ }},
118
+ policyEngineConfiguration: {arn: $policyArn, mode: "ENFORCE"}
119
+ }' >"$tmp_dir/gateway.json"
120
+
121
+ gateway_id="$(list_id_by_name list-gateways items gatewayId "$GATEWAY_NAME")"
122
+ if [[ -z "$gateway_id" ]]; then
123
+ gateway_id="$(aws bedrock-agentcore-control create-gateway \
124
+ --region "$AWS_REGION" --cli-input-json "file://$tmp_dir/gateway.json" \
125
+ --query gatewayId --output text)"
126
+ else
127
+ jq --arg id "$gateway_id" '. + {gatewayIdentifier: $id}' \
128
+ "$tmp_dir/gateway.json" >"$tmp_dir/gateway-update.json"
129
+ aws bedrock-agentcore-control update-gateway --region "$AWS_REGION" \
130
+ --cli-input-json "file://$tmp_dir/gateway-update.json" >/dev/null
131
+ fi
132
+ wait_status get-gateway --gateway-identifier "$gateway_id" READY
133
+ gateway_arn="$(aws bedrock-agentcore-control get-gateway --region "$AWS_REGION" \
134
+ --gateway-identifier "$gateway_id" --query gatewayArn --output text)"
135
+
136
+ # Gateway creates a service-managed workload identity named after its concrete
137
+ # gateway id. OAuth 3LO fails internally unless the selected return URL is also
138
+ # allowlisted on that managed identity; target configuration alone is not
139
+ # sufficient.
140
+ aws bedrock-agentcore-control update-workload-identity \
141
+ --region "$AWS_REGION" \
142
+ --name "$gateway_id" \
143
+ --allowed-resource-oauth2-return-urls "$OAUTH_RETURN_URL" >/dev/null
144
+
145
+ openapi_payload="$(jq -nc --arg server "$TARGET_BASE_URL" '{
146
+ openapi: "3.0.3",
147
+ info: {title: "ThinkWork identity boundary proof", version: "1.0.0"},
148
+ servers: [{url: $server}],
149
+ paths: {
150
+ "/agentcore-proof/target/owner": {get: {
151
+ operationId: "owner_probe",
152
+ summary: "Return a structurally sanitized owner fixture",
153
+ parameters: [{
154
+ name: "requested_owner", in: "query", required: true,
155
+ schema: {type: "string"}
156
+ }],
157
+ responses: {"200": {description: "Sanitized owner projection"}}
158
+ }},
159
+ "/agentcore-proof/target/mixed": {get: {
160
+ operationId: "mixed_disclosure",
161
+ summary: "Return an allowlisted task field and a withholding decision",
162
+ parameters: [{
163
+ name: "requested_owner", in: "query", required: true,
164
+ schema: {type: "string"}
165
+ }],
166
+ responses: {"200": {description: "Sanitized mixed-sensitivity projection"}}
167
+ }},
168
+ "/agentcore/capabilities/mcp/tools/list": {post: {
169
+ operationId: "list_connector_tools",
170
+ summary: "List the current participant authorized tools for one ThinkWork connector",
171
+ requestBody: {required: true, content: {"application/json": {schema: {
172
+ type: "object", additionalProperties: false, required: ["connector", "query"],
173
+ properties: {
174
+ connector: {type: "string", description: "Connector name from the trusted turn context"},
175
+ query: {type: "string", description: "The connector task, used to return only relevant direct tools"}
176
+ }
177
+ }}}},
178
+ responses: {"200": {description: "Authorized connector tool definitions"}}
179
+ }},
180
+ "/agentcore/capabilities/mcp/tools/call": {post: {
181
+ operationId: "call_connector_tool",
182
+ summary: "Call one currently authorized ThinkWork connector tool as the exact turn participant",
183
+ requestBody: {required: true, content: {"application/json": {schema: {
184
+ type: "object", additionalProperties: false,
185
+ required: ["connector", "query", "tool", "arguments"],
186
+ properties: {
187
+ connector: {type: "string", description: "Connector name from the trusted turn context"},
188
+ query: {type: "string", description: "The same user task passed to list_connector_tools"},
189
+ tool: {type: "string", description: "Tool name returned by list_connector_tools"},
190
+ arguments: {type: "object", additionalProperties: true}
191
+ }
192
+ }}}},
193
+ responses: {"200": {description: "Connector tool result"}}
194
+ }},
195
+ "/agentcore/capabilities/sandbox/execute": {post: {
196
+ operationId: "execute_code",
197
+ summary: "Execute one bounded Python program in a short-lived internal-only sandbox",
198
+ requestBody: {required: true, content: {"application/json": {schema: {
199
+ type: "object", additionalProperties: false,
200
+ required: ["language", "code"],
201
+ properties: {
202
+ language: {type: "string", enum: ["python"]},
203
+ code: {type: "string", maxLength: 16384},
204
+ output_files: {
205
+ type: "array", maxItems: 5,
206
+ description: "Optional absolute files under /tmp/thinkwork/ to return as text",
207
+ items: {type: "string", pattern: "^/tmp/thinkwork/[A-Za-z0-9][A-Za-z0-9._/-]{0,180}$"}
208
+ }
209
+ }
210
+ }}}},
211
+ responses: {"200": {description: "Sanitized code result and declared files"}}
212
+ }},
213
+ "/agentcore/capabilities/web/search": {post: {
214
+ operationId: "web_search",
215
+ summary: "Search the current web through the tenant-configured governed provider",
216
+ requestBody: {required: true, content: {"application/json": {schema: {
217
+ type: "object", additionalProperties: false,
218
+ required: ["query"],
219
+ properties: {
220
+ query: {type: "string", minLength: 1, maxLength: 2000},
221
+ limit: {type: "integer", minimum: 1, maximum: 10, default: 5}
222
+ }
223
+ }}}},
224
+ responses: {"200": {description: "Sanitized current web search results"}}
225
+ }},
226
+ "/agentcore/capabilities/web/extract": {post: {
227
+ operationId: "web_extract",
228
+ summary: "Extract one known HTTPS page through the tenant-configured governed provider",
229
+ requestBody: {required: true, content: {"application/json": {schema: {
230
+ type: "object", additionalProperties: false,
231
+ required: ["url"],
232
+ properties: {
233
+ url: {type: "string", format: "uri", maxLength: 2048, pattern: "^https://"}
234
+ }
235
+ }}}},
236
+ responses: {"200": {description: "Sanitized bounded page content"}}
237
+ }},
238
+ "/agentcore/capabilities/brain/query": {post: {
239
+ operationId: "query_brain",
240
+ summary: "Query permissioned ThinkWork Brain context as the exact turn participant",
241
+ requestBody: {required: true, content: {"application/json": {schema: {
242
+ type: "object", additionalProperties: false,
243
+ required: ["query"],
244
+ properties: {
245
+ query: {type: "string", minLength: 1, maxLength: 2000},
246
+ mode: {type: "string", enum: ["results", "answer"], default: "results"},
247
+ limit: {type: "integer", minimum: 1, maximum: 10, default: 8}
248
+ }
249
+ }}}},
250
+ responses: {"200": {description: "Sanitized permissioned Brain context"}}
251
+ }},
252
+ "/agentcore/capabilities/workspace/skills/list": {post: {
253
+ operationId: "list_workspace_skills",
254
+ summary: "List the exact participant current authorized ThinkWork workspace skills",
255
+ requestBody: {required: true, content: {"application/json": {schema: {
256
+ type: "object", additionalProperties: false,
257
+ properties: {}
258
+ }}}},
259
+ responses: {"200": {description: "Current canonical authorized skill index"}}
260
+ }},
261
+ "/agentcore/capabilities/workspace/skills/load": {post: {
262
+ operationId: "load_workspace_skill",
263
+ summary: "Load one currently authorized ThinkWork SKILL.md as the exact turn participant",
264
+ requestBody: {required: true, content: {"application/json": {schema: {
265
+ type: "object", additionalProperties: false,
266
+ required: ["skill"],
267
+ properties: {
268
+ skill: {type: "string", pattern: "^[a-z0-9](?:[a-z0-9-]{0,62}[a-z0-9])?$"}
269
+ }
270
+ }}}},
271
+ responses: {
272
+ "200": {description: "Bounded authorized skill body"},
273
+ "403": {description: "Skill is not currently authorized"}
274
+ }
275
+ }},
276
+ "/agentcore/capabilities/message/attachments/list": {post: {
277
+ operationId: "list_message_attachments",
278
+ summary: "List files attached to the exact canonical triggering message",
279
+ requestBody: {required: true, content: {"application/json": {schema: {
280
+ type: "object", additionalProperties: false,
281
+ properties: {}
282
+ }}}},
283
+ responses: {"200": {description: "Sanitized canonical attachment metadata"}}
284
+ }},
285
+ "/agentcore/capabilities/message/attachments/read": {post: {
286
+ operationId: "read_message_attachment",
287
+ summary: "Read a bounded text chunk from one file on the exact triggering message",
288
+ requestBody: {required: true, content: {"application/json": {schema: {
289
+ type: "object", additionalProperties: false,
290
+ required: ["attachment_id"],
291
+ properties: {
292
+ attachment_id: {type: "string", format: "uuid"},
293
+ offset: {type: "integer", minimum: 0, default: 0},
294
+ max_chars: {type: "integer", minimum: 1, maximum: 65536, default: 32768}
295
+ }
296
+ }}}},
297
+ responses: {
298
+ "200": {description: "Bounded extracted text and continuation offset"},
299
+ "403": {description: "Attachment is not on the canonical triggering message"},
300
+ "422": {description: "Attachment format has no safe text projection"}
301
+ }
302
+ }},
303
+ "/agentcore/capabilities/user/questions/ask": {post: {
304
+ operationId: "ask_user_question",
305
+ summary: "Pause the exact participant turn for one governed structured question batch",
306
+ requestBody: {required: true, content: {"application/json": {schema: {
307
+ type: "object", additionalProperties: false,
308
+ required: ["questions"],
309
+ properties: {
310
+ questions: {
311
+ type: "array", minItems: 1, maxItems: 4,
312
+ items: {
313
+ type: "object", additionalProperties: false,
314
+ required: ["question", "header", "options"],
315
+ properties: {
316
+ question: {type: "string", minLength: 1, maxLength: 500},
317
+ header: {type: "string", minLength: 1, maxLength: 12},
318
+ options: {
319
+ type: "array", minItems: 2, maxItems: 4,
320
+ items: {
321
+ type: "object", additionalProperties: false,
322
+ required: ["label", "description"],
323
+ properties: {
324
+ label: {type: "string", minLength: 1, maxLength: 60},
325
+ description: {type: "string", minLength: 1, maxLength: 300}
326
+ }
327
+ }
328
+ },
329
+ multiSelect: {type: "boolean", default: false}
330
+ }
331
+ }
332
+ },
333
+ delegation_context: {type: "object", additionalProperties: true}
334
+ }
335
+ }}}},
336
+ responses: {
337
+ "200": {description: "Question batch posted or an existing pending batch retained"},
338
+ "403": {description: "Question capability denied for this exact participant"}
339
+ }
340
+ }},
341
+ "/agentcore/capabilities/email/send": {post: {
342
+ operationId: "send_email",
343
+ summary: "Send or request approval for one idempotent policy-governed email",
344
+ requestBody: {required: true, content: {"application/json": {schema: {
345
+ type: "object", additionalProperties: false,
346
+ required: ["to", "subject", "content"],
347
+ properties: {
348
+ to: {type: "array", minItems: 1, maxItems: 5, items: {type: "string", format: "email", maxLength: 320}},
349
+ subject: {type: "string", minLength: 1, maxLength: 500},
350
+ content: {type: "string", minLength: 1, maxLength: 60000, description: "Complete email message body"}
351
+ }
352
+ }}}},
353
+ responses: {
354
+ "200": {description: "Email sent or replayed safely"},
355
+ "202": {description: "First-send human review requested"}
356
+ }
357
+ }}
358
+ }
359
+ }')"
360
+
361
+ jq -n \
362
+ --arg name "$TARGET_NAME" \
363
+ --arg schema "$openapi_payload" \
364
+ --arg providerArn "$OAUTH_CREDENTIAL_PROVIDER_ARN" \
365
+ --arg returnUrl "$OAUTH_RETURN_URL" \
366
+ '{
367
+ name: $name,
368
+ description: "THINK-316 OAuth owner-isolation target",
369
+ targetConfiguration: {mcp: {openApiSchema: {inlinePayload: $schema}}},
370
+ credentialProviderConfigurations: [{
371
+ credentialProviderType: "OAUTH",
372
+ credentialProvider: {oauthCredentialProvider: {
373
+ providerArn: $providerArn,
374
+ scopes: ["owner.read"],
375
+ grantType: "TOKEN_EXCHANGE"
376
+ }}
377
+ }]
378
+ }' >"$tmp_dir/target.json"
379
+
380
+ target_id="$(aws bedrock-agentcore-control list-gateway-targets \
381
+ --region "$AWS_REGION" --gateway-identifier "$gateway_id" --output json \
382
+ | jq -r --arg name "$TARGET_NAME" '(.items // .targets // [])[] | select(.name == $name) | .targetId' \
383
+ | head -n 1)"
384
+ if [[ -z "$target_id" ]]; then
385
+ target_id="$(jq --arg gateway "$gateway_id" '. + {gatewayIdentifier: $gateway}' \
386
+ "$tmp_dir/target.json" >"$tmp_dir/target-create.json" && \
387
+ aws bedrock-agentcore-control create-gateway-target --region "$AWS_REGION" \
388
+ --cli-input-json "file://$tmp_dir/target-create.json" --query targetId --output text)"
389
+ else
390
+ jq --arg gateway "$gateway_id" --arg target "$target_id" \
391
+ '. + {gatewayIdentifier: $gateway, targetId: $target}' \
392
+ "$tmp_dir/target.json" >"$tmp_dir/target-update.json"
393
+ aws bedrock-agentcore-control update-gateway-target --region "$AWS_REGION" \
394
+ --cli-input-json "file://$tmp_dir/target-update.json" >/dev/null
395
+ fi
396
+
397
+ target_status=""
398
+ for _ in $(seq 1 90); do
399
+ target_status="$(aws bedrock-agentcore-control get-gateway-target \
400
+ --region "$AWS_REGION" --gateway-identifier "$gateway_id" --target-id "$target_id" \
401
+ --query status --output text 2>/dev/null || true)"
402
+ [[ "$target_status" == "READY" || "$target_status" == "CREATE_PENDING_AUTH" || "$target_status" == "UPDATE_PENDING_AUTH" ]] && break
403
+ [[ "$target_status" == "FAILED" || "$target_status" == "UPDATE_UNSUCCESSFUL" ]] && {
404
+ printf 'target %s entered terminal status %s\n' "$target_id" "$target_status" >&2; exit 1;
405
+ }
406
+ sleep 2
407
+ done
408
+ [[ "$target_status" == "READY" || "$target_status" == "CREATE_PENDING_AUTH" || "$target_status" == "UPDATE_PENDING_AUTH" ]] || {
409
+ printf 'target %s never reached a usable authorization state (last=%s)\n' "$target_id" "$target_status" >&2; exit 1;
410
+ }
411
+
412
+ # The Harness config grants one Gateway namespace, so a missing OpenAPI
413
+ # operation is otherwise silent: the model simply never sees that tool. Keep
414
+ # the reconciler from reporting success when Terraform's expected contract and
415
+ # AgentCore's live target schema have drifted apart.
416
+ expected_operations=(
417
+ owner_probe mixed_disclosure list_connector_tools call_connector_tool
418
+ execute_code web_search web_extract query_brain list_workspace_skills
419
+ load_workspace_skill list_message_attachments read_message_attachment
420
+ ask_user_question send_email
421
+ )
422
+ live_schema="$(aws bedrock-agentcore-control get-gateway-target \
423
+ --region "$AWS_REGION" --gateway-identifier "$gateway_id" --target-id "$target_id" \
424
+ --query 'targetConfiguration.mcp.openApiSchema.inlinePayload' --output text)"
425
+ for operation_id in "${expected_operations[@]}"; do
426
+ jq -e --arg operation_id "$operation_id" \
427
+ '[.paths[][] | .operationId] | index($operation_id) != null' \
428
+ <<<"$live_schema" >/dev/null || {
429
+ printf 'Gateway target %s is missing required operationId %s after reconciliation\n' \
430
+ "$target_id" "$operation_id" >&2
431
+ exit 1
432
+ }
433
+ done
434
+
435
+ # Explicit OAuthUser principal branches make the owner match mechanically
436
+ # reviewable and let Cedar reject cross-owner requests before AgentCore resolves
437
+ # a target credential. AgentCore maps JWT `sub` to the principal entity id (not
438
+ # a tag) and accepts one Cedar statement per policy definition. Connector and
439
+ # tool assignments are mutable ThinkWork state, so Cedar provides authenticated
440
+ # tenant admission while the target re-authorizes the live turn, connector, and
441
+ # tool assignment before resolving credentials or invoking the provider.
442
+ IFS=',' read -r -a proof_owners <<<"$PROOF_OWNER_ALLOWLIST"
443
+ owner_conditions=""
444
+ first_owner=""
445
+ for raw_owner in "${proof_owners[@]}"; do
446
+ owner="$(tr '[:upper:]' '[:lower:]' <<<"$raw_owner" | xargs)"
447
+ [[ "$owner" =~ ^[a-z0-9-]{1,128}$ ]] || {
448
+ printf 'invalid proof owner subject\n' >&2
449
+ exit 1
450
+ }
451
+ branch="(principal == AgentCore::OAuthUser::\"${owner}\" && context.input.requested_owner == \"${owner}\")"
452
+ [[ -z "$owner_conditions" ]] || owner_conditions+=$' ||\n '
453
+ owner_conditions+="$branch"
454
+ [[ -n "$first_owner" ]] || first_owner="$owner"
455
+ done
456
+ [[ "${#proof_owners[@]}" -ge 2 ]] || {
457
+ printf 'at least two proof owners are required\n' >&2
458
+ exit 1
459
+ }
460
+ cedar_statement="$(cat <<CEDAR
461
+ permit(
462
+ principal,
463
+ action in [
464
+ AgentCore::Action::"${TARGET_NAME}___owner_probe",
465
+ AgentCore::Action::"${TARGET_NAME}___mixed_disclosure",
466
+ AgentCore::Action::"${TARGET_NAME}___list_connector_tools",
467
+ AgentCore::Action::"${TARGET_NAME}___call_connector_tool",
468
+ AgentCore::Action::"${TARGET_NAME}___execute_code",
469
+ AgentCore::Action::"${TARGET_NAME}___web_search",
470
+ AgentCore::Action::"${TARGET_NAME}___web_extract",
471
+ AgentCore::Action::"${TARGET_NAME}___query_brain",
472
+ AgentCore::Action::"${TARGET_NAME}___list_workspace_skills",
473
+ AgentCore::Action::"${TARGET_NAME}___load_workspace_skill",
474
+ AgentCore::Action::"${TARGET_NAME}___list_message_attachments",
475
+ AgentCore::Action::"${TARGET_NAME}___read_message_attachment",
476
+ AgentCore::Action::"${TARGET_NAME}___ask_user_question",
477
+ AgentCore::Action::"${TARGET_NAME}___send_email"
478
+ ],
479
+ resource == AgentCore::Gateway::"${gateway_arn}"
480
+ )
481
+ when {
482
+ principal.hasTag("tenant_id") &&
483
+ principal.hasTag("purpose") &&
484
+ principal.getTag("purpose") == "gateway_operation" &&
485
+ (
486
+ (
487
+ action == AgentCore::Action::"${TARGET_NAME}___owner_probe" &&
488
+ (${owner_conditions})
489
+ ) ||
490
+ (
491
+ action == AgentCore::Action::"${TARGET_NAME}___mixed_disclosure" &&
492
+ principal == AgentCore::OAuthUser::"${first_owner}" &&
493
+ context.input.requested_owner == "${first_owner}"
494
+ ) ||
495
+ (
496
+ (
497
+ action == AgentCore::Action::"${TARGET_NAME}___list_connector_tools" ||
498
+ action == AgentCore::Action::"${TARGET_NAME}___call_connector_tool" ||
499
+ action == AgentCore::Action::"${TARGET_NAME}___execute_code" ||
500
+ action == AgentCore::Action::"${TARGET_NAME}___web_search" ||
501
+ action == AgentCore::Action::"${TARGET_NAME}___web_extract" ||
502
+ action == AgentCore::Action::"${TARGET_NAME}___query_brain" ||
503
+ action == AgentCore::Action::"${TARGET_NAME}___list_workspace_skills" ||
504
+ action == AgentCore::Action::"${TARGET_NAME}___load_workspace_skill" ||
505
+ action == AgentCore::Action::"${TARGET_NAME}___list_message_attachments" ||
506
+ action == AgentCore::Action::"${TARGET_NAME}___read_message_attachment" ||
507
+ action == AgentCore::Action::"${TARGET_NAME}___ask_user_question" ||
508
+ action == AgentCore::Action::"${TARGET_NAME}___send_email"
509
+ )
510
+ )
511
+ )
512
+ };
513
+ CEDAR
514
+ )"
515
+
516
+ jq -n --arg name "$POLICY_NAME" --arg engine "$policy_engine_id" \
517
+ --arg statement "$cedar_statement" '{
518
+ name: $name,
519
+ description: "THINK-316 exact-user admission; target owns dynamic capability authorization",
520
+ definition: {cedar: {statement: $statement}},
521
+ validationMode: "FAIL_ON_ANY_FINDINGS",
522
+ policyEngineId: $engine
523
+ }' >"$tmp_dir/policy.json"
524
+
525
+ policy_id="$(aws bedrock-agentcore-control list-policies --region "$AWS_REGION" \
526
+ --policy-engine-id "$policy_engine_id" --output json \
527
+ | jq -r --arg name "$POLICY_NAME" '(.policies // .items // [])[] | select(.name == $name) | .policyId' \
528
+ | head -n 1)"
529
+ if [[ -z "$policy_id" ]]; then
530
+ policy_id="$(aws bedrock-agentcore-control create-policy --region "$AWS_REGION" \
531
+ --cli-input-json "file://$tmp_dir/policy.json" --query policyId --output text)"
532
+ else
533
+ jq --arg id "$policy_id" '{
534
+ policyEngineId, policyId: $id, description: {optionalValue: .description},
535
+ definition, validationMode
536
+ }' "$tmp_dir/policy.json" >"$tmp_dir/policy-update.json"
537
+ aws bedrock-agentcore-control update-policy --region "$AWS_REGION" \
538
+ --cli-input-json "file://$tmp_dir/policy-update.json" >/dev/null
539
+ fi
540
+ wait_policy_status "$policy_engine_id" "$policy_id"
541
+
542
+ printf 'AgentCore Gateway proof resources reconciled: gateway=%s target=%s engine=%s policy=%s\n' \
543
+ "$gateway_id" "$target_id" "$policy_engine_id" "$policy_id"
@@ -0,0 +1,70 @@
1
+ variable "enabled" {
2
+ description = "Reconcile the non-production THINK-316 Gateway proof resources."
3
+ type = bool
4
+ default = false
5
+ }
6
+
7
+ variable "stage" {
8
+ description = "Deployment stage."
9
+ type = string
10
+ }
11
+
12
+ variable "region" {
13
+ description = "AWS region."
14
+ type = string
15
+ }
16
+
17
+ variable "account_id" {
18
+ description = "AWS account id."
19
+ type = string
20
+ }
21
+
22
+ variable "discovery_url" {
23
+ description = "CUSTOM_JWT OIDC discovery URL for the purpose-bound Gateway assertion issuer."
24
+ type = string
25
+ }
26
+
27
+ variable "gateway_audience" {
28
+ description = "Exact audience accepted by this proof Gateway."
29
+ type = string
30
+ }
31
+
32
+ variable "target_base_url" {
33
+ description = "Owned HTTPS API base URL hosting the controlled proof target."
34
+ type = string
35
+ }
36
+
37
+ variable "oauth_credential_provider_arn" {
38
+ description = "Exact AgentCore Identity OAuth provider ARN used for the target."
39
+ type = string
40
+ }
41
+
42
+ variable "oauth_credential_secret_arn" {
43
+ description = "Exact AgentCore-managed secret backing the OAuth provider."
44
+ type = string
45
+ sensitive = true
46
+ }
47
+
48
+ variable "oauth_return_url" {
49
+ description = "Application callback URL allowed for the 3LO user-federation flow."
50
+ type = string
51
+ }
52
+
53
+ variable "proof_owner_allowlist" {
54
+ description = "Comma-separated exact OAuthUser subjects admitted by the proof Cedar policy."
55
+ type = string
56
+ default = ""
57
+ }
58
+
59
+ variable "observability_retention_days" {
60
+ description = "Retention for AgentCore Gateway application logs delivered to CloudWatch."
61
+ type = number
62
+ default = 90
63
+
64
+ validation {
65
+ condition = contains([
66
+ 1, 3, 5, 7, 14, 30, 60, 90, 120, 150, 180, 365, 400, 545, 731, 1096, 1827, 2192, 2557, 2922, 3288, 3653,
67
+ ], var.observability_retention_days)
68
+ error_message = "observability_retention_days must be a CloudWatch Logs-supported retention period."
69
+ }
70
+ }