Skip to content

Commit e0bfbfe

Browse files
Bill LeoutsakosBill Leoutsakos
authored andcommitted
fix(trigger): sync worker configuration from Secrets Manager at deploy
1 parent a89b158 commit e0bfbfe

4 files changed

Lines changed: 948 additions & 52 deletions

File tree

.claude/rules/sim-architecture.md

Lines changed: 87 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,10 +60,93 @@ Every export of a `'use client'` module becomes a *client reference* on the serv
6060
## The app/worker runtime boundary
6161

6262
Server code runs in two runtimes with **different environments**. The app container loads the
63-
full env from `SIM_ENV_SECRET_ID` (Secrets Manager). Trigger.dev workers — which execute
64-
workflows, so every block handler and every tool call — get their env from the Trigger.dev
65-
dashboard; `trigger.config.ts` additionally syncs `DB_APP_NAME`, `TRIGGER_DEV_ENABLED`, and the
66-
`FUNCTION_EXECUTION_ENV` vars. The repo cannot see what the dashboard holds.
63+
full env from `SIM_ENV_SECRET_ID` (Secrets Manager). Trigger.dev workers execute application
64+
code directly and receive runtime configuration through Trigger.dev. At deployment,
65+
`trigger.config.ts` calls `scripts/trigger-env-sync.ts` through the existing `syncEnvVars`
66+
extension. It reads only the mapped combined secret's `AWSCURRENT` version, selects approved
67+
platform variables in memory, validates them, and returns explicitly classified secret/public
68+
entries. `DB_APP_NAME=sim-trigger` is fixed; the run `init` marker remains the source of runtime
69+
detection. Reserved `TRIGGER_*` variables, deployment credentials, arbitrary source keys, and
70+
customer credentials are never selected. Customer OAuth tokens and workspace/provider
71+
credentials remain in the application database, decrypted by the existing runtime code.
72+
73+
```text
74+
ECS boot: environment secret -> runtime-secrets loader -> app process
75+
Trigger deploy: environment secret -> worker policy/validation -> syncEnvVars -> Trigger runtime
76+
+ preserved Trigger-owned settings
77+
```
78+
79+
### Worker synchronization ownership and rollout
80+
81+
The mapping is deliberately closed: `preview` with branch `dev-sim` reads `/dev/sim/env-vars`,
82+
`staging` without a branch reads `/staging/sim/env-vars`, and `prod` without a branch reads
83+
`/production/sim/env-vars`. Unknown targets fail before AWS access; no preview-parent writes.
84+
The deployment entrypoint must supply `SIM_TRIGGER_ENV_SYNC_PROJECT_REF` (the approved project,
85+
checked against the callback project) and `SIM_TRIGGER_ENV_SYNC_REGION` (the source region).
86+
These deployment-only controls are not exported to workers. No `NODE_ENV` inference or ambient
87+
source-value fallback is permitted. An unconfigured deployment fails closed; coordinate this
88+
change with the separate deployment-orchestration work before merging/enabling it.
89+
90+
`WORKER_CONFIGURATION` is the reviewable names/classification/consumer policy. Shared capability
91+
fields, OAuth application registrations, and platform LLM pools come from the existing registry.
92+
Additional groups document their worker consumer and requiredness. Required source settings
93+
include app/auth URLs, encryption/internal authentication, and explicit billing/enterprise flags
94+
(`false` is valid). Capability validators reject incomplete active providers. The source subset
95+
and effective worker configuration are checked so missing values cannot hide behind old values
96+
or silently switch storage/OCR backends. Optional absence is allowed; configured features must
97+
still be usable. Before enabling each target, its owner must approve a names-only source/target
98+
inventory, a supported capability baseline, and the ownership exceptions. Validation does not
99+
prove that a configured endpoint is reachable or a credential is authorized.
100+
101+
Each target currently preserves the conservative `WORKER_OWNED` list: database URLs (including
102+
role/replica/sub-pool URLs), `SIM_DB_ROLE`, Redis URL/TLS server name, PII endpoint, and Grafana
103+
telemetry settings. The effective database must already be usable. These exceptions apply even
104+
when a source value exists; transfer ownership only through an explicitly reviewed policy change.
105+
The list is a preservation policy, not a claim about the contents of a live target. Staging/prod
106+
project references and deployment entrypoints still require live verification. Telemetry setup,
107+
DB clients, ECS hydration and worker initialization are unchanged.
108+
109+
Omitted optional keys preserve existing Trigger values, with a names-only notice when the key
110+
was present in the callback's current environment. This is not deletion and does not transfer
111+
ownership. Removed/renamed variables require owner-reviewed retirement in Trigger, including
112+
preview inheritance checks so deleting an override cannot resurrect a parent value. Existing
113+
public variables needing secret classification must be reviewed: Trigger's secret classification
114+
is a creation-time property, so returning `isSecret` must not be treated as an in-place migration.
115+
116+
Reuse the deployment identity's existing Trigger authentication and AWS default credential chain.
117+
Grant it `secretsmanager:GetSecretValue` on the exact environment secret ARN, and `kms:Decrypt`
118+
only for its customer-managed key when required. No worker Secrets Manager permission is needed.
119+
Runtime AWS credentials selected from the source are platform configuration; runner credentials
120+
are never copied from `process.env`. IAM definition location and staging/prod deploy wiring are
121+
external prerequisites owned by the separate investigation. This step belongs inside every
122+
existing Trigger deployment, after authentication and before the release is accepted. Do not
123+
use `--skip-sync-env-vars` or tolerate nonzero exits. Trigger 4.5.12 catches callback exceptions,
124+
so the adapter logs only controlled categories/names and exits the deploy process with code 1.
125+
CLI environment-import failures must also fail deployment. Never log source objects or SDK/parser
126+
errors, hydrate the deployer, write dotenv/manifests, or pass secrets as image/build arguments.
127+
128+
Roll out preview/dev-sim, then staging, then production. Synchronization is deployment-time;
129+
rotation without deployment is outside this mechanism. Env import and code promotion are not
130+
atomic: even a later failed build can leave updated configuration. Running/checkpointed jobs
131+
and cached application clients are not guaranteed to adopt updates. Allow old credentials to
132+
remain valid until executions finish, or use a separately authorized drain procedure. Optional
133+
omission and code rollback do not restore prior values.
134+
135+
One disposable non-production smoke test is sufficient after access and ownership approval:
136+
use a disposable Trigger project and an isolated non-production AWS account with fake platform
137+
configuration at `/dev/sim/env-vars`. Supply that project and region through the deployment
138+
controls, preseed fake Trigger-owned configuration, and invoke the existing deployment path for
139+
`preview/dev-sim`. Verify creation,
140+
update, unrelated-variable preservation and optional omission. Assert a fresh job sees expected
141+
values without printing them. Check build artifacts and logs for the fake marker, explicitly
142+
remove test variables (including inherited preview values), and delete the disposable secret
143+
and project. Do not point the smoke test at an environment's real combined secret. Do not add
144+
this live test to CI or use production credentials. Automatic deletion/rotation behavior is not
145+
implemented; any explicit deletion test must account for preview inheritance.
146+
147+
References: [Trigger syncEnvVars](https://trigger.dev/docs/config/extensions/syncEnvVars),
148+
[Trigger environment variables](https://trigger.dev/docs/deploy-environment-variables),
149+
[AWS GetSecretValue](https://docs.aws.amazon.com/secretsmanager/latest/apireference/API_GetSecretValue.html).
67150

68151
So before replacing a worker's HTTP call to our own API with an in-process call, ask what env
69152
that work reads *on the app side*. Anything gated by a `require*Capability` helper is the sharp

0 commit comments

Comments
 (0)