Skip to content

feat: support standard AWS env vars and default credential chain - #401

Merged
KMKoushik merged 5 commits into
mainfrom
fix/aws-env-vars-on-pr-395
May 17, 2026
Merged

feat: support standard AWS env vars and default credential chain#401
KMKoushik merged 5 commits into
mainfrom
fix/aws-env-vars-on-pr-395

Conversation

@KMKoushik

@KMKoushikKMKoushik commented May 17, 2026

Copy link
Copy Markdown
Member

Summary

  • Support standard AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY while keeping runtime fallback for existing legacy envs
  • Allow the AWS SDK default credential chain when static credentials are omitted
  • Align Docker, docs, CI env, and turbo env declarations with standard AWS names

Based on #395 by @purva-8, with maintainer fixes on top.

Closes#316

Verification

  • git diff --check
  • pnpm --filter=web exec eslint src/env.js next.config.js (AWS/turbo warnings resolved; unrelated existing warnings remain)

Merge note

If squash-merging and you want co-author credit preserved on the squash commit, include:

Co-authored-by: Purva Kandalgaonkar 136103488+purva-8@users.noreply.github.com


Summary by cubic

Switches to the standard AWS env vars AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY and enables the AWS SDK default credential chain when both are unset. Updates code, Docker, CI, docs, and Turbo config; legacy envs still work as fallbacks.

  • New Features

    • Use AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY; AWS_ACCESS_KEY / AWS_SECRET_KEY remain as runtime fallbacks.
    • Omit both vars to use the AWS SDK default credential chain for SES/SNS/STS.
    • Added getAwsCredentialOptions with a guard that errors on partial config.
    • Use an aliased import for the credentials helper to avoid path issues.
  • Migration

    • Prefer AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY, or rely on IAM/instance roles by leaving both unset.
    • Update your .env, CI, Docker, and Turbo env lists to the new names; examples and docs are aligned.

Written for commit b2147df. Summary will update on new commits. Review in cubic

Summary by CodeRabbit

  • New Features

    • Added AWS credential validation with safe fallback behavior; deployments can run without credentials set.
  • Documentation

    • Updated setup guides, examples, and run instructions to use the standardized AWS environment variable names.
  • Chores

    • Standardized AWS credential configuration across examples, tests, CI workflows, Docker, and build tooling to align with AWS conventions.

Review Change Stack

purva-8and others added 4 commits May 2, 2026 17:52
Replace non-standard AWS_ACCESS_KEY / AWS_SECRET_KEY with the AWS-standard
AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY. The old names are kept as
fallbacks in the runtimeEnv for backward compatibility.
Both vars are now optional. When omitted, the credentials object is not
passed to SESv2Client, STSClient, or SNSClient — the AWS SDK then falls
back to its default provider chain (IAM roles, ECS task roles, instance
profiles, etc.), which is the recommended approach for cloud-native deployments.
Closes#316
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
…al-config guard
- Move the credential spread logic into a single credentials.ts helper
so SESv2Client, STSClient, and SNSClient all share one implementation
- Throw a clear error if only one of AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY
is set, preventing silent fallback to the default provider chain with a
half-configured environment
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@vercel

vercelBot commented May 17, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

ProjectDeploymentActionsUpdated (UTC)
unsend-marketingReadyReadyPreview, CommentMay 17, 2026 11:21am

@greptile-appsgreptile-appsBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.

@coderabbitai

coderabbitaiBot commented May 17, 2026

Copy link
Copy Markdown
Contributor

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: e593e2ea-adba-4d19-9151-b80f2fe5a460

📥 Commits

Reviewing files that changed from the base of the PR and between 1c6317d and b2147df.

📒 Files selected for processing (2)
  • apps/web/src/server/aws/ses.ts
  • apps/web/src/server/aws/sns.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • apps/web/src/server/aws/sns.ts
  • apps/web/src/server/aws/ses.ts

Walkthrough

This PR standardizes AWS credential environment variable names from AWS_ACCESS_KEY/AWS_SECRET_KEY to AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY across examples, docs, CI, and runtime. It adds getAwsCredentialOptions() which returns explicit credentials when both env vars are set, throws on partial configuration, or returns an empty object so the AWS SDK default credential provider chain can be used. SES and SNS clients now use this helper instead of inline credential objects.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 0.00% which is insufficient. The required threshold is 80.00%.Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe PR title accurately summarizes the main changes: adding support for standard AWS environment variables and enabling the AWS default credential chain.
Linked Issues check✅ PassedThe PR successfully addresses all key requirements from issue #316: supports standard AWS env vars (AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY), makes credentials optional via default chain, maintains backward compatibility with legacy vars, and implements validation for partial configuration.
Out of Scope Changes check✅ PassedAll changes are directly related to the objective of supporting standard AWS environment variables and the credential chain. Updates to env files, documentation, CI workflows, and code are all in scope.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@cloudflare-workers-and-pages

cloudflare-workers-and-pagesBot commented May 17, 2026

Copy link
Copy Markdown

Deploying usesend with Cloudflare Pages Cloudflare Pages

Latest commit:b2147df
Status: ✅ Deploy successful!
Preview URL:https://6f7e6eeb.usesend.pages.dev
Branch Preview URL:https://fix-aws-env-vars-on-pr-395.usesend.pages.dev

View logs

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (1)
apps/docs/get-started/set-up-docker.mdx (1)

55-57: ⚡ Quick win

Document AWS static credentials as optional in standalone Docker flow.

Line 55–57 and Line 63 currently imply static AWS keys are always needed. Since credentials are now optional, please note that users can omit these vars when their runtime provides IAM-role/default credential chain access.

Proposed doc patch
 docker run -d \
-p 3000:3000 \
-e NEXTAUTH_URL="<your-nextauth-url>" \
-e NEXTAUTH_SECRET="<your-nextauth-secret>" \
-e DATABASE_URL="<your-next-private-database-url>" \
-e REDIS_URL="<your-next-private-redis-url>" \
- -e AWS_ACCESS_KEY_ID="<your-next-private-aws-access-key-id>" \- -e AWS_SECRET_ACCESS_KEY="<your-next-private-aws-secret-access-key>" \
-e AWS_DEFAULT_REGION="<your-next-private-aws-region>" \
-e GITHUB_ID="<your-next-private-github-id>" \
-e GITHUB_SECRET="<your-next-private-github-secret>" \
usesend/usesend

-Replace the placeholders with your actual database and AWS details.
+Replace the placeholders with your actual database details.
+If your environment does not provide AWS credentials via IAM/default provider chain, also set:
+AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY.

</details>
Also applies to: 63-63
<details>
<summary>🤖 Prompt for AI Agents</summary>

Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @apps/docs/get-started/set-up-docker.mdx around lines 55 - 57, Update the
Docker setup instructions so the AWS static credential environment variables
(AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_DEFAULT_REGION) are documented as
optional: change the text that currently tells users to "Replace the
placeholders with your actual database and AWS details." to "Replace the
placeholders with your actual database details. If your environment does not
provide AWS credentials via IAM/default provider chain, also set:
AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY." Ensure this change is applied to
the same explanatory lines that contain the three environment variable
placeholders and the similar line around the later occurrence (the one
referenced at line 63).


</details>
</blockquote></details>
</blockquote></details>
<details>
<summary>🤖 Prompt for all review comments with AI agents</summary>

Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @apps/web/src/env.js:

  • Around line 102-103: The current fallback uses independent || for
    AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY which can mix standard and legacy
    values; update the logic so the code selects either the standard pair
    (AWS_ACCESS_KEY_ID + AWS_SECRET_ACCESS_KEY) or, only if both are absent, the
    legacy pair (AWS_ACCESS_KEY + AWS_SECRET) as a unit. In practice change the
    assignment for AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY to a small
    conditional that prefers the standard env vars together, otherwise uses the
    legacy pair only when both legacy vars exist, and yields undefined/null if
    neither full pair is present; reference the AWS_ACCESS_KEY_ID and
    AWS_SECRET_ACCESS_KEY symbols when locating where to implement this.

In @apps/web/src/server/aws/ses.ts:

  • Line 20: Replace the relative import of getAwsCredentialOptions from
    "./credentials" with the repo-standard src alias import (e.g. import {
    getAwsCredentialOptions } from "~/server/aws/credentials";) so the module uses
    the ~/ alias form consistent with apps/web src imports.

In @apps/web/src/server/aws/sns.ts:

  • Line 8: Replace the relative import for getAwsCredentialOptions with the
    project src alias; change the import source from "./credentials" to the aliased
    module (e.g. "/server/aws/credentials") so the import reads: import {
    getAwsCredentialOptions } from "
    /server/aws/credentials"; this aligns the
    getAwsCredentialOptions import with the apps/web src alias convention.

Nitpick comments:
In @apps/docs/get-started/set-up-docker.mdx:

  • Around line 55-57: Update the Docker setup instructions so the AWS static
    credential environment variables (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY,
    AWS_DEFAULT_REGION) are documented as optional: change the text that currently
    tells users to "Replace the placeholders with your actual database and AWS
    details." to "Replace the placeholders with your actual database details. If
    your environment does not provide AWS credentials via IAM/default provider
    chain, also set: AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY." Ensure this
    change is applied to the same explanatory lines that contain the three
    environment variable placeholders and the similar line around the later
    occurrence (the one referenced at line 63).

</details>
<details>
<summary>🪄 Autofix (Beta)</summary>
Fix all unresolved CodeRabbit comments on this PR:
- [ ] <!-- {"checkboxId": "4b0d0e0a-96d7-4f10-b296-3a18ea78f0b9"} --> Push a commit to this branch (recommended)
- [ ] <!-- {"checkboxId": "ff5b1114-7d8c-49e6-8ac1-43f82af23a33"} --> Create a new PR with the fixes
</details>
---
<details>
<summary>ℹ️ Review info</summary>
<details>
<summary>⚙️ Run configuration</summary>
**Configuration used**: Organization UI
**Review profile**: CHILL
**Plan**: Pro
**Run ID**: `b582a91e-d79f-48e3-bf7b-c0e17c7b23fc`
</details>
<details>
<summary>📥 Commits</summary>
Reviewing files that changed from the base of the PR and between 31a49fbdca243a4674ec07946f69e8479c86f1f9 and 1c6317daccebc1e2b2afe54cec38e735ac58d913.
</details>
<details>
<summary>📒 Files selected for processing (18)</summary>
* `.env.example`
* `.env.selfhost.example`
* `.github/workflows/test-web.yml`
* `CONTRIBUTION.md`
* `apps/docs/get-started/create-aws-credentials.mdx`
* `apps/docs/get-started/local.mdx`
* `apps/docs/get-started/set-up-docker.mdx`
* `apps/docs/self-hosting/overview.mdx`
* `apps/docs/self-hosting/railway.mdx`
* `apps/web/.env.test.example`
* `apps/web/src/env.js`
* `apps/web/src/server/aws/credentials.ts`
* `apps/web/src/server/aws/ses.ts`
* `apps/web/src/server/aws/sns.ts`
* `apps/web/src/test/setup/setup-env.ts`
* `docker/README.md`
* `docker/prod/compose.yml`
* `turbo.json`
</details>
</details>
<!-- This is an auto-generated comment by CodeRabbit for review status -->

Comment threadapps/web/src/env.js
Comment on lines +102 to +103
AWS_ACCESS_KEY_ID: process.env.AWS_ACCESS_KEY_ID || process.env.AWS_ACCESS_KEY,
AWS_SECRET_ACCESS_KEY: process.env.AWS_SECRET_ACCESS_KEY || process.env.AWS_SECRET_KEY,

@coderabbitaicoderabbitaiBotMay 17, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Avoid mixing standard and legacy credential sources across fields.

Line 102 and Line 103 independently fall back with ||, which can combine AWS_ACCESS_KEY_ID with legacy AWS_SECRET_KEY (or vice versa). That can create an invalid pair and undercut partial-config safeguards.

Suggested fix
- AWS_ACCESS_KEY_ID: process.env.AWS_ACCESS_KEY_ID || process.env.AWS_ACCESS_KEY,- AWS_SECRET_ACCESS_KEY: process.env.AWS_SECRET_ACCESS_KEY || process.env.AWS_SECRET_KEY,+ AWS_ACCESS_KEY_ID:+ process.env.AWS_ACCESS_KEY_ID ?? process.env.AWS_ACCESS_KEY,+ AWS_SECRET_ACCESS_KEY:+ process.env.AWS_ACCESS_KEY_ID != null ||+ process.env.AWS_SECRET_ACCESS_KEY != null+ ? process.env.AWS_SECRET_ACCESS_KEY+ : process.env.AWS_SECRET_KEY,
📝 Committable suggestion

‼️IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
AWS_ACCESS_KEY_ID: process.env.AWS_ACCESS_KEY_ID||process.env.AWS_ACCESS_KEY,
AWS_SECRET_ACCESS_KEY: process.env.AWS_SECRET_ACCESS_KEY||process.env.AWS_SECRET_KEY,
AWS_ACCESS_KEY_ID:
process.env.AWS_ACCESS_KEY_ID??process.env.AWS_ACCESS_KEY,
AWS_SECRET_ACCESS_KEY:
process.env.AWS_ACCESS_KEY_ID!=null||
process.env.AWS_SECRET_ACCESS_KEY!=null
? process.env.AWS_SECRET_ACCESS_KEY
: process.env.AWS_SECRET_KEY,
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@apps/web/src/env.js` around lines 102 - 103, The current fallback uses
independent || for AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY which can mix
standard and legacy values; update the logic so the code selects either the
standard pair (AWS_ACCESS_KEY_ID + AWS_SECRET_ACCESS_KEY) or, only if both are
absent, the legacy pair (AWS_ACCESS_KEY + AWS_SECRET) as a unit. In practice
change the assignment for AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY to a small
conditional that prefers the standard env vars together, otherwise uses the
legacy pair only when both legacy vars exist, and yields undefined/null if
neither full pair is present; reference the AWS_ACCESS_KEY_ID and
AWS_SECRET_ACCESS_KEY symbols when locating where to implement this.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nah thats fine, we should give responsibilty to users

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@KMKoushik, understood — the independent fallback is intentional, and the partial-config guard in getAwsCredentialOptions in credentials.ts will still catch the case where only one standard key is set at runtime. Acknowledged!

(ᵔ ᵕ ᵔ) 🐇


✏️ Learnings added
Learnt from: KMKoushik
Repo: usesend/useSend PR: 401
File: apps/web/src/env.js:102-103
Timestamp: 2026-05-17T11:17:08.286Z
Learning: In `apps/web/src/env.js` (usesend/useSend), the independent `||` fallback for `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` (falling back to legacy `AWS_ACCESS_KEY`/`AWS_SECRET_KEY` respectively) is intentional. The project maintainer explicitly chose to give users responsibility for providing consistent credential pairs rather than enforcing paired fallback logic at the env layer. The partial-config guard is handled at runtime in `apps/web/src/server/aws/credentials.ts` via `getAwsCredentialOptions()`.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

Comment threadapps/web/src/server/aws/ses.ts Outdated
Comment threadapps/web/src/server/aws/sns.ts Outdated

@greptile-appsgreptile-appsBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.

@KMKoushik
KMKoushik merged commit 04d0f4b into mainMay 17, 2026
7 checks passed
@KMKoushik
KMKoushik deleted the fix/aws-env-vars-on-pr-395 branch May 17, 2026 11:23
@coderabbitaicoderabbitaiBot mentioned this pull request Jul 31, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feat: Avoid hardcoding AWS credentials & support standard AWS env variables

2 participants

@KMKoushik@purva-8
, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
feat: support standard AWS env vars and default credential chain by KMKoushik · Pull Request #401 · usesend/useSend · GitHub
Skip to content

feat: support standard AWS env vars and default credential chain - #401

Merged
KMKoushik merged 5 commits into
mainfrom
fix/aws-env-vars-on-pr-395
May 17, 2026
Merged

feat: support standard AWS env vars and default credential chain#401
KMKoushik merged 5 commits into
mainfrom
fix/aws-env-vars-on-pr-395

Conversation

@KMKoushik

@KMKoushikKMKoushik commented May 17, 2026

Copy link
Copy Markdown
Member

Summary

  • Support standard AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY while keeping runtime fallback for existing legacy envs
  • Allow the AWS SDK default credential chain when static credentials are omitted
  • Align Docker, docs, CI env, and turbo env declarations with standard AWS names

Based on #395 by @purva-8, with maintainer fixes on top.

Closes#316

Verification

  • git diff --check
  • pnpm --filter=web exec eslint src/env.js next.config.js (AWS/turbo warnings resolved; unrelated existing warnings remain)

Merge note

If squash-merging and you want co-author credit preserved on the squash commit, include:

Co-authored-by: Purva Kandalgaonkar 136103488+purva-8@users.noreply.github.com


Summary by cubic

Switches to the standard AWS env vars AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY and enables the AWS SDK default credential chain when both are unset. Updates code, Docker, CI, docs, and Turbo config; legacy envs still work as fallbacks.

  • New Features

    • Use AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY; AWS_ACCESS_KEY / AWS_SECRET_KEY remain as runtime fallbacks.
    • Omit both vars to use the AWS SDK default credential chain for SES/SNS/STS.
    • Added getAwsCredentialOptions with a guard that errors on partial config.
    • Use an aliased import for the credentials helper to avoid path issues.
  • Migration

    • Prefer AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY, or rely on IAM/instance roles by leaving both unset.
    • Update your .env, CI, Docker, and Turbo env lists to the new names; examples and docs are aligned.

Written for commit b2147df. Summary will update on new commits. Review in cubic

Summary by CodeRabbit

  • New Features

    • Added AWS credential validation with safe fallback behavior; deployments can run without credentials set.
  • Documentation

    • Updated setup guides, examples, and run instructions to use the standardized AWS environment variable names.
  • Chores

    • Standardized AWS credential configuration across examples, tests, CI workflows, Docker, and build tooling to align with AWS conventions.

Review Change Stack

purva-8and others added 4 commits May 2, 2026 17:52
Replace non-standard AWS_ACCESS_KEY / AWS_SECRET_KEY with the AWS-standard
AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY. The old names are kept as
fallbacks in the runtimeEnv for backward compatibility.
Both vars are now optional. When omitted, the credentials object is not
passed to SESv2Client, STSClient, or SNSClient — the AWS SDK then falls
back to its default provider chain (IAM roles, ECS task roles, instance
profiles, etc.), which is the recommended approach for cloud-native deployments.
Closes#316
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
…al-config guard
- Move the credential spread logic into a single credentials.ts helper
so SESv2Client, STSClient, and SNSClient all share one implementation
- Throw a clear error if only one of AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY
is set, preventing silent fallback to the default provider chain with a
half-configured environment
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@vercel

vercelBot commented May 17, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

ProjectDeploymentActionsUpdated (UTC)
unsend-marketingReadyReadyPreview, CommentMay 17, 2026 11:21am

@greptile-appsgreptile-appsBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.

@coderabbitai

coderabbitaiBot commented May 17, 2026

Copy link
Copy Markdown
Contributor

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: e593e2ea-adba-4d19-9151-b80f2fe5a460

📥 Commits

Reviewing files that changed from the base of the PR and between 1c6317d and b2147df.

📒 Files selected for processing (2)
  • apps/web/src/server/aws/ses.ts
  • apps/web/src/server/aws/sns.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • apps/web/src/server/aws/sns.ts
  • apps/web/src/server/aws/ses.ts

Walkthrough

This PR standardizes AWS credential environment variable names from AWS_ACCESS_KEY/AWS_SECRET_KEY to AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY across examples, docs, CI, and runtime. It adds getAwsCredentialOptions() which returns explicit credentials when both env vars are set, throws on partial configuration, or returns an empty object so the AWS SDK default credential provider chain can be used. SES and SNS clients now use this helper instead of inline credential objects.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 0.00% which is insufficient. The required threshold is 80.00%.Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe PR title accurately summarizes the main changes: adding support for standard AWS environment variables and enabling the AWS default credential chain.
Linked Issues check✅ PassedThe PR successfully addresses all key requirements from issue #316: supports standard AWS env vars (AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY), makes credentials optional via default chain, maintains backward compatibility with legacy vars, and implements validation for partial configuration.
Out of Scope Changes check✅ PassedAll changes are directly related to the objective of supporting standard AWS environment variables and the credential chain. Updates to env files, documentation, CI workflows, and code are all in scope.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@cloudflare-workers-and-pages

cloudflare-workers-and-pagesBot commented May 17, 2026

Copy link
Copy Markdown

Deploying usesend with Cloudflare Pages Cloudflare Pages

Latest commit:b2147df
Status: ✅ Deploy successful!
Preview URL:https://6f7e6eeb.usesend.pages.dev
Branch Preview URL:https://fix-aws-env-vars-on-pr-395.usesend.pages.dev

View logs

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (1)
apps/docs/get-started/set-up-docker.mdx (1)

55-57: ⚡ Quick win

Document AWS static credentials as optional in standalone Docker flow.

Line 55–57 and Line 63 currently imply static AWS keys are always needed. Since credentials are now optional, please note that users can omit these vars when their runtime provides IAM-role/default credential chain access.

Proposed doc patch
 docker run -d \
-p 3000:3000 \
-e NEXTAUTH_URL="<your-nextauth-url>" \
-e NEXTAUTH_SECRET="<your-nextauth-secret>" \
-e DATABASE_URL="<your-next-private-database-url>" \
-e REDIS_URL="<your-next-private-redis-url>" \
- -e AWS_ACCESS_KEY_ID="<your-next-private-aws-access-key-id>" \- -e AWS_SECRET_ACCESS_KEY="<your-next-private-aws-secret-access-key>" \
-e AWS_DEFAULT_REGION="<your-next-private-aws-region>" \
-e GITHUB_ID="<your-next-private-github-id>" \
-e GITHUB_SECRET="<your-next-private-github-secret>" \
usesend/usesend

-Replace the placeholders with your actual database and AWS details.
+Replace the placeholders with your actual database details.
+If your environment does not provide AWS credentials via IAM/default provider chain, also set:
+AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY.

</details>
Also applies to: 63-63
<details>
<summary>🤖 Prompt for AI Agents</summary>

Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @apps/docs/get-started/set-up-docker.mdx around lines 55 - 57, Update the
Docker setup instructions so the AWS static credential environment variables
(AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_DEFAULT_REGION) are documented as
optional: change the text that currently tells users to "Replace the
placeholders with your actual database and AWS details." to "Replace the
placeholders with your actual database details. If your environment does not
provide AWS credentials via IAM/default provider chain, also set:
AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY." Ensure this change is applied to
the same explanatory lines that contain the three environment variable
placeholders and the similar line around the later occurrence (the one
referenced at line 63).


</details>
</blockquote></details>
</blockquote></details>
<details>
<summary>🤖 Prompt for all review comments with AI agents</summary>

Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @apps/web/src/env.js:

  • Around line 102-103: The current fallback uses independent || for
    AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY which can mix standard and legacy
    values; update the logic so the code selects either the standard pair
    (AWS_ACCESS_KEY_ID + AWS_SECRET_ACCESS_KEY) or, only if both are absent, the
    legacy pair (AWS_ACCESS_KEY + AWS_SECRET) as a unit. In practice change the
    assignment for AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY to a small
    conditional that prefers the standard env vars together, otherwise uses the
    legacy pair only when both legacy vars exist, and yields undefined/null if
    neither full pair is present; reference the AWS_ACCESS_KEY_ID and
    AWS_SECRET_ACCESS_KEY symbols when locating where to implement this.

In @apps/web/src/server/aws/ses.ts:

  • Line 20: Replace the relative import of getAwsCredentialOptions from
    "./credentials" with the repo-standard src alias import (e.g. import {
    getAwsCredentialOptions } from "~/server/aws/credentials";) so the module uses
    the ~/ alias form consistent with apps/web src imports.

In @apps/web/src/server/aws/sns.ts:

  • Line 8: Replace the relative import for getAwsCredentialOptions with the
    project src alias; change the import source from "./credentials" to the aliased
    module (e.g. "/server/aws/credentials") so the import reads: import {
    getAwsCredentialOptions } from "
    /server/aws/credentials"; this aligns the
    getAwsCredentialOptions import with the apps/web src alias convention.

Nitpick comments:
In @apps/docs/get-started/set-up-docker.mdx:

  • Around line 55-57: Update the Docker setup instructions so the AWS static
    credential environment variables (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY,
    AWS_DEFAULT_REGION) are documented as optional: change the text that currently
    tells users to "Replace the placeholders with your actual database and AWS
    details." to "Replace the placeholders with your actual database details. If
    your environment does not provide AWS credentials via IAM/default provider
    chain, also set: AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY." Ensure this
    change is applied to the same explanatory lines that contain the three
    environment variable placeholders and the similar line around the later
    occurrence (the one referenced at line 63).

</details>
<details>
<summary>🪄 Autofix (Beta)</summary>
Fix all unresolved CodeRabbit comments on this PR:
- [ ] <!-- {"checkboxId": "4b0d0e0a-96d7-4f10-b296-3a18ea78f0b9"} --> Push a commit to this branch (recommended)
- [ ] <!-- {"checkboxId": "ff5b1114-7d8c-49e6-8ac1-43f82af23a33"} --> Create a new PR with the fixes
</details>
---
<details>
<summary>ℹ️ Review info</summary>
<details>
<summary>⚙️ Run configuration</summary>
**Configuration used**: Organization UI
**Review profile**: CHILL
**Plan**: Pro
**Run ID**: `b582a91e-d79f-48e3-bf7b-c0e17c7b23fc`
</details>
<details>
<summary>📥 Commits</summary>
Reviewing files that changed from the base of the PR and between 31a49fbdca243a4674ec07946f69e8479c86f1f9 and 1c6317daccebc1e2b2afe54cec38e735ac58d913.
</details>
<details>
<summary>📒 Files selected for processing (18)</summary>
* `.env.example`
* `.env.selfhost.example`
* `.github/workflows/test-web.yml`
* `CONTRIBUTION.md`
* `apps/docs/get-started/create-aws-credentials.mdx`
* `apps/docs/get-started/local.mdx`
* `apps/docs/get-started/set-up-docker.mdx`
* `apps/docs/self-hosting/overview.mdx`
* `apps/docs/self-hosting/railway.mdx`
* `apps/web/.env.test.example`
* `apps/web/src/env.js`
* `apps/web/src/server/aws/credentials.ts`
* `apps/web/src/server/aws/ses.ts`
* `apps/web/src/server/aws/sns.ts`
* `apps/web/src/test/setup/setup-env.ts`
* `docker/README.md`
* `docker/prod/compose.yml`
* `turbo.json`
</details>
</details>
<!-- This is an auto-generated comment by CodeRabbit for review status -->

Comment threadapps/web/src/env.js
Comment on lines +102 to +103
AWS_ACCESS_KEY_ID: process.env.AWS_ACCESS_KEY_ID || process.env.AWS_ACCESS_KEY,
AWS_SECRET_ACCESS_KEY: process.env.AWS_SECRET_ACCESS_KEY || process.env.AWS_SECRET_KEY,

@coderabbitaicoderabbitaiBotMay 17, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Avoid mixing standard and legacy credential sources across fields.

Line 102 and Line 103 independently fall back with ||, which can combine AWS_ACCESS_KEY_ID with legacy AWS_SECRET_KEY (or vice versa). That can create an invalid pair and undercut partial-config safeguards.

Suggested fix
- AWS_ACCESS_KEY_ID: process.env.AWS_ACCESS_KEY_ID || process.env.AWS_ACCESS_KEY,- AWS_SECRET_ACCESS_KEY: process.env.AWS_SECRET_ACCESS_KEY || process.env.AWS_SECRET_KEY,+ AWS_ACCESS_KEY_ID:+ process.env.AWS_ACCESS_KEY_ID ?? process.env.AWS_ACCESS_KEY,+ AWS_SECRET_ACCESS_KEY:+ process.env.AWS_ACCESS_KEY_ID != null ||+ process.env.AWS_SECRET_ACCESS_KEY != null+ ? process.env.AWS_SECRET_ACCESS_KEY+ : process.env.AWS_SECRET_KEY,
📝 Committable suggestion

‼️IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
AWS_ACCESS_KEY_ID: process.env.AWS_ACCESS_KEY_ID||process.env.AWS_ACCESS_KEY,
AWS_SECRET_ACCESS_KEY: process.env.AWS_SECRET_ACCESS_KEY||process.env.AWS_SECRET_KEY,
AWS_ACCESS_KEY_ID:
process.env.AWS_ACCESS_KEY_ID??process.env.AWS_ACCESS_KEY,
AWS_SECRET_ACCESS_KEY:
process.env.AWS_ACCESS_KEY_ID!=null||
process.env.AWS_SECRET_ACCESS_KEY!=null
? process.env.AWS_SECRET_ACCESS_KEY
: process.env.AWS_SECRET_KEY,
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@apps/web/src/env.js` around lines 102 - 103, The current fallback uses
independent || for AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY which can mix
standard and legacy values; update the logic so the code selects either the
standard pair (AWS_ACCESS_KEY_ID + AWS_SECRET_ACCESS_KEY) or, only if both are
absent, the legacy pair (AWS_ACCESS_KEY + AWS_SECRET) as a unit. In practice
change the assignment for AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY to a small
conditional that prefers the standard env vars together, otherwise uses the
legacy pair only when both legacy vars exist, and yields undefined/null if
neither full pair is present; reference the AWS_ACCESS_KEY_ID and
AWS_SECRET_ACCESS_KEY symbols when locating where to implement this.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nah thats fine, we should give responsibilty to users

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@KMKoushik, understood — the independent fallback is intentional, and the partial-config guard in getAwsCredentialOptions in credentials.ts will still catch the case where only one standard key is set at runtime. Acknowledged!

(ᵔ ᵕ ᵔ) 🐇


✏️ Learnings added
Learnt from: KMKoushik
Repo: usesend/useSend PR: 401
File: apps/web/src/env.js:102-103
Timestamp: 2026-05-17T11:17:08.286Z
Learning: In `apps/web/src/env.js` (usesend/useSend), the independent `||` fallback for `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` (falling back to legacy `AWS_ACCESS_KEY`/`AWS_SECRET_KEY` respectively) is intentional. The project maintainer explicitly chose to give users responsibility for providing consistent credential pairs rather than enforcing paired fallback logic at the env layer. The partial-config guard is handled at runtime in `apps/web/src/server/aws/credentials.ts` via `getAwsCredentialOptions()`.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

Comment threadapps/web/src/server/aws/ses.ts Outdated
Comment threadapps/web/src/server/aws/sns.ts Outdated

@greptile-appsgreptile-appsBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.

@KMKoushik
KMKoushik merged commit 04d0f4b into mainMay 17, 2026
7 checks passed
@KMKoushik
KMKoushik deleted the fix/aws-env-vars-on-pr-395 branch May 17, 2026 11:23
@coderabbitaicoderabbitaiBot mentioned this pull request Jul 31, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feat: Avoid hardcoding AWS credentials & support standard AWS env variables

2 participants

@KMKoushik@purva-8
, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' feat: support standard AWS env vars and default credential chain by KMKoushik · Pull Request #401 · usesend/useSend · GitHub
Skip to content

feat: support standard AWS env vars and default credential chain - #401

Merged
KMKoushik merged 5 commits into
mainfrom
fix/aws-env-vars-on-pr-395
May 17, 2026
Merged

feat: support standard AWS env vars and default credential chain#401
KMKoushik merged 5 commits into
mainfrom
fix/aws-env-vars-on-pr-395

Conversation

@KMKoushik

@KMKoushikKMKoushik commented May 17, 2026

Copy link
Copy Markdown
Member

Summary

  • Support standard AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY while keeping runtime fallback for existing legacy envs
  • Allow the AWS SDK default credential chain when static credentials are omitted
  • Align Docker, docs, CI env, and turbo env declarations with standard AWS names

Based on #395 by @purva-8, with maintainer fixes on top.

Closes#316

Verification

  • git diff --check
  • pnpm --filter=web exec eslint src/env.js next.config.js (AWS/turbo warnings resolved; unrelated existing warnings remain)

Merge note

If squash-merging and you want co-author credit preserved on the squash commit, include:

Co-authored-by: Purva Kandalgaonkar 136103488+purva-8@users.noreply.github.com


Summary by cubic

Switches to the standard AWS env vars AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY and enables the AWS SDK default credential chain when both are unset. Updates code, Docker, CI, docs, and Turbo config; legacy envs still work as fallbacks.

  • New Features

    • Use AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY; AWS_ACCESS_KEY / AWS_SECRET_KEY remain as runtime fallbacks.
    • Omit both vars to use the AWS SDK default credential chain for SES/SNS/STS.
    • Added getAwsCredentialOptions with a guard that errors on partial config.
    • Use an aliased import for the credentials helper to avoid path issues.
  • Migration

    • Prefer AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY, or rely on IAM/instance roles by leaving both unset.
    • Update your .env, CI, Docker, and Turbo env lists to the new names; examples and docs are aligned.

Written for commit b2147df. Summary will update on new commits. Review in cubic

Summary by CodeRabbit

  • New Features

    • Added AWS credential validation with safe fallback behavior; deployments can run without credentials set.
  • Documentation

    • Updated setup guides, examples, and run instructions to use the standardized AWS environment variable names.
  • Chores

    • Standardized AWS credential configuration across examples, tests, CI workflows, Docker, and build tooling to align with AWS conventions.

Review Change Stack

purva-8and others added 4 commits May 2, 2026 17:52
Replace non-standard AWS_ACCESS_KEY / AWS_SECRET_KEY with the AWS-standard
AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY. The old names are kept as
fallbacks in the runtimeEnv for backward compatibility.
Both vars are now optional. When omitted, the credentials object is not
passed to SESv2Client, STSClient, or SNSClient — the AWS SDK then falls
back to its default provider chain (IAM roles, ECS task roles, instance
profiles, etc.), which is the recommended approach for cloud-native deployments.
Closes#316
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
…al-config guard
- Move the credential spread logic into a single credentials.ts helper
so SESv2Client, STSClient, and SNSClient all share one implementation
- Throw a clear error if only one of AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY
is set, preventing silent fallback to the default provider chain with a
half-configured environment
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@vercel

vercelBot commented May 17, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

ProjectDeploymentActionsUpdated (UTC)
unsend-marketingReadyReadyPreview, CommentMay 17, 2026 11:21am

@greptile-appsgreptile-appsBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.

@coderabbitai

coderabbitaiBot commented May 17, 2026

Copy link
Copy Markdown
Contributor

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: e593e2ea-adba-4d19-9151-b80f2fe5a460

📥 Commits

Reviewing files that changed from the base of the PR and between 1c6317d and b2147df.

📒 Files selected for processing (2)
  • apps/web/src/server/aws/ses.ts
  • apps/web/src/server/aws/sns.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • apps/web/src/server/aws/sns.ts
  • apps/web/src/server/aws/ses.ts

Walkthrough

This PR standardizes AWS credential environment variable names from AWS_ACCESS_KEY/AWS_SECRET_KEY to AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY across examples, docs, CI, and runtime. It adds getAwsCredentialOptions() which returns explicit credentials when both env vars are set, throws on partial configuration, or returns an empty object so the AWS SDK default credential provider chain can be used. SES and SNS clients now use this helper instead of inline credential objects.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 0.00% which is insufficient. The required threshold is 80.00%.Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe PR title accurately summarizes the main changes: adding support for standard AWS environment variables and enabling the AWS default credential chain.
Linked Issues check✅ PassedThe PR successfully addresses all key requirements from issue #316: supports standard AWS env vars (AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY), makes credentials optional via default chain, maintains backward compatibility with legacy vars, and implements validation for partial configuration.
Out of Scope Changes check✅ PassedAll changes are directly related to the objective of supporting standard AWS environment variables and the credential chain. Updates to env files, documentation, CI workflows, and code are all in scope.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@cloudflare-workers-and-pages

cloudflare-workers-and-pagesBot commented May 17, 2026

Copy link
Copy Markdown

Deploying usesend with Cloudflare Pages Cloudflare Pages

Latest commit:b2147df
Status: ✅ Deploy successful!
Preview URL:https://6f7e6eeb.usesend.pages.dev
Branch Preview URL:https://fix-aws-env-vars-on-pr-395.usesend.pages.dev

View logs

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (1)
apps/docs/get-started/set-up-docker.mdx (1)

55-57: ⚡ Quick win

Document AWS static credentials as optional in standalone Docker flow.

Line 55–57 and Line 63 currently imply static AWS keys are always needed. Since credentials are now optional, please note that users can omit these vars when their runtime provides IAM-role/default credential chain access.

Proposed doc patch
 docker run -d \
-p 3000:3000 \
-e NEXTAUTH_URL="<your-nextauth-url>" \
-e NEXTAUTH_SECRET="<your-nextauth-secret>" \
-e DATABASE_URL="<your-next-private-database-url>" \
-e REDIS_URL="<your-next-private-redis-url>" \
- -e AWS_ACCESS_KEY_ID="<your-next-private-aws-access-key-id>" \- -e AWS_SECRET_ACCESS_KEY="<your-next-private-aws-secret-access-key>" \
-e AWS_DEFAULT_REGION="<your-next-private-aws-region>" \
-e GITHUB_ID="<your-next-private-github-id>" \
-e GITHUB_SECRET="<your-next-private-github-secret>" \
usesend/usesend

-Replace the placeholders with your actual database and AWS details.
+Replace the placeholders with your actual database details.
+If your environment does not provide AWS credentials via IAM/default provider chain, also set:
+AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY.

</details>
Also applies to: 63-63
<details>
<summary>🤖 Prompt for AI Agents</summary>

Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @apps/docs/get-started/set-up-docker.mdx around lines 55 - 57, Update the
Docker setup instructions so the AWS static credential environment variables
(AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_DEFAULT_REGION) are documented as
optional: change the text that currently tells users to "Replace the
placeholders with your actual database and AWS details." to "Replace the
placeholders with your actual database details. If your environment does not
provide AWS credentials via IAM/default provider chain, also set:
AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY." Ensure this change is applied to
the same explanatory lines that contain the three environment variable
placeholders and the similar line around the later occurrence (the one
referenced at line 63).


</details>
</blockquote></details>
</blockquote></details>
<details>
<summary>🤖 Prompt for all review comments with AI agents</summary>

Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @apps/web/src/env.js:

  • Around line 102-103: The current fallback uses independent || for
    AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY which can mix standard and legacy
    values; update the logic so the code selects either the standard pair
    (AWS_ACCESS_KEY_ID + AWS_SECRET_ACCESS_KEY) or, only if both are absent, the
    legacy pair (AWS_ACCESS_KEY + AWS_SECRET) as a unit. In practice change the
    assignment for AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY to a small
    conditional that prefers the standard env vars together, otherwise uses the
    legacy pair only when both legacy vars exist, and yields undefined/null if
    neither full pair is present; reference the AWS_ACCESS_KEY_ID and
    AWS_SECRET_ACCESS_KEY symbols when locating where to implement this.

In @apps/web/src/server/aws/ses.ts:

  • Line 20: Replace the relative import of getAwsCredentialOptions from
    "./credentials" with the repo-standard src alias import (e.g. import {
    getAwsCredentialOptions } from "~/server/aws/credentials";) so the module uses
    the ~/ alias form consistent with apps/web src imports.

In @apps/web/src/server/aws/sns.ts:

  • Line 8: Replace the relative import for getAwsCredentialOptions with the
    project src alias; change the import source from "./credentials" to the aliased
    module (e.g. "/server/aws/credentials") so the import reads: import {
    getAwsCredentialOptions } from "
    /server/aws/credentials"; this aligns the
    getAwsCredentialOptions import with the apps/web src alias convention.

Nitpick comments:
In @apps/docs/get-started/set-up-docker.mdx:

  • Around line 55-57: Update the Docker setup instructions so the AWS static
    credential environment variables (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY,
    AWS_DEFAULT_REGION) are documented as optional: change the text that currently
    tells users to "Replace the placeholders with your actual database and AWS
    details." to "Replace the placeholders with your actual database details. If
    your environment does not provide AWS credentials via IAM/default provider
    chain, also set: AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY." Ensure this
    change is applied to the same explanatory lines that contain the three
    environment variable placeholders and the similar line around the later
    occurrence (the one referenced at line 63).

</details>
<details>
<summary>🪄 Autofix (Beta)</summary>
Fix all unresolved CodeRabbit comments on this PR:
- [ ] <!-- {"checkboxId": "4b0d0e0a-96d7-4f10-b296-3a18ea78f0b9"} --> Push a commit to this branch (recommended)
- [ ] <!-- {"checkboxId": "ff5b1114-7d8c-49e6-8ac1-43f82af23a33"} --> Create a new PR with the fixes
</details>
---
<details>
<summary>ℹ️ Review info</summary>
<details>
<summary>⚙️ Run configuration</summary>
**Configuration used**: Organization UI
**Review profile**: CHILL
**Plan**: Pro
**Run ID**: `b582a91e-d79f-48e3-bf7b-c0e17c7b23fc`
</details>
<details>
<summary>📥 Commits</summary>
Reviewing files that changed from the base of the PR and between 31a49fbdca243a4674ec07946f69e8479c86f1f9 and 1c6317daccebc1e2b2afe54cec38e735ac58d913.
</details>
<details>
<summary>📒 Files selected for processing (18)</summary>
* `.env.example`
* `.env.selfhost.example`
* `.github/workflows/test-web.yml`
* `CONTRIBUTION.md`
* `apps/docs/get-started/create-aws-credentials.mdx`
* `apps/docs/get-started/local.mdx`
* `apps/docs/get-started/set-up-docker.mdx`
* `apps/docs/self-hosting/overview.mdx`
* `apps/docs/self-hosting/railway.mdx`
* `apps/web/.env.test.example`
* `apps/web/src/env.js`
* `apps/web/src/server/aws/credentials.ts`
* `apps/web/src/server/aws/ses.ts`
* `apps/web/src/server/aws/sns.ts`
* `apps/web/src/test/setup/setup-env.ts`
* `docker/README.md`
* `docker/prod/compose.yml`
* `turbo.json`
</details>
</details>
<!-- This is an auto-generated comment by CodeRabbit for review status -->

Comment threadapps/web/src/env.js
Comment on lines +102 to +103
AWS_ACCESS_KEY_ID: process.env.AWS_ACCESS_KEY_ID || process.env.AWS_ACCESS_KEY,
AWS_SECRET_ACCESS_KEY: process.env.AWS_SECRET_ACCESS_KEY || process.env.AWS_SECRET_KEY,

@coderabbitaicoderabbitaiBotMay 17, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Avoid mixing standard and legacy credential sources across fields.

Line 102 and Line 103 independently fall back with ||, which can combine AWS_ACCESS_KEY_ID with legacy AWS_SECRET_KEY (or vice versa). That can create an invalid pair and undercut partial-config safeguards.

Suggested fix
- AWS_ACCESS_KEY_ID: process.env.AWS_ACCESS_KEY_ID || process.env.AWS_ACCESS_KEY,- AWS_SECRET_ACCESS_KEY: process.env.AWS_SECRET_ACCESS_KEY || process.env.AWS_SECRET_KEY,+ AWS_ACCESS_KEY_ID:+ process.env.AWS_ACCESS_KEY_ID ?? process.env.AWS_ACCESS_KEY,+ AWS_SECRET_ACCESS_KEY:+ process.env.AWS_ACCESS_KEY_ID != null ||+ process.env.AWS_SECRET_ACCESS_KEY != null+ ? process.env.AWS_SECRET_ACCESS_KEY+ : process.env.AWS_SECRET_KEY,
📝 Committable suggestion

‼️IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
AWS_ACCESS_KEY_ID: process.env.AWS_ACCESS_KEY_ID||process.env.AWS_ACCESS_KEY,
AWS_SECRET_ACCESS_KEY: process.env.AWS_SECRET_ACCESS_KEY||process.env.AWS_SECRET_KEY,
AWS_ACCESS_KEY_ID:
process.env.AWS_ACCESS_KEY_ID??process.env.AWS_ACCESS_KEY,
AWS_SECRET_ACCESS_KEY:
process.env.AWS_ACCESS_KEY_ID!=null||
process.env.AWS_SECRET_ACCESS_KEY!=null
? process.env.AWS_SECRET_ACCESS_KEY
: process.env.AWS_SECRET_KEY,
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@apps/web/src/env.js` around lines 102 - 103, The current fallback uses
independent || for AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY which can mix
standard and legacy values; update the logic so the code selects either the
standard pair (AWS_ACCESS_KEY_ID + AWS_SECRET_ACCESS_KEY) or, only if both are
absent, the legacy pair (AWS_ACCESS_KEY + AWS_SECRET) as a unit. In practice
change the assignment for AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY to a small
conditional that prefers the standard env vars together, otherwise uses the
legacy pair only when both legacy vars exist, and yields undefined/null if
neither full pair is present; reference the AWS_ACCESS_KEY_ID and
AWS_SECRET_ACCESS_KEY symbols when locating where to implement this.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nah thats fine, we should give responsibilty to users

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@KMKoushik, understood — the independent fallback is intentional, and the partial-config guard in getAwsCredentialOptions in credentials.ts will still catch the case where only one standard key is set at runtime. Acknowledged!

(ᵔ ᵕ ᵔ) 🐇


✏️ Learnings added
Learnt from: KMKoushik
Repo: usesend/useSend PR: 401
File: apps/web/src/env.js:102-103
Timestamp: 2026-05-17T11:17:08.286Z
Learning: In `apps/web/src/env.js` (usesend/useSend), the independent `||` fallback for `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` (falling back to legacy `AWS_ACCESS_KEY`/`AWS_SECRET_KEY` respectively) is intentional. The project maintainer explicitly chose to give users responsibility for providing consistent credential pairs rather than enforcing paired fallback logic at the env layer. The partial-config guard is handled at runtime in `apps/web/src/server/aws/credentials.ts` via `getAwsCredentialOptions()`.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

Comment threadapps/web/src/server/aws/ses.ts Outdated
Comment threadapps/web/src/server/aws/sns.ts Outdated

@greptile-appsgreptile-appsBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.

@KMKoushik
KMKoushik merged commit 04d0f4b into mainMay 17, 2026
7 checks passed
@KMKoushik
KMKoushik deleted the fix/aws-env-vars-on-pr-395 branch May 17, 2026 11:23
@coderabbitaicoderabbitaiBot mentioned this pull request Jul 31, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feat: Avoid hardcoding AWS credentials & support standard AWS env variables

2 participants

@KMKoushik@purva-8
, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' feat: support standard AWS env vars and default credential chain by KMKoushik · Pull Request #401 · usesend/useSend · GitHub
Skip to content

feat: support standard AWS env vars and default credential chain - #401

Merged
KMKoushik merged 5 commits into
mainfrom
fix/aws-env-vars-on-pr-395
May 17, 2026
Merged

feat: support standard AWS env vars and default credential chain#401
KMKoushik merged 5 commits into
mainfrom
fix/aws-env-vars-on-pr-395

Conversation

@KMKoushik

@KMKoushikKMKoushik commented May 17, 2026

Copy link
Copy Markdown
Member

Summary

  • Support standard AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY while keeping runtime fallback for existing legacy envs
  • Allow the AWS SDK default credential chain when static credentials are omitted
  • Align Docker, docs, CI env, and turbo env declarations with standard AWS names

Based on #395 by @purva-8, with maintainer fixes on top.

Closes#316

Verification

  • git diff --check
  • pnpm --filter=web exec eslint src/env.js next.config.js (AWS/turbo warnings resolved; unrelated existing warnings remain)

Merge note

If squash-merging and you want co-author credit preserved on the squash commit, include:

Co-authored-by: Purva Kandalgaonkar 136103488+purva-8@users.noreply.github.com


Summary by cubic

Switches to the standard AWS env vars AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY and enables the AWS SDK default credential chain when both are unset. Updates code, Docker, CI, docs, and Turbo config; legacy envs still work as fallbacks.

  • New Features

    • Use AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY; AWS_ACCESS_KEY / AWS_SECRET_KEY remain as runtime fallbacks.
    • Omit both vars to use the AWS SDK default credential chain for SES/SNS/STS.
    • Added getAwsCredentialOptions with a guard that errors on partial config.
    • Use an aliased import for the credentials helper to avoid path issues.
  • Migration

    • Prefer AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY, or rely on IAM/instance roles by leaving both unset.
    • Update your .env, CI, Docker, and Turbo env lists to the new names; examples and docs are aligned.

Written for commit b2147df. Summary will update on new commits. Review in cubic

Summary by CodeRabbit

  • New Features

    • Added AWS credential validation with safe fallback behavior; deployments can run without credentials set.
  • Documentation

    • Updated setup guides, examples, and run instructions to use the standardized AWS environment variable names.
  • Chores

    • Standardized AWS credential configuration across examples, tests, CI workflows, Docker, and build tooling to align with AWS conventions.

Review Change Stack

purva-8and others added 4 commits May 2, 2026 17:52
Replace non-standard AWS_ACCESS_KEY / AWS_SECRET_KEY with the AWS-standard
AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY. The old names are kept as
fallbacks in the runtimeEnv for backward compatibility.
Both vars are now optional. When omitted, the credentials object is not
passed to SESv2Client, STSClient, or SNSClient — the AWS SDK then falls
back to its default provider chain (IAM roles, ECS task roles, instance
profiles, etc.), which is the recommended approach for cloud-native deployments.
Closes#316
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
…al-config guard
- Move the credential spread logic into a single credentials.ts helper
so SESv2Client, STSClient, and SNSClient all share one implementation
- Throw a clear error if only one of AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY
is set, preventing silent fallback to the default provider chain with a
half-configured environment
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@vercel

vercelBot commented May 17, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

ProjectDeploymentActionsUpdated (UTC)
unsend-marketingReadyReadyPreview, CommentMay 17, 2026 11:21am

@greptile-appsgreptile-appsBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.

@coderabbitai

coderabbitaiBot commented May 17, 2026

Copy link
Copy Markdown
Contributor

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: e593e2ea-adba-4d19-9151-b80f2fe5a460

📥 Commits

Reviewing files that changed from the base of the PR and between 1c6317d and b2147df.

📒 Files selected for processing (2)
  • apps/web/src/server/aws/ses.ts
  • apps/web/src/server/aws/sns.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • apps/web/src/server/aws/sns.ts
  • apps/web/src/server/aws/ses.ts

Walkthrough

This PR standardizes AWS credential environment variable names from AWS_ACCESS_KEY/AWS_SECRET_KEY to AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY across examples, docs, CI, and runtime. It adds getAwsCredentialOptions() which returns explicit credentials when both env vars are set, throws on partial configuration, or returns an empty object so the AWS SDK default credential provider chain can be used. SES and SNS clients now use this helper instead of inline credential objects.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 0.00% which is insufficient. The required threshold is 80.00%.Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe PR title accurately summarizes the main changes: adding support for standard AWS environment variables and enabling the AWS default credential chain.
Linked Issues check✅ PassedThe PR successfully addresses all key requirements from issue #316: supports standard AWS env vars (AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY), makes credentials optional via default chain, maintains backward compatibility with legacy vars, and implements validation for partial configuration.
Out of Scope Changes check✅ PassedAll changes are directly related to the objective of supporting standard AWS environment variables and the credential chain. Updates to env files, documentation, CI workflows, and code are all in scope.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@cloudflare-workers-and-pages

cloudflare-workers-and-pagesBot commented May 17, 2026

Copy link
Copy Markdown

Deploying usesend with Cloudflare Pages Cloudflare Pages

Latest commit:b2147df
Status: ✅ Deploy successful!
Preview URL:https://6f7e6eeb.usesend.pages.dev
Branch Preview URL:https://fix-aws-env-vars-on-pr-395.usesend.pages.dev

View logs

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (1)
apps/docs/get-started/set-up-docker.mdx (1)

55-57: ⚡ Quick win

Document AWS static credentials as optional in standalone Docker flow.

Line 55–57 and Line 63 currently imply static AWS keys are always needed. Since credentials are now optional, please note that users can omit these vars when their runtime provides IAM-role/default credential chain access.

Proposed doc patch
 docker run -d \
-p 3000:3000 \
-e NEXTAUTH_URL="<your-nextauth-url>" \
-e NEXTAUTH_SECRET="<your-nextauth-secret>" \
-e DATABASE_URL="<your-next-private-database-url>" \
-e REDIS_URL="<your-next-private-redis-url>" \
- -e AWS_ACCESS_KEY_ID="<your-next-private-aws-access-key-id>" \- -e AWS_SECRET_ACCESS_KEY="<your-next-private-aws-secret-access-key>" \
-e AWS_DEFAULT_REGION="<your-next-private-aws-region>" \
-e GITHUB_ID="<your-next-private-github-id>" \
-e GITHUB_SECRET="<your-next-private-github-secret>" \
usesend/usesend

-Replace the placeholders with your actual database and AWS details.
+Replace the placeholders with your actual database details.
+If your environment does not provide AWS credentials via IAM/default provider chain, also set:
+AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY.

</details>
Also applies to: 63-63
<details>
<summary>🤖 Prompt for AI Agents</summary>

Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @apps/docs/get-started/set-up-docker.mdx around lines 55 - 57, Update the
Docker setup instructions so the AWS static credential environment variables
(AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_DEFAULT_REGION) are documented as
optional: change the text that currently tells users to "Replace the
placeholders with your actual database and AWS details." to "Replace the
placeholders with your actual database details. If your environment does not
provide AWS credentials via IAM/default provider chain, also set:
AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY." Ensure this change is applied to
the same explanatory lines that contain the three environment variable
placeholders and the similar line around the later occurrence (the one
referenced at line 63).


</details>
</blockquote></details>
</blockquote></details>
<details>
<summary>🤖 Prompt for all review comments with AI agents</summary>

Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @apps/web/src/env.js:

  • Around line 102-103: The current fallback uses independent || for
    AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY which can mix standard and legacy
    values; update the logic so the code selects either the standard pair
    (AWS_ACCESS_KEY_ID + AWS_SECRET_ACCESS_KEY) or, only if both are absent, the
    legacy pair (AWS_ACCESS_KEY + AWS_SECRET) as a unit. In practice change the
    assignment for AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY to a small
    conditional that prefers the standard env vars together, otherwise uses the
    legacy pair only when both legacy vars exist, and yields undefined/null if
    neither full pair is present; reference the AWS_ACCESS_KEY_ID and
    AWS_SECRET_ACCESS_KEY symbols when locating where to implement this.

In @apps/web/src/server/aws/ses.ts:

  • Line 20: Replace the relative import of getAwsCredentialOptions from
    "./credentials" with the repo-standard src alias import (e.g. import {
    getAwsCredentialOptions } from "~/server/aws/credentials";) so the module uses
    the ~/ alias form consistent with apps/web src imports.

In @apps/web/src/server/aws/sns.ts:

  • Line 8: Replace the relative import for getAwsCredentialOptions with the
    project src alias; change the import source from "./credentials" to the aliased
    module (e.g. "/server/aws/credentials") so the import reads: import {
    getAwsCredentialOptions } from "
    /server/aws/credentials"; this aligns the
    getAwsCredentialOptions import with the apps/web src alias convention.

Nitpick comments:
In @apps/docs/get-started/set-up-docker.mdx:

  • Around line 55-57: Update the Docker setup instructions so the AWS static
    credential environment variables (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY,
    AWS_DEFAULT_REGION) are documented as optional: change the text that currently
    tells users to "Replace the placeholders with your actual database and AWS
    details." to "Replace the placeholders with your actual database details. If
    your environment does not provide AWS credentials via IAM/default provider
    chain, also set: AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY." Ensure this
    change is applied to the same explanatory lines that contain the three
    environment variable placeholders and the similar line around the later
    occurrence (the one referenced at line 63).

</details>
<details>
<summary>🪄 Autofix (Beta)</summary>
Fix all unresolved CodeRabbit comments on this PR:
- [ ] <!-- {"checkboxId": "4b0d0e0a-96d7-4f10-b296-3a18ea78f0b9"} --> Push a commit to this branch (recommended)
- [ ] <!-- {"checkboxId": "ff5b1114-7d8c-49e6-8ac1-43f82af23a33"} --> Create a new PR with the fixes
</details>
---
<details>
<summary>ℹ️ Review info</summary>
<details>
<summary>⚙️ Run configuration</summary>
**Configuration used**: Organization UI
**Review profile**: CHILL
**Plan**: Pro
**Run ID**: `b582a91e-d79f-48e3-bf7b-c0e17c7b23fc`
</details>
<details>
<summary>📥 Commits</summary>
Reviewing files that changed from the base of the PR and between 31a49fbdca243a4674ec07946f69e8479c86f1f9 and 1c6317daccebc1e2b2afe54cec38e735ac58d913.
</details>
<details>
<summary>📒 Files selected for processing (18)</summary>
* `.env.example`
* `.env.selfhost.example`
* `.github/workflows/test-web.yml`
* `CONTRIBUTION.md`
* `apps/docs/get-started/create-aws-credentials.mdx`
* `apps/docs/get-started/local.mdx`
* `apps/docs/get-started/set-up-docker.mdx`
* `apps/docs/self-hosting/overview.mdx`
* `apps/docs/self-hosting/railway.mdx`
* `apps/web/.env.test.example`
* `apps/web/src/env.js`
* `apps/web/src/server/aws/credentials.ts`
* `apps/web/src/server/aws/ses.ts`
* `apps/web/src/server/aws/sns.ts`
* `apps/web/src/test/setup/setup-env.ts`
* `docker/README.md`
* `docker/prod/compose.yml`
* `turbo.json`
</details>
</details>
<!-- This is an auto-generated comment by CodeRabbit for review status -->

Comment threadapps/web/src/env.js
Comment on lines +102 to +103
AWS_ACCESS_KEY_ID: process.env.AWS_ACCESS_KEY_ID || process.env.AWS_ACCESS_KEY,
AWS_SECRET_ACCESS_KEY: process.env.AWS_SECRET_ACCESS_KEY || process.env.AWS_SECRET_KEY,

@coderabbitaicoderabbitaiBotMay 17, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Avoid mixing standard and legacy credential sources across fields.

Line 102 and Line 103 independently fall back with ||, which can combine AWS_ACCESS_KEY_ID with legacy AWS_SECRET_KEY (or vice versa). That can create an invalid pair and undercut partial-config safeguards.

Suggested fix
- AWS_ACCESS_KEY_ID: process.env.AWS_ACCESS_KEY_ID || process.env.AWS_ACCESS_KEY,- AWS_SECRET_ACCESS_KEY: process.env.AWS_SECRET_ACCESS_KEY || process.env.AWS_SECRET_KEY,+ AWS_ACCESS_KEY_ID:+ process.env.AWS_ACCESS_KEY_ID ?? process.env.AWS_ACCESS_KEY,+ AWS_SECRET_ACCESS_KEY:+ process.env.AWS_ACCESS_KEY_ID != null ||+ process.env.AWS_SECRET_ACCESS_KEY != null+ ? process.env.AWS_SECRET_ACCESS_KEY+ : process.env.AWS_SECRET_KEY,
📝 Committable suggestion

‼️IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
AWS_ACCESS_KEY_ID: process.env.AWS_ACCESS_KEY_ID||process.env.AWS_ACCESS_KEY,
AWS_SECRET_ACCESS_KEY: process.env.AWS_SECRET_ACCESS_KEY||process.env.AWS_SECRET_KEY,
AWS_ACCESS_KEY_ID:
process.env.AWS_ACCESS_KEY_ID??process.env.AWS_ACCESS_KEY,
AWS_SECRET_ACCESS_KEY:
process.env.AWS_ACCESS_KEY_ID!=null||
process.env.AWS_SECRET_ACCESS_KEY!=null
? process.env.AWS_SECRET_ACCESS_KEY
: process.env.AWS_SECRET_KEY,
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@apps/web/src/env.js` around lines 102 - 103, The current fallback uses
independent || for AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY which can mix
standard and legacy values; update the logic so the code selects either the
standard pair (AWS_ACCESS_KEY_ID + AWS_SECRET_ACCESS_KEY) or, only if both are
absent, the legacy pair (AWS_ACCESS_KEY + AWS_SECRET) as a unit. In practice
change the assignment for AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY to a small
conditional that prefers the standard env vars together, otherwise uses the
legacy pair only when both legacy vars exist, and yields undefined/null if
neither full pair is present; reference the AWS_ACCESS_KEY_ID and
AWS_SECRET_ACCESS_KEY symbols when locating where to implement this.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nah thats fine, we should give responsibilty to users

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@KMKoushik, understood — the independent fallback is intentional, and the partial-config guard in getAwsCredentialOptions in credentials.ts will still catch the case where only one standard key is set at runtime. Acknowledged!

(ᵔ ᵕ ᵔ) 🐇


✏️ Learnings added
Learnt from: KMKoushik
Repo: usesend/useSend PR: 401
File: apps/web/src/env.js:102-103
Timestamp: 2026-05-17T11:17:08.286Z
Learning: In `apps/web/src/env.js` (usesend/useSend), the independent `||` fallback for `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` (falling back to legacy `AWS_ACCESS_KEY`/`AWS_SECRET_KEY` respectively) is intentional. The project maintainer explicitly chose to give users responsibility for providing consistent credential pairs rather than enforcing paired fallback logic at the env layer. The partial-config guard is handled at runtime in `apps/web/src/server/aws/credentials.ts` via `getAwsCredentialOptions()`.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

Comment threadapps/web/src/server/aws/ses.ts Outdated
Comment threadapps/web/src/server/aws/sns.ts Outdated

@greptile-appsgreptile-appsBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.

@KMKoushik
KMKoushik merged commit 04d0f4b into mainMay 17, 2026
7 checks passed
@KMKoushik
KMKoushik deleted the fix/aws-env-vars-on-pr-395 branch May 17, 2026 11:23
@coderabbitaicoderabbitaiBot mentioned this pull request Jul 31, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feat: Avoid hardcoding AWS credentials & support standard AWS env variables

2 participants

@KMKoushik@purva-8
, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' feat: support standard AWS env vars and default credential chain by KMKoushik · Pull Request #401 · usesend/useSend · GitHub
Skip to content

feat: support standard AWS env vars and default credential chain - #401

Merged
KMKoushik merged 5 commits into
mainfrom
fix/aws-env-vars-on-pr-395
May 17, 2026
Merged

feat: support standard AWS env vars and default credential chain#401
KMKoushik merged 5 commits into
mainfrom
fix/aws-env-vars-on-pr-395

Conversation

@KMKoushik

@KMKoushikKMKoushik commented May 17, 2026

Copy link
Copy Markdown
Member

Summary

  • Support standard AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY while keeping runtime fallback for existing legacy envs
  • Allow the AWS SDK default credential chain when static credentials are omitted
  • Align Docker, docs, CI env, and turbo env declarations with standard AWS names

Based on #395 by @purva-8, with maintainer fixes on top.

Closes#316

Verification

  • git diff --check
  • pnpm --filter=web exec eslint src/env.js next.config.js (AWS/turbo warnings resolved; unrelated existing warnings remain)

Merge note

If squash-merging and you want co-author credit preserved on the squash commit, include:

Co-authored-by: Purva Kandalgaonkar 136103488+purva-8@users.noreply.github.com


Summary by cubic

Switches to the standard AWS env vars AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY and enables the AWS SDK default credential chain when both are unset. Updates code, Docker, CI, docs, and Turbo config; legacy envs still work as fallbacks.

  • New Features

    • Use AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY; AWS_ACCESS_KEY / AWS_SECRET_KEY remain as runtime fallbacks.
    • Omit both vars to use the AWS SDK default credential chain for SES/SNS/STS.
    • Added getAwsCredentialOptions with a guard that errors on partial config.
    • Use an aliased import for the credentials helper to avoid path issues.
  • Migration

    • Prefer AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY, or rely on IAM/instance roles by leaving both unset.
    • Update your .env, CI, Docker, and Turbo env lists to the new names; examples and docs are aligned.

Written for commit b2147df. Summary will update on new commits. Review in cubic

Summary by CodeRabbit

  • New Features

    • Added AWS credential validation with safe fallback behavior; deployments can run without credentials set.
  • Documentation

    • Updated setup guides, examples, and run instructions to use the standardized AWS environment variable names.
  • Chores

    • Standardized AWS credential configuration across examples, tests, CI workflows, Docker, and build tooling to align with AWS conventions.

Review Change Stack

purva-8and others added 4 commits May 2, 2026 17:52
Replace non-standard AWS_ACCESS_KEY / AWS_SECRET_KEY with the AWS-standard
AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY. The old names are kept as
fallbacks in the runtimeEnv for backward compatibility.
Both vars are now optional. When omitted, the credentials object is not
passed to SESv2Client, STSClient, or SNSClient — the AWS SDK then falls
back to its default provider chain (IAM roles, ECS task roles, instance
profiles, etc.), which is the recommended approach for cloud-native deployments.
Closes#316
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
…al-config guard
- Move the credential spread logic into a single credentials.ts helper
so SESv2Client, STSClient, and SNSClient all share one implementation
- Throw a clear error if only one of AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY
is set, preventing silent fallback to the default provider chain with a
half-configured environment
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@vercel

vercelBot commented May 17, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

ProjectDeploymentActionsUpdated (UTC)
unsend-marketingReadyReadyPreview, CommentMay 17, 2026 11:21am

@greptile-appsgreptile-appsBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.

@coderabbitai

coderabbitaiBot commented May 17, 2026

Copy link
Copy Markdown
Contributor

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: e593e2ea-adba-4d19-9151-b80f2fe5a460

📥 Commits

Reviewing files that changed from the base of the PR and between 1c6317d and b2147df.

📒 Files selected for processing (2)
  • apps/web/src/server/aws/ses.ts
  • apps/web/src/server/aws/sns.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • apps/web/src/server/aws/sns.ts
  • apps/web/src/server/aws/ses.ts

Walkthrough

This PR standardizes AWS credential environment variable names from AWS_ACCESS_KEY/AWS_SECRET_KEY to AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY across examples, docs, CI, and runtime. It adds getAwsCredentialOptions() which returns explicit credentials when both env vars are set, throws on partial configuration, or returns an empty object so the AWS SDK default credential provider chain can be used. SES and SNS clients now use this helper instead of inline credential objects.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 0.00% which is insufficient. The required threshold is 80.00%.Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe PR title accurately summarizes the main changes: adding support for standard AWS environment variables and enabling the AWS default credential chain.
Linked Issues check✅ PassedThe PR successfully addresses all key requirements from issue #316: supports standard AWS env vars (AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY), makes credentials optional via default chain, maintains backward compatibility with legacy vars, and implements validation for partial configuration.
Out of Scope Changes check✅ PassedAll changes are directly related to the objective of supporting standard AWS environment variables and the credential chain. Updates to env files, documentation, CI workflows, and code are all in scope.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@cloudflare-workers-and-pages

cloudflare-workers-and-pagesBot commented May 17, 2026

Copy link
Copy Markdown

Deploying usesend with Cloudflare Pages Cloudflare Pages

Latest commit:b2147df
Status: ✅ Deploy successful!
Preview URL:https://6f7e6eeb.usesend.pages.dev
Branch Preview URL:https://fix-aws-env-vars-on-pr-395.usesend.pages.dev

View logs

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (1)
apps/docs/get-started/set-up-docker.mdx (1)

55-57: ⚡ Quick win

Document AWS static credentials as optional in standalone Docker flow.

Line 55–57 and Line 63 currently imply static AWS keys are always needed. Since credentials are now optional, please note that users can omit these vars when their runtime provides IAM-role/default credential chain access.

Proposed doc patch
 docker run -d \
-p 3000:3000 \
-e NEXTAUTH_URL="<your-nextauth-url>" \
-e NEXTAUTH_SECRET="<your-nextauth-secret>" \
-e DATABASE_URL="<your-next-private-database-url>" \
-e REDIS_URL="<your-next-private-redis-url>" \
- -e AWS_ACCESS_KEY_ID="<your-next-private-aws-access-key-id>" \- -e AWS_SECRET_ACCESS_KEY="<your-next-private-aws-secret-access-key>" \
-e AWS_DEFAULT_REGION="<your-next-private-aws-region>" \
-e GITHUB_ID="<your-next-private-github-id>" \
-e GITHUB_SECRET="<your-next-private-github-secret>" \
usesend/usesend

-Replace the placeholders with your actual database and AWS details.
+Replace the placeholders with your actual database details.
+If your environment does not provide AWS credentials via IAM/default provider chain, also set:
+AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY.

</details>
Also applies to: 63-63
<details>
<summary>🤖 Prompt for AI Agents</summary>

Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @apps/docs/get-started/set-up-docker.mdx around lines 55 - 57, Update the
Docker setup instructions so the AWS static credential environment variables
(AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_DEFAULT_REGION) are documented as
optional: change the text that currently tells users to "Replace the
placeholders with your actual database and AWS details." to "Replace the
placeholders with your actual database details. If your environment does not
provide AWS credentials via IAM/default provider chain, also set:
AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY." Ensure this change is applied to
the same explanatory lines that contain the three environment variable
placeholders and the similar line around the later occurrence (the one
referenced at line 63).


</details>
</blockquote></details>
</blockquote></details>
<details>
<summary>🤖 Prompt for all review comments with AI agents</summary>

Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @apps/web/src/env.js:

  • Around line 102-103: The current fallback uses independent || for
    AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY which can mix standard and legacy
    values; update the logic so the code selects either the standard pair
    (AWS_ACCESS_KEY_ID + AWS_SECRET_ACCESS_KEY) or, only if both are absent, the
    legacy pair (AWS_ACCESS_KEY + AWS_SECRET) as a unit. In practice change the
    assignment for AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY to a small
    conditional that prefers the standard env vars together, otherwise uses the
    legacy pair only when both legacy vars exist, and yields undefined/null if
    neither full pair is present; reference the AWS_ACCESS_KEY_ID and
    AWS_SECRET_ACCESS_KEY symbols when locating where to implement this.

In @apps/web/src/server/aws/ses.ts:

  • Line 20: Replace the relative import of getAwsCredentialOptions from
    "./credentials" with the repo-standard src alias import (e.g. import {
    getAwsCredentialOptions } from "~/server/aws/credentials";) so the module uses
    the ~/ alias form consistent with apps/web src imports.

In @apps/web/src/server/aws/sns.ts:

  • Line 8: Replace the relative import for getAwsCredentialOptions with the
    project src alias; change the import source from "./credentials" to the aliased
    module (e.g. "/server/aws/credentials") so the import reads: import {
    getAwsCredentialOptions } from "
    /server/aws/credentials"; this aligns the
    getAwsCredentialOptions import with the apps/web src alias convention.

Nitpick comments:
In @apps/docs/get-started/set-up-docker.mdx:

  • Around line 55-57: Update the Docker setup instructions so the AWS static
    credential environment variables (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY,
    AWS_DEFAULT_REGION) are documented as optional: change the text that currently
    tells users to "Replace the placeholders with your actual database and AWS
    details." to "Replace the placeholders with your actual database details. If
    your environment does not provide AWS credentials via IAM/default provider
    chain, also set: AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY." Ensure this
    change is applied to the same explanatory lines that contain the three
    environment variable placeholders and the similar line around the later
    occurrence (the one referenced at line 63).

</details>
<details>
<summary>🪄 Autofix (Beta)</summary>
Fix all unresolved CodeRabbit comments on this PR:
- [ ] <!-- {"checkboxId": "4b0d0e0a-96d7-4f10-b296-3a18ea78f0b9"} --> Push a commit to this branch (recommended)
- [ ] <!-- {"checkboxId": "ff5b1114-7d8c-49e6-8ac1-43f82af23a33"} --> Create a new PR with the fixes
</details>
---
<details>
<summary>ℹ️ Review info</summary>
<details>
<summary>⚙️ Run configuration</summary>
**Configuration used**: Organization UI
**Review profile**: CHILL
**Plan**: Pro
**Run ID**: `b582a91e-d79f-48e3-bf7b-c0e17c7b23fc`
</details>
<details>
<summary>📥 Commits</summary>
Reviewing files that changed from the base of the PR and between 31a49fbdca243a4674ec07946f69e8479c86f1f9 and 1c6317daccebc1e2b2afe54cec38e735ac58d913.
</details>
<details>
<summary>📒 Files selected for processing (18)</summary>
* `.env.example`
* `.env.selfhost.example`
* `.github/workflows/test-web.yml`
* `CONTRIBUTION.md`
* `apps/docs/get-started/create-aws-credentials.mdx`
* `apps/docs/get-started/local.mdx`
* `apps/docs/get-started/set-up-docker.mdx`
* `apps/docs/self-hosting/overview.mdx`
* `apps/docs/self-hosting/railway.mdx`
* `apps/web/.env.test.example`
* `apps/web/src/env.js`
* `apps/web/src/server/aws/credentials.ts`
* `apps/web/src/server/aws/ses.ts`
* `apps/web/src/server/aws/sns.ts`
* `apps/web/src/test/setup/setup-env.ts`
* `docker/README.md`
* `docker/prod/compose.yml`
* `turbo.json`
</details>
</details>
<!-- This is an auto-generated comment by CodeRabbit for review status -->

Comment threadapps/web/src/env.js
Comment on lines +102 to +103
AWS_ACCESS_KEY_ID: process.env.AWS_ACCESS_KEY_ID || process.env.AWS_ACCESS_KEY,
AWS_SECRET_ACCESS_KEY: process.env.AWS_SECRET_ACCESS_KEY || process.env.AWS_SECRET_KEY,

@coderabbitaicoderabbitaiBotMay 17, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Avoid mixing standard and legacy credential sources across fields.

Line 102 and Line 103 independently fall back with ||, which can combine AWS_ACCESS_KEY_ID with legacy AWS_SECRET_KEY (or vice versa). That can create an invalid pair and undercut partial-config safeguards.

Suggested fix
- AWS_ACCESS_KEY_ID: process.env.AWS_ACCESS_KEY_ID || process.env.AWS_ACCESS_KEY,- AWS_SECRET_ACCESS_KEY: process.env.AWS_SECRET_ACCESS_KEY || process.env.AWS_SECRET_KEY,+ AWS_ACCESS_KEY_ID:+ process.env.AWS_ACCESS_KEY_ID ?? process.env.AWS_ACCESS_KEY,+ AWS_SECRET_ACCESS_KEY:+ process.env.AWS_ACCESS_KEY_ID != null ||+ process.env.AWS_SECRET_ACCESS_KEY != null+ ? process.env.AWS_SECRET_ACCESS_KEY+ : process.env.AWS_SECRET_KEY,
📝 Committable suggestion

‼️IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
AWS_ACCESS_KEY_ID: process.env.AWS_ACCESS_KEY_ID||process.env.AWS_ACCESS_KEY,
AWS_SECRET_ACCESS_KEY: process.env.AWS_SECRET_ACCESS_KEY||process.env.AWS_SECRET_KEY,
AWS_ACCESS_KEY_ID:
process.env.AWS_ACCESS_KEY_ID??process.env.AWS_ACCESS_KEY,
AWS_SECRET_ACCESS_KEY:
process.env.AWS_ACCESS_KEY_ID!=null||
process.env.AWS_SECRET_ACCESS_KEY!=null
? process.env.AWS_SECRET_ACCESS_KEY
: process.env.AWS_SECRET_KEY,
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@apps/web/src/env.js` around lines 102 - 103, The current fallback uses
independent || for AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY which can mix
standard and legacy values; update the logic so the code selects either the
standard pair (AWS_ACCESS_KEY_ID + AWS_SECRET_ACCESS_KEY) or, only if both are
absent, the legacy pair (AWS_ACCESS_KEY + AWS_SECRET) as a unit. In practice
change the assignment for AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY to a small
conditional that prefers the standard env vars together, otherwise uses the
legacy pair only when both legacy vars exist, and yields undefined/null if
neither full pair is present; reference the AWS_ACCESS_KEY_ID and
AWS_SECRET_ACCESS_KEY symbols when locating where to implement this.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nah thats fine, we should give responsibilty to users

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@KMKoushik, understood — the independent fallback is intentional, and the partial-config guard in getAwsCredentialOptions in credentials.ts will still catch the case where only one standard key is set at runtime. Acknowledged!

(ᵔ ᵕ ᵔ) 🐇


✏️ Learnings added
Learnt from: KMKoushik
Repo: usesend/useSend PR: 401
File: apps/web/src/env.js:102-103
Timestamp: 2026-05-17T11:17:08.286Z
Learning: In `apps/web/src/env.js` (usesend/useSend), the independent `||` fallback for `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` (falling back to legacy `AWS_ACCESS_KEY`/`AWS_SECRET_KEY` respectively) is intentional. The project maintainer explicitly chose to give users responsibility for providing consistent credential pairs rather than enforcing paired fallback logic at the env layer. The partial-config guard is handled at runtime in `apps/web/src/server/aws/credentials.ts` via `getAwsCredentialOptions()`.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

Comment threadapps/web/src/server/aws/ses.ts Outdated
Comment threadapps/web/src/server/aws/sns.ts Outdated

@greptile-appsgreptile-appsBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.

@KMKoushik
KMKoushik merged commit 04d0f4b into mainMay 17, 2026
7 checks passed
@KMKoushik
KMKoushik deleted the fix/aws-env-vars-on-pr-395 branch May 17, 2026 11:23
@coderabbitaicoderabbitaiBot mentioned this pull request Jul 31, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feat: Avoid hardcoding AWS credentials & support standard AWS env variables

2 participants

@KMKoushik@purva-8
, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' feat: support standard AWS env vars and default credential chain by KMKoushik · Pull Request #401 · usesend/useSend · GitHub
Skip to content

feat: support standard AWS env vars and default credential chain - #401

Merged
KMKoushik merged 5 commits into
mainfrom
fix/aws-env-vars-on-pr-395
May 17, 2026
Merged

feat: support standard AWS env vars and default credential chain#401
KMKoushik merged 5 commits into
mainfrom
fix/aws-env-vars-on-pr-395

Conversation

@KMKoushik

@KMKoushikKMKoushik commented May 17, 2026

Copy link
Copy Markdown
Member

Summary

  • Support standard AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY while keeping runtime fallback for existing legacy envs
  • Allow the AWS SDK default credential chain when static credentials are omitted
  • Align Docker, docs, CI env, and turbo env declarations with standard AWS names

Based on #395 by @purva-8, with maintainer fixes on top.

Closes#316

Verification

  • git diff --check
  • pnpm --filter=web exec eslint src/env.js next.config.js (AWS/turbo warnings resolved; unrelated existing warnings remain)

Merge note

If squash-merging and you want co-author credit preserved on the squash commit, include:

Co-authored-by: Purva Kandalgaonkar 136103488+purva-8@users.noreply.github.com


Summary by cubic

Switches to the standard AWS env vars AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY and enables the AWS SDK default credential chain when both are unset. Updates code, Docker, CI, docs, and Turbo config; legacy envs still work as fallbacks.

  • New Features

    • Use AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY; AWS_ACCESS_KEY / AWS_SECRET_KEY remain as runtime fallbacks.
    • Omit both vars to use the AWS SDK default credential chain for SES/SNS/STS.
    • Added getAwsCredentialOptions with a guard that errors on partial config.
    • Use an aliased import for the credentials helper to avoid path issues.
  • Migration

    • Prefer AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY, or rely on IAM/instance roles by leaving both unset.
    • Update your .env, CI, Docker, and Turbo env lists to the new names; examples and docs are aligned.

Written for commit b2147df. Summary will update on new commits. Review in cubic

Summary by CodeRabbit

  • New Features

    • Added AWS credential validation with safe fallback behavior; deployments can run without credentials set.
  • Documentation

    • Updated setup guides, examples, and run instructions to use the standardized AWS environment variable names.
  • Chores

    • Standardized AWS credential configuration across examples, tests, CI workflows, Docker, and build tooling to align with AWS conventions.

Review Change Stack

purva-8and others added 4 commits May 2, 2026 17:52
Replace non-standard AWS_ACCESS_KEY / AWS_SECRET_KEY with the AWS-standard
AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY. The old names are kept as
fallbacks in the runtimeEnv for backward compatibility.
Both vars are now optional. When omitted, the credentials object is not
passed to SESv2Client, STSClient, or SNSClient — the AWS SDK then falls
back to its default provider chain (IAM roles, ECS task roles, instance
profiles, etc.), which is the recommended approach for cloud-native deployments.
Closes#316
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
…al-config guard
- Move the credential spread logic into a single credentials.ts helper
so SESv2Client, STSClient, and SNSClient all share one implementation
- Throw a clear error if only one of AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY
is set, preventing silent fallback to the default provider chain with a
half-configured environment
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@vercel

vercelBot commented May 17, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

ProjectDeploymentActionsUpdated (UTC)
unsend-marketingReadyReadyPreview, CommentMay 17, 2026 11:21am

@greptile-appsgreptile-appsBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.

@coderabbitai

coderabbitaiBot commented May 17, 2026

Copy link
Copy Markdown
Contributor

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: e593e2ea-adba-4d19-9151-b80f2fe5a460

📥 Commits

Reviewing files that changed from the base of the PR and between 1c6317d and b2147df.

📒 Files selected for processing (2)
  • apps/web/src/server/aws/ses.ts
  • apps/web/src/server/aws/sns.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • apps/web/src/server/aws/sns.ts
  • apps/web/src/server/aws/ses.ts

Walkthrough

This PR standardizes AWS credential environment variable names from AWS_ACCESS_KEY/AWS_SECRET_KEY to AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY across examples, docs, CI, and runtime. It adds getAwsCredentialOptions() which returns explicit credentials when both env vars are set, throws on partial configuration, or returns an empty object so the AWS SDK default credential provider chain can be used. SES and SNS clients now use this helper instead of inline credential objects.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 0.00% which is insufficient. The required threshold is 80.00%.Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe PR title accurately summarizes the main changes: adding support for standard AWS environment variables and enabling the AWS default credential chain.
Linked Issues check✅ PassedThe PR successfully addresses all key requirements from issue #316: supports standard AWS env vars (AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY), makes credentials optional via default chain, maintains backward compatibility with legacy vars, and implements validation for partial configuration.
Out of Scope Changes check✅ PassedAll changes are directly related to the objective of supporting standard AWS environment variables and the credential chain. Updates to env files, documentation, CI workflows, and code are all in scope.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@cloudflare-workers-and-pages

cloudflare-workers-and-pagesBot commented May 17, 2026

Copy link
Copy Markdown

Deploying usesend with Cloudflare Pages Cloudflare Pages

Latest commit:b2147df
Status: ✅ Deploy successful!
Preview URL:https://6f7e6eeb.usesend.pages.dev
Branch Preview URL:https://fix-aws-env-vars-on-pr-395.usesend.pages.dev

View logs

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (1)
apps/docs/get-started/set-up-docker.mdx (1)

55-57: ⚡ Quick win

Document AWS static credentials as optional in standalone Docker flow.

Line 55–57 and Line 63 currently imply static AWS keys are always needed. Since credentials are now optional, please note that users can omit these vars when their runtime provides IAM-role/default credential chain access.

Proposed doc patch
 docker run -d \
-p 3000:3000 \
-e NEXTAUTH_URL="<your-nextauth-url>" \
-e NEXTAUTH_SECRET="<your-nextauth-secret>" \
-e DATABASE_URL="<your-next-private-database-url>" \
-e REDIS_URL="<your-next-private-redis-url>" \
- -e AWS_ACCESS_KEY_ID="<your-next-private-aws-access-key-id>" \- -e AWS_SECRET_ACCESS_KEY="<your-next-private-aws-secret-access-key>" \
-e AWS_DEFAULT_REGION="<your-next-private-aws-region>" \
-e GITHUB_ID="<your-next-private-github-id>" \
-e GITHUB_SECRET="<your-next-private-github-secret>" \
usesend/usesend

-Replace the placeholders with your actual database and AWS details.
+Replace the placeholders with your actual database details.
+If your environment does not provide AWS credentials via IAM/default provider chain, also set:
+AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY.

</details>
Also applies to: 63-63
<details>
<summary>🤖 Prompt for AI Agents</summary>

Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @apps/docs/get-started/set-up-docker.mdx around lines 55 - 57, Update the
Docker setup instructions so the AWS static credential environment variables
(AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_DEFAULT_REGION) are documented as
optional: change the text that currently tells users to "Replace the
placeholders with your actual database and AWS details." to "Replace the
placeholders with your actual database details. If your environment does not
provide AWS credentials via IAM/default provider chain, also set:
AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY." Ensure this change is applied to
the same explanatory lines that contain the three environment variable
placeholders and the similar line around the later occurrence (the one
referenced at line 63).


</details>
</blockquote></details>
</blockquote></details>
<details>
<summary>🤖 Prompt for all review comments with AI agents</summary>

Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @apps/web/src/env.js:

  • Around line 102-103: The current fallback uses independent || for
    AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY which can mix standard and legacy
    values; update the logic so the code selects either the standard pair
    (AWS_ACCESS_KEY_ID + AWS_SECRET_ACCESS_KEY) or, only if both are absent, the
    legacy pair (AWS_ACCESS_KEY + AWS_SECRET) as a unit. In practice change the
    assignment for AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY to a small
    conditional that prefers the standard env vars together, otherwise uses the
    legacy pair only when both legacy vars exist, and yields undefined/null if
    neither full pair is present; reference the AWS_ACCESS_KEY_ID and
    AWS_SECRET_ACCESS_KEY symbols when locating where to implement this.

In @apps/web/src/server/aws/ses.ts:

  • Line 20: Replace the relative import of getAwsCredentialOptions from
    "./credentials" with the repo-standard src alias import (e.g. import {
    getAwsCredentialOptions } from "~/server/aws/credentials";) so the module uses
    the ~/ alias form consistent with apps/web src imports.

In @apps/web/src/server/aws/sns.ts:

  • Line 8: Replace the relative import for getAwsCredentialOptions with the
    project src alias; change the import source from "./credentials" to the aliased
    module (e.g. "/server/aws/credentials") so the import reads: import {
    getAwsCredentialOptions } from "
    /server/aws/credentials"; this aligns the
    getAwsCredentialOptions import with the apps/web src alias convention.

Nitpick comments:
In @apps/docs/get-started/set-up-docker.mdx:

  • Around line 55-57: Update the Docker setup instructions so the AWS static
    credential environment variables (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY,
    AWS_DEFAULT_REGION) are documented as optional: change the text that currently
    tells users to "Replace the placeholders with your actual database and AWS
    details." to "Replace the placeholders with your actual database details. If
    your environment does not provide AWS credentials via IAM/default provider
    chain, also set: AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY." Ensure this
    change is applied to the same explanatory lines that contain the three
    environment variable placeholders and the similar line around the later
    occurrence (the one referenced at line 63).

</details>
<details>
<summary>🪄 Autofix (Beta)</summary>
Fix all unresolved CodeRabbit comments on this PR:
- [ ] <!-- {"checkboxId": "4b0d0e0a-96d7-4f10-b296-3a18ea78f0b9"} --> Push a commit to this branch (recommended)
- [ ] <!-- {"checkboxId": "ff5b1114-7d8c-49e6-8ac1-43f82af23a33"} --> Create a new PR with the fixes
</details>
---
<details>
<summary>ℹ️ Review info</summary>
<details>
<summary>⚙️ Run configuration</summary>
**Configuration used**: Organization UI
**Review profile**: CHILL
**Plan**: Pro
**Run ID**: `b582a91e-d79f-48e3-bf7b-c0e17c7b23fc`
</details>
<details>
<summary>📥 Commits</summary>
Reviewing files that changed from the base of the PR and between 31a49fbdca243a4674ec07946f69e8479c86f1f9 and 1c6317daccebc1e2b2afe54cec38e735ac58d913.
</details>
<details>
<summary>📒 Files selected for processing (18)</summary>
* `.env.example`
* `.env.selfhost.example`
* `.github/workflows/test-web.yml`
* `CONTRIBUTION.md`
* `apps/docs/get-started/create-aws-credentials.mdx`
* `apps/docs/get-started/local.mdx`
* `apps/docs/get-started/set-up-docker.mdx`
* `apps/docs/self-hosting/overview.mdx`
* `apps/docs/self-hosting/railway.mdx`
* `apps/web/.env.test.example`
* `apps/web/src/env.js`
* `apps/web/src/server/aws/credentials.ts`
* `apps/web/src/server/aws/ses.ts`
* `apps/web/src/server/aws/sns.ts`
* `apps/web/src/test/setup/setup-env.ts`
* `docker/README.md`
* `docker/prod/compose.yml`
* `turbo.json`
</details>
</details>
<!-- This is an auto-generated comment by CodeRabbit for review status -->

Comment threadapps/web/src/env.js
Comment on lines +102 to +103
AWS_ACCESS_KEY_ID: process.env.AWS_ACCESS_KEY_ID || process.env.AWS_ACCESS_KEY,
AWS_SECRET_ACCESS_KEY: process.env.AWS_SECRET_ACCESS_KEY || process.env.AWS_SECRET_KEY,

@coderabbitaicoderabbitaiBotMay 17, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Avoid mixing standard and legacy credential sources across fields.

Line 102 and Line 103 independently fall back with ||, which can combine AWS_ACCESS_KEY_ID with legacy AWS_SECRET_KEY (or vice versa). That can create an invalid pair and undercut partial-config safeguards.

Suggested fix
- AWS_ACCESS_KEY_ID: process.env.AWS_ACCESS_KEY_ID || process.env.AWS_ACCESS_KEY,- AWS_SECRET_ACCESS_KEY: process.env.AWS_SECRET_ACCESS_KEY || process.env.AWS_SECRET_KEY,+ AWS_ACCESS_KEY_ID:+ process.env.AWS_ACCESS_KEY_ID ?? process.env.AWS_ACCESS_KEY,+ AWS_SECRET_ACCESS_KEY:+ process.env.AWS_ACCESS_KEY_ID != null ||+ process.env.AWS_SECRET_ACCESS_KEY != null+ ? process.env.AWS_SECRET_ACCESS_KEY+ : process.env.AWS_SECRET_KEY,
📝 Committable suggestion

‼️IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
AWS_ACCESS_KEY_ID: process.env.AWS_ACCESS_KEY_ID||process.env.AWS_ACCESS_KEY,
AWS_SECRET_ACCESS_KEY: process.env.AWS_SECRET_ACCESS_KEY||process.env.AWS_SECRET_KEY,
AWS_ACCESS_KEY_ID:
process.env.AWS_ACCESS_KEY_ID??process.env.AWS_ACCESS_KEY,
AWS_SECRET_ACCESS_KEY:
process.env.AWS_ACCESS_KEY_ID!=null||
process.env.AWS_SECRET_ACCESS_KEY!=null
? process.env.AWS_SECRET_ACCESS_KEY
: process.env.AWS_SECRET_KEY,
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@apps/web/src/env.js` around lines 102 - 103, The current fallback uses
independent || for AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY which can mix
standard and legacy values; update the logic so the code selects either the
standard pair (AWS_ACCESS_KEY_ID + AWS_SECRET_ACCESS_KEY) or, only if both are
absent, the legacy pair (AWS_ACCESS_KEY + AWS_SECRET) as a unit. In practice
change the assignment for AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY to a small
conditional that prefers the standard env vars together, otherwise uses the
legacy pair only when both legacy vars exist, and yields undefined/null if
neither full pair is present; reference the AWS_ACCESS_KEY_ID and
AWS_SECRET_ACCESS_KEY symbols when locating where to implement this.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nah thats fine, we should give responsibilty to users

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@KMKoushik, understood — the independent fallback is intentional, and the partial-config guard in getAwsCredentialOptions in credentials.ts will still catch the case where only one standard key is set at runtime. Acknowledged!

(ᵔ ᵕ ᵔ) 🐇


✏️ Learnings added
Learnt from: KMKoushik
Repo: usesend/useSend PR: 401
File: apps/web/src/env.js:102-103
Timestamp: 2026-05-17T11:17:08.286Z
Learning: In `apps/web/src/env.js` (usesend/useSend), the independent `||` fallback for `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` (falling back to legacy `AWS_ACCESS_KEY`/`AWS_SECRET_KEY` respectively) is intentional. The project maintainer explicitly chose to give users responsibility for providing consistent credential pairs rather than enforcing paired fallback logic at the env layer. The partial-config guard is handled at runtime in `apps/web/src/server/aws/credentials.ts` via `getAwsCredentialOptions()`.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

Comment threadapps/web/src/server/aws/ses.ts Outdated
Comment threadapps/web/src/server/aws/sns.ts Outdated

@greptile-appsgreptile-appsBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.

@KMKoushik
KMKoushik merged commit 04d0f4b into mainMay 17, 2026
7 checks passed
@KMKoushik
KMKoushik deleted the fix/aws-env-vars-on-pr-395 branch May 17, 2026 11:23
@coderabbitaicoderabbitaiBot mentioned this pull request Jul 31, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feat: Avoid hardcoding AWS credentials & support standard AWS env variables

2 participants

@KMKoushik@purva-8
, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' feat: support standard AWS env vars and default credential chain by KMKoushik · Pull Request #401 · usesend/useSend · GitHub
Skip to content

feat: support standard AWS env vars and default credential chain - #401

Merged
KMKoushik merged 5 commits into
mainfrom
fix/aws-env-vars-on-pr-395
May 17, 2026
Merged

feat: support standard AWS env vars and default credential chain#401
KMKoushik merged 5 commits into
mainfrom
fix/aws-env-vars-on-pr-395

Conversation

@KMKoushik

@KMKoushikKMKoushik commented May 17, 2026

Copy link
Copy Markdown
Member

Summary

  • Support standard AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY while keeping runtime fallback for existing legacy envs
  • Allow the AWS SDK default credential chain when static credentials are omitted
  • Align Docker, docs, CI env, and turbo env declarations with standard AWS names

Based on #395 by @purva-8, with maintainer fixes on top.

Closes#316

Verification

  • git diff --check
  • pnpm --filter=web exec eslint src/env.js next.config.js (AWS/turbo warnings resolved; unrelated existing warnings remain)

Merge note

If squash-merging and you want co-author credit preserved on the squash commit, include:

Co-authored-by: Purva Kandalgaonkar 136103488+purva-8@users.noreply.github.com


Summary by cubic

Switches to the standard AWS env vars AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY and enables the AWS SDK default credential chain when both are unset. Updates code, Docker, CI, docs, and Turbo config; legacy envs still work as fallbacks.

  • New Features

    • Use AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY; AWS_ACCESS_KEY / AWS_SECRET_KEY remain as runtime fallbacks.
    • Omit both vars to use the AWS SDK default credential chain for SES/SNS/STS.
    • Added getAwsCredentialOptions with a guard that errors on partial config.
    • Use an aliased import for the credentials helper to avoid path issues.
  • Migration

    • Prefer AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY, or rely on IAM/instance roles by leaving both unset.
    • Update your .env, CI, Docker, and Turbo env lists to the new names; examples and docs are aligned.

Written for commit b2147df. Summary will update on new commits. Review in cubic

Summary by CodeRabbit

  • New Features

    • Added AWS credential validation with safe fallback behavior; deployments can run without credentials set.
  • Documentation

    • Updated setup guides, examples, and run instructions to use the standardized AWS environment variable names.
  • Chores

    • Standardized AWS credential configuration across examples, tests, CI workflows, Docker, and build tooling to align with AWS conventions.

Review Change Stack

purva-8and others added 4 commits May 2, 2026 17:52
Replace non-standard AWS_ACCESS_KEY / AWS_SECRET_KEY with the AWS-standard
AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY. The old names are kept as
fallbacks in the runtimeEnv for backward compatibility.
Both vars are now optional. When omitted, the credentials object is not
passed to SESv2Client, STSClient, or SNSClient — the AWS SDK then falls
back to its default provider chain (IAM roles, ECS task roles, instance
profiles, etc.), which is the recommended approach for cloud-native deployments.
Closes#316
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
…al-config guard
- Move the credential spread logic into a single credentials.ts helper
so SESv2Client, STSClient, and SNSClient all share one implementation
- Throw a clear error if only one of AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY
is set, preventing silent fallback to the default provider chain with a
half-configured environment
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@vercel

vercelBot commented May 17, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

ProjectDeploymentActionsUpdated (UTC)
unsend-marketingReadyReadyPreview, CommentMay 17, 2026 11:21am

@greptile-appsgreptile-appsBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.

@coderabbitai

coderabbitaiBot commented May 17, 2026

Copy link
Copy Markdown
Contributor

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: e593e2ea-adba-4d19-9151-b80f2fe5a460

📥 Commits

Reviewing files that changed from the base of the PR and between 1c6317d and b2147df.

📒 Files selected for processing (2)
  • apps/web/src/server/aws/ses.ts
  • apps/web/src/server/aws/sns.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • apps/web/src/server/aws/sns.ts
  • apps/web/src/server/aws/ses.ts

Walkthrough

This PR standardizes AWS credential environment variable names from AWS_ACCESS_KEY/AWS_SECRET_KEY to AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY across examples, docs, CI, and runtime. It adds getAwsCredentialOptions() which returns explicit credentials when both env vars are set, throws on partial configuration, or returns an empty object so the AWS SDK default credential provider chain can be used. SES and SNS clients now use this helper instead of inline credential objects.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 0.00% which is insufficient. The required threshold is 80.00%.Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe PR title accurately summarizes the main changes: adding support for standard AWS environment variables and enabling the AWS default credential chain.
Linked Issues check✅ PassedThe PR successfully addresses all key requirements from issue #316: supports standard AWS env vars (AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY), makes credentials optional via default chain, maintains backward compatibility with legacy vars, and implements validation for partial configuration.
Out of Scope Changes check✅ PassedAll changes are directly related to the objective of supporting standard AWS environment variables and the credential chain. Updates to env files, documentation, CI workflows, and code are all in scope.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@cloudflare-workers-and-pages

cloudflare-workers-and-pagesBot commented May 17, 2026

Copy link
Copy Markdown

Deploying usesend with Cloudflare Pages Cloudflare Pages

Latest commit:b2147df
Status: ✅ Deploy successful!
Preview URL:https://6f7e6eeb.usesend.pages.dev
Branch Preview URL:https://fix-aws-env-vars-on-pr-395.usesend.pages.dev

View logs

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (1)
apps/docs/get-started/set-up-docker.mdx (1)

55-57: ⚡ Quick win

Document AWS static credentials as optional in standalone Docker flow.

Line 55–57 and Line 63 currently imply static AWS keys are always needed. Since credentials are now optional, please note that users can omit these vars when their runtime provides IAM-role/default credential chain access.

Proposed doc patch
 docker run -d \
-p 3000:3000 \
-e NEXTAUTH_URL="<your-nextauth-url>" \
-e NEXTAUTH_SECRET="<your-nextauth-secret>" \
-e DATABASE_URL="<your-next-private-database-url>" \
-e REDIS_URL="<your-next-private-redis-url>" \
- -e AWS_ACCESS_KEY_ID="<your-next-private-aws-access-key-id>" \- -e AWS_SECRET_ACCESS_KEY="<your-next-private-aws-secret-access-key>" \
-e AWS_DEFAULT_REGION="<your-next-private-aws-region>" \
-e GITHUB_ID="<your-next-private-github-id>" \
-e GITHUB_SECRET="<your-next-private-github-secret>" \
usesend/usesend

-Replace the placeholders with your actual database and AWS details.
+Replace the placeholders with your actual database details.
+If your environment does not provide AWS credentials via IAM/default provider chain, also set:
+AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY.

</details>
Also applies to: 63-63
<details>
<summary>🤖 Prompt for AI Agents</summary>

Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @apps/docs/get-started/set-up-docker.mdx around lines 55 - 57, Update the
Docker setup instructions so the AWS static credential environment variables
(AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_DEFAULT_REGION) are documented as
optional: change the text that currently tells users to "Replace the
placeholders with your actual database and AWS details." to "Replace the
placeholders with your actual database details. If your environment does not
provide AWS credentials via IAM/default provider chain, also set:
AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY." Ensure this change is applied to
the same explanatory lines that contain the three environment variable
placeholders and the similar line around the later occurrence (the one
referenced at line 63).


</details>
</blockquote></details>
</blockquote></details>
<details>
<summary>🤖 Prompt for all review comments with AI agents</summary>

Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @apps/web/src/env.js:

  • Around line 102-103: The current fallback uses independent || for
    AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY which can mix standard and legacy
    values; update the logic so the code selects either the standard pair
    (AWS_ACCESS_KEY_ID + AWS_SECRET_ACCESS_KEY) or, only if both are absent, the
    legacy pair (AWS_ACCESS_KEY + AWS_SECRET) as a unit. In practice change the
    assignment for AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY to a small
    conditional that prefers the standard env vars together, otherwise uses the
    legacy pair only when both legacy vars exist, and yields undefined/null if
    neither full pair is present; reference the AWS_ACCESS_KEY_ID and
    AWS_SECRET_ACCESS_KEY symbols when locating where to implement this.

In @apps/web/src/server/aws/ses.ts:

  • Line 20: Replace the relative import of getAwsCredentialOptions from
    "./credentials" with the repo-standard src alias import (e.g. import {
    getAwsCredentialOptions } from "~/server/aws/credentials";) so the module uses
    the ~/ alias form consistent with apps/web src imports.

In @apps/web/src/server/aws/sns.ts:

  • Line 8: Replace the relative import for getAwsCredentialOptions with the
    project src alias; change the import source from "./credentials" to the aliased
    module (e.g. "/server/aws/credentials") so the import reads: import {
    getAwsCredentialOptions } from "
    /server/aws/credentials"; this aligns the
    getAwsCredentialOptions import with the apps/web src alias convention.

Nitpick comments:
In @apps/docs/get-started/set-up-docker.mdx:

  • Around line 55-57: Update the Docker setup instructions so the AWS static
    credential environment variables (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY,
    AWS_DEFAULT_REGION) are documented as optional: change the text that currently
    tells users to "Replace the placeholders with your actual database and AWS
    details." to "Replace the placeholders with your actual database details. If
    your environment does not provide AWS credentials via IAM/default provider
    chain, also set: AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY." Ensure this
    change is applied to the same explanatory lines that contain the three
    environment variable placeholders and the similar line around the later
    occurrence (the one referenced at line 63).

</details>
<details>
<summary>🪄 Autofix (Beta)</summary>
Fix all unresolved CodeRabbit comments on this PR:
- [ ] <!-- {"checkboxId": "4b0d0e0a-96d7-4f10-b296-3a18ea78f0b9"} --> Push a commit to this branch (recommended)
- [ ] <!-- {"checkboxId": "ff5b1114-7d8c-49e6-8ac1-43f82af23a33"} --> Create a new PR with the fixes
</details>
---
<details>
<summary>ℹ️ Review info</summary>
<details>
<summary>⚙️ Run configuration</summary>
**Configuration used**: Organization UI
**Review profile**: CHILL
**Plan**: Pro
**Run ID**: `b582a91e-d79f-48e3-bf7b-c0e17c7b23fc`
</details>
<details>
<summary>📥 Commits</summary>
Reviewing files that changed from the base of the PR and between 31a49fbdca243a4674ec07946f69e8479c86f1f9 and 1c6317daccebc1e2b2afe54cec38e735ac58d913.
</details>
<details>
<summary>📒 Files selected for processing (18)</summary>
* `.env.example`
* `.env.selfhost.example`
* `.github/workflows/test-web.yml`
* `CONTRIBUTION.md`
* `apps/docs/get-started/create-aws-credentials.mdx`
* `apps/docs/get-started/local.mdx`
* `apps/docs/get-started/set-up-docker.mdx`
* `apps/docs/self-hosting/overview.mdx`
* `apps/docs/self-hosting/railway.mdx`
* `apps/web/.env.test.example`
* `apps/web/src/env.js`
* `apps/web/src/server/aws/credentials.ts`
* `apps/web/src/server/aws/ses.ts`
* `apps/web/src/server/aws/sns.ts`
* `apps/web/src/test/setup/setup-env.ts`
* `docker/README.md`
* `docker/prod/compose.yml`
* `turbo.json`
</details>
</details>
<!-- This is an auto-generated comment by CodeRabbit for review status -->

Comment threadapps/web/src/env.js
Comment on lines +102 to +103
AWS_ACCESS_KEY_ID: process.env.AWS_ACCESS_KEY_ID || process.env.AWS_ACCESS_KEY,
AWS_SECRET_ACCESS_KEY: process.env.AWS_SECRET_ACCESS_KEY || process.env.AWS_SECRET_KEY,

@coderabbitaicoderabbitaiBotMay 17, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Avoid mixing standard and legacy credential sources across fields.

Line 102 and Line 103 independently fall back with ||, which can combine AWS_ACCESS_KEY_ID with legacy AWS_SECRET_KEY (or vice versa). That can create an invalid pair and undercut partial-config safeguards.

Suggested fix
- AWS_ACCESS_KEY_ID: process.env.AWS_ACCESS_KEY_ID || process.env.AWS_ACCESS_KEY,- AWS_SECRET_ACCESS_KEY: process.env.AWS_SECRET_ACCESS_KEY || process.env.AWS_SECRET_KEY,+ AWS_ACCESS_KEY_ID:+ process.env.AWS_ACCESS_KEY_ID ?? process.env.AWS_ACCESS_KEY,+ AWS_SECRET_ACCESS_KEY:+ process.env.AWS_ACCESS_KEY_ID != null ||+ process.env.AWS_SECRET_ACCESS_KEY != null+ ? process.env.AWS_SECRET_ACCESS_KEY+ : process.env.AWS_SECRET_KEY,
📝 Committable suggestion

‼️IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
AWS_ACCESS_KEY_ID: process.env.AWS_ACCESS_KEY_ID||process.env.AWS_ACCESS_KEY,
AWS_SECRET_ACCESS_KEY: process.env.AWS_SECRET_ACCESS_KEY||process.env.AWS_SECRET_KEY,
AWS_ACCESS_KEY_ID:
process.env.AWS_ACCESS_KEY_ID??process.env.AWS_ACCESS_KEY,
AWS_SECRET_ACCESS_KEY:
process.env.AWS_ACCESS_KEY_ID!=null||
process.env.AWS_SECRET_ACCESS_KEY!=null
? process.env.AWS_SECRET_ACCESS_KEY
: process.env.AWS_SECRET_KEY,
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@apps/web/src/env.js` around lines 102 - 103, The current fallback uses
independent || for AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY which can mix
standard and legacy values; update the logic so the code selects either the
standard pair (AWS_ACCESS_KEY_ID + AWS_SECRET_ACCESS_KEY) or, only if both are
absent, the legacy pair (AWS_ACCESS_KEY + AWS_SECRET) as a unit. In practice
change the assignment for AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY to a small
conditional that prefers the standard env vars together, otherwise uses the
legacy pair only when both legacy vars exist, and yields undefined/null if
neither full pair is present; reference the AWS_ACCESS_KEY_ID and
AWS_SECRET_ACCESS_KEY symbols when locating where to implement this.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nah thats fine, we should give responsibilty to users

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@KMKoushik, understood — the independent fallback is intentional, and the partial-config guard in getAwsCredentialOptions in credentials.ts will still catch the case where only one standard key is set at runtime. Acknowledged!

(ᵔ ᵕ ᵔ) 🐇


✏️ Learnings added
Learnt from: KMKoushik
Repo: usesend/useSend PR: 401
File: apps/web/src/env.js:102-103
Timestamp: 2026-05-17T11:17:08.286Z
Learning: In `apps/web/src/env.js` (usesend/useSend), the independent `||` fallback for `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` (falling back to legacy `AWS_ACCESS_KEY`/`AWS_SECRET_KEY` respectively) is intentional. The project maintainer explicitly chose to give users responsibility for providing consistent credential pairs rather than enforcing paired fallback logic at the env layer. The partial-config guard is handled at runtime in `apps/web/src/server/aws/credentials.ts` via `getAwsCredentialOptions()`.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

Comment threadapps/web/src/server/aws/ses.ts Outdated
Comment threadapps/web/src/server/aws/sns.ts Outdated

@greptile-appsgreptile-appsBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.

@KMKoushik
KMKoushik merged commit 04d0f4b into mainMay 17, 2026
7 checks passed
@KMKoushik
KMKoushik deleted the fix/aws-env-vars-on-pr-395 branch May 17, 2026 11:23
@coderabbitaicoderabbitaiBot mentioned this pull request Jul 31, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feat: Avoid hardcoding AWS credentials & support standard AWS env variables

2 participants

@KMKoushik@purva-8
, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })(); feat: support standard AWS env vars and default credential chain by KMKoushik · Pull Request #401 · usesend/useSend · GitHub
Skip to content

feat: support standard AWS env vars and default credential chain - #401

Merged
KMKoushik merged 5 commits into
mainfrom
fix/aws-env-vars-on-pr-395
May 17, 2026
Merged

feat: support standard AWS env vars and default credential chain#401
KMKoushik merged 5 commits into
mainfrom
fix/aws-env-vars-on-pr-395

Conversation

@KMKoushik

@KMKoushikKMKoushik commented May 17, 2026

Copy link
Copy Markdown
Member

Summary

  • Support standard AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY while keeping runtime fallback for existing legacy envs
  • Allow the AWS SDK default credential chain when static credentials are omitted
  • Align Docker, docs, CI env, and turbo env declarations with standard AWS names

Based on #395 by @purva-8, with maintainer fixes on top.

Closes#316

Verification

  • git diff --check
  • pnpm --filter=web exec eslint src/env.js next.config.js (AWS/turbo warnings resolved; unrelated existing warnings remain)

Merge note

If squash-merging and you want co-author credit preserved on the squash commit, include:

Co-authored-by: Purva Kandalgaonkar 136103488+purva-8@users.noreply.github.com


Summary by cubic

Switches to the standard AWS env vars AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY and enables the AWS SDK default credential chain when both are unset. Updates code, Docker, CI, docs, and Turbo config; legacy envs still work as fallbacks.

  • New Features

    • Use AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY; AWS_ACCESS_KEY / AWS_SECRET_KEY remain as runtime fallbacks.
    • Omit both vars to use the AWS SDK default credential chain for SES/SNS/STS.
    • Added getAwsCredentialOptions with a guard that errors on partial config.
    • Use an aliased import for the credentials helper to avoid path issues.
  • Migration

    • Prefer AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY, or rely on IAM/instance roles by leaving both unset.
    • Update your .env, CI, Docker, and Turbo env lists to the new names; examples and docs are aligned.

Written for commit b2147df. Summary will update on new commits. Review in cubic

Summary by CodeRabbit

  • New Features

    • Added AWS credential validation with safe fallback behavior; deployments can run without credentials set.
  • Documentation

    • Updated setup guides, examples, and run instructions to use the standardized AWS environment variable names.
  • Chores

    • Standardized AWS credential configuration across examples, tests, CI workflows, Docker, and build tooling to align with AWS conventions.

Review Change Stack

purva-8and others added 4 commits May 2, 2026 17:52
Replace non-standard AWS_ACCESS_KEY / AWS_SECRET_KEY with the AWS-standard
AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY. The old names are kept as
fallbacks in the runtimeEnv for backward compatibility.
Both vars are now optional. When omitted, the credentials object is not
passed to SESv2Client, STSClient, or SNSClient — the AWS SDK then falls
back to its default provider chain (IAM roles, ECS task roles, instance
profiles, etc.), which is the recommended approach for cloud-native deployments.
Closes#316
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
…al-config guard
- Move the credential spread logic into a single credentials.ts helper
so SESv2Client, STSClient, and SNSClient all share one implementation
- Throw a clear error if only one of AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY
is set, preventing silent fallback to the default provider chain with a
half-configured environment
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@vercel

vercelBot commented May 17, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

ProjectDeploymentActionsUpdated (UTC)
unsend-marketingReadyReadyPreview, CommentMay 17, 2026 11:21am

@greptile-appsgreptile-appsBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.

@coderabbitai

coderabbitaiBot commented May 17, 2026

Copy link
Copy Markdown
Contributor

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: e593e2ea-adba-4d19-9151-b80f2fe5a460

📥 Commits

Reviewing files that changed from the base of the PR and between 1c6317d and b2147df.

📒 Files selected for processing (2)
  • apps/web/src/server/aws/ses.ts
  • apps/web/src/server/aws/sns.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • apps/web/src/server/aws/sns.ts
  • apps/web/src/server/aws/ses.ts

Walkthrough

This PR standardizes AWS credential environment variable names from AWS_ACCESS_KEY/AWS_SECRET_KEY to AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY across examples, docs, CI, and runtime. It adds getAwsCredentialOptions() which returns explicit credentials when both env vars are set, throws on partial configuration, or returns an empty object so the AWS SDK default credential provider chain can be used. SES and SNS clients now use this helper instead of inline credential objects.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 0.00% which is insufficient. The required threshold is 80.00%.Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe PR title accurately summarizes the main changes: adding support for standard AWS environment variables and enabling the AWS default credential chain.
Linked Issues check✅ PassedThe PR successfully addresses all key requirements from issue #316: supports standard AWS env vars (AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY), makes credentials optional via default chain, maintains backward compatibility with legacy vars, and implements validation for partial configuration.
Out of Scope Changes check✅ PassedAll changes are directly related to the objective of supporting standard AWS environment variables and the credential chain. Updates to env files, documentation, CI workflows, and code are all in scope.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@cloudflare-workers-and-pages

cloudflare-workers-and-pagesBot commented May 17, 2026

Copy link
Copy Markdown

Deploying usesend with Cloudflare Pages Cloudflare Pages

Latest commit:b2147df
Status: ✅ Deploy successful!
Preview URL:https://6f7e6eeb.usesend.pages.dev
Branch Preview URL:https://fix-aws-env-vars-on-pr-395.usesend.pages.dev

View logs

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (1)
apps/docs/get-started/set-up-docker.mdx (1)

55-57: ⚡ Quick win

Document AWS static credentials as optional in standalone Docker flow.

Line 55–57 and Line 63 currently imply static AWS keys are always needed. Since credentials are now optional, please note that users can omit these vars when their runtime provides IAM-role/default credential chain access.

Proposed doc patch
 docker run -d \
-p 3000:3000 \
-e NEXTAUTH_URL="<your-nextauth-url>" \
-e NEXTAUTH_SECRET="<your-nextauth-secret>" \
-e DATABASE_URL="<your-next-private-database-url>" \
-e REDIS_URL="<your-next-private-redis-url>" \
- -e AWS_ACCESS_KEY_ID="<your-next-private-aws-access-key-id>" \- -e AWS_SECRET_ACCESS_KEY="<your-next-private-aws-secret-access-key>" \
-e AWS_DEFAULT_REGION="<your-next-private-aws-region>" \
-e GITHUB_ID="<your-next-private-github-id>" \
-e GITHUB_SECRET="<your-next-private-github-secret>" \
usesend/usesend

-Replace the placeholders with your actual database and AWS details.
+Replace the placeholders with your actual database details.
+If your environment does not provide AWS credentials via IAM/default provider chain, also set:
+AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY.

</details>
Also applies to: 63-63
<details>
<summary>🤖 Prompt for AI Agents</summary>

Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @apps/docs/get-started/set-up-docker.mdx around lines 55 - 57, Update the
Docker setup instructions so the AWS static credential environment variables
(AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_DEFAULT_REGION) are documented as
optional: change the text that currently tells users to "Replace the
placeholders with your actual database and AWS details." to "Replace the
placeholders with your actual database details. If your environment does not
provide AWS credentials via IAM/default provider chain, also set:
AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY." Ensure this change is applied to
the same explanatory lines that contain the three environment variable
placeholders and the similar line around the later occurrence (the one
referenced at line 63).


</details>
</blockquote></details>
</blockquote></details>
<details>
<summary>🤖 Prompt for all review comments with AI agents</summary>

Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @apps/web/src/env.js:

  • Around line 102-103: The current fallback uses independent || for
    AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY which can mix standard and legacy
    values; update the logic so the code selects either the standard pair
    (AWS_ACCESS_KEY_ID + AWS_SECRET_ACCESS_KEY) or, only if both are absent, the
    legacy pair (AWS_ACCESS_KEY + AWS_SECRET) as a unit. In practice change the
    assignment for AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY to a small
    conditional that prefers the standard env vars together, otherwise uses the
    legacy pair only when both legacy vars exist, and yields undefined/null if
    neither full pair is present; reference the AWS_ACCESS_KEY_ID and
    AWS_SECRET_ACCESS_KEY symbols when locating where to implement this.

In @apps/web/src/server/aws/ses.ts:

  • Line 20: Replace the relative import of getAwsCredentialOptions from
    "./credentials" with the repo-standard src alias import (e.g. import {
    getAwsCredentialOptions } from "~/server/aws/credentials";) so the module uses
    the ~/ alias form consistent with apps/web src imports.

In @apps/web/src/server/aws/sns.ts:

  • Line 8: Replace the relative import for getAwsCredentialOptions with the
    project src alias; change the import source from "./credentials" to the aliased
    module (e.g. "/server/aws/credentials") so the import reads: import {
    getAwsCredentialOptions } from "
    /server/aws/credentials"; this aligns the
    getAwsCredentialOptions import with the apps/web src alias convention.

Nitpick comments:
In @apps/docs/get-started/set-up-docker.mdx:

  • Around line 55-57: Update the Docker setup instructions so the AWS static
    credential environment variables (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY,
    AWS_DEFAULT_REGION) are documented as optional: change the text that currently
    tells users to "Replace the placeholders with your actual database and AWS
    details." to "Replace the placeholders with your actual database details. If
    your environment does not provide AWS credentials via IAM/default provider
    chain, also set: AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY." Ensure this
    change is applied to the same explanatory lines that contain the three
    environment variable placeholders and the similar line around the later
    occurrence (the one referenced at line 63).

</details>
<details>
<summary>🪄 Autofix (Beta)</summary>
Fix all unresolved CodeRabbit comments on this PR:
- [ ] <!-- {"checkboxId": "4b0d0e0a-96d7-4f10-b296-3a18ea78f0b9"} --> Push a commit to this branch (recommended)
- [ ] <!-- {"checkboxId": "ff5b1114-7d8c-49e6-8ac1-43f82af23a33"} --> Create a new PR with the fixes
</details>
---
<details>
<summary>ℹ️ Review info</summary>
<details>
<summary>⚙️ Run configuration</summary>
**Configuration used**: Organization UI
**Review profile**: CHILL
**Plan**: Pro
**Run ID**: `b582a91e-d79f-48e3-bf7b-c0e17c7b23fc`
</details>
<details>
<summary>📥 Commits</summary>
Reviewing files that changed from the base of the PR and between 31a49fbdca243a4674ec07946f69e8479c86f1f9 and 1c6317daccebc1e2b2afe54cec38e735ac58d913.
</details>
<details>
<summary>📒 Files selected for processing (18)</summary>
* `.env.example`
* `.env.selfhost.example`
* `.github/workflows/test-web.yml`
* `CONTRIBUTION.md`
* `apps/docs/get-started/create-aws-credentials.mdx`
* `apps/docs/get-started/local.mdx`
* `apps/docs/get-started/set-up-docker.mdx`
* `apps/docs/self-hosting/overview.mdx`
* `apps/docs/self-hosting/railway.mdx`
* `apps/web/.env.test.example`
* `apps/web/src/env.js`
* `apps/web/src/server/aws/credentials.ts`
* `apps/web/src/server/aws/ses.ts`
* `apps/web/src/server/aws/sns.ts`
* `apps/web/src/test/setup/setup-env.ts`
* `docker/README.md`
* `docker/prod/compose.yml`
* `turbo.json`
</details>
</details>
<!-- This is an auto-generated comment by CodeRabbit for review status -->

Comment threadapps/web/src/env.js
Comment on lines +102 to +103
AWS_ACCESS_KEY_ID: process.env.AWS_ACCESS_KEY_ID || process.env.AWS_ACCESS_KEY,
AWS_SECRET_ACCESS_KEY: process.env.AWS_SECRET_ACCESS_KEY || process.env.AWS_SECRET_KEY,

@coderabbitaicoderabbitaiBotMay 17, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Avoid mixing standard and legacy credential sources across fields.

Line 102 and Line 103 independently fall back with ||, which can combine AWS_ACCESS_KEY_ID with legacy AWS_SECRET_KEY (or vice versa). That can create an invalid pair and undercut partial-config safeguards.

Suggested fix
- AWS_ACCESS_KEY_ID: process.env.AWS_ACCESS_KEY_ID || process.env.AWS_ACCESS_KEY,- AWS_SECRET_ACCESS_KEY: process.env.AWS_SECRET_ACCESS_KEY || process.env.AWS_SECRET_KEY,+ AWS_ACCESS_KEY_ID:+ process.env.AWS_ACCESS_KEY_ID ?? process.env.AWS_ACCESS_KEY,+ AWS_SECRET_ACCESS_KEY:+ process.env.AWS_ACCESS_KEY_ID != null ||+ process.env.AWS_SECRET_ACCESS_KEY != null+ ? process.env.AWS_SECRET_ACCESS_KEY+ : process.env.AWS_SECRET_KEY,
📝 Committable suggestion

‼️IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
AWS_ACCESS_KEY_ID: process.env.AWS_ACCESS_KEY_ID||process.env.AWS_ACCESS_KEY,
AWS_SECRET_ACCESS_KEY: process.env.AWS_SECRET_ACCESS_KEY||process.env.AWS_SECRET_KEY,
AWS_ACCESS_KEY_ID:
process.env.AWS_ACCESS_KEY_ID??process.env.AWS_ACCESS_KEY,
AWS_SECRET_ACCESS_KEY:
process.env.AWS_ACCESS_KEY_ID!=null||
process.env.AWS_SECRET_ACCESS_KEY!=null
? process.env.AWS_SECRET_ACCESS_KEY
: process.env.AWS_SECRET_KEY,
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@apps/web/src/env.js` around lines 102 - 103, The current fallback uses
independent || for AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY which can mix
standard and legacy values; update the logic so the code selects either the
standard pair (AWS_ACCESS_KEY_ID + AWS_SECRET_ACCESS_KEY) or, only if both are
absent, the legacy pair (AWS_ACCESS_KEY + AWS_SECRET) as a unit. In practice
change the assignment for AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY to a small
conditional that prefers the standard env vars together, otherwise uses the
legacy pair only when both legacy vars exist, and yields undefined/null if
neither full pair is present; reference the AWS_ACCESS_KEY_ID and
AWS_SECRET_ACCESS_KEY symbols when locating where to implement this.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nah thats fine, we should give responsibilty to users

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@KMKoushik, understood — the independent fallback is intentional, and the partial-config guard in getAwsCredentialOptions in credentials.ts will still catch the case where only one standard key is set at runtime. Acknowledged!

(ᵔ ᵕ ᵔ) 🐇


✏️ Learnings added
Learnt from: KMKoushik
Repo: usesend/useSend PR: 401
File: apps/web/src/env.js:102-103
Timestamp: 2026-05-17T11:17:08.286Z
Learning: In `apps/web/src/env.js` (usesend/useSend), the independent `||` fallback for `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` (falling back to legacy `AWS_ACCESS_KEY`/`AWS_SECRET_KEY` respectively) is intentional. The project maintainer explicitly chose to give users responsibility for providing consistent credential pairs rather than enforcing paired fallback logic at the env layer. The partial-config guard is handled at runtime in `apps/web/src/server/aws/credentials.ts` via `getAwsCredentialOptions()`.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

Comment threadapps/web/src/server/aws/ses.ts Outdated
Comment threadapps/web/src/server/aws/sns.ts Outdated

@greptile-appsgreptile-appsBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.

@KMKoushik
KMKoushik merged commit 04d0f4b into mainMay 17, 2026
7 checks passed
@KMKoushik
KMKoushik deleted the fix/aws-env-vars-on-pr-395 branch May 17, 2026 11:23
@coderabbitaicoderabbitaiBot mentioned this pull request Jul 31, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feat: Avoid hardcoding AWS credentials & support standard AWS env variables

2 participants

@KMKoushik@purva-8