Skip to content

Commit 719cb74

Browse files
committed
fix(aws): keep the default chain outside workload identity and cover ses
getAwsCredentials returned explicit static keys when present, which dropped AWS_SESSION_TOKEN for clients that used to reach it through the default chain (Bedrock, CloudWatch). It now returns the workload-identity provider or undefined, so every non-Trigger path resolves exactly as before. The SES email client reads it too, so worker email keeps working once static keys leave Trigger.dev. The release-age comment records why the exclusions are bare names.
1 parent e93a105 commit 719cb74

3 files changed

Lines changed: 28 additions & 30 deletions

File tree

‎apps/sim/lib/core/config/aws.ts‎

Lines changed: 11 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,6 @@ import { env } from '@/lib/core/config/env'
44

55
const logger = createLogger('AwsCredentials')
66

7-
interface StaticAwsCredentials {
8-
accessKeyId: string
9-
secretAccessKey: string
10-
}
11-
127
type AwsCredentialsProvider = () => Promise<AWSCredentials>
138

149
/**
@@ -76,27 +71,20 @@ function resolveWorkloadCredentials(
7671
}
7772

7873
/**
79-
* Credentials for Sim's own AWS clients: file storage (S3), AppConfig, hosted-key metrics and
80-
* hosted Bedrock. Never for a user's integration, which brings its own keys.
74+
* Credentials for Sim's own AWS clients: file storage (S3), AppConfig, email (SES), hosted-key
75+
* metrics and hosted Bedrock. Never for a user's integration, which brings its own keys.
8176
*
82-
* - `TRIGGER_AWS_ROLE_ARN` set (deployed Trigger.dev runs): temporary credentials for that role,
83-
* exchanged for the run's Trigger.dev workload-identity token. Takes precedence over static
84-
* keys, so a failed exchange surfaces instead of silently falling back to a stored key.
85-
* - `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` set: those keys (self-hosted deployments).
86-
* - Neither: `undefined`, deferring to the AWS default provider chain (the ECS task role).
77+
* With `TRIGGER_AWS_ROLE_ARN` set (deployed Trigger.dev runs), temporary credentials for that
78+
* role, exchanged for the run's Trigger.dev workload-identity token. It takes precedence over any
79+
* static keys in the environment, so a failed exchange surfaces instead of silently falling back
80+
* to a stored key. Otherwise `undefined`: the AWS SDK's default chain, which reads
81+
* `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY` and `AWS_SESSION_TOKEN`, then shared profiles, then
82+
* the ECS task role.
8783
*/
88-
export function getAwsCredentials(): StaticAwsCredentials | AwsCredentialsProvider | undefined {
84+
export function getAwsCredentials(): AwsCredentialsProvider | undefined {
8985
const roleArn = env.TRIGGER_AWS_ROLE_ARN
90-
if (roleArn) {
91-
return () => resolveWorkloadCredentials(roleArn, REFRESH_BEFORE_EXPIRY_MS)
92-
}
93-
if (env.AWS_ACCESS_KEY_ID && env.AWS_SECRET_ACCESS_KEY) {
94-
return {
95-
accessKeyId: env.AWS_ACCESS_KEY_ID,
96-
secretAccessKey: env.AWS_SECRET_ACCESS_KEY,
97-
}
98-
}
99-
return undefined
86+
if (!roleArn) return undefined
87+
return () => resolveWorkloadCredentials(roleArn, REFRESH_BEFORE_EXPIRY_MS)
10088
}
10189

10290
/** Whether Sim's own AWS clients have credentials of their own rather than the default chain. */

‎apps/sim/lib/messaging/email/providers/ses.ts‎

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,22 @@
11
import { SESv2Client, SendEmailCommand } from '@aws-sdk/client-sesv2'
22
import nodemailer from 'nodemailer'
33
import type SESTransport from 'nodemailer/lib/ses-transport'
4+
import { getAwsCredentials } from '@/lib/core/config/aws'
45
import { env } from '@/lib/core/config/env'
56
import { sendViaNodemailer } from '@/lib/messaging/email/providers/send-via-nodemailer'
67
import type { MailProvider } from '@/lib/messaging/email/types'
78

89
/**
910
* AWS SES via nodemailer's SES transport using the AWS SDK v3 client.
10-
* Credentials resolve through the SDK's default provider chain (env vars,
11-
* shared config, ECS/EKS task role, EC2 instance profile, SSO).
11+
* Credentials come from `getAwsCredentials()`: workload identity in Trigger.dev
12+
* runs, otherwise the SDK's default provider chain (env vars, shared config,
13+
* ECS/EKS task role, EC2 instance profile, SSO).
1214
*/
1315
export function createSesProvider(): MailProvider | null {
1416
const region = env.AWS_SES_REGION
1517
if (!region) return null
1618

17-
const sesClient = new SESv2Client({ region })
19+
const sesClient = new SESv2Client({ region, credentials: getAwsCredentials() })
1820
const sesOptions: SESTransport.Options = {
1921
SES: { sesClient, SendEmailCommand },
2022
}

‎bunfig.toml‎

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,18 @@ exact = true
44
# (blocks freshly published, potentially compromised releases).
55
minimumReleaseAge = 604800
66
# Explicit framework pins must install before their release reaches the age threshold: a
7-
# security release of Next.js is pinned exactly the day it ships. The Trigger.dev packages are
8-
# excluded only until 4.8.3 (published 2026-10-30, the first release with workload identity)
9-
# clears the threshold on 2026-11-06; drop them then.
10-
minimumReleaseAgeExcludes = ["next", "@next/env", "@trigger.dev/sdk", "@trigger.dev/core", "@trigger.dev/build", "trigger.dev"]
7+
# security release of Next.js is pinned exactly the day it ships. Trigger.dev 4.8.3 (published
8+
# 2026-10-30, the first release with workload identity) is exempted until it clears the threshold
9+
# on 2026-11-06; drop the four Trigger.dev entries then. They are bare names because Bun 1.4 ignores
10+
# version-pinned exclusions; `exact = true` and the lockfile still hold the packages at 4.8.3.
11+
minimumReleaseAgeExcludes = [
12+
"next",
13+
"@next/env",
14+
"@trigger.dev/sdk",
15+
"@trigger.dev/core",
16+
"@trigger.dev/build",
17+
"trigger.dev",
18+
]
1119

1220
[run]
1321
env = { NEXT_PUBLIC_APP_URL = "http://localhost:3000" }

0 commit comments

Comments
 (0)