chore(trigger): sync Trigger.dev env vars from the app's Secrets Manager secret, gated per environment
Merged
WA
6d ago+320+320+012345678901234567890123456789-18-18-01234567890123456789
Summary
- Trigger.dev deploys can now sync the target environment from the app's env-vars secret in Secrets Manager instead of relying on hand-copied variables
- Off by default: a deploy syncs only when its environment slug (
prod,staging,preview) is listed in theTRIGGER_ENV_SYNC_TARGETSrepo variable, and only then does the job assume the deploy role for Secrets Manager. Nothing changes until that variable is set - Each slug maps to exactly one app secret in code, so a deploy can't sync one environment's config into another
- Trigger-owned keys are never synced, so whatever value Trigger already holds stays:
AWS_*(runs use workload identity, so static keys never go back in),REDIS_URL/REDIS_TLS_SERVERNAME(workers reach Redis through their own endpoint),INTERNAL_API_BASE_URL,MIGRATION_DATABASE_URL,OTEL_EXPORTER_OTLP_*,TRIGGER_*,GITHUB_TOKEN.DB_APP_NAME/SIM_DB_ROLEare code constants - Synced app values are stored as secrets, except
NEXT_PUBLIC_* - The sync only upserts. Variables it doesn't return are left alone, and it never deletes anything
- A failure reading the secret exits the deploy.
syncEnvVars(4.8.3) catches callback errors and deploys without syncing, so throwing isn't enough. The CI log shows counts only, never names or values - With sync disabled, the deploy sends the shared constants (
DB_APP_NAME, now alsoSIM_DB_ROLE=trigger, which every environment already holds, so the CLI's unchanged-value check skips it) plus the function-execution vars as before. TheTRIGGER_DEV_ENABLEDentry is dropped:syncEnvVarsstrips everyTRIGGER_*key, so it never synced - Adds
plan-trigger-env-sync.ts, a names-only dry run of what enabling an environment would add or change.--apply-secret-flagsmarks unchanged plain-text variables as secrets, re-reading before each batch so a value rotated mid-run is skipped rather than overwritten: the CLI skips unchanged values, soisSecretalone never converts an existing variable - Extracts
fetchRuntimeSecretsfromloadRuntimeSecretsso the boot path and the deploy read the secret the same way
Type of Change
- Chore / infrastructure
Testing
- Read the pinned
@trigger.dev/build/trigger.dev4.8.3 source and the webapp import route to confirm the semantics: upsert-only,isSecretflips only on changed values, sync runs before deployment init, callback errors are swallowed - Ran the dry-run script against all three environments, comparing values by hash only
- Exercised the callback's success path, unmapped-environment exit, and missing-credentials exit
packages/runtime-secretstests; biome;check-source-conventions,check-file-names,check-import-specifiers,check-monorepo-boundaries,check-comment-hygiene,check-utils-enforcement,check-explicit-any. Full type-check and audits run in CI
Checklist
- Code follows project style guidelines
- Self-reviewed my changes
- Tests added/updated and passing (new tests pass the
test-auditauthoring gate) - No new warnings introduced
- I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)