thinkwork-cli 0.13.1 → 1.0.0

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 (262) hide show
  1. package/README.md +3 -14
  2. package/dist/{api-client-4DZ266J5.js → api-client-4P4JZOBX.js} +3 -1
  3. package/dist/bowser-6Z6JFAIR.js +2822 -0
  4. package/dist/{chunk-Y2WHJECR.js → chunk-4OMDWYZQ.js} +5 -44
  5. package/dist/chunk-AD2NIWB5.js +6516 -0
  6. package/dist/chunk-DV3MRBR5.js +43 -0
  7. package/dist/chunk-EI5ZX7CN.js +522 -0
  8. package/dist/chunk-EUJ7X6YD.js +126 -0
  9. package/dist/chunk-GG5WKBOX.js +436 -0
  10. package/dist/chunk-I64EZSU5.js +358 -0
  11. package/dist/chunk-KMIJ5KGT.js +128 -0
  12. package/dist/chunk-MWQ7RO76.js +137 -0
  13. package/dist/chunk-OCPHU34C.js +996 -0
  14. package/dist/chunk-OLUQ4U2Z.js +1728 -0
  15. package/dist/chunk-XYM7PE2A.js +2264 -0
  16. package/dist/chunk-YQCYD6NE.js +3299 -0
  17. package/dist/cli.js +49156 -31257
  18. package/dist/commands/enterprise/templates/deploy-repo/scripts/apply-release.mjs +0 -1
  19. package/dist/commands/enterprise/templates/deploy-repo/scripts/smoke.mjs +0 -1
  20. package/dist/commands/enterprise/templates/deploy-repo/terraform/main.tf +0 -14
  21. package/dist/dist-es-2OTNTL4N.js +315 -0
  22. package/dist/dist-es-2XVAH4BQ.js +14726 -0
  23. package/dist/dist-es-3DPDUJAH.js +2000 -0
  24. package/dist/dist-es-BNZTBBVC.js +176 -0
  25. package/dist/dist-es-CD2RBDAC.js +88 -0
  26. package/dist/dist-es-I4FW57PS.js +88 -0
  27. package/dist/dist-es-KL7Y5NB2.js +377 -0
  28. package/dist/dist-es-KVFWJNDY.js +318 -0
  29. package/dist/dist-es-PS73DWNL.js +70 -0
  30. package/dist/dist-es-S3NZQFGT.js +170 -0
  31. package/dist/dist-es-SGCA4P32.js +48 -0
  32. package/dist/dist-es-WBM6J4RA.js +70 -0
  33. package/dist/dist-es-ZGVADYIF.js +485 -0
  34. package/dist/dist-es-ZKC2QKD2.js +377 -0
  35. package/dist/drizzle/0076_scheduled_jobs_marco_backfill.sql +2 -1
  36. package/dist/drizzle/0079_seed_tenant_customize_catalog.sql +1 -0
  37. package/dist/drizzle/0090_brain_schema_extraction.sql +10 -0
  38. package/dist/drizzle/0132_drop_computer_tables.sql +3 -0
  39. package/dist/drizzle/0160_compliance_event_types_plugins.sql +2 -0
  40. package/dist/drizzle/0214_think137_drop_judge_evidence_roi.sql +1 -0
  41. package/dist/drizzle/0216_drop_agent_loop_versions_goal_worker_policy.sql +1 -0
  42. package/dist/drizzle/0227_analyst_reader_role.sql +17 -20
  43. package/dist/drizzle/0230_analyst_rls.sql +28 -36
  44. package/dist/drizzle/0250_kg_schema_extraction.sql +27 -0
  45. package/dist/drizzle/0251_brain_stragglers.sql +21 -0
  46. package/dist/drizzle/0253_drop_brain_substrate.sql +2 -0
  47. package/dist/drizzle/0257_agents_runtime_allow_harness.sql +24 -0
  48. package/dist/drizzle/0261_native_auth_control_plane.sql +332 -0
  49. package/dist/drizzle/0262_auth_subscription_tickets.sql +59 -0
  50. package/dist/drizzle/0263_agentcore_runtime_identifier.sql +69 -0
  51. package/dist/drizzle/0263_drop_workos_auth_runtime.sql +236 -0
  52. package/dist/drizzle/0264_auth_enrollment_attempt_limits.sql +15 -0
  53. package/dist/drizzle/0265_eval_runs_requester_identity.sql +28 -0
  54. package/dist/drizzle/0265_require_fully_valid_auth_publication.sql +27 -0
  55. package/dist/drizzle/0266_auth_identity_recovery_grants.sql +9 -0
  56. package/dist/drizzle/0266_eval_profiles_runtime_type.sql +12 -0
  57. package/dist/drizzle/0267_ontology_candidate_rejections.sql +53 -0
  58. package/dist/drizzle/0268_identity_crosswalk_routing.sql +182 -0
  59. package/dist/drizzle/0269_ontology_system_map.sql +31 -0
  60. package/dist/drizzle/0270_tool_execution_ledger.sql +115 -0
  61. package/dist/drizzle/0271_ontology_twin_declarations.sql +47 -0
  62. package/dist/drizzle/0272_identity_graph_projection_cursor.sql +23 -0
  63. package/dist/drizzle/0273_twin_materialization_suggestions.sql +29 -0
  64. package/dist/drizzle/0274_tenant_mcp_twin_keys.sql +59 -0
  65. package/dist/drizzle/0275_identity_bulk_rebuild_fence.sql +30 -0
  66. package/dist/drizzle/0276_tool_execution_ledger_allow_cascade_delete.sql +18 -0
  67. package/dist/drizzle/0277_knowledge_base_sources.sql +107 -0
  68. package/dist/drizzle/0278_kb_page_transcription.sql +55 -0
  69. package/dist/drizzle/0279_mcp_servers_off_plugin_provenance.sql +93 -0
  70. package/dist/drizzle/0280_work_item_external_refs_drop_plane_provider.sql +46 -0
  71. package/dist/drizzle/0281_tenant_mcp_twin_keys_expiry_suffix.sql +9 -0
  72. package/dist/drizzle/0282_tenant_mcp_twin_keys_grants.sql +24 -0
  73. package/dist/drizzle/0283_agents_agentcore_runtime_dispatch.sql +13 -0
  74. package/dist/drizzle/0284_user_brain_claims.sql +69 -0
  75. package/dist/drizzle/0285_tenant_mcp_twin_keys_trusted_subsystem.sql +30 -0
  76. package/dist/drizzle/0286_brain_analytics_key.sql +26 -0
  77. package/dist/drizzle/0287_brain_subject.sql +25 -0
  78. package/dist/drizzle/0288_multi_lane_identities.sql +25 -0
  79. package/dist/event-streams-7JNLJEEL.js +894 -0
  80. package/dist/event-streams-KDF5RWR6.js +1515 -0
  81. package/dist/loadSso-ETCXTR4I.js +576 -0
  82. package/dist/loadSso-UBD7KUHE.js +583 -0
  83. package/dist/plugins/README.md +2 -2
  84. package/dist/plugins/catalog/package.json +1 -5
  85. package/dist/plugins/catalog/src/__tests__/build-catalog.test.ts +6 -4
  86. package/dist/plugins/catalog/src/__tests__/catalog.test.ts +21 -21
  87. package/dist/plugins/catalog/src/__tests__/contracts.test.ts +102 -94
  88. package/dist/plugins/catalog/src/__tests__/plugin-package.test.ts +7 -8
  89. package/dist/plugins/catalog/src/__tests__/plugin-registry.test.ts +0 -20
  90. package/dist/plugins/catalog/src/contracts.ts +17 -179
  91. package/dist/plugins/catalog/src/registry/generated-first-party.ts +0 -24
  92. package/dist/plugins/n8n/test/integrated-app-contract.test.ts +1 -1
  93. package/dist/plugins/twenty/package.json +2 -1
  94. package/dist/plugins/twenty/scripts/LAMBDA_DEPLOY.md +114 -0
  95. package/dist/plugins/twenty/scripts/build-lambda.sh +29 -0
  96. package/dist/plugins/twenty/scripts/configure-product-views.ts +195 -0
  97. package/dist/plugins/twenty/scripts/lambda-handler.ts +49 -0
  98. package/dist/plugins/twenty/scripts/lib/__tests__/load-attachments.test.ts +38 -0
  99. package/dist/plugins/twenty/scripts/lib/__tests__/load-records.test.ts +145 -2
  100. package/dist/plugins/twenty/scripts/lib/__tests__/mappers.test.ts +397 -151
  101. package/dist/plugins/twenty/scripts/lib/__tests__/members-ensure.test.ts +28 -129
  102. package/dist/plugins/twenty/scripts/lib/__tests__/provision-members-db.test.ts +10 -0
  103. package/dist/plugins/twenty/scripts/lib/__tests__/schema-ensure.test.ts +13 -8
  104. package/dist/plugins/twenty/scripts/lib/lastmile-reader.ts +222 -2
  105. package/dist/plugins/twenty/scripts/lib/load-attachments.ts +29 -0
  106. package/dist/plugins/twenty/scripts/lib/load-records.ts +160 -43
  107. package/dist/plugins/twenty/scripts/lib/mappers.ts +368 -152
  108. package/dist/plugins/twenty/scripts/lib/members-ensure.ts +43 -268
  109. package/dist/plugins/twenty/scripts/lib/provision-members-db.ts +57 -0
  110. package/dist/plugins/twenty/scripts/lib/schema-ensure.ts +136 -31
  111. package/dist/plugins/twenty/scripts/migrate-lastmile.ts +254 -152
  112. package/dist/plugins/twenty/scripts/provision-twenty-members.ts +44 -1
  113. package/dist/plugins/twenty/scripts/purge-lastmile-import.ts +178 -0
  114. package/dist/plugins/twenty/scripts/restructure-products.ts +312 -0
  115. package/dist/plugins/twenty/scripts/retag-stage-values.ts +362 -0
  116. package/dist/plugins/twenty/test/manifest.test.ts +2 -4
  117. package/dist/scripts/post-deploy.sh +79 -1
  118. package/dist/signin-5QZNRSOO.js +821 -0
  119. package/dist/sso-oidc-XK673P54.js +837 -0
  120. package/dist/sts-OXI2UALF.js +1113 -0
  121. package/dist/sts-SQW4NBK3.js +1117 -0
  122. package/dist/terraform/examples/greenfield/main.tf +391 -176
  123. package/dist/terraform/examples/greenfield/terraform.tfvars.example +26 -8
  124. package/dist/terraform/modules/app/agentcore-admin/main.tf +47 -0
  125. package/dist/terraform/modules/app/agentcore-code-interpreter/README.md +39 -47
  126. package/dist/terraform/modules/app/agentcore-code-interpreter/main.tf +13 -66
  127. package/dist/terraform/modules/app/agentcore-identity/main.tf +253 -0
  128. package/dist/terraform/modules/app/agentcore-identity/outputs.tf +51 -0
  129. package/dist/terraform/modules/app/agentcore-identity/scripts/bootstrap_twenty_oauth_client.sh +239 -0
  130. package/dist/terraform/modules/app/agentcore-identity/scripts/delete_identity.sh +22 -0
  131. package/dist/terraform/modules/app/agentcore-identity/scripts/delete_twenty_identity.sh +16 -0
  132. package/dist/terraform/modules/app/agentcore-identity/scripts/delete_workload_identity.sh +19 -0
  133. package/dist/terraform/modules/app/agentcore-identity/scripts/ensure_workload_identity.sh +29 -0
  134. package/dist/terraform/modules/app/agentcore-identity/scripts/read_identity.sh +55 -0
  135. package/dist/terraform/modules/app/agentcore-identity/scripts/reconcile_identity.sh +73 -0
  136. package/dist/terraform/modules/app/agentcore-identity/scripts/reconcile_twenty_identity.sh +45 -0
  137. package/dist/terraform/modules/app/agentcore-identity/scripts/reconcile_twenty_provider.mjs +123 -0
  138. package/dist/terraform/modules/app/agentcore-identity/tests/tainted-marker/after.tf +15 -0
  139. package/dist/terraform/modules/app/agentcore-identity/tests/tainted-marker/before.tf +7 -0
  140. package/dist/terraform/modules/app/agentcore-identity/tests/tainted-marker/identity-after.tf +8 -0
  141. package/dist/terraform/modules/app/agentcore-identity/tests/tainted-marker/identity-before.tf +9 -0
  142. package/dist/terraform/modules/app/agentcore-identity/tests/tainted-marker/thinkwork-after.tf +3 -0
  143. package/dist/terraform/modules/app/agentcore-identity/tests/tainted-marker/thinkwork-before.tf +3 -0
  144. package/dist/terraform/modules/app/agentcore-identity/variables.tf +60 -0
  145. package/dist/terraform/modules/app/agentcore-memory/README.md +46 -9
  146. package/dist/terraform/modules/app/agentcore-memory/main.tf +27 -10
  147. package/dist/terraform/modules/app/agentcore-memory/scripts/create_or_find_memory.sh +156 -24
  148. package/dist/terraform/modules/app/agentcore-pi/README.md +1 -3
  149. package/dist/terraform/modules/app/agentcore-pi/main.tf +42 -52
  150. package/dist/terraform/modules/app/agentcore-pi/outputs.tf +3 -3
  151. package/dist/terraform/modules/app/agentcore-pi/scripts/reconcile_pi_runtime.mjs +175 -0
  152. package/dist/terraform/modules/app/agentcore-pi/variables.tf +35 -28
  153. package/dist/terraform/modules/app/agentcore-platform/main.tf +68 -0
  154. package/dist/terraform/modules/app/agentcore-runtime/main.tf +4 -20
  155. package/dist/terraform/modules/app/appsync-subscriptions/main.tf +127 -21
  156. package/dist/terraform/modules/app/appsync-subscriptions/outputs.tf +0 -6
  157. package/dist/terraform/modules/app/appsync-subscriptions/variables.tf +5 -0
  158. package/dist/terraform/modules/app/capability-broker/main.tf +2 -2
  159. package/dist/terraform/modules/app/capability-broker/variables.tf +11 -0
  160. package/dist/terraform/modules/app/deployment-control-plane/README.md +264 -0
  161. package/dist/terraform/modules/app/deployment-control-plane/buildspec.yml +4 -1
  162. package/dist/terraform/modules/app/deployment-control-plane/main.tf +94 -0
  163. package/dist/terraform/modules/app/deployment-control-plane/outputs.tf +5 -0
  164. package/dist/terraform/modules/app/deployment-control-plane/runner.py +3689 -233
  165. package/dist/terraform/modules/app/deployment-control-plane/test_runner_bundle.py +2579 -140
  166. package/dist/terraform/modules/app/deployment-control-plane/variables.tf +33 -0
  167. package/dist/terraform/modules/app/lambda-api/auth-state.tf +72 -0
  168. package/dist/terraform/modules/app/lambda-api/chat-latency-observability.tf +466 -0
  169. package/dist/terraform/modules/app/lambda-api/dispatch-dlq.tf +55 -0
  170. package/dist/terraform/modules/app/lambda-api/handlers.tf +531 -619
  171. package/dist/terraform/modules/app/lambda-api/iam-grouped.tf +350 -241
  172. package/dist/terraform/modules/app/lambda-api/main.tf +75 -13
  173. package/dist/terraform/modules/app/lambda-api/memory-alarms.tf +3 -28
  174. package/dist/terraform/modules/app/lambda-api/oauth-secrets.tf +1 -2
  175. package/dist/terraform/modules/app/lambda-api/outputs.tf +17 -10
  176. package/dist/terraform/modules/app/lambda-api/runtime-config.tf +3 -21
  177. package/dist/terraform/modules/app/lambda-api/turn-assertion.tf +45 -0
  178. package/dist/terraform/modules/app/lambda-api/variables.tf +307 -121
  179. package/dist/{plugins/n8n/terraform → terraform/modules/app}/n8n/README.md +1 -1
  180. package/dist/{plugins/n8n/terraform → terraform/modules/app}/n8n/main.tf +18 -18
  181. package/dist/terraform/modules/app/sandbox-log-scrubber/README.md +11 -10
  182. package/dist/terraform/modules/app/sandbox-log-scrubber/main.tf +5 -5
  183. package/dist/terraform/modules/app/static-site/main.tf +1 -1
  184. package/dist/terraform/modules/app/www-dns/main.tf +9 -27
  185. package/dist/terraform/modules/app/www-dns/variables.tf +4 -10
  186. package/dist/terraform/modules/data/aurora-postgres/README.md +34 -0
  187. package/dist/terraform/modules/data/aurora-postgres/alarms.tf +82 -0
  188. package/dist/terraform/modules/data/aurora-postgres/main.tf +27 -57
  189. package/dist/terraform/modules/data/aurora-postgres/outputs.tf +0 -9
  190. package/dist/terraform/modules/data/aurora-postgres/variables.tf +41 -0
  191. package/dist/terraform/modules/data/s3-buckets/main.tf +5 -6
  192. package/dist/terraform/modules/foundation/cognito/main.tf +367 -72
  193. package/dist/terraform/modules/foundation/cognito/outputs.tf +47 -0
  194. package/dist/terraform/modules/foundation/cognito/variables.tf +131 -9
  195. package/dist/terraform/modules/thinkwork/README.md +5 -1
  196. package/dist/terraform/modules/thinkwork/main.tf +459 -234
  197. package/dist/terraform/modules/thinkwork/outputs.tf +44 -62
  198. package/dist/terraform/modules/thinkwork/variables.tf +353 -89
  199. package/dist/terraform/schema.graphql +69 -36
  200. package/dist/workspace-defaults/files/INSTRUCTIONS.md +9 -11
  201. package/dist/workspace-defaults/files/MEMORY_GUIDE.md +38 -35
  202. package/dist/workspace-defaults/files/ROUTER.md +1 -1
  203. package/dist/workspace-defaults/files/TOOLS.md +9 -39
  204. package/dist/workspace-defaults/files/USER.md +1 -0
  205. package/dist/workspace-defaults/files/agents/analyst/INSTRUCTIONS.md +6 -3
  206. package/dist/workspace-defaults/files/catalog-skills/brain-brief-builder/SKILL.md +165 -0
  207. package/dist/workspace-defaults/files/catalog-skills/n8n-workflow-operator/SKILL.md +75 -0
  208. package/dist/workspace-defaults/files/catalog-skills/n8n-workflow-operator/references/mcp-tooling.md +40 -0
  209. package/dist/workspace-defaults/files/catalog-skills/n8n-workflow-operator/references/validation-and-handoff.md +40 -0
  210. package/dist/workspace-defaults/files/catalog-skills/n8n-workflow-operator/references/workflow-authoring.md +46 -0
  211. package/dist/workspace-defaults/files/skills/artifact-builder/references/crm-dashboard.md +1 -1
  212. package/dist/workspace-defaults/files/skills/document-composer/SKILL.md +22 -3
  213. package/package.json +3 -2
  214. package/dist/drizzle/0261_thread_turns_origin_turn_index.sql +0 -11
  215. package/dist/plugins/company-data/README.md +0 -49
  216. package/dist/plugins/company-data/package.json +0 -21
  217. package/dist/plugins/company-data/src/index.ts +0 -30
  218. package/dist/plugins/company-data/src/manifest.ts +0 -26
  219. package/dist/plugins/company-data/test/manifest.test.ts +0 -116
  220. package/dist/plugins/company-data/tsconfig.json +0 -8
  221. package/dist/plugins/company-etl/README.md +0 -46
  222. package/dist/plugins/company-etl/package.json +0 -21
  223. package/dist/plugins/company-etl/src/index.ts +0 -29
  224. package/dist/plugins/company-etl/src/manifest.ts +0 -26
  225. package/dist/plugins/company-etl/test/manifest.test.ts +0 -108
  226. package/dist/plugins/company-etl/tsconfig.json +0 -8
  227. package/dist/plugins/lastmile/README.md +0 -50
  228. package/dist/plugins/lastmile/package.json +0 -23
  229. package/dist/plugins/lastmile/smoke/lastmile-plugin-smoke.mjs +0 -661
  230. package/dist/plugins/lastmile/src/api/tasks-adapter.ts +0 -572
  231. package/dist/plugins/lastmile/src/discovery.fixture.ts +0 -64
  232. package/dist/plugins/lastmile/src/index.ts +0 -46
  233. package/dist/plugins/lastmile/src/manifest.ts +0 -139
  234. package/dist/plugins/lastmile/test/api/tasks-adapter.test.ts +0 -266
  235. package/dist/plugins/lastmile/test/discovery.test.ts +0 -88
  236. package/dist/plugins/lastmile/tsconfig.json +0 -8
  237. package/dist/plugins/n8n/smoke/n8n-managed-app-smoke.mjs +0 -409
  238. package/dist/plugins/twenty/smoke/twenty-managed-app-smoke.mjs +0 -359
  239. package/dist/plugins/workos-auth/package.json +0 -22
  240. package/dist/plugins/workos-auth/src/index.ts +0 -30
  241. package/dist/plugins/workos-auth/src/manifest.ts +0 -40
  242. package/dist/plugins/workos-auth/src/provider-contract.ts +0 -39
  243. package/dist/plugins/workos-auth/test/manifest.test.ts +0 -94
  244. package/dist/plugins/workos-auth/tsconfig.json +0 -8
  245. package/dist/terraform/modules/app/agentcore-code-interpreter/Dockerfile.sandbox-base +0 -61
  246. package/dist/terraform/modules/app/agentcore-code-interpreter/sandbox/sitecustomize.py +0 -227
  247. package/dist/terraform/modules/app/agentcore-code-interpreter/sandbox/test_sitecustomize.py +0 -277
  248. package/dist/terraform/modules/app/agentcore-code-interpreter/scripts/build_and_push_sandbox_base.sh +0 -70
  249. package/dist/terraform/modules/app/agentcore-harness/main.tf +0 -101
  250. package/dist/terraform/modules/app/agentcore-harness/outputs.tf +0 -9
  251. package/dist/terraform/modules/app/agentcore-harness/variables.tf +0 -25
  252. package/dist/terraform/modules/app/hindsight-memory/README.md +0 -89
  253. package/dist/terraform/modules/app/hindsight-memory/main.tf +0 -411
  254. package/dist/terraform/modules/data/bedrock-knowledge-base/main.tf +0 -102
  255. /package/dist/{plugins/n8n/terraform → terraform/modules/app}/n8n/outputs.tf +0 -0
  256. /package/dist/{plugins/n8n/terraform → terraform/modules/app}/n8n/scripts/sync-database.py +0 -0
  257. /package/dist/{plugins/n8n/terraform → terraform/modules/app}/n8n/scripts/test_sync_database.py +0 -0
  258. /package/dist/{plugins/n8n/terraform → terraform/modules/app}/n8n/variables.tf +0 -0
  259. /package/dist/{plugins/twenty/terraform → terraform/modules/app}/twenty/README.md +0 -0
  260. /package/dist/{plugins/twenty/terraform → terraform/modules/app}/twenty/main.tf +0 -0
  261. /package/dist/{plugins/twenty/terraform → terraform/modules/app}/twenty/outputs.tf +0 -0
  262. /package/dist/{plugins/twenty/terraform → terraform/modules/app}/twenty/variables.tf +0 -0
@@ -1,227 +0,0 @@
1
- """sitecustomize — primary R13 token redactor for the AgentCore sandbox base image.
2
-
3
- Python auto-imports any module named ``sitecustomize`` during interpreter
4
- startup (before user code, before the preamble, before framework tracebacks on
5
- cold start). This file installs a stdio write-wrapper keyed on a session-scoped
6
- set of token values so no token leaks to stdout / stderr via Python-stdio
7
- writes.
8
-
9
- The invariant is honestly scoped per the brainstorm's R13 (as aligned in
10
- docs/brainstorms/2026-04-22-agentcore-code-sandbox-requirements.md):
11
-
12
- "no token value reaches a persisted log ... via Python-stdio-mediated writes"
13
-
14
- Bytes that bypass Python stdio (``os.write(fd, ...)``, subprocesses inheriting
15
- fds, C extensions, multiprocessing children) are the named residual class
16
- covered by the Unit 12 CloudWatch subscription-filter backstop for known
17
- OAuth prefixes, not by this module.
18
-
19
- Public API, callable from the sandbox preamble:
20
- register_token(value: str) -> None
21
- register_tokens(values: Iterable[str]) -> None
22
- clear_tokens() -> None
23
- installed() -> bool
24
- """
25
-
26
- from __future__ import annotations
27
-
28
- import base64
29
- import binascii
30
- import os
31
- import sys
32
- import urllib.parse
33
- from collections.abc import Iterable
34
- from typing import Any
35
-
36
- # ---------------------------------------------------------------------------
37
- # Module state
38
- # ---------------------------------------------------------------------------
39
-
40
- # Every unique byte-sequence we redact. Populated by ``register_token`` — each
41
- # registered token expands into its cleartext, standard base64, URL-safe
42
- # base64, URL-encoded, and hex forms (only the forms whose length is at least
43
- # MIN_TOKEN_LEN, to avoid redacting short accidental matches like "AQ").
44
- _redactions: set[bytes] = set()
45
-
46
- # Redaction placeholder. Length unimportant — stream layout survives because
47
- # writes stay synchronous.
48
- _REDACTION = b"<redacted>"
49
-
50
- # Forms shorter than this are rejected — redacting 3-character strings is the
51
- # shape of a wildcard bug, not a security control.
52
- MIN_TOKEN_LEN = 12
53
-
54
- # Rolling-suffix buffer size. Set at ``register_token`` time to
55
- # max(existing, 2 * len(new_token_form)). The wrapper keeps this many bytes
56
- # from the previous write and prepends them to the current write before
57
- # searching, so a token split across two ``write()`` calls is caught as long
58
- # as neither split half exceeds the buffer. Adversarial fragmentation at
59
- # arbitrary positions is a named residual (see R13).
60
- _rolling_buffer_size: int = 0
61
-
62
-
63
- def _expand(value: str) -> list[bytes]:
64
- """Return the encoded forms of a token value we treat as equivalent.
65
-
66
- Each form is added to the redaction set so ``print(base64.b64encode(token))``
67
- and the cleartext ``print(token)`` are both scrubbed.
68
- """
69
- if not value:
70
- return []
71
- raw = value.encode("utf-8")
72
- forms: list[bytes] = []
73
-
74
- def maybe_add(candidate: bytes) -> None:
75
- if len(candidate) >= MIN_TOKEN_LEN:
76
- forms.append(candidate)
77
-
78
- maybe_add(raw)
79
- maybe_add(base64.b64encode(raw).rstrip(b"="))
80
- maybe_add(base64.b64encode(raw))
81
- maybe_add(base64.urlsafe_b64encode(raw).rstrip(b"="))
82
- maybe_add(base64.urlsafe_b64encode(raw))
83
- maybe_add(urllib.parse.quote(value, safe="").encode("ascii"))
84
- maybe_add(binascii.hexlify(raw))
85
- return forms
86
-
87
-
88
- def register_token(value: str) -> None:
89
- """Add a token (and its derived encodings) to the redaction set.
90
-
91
- Safe to call multiple times with the same value. No-op for empty values.
92
- """
93
- global _rolling_buffer_size
94
- for form in _expand(value):
95
- _redactions.add(form)
96
- required = 2 * len(form)
97
- if required > _rolling_buffer_size:
98
- _rolling_buffer_size = required
99
-
100
-
101
- def register_tokens(values: Iterable[str]) -> None:
102
- for v in values:
103
- register_token(v)
104
-
105
-
106
- def clear_tokens() -> None:
107
- """Drop every registered token. Called at session teardown by the container."""
108
- global _rolling_buffer_size
109
- _redactions.clear()
110
- _rolling_buffer_size = 0
111
-
112
-
113
- # ---------------------------------------------------------------------------
114
- # Stdio wrapper
115
- # ---------------------------------------------------------------------------
116
-
117
-
118
- def _redact(chunk: bytes, tail_buffer: bytearray) -> tuple[bytes, bytearray]:
119
- """Return (scrubbed_output_chunk, new_tail_buffer).
120
-
121
- The tail buffer holds the trailing N bytes of the previous write so we can
122
- catch tokens split across write boundaries. The output we emit is the part
123
- of ``tail_buffer + chunk`` that is safely past the trailing window; the
124
- suffix stays in the new tail for the next call.
125
- """
126
- if not _redactions:
127
- return chunk, tail_buffer
128
-
129
- combined = bytes(tail_buffer) + chunk
130
- for form in _redactions:
131
- combined = combined.replace(form, _REDACTION)
132
-
133
- if _rolling_buffer_size and len(combined) > _rolling_buffer_size:
134
- emit = combined[:-_rolling_buffer_size]
135
- new_tail = bytearray(combined[-_rolling_buffer_size:])
136
- else:
137
- emit = b""
138
- new_tail = bytearray(combined)
139
-
140
- return emit, new_tail
141
-
142
-
143
- class _RedactingStream:
144
- """Wraps sys.stdout / sys.stderr's underlying buffer with a redactor.
145
-
146
- Intercepts both ``write(str)`` (TextIOBase) and ``.buffer.write(bytes)``
147
- paths so ``print(...)``, ``sys.stdout.write(...)``, and
148
- ``sys.stdout.buffer.write(...)`` all flow through the scrubber.
149
- """
150
-
151
- def __init__(self, wrapped: Any, name: str) -> None:
152
- self._wrapped = wrapped
153
- self._name = name
154
- self._tail = bytearray()
155
- # AgentCore writes to stdout/stderr line-buffered; we flush our tail
156
- # on every newline-terminated write so output appears promptly.
157
-
158
- def write(self, data: Any) -> int:
159
- if isinstance(data, str):
160
- payload = data.encode("utf-8", errors="replace")
161
- wrote_str = True
162
- elif isinstance(data, (bytes, bytearray, memoryview)):
163
- payload = bytes(data)
164
- wrote_str = False
165
- else:
166
- # Defer unknown types to the wrapped object — let it raise.
167
- return self._wrapped.write(data)
168
-
169
- emit, self._tail = _redact(payload, self._tail)
170
- # A newline forces a tail flush so output doesn't lag arbitrarily when
171
- # no new writes arrive. This is a UX concession, not a security one —
172
- # redaction is complete whether we flush or not.
173
- if b"\n" in payload:
174
- emit = emit + bytes(self._tail)
175
- self._tail = bytearray()
176
-
177
- if not emit:
178
- return len(data) if wrote_str else len(payload)
179
-
180
- if wrote_str:
181
- self._wrapped.write(emit.decode("utf-8", errors="replace"))
182
- else:
183
- # TextIOWrapper.write raises on bytes; prefer the underlying buffer.
184
- buf = getattr(self._wrapped, "buffer", None)
185
- if buf is not None:
186
- buf.write(emit)
187
- else:
188
- self._wrapped.write(emit)
189
- return len(data) if wrote_str else len(payload)
190
-
191
- def flush(self) -> None:
192
- if self._tail:
193
- data = bytes(self._tail)
194
- self._tail = bytearray()
195
- buf = getattr(self._wrapped, "buffer", None)
196
- if buf is not None:
197
- buf.write(data)
198
- else:
199
- self._wrapped.write(data.decode("utf-8", errors="replace"))
200
- self._wrapped.flush()
201
-
202
- # Forward any other attribute access (fileno, isatty, encoding, etc.) so
203
- # libraries that introspect the stream still see what they expect.
204
- def __getattr__(self, item: str) -> Any:
205
- return getattr(self._wrapped, item)
206
-
207
-
208
- _installed = False
209
-
210
-
211
- def installed() -> bool:
212
- return _installed
213
-
214
-
215
- def _install() -> None:
216
- global _installed
217
- if _installed:
218
- return
219
- sys.stdout = _RedactingStream(sys.stdout, "stdout")
220
- sys.stderr = _RedactingStream(sys.stderr, "stderr")
221
- _installed = True
222
-
223
-
224
- # Install unconditionally on import. Disable only for a pytest diagnostic
225
- # marker the test suite can opt out of (set THINKWORK_SANDBOX_SCRUBBER=off).
226
- if os.environ.get("THINKWORK_SANDBOX_SCRUBBER", "on") != "off":
227
- _install()
@@ -1,277 +0,0 @@
1
- """Unit tests for the AgentCore sandbox base-image stdio token redactor.
2
-
3
- Tests hit ``_RedactingStream`` directly with a test-owned stream instead of
4
- mutating ``sys.stdout`` — that side-steps pytest's capture machinery, which
5
- owns sys.stdout at test time and would otherwise see writes before the
6
- wrapper does. Correctness of the sys.stdout replacement path is proven by
7
- a separate end-to-end test that runs the module as a subprocess with its
8
- auto-install path active.
9
- """
10
-
11
- from __future__ import annotations
12
-
13
- import base64
14
- import binascii
15
- import importlib.util
16
- import io
17
- import os
18
- import subprocess
19
- import sys
20
- import urllib.parse
21
-
22
- import pytest
23
-
24
- os.environ["THINKWORK_SANDBOX_SCRUBBER"] = "off"
25
-
26
- _HERE = os.path.dirname(os.path.abspath(__file__))
27
- _SPEC = importlib.util.spec_from_file_location(
28
- "sandbox_base_sitecustomize",
29
- os.path.join(_HERE, "sitecustomize.py"),
30
- )
31
- assert _SPEC is not None and _SPEC.loader is not None
32
- sc = importlib.util.module_from_spec(_SPEC)
33
- _SPEC.loader.exec_module(sc)
34
-
35
-
36
- class _StringSink:
37
- """Minimal sys.stdout-shaped target: the wrapper writes strings into us,
38
- we collect them as UTF-8 bytes. Also exposes ``.buffer`` so bytes-path
39
- writes have a path through the wrapper."""
40
-
41
- def __init__(self) -> None:
42
- self.str_bytes = bytearray()
43
- self.buffer = io.BytesIO()
44
- self.name = "test-sink"
45
- self.encoding = "utf-8"
46
- self.errors = "strict"
47
-
48
- def write(self, s: str) -> int:
49
- self.str_bytes.extend(s.encode("utf-8", errors="replace"))
50
- return len(s)
51
-
52
- def flush(self) -> None:
53
- pass
54
-
55
- def captured(self) -> str:
56
- combined = bytes(self.str_bytes) + self.buffer.getvalue()
57
- return combined.decode("utf-8", errors="replace")
58
-
59
-
60
- @pytest.fixture
61
- def wrapper() -> tuple:
62
- """A fresh redactor wrapping a new sink, with an empty token set."""
63
- sc.clear_tokens()
64
- sink = _StringSink()
65
- stream = sc._RedactingStream(sink, "test-stdout") # type: ignore[attr-defined]
66
- yield stream, sink
67
- stream.flush()
68
- sc.clear_tokens()
69
-
70
-
71
- def test_cleartext_is_redacted(wrapper):
72
- stream, sink = wrapper
73
- token = "ghp_abc123abc123abc123"
74
- sc.register_token(token)
75
- stream.write(f"the token was {token} and not noticeable\n")
76
- stream.flush()
77
- text = sink.captured()
78
- assert token not in text
79
- assert "<redacted>" in text
80
- assert "the token was" in text
81
-
82
-
83
- def test_base64_form_is_redacted(wrapper):
84
- stream, sink = wrapper
85
- token = "ghp_abc123abc123abc123"
86
- sc.register_token(token)
87
- encoded = base64.b64encode(token.encode()).decode()
88
- stream.write(f"encoded={encoded}\n")
89
- stream.flush()
90
- text = sink.captured()
91
- assert encoded not in text
92
- assert "<redacted>" in text
93
-
94
-
95
- def test_urlsafe_base64_form_is_redacted(wrapper):
96
- stream, sink = wrapper
97
- token = "some_opaque_secret_for_urlsafe"
98
- sc.register_token(token)
99
- encoded = base64.urlsafe_b64encode(token.encode()).decode()
100
- stream.write(f"encoded={encoded}\n")
101
- stream.flush()
102
- text = sink.captured()
103
- assert encoded not in text
104
- assert "<redacted>" in text
105
-
106
-
107
- def test_url_encoded_form_is_redacted(wrapper):
108
- stream, sink = wrapper
109
- token = "token with spaces & special=chars"
110
- sc.register_token(token)
111
- encoded = urllib.parse.quote(token, safe="")
112
- stream.write(f"in_url={encoded}\n")
113
- stream.flush()
114
- text = sink.captured()
115
- assert encoded not in text
116
- assert "<redacted>" in text
117
-
118
-
119
- def test_hex_form_is_redacted(wrapper):
120
- stream, sink = wrapper
121
- token = "0123456789abcdef01234567"
122
- sc.register_token(token)
123
- encoded = binascii.hexlify(token.encode()).decode()
124
- stream.write(f"hex={encoded}\n")
125
- stream.flush()
126
- text = sink.captured()
127
- assert encoded not in text
128
- assert "<redacted>" in text
129
-
130
-
131
- def test_register_after_first_write_still_redacts_subsequent(wrapper):
132
- stream, sink = wrapper
133
- stream.write("before registration\n")
134
- token = "late_registered_token_value"
135
- sc.register_token(token)
136
- stream.write(f"after {token} registration\n")
137
- stream.flush()
138
- text = sink.captured()
139
- assert "before registration" in text
140
- assert token not in text
141
- assert "<redacted>" in text
142
-
143
-
144
- def test_split_write_across_boundary_is_caught(wrapper):
145
- stream, sink = wrapper
146
- token = "ghp_splitfragmenttokenvalue"
147
- sc.register_token(token)
148
- stream.write(token[:10])
149
- stream.write(token[10:])
150
- stream.write("\n")
151
- stream.flush()
152
- text = sink.captured()
153
- assert token not in text
154
- assert "<redacted>" in text
155
-
156
-
157
- def test_short_token_below_min_len_is_ignored(wrapper):
158
- """Redacting 3-char strings would produce wildcard false-positives."""
159
- stream, sink = wrapper
160
- sc.register_token("AQ")
161
- stream.write("AQ should appear unchanged because AQ is too short to redact\n")
162
- stream.flush()
163
- text = sink.captured()
164
- assert "AQ" in text
165
- assert "<redacted>" not in text
166
-
167
-
168
- def test_bytes_path_through_buffer(wrapper):
169
- stream, sink = wrapper
170
- token = "some_token_value_we_registered"
171
- sc.register_token(token)
172
- # Write bytes through the wrapper — it routes into sink.buffer.
173
- stream.write(b"\x00\x01\x02binary with " + token.encode() + b" embedded\n")
174
- stream.flush()
175
- text = sink.captured()
176
- assert token not in text
177
- assert "<redacted>" in text
178
- assert "binary with" in text
179
-
180
-
181
- def test_clear_tokens_disables_redaction_for_later_writes(wrapper):
182
- stream, sink = wrapper
183
- token = "a_token_that_will_be_cleared_soon"
184
- sc.register_token(token)
185
- stream.write(f"before clear: {token}\n")
186
- sc.clear_tokens()
187
- stream.write(f"after clear: {token}\n")
188
- stream.flush()
189
- text = sink.captured()
190
- assert text.count("<redacted>") == 1
191
- assert text.count(token) == 1
192
-
193
-
194
- def test_register_tokens_plural_is_equivalent(wrapper):
195
- stream, sink = wrapper
196
- sc.register_tokens(["first_registered_token_abc", "second_registered_token_def"])
197
- stream.write("first_registered_token_abc / second_registered_token_def\n")
198
- stream.flush()
199
- text = sink.captured()
200
- assert "first_registered_token_abc" not in text
201
- assert "second_registered_token_def" not in text
202
- assert text.count("<redacted>") >= 2
203
-
204
-
205
- def test_empty_token_is_ignored(wrapper):
206
- stream, sink = wrapper
207
- sc.register_token("")
208
- stream.write("nothing to redact here\n")
209
- stream.flush()
210
- text = sink.captured()
211
- assert "nothing to redact here" in text
212
- assert "<redacted>" not in text
213
-
214
-
215
- def test_no_crash_on_raw_bytes_without_matching_token(wrapper):
216
- stream, sink = wrapper
217
- sc.register_token("something_registered_but_not_present")
218
- stream.write(b"\x00\x01\x02binary bytes\n")
219
- stream.flush()
220
- text = sink.captured()
221
- assert "binary bytes" in text
222
-
223
-
224
- # --- End-to-end: the auto-install path ---------------------------------------
225
- #
226
- # Tests above exercise _RedactingStream directly, which is fine for the
227
- # redaction logic itself but bypasses the sitecustomize auto-install step
228
- # that replaces sys.stdout on interpreter startup. This subprocess test
229
- # proves that step works — a fresh Python process, with PYTHONPATH pointed
230
- # at the module directory and THINKWORK_SANDBOX_SCRUBBER unset, installs
231
- # the wrapper on its own and redacts a registered token before stdout is
232
- # flushed.
233
-
234
-
235
- def test_auto_install_redacts_on_fresh_interpreter(tmp_path):
236
- script = tmp_path / "run.py"
237
- script.write_text(
238
- """
239
- import sys, sitecustomize
240
- sitecustomize.register_token("ghp_autoInstallValueTokenX")
241
- print("auto-install redacts ghp_autoInstallValueTokenX mid-line here")
242
- """.strip()
243
- )
244
- env = os.environ.copy()
245
- # Strip our opt-out so sitecustomize installs on import.
246
- env.pop("THINKWORK_SANDBOX_SCRUBBER", None)
247
- # Prepend the module dir so Python's startup hook finds our
248
- # sitecustomize.py before any installed one.
249
- env["PYTHONPATH"] = _HERE + os.pathsep + env.get("PYTHONPATH", "")
250
- out = subprocess.run(
251
- [sys.executable, str(script)],
252
- env=env,
253
- check=True,
254
- capture_output=True,
255
- text=True,
256
- )
257
- assert "ghp_autoInstallValueTokenX" not in out.stdout
258
- assert "<redacted>" in out.stdout
259
- assert "auto-install redacts" in out.stdout
260
-
261
-
262
- def test_installed_reports_true_after_auto_install(tmp_path):
263
- """Probe ``installed()`` from a fresh interpreter — confirms the startup
264
- hook ran (and set the flag)."""
265
- script = tmp_path / "run.py"
266
- script.write_text("import sitecustomize; print(sitecustomize.installed())")
267
- env = os.environ.copy()
268
- env.pop("THINKWORK_SANDBOX_SCRUBBER", None)
269
- env["PYTHONPATH"] = _HERE + os.pathsep + env.get("PYTHONPATH", "")
270
- out = subprocess.run(
271
- [sys.executable, str(script)],
272
- env=env,
273
- check=True,
274
- capture_output=True,
275
- text=True,
276
- )
277
- assert out.stdout.strip() == "True"
@@ -1,70 +0,0 @@
1
- #!/usr/bin/env bash
2
- ################################################################################
3
- # build_and_push_sandbox_base.sh — build + push the AgentCore sandbox base
4
- # image to the stage's ECR repo. Invoked by CI; also safe to run locally
5
- # once ``thinkwork doctor`` reports green.
6
- #
7
- # Usage (from repo root):
8
- # bash terraform/modules/app/agentcore-code-interpreter/scripts/build_and_push_sandbox_base.sh \
9
- # --stage dev --region us-east-1
10
- #
11
- # The script:
12
- # 1. Reads the ECR repo URL from ``terraform output -raw`` (must be run
13
- # after ``terraform apply`` lands the agentcore-code-interpreter
14
- # module for the target stage).
15
- # 2. docker build the Dockerfile.sandbox-base with the repo root as
16
- # context (so the COPY can reach packages/).
17
- # 3. Tags with the current git SHA (immutable tag per the ECR repo
18
- # config) and ``:latest``.
19
- # 4. docker push both tags after ``aws ecr get-login-password``.
20
- ################################################################################
21
- set -euo pipefail
22
-
23
- STAGE=""
24
- REGION=""
25
-
26
- while [[ $# -gt 0 ]]; do
27
- case "$1" in
28
- --stage) STAGE="$2"; shift 2 ;;
29
- --region) REGION="$2"; shift 2 ;;
30
- *) echo "unknown arg: $1" >&2; exit 2 ;;
31
- esac
32
- done
33
-
34
- : "${STAGE:?--stage is required}"
35
- : "${REGION:?--region is required}"
36
-
37
- # Resolve the repo URL from terraform state. Tolerant: if the caller runs
38
- # this before the module applies, fall back to the deterministic name.
39
- REPO_URL="$(
40
- terraform -chdir="terraform/examples/greenfield" output -raw \
41
- sandbox_base_ecr_repository_url 2>/dev/null \
42
- || echo ""
43
- )"
44
- if [[ -z "$REPO_URL" ]]; then
45
- ACCOUNT_ID="$(aws sts get-caller-identity --query Account --output text)"
46
- REPO_URL="${ACCOUNT_ID}.dkr.ecr.${REGION}.amazonaws.com/thinkwork-${STAGE}-sandbox-base"
47
- fi
48
-
49
- GIT_SHA="$(git rev-parse --short HEAD)"
50
- IMAGE_TAG="${GIT_SHA}"
51
-
52
- echo "[sandbox-base] repo: ${REPO_URL}"
53
- echo "[sandbox-base] tag: ${IMAGE_TAG}"
54
-
55
- # ECR login
56
- aws ecr get-login-password --region "${REGION}" \
57
- | docker login --username AWS --password-stdin "${REPO_URL%/*}"
58
-
59
- # Build with repo root as the context so COPY can reach packages/.
60
- docker build \
61
- --platform=linux/amd64 \
62
- -f terraform/modules/app/agentcore-code-interpreter/Dockerfile.sandbox-base \
63
- -t "${REPO_URL}:${IMAGE_TAG}" \
64
- -t "${REPO_URL}:latest" \
65
- .
66
-
67
- docker push "${REPO_URL}:${IMAGE_TAG}"
68
- docker push "${REPO_URL}:latest"
69
-
70
- echo "[sandbox-base] pushed ${REPO_URL}:${IMAGE_TAG}"
@@ -1,101 +0,0 @@
1
- ################################################################################
2
- # AgentCore Harness — App Module (THINK-311 U4, ship-inert)
3
- #
4
- # IAM surface for the AWS Bedrock AgentCore Harness trial: the execution role
5
- # Harness microVMs assume, plus (via outputs consumed by lambda-api's grouped
6
- # policies) the invoker grants the shared api Lambda role needs to create and
7
- # invoke Harness resources. Nothing reads or invokes any of this until the
8
- # harness-runner handler lands in U5 — this module is pure IAM.
9
- #
10
- # Trust-policy note: sibling agentcore roles (agentcore-pi, agentcore-runtime)
11
- # trust the bare `bedrock-agentcore.amazonaws.com` service principal with no
12
- # account/source-arn conditions; this role mirrors that repo pattern.
13
- ################################################################################
14
-
15
- ################################################################################
16
- # Harness execution role — assumed by Harness microVMs
17
- ################################################################################
18
-
19
- resource "aws_iam_role" "harness_execution" {
20
- count = var.enabled ? 1 : 0
21
-
22
- name = "thinkwork-${var.stage}-agentcore-harness-role"
23
-
24
- assume_role_policy = jsonencode({
25
- Version = "2012-10-17"
26
- Statement = [{
27
- Effect = "Allow"
28
- Principal = { Service = "bedrock-agentcore.amazonaws.com" }
29
- Action = "sts:AssumeRole"
30
- }]
31
- })
32
-
33
- tags = {
34
- Name = "thinkwork-${var.stage}-agentcore-harness-role"
35
- }
36
- }
37
-
38
- resource "aws_iam_role_policy" "harness_execution" {
39
- count = var.enabled ? 1 : 0
40
-
41
- name = "agentcore-harness-permissions"
42
- role = aws_iam_role.harness_execution[0].id
43
-
44
- policy = jsonencode({
45
- Version = "2012-10-17"
46
- Statement = [
47
- {
48
- # Cross-region inference profiles (us.anthropic.claude-*) require
49
- # `bedrock:InvokeModel` on the *inference-profile* ARN AND on the
50
- # underlying foundation-model ARN in every region the profile can
51
- # route to — same resource list the api Lambda's grouped ai policy
52
- # uses (see ../lambda-api/iam-grouped.tf "bedrock-invoke").
53
- Sid = "BedrockInvoke"
54
- Effect = "Allow"
55
- Action = ["bedrock:InvokeModel", "bedrock:InvokeModelWithResponseStream"]
56
- Resource = [
57
- "arn:aws:bedrock:*::foundation-model/*",
58
- "arn:aws:bedrock:*:${var.account_id}:inference-profile/*",
59
- ]
60
- },
61
- {
62
- # Tenant skill catalog sources + materialized workspace skill folders
63
- # live under tenants/* in the stage workspace bucket. Read-only —
64
- # Harness microVMs never write back to the workspace bucket.
65
- Sid = "WorkspaceSkillSourcesRead"
66
- Effect = "Allow"
67
- Action = ["s3:GetObject"]
68
- Resource = "arn:aws:s3:::${var.bucket_name}/tenants/*"
69
- },
70
- {
71
- Sid = "WorkspaceSkillSourcesList"
72
- Effect = "Allow"
73
- Action = ["s3:ListBucket"]
74
- Resource = "arn:aws:s3:::${var.bucket_name}"
75
- Condition = {
76
- StringLike = {
77
- "s3:prefix" = "tenants/*"
78
- }
79
- }
80
- },
81
- {
82
- # Harness containers log to the service-managed bedrock-agentcore
83
- # log-group namespace, mirroring the agentcore-pi role's runtimes
84
- # grant.
85
- Sid = "CloudWatchLogs"
86
- Effect = "Allow"
87
- Action = [
88
- "logs:CreateLogGroup",
89
- "logs:CreateLogStream",
90
- "logs:DescribeLogGroups",
91
- "logs:DescribeLogStreams",
92
- "logs:PutLogEvents",
93
- ]
94
- Resource = [
95
- "arn:aws:logs:${var.region}:${var.account_id}:log-group:/aws/bedrock-agentcore/*",
96
- "arn:aws:logs:${var.region}:${var.account_id}:log-group:/aws/bedrock-agentcore/*:*",
97
- ]
98
- },
99
- ]
100
- })
101
- }
@@ -1,9 +0,0 @@
1
- output "execution_role_arn" {
2
- description = "ARN of the Harness execution role (CreateHarness executionRoleArn). Empty string when the module is disabled."
3
- value = var.enabled ? aws_iam_role.harness_execution[0].arn : ""
4
- }
5
-
6
- output "execution_role_name" {
7
- description = "Name of the Harness execution role. Empty string when the module is disabled."
8
- value = var.enabled ? aws_iam_role.harness_execution[0].name : ""
9
- }