thinkwork-cli 0.12.15 → 0.12.17
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-4VT3FWOH.js → api-client-JUBCQQDF.js} +1 -1
- package/dist/{chunk-H7AB42ES.js → chunk-STY44FQO.js} +13 -0
- package/dist/cli.js +1107 -10225
- package/dist/commands/enterprise/templates/deploy-repo/docs/runbook.md +3 -8
- package/dist/commands/enterprise/templates/deploy-repo/terraform/main.tf +1 -184
- package/dist/drizzle/0050_brain_v0_entity_subtype.sql +2 -2
- package/dist/drizzle/0051_brain_v0_tenant_entity_pages.sql +6 -6
- package/dist/drizzle/0052_brain_v0_external_refs.sql +2 -2
- package/dist/drizzle/0053_brain_v0_unresolved_mentions_subtype.sql +2 -2
- package/dist/drizzle/0145_knowledge_graph_thread_ingest.sql +14 -14
- package/dist/drizzle/0146_knowledge_graph_source_scope.sql +1 -1
- package/dist/drizzle/0157_knowledge_graph_observations_source.sql +2 -2
- package/dist/drizzle/0158_wiki_tenant_scope.sql +1 -1
- package/dist/drizzle/0165_plugin_premium_entitlements.sql +2 -2
- package/dist/drizzle/{0166_company_brain_substrate_contract.sql → 0166_brain_substrate_contract.sql} +9 -9
- package/dist/drizzle/{0167_company_brain_artifact_manifest_runtime.sql → 0167_brain_artifact_manifest_runtime.sql} +5 -5
- package/dist/drizzle/0168_eval_skill_gate.sql +1 -1
- package/dist/drizzle/0183_okf_artifact_manifests.sql +1 -1
- package/dist/drizzle/0197_rcm_context_columns.sql +28 -0
- package/dist/drizzle/0200_eval_results_execution_tier.sql +40 -0
- package/dist/drizzle/0201_brain_dream_runs.sql +72 -0
- package/dist/drizzle/0202_backfill_thread_participants_from_senders.sql +110 -0
- package/dist/drizzle/0203_threads_mode_override.sql +61 -0
- package/dist/drizzle/0204_thread_turns_triggering_message_id.sql +48 -0
- package/dist/drizzle/0205_routines_git_python.sql +185 -0
- package/dist/drizzle/0206_agent_loop_versions_routine_actions.sql +40 -0
- package/dist/drizzle/0207_tenant_credentials_github_repo_kind.sql +52 -0
- package/dist/drizzle/0208_knowledge_graph_neutral_identifiers.sql +253 -0
- package/dist/drizzle/0209_living_artifacts_schema.sql +109 -0
- package/dist/drizzle/0210_think137_automations_additive_schema.sql +113 -0
- package/dist/drizzle/0211_backfill_agent_loop_versions_target_spec.sql +120 -0
- package/dist/drizzle/0212_fold_webhooks_into_automations.sql +312 -0
- package/dist/drizzle/0213_agent_loop_versions_judge_evidence_nullable.sql +63 -0
- package/dist/drizzle/0214_think137_drop_judge_evidence_roi.sql +99 -0
- package/dist/drizzle/0215_agent_loop_versions_goal_worker_policy_nullable.sql +70 -0
- package/dist/drizzle/0216_drop_agent_loop_versions_goal_worker_policy.sql +81 -0
- package/dist/drizzle/0217_agents_capability_folder_dispatch.sql +12 -0
- package/dist/drizzle/0218_document_plates.sql +30 -0
- package/dist/drizzle/0219_document_section_waivers.sql +29 -0
- package/dist/drizzle/0220_artifacts_created_by_user.sql +21 -0
- package/dist/drizzle/0221_artifact_shares.sql +29 -0
- package/dist/drizzle/0221_workflow_interpreter_thin_slice.sql +71 -0
- package/dist/drizzle/0222_compliance_drainer_select_audit_events.sql +21 -0
- package/dist/drizzle/0223_document_conformance_reports.sql +38 -0
- package/dist/drizzle/0224_artifact_refresh_state.sql +11 -0
- package/dist/drizzle/0225_think216_agent_loop_convergence.sql +21 -0
- package/dist/drizzle/0226_drop_n8n_agent_step_runs.sql +6 -0
- package/dist/drizzle/0227_analyst_reader_role.sql +1055 -0
- package/dist/drizzle/0228_tenant_credentials_rds_iam_kind.sql +62 -0
- package/dist/drizzle/0229_analyst_reader_rds_iam_grant.sql +79 -0
- package/dist/drizzle/0230_analyst_rls.sql +1613 -0
- package/dist/drizzle/0231_cost_events_cache_write_enforcement_exempt.sql +11 -0
- package/dist/plugins/catalog/package.json +0 -1
- package/dist/plugins/catalog/src/__tests__/build-catalog.test.ts +0 -1
- package/dist/plugins/catalog/src/__tests__/catalog.test.ts +16 -8
- package/dist/plugins/catalog/src/__tests__/contracts.test.ts +56 -0
- 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 +112 -0
- package/dist/plugins/catalog/src/registry/generated-first-party.ts +0 -6
- package/dist/plugins/n8n/README.md +4 -36
- package/dist/plugins/n8n/src/deployment/managed-app.ts +0 -17
- package/dist/plugins/n8n/src/manifest.ts +0 -5
- package/dist/plugins/n8n/terraform/n8n/main.tf +0 -26
- package/dist/plugins/n8n/terraform/n8n/outputs.tf +0 -5
- package/dist/plugins/n8n/terraform/n8n/variables.tf +0 -6
- package/dist/plugins/n8n/test/manifest.test.ts +0 -1
- package/dist/plugins/twenty/package.json +5 -0
- package/dist/plugins/twenty/scripts/lib/__tests__/load-records.test.ts +232 -0
- package/dist/plugins/twenty/scripts/lib/__tests__/mappers.test.ts +489 -0
- package/dist/plugins/twenty/scripts/lib/__tests__/members-ensure.test.ts +199 -0
- package/dist/plugins/twenty/scripts/lib/__tests__/provision-members-db.test.ts +43 -0
- package/dist/plugins/twenty/scripts/lib/__tests__/schema-ensure.test.ts +230 -0
- package/dist/plugins/twenty/scripts/lib/__tests__/twenty-client.test.ts +207 -0
- package/dist/plugins/twenty/scripts/lib/lastmile-reader.ts +282 -0
- package/dist/plugins/twenty/scripts/lib/load-attachments.ts +220 -0
- package/dist/plugins/twenty/scripts/lib/load-records.ts +680 -0
- package/dist/plugins/twenty/scripts/lib/mappers.ts +559 -0
- package/dist/plugins/twenty/scripts/lib/members-ensure.ts +381 -0
- package/dist/plugins/twenty/scripts/lib/provision-members-db.ts +191 -0
- package/dist/plugins/twenty/scripts/lib/schema-ensure.ts +425 -0
- package/dist/plugins/twenty/scripts/lib/twenty-client.ts +246 -0
- package/dist/plugins/twenty/scripts/migrate-lastmile.ts +610 -0
- package/dist/plugins/twenty/scripts/provision-twenty-members.ts +214 -0
- package/dist/plugins/twenty/src/manifest.ts +99 -0
- package/dist/plugins/twenty/terraform/twenty/README.md +1 -1
- package/dist/plugins/twenty/test/manifest.test.ts +12 -2
- package/dist/terraform/examples/greenfield/main.tf +90 -380
- package/dist/terraform/examples/greenfield/terraform.tfvars.example +0 -1
- package/dist/terraform/modules/app/agentcore-pi/README.md +1 -3
- package/dist/terraform/modules/app/agentcore-pi/main.tf +36 -32
- package/dist/terraform/modules/app/agentcore-pi/variables.tf +23 -15
- package/dist/terraform/modules/app/agentcore-runtime/main.tf +3 -3
- package/dist/terraform/modules/app/customer-domain/main.tf +16 -2
- package/dist/terraform/modules/app/deployment-control-plane/main.tf +5 -0
- package/dist/terraform/modules/app/deployment-control-plane/runner.py +85 -207
- package/dist/terraform/modules/app/deployment-control-plane/test_runner_bundle.py +56 -2
- package/dist/terraform/modules/app/hindsight-memory/main.tf +52 -4
- package/dist/terraform/modules/app/lambda-api/eval-fanout.tf +7 -0
- package/dist/terraform/modules/app/lambda-api/handlers.tf +493 -89
- package/dist/terraform/modules/app/lambda-api/iam-grouped.tf +215 -96
- package/dist/terraform/modules/app/lambda-api/main.tf +24 -5
- package/dist/terraform/modules/app/lambda-api/outputs.tf +19 -11
- package/dist/terraform/modules/app/lambda-api/variables.tf +94 -67
- package/dist/terraform/modules/app/ses-email/main.tf +14 -2
- package/dist/terraform/modules/app/workflow-interpreter-stepfunctions/main.tf +493 -0
- package/dist/terraform/modules/app/workflow-interpreter-stepfunctions/outputs.tf +34 -0
- package/dist/terraform/modules/app/workflow-interpreter-stepfunctions/variables.tf +32 -0
- package/dist/terraform/modules/data/aurora-postgres/main.tf +55 -0
- package/dist/terraform/modules/data/aurora-postgres/outputs.tf +15 -0
- package/dist/terraform/modules/data/s3-buckets/main.tf +26 -0
- package/dist/terraform/modules/thinkwork/README.md +0 -1
- package/dist/terraform/modules/thinkwork/main.tf +167 -446
- package/dist/terraform/modules/thinkwork/outputs.tf +2 -142
- package/dist/terraform/modules/thinkwork/variables.tf +55 -309
- package/dist/terraform/schema.graphql +4 -0
- package/dist/workspace-defaults/files/AGENTS.md +45 -31
- package/dist/workspace-defaults/files/CONTEXT.md +48 -4
- package/dist/workspace-defaults/files/GUARDRAILS.md +18 -0
- package/dist/workspace-defaults/files/MEMORY_GUIDE.md +32 -4
- package/dist/workspace-defaults/files/SPACE.md +34 -19
- package/dist/workspace-defaults/files/TOOLS.md +30 -0
- package/dist/workspace-defaults/files/skills/document-composer/SKILL.md +154 -0
- package/dist/workspace-defaults/files/skills/document-composer/references/authoring-rules.md +101 -0
- package/package.json +2 -1
- package/dist/plugins/company-brain/README.md +0 -37
- package/dist/plugins/company-brain/package.json +0 -33
- package/dist/plugins/company-brain/runtime/cognee/Dockerfile +0 -11
- package/dist/plugins/company-brain/smoke/cognee-managed-app-smoke.mjs +0 -458
- package/dist/plugins/company-brain/smoke/cognee-memory-cutover-smoke.mjs +0 -539
- package/dist/plugins/company-brain/smoke/company-brain-context-engine-smoke.mjs +0 -312
- package/dist/plugins/company-brain/smoke/company-brain-operations-smoke.mjs +0 -449
- package/dist/plugins/company-brain/smoke/company-brain-plugin-smoke.mjs +0 -655
- package/dist/plugins/company-brain/smoke/hindsight-memory-isolation-smoke.mjs +0 -474
- package/dist/plugins/company-brain/src/api/cognee-client.ts +0 -896
- package/dist/plugins/company-brain/src/api/cognee-cluster-identity.ts +0 -49
- package/dist/plugins/company-brain/src/api/cognee-memory-scope.ts +0 -84
- package/dist/plugins/company-brain/src/api/context-engine-provider.ts +0 -888
- package/dist/plugins/company-brain/src/api/migration.ts +0 -665
- package/dist/plugins/company-brain/src/deployment/cognee-managed-app.ts +0 -396
- package/dist/plugins/company-brain/src/index.ts +0 -62
- package/dist/plugins/company-brain/src/manifest.ts +0 -112
- package/dist/plugins/company-brain/terraform/cognee/README.md +0 -263
- package/dist/plugins/company-brain/terraform/cognee/main.tf +0 -766
- package/dist/plugins/company-brain/terraform/cognee/outputs.tf +0 -144
- package/dist/plugins/company-brain/terraform/cognee/variables.tf +0 -402
- package/dist/plugins/company-brain/test/api/cognee-client.test.ts +0 -562
- package/dist/plugins/company-brain/test/api/cognee-memory-scope.test.ts +0 -74
- package/dist/plugins/company-brain/test/api/context-engine-provider.test.ts +0 -447
- package/dist/plugins/company-brain/test/api/migration.test.ts +0 -465
- package/dist/plugins/company-brain/test/manifest.test.ts +0 -95
- package/dist/plugins/company-brain/tsconfig.json +0 -8
|
@@ -0,0 +1,493 @@
|
|
|
1
|
+
################################################################################
|
|
2
|
+
# Workflow Interpreter Step Functions — App Module (stage-level)
|
|
3
|
+
#
|
|
4
|
+
# ONE static Step Functions Standard state machine per stage interprets every
|
|
5
|
+
# ThinkWork workflow definition (THINK-219). Unlike the routines substrate —
|
|
6
|
+
# which mints a state machine per routine at runtime — the interpreter is a
|
|
7
|
+
# fixed loop that lives entirely in this module:
|
|
8
|
+
#
|
|
9
|
+
# LoadNextStep (Lambda) -> Choice on directive -> dispatch
|
|
10
|
+
# (waitForTaskToken for agent/approval, Wait with TimestampPath for wait)
|
|
11
|
+
# -> RecordAdvance -> Choice (loop / rollover / terminal).
|
|
12
|
+
#
|
|
13
|
+
# SFN state carries ONLY a cursor {workflowRunId, tenantId, stepPointer,
|
|
14
|
+
# iteration, loopCycleCount}; all step results live in Postgres, so the 256KB
|
|
15
|
+
# payload cap is a non-issue by construction (KTD1). Rollover self-restarts the
|
|
16
|
+
# machine at loop-cycle thresholds via a fire-and-forget states:startExecution
|
|
17
|
+
# so the ~1,400-event history ceiling is never hit (KTD6).
|
|
18
|
+
#
|
|
19
|
+
# **Fresh module name.** This deliberately does NOT reclaim the empty
|
|
20
|
+
# `system-workflows-stepfunctions/` directory — that is the tombstone of the
|
|
21
|
+
# System Workflows subsystem destroyed 2026-05-06 (#871); re-attaching the
|
|
22
|
+
# retired name would confuse state history.
|
|
23
|
+
#
|
|
24
|
+
# **Tenant isolation is application-layer for the shared role (KTD9).** Matching
|
|
25
|
+
# the routines substrate reality, one shared execution role serves the single
|
|
26
|
+
# machine; the step-dispatch Lambda re-asserts tenant_id from the run row on
|
|
27
|
+
# every invocation. Accepted v1 posture — no per-tenant tags, no ABAC.
|
|
28
|
+
################################################################################
|
|
29
|
+
|
|
30
|
+
terraform {
|
|
31
|
+
required_providers {
|
|
32
|
+
aws = {
|
|
33
|
+
source = "hashicorp/aws"
|
|
34
|
+
version = ">= 5.0"
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
locals {
|
|
40
|
+
state_machine_name = "thinkwork-${var.stage}-workflow-interpreter"
|
|
41
|
+
log_group_name = "/aws/vendedlogs/states/thinkwork-${var.stage}-workflow-interpreter"
|
|
42
|
+
role_name = "thinkwork-${var.stage}-workflow-interpreter-execution-role"
|
|
43
|
+
|
|
44
|
+
# Constructed (not resource-referenced) to avoid a cycle: the state machine's
|
|
45
|
+
# ARN is deterministic from name/region/account, so the execution role can
|
|
46
|
+
# grant states:StartExecution on its OWN machine without a self-reference.
|
|
47
|
+
state_machine_arn = "arn:aws:states:${var.region}:${var.account_id}:stateMachine:${local.state_machine_name}"
|
|
48
|
+
|
|
49
|
+
# Single Lambda serves all interpreter phases (load_next, dispatch_agent,
|
|
50
|
+
# await_approval, record_approval, record_advance). Constructed by string to
|
|
51
|
+
# avoid a chicken-and-egg with the lambda-api module.
|
|
52
|
+
step_dispatch_lambda_arn = "arn:aws:lambda:${var.region}:${var.account_id}:function:thinkwork-${var.stage}-api-workflow-step-dispatch"
|
|
53
|
+
|
|
54
|
+
# Retry applied to every synchronous lambda:invoke Task (transient
|
|
55
|
+
# service/SDK faults only — application errors surface, they do not retry).
|
|
56
|
+
lambda_invoke_retry = [{
|
|
57
|
+
ErrorEquals = [
|
|
58
|
+
"Lambda.ServiceException",
|
|
59
|
+
"Lambda.AWSLambdaException",
|
|
60
|
+
"Lambda.SdkClientException",
|
|
61
|
+
"Lambda.TooManyRequestsException",
|
|
62
|
+
]
|
|
63
|
+
IntervalSeconds = 2
|
|
64
|
+
MaxAttempts = 3
|
|
65
|
+
BackoffRate = 2
|
|
66
|
+
}]
|
|
67
|
+
|
|
68
|
+
ssm_state_machine_arn_param = "/thinkwork/${var.stage}/workflow-interpreter/state-machine-arn"
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
################################################################################
|
|
72
|
+
# CloudWatch Log Group — vendedlogs prefix dodges the resource-policy size cap.
|
|
73
|
+
################################################################################
|
|
74
|
+
|
|
75
|
+
resource "aws_cloudwatch_log_group" "interpreter" {
|
|
76
|
+
name = local.log_group_name
|
|
77
|
+
retention_in_days = var.log_retention_days
|
|
78
|
+
|
|
79
|
+
tags = {
|
|
80
|
+
Name = local.log_group_name
|
|
81
|
+
Stage = var.stage
|
|
82
|
+
Purpose = "step-functions-workflow-interpreter"
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
################################################################################
|
|
87
|
+
# Step Functions Execution Role — single shared role for the one machine.
|
|
88
|
+
# Trust: states.amazonaws.com, scoped by aws:SourceAccount.
|
|
89
|
+
################################################################################
|
|
90
|
+
|
|
91
|
+
resource "aws_iam_role" "execution" {
|
|
92
|
+
name = local.role_name
|
|
93
|
+
|
|
94
|
+
assume_role_policy = jsonencode({
|
|
95
|
+
Version = "2012-10-17"
|
|
96
|
+
Statement = [{
|
|
97
|
+
Effect = "Allow"
|
|
98
|
+
Principal = { Service = "states.amazonaws.com" }
|
|
99
|
+
Action = "sts:AssumeRole"
|
|
100
|
+
Condition = {
|
|
101
|
+
StringEquals = {
|
|
102
|
+
"aws:SourceAccount" = var.account_id
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}]
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
tags = {
|
|
109
|
+
Name = local.role_name
|
|
110
|
+
Stage = var.stage
|
|
111
|
+
Purpose = "step-functions-workflow-interpreter-execution"
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
# CloudWatch Logs delivery + X-Ray. Step Functions requires these to populate
|
|
116
|
+
# execution history into the vendedlogs prefix.
|
|
117
|
+
resource "aws_iam_role_policy" "execution_logs" {
|
|
118
|
+
name = "logs-and-xray"
|
|
119
|
+
role = aws_iam_role.execution.id
|
|
120
|
+
|
|
121
|
+
policy = jsonencode({
|
|
122
|
+
Version = "2012-10-17"
|
|
123
|
+
Statement = [
|
|
124
|
+
{
|
|
125
|
+
Effect = "Allow"
|
|
126
|
+
Action = [
|
|
127
|
+
"logs:CreateLogDelivery",
|
|
128
|
+
"logs:GetLogDelivery",
|
|
129
|
+
"logs:UpdateLogDelivery",
|
|
130
|
+
"logs:DeleteLogDelivery",
|
|
131
|
+
"logs:ListLogDeliveries",
|
|
132
|
+
"logs:PutResourcePolicy",
|
|
133
|
+
"logs:DescribeResourcePolicies",
|
|
134
|
+
"logs:DescribeLogGroups",
|
|
135
|
+
]
|
|
136
|
+
Resource = "*"
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
Effect = "Allow"
|
|
140
|
+
Action = [
|
|
141
|
+
"logs:CreateLogStream",
|
|
142
|
+
"logs:PutLogEvents",
|
|
143
|
+
]
|
|
144
|
+
Resource = "${aws_cloudwatch_log_group.interpreter.arn}:*"
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
Effect = "Allow"
|
|
148
|
+
Action = [
|
|
149
|
+
"xray:PutTraceSegments",
|
|
150
|
+
"xray:PutTelemetryRecords",
|
|
151
|
+
"xray:GetSamplingRules",
|
|
152
|
+
"xray:GetSamplingTargets",
|
|
153
|
+
]
|
|
154
|
+
Resource = "*"
|
|
155
|
+
},
|
|
156
|
+
]
|
|
157
|
+
})
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
# Lambda invocation — scoped to the single interpreter step-dispatch Lambda,
|
|
161
|
+
# which serves every ASL phase. The Lambda itself re-asserts tenant_id from the
|
|
162
|
+
# run row, so no ABAC is layered here.
|
|
163
|
+
resource "aws_iam_role_policy" "execution_lambda_invoke" {
|
|
164
|
+
name = "lambda-invoke-step-dispatch"
|
|
165
|
+
role = aws_iam_role.execution.id
|
|
166
|
+
|
|
167
|
+
policy = jsonencode({
|
|
168
|
+
Version = "2012-10-17"
|
|
169
|
+
Statement = [{
|
|
170
|
+
Effect = "Allow"
|
|
171
|
+
Action = ["lambda:InvokeFunction"]
|
|
172
|
+
Resource = [local.step_dispatch_lambda_arn]
|
|
173
|
+
}]
|
|
174
|
+
})
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
# Step Functions self-invocation (rollover continue-as-new via RolloverStart's
|
|
178
|
+
# fire-and-forget states:startExecution) plus task-token completion. The
|
|
179
|
+
# self-reference uses the constructed ARN (local.state_machine_arn) rather than
|
|
180
|
+
# the resource attribute to avoid a definition<->role dependency cycle.
|
|
181
|
+
#
|
|
182
|
+
# Application-layer tenant isolation (KTD9): the shared role has no tenantId
|
|
183
|
+
# principal tag; tenant scoping lives in the step-dispatch Lambda + the run row.
|
|
184
|
+
resource "aws_iam_role_policy" "execution_states" {
|
|
185
|
+
name = "states-self-invoke"
|
|
186
|
+
role = aws_iam_role.execution.id
|
|
187
|
+
|
|
188
|
+
policy = jsonencode({
|
|
189
|
+
Version = "2012-10-17"
|
|
190
|
+
Statement = [
|
|
191
|
+
{
|
|
192
|
+
Effect = "Allow"
|
|
193
|
+
Action = ["states:StartExecution"]
|
|
194
|
+
Resource = local.state_machine_arn
|
|
195
|
+
},
|
|
196
|
+
{
|
|
197
|
+
Effect = "Allow"
|
|
198
|
+
Action = [
|
|
199
|
+
"states:SendTaskSuccess",
|
|
200
|
+
"states:SendTaskFailure",
|
|
201
|
+
"states:SendTaskHeartbeat",
|
|
202
|
+
]
|
|
203
|
+
Resource = "*"
|
|
204
|
+
},
|
|
205
|
+
]
|
|
206
|
+
})
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
################################################################################
|
|
210
|
+
# The one static interpreter state machine (Standard).
|
|
211
|
+
#
|
|
212
|
+
# See KTD1 for the loop shape. Directives are the FROZEN protocol the
|
|
213
|
+
# step-dispatch Lambda emits: dispatch_agent, wait_until, execute_step,
|
|
214
|
+
# await_approval, continue, rollover, terminal_success, terminal_failure,
|
|
215
|
+
# terminal_canceled.
|
|
216
|
+
################################################################################
|
|
217
|
+
|
|
218
|
+
resource "aws_sfn_state_machine" "interpreter" {
|
|
219
|
+
name = local.state_machine_name
|
|
220
|
+
role_arn = aws_iam_role.execution.arn
|
|
221
|
+
|
|
222
|
+
logging_configuration {
|
|
223
|
+
include_execution_data = false
|
|
224
|
+
level = "ALL"
|
|
225
|
+
log_destination = "${aws_cloudwatch_log_group.interpreter.arn}:*"
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
definition = jsonencode({
|
|
229
|
+
Comment = "ThinkWork Workflow Interpreter — one static loop per stage. DB is source of truth; SFN state carries only a cursor."
|
|
230
|
+
StartAt = "LoadNextStep"
|
|
231
|
+
States = {
|
|
232
|
+
# ---- Load the next step for the current cursor -------------------------
|
|
233
|
+
LoadNextStep = {
|
|
234
|
+
Type = "Task"
|
|
235
|
+
Resource = "arn:aws:states:::lambda:invoke"
|
|
236
|
+
Parameters = {
|
|
237
|
+
FunctionName = local.step_dispatch_lambda_arn
|
|
238
|
+
Payload = {
|
|
239
|
+
phase = "load_next"
|
|
240
|
+
"cursor.$" = "$.cursor"
|
|
241
|
+
"executionArn.$" = "$$.Execution.Id"
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
OutputPath = "$.Payload"
|
|
245
|
+
Retry = local.lambda_invoke_retry
|
|
246
|
+
Next = "DirectiveChoice"
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
# ---- Branch on the directive the Lambda emitted ------------------------
|
|
250
|
+
DirectiveChoice = {
|
|
251
|
+
Type = "Choice"
|
|
252
|
+
Choices = [
|
|
253
|
+
{ Variable = "$.directive", StringEquals = "dispatch_agent", Next = "AgentStep" },
|
|
254
|
+
{ Variable = "$.directive", StringEquals = "wait_until", Next = "WaitState" },
|
|
255
|
+
{ Variable = "$.directive", StringEquals = "execute_step", Next = "ExecuteStep" },
|
|
256
|
+
{ Variable = "$.directive", StringEquals = "await_approval", Next = "ApprovalStep" },
|
|
257
|
+
{ Variable = "$.directive", StringEquals = "continue", Next = "LoadNextStep" },
|
|
258
|
+
{ Variable = "$.directive", StringEquals = "rollover", Next = "RolloverStart" },
|
|
259
|
+
{ Variable = "$.directive", StringEquals = "terminal_success", Next = "SucceedState" },
|
|
260
|
+
{ Variable = "$.directive", StringEquals = "terminal_canceled", Next = "SucceedState" },
|
|
261
|
+
]
|
|
262
|
+
# terminal_failure and any unknown directive fail the run.
|
|
263
|
+
Default = "FailState"
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
# ---- Agent step: dispatch a Pi goal turn, park on the task token -------
|
|
267
|
+
AgentStep = {
|
|
268
|
+
Type = "Task"
|
|
269
|
+
Resource = "arn:aws:states:::lambda:invoke.waitForTaskToken"
|
|
270
|
+
Parameters = {
|
|
271
|
+
FunctionName = local.step_dispatch_lambda_arn
|
|
272
|
+
Payload = {
|
|
273
|
+
phase = "dispatch_agent"
|
|
274
|
+
"cursor.$" = "$.cursor"
|
|
275
|
+
"taskToken.$" = "$$.Task.Token"
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
ResultPath = "$.stepResult"
|
|
279
|
+
HeartbeatSeconds = 3600
|
|
280
|
+
TimeoutSeconds = 172800
|
|
281
|
+
# States.ALL must stand alone; it subsumes States.Timeout/States.TaskFailed.
|
|
282
|
+
# Any agent-step failure routes to RecordAdvance so the Lambda records a
|
|
283
|
+
# step-failed event rather than stranding the run.
|
|
284
|
+
Catch = [{
|
|
285
|
+
ErrorEquals = ["States.ALL"]
|
|
286
|
+
ResultPath = "$.stepResult"
|
|
287
|
+
Next = "RecordAdvance"
|
|
288
|
+
}]
|
|
289
|
+
Next = "RecordAdvance"
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
# ---- Executable step: routine / http / emit_event run synchronously in
|
|
293
|
+
# the Lambda (THINK-215). The phase executes the step, records outcome +
|
|
294
|
+
# output evidence, evaluates advance/policy itself, and returns the next
|
|
295
|
+
# directive — so its output feeds DirectiveChoice directly. Application
|
|
296
|
+
# failures are recorded in the ledger by the Lambda; only an infra-level
|
|
297
|
+
# crash reaches Catch, where the EventBridge execution-callback
|
|
298
|
+
# terminalizes the run.
|
|
299
|
+
ExecuteStep = {
|
|
300
|
+
Type = "Task"
|
|
301
|
+
Resource = "arn:aws:states:::lambda:invoke"
|
|
302
|
+
Parameters = {
|
|
303
|
+
FunctionName = local.step_dispatch_lambda_arn
|
|
304
|
+
Payload = {
|
|
305
|
+
phase = "execute_step"
|
|
306
|
+
"cursor.$" = "$.cursor"
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
OutputPath = "$.Payload"
|
|
310
|
+
TimeoutSeconds = 900
|
|
311
|
+
Retry = local.lambda_invoke_retry
|
|
312
|
+
Catch = [{
|
|
313
|
+
ErrorEquals = ["States.ALL"]
|
|
314
|
+
Next = "FailState"
|
|
315
|
+
}]
|
|
316
|
+
Next = "DirectiveChoice"
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
# ---- Wait step: park until the ISO timestamp the Lambda emitted --------
|
|
320
|
+
WaitState = {
|
|
321
|
+
Type = "Wait"
|
|
322
|
+
TimestampPath = "$.until"
|
|
323
|
+
Next = "InjectWaitResult"
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
# Wait carries no stepResult; inject a marker so RecordAdvance's frozen
|
|
327
|
+
# contract (top-level cursor + stepResult) holds uniformly.
|
|
328
|
+
InjectWaitResult = {
|
|
329
|
+
Type = "Pass"
|
|
330
|
+
Result = { waitCompleted = true }
|
|
331
|
+
ResultPath = "$.stepResult"
|
|
332
|
+
Next = "RecordAdvance"
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
# ---- Approval step: suspend as waiting_for_human on a task token -------
|
|
336
|
+
ApprovalStep = {
|
|
337
|
+
Type = "Task"
|
|
338
|
+
Resource = "arn:aws:states:::lambda:invoke.waitForTaskToken"
|
|
339
|
+
Parameters = {
|
|
340
|
+
FunctionName = local.step_dispatch_lambda_arn
|
|
341
|
+
Payload = {
|
|
342
|
+
phase = "await_approval"
|
|
343
|
+
"cursor.$" = "$.cursor"
|
|
344
|
+
"taskToken.$" = "$$.Task.Token"
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
ResultPath = "$.approval"
|
|
348
|
+
TimeoutSeconds = 604800
|
|
349
|
+
Catch = [{
|
|
350
|
+
ErrorEquals = ["States.Timeout"]
|
|
351
|
+
Next = "FailState"
|
|
352
|
+
}]
|
|
353
|
+
Next = "RecordApproval"
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
RecordApproval = {
|
|
357
|
+
Type = "Task"
|
|
358
|
+
Resource = "arn:aws:states:::lambda:invoke"
|
|
359
|
+
Parameters = {
|
|
360
|
+
FunctionName = local.step_dispatch_lambda_arn
|
|
361
|
+
Payload = {
|
|
362
|
+
phase = "record_approval"
|
|
363
|
+
"cursor.$" = "$.cursor"
|
|
364
|
+
"approval.$" = "$.approval"
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
OutputPath = "$.Payload"
|
|
368
|
+
Retry = local.lambda_invoke_retry
|
|
369
|
+
Next = "DirectiveChoice"
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
# ---- Record the step outcome, evaluate policy, emit the next directive -
|
|
373
|
+
RecordAdvance = {
|
|
374
|
+
Type = "Task"
|
|
375
|
+
Resource = "arn:aws:states:::lambda:invoke"
|
|
376
|
+
Parameters = {
|
|
377
|
+
FunctionName = local.step_dispatch_lambda_arn
|
|
378
|
+
Payload = {
|
|
379
|
+
phase = "record_advance"
|
|
380
|
+
"cursor.$" = "$.cursor"
|
|
381
|
+
"stepResult.$" = "$.stepResult"
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
OutputPath = "$.Payload"
|
|
385
|
+
Retry = local.lambda_invoke_retry
|
|
386
|
+
Next = "DirectiveChoice"
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
# ---- Rollover: continue-as-new self-restart (fire-and-forget) ----------
|
|
390
|
+
RolloverStart = {
|
|
391
|
+
Type = "Task"
|
|
392
|
+
Resource = "arn:aws:states:::states:startExecution"
|
|
393
|
+
Parameters = {
|
|
394
|
+
"StateMachineArn.$" = "$$.StateMachine.Id"
|
|
395
|
+
Input = {
|
|
396
|
+
"cursor.$" = "$.cursor"
|
|
397
|
+
"AWS_STEP_FUNCTIONS_STARTED_BY_EXECUTION_ID.$" = "$$.Execution.Id"
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
Next = "SucceedState"
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
SucceedState = { Type = "Succeed" }
|
|
404
|
+
|
|
405
|
+
FailState = {
|
|
406
|
+
Type = "Fail"
|
|
407
|
+
Error = "WorkflowFailed"
|
|
408
|
+
Cause = "see ThinkWork run ledger"
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
})
|
|
412
|
+
|
|
413
|
+
tags = {
|
|
414
|
+
Name = local.state_machine_name
|
|
415
|
+
Stage = var.stage
|
|
416
|
+
Purpose = "workflow-interpreter"
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
################################################################################
|
|
421
|
+
# SSM parameter — interpreter machine ARN.
|
|
422
|
+
#
|
|
423
|
+
# graphql-http (manual triggerWorkflowRun) and job-trigger (workflow_schedule)
|
|
424
|
+
# resolve the machine ARN from SSM rather than a Lambda env var, dodging the
|
|
425
|
+
# graphql-http 4KB env ceiling (plan Risks). The shared API lambda role already
|
|
426
|
+
# reads /thinkwork/${stage}/* via the api_data_plane grant.
|
|
427
|
+
################################################################################
|
|
428
|
+
|
|
429
|
+
resource "aws_ssm_parameter" "state_machine_arn" {
|
|
430
|
+
name = local.ssm_state_machine_arn_param
|
|
431
|
+
description = "ARN of the shared workflow-interpreter Step Functions state machine."
|
|
432
|
+
type = "String"
|
|
433
|
+
value = aws_sfn_state_machine.interpreter.arn
|
|
434
|
+
|
|
435
|
+
tags = {
|
|
436
|
+
Stage = var.stage
|
|
437
|
+
Purpose = "workflow-interpreter"
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
################################################################################
|
|
442
|
+
# EventBridge — Step Functions execution-state-change -> workflow-execution-callback
|
|
443
|
+
#
|
|
444
|
+
# AWS fires `Step Functions Execution Status Change` on every transition. The
|
|
445
|
+
# callback Lambda projects terminal status onto workflow_runs (with the
|
|
446
|
+
# current-ARN guard for rolled-over executions, KTD6). Gated on the callback
|
|
447
|
+
# ARN being wired so this substrate module applies before lambda-api defines
|
|
448
|
+
# the function; the composite module passes the ARN once both apply.
|
|
449
|
+
################################################################################
|
|
450
|
+
|
|
451
|
+
resource "aws_cloudwatch_event_rule" "sfn_state_change" {
|
|
452
|
+
count = var.enable_execution_callback ? 1 : 0
|
|
453
|
+
name = "thinkwork-${var.stage}-workflow-interpreter-sfn-state-change"
|
|
454
|
+
description = "Forward interpreter Step Functions execution-state-change events to workflow-execution-callback so workflow_runs tracks lifecycle status."
|
|
455
|
+
|
|
456
|
+
event_pattern = jsonencode({
|
|
457
|
+
source = ["aws.states"]
|
|
458
|
+
"detail-type" = ["Step Functions Execution Status Change"]
|
|
459
|
+
detail = {
|
|
460
|
+
stateMachineArn = [
|
|
461
|
+
{
|
|
462
|
+
prefix = local.state_machine_arn
|
|
463
|
+
},
|
|
464
|
+
]
|
|
465
|
+
# SUCCEEDED is intentionally excluded: success is always projected onto
|
|
466
|
+
# workflow_runs by the step-dispatch Lambda BEFORE the execution ends,
|
|
467
|
+
# and a rolled-over execution's SUCCEEDED racing the repoint could
|
|
468
|
+
# otherwise terminalize a live looping run.
|
|
469
|
+
status = ["FAILED", "TIMED_OUT", "ABORTED"]
|
|
470
|
+
}
|
|
471
|
+
})
|
|
472
|
+
|
|
473
|
+
tags = {
|
|
474
|
+
Name = "thinkwork-${var.stage}-workflow-interpreter-sfn-state-change"
|
|
475
|
+
Stage = var.stage
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
resource "aws_cloudwatch_event_target" "sfn_state_change" {
|
|
480
|
+
count = var.enable_execution_callback ? 1 : 0
|
|
481
|
+
rule = aws_cloudwatch_event_rule.sfn_state_change[0].name
|
|
482
|
+
target_id = "workflow-execution-callback"
|
|
483
|
+
arn = var.execution_callback_lambda_arn
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
resource "aws_lambda_permission" "sfn_state_change" {
|
|
487
|
+
count = var.enable_execution_callback ? 1 : 0
|
|
488
|
+
statement_id = "AllowEventBridgeInvokeWorkflowExecutionCallback"
|
|
489
|
+
action = "lambda:InvokeFunction"
|
|
490
|
+
function_name = var.execution_callback_lambda_arn
|
|
491
|
+
principal = "events.amazonaws.com"
|
|
492
|
+
source_arn = aws_cloudwatch_event_rule.sfn_state_change[0].arn
|
|
493
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
output "state_machine_arn" {
|
|
2
|
+
description = "ARN of the shared workflow-interpreter state machine."
|
|
3
|
+
value = aws_sfn_state_machine.interpreter.arn
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
output "state_machine_name" {
|
|
7
|
+
description = "Name of the shared workflow-interpreter state machine."
|
|
8
|
+
value = aws_sfn_state_machine.interpreter.name
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
output "state_machine_arn_ssm_parameter_name" {
|
|
12
|
+
description = "SSM parameter name holding the interpreter machine ARN (read by graphql-http + job-trigger)."
|
|
13
|
+
value = aws_ssm_parameter.state_machine_arn.name
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
output "execution_role_arn" {
|
|
17
|
+
description = "ARN of the Step Functions execution role assumed by the interpreter machine."
|
|
18
|
+
value = aws_iam_role.execution.arn
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
output "execution_role_name" {
|
|
22
|
+
description = "Name of the Step Functions execution role."
|
|
23
|
+
value = aws_iam_role.execution.name
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
output "log_group_arn" {
|
|
27
|
+
description = "CloudWatch log group ARN for interpreter execution histories."
|
|
28
|
+
value = aws_cloudwatch_log_group.interpreter.arn
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
output "log_group_name" {
|
|
32
|
+
description = "CloudWatch log group name."
|
|
33
|
+
value = aws_cloudwatch_log_group.interpreter.name
|
|
34
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
variable "stage" {
|
|
2
|
+
description = "Deployment stage (dev, prod, etc.)."
|
|
3
|
+
type = string
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
variable "region" {
|
|
7
|
+
description = "AWS region."
|
|
8
|
+
type = string
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
variable "account_id" {
|
|
12
|
+
description = "AWS account ID (used to construct IAM + Lambda + state-machine ARNs)."
|
|
13
|
+
type = string
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
variable "log_retention_days" {
|
|
17
|
+
description = "CloudWatch log retention for interpreter state machine executions."
|
|
18
|
+
type = number
|
|
19
|
+
default = 30
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
variable "execution_callback_lambda_arn" {
|
|
23
|
+
description = "ARN of the workflow-execution-callback Lambda. EventBridge sends SFN execution-state-change events here so workflow_runs lifecycle status mirrors the SFN-side reality. Only consumed when enable_execution_callback is true."
|
|
24
|
+
type = string
|
|
25
|
+
default = ""
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
variable "enable_execution_callback" {
|
|
29
|
+
description = "Provision the EventBridge SFN-state-change rule targeting the execution-callback Lambda. Must be a STATIC value (never derived from a computed resource attribute): it gates resource count, and Terraform cannot plan a count that depends on attributes only known after apply — the ARN itself is fine to consume inside the resources."
|
|
30
|
+
type = bool
|
|
31
|
+
default = false
|
|
32
|
+
}
|
|
@@ -117,6 +117,18 @@ resource "aws_rds_cluster" "main" {
|
|
|
117
117
|
deletion_protection = local.deletion_protection
|
|
118
118
|
storage_encrypted = true
|
|
119
119
|
|
|
120
|
+
# THINK-229 U1 (R1): the analyst-query-broker Lambda authenticates as
|
|
121
|
+
# analyst_reader with per-connect RDS IAM auth tokens instead of a
|
|
122
|
+
# stored password. Cluster-level flag; applies without downtime.
|
|
123
|
+
# apply_immediately is required: the provider default defers cluster
|
|
124
|
+
# modifications to the maintenance window, and if the GRANT rds_iam
|
|
125
|
+
# migration (0229) landed inside that pending window the role would
|
|
126
|
+
# refuse BOTH password (grant applied) and IAM (flag still pending)
|
|
127
|
+
# login. Deploys on this platform are CLI/CI-driven and expect
|
|
128
|
+
# immediate semantics.
|
|
129
|
+
iam_database_authentication_enabled = true
|
|
130
|
+
apply_immediately = true
|
|
131
|
+
|
|
120
132
|
serverlessv2_scaling_configuration {
|
|
121
133
|
min_capacity = var.min_capacity
|
|
122
134
|
max_capacity = var.max_capacity
|
|
@@ -180,6 +192,13 @@ resource "aws_db_instance" "main" {
|
|
|
180
192
|
skip_final_snapshot = true
|
|
181
193
|
deletion_protection = local.deletion_protection
|
|
182
194
|
|
|
195
|
+
# THINK-229 U1 (R1): keep the rds-postgres dev/test engine at parity
|
|
196
|
+
# with the Aurora cluster — analyst_reader logs in with IAM tokens.
|
|
197
|
+
# apply_immediately for the same both-paths-stranded reason as the
|
|
198
|
+
# Aurora cluster block above.
|
|
199
|
+
iam_database_authentication_enabled = true
|
|
200
|
+
apply_immediately = true
|
|
201
|
+
|
|
183
202
|
tags = {
|
|
184
203
|
Name = "thinkwork-${var.stage}-db"
|
|
185
204
|
}
|
|
@@ -358,3 +377,39 @@ resource "aws_secretsmanager_secret" "compliance_reader" {
|
|
|
358
377
|
Role = "compliance_reader"
|
|
359
378
|
}
|
|
360
379
|
}
|
|
380
|
+
|
|
381
|
+
################################################################################
|
|
382
|
+
# Secrets Manager — Analyst Reader Role Credentials (THINK-228 U2)
|
|
383
|
+
#
|
|
384
|
+
# Container for the analyst_reader Aurora role used by the analyst
|
|
385
|
+
# query-broker Lambda. Terraform owns the SECRET CONTAINER; the operator
|
|
386
|
+
# owns the SECRET VALUE (populated by scripts/bootstrap-analyst-roles.sh,
|
|
387
|
+
# which also applies drizzle/0227_analyst_reader_role.sql to create the
|
|
388
|
+
# matching hardened read-only role).
|
|
389
|
+
################################################################################
|
|
390
|
+
|
|
391
|
+
resource "aws_secretsmanager_secret" "analyst_reader" {
|
|
392
|
+
count = local.create ? 1 : 0
|
|
393
|
+
name = "thinkwork/${var.stage}/analyst/reader-credentials"
|
|
394
|
+
|
|
395
|
+
tags = {
|
|
396
|
+
Name = "thinkwork-${var.stage}-analyst-reader-credentials"
|
|
397
|
+
Role = "analyst_reader"
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
# Broker caller credential for the analyst query broker (THINK-228 U3).
|
|
402
|
+
# The connector row (tenant_mcp_servers, seeded by
|
|
403
|
+
# scripts/provision-analyst-connector.mts) references this ARN as its
|
|
404
|
+
# auth_config.secretRef; the broker Lambda validates incoming Bearer
|
|
405
|
+
# tokens against it. Value shape: JSON {token, tenantId} — populated by
|
|
406
|
+
# the provisioning script, never by Terraform.
|
|
407
|
+
resource "aws_secretsmanager_secret" "analyst_broker" {
|
|
408
|
+
count = local.create ? 1 : 0
|
|
409
|
+
name = "thinkwork/${var.stage}/analyst/broker-credential"
|
|
410
|
+
|
|
411
|
+
tags = {
|
|
412
|
+
Name = "thinkwork-${var.stage}-analyst-broker-credential"
|
|
413
|
+
Role = "analyst_query_broker"
|
|
414
|
+
}
|
|
415
|
+
}
|
|
@@ -8,6 +8,11 @@ output "db_cluster_arn" {
|
|
|
8
8
|
value = local.db_cluster_arn
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
+
output "cluster_resource_id" {
|
|
12
|
+
description = "Immutable RDS cluster resource ID (cluster-XXXX / db-XXXX), the identifier IAM rds-db:connect policies key on — NOT the ARN (THINK-229 U1). Empty string when create_database = false."
|
|
13
|
+
value = local.use_aurora ? aws_rds_cluster.main[0].cluster_resource_id : (local.use_rds ? aws_db_instance.main[0].resource_id : "")
|
|
14
|
+
}
|
|
15
|
+
|
|
11
16
|
output "graphql_db_secret_arn" {
|
|
12
17
|
description = "Secrets Manager ARN for DB credentials (created or existing)"
|
|
13
18
|
value = local.graphql_db_secret_arn
|
|
@@ -62,3 +67,13 @@ output "compliance_reader_secret_arn" {
|
|
|
62
67
|
description = "Secrets Manager ARN for the compliance_reader Aurora role (Phase 3 U2). Empty string when create_database = false."
|
|
63
68
|
value = local.create ? aws_secretsmanager_secret.compliance_reader[0].arn : ""
|
|
64
69
|
}
|
|
70
|
+
|
|
71
|
+
output "analyst_reader_secret_arn" {
|
|
72
|
+
description = "Secrets Manager ARN for the analyst_reader Aurora role (THINK-228 U2). Empty string when create_database = false."
|
|
73
|
+
value = local.create ? aws_secretsmanager_secret.analyst_reader[0].arn : ""
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
output "analyst_broker_secret_arn" {
|
|
77
|
+
description = "Secrets Manager ARN for the analyst query-broker caller credential (THINK-228 U3). Empty string when create_database = false."
|
|
78
|
+
value = local.create ? aws_secretsmanager_secret.analyst_broker[0].arn : ""
|
|
79
|
+
}
|
|
@@ -108,3 +108,29 @@ output "bucket_arn" {
|
|
|
108
108
|
description = "ARN of the S3 bucket"
|
|
109
109
|
value = aws_s3_bucket.main.arn
|
|
110
110
|
}
|
|
111
|
+
|
|
112
|
+
# Analyst query-broker result staging (THINK-228 U3). Results larger than
|
|
113
|
+
# the inline envelope cap land as CSVs under analyst-staging/<tenantId>/
|
|
114
|
+
# with SSE; they are scratch data consumed by the agent sandbox within the
|
|
115
|
+
# same delegation, so a short TTL bounds both storage cost and the window
|
|
116
|
+
# in which a leaked object key is useful.
|
|
117
|
+
resource "aws_s3_bucket_lifecycle_configuration" "analyst_staging" {
|
|
118
|
+
bucket = aws_s3_bucket.main.id
|
|
119
|
+
|
|
120
|
+
rule {
|
|
121
|
+
id = "analyst-staging-ttl"
|
|
122
|
+
status = "Enabled"
|
|
123
|
+
|
|
124
|
+
filter {
|
|
125
|
+
prefix = "analyst-staging/"
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
expiration {
|
|
129
|
+
days = 3
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
abort_incomplete_multipart_upload {
|
|
133
|
+
days_after_initiation = 1
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|