thinkwork-cli 0.13.1 → 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.
- package/dist/{api-client-4DZ266J5.js → api-client-JYZXYQJR.js} +3 -1
- package/dist/bowser-6Z6JFAIR.js +2822 -0
- package/dist/chunk-DV3MRBR5.js +43 -0
- package/dist/chunk-DVPBI5HM.js +1728 -0
- package/dist/chunk-EI5ZX7CN.js +522 -0
- package/dist/chunk-EUJ7X6YD.js +126 -0
- package/dist/chunk-GG5WKBOX.js +436 -0
- package/dist/chunk-I64EZSU5.js +358 -0
- package/dist/chunk-ILZKG5WV.js +6151 -0
- package/dist/chunk-KMIJ5KGT.js +128 -0
- package/dist/chunk-OCPHU34C.js +996 -0
- package/dist/chunk-QOERT44A.js +3286 -0
- package/dist/chunk-XYM7PE2A.js +2264 -0
- package/dist/{chunk-Y2WHJECR.js → chunk-Z2F6RJFR.js} +1 -39
- package/dist/cli.js +43080 -13150
- package/dist/dist-es-CRV46D5B.js +315 -0
- package/dist/dist-es-DCY4IC3Y.js +2000 -0
- package/dist/dist-es-ENBUC3JP.js +14726 -0
- package/dist/dist-es-G54LBMRN.js +48 -0
- package/dist/dist-es-G7PTG75M.js +176 -0
- package/dist/dist-es-GKDBE7E6.js +88 -0
- package/dist/dist-es-HY3535OI.js +70 -0
- package/dist/dist-es-KL7Y5NB2.js +377 -0
- package/dist/dist-es-LDE437AM.js +170 -0
- package/dist/dist-es-P26FWFLT.js +485 -0
- package/dist/dist-es-Q57SZXZ7.js +70 -0
- package/dist/dist-es-R7FGL2IB.js +88 -0
- package/dist/dist-es-USORBXZ5.js +318 -0
- package/dist/dist-es-ZKC2QKD2.js +377 -0
- package/dist/drizzle/0076_scheduled_jobs_marco_backfill.sql +2 -1
- package/dist/drizzle/0079_seed_tenant_customize_catalog.sql +1 -0
- package/dist/drizzle/0090_brain_schema_extraction.sql +10 -0
- package/dist/drizzle/0132_drop_computer_tables.sql +3 -0
- package/dist/drizzle/0160_compliance_event_types_plugins.sql +2 -0
- package/dist/drizzle/0214_think137_drop_judge_evidence_roi.sql +1 -0
- package/dist/drizzle/0216_drop_agent_loop_versions_goal_worker_policy.sql +1 -0
- package/dist/drizzle/0227_analyst_reader_role.sql +6 -0
- package/dist/drizzle/0230_analyst_rls.sql +9 -0
- package/dist/drizzle/0250_kg_schema_extraction.sql +27 -0
- package/dist/drizzle/0251_brain_stragglers.sql +21 -0
- package/dist/drizzle/0253_drop_brain_substrate.sql +2 -0
- package/dist/drizzle/0257_agents_runtime_allow_harness.sql +24 -0
- package/dist/drizzle/0261_managed_harness_multiplayer.sql +313 -0
- package/dist/drizzle/0261_native_auth_control_plane.sql +328 -0
- package/dist/drizzle/0262_auth_subscription_tickets.sql +59 -0
- package/dist/drizzle/0262_parallel_harness_threads.sql +9 -0
- package/dist/drizzle/0263_agentcore_runtime_identifier.sql +69 -0
- package/dist/drizzle/0263_drop_workos_auth_runtime.sql +236 -0
- package/dist/drizzle/0264_auth_enrollment_attempt_limits.sql +15 -0
- package/dist/drizzle/0264_harness_tool_execution_ledger.sql +113 -0
- package/dist/drizzle/0265_eval_runs_requester_identity.sql +28 -0
- package/dist/drizzle/0265_require_fully_valid_auth_publication.sql +27 -0
- package/dist/drizzle/0266_auth_identity_recovery_grants.sql +9 -0
- package/dist/drizzle/0266_eval_profiles_runtime_type.sql +12 -0
- package/dist/drizzle/0267_ontology_candidate_rejections.sql +53 -0
- package/dist/drizzle/0268_identity_crosswalk_routing.sql +182 -0
- package/dist/drizzle/0269_ontology_system_map.sql +31 -0
- package/dist/event-streams-7JNLJEEL.js +894 -0
- package/dist/event-streams-KDF5RWR6.js +1515 -0
- package/dist/loadSso-DJVB7BXE.js +576 -0
- package/dist/loadSso-JAMNA3WY.js +583 -0
- package/dist/plugins/catalog/package.json +1 -2
- package/dist/plugins/catalog/src/__tests__/build-catalog.test.ts +0 -1
- package/dist/plugins/catalog/src/__tests__/contracts.test.ts +0 -69
- package/dist/plugins/catalog/src/__tests__/plugin-package.test.ts +0 -2
- package/dist/plugins/catalog/src/__tests__/plugin-registry.test.ts +0 -5
- package/dist/plugins/catalog/src/contracts.ts +2 -179
- package/dist/plugins/catalog/src/registry/generated-first-party.ts +0 -6
- package/dist/signin-UGDWTGS4.js +821 -0
- package/dist/sso-oidc-Q4VXANXY.js +837 -0
- package/dist/sts-CWLSE3GH.js +1241 -0
- package/dist/sts-DNZLNVOV.js +1245 -0
- package/dist/terraform/examples/greenfield/main.tf +223 -66
- package/dist/terraform/examples/greenfield/terraform.tfvars.example +15 -1
- package/dist/terraform/modules/app/agentcore-gateway/main.tf +305 -0
- package/dist/terraform/modules/app/agentcore-gateway/outputs.tf +44 -0
- package/dist/terraform/modules/app/agentcore-gateway/scripts/delete_gateway.sh +93 -0
- package/dist/terraform/modules/app/agentcore-gateway/scripts/read_gateway.sh +33 -0
- package/dist/terraform/modules/app/agentcore-gateway/scripts/reconcile_gateway.sh +543 -0
- package/dist/terraform/modules/app/agentcore-gateway/variables.tf +70 -0
- package/dist/terraform/modules/app/agentcore-harness/main.tf +237 -8
- package/dist/terraform/modules/app/agentcore-harness/outputs.tf +63 -0
- package/dist/terraform/modules/app/agentcore-harness/scripts/delete_harness.sh +5 -0
- package/dist/terraform/modules/app/agentcore-harness/scripts/harness-lifecycle.mjs +430 -0
- package/dist/terraform/modules/app/agentcore-harness/scripts/harness-readback.mjs +180 -0
- package/dist/terraform/modules/app/agentcore-harness/scripts/harness-tool-contract.mjs +193 -0
- package/dist/terraform/modules/app/agentcore-harness/scripts/prune_harness.sh +5 -0
- package/dist/terraform/modules/app/agentcore-harness/scripts/read_harness.sh +5 -0
- package/dist/terraform/modules/app/agentcore-harness/scripts/reconcile_harness.sh +5 -0
- package/dist/terraform/modules/app/agentcore-harness/variables.tf +72 -1
- package/dist/terraform/modules/app/agentcore-identity/main.tf +173 -0
- package/dist/terraform/modules/app/agentcore-identity/outputs.tf +51 -0
- package/dist/terraform/modules/app/agentcore-identity/scripts/bootstrap_twenty_oauth_client.sh +122 -0
- package/dist/terraform/modules/app/agentcore-identity/scripts/delete_identity.sh +25 -0
- package/dist/terraform/modules/app/agentcore-identity/scripts/delete_twenty_identity.sh +16 -0
- package/dist/terraform/modules/app/agentcore-identity/scripts/read_identity.sh +40 -0
- package/dist/terraform/modules/app/agentcore-identity/scripts/reconcile_identity.sh +73 -0
- package/dist/terraform/modules/app/agentcore-identity/scripts/reconcile_twenty_identity.sh +74 -0
- package/dist/terraform/modules/app/agentcore-identity/scripts/reconcile_twenty_provider.mjs +61 -0
- package/dist/terraform/modules/app/agentcore-identity/variables.tf +54 -0
- package/dist/terraform/modules/app/appsync-subscriptions/main.tf +127 -21
- package/dist/terraform/modules/app/appsync-subscriptions/outputs.tf +0 -6
- package/dist/terraform/modules/app/appsync-subscriptions/variables.tf +5 -0
- package/dist/terraform/modules/app/deployment-control-plane/runner.py +966 -27
- package/dist/terraform/modules/app/deployment-control-plane/test_runner_bundle.py +581 -22
- package/dist/terraform/modules/app/lambda-api/agentcore-harness-alarms.tf +88 -0
- package/dist/terraform/modules/app/lambda-api/agentcore-identity-alarms.tf +91 -0
- package/dist/terraform/modules/app/lambda-api/handlers.tf +298 -74
- package/dist/terraform/modules/app/lambda-api/iam-grouped.tf +99 -54
- package/dist/terraform/modules/app/lambda-api/main.tf +24 -0
- package/dist/terraform/modules/app/lambda-api/mcp-oauth.tf +181 -4
- package/dist/terraform/modules/app/lambda-api/outputs.tf +35 -0
- package/dist/terraform/modules/app/lambda-api/runtime-config.tf +3 -21
- package/dist/terraform/modules/app/lambda-api/variables.tf +109 -16
- package/dist/terraform/modules/foundation/cognito/main.tf +294 -72
- package/dist/terraform/modules/foundation/cognito/outputs.tf +42 -0
- package/dist/terraform/modules/foundation/cognito/variables.tf +114 -4
- package/dist/terraform/modules/thinkwork/main.tf +269 -46
- package/dist/terraform/modules/thinkwork/outputs.tf +136 -8
- package/dist/terraform/modules/thinkwork/variables.tf +124 -17
- package/dist/terraform/schema.graphql +69 -36
- package/dist/workspace-defaults/files/USER.md +1 -0
- package/package.json +3 -2
- package/dist/drizzle/0261_thread_turns_origin_turn_index.sql +0 -11
- package/dist/plugins/workos-auth/package.json +0 -22
- package/dist/plugins/workos-auth/src/index.ts +0 -30
- package/dist/plugins/workos-auth/src/manifest.ts +0 -40
- package/dist/plugins/workos-auth/src/provider-contract.ts +0 -39
- package/dist/plugins/workos-auth/test/manifest.test.ts +0 -94
- package/dist/plugins/workos-auth/tsconfig.json +0 -8
|
@@ -181,6 +181,8 @@ locals {
|
|
|
181
181
|
"cognito-idp:AdminRespondToAuthChallenge",
|
|
182
182
|
"cognito-idp:AdminSetUserPassword",
|
|
183
183
|
"cognito-idp:AdminUpdateUserAttributes",
|
|
184
|
+
"cognito-idp:DescribeIdentityProvider",
|
|
185
|
+
"cognito-idp:DescribeUserPoolClient",
|
|
184
186
|
"cognito-idp:ListUsers",
|
|
185
187
|
]
|
|
186
188
|
Resource = var.user_pool_arn
|
|
@@ -346,6 +348,7 @@ locals {
|
|
|
346
348
|
# refresh path cannot replace the old manual AWS CLI step.
|
|
347
349
|
var.deployment_evidence_bucket != "" ? [
|
|
348
350
|
{
|
|
351
|
+
Sid = "DeploymentEvidenceBucket"
|
|
349
352
|
Effect = "Allow"
|
|
350
353
|
Action = [
|
|
351
354
|
"s3:GetObject",
|
|
@@ -357,6 +360,12 @@ locals {
|
|
|
357
360
|
"arn:aws:s3:::${var.deployment_evidence_bucket}/*",
|
|
358
361
|
]
|
|
359
362
|
},
|
|
363
|
+
{
|
|
364
|
+
Sid = "AgentCoreHarnessGatewayOauthSecret"
|
|
365
|
+
Effect = "Allow"
|
|
366
|
+
Action = ["secretsmanager:GetSecretValue"]
|
|
367
|
+
Resource = ["arn:aws:secretsmanager:${var.region}:${var.account_id}:secret:bedrock-agentcore-identity!default/oauth2/thinkwork-${var.stage}-proof-oauth-*"]
|
|
368
|
+
},
|
|
360
369
|
] : [],
|
|
361
370
|
var.billing_export_bucket_name != "" ? [
|
|
362
371
|
{
|
|
@@ -524,6 +533,17 @@ locals {
|
|
|
524
533
|
# wiki-bootstrap-import: bootstrapJournalImport admin mutation
|
|
525
534
|
# Event-invokes this for the long-running ingest path.
|
|
526
535
|
"arn:aws:lambda:${var.region}:${var.account_id}:function:thinkwork-${var.stage}-api-wiki-bootstrap-import",
|
|
536
|
+
# harness-runner: chat-agent-invoke Event-invokes this for chat
|
|
537
|
+
# turns routed to the AWS AgentCore runtime (THINK-311 trial).
|
|
538
|
+
"arn:aws:lambda:${var.region}:${var.account_id}:function:thinkwork-${var.stage}-api-harness-runner",
|
|
539
|
+
# harness-runner queues the same canonical post-turn memory pipeline
|
|
540
|
+
# as Pi after a completed AgentCore turn. The retain ledger makes the
|
|
541
|
+
# Event invoke idempotent on the thread-turn source key.
|
|
542
|
+
"arn:aws:lambda:${var.region}:${var.account_id}:function:thinkwork-${var.stage}-api-memory-retain",
|
|
543
|
+
# harness-runner RequestResponse-invokes this dedicated signer. The
|
|
544
|
+
# signer re-derives the actor/tenant/thread tuple from the running
|
|
545
|
+
# turn and alone holds KMS Sign; the shared runner role never does.
|
|
546
|
+
"arn:aws:lambda:${var.region}:${var.account_id}:function:thinkwork-${var.stage}-api-turn-assertion-mint",
|
|
527
547
|
# ontology-scan: startOntologySuggestionScan Event-invokes this
|
|
528
548
|
# after inserting a durable scan job row.
|
|
529
549
|
"arn:aws:lambda:${var.region}:${var.account_id}:function:thinkwork-${var.stage}-api-ontology-scan",
|
|
@@ -887,14 +907,14 @@ locals {
|
|
|
887
907
|
Resource = "*"
|
|
888
908
|
},
|
|
889
909
|
],
|
|
890
|
-
# THINK-
|
|
891
|
-
#
|
|
892
|
-
#
|
|
910
|
+
# THINK-316 U2 — request path receives data-plane invocation only.
|
|
911
|
+
# Provisioning/version/endpoint/PassRole rights belong to Terraform's
|
|
912
|
+
# dedicated Harness lifecycle and never reach a chat Lambda.
|
|
893
913
|
#
|
|
894
914
|
# CRITICAL: never grant `bedrock-agentcore:InvokeAgentRuntimeCommand`
|
|
895
915
|
# anywhere — it bypasses Harness allowedTools enforcement. Invocation goes
|
|
896
916
|
# through InvokeHarness / InvokeAgentRuntime only.
|
|
897
|
-
var.
|
|
917
|
+
var.enable_agentcore_harness_invocation ? [
|
|
898
918
|
{
|
|
899
919
|
# Data plane — invoke a Harness (and its runtime endpoints) directly.
|
|
900
920
|
Sid = "AgentCoreHarnessInvoke"
|
|
@@ -903,45 +923,27 @@ locals {
|
|
|
903
923
|
"bedrock-agentcore:InvokeHarness",
|
|
904
924
|
"bedrock-agentcore:InvokeAgentRuntime",
|
|
905
925
|
]
|
|
906
|
-
Resource = "arn:aws:bedrock-agentcore:${var.region}:${var.account_id}:harness/*"
|
|
926
|
+
Resource = ["arn:aws:bedrock-agentcore:${var.region}:${var.account_id}:harness/*"]
|
|
907
927
|
},
|
|
908
928
|
{
|
|
909
|
-
#
|
|
910
|
-
#
|
|
911
|
-
#
|
|
912
|
-
|
|
913
|
-
Sid = "AgentCoreHarnessControl"
|
|
929
|
+
# The deterministic report adapter uses the same AgentCore Identity
|
|
930
|
+
# chain as Harness Gateway outbound auth: turn JWT -> workload token
|
|
931
|
+
# -> OBO Gateway token. No provider client secret enters Lambda.
|
|
932
|
+
Sid = "AgentCoreHarnessGatewayIdentity"
|
|
914
933
|
Effect = "Allow"
|
|
915
934
|
Action = [
|
|
916
|
-
"bedrock-agentcore:
|
|
917
|
-
"bedrock-agentcore:
|
|
918
|
-
"bedrock-agentcore:
|
|
919
|
-
"bedrock-agentcore:
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
"bedrock-agentcore:
|
|
923
|
-
"bedrock-agentcore:
|
|
924
|
-
"bedrock-agentcore:
|
|
935
|
+
"bedrock-agentcore:GetWorkloadAccessTokenForJWT",
|
|
936
|
+
"bedrock-agentcore:GetWorkloadAccessTokenForUserId",
|
|
937
|
+
"bedrock-agentcore:GetResourceOauth2Token",
|
|
938
|
+
"bedrock-agentcore:CompleteResourceTokenAuth",
|
|
939
|
+
]
|
|
940
|
+
Resource = [
|
|
941
|
+
"arn:aws:bedrock-agentcore:${var.region}:${var.account_id}:workload-identity-directory/default",
|
|
942
|
+
"arn:aws:bedrock-agentcore:${var.region}:${var.account_id}:workload-identity-directory/default/workload-identity/thinkwork-${var.stage}-multiplayer-proof",
|
|
943
|
+
"arn:aws:bedrock-agentcore:${var.region}:${var.account_id}:token-vault/default",
|
|
944
|
+
"arn:aws:bedrock-agentcore:${var.region}:${var.account_id}:token-vault/default/oauth2credentialprovider/thinkwork-${var.stage}-proof-oauth",
|
|
945
|
+
"arn:aws:bedrock-agentcore:${var.region}:${var.account_id}:token-vault/default/oauth2credentialprovider/thinkwork-${var.stage}-twenty-crm",
|
|
925
946
|
]
|
|
926
|
-
Resource = "*"
|
|
927
|
-
},
|
|
928
|
-
] : [],
|
|
929
|
-
# (Separate conditional from the two statements above only because the
|
|
930
|
-
# Condition attribute gives this object a different Terraform type —
|
|
931
|
-
# same gate, same feature.)
|
|
932
|
-
var.agentcore_harness_execution_role_arn != "" ? [
|
|
933
|
-
{
|
|
934
|
-
# CreateHarness takes executionRoleArn; the caller must be able to
|
|
935
|
-
# pass exactly that role, and only to the bedrock-agentcore service.
|
|
936
|
-
Sid = "AgentCoreHarnessPassExecutionRole"
|
|
937
|
-
Effect = "Allow"
|
|
938
|
-
Action = ["iam:PassRole"]
|
|
939
|
-
Resource = var.agentcore_harness_execution_role_arn
|
|
940
|
-
Condition = {
|
|
941
|
-
StringEquals = {
|
|
942
|
-
"iam:PassedToService" = "bedrock-agentcore.amazonaws.com"
|
|
943
|
-
}
|
|
944
|
-
}
|
|
945
947
|
},
|
|
946
948
|
] : [],
|
|
947
949
|
)
|
|
@@ -1040,6 +1042,33 @@ locals {
|
|
|
1040
1042
|
)
|
|
1041
1043
|
|
|
1042
1044
|
api_observability_statements = concat(local.api_observability_sqs_statements, [
|
|
1045
|
+
# Backend notification publishing is IAM-only. Scope the shared API
|
|
1046
|
+
# execution role to the NONE-resolver mutation fields; end-user identity-
|
|
1047
|
+
# pool credentials have no AppSync grant. This statement lives in the
|
|
1048
|
+
# observability envelope for size balance: adding subscription invalidation
|
|
1049
|
+
# pushed the data-plane policy over IAM's 6,144-character hard cap.
|
|
1050
|
+
{
|
|
1051
|
+
Sid = "PublishAppSyncNotifications"
|
|
1052
|
+
Effect = "Allow"
|
|
1053
|
+
Action = ["appsync:GraphQL"]
|
|
1054
|
+
Resource = [
|
|
1055
|
+
for field in [
|
|
1056
|
+
"notifyAgentStatus",
|
|
1057
|
+
"notifyNewMessage",
|
|
1058
|
+
"notifyHeartbeatActivity",
|
|
1059
|
+
"notifyThreadActivity",
|
|
1060
|
+
"notifyThreadUpdate",
|
|
1061
|
+
"notifyInboxItemUpdate",
|
|
1062
|
+
"notifyThreadTurnUpdate",
|
|
1063
|
+
"notifyThreadTurnStep",
|
|
1064
|
+
"notifyOrgUpdate",
|
|
1065
|
+
"notifyCostRecorded",
|
|
1066
|
+
"notifyEvalRunUpdate",
|
|
1067
|
+
"notifyWorkspaceAccessRevoked",
|
|
1068
|
+
"invalidateSubscription",
|
|
1069
|
+
] : "arn:aws:appsync:${var.region}:${var.account_id}:apis/${var.appsync_api_id}/types/Mutation/fields/${field}"
|
|
1070
|
+
]
|
|
1071
|
+
},
|
|
1043
1072
|
# (was inline policy "cloudwatch-logs-read")
|
|
1044
1073
|
{
|
|
1045
1074
|
Effect = "Allow"
|
|
@@ -1083,16 +1112,41 @@ locals {
|
|
|
1083
1112
|
Resource = "*"
|
|
1084
1113
|
},
|
|
1085
1114
|
])
|
|
1115
|
+
|
|
1116
|
+
api_grouped_policy_documents = {
|
|
1117
|
+
data_plane = jsonencode({
|
|
1118
|
+
Version = "2012-10-17"
|
|
1119
|
+
Statement = local.api_data_plane_statements
|
|
1120
|
+
})
|
|
1121
|
+
orchestration = jsonencode({
|
|
1122
|
+
Version = "2012-10-17"
|
|
1123
|
+
Statement = local.api_orchestration_statements
|
|
1124
|
+
})
|
|
1125
|
+
ai = jsonencode({
|
|
1126
|
+
Version = "2012-10-17"
|
|
1127
|
+
Statement = local.api_ai_statements
|
|
1128
|
+
})
|
|
1129
|
+
observability = jsonencode({
|
|
1130
|
+
Version = "2012-10-17"
|
|
1131
|
+
Statement = local.api_observability_statements
|
|
1132
|
+
})
|
|
1133
|
+
}
|
|
1134
|
+
}
|
|
1135
|
+
|
|
1136
|
+
check "api_grouped_managed_policy_sizes" {
|
|
1137
|
+
assert {
|
|
1138
|
+
condition = alltrue([
|
|
1139
|
+
for document in values(local.api_grouped_policy_documents) : length(document) <= 6144
|
|
1140
|
+
])
|
|
1141
|
+
error_message = "Each grouped API managed-policy document must remain within AWS IAM's 6,144-character limit."
|
|
1142
|
+
}
|
|
1086
1143
|
}
|
|
1087
1144
|
|
|
1088
1145
|
resource "aws_iam_policy" "api_data_plane" {
|
|
1089
1146
|
name = "thinkwork-${var.stage}-api-data-plane"
|
|
1090
1147
|
description = "Grouped data-plane grants (RDS Data API, Secrets Manager, S3, DynamoDB, Cognito, SSM, KMS-via-SSM, SQS) for the shared api Lambda role"
|
|
1091
1148
|
|
|
1092
|
-
policy =
|
|
1093
|
-
Version = "2012-10-17"
|
|
1094
|
-
Statement = local.api_data_plane_statements
|
|
1095
|
-
})
|
|
1149
|
+
policy = local.api_grouped_policy_documents.data_plane
|
|
1096
1150
|
}
|
|
1097
1151
|
|
|
1098
1152
|
resource "aws_iam_role_policy_attachment" "api_data_plane" {
|
|
@@ -1104,10 +1158,7 @@ resource "aws_iam_policy" "api_orchestration" {
|
|
|
1104
1158
|
name = "thinkwork-${var.stage}-api-orchestration"
|
|
1105
1159
|
description = "Grouped orchestration grants (Lambda invoke, EventBridge Scheduler, Step Functions, SES) for the shared api Lambda role"
|
|
1106
1160
|
|
|
1107
|
-
policy =
|
|
1108
|
-
Version = "2012-10-17"
|
|
1109
|
-
Statement = local.api_orchestration_statements
|
|
1110
|
-
})
|
|
1161
|
+
policy = local.api_grouped_policy_documents.orchestration
|
|
1111
1162
|
}
|
|
1112
1163
|
|
|
1113
1164
|
resource "aws_iam_role_policy_attachment" "api_orchestration" {
|
|
@@ -1119,10 +1170,7 @@ resource "aws_iam_policy" "api_ai" {
|
|
|
1119
1170
|
name = "thinkwork-${var.stage}-api-ai"
|
|
1120
1171
|
description = "Grouped AI grants (Bedrock invoke, Knowledge Bases, AgentCore memory/eval/code-interpreter) for the shared api Lambda role"
|
|
1121
1172
|
|
|
1122
|
-
policy =
|
|
1123
|
-
Version = "2012-10-17"
|
|
1124
|
-
Statement = local.api_ai_statements
|
|
1125
|
-
})
|
|
1173
|
+
policy = local.api_grouped_policy_documents.ai
|
|
1126
1174
|
}
|
|
1127
1175
|
|
|
1128
1176
|
resource "aws_iam_role_policy_attachment" "api_ai" {
|
|
@@ -1134,10 +1182,7 @@ resource "aws_iam_policy" "api_observability" {
|
|
|
1134
1182
|
name = "thinkwork-${var.stage}-api-observability"
|
|
1135
1183
|
description = "Grouped observability grants (CloudWatch Logs reads, ECS/ALB health reads) for the shared api Lambda role"
|
|
1136
1184
|
|
|
1137
|
-
policy =
|
|
1138
|
-
Version = "2012-10-17"
|
|
1139
|
-
Statement = local.api_observability_statements
|
|
1140
|
-
})
|
|
1185
|
+
policy = local.api_grouped_policy_documents.observability
|
|
1141
1186
|
}
|
|
1142
1187
|
|
|
1143
1188
|
resource "aws_iam_role_policy_attachment" "api_observability" {
|
|
@@ -73,6 +73,14 @@ resource "aws_apigatewayv2_stage" "default" {
|
|
|
73
73
|
throttling_burst_limit = 20
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
+
# Session revocation is authenticated and independently rate-limited in the
|
|
77
|
+
# handler per principal. This edge throttle also bounds aggregate abuse.
|
|
78
|
+
route_settings {
|
|
79
|
+
route_key = "POST /api/auth/revoke"
|
|
80
|
+
throttling_rate_limit = 5
|
|
81
|
+
throttling_burst_limit = 10
|
|
82
|
+
}
|
|
83
|
+
|
|
76
84
|
# UpdateStage 404s ("Unable to find Route by key … within the provided
|
|
77
85
|
# RouteSettings") if the stage update races the route creation — Terraform
|
|
78
86
|
# sees no reference edge between route_settings.route_key and the route
|
|
@@ -256,3 +264,19 @@ resource "aws_lambda_permission" "placeholder_apigw" {
|
|
|
256
264
|
principal = "apigateway.amazonaws.com"
|
|
257
265
|
source_arn = "${aws_apigatewayv2_api.main.execution_arn}/*/*"
|
|
258
266
|
}
|
|
267
|
+
resource "terraform_data" "auth_migration_recovery_deadline_guard" {
|
|
268
|
+
input = {
|
|
269
|
+
phase = var.auth_retirement_phase
|
|
270
|
+
deadline = var.auth_migration_recovery_deadline
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
lifecycle {
|
|
274
|
+
precondition {
|
|
275
|
+
condition = var.auth_retirement_phase != "coexistence" || (
|
|
276
|
+
trimspace(var.auth_migration_recovery_deadline) != "" &&
|
|
277
|
+
can(timecmp(var.auth_migration_recovery_deadline, var.auth_migration_recovery_deadline))
|
|
278
|
+
)
|
|
279
|
+
error_message = "auth_migration_recovery_deadline must be an RFC3339 timestamp when auth_retirement_phase is coexistence."
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
}
|
|
@@ -1,8 +1,185 @@
|
|
|
1
1
|
locals {
|
|
2
|
-
mcp_oauth_api_base_url
|
|
3
|
-
mcp_oauth_cognito_base_url
|
|
4
|
-
mcp_oauth_identity_providers
|
|
5
|
-
mcp_oauth_logo_path
|
|
2
|
+
mcp_oauth_api_base_url = "https://${aws_apigatewayv2_api.main.id}.execute-api.${var.region}.amazonaws.com"
|
|
3
|
+
mcp_oauth_cognito_base_url = var.cognito_auth_domain != "" ? "https://${var.cognito_auth_domain}.auth.${var.region}.amazoncognito.com" : ""
|
|
4
|
+
mcp_oauth_identity_providers = var.google_oauth_client_id != "" ? ["Google", "COGNITO"] : ["COGNITO"]
|
|
5
|
+
mcp_oauth_logo_path = "${path.module}/../../../../apps/web/public/logo.png"
|
|
6
|
+
agentcore_turn_assertion_issuer = "${local.mcp_oauth_api_base_url}/agentcore"
|
|
7
|
+
agentcore_harness_audience = "urn:thinkwork:${var.stage}:agentcore:harness"
|
|
8
|
+
agentcore_gateway_audience = "urn:thinkwork:${var.stage}:agentcore:gateway"
|
|
9
|
+
agentcore_turn_assertion_keys = {
|
|
10
|
+
for version, key in aws_kms_key.agentcore_turn_assertion : version => {
|
|
11
|
+
key_id = key.arn
|
|
12
|
+
# A version label alone is not globally unique: destroying and
|
|
13
|
+
# reprovisioning v1 creates different RSA material while downstream JWT
|
|
14
|
+
# validators may still cache the old public key under the same kid.
|
|
15
|
+
# Bind the kid to the immutable KMS key id so a reprovision is observed
|
|
16
|
+
# as a real key rotation instead of an invalid-signature outage.
|
|
17
|
+
kid = "thinkwork-${var.stage}-agentcore-turn-${version}-${substr(key.key_id, 0, 8)}"
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
agentcore_turn_assertion_active_key = try(
|
|
21
|
+
local.agentcore_turn_assertion_keys[var.agentcore_turn_assertion_active_key_version],
|
|
22
|
+
{ key_id = "", kid = "" },
|
|
23
|
+
)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
# THINK-316 U1: short-lived CUSTOM_JWT assertions are signed by KMS so private
|
|
27
|
+
# key material never enters Lambda configuration or process memory. The key
|
|
28
|
+
# policy is the capability boundary: the dedicated mint role can Sign, while
|
|
29
|
+
# the shared mcp-oauth role can only fetch the public key for JWKS publication.
|
|
30
|
+
resource "aws_iam_role" "turn_assertion_mint" {
|
|
31
|
+
count = var.enable_agentcore_multiplayer_proof ? 1 : 0
|
|
32
|
+
name = "thinkwork-${var.stage}-turn-assertion-mint-role"
|
|
33
|
+
|
|
34
|
+
assume_role_policy = jsonencode({
|
|
35
|
+
Version = "2012-10-17"
|
|
36
|
+
Statement = [{
|
|
37
|
+
Effect = "Allow"
|
|
38
|
+
Principal = { Service = "lambda.amazonaws.com" }
|
|
39
|
+
Action = "sts:AssumeRole"
|
|
40
|
+
}]
|
|
41
|
+
})
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
resource "aws_iam_role_policy_attachment" "turn_assertion_mint_basic" {
|
|
45
|
+
count = var.enable_agentcore_multiplayer_proof ? 1 : 0
|
|
46
|
+
role = aws_iam_role.turn_assertion_mint[0].name
|
|
47
|
+
policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
# The synthetic OAuth provider and boundary target are public proof surfaces
|
|
51
|
+
# but need no AWS data-plane permissions. A sibling logs-only role prevents a
|
|
52
|
+
# parser defect from inheriting the shared API role or its platform secrets.
|
|
53
|
+
resource "aws_iam_role" "agentcore_proof_boundary" {
|
|
54
|
+
count = var.enable_agentcore_multiplayer_proof ? 1 : 0
|
|
55
|
+
name = "thinkwork-${var.stage}-agentcore-proof-boundary-role"
|
|
56
|
+
|
|
57
|
+
assume_role_policy = jsonencode({
|
|
58
|
+
Version = "2012-10-17"
|
|
59
|
+
Statement = [{
|
|
60
|
+
Effect = "Allow"
|
|
61
|
+
Principal = { Service = "lambda.amazonaws.com" }
|
|
62
|
+
Action = "sts:AssumeRole"
|
|
63
|
+
}]
|
|
64
|
+
})
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
resource "aws_iam_role_policy_attachment" "agentcore_proof_boundary_basic" {
|
|
68
|
+
count = var.enable_agentcore_multiplayer_proof ? 1 : 0
|
|
69
|
+
role = aws_iam_role.agentcore_proof_boundary[0].name
|
|
70
|
+
policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
# The token-exchange provider is the only proof boundary allowed to mint the
|
|
74
|
+
# derived Gateway assertion. Keep that capability off the public target role.
|
|
75
|
+
resource "aws_iam_role" "agentcore_proof_provider" {
|
|
76
|
+
count = var.enable_agentcore_multiplayer_proof ? 1 : 0
|
|
77
|
+
name = "thinkwork-${var.stage}-agentcore-proof-provider-role"
|
|
78
|
+
|
|
79
|
+
assume_role_policy = jsonencode({
|
|
80
|
+
Version = "2012-10-17"
|
|
81
|
+
Statement = [{
|
|
82
|
+
Effect = "Allow"
|
|
83
|
+
Principal = { Service = "lambda.amazonaws.com" }
|
|
84
|
+
Action = "sts:AssumeRole"
|
|
85
|
+
}]
|
|
86
|
+
})
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
resource "aws_iam_role_policy_attachment" "agentcore_proof_provider_basic" {
|
|
90
|
+
count = var.enable_agentcore_multiplayer_proof ? 1 : 0
|
|
91
|
+
role = aws_iam_role.agentcore_proof_provider[0].name
|
|
92
|
+
policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
resource "aws_iam_role_policy" "agentcore_proof_provider_kms" {
|
|
96
|
+
count = var.enable_agentcore_multiplayer_proof ? 1 : 0
|
|
97
|
+
name = "thinkwork-${var.stage}-agentcore-proof-provider-key"
|
|
98
|
+
role = aws_iam_role.agentcore_proof_provider[0].id
|
|
99
|
+
|
|
100
|
+
policy = jsonencode({
|
|
101
|
+
Version = "2012-10-17"
|
|
102
|
+
Statement = [{
|
|
103
|
+
Effect = "Allow"
|
|
104
|
+
Action = ["kms:Sign"]
|
|
105
|
+
Resource = [local.agentcore_turn_assertion_active_key.key_id]
|
|
106
|
+
Condition = {
|
|
107
|
+
StringEquals = {
|
|
108
|
+
"kms:SigningAlgorithm" = "RSASSA_PKCS1_V1_5_SHA_256"
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}]
|
|
112
|
+
})
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
resource "aws_kms_key" "agentcore_turn_assertion" {
|
|
116
|
+
for_each = var.enable_agentcore_multiplayer_proof ? toset(var.agentcore_turn_assertion_key_versions) : toset([])
|
|
117
|
+
|
|
118
|
+
description = "ThinkWork ${var.stage} AgentCore per-turn assertion signing ${each.key}"
|
|
119
|
+
key_usage = "SIGN_VERIFY"
|
|
120
|
+
customer_master_key_spec = "RSA_2048"
|
|
121
|
+
deletion_window_in_days = 7
|
|
122
|
+
|
|
123
|
+
policy = jsonencode({
|
|
124
|
+
Version = "2012-10-17"
|
|
125
|
+
Statement = [
|
|
126
|
+
{
|
|
127
|
+
Sid = "AccountAdministration"
|
|
128
|
+
Effect = "Allow"
|
|
129
|
+
Principal = { AWS = "arn:aws:iam::${var.account_id}:root" }
|
|
130
|
+
Action = "kms:*"
|
|
131
|
+
Resource = "*"
|
|
132
|
+
},
|
|
133
|
+
]
|
|
134
|
+
})
|
|
135
|
+
|
|
136
|
+
tags = {
|
|
137
|
+
Name = "thinkwork-${var.stage}-agentcore-turn-assertion-${each.key}"
|
|
138
|
+
KeyVersion = each.key
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
resource "aws_kms_alias" "agentcore_turn_assertion" {
|
|
143
|
+
for_each = aws_kms_key.agentcore_turn_assertion
|
|
144
|
+
name = "alias/thinkwork-${var.stage}-agentcore-turn-assertion-${each.key}"
|
|
145
|
+
target_key_id = each.value.key_id
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
# The mint role can sign with exactly the active key. The public discovery
|
|
149
|
+
# handler can read all currently published public keys, but can never sign.
|
|
150
|
+
resource "aws_iam_role_policy" "turn_assertion_mint_kms" {
|
|
151
|
+
count = var.enable_agentcore_multiplayer_proof ? 1 : 0
|
|
152
|
+
name = "thinkwork-${var.stage}-turn-assertion-active-key"
|
|
153
|
+
role = aws_iam_role.turn_assertion_mint[0].id
|
|
154
|
+
|
|
155
|
+
policy = jsonencode({
|
|
156
|
+
Version = "2012-10-17"
|
|
157
|
+
Statement = [{
|
|
158
|
+
Effect = "Allow"
|
|
159
|
+
Action = ["kms:Sign"]
|
|
160
|
+
Resource = [local.agentcore_turn_assertion_active_key.key_id]
|
|
161
|
+
Condition = {
|
|
162
|
+
StringEquals = {
|
|
163
|
+
"kms:SigningAlgorithm" = "RSASSA_PKCS1_V1_5_SHA_256"
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}]
|
|
167
|
+
})
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
resource "aws_iam_role_policy" "turn_assertion_jwks_kms" {
|
|
171
|
+
count = var.enable_agentcore_multiplayer_proof ? 1 : 0
|
|
172
|
+
name = "thinkwork-${var.stage}-turn-assertion-published-keys"
|
|
173
|
+
role = aws_iam_role.lambda.id
|
|
174
|
+
|
|
175
|
+
policy = jsonencode({
|
|
176
|
+
Version = "2012-10-17"
|
|
177
|
+
Statement = [{
|
|
178
|
+
Effect = "Allow"
|
|
179
|
+
Action = ["kms:GetPublicKey"]
|
|
180
|
+
Resource = [for key in values(local.agentcore_turn_assertion_keys) : key.key_id]
|
|
181
|
+
}]
|
|
182
|
+
})
|
|
6
183
|
}
|
|
7
184
|
|
|
8
185
|
resource "aws_dynamodb_table" "mcp_oauth_revocations" {
|
|
@@ -8,6 +8,41 @@ output "api_endpoint" {
|
|
|
8
8
|
value = local.api_base_url
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
+
output "agentcore_turn_assertion_issuer" {
|
|
12
|
+
description = "Proof-only CUSTOM_JWT issuer on the regional HTTP API."
|
|
13
|
+
value = var.enable_agentcore_multiplayer_proof ? local.agentcore_turn_assertion_issuer : ""
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
output "agentcore_harness_audience" {
|
|
17
|
+
description = "Purpose-bound audience for proof Harness invocations."
|
|
18
|
+
value = var.enable_agentcore_multiplayer_proof ? local.agentcore_harness_audience : ""
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
output "agentcore_gateway_audience" {
|
|
22
|
+
description = "Purpose-bound audience for proof Gateway operations."
|
|
23
|
+
value = var.enable_agentcore_multiplayer_proof ? local.agentcore_gateway_audience : ""
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
output "agentcore_turn_assertion_active_key_arn" {
|
|
27
|
+
description = "Operator-only active proof signing key ARN used by deployed verification probes."
|
|
28
|
+
value = var.enable_agentcore_multiplayer_proof ? local.agentcore_turn_assertion_active_key.key_id : ""
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
output "agentcore_turn_assertion_active_kid" {
|
|
32
|
+
description = "Public JWKS key identifier for the active proof signing key."
|
|
33
|
+
value = var.enable_agentcore_multiplayer_proof ? local.agentcore_turn_assertion_active_key.kid : ""
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
output "agentcore_proof_oauth_issuer" {
|
|
37
|
+
description = "Synthetic proof OAuth issuer on the regional HTTP API."
|
|
38
|
+
value = var.enable_agentcore_multiplayer_proof ? "${local.mcp_oauth_api_base_url}/agentcore-proof/oauth" : ""
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
output "agentcore_proof_target_base_url" {
|
|
42
|
+
description = "Regional HTTP API base URL hosting the controlled identity target."
|
|
43
|
+
value = var.enable_agentcore_multiplayer_proof ? local.mcp_oauth_api_base_url : ""
|
|
44
|
+
}
|
|
45
|
+
|
|
11
46
|
output "api_execution_arn" {
|
|
12
47
|
description = "API Gateway V2 execution ARN (for Lambda permissions)"
|
|
13
48
|
value = aws_apigatewayv2_api.main.execution_arn
|
|
@@ -51,9 +51,9 @@ locals {
|
|
|
51
51
|
# ----------------------------------------------------------------------------
|
|
52
52
|
# Platform secrets (plan 2026-06-11-006 U5/R4)
|
|
53
53
|
#
|
|
54
|
-
# API_AUTH_SECRET
|
|
55
|
-
#
|
|
56
|
-
#
|
|
54
|
+
# API_AUTH_SECRET leaves plaintext Lambda env: the runtime-config loader
|
|
55
|
+
# prefetches it at cold start (getApiAuthSecret, env-wins during the transition
|
|
56
|
+
# window). Names
|
|
57
57
|
# use the `thinkwork/${stage}/...` prefix so the shared role's existing
|
|
58
58
|
# `secretsmanager:GetSecretValue` grant on `thinkwork/*` covers them.
|
|
59
59
|
# The env copies in common_env are dropped one release AFTER this ships
|
|
@@ -83,24 +83,6 @@ resource "aws_secretsmanager_secret_version" "api_auth" {
|
|
|
83
83
|
# console.
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
-
resource "aws_secretsmanager_secret" "appsync_api_key" {
|
|
87
|
-
name = "thinkwork/${var.stage}/appsync-api-key"
|
|
88
|
-
description = "AppSync API key for subscription notify fan-out. Prefetched at Lambda cold start by @thinkwork/runtime-config."
|
|
89
|
-
tags = {
|
|
90
|
-
Name = "thinkwork-${var.stage}-appsync-api-key"
|
|
91
|
-
Stage = var.stage
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
resource "aws_secretsmanager_secret_version" "appsync_api_key" {
|
|
96
|
-
secret_id = aws_secretsmanager_secret.appsync_api_key.id
|
|
97
|
-
secret_string = var.appsync_api_key
|
|
98
|
-
|
|
99
|
-
# AppSync keys are terraform-rotated (the appsync module recreates them),
|
|
100
|
-
# so track the var here — unlike api_auth there is no operator rotation
|
|
101
|
-
# path outside terraform.
|
|
102
|
-
}
|
|
103
|
-
|
|
104
86
|
# The standalone compliance Lambdas (anchor, export-runner) bundle the
|
|
105
87
|
# runtime-config loader but run under dedicated roles that lack the shared
|
|
106
88
|
# role's ssm grant. Without these, every cold start auto-prime fails
|