Skip to content

fix(terraform/aws): add dashboard_url override for Lambda-Function-URL deployments (follow-up to #355) - #363

Merged
cristim merged 2 commits into
feat/multicloud-web-frontendfrom
fix/terraform-dashboard-url-fallback
May 13, 2026
Merged

fix(terraform/aws): add dashboard_url override for Lambda-Function-URL deployments (follow-up to #355)#363
cristim merged 2 commits into
feat/multicloud-web-frontendfrom
fix/terraform-dashboard-url-fallback

Conversation

@cristim

@cristim cristim commented May 13, 2026

Copy link
Copy Markdown
Member

Summary

Follow-up to #355: even with PR #362's app-layer guards in place, the dev Lambda deployment had DASHBOARD_URL="" because local.dashboard_url (used to build the env var) only fell back to custom domains, not to the Lambda Function URL itself. Operators of any Lambda-Function-URL deployment without a custom domain configured got silent email loss.

This PR adds a var.dashboard_url tfvar that takes priority over var.frontend_domain_names, so operators can bootstrap the env var manually for Function-URL deployments.

Why not just read module.compute_lambda[0].function_url directly?

Dependency cycle. The same module consumes additional_env_vars (which contains local.dashboard_url), so referencing its output from the local would mean:

local.dashboard_url  →  module.compute_lambda.function_url
                      ↗  (output of the lambda function URL resource)
                     ↗  (depends on the lambda function resource)
                    ↗  (which depends on additional_env_vars)
                   ↗  (which depends on local.dashboard_url)  ← cycle

The workable Terraform-only path is a manual bootstrap:

  1. First terraform applyDASHBOARD_URL="" in the env, app refuses to send.
  2. terraform output frontend_url — gives the function URL.
  3. Set dashboard_url = "<that value>" in tfvars.
  4. Re-apply — DASHBOARD_URL is now persisted across deploys.

The trace was: local.dashboard_url priority chain (main.tf:58) was shallower than the frontend_url output's chain (outputs.tf:195-200), which already handles all four tiers correctly. This PR closes the gap with a single override variable (the cycle prevents a direct mirror).

Changes

  • terraform/environments/aws/variables.tf — new dashboard_url variable with validation (must include scheme, no trailing slash, no path).
  • terraform/environments/aws/main.tflocal.dashboard_url checks the new var first, then falls back to the existing frontend_domain_names path. Comment refreshed to spell out why the Lambda-Function-URL tier can't live here.
  • terraform/environments/aws/github-dev.tfvars — comment updated to call out the new tfvar + the bootstrap pattern. The CI/CD TF_VAR_dashboard_url line is documented but not hard-coded (it's per-environment).

Test plan

  • terraform fmt -check -recursive clean.
  • terraform validate — not run locally; this PR's CI will exercise it against the prod state backend.
  • After merge + apply on dev: DASHBOARD_URL in the Lambda env survives subsequent applies (no longer reset to empty by additional_env_vars reconciliation).

Out of scope

  • Auto-populating dashboard_url for CDN / Fargate / custom-domain deployments — those already work via the existing chain. The new tfvar is the Lambda-Function-URL escape hatch.
  • The temporary aws lambda update-function-configuration env-var poke applied directly to the live Lambda earlier today gets clobbered by the next terraform apply until this PR's dashboard_url tfvar value is set in the dev CI/CD pipeline. That's the operational follow-up.

Sister PRs

Summary by CodeRabbit

  • New Features
    • Added a new dashboard_url configuration option to specify a custom dashboard origin for email links and CORS headers; it can be set explicitly or will fall back to existing frontend domain values when unset.
  • Documentation
    • Included guidance on when to set the dashboard_url and the expected http/https host-only format (no trailing slash, path, query, fragment, or userinfo).

Review Change Stack

…L deployments (#355)

local.dashboard_url at terraform/environments/aws/main.tf only fell
back to "" when var.frontend_domain_names was empty — there was no
tier for deployments served from a raw Lambda Function URL. Result:
DASHBOARD_URL reached the Lambda as empty, the auth Service refused
to send invite / password-reset emails (the guard introduced earlier
in this branch), and every operator using a dev / scratch deployment
without a custom domain saw silent email loss.

A direct local.dashboard_url = module.compute_lambda[0].function_url
fallback creates a dependency cycle (compute_lambda consumes
additional_env_vars which contains local.dashboard_url; we'd then
have local.dashboard_url → compute_lambda → compute_lambda).

Adding a tfvar bootstraps cleanly:

  1. var.dashboard_url       — explicit override (NEW)
  2. var.frontend_domain_names[0] (existing) — custom domain path
  3. empty — the app's startup WARN + per-send guards already
     surface the misconfiguration

Operators of Lambda-Function-URL deployments now:
  - `terraform apply` once (DASHBOARD_URL empty in the env)
  - `terraform output frontend_url` prints the just-provisioned URL
  - set var.dashboard_url to that value in tfvars
  - `terraform apply` again — DASHBOARD_URL is now persisted

Matches outputs.tf's frontend_url chain (which already prioritises
the Lambda Function URL for Lambda compute platforms) modulo the
cycle-avoidance constraint.

Doc updated in github-dev.tfvars to call out the bootstrap pattern.
@cristim cristim added bug Something isn't working triaged Item has been triaged priority/p1 Next up; this sprint severity/high Significant harm urgency/this-sprint Within the current sprint impact/many Affects most users effort/xs Trivial / one-liner type/bug Defect labels May 13, 2026
@cristim

cristim commented May 13, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented May 13, 2026

Copy link
Copy Markdown
Contributor
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai

coderabbitai Bot commented May 13, 2026

Copy link
Copy Markdown
Contributor

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 6e5d7d48-c390-4e81-a46a-57dcd6aeb833

📥 Commits

Reviewing files that changed from the base of the PR and between db296b3 and 23e8193.

📒 Files selected for processing (1)
  • terraform/environments/aws/variables.tf
🚧 Files skipped from review as they are similar to previous changes (1)
  • terraform/environments/aws/variables.tf

📝 Walkthrough

Walkthrough

This PR adds a dashboard_url Terraform input variable with URL validation, updates locals.dashboard_url to prefer an explicit override then the frontend domain, and includes a commented TF_VAR_dashboard_url example and instructions for the dev environment.

Changes

Dashboard URL Configuration

Layer / File(s) Summary
Dashboard URL input variable and priority resolution
terraform/environments/aws/variables.tf, terraform/environments/aws/main.tf, terraform/environments/aws/github-dev.tfvars
Adds dashboard_url input variable with regex validation allowing empty or http(s)://host(:port) (no trailing slash/path/query/fragment/userinfo). Updates locals.dashboard_url to use var.dashboard_url when non-empty, else var.frontend_domain_names[0] (with https:// prefix), else empty. Adds a commented TF_VAR_dashboard_url placeholder and instructions for dev bootstrap.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~8 minutes

Possibly related PRs

  • LeanerCloud/CUDly#362: Updates email/auth guards to skip notifications when ServiceConfig.DashboardURL is empty, directly consuming the dashboard URL configuration introduced in this PR.

Suggested labels

effort/s

Poem

🐰 A dashboard URL takes the stage,
With fallback logic wise and fair—
Explicit choice, or fronted domain's grace,
Configuration flows with care,
One hop forward for the dev's embrace! ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: adding a dashboard_url override variable for Lambda Function URL deployments, which is the core feature across all three modified files.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/terraform-dashboard-url-fallback

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

@cristim cristim added bug Something isn't working triaged Item has been triaged priority/p1 Next up; this sprint severity/high Significant harm urgency/this-sprint Within the current sprint impact/many Affects most users effort/xs Trivial / one-liner type/bug Defect labels May 13, 2026

@coderabbitai coderabbitai Bot 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: 1

🤖 Prompt for all review comments with 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.

Inline comments:
In `@terraform/environments/aws/variables.tf`:
- Around line 441-443: Validation for variable dashboard_url should be tightened
to reject query strings, fragments and userinfo: update the validation.condition
(the block validating var.dashboard_url) to still allow empty string or a full
origin but replace the current regex with one that requires an http or https
scheme, then a host portion that does NOT allow user@ (no userinfo) and accepts
either a hostname/FQDN or bracketed IPv6, followed optionally by a colon and
numeric port, and then anchors to end-of-string so no path/query/fragment are
allowed; keep the existing can() wrapping and the var.dashboard_url == ""
short-circuit.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 519959aa-1255-4f53-9769-e199cf5842c5

📥 Commits

Reviewing files that changed from the base of the PR and between 44365bb and db296b3.

📒 Files selected for processing (3)
  • terraform/environments/aws/github-dev.tfvars
  • terraform/environments/aws/main.tf
  • terraform/environments/aws/variables.tf

Comment thread terraform/environments/aws/variables.tf Outdated
Address CR feedback on PR #363: the previous regex
`^https?://[^/]+(?::[0-9]+)?$` was too permissive — `[^/]+` matched
anything except `/`, so URLs containing `@` (userinfo), `?` (query),
or `#` (fragment) silently slipped through and would have produced
invalid CORS origins downstream.

New pattern:

  ^https?://                          scheme: http or https
  (?:
    [A-Za-z0-9.-]+                    hostname / FQDN
    |\[[0-9A-Fa-f:]+\]                OR bracketed IPv6 literal
  )
  (?::[0-9]+)?                        optional numeric port
  $                                   end-of-string

Rejects userinfo (`https://user@example.com`), path
(`https://example.com/foo`), query (`https://example.com?q=1`),
fragment (`https://example.com#frag`), and trailing slash. Accepts
plain hostnames (`http://localhost`), FQDNs (`https://app.example.com`),
IPv4 (`http://192.168.1.1`), and IPv6 literals
(`https://[::1]:8443`).

Empty-string short-circuit preserved (the value is optional; leaving
it blank falls through to frontend_domain_names → empty as before).

Verified against 13 sample inputs (positive + negative).
@cristim

cristim commented May 13, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented May 13, 2026

Copy link
Copy Markdown
Contributor
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@cristim

cristim commented May 13, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented May 13, 2026

Copy link
Copy Markdown
Contributor
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@cristim
cristim merged commit f63df46 into feat/multicloud-web-frontend May 13, 2026
4 checks passed
cristim added a commit that referenced this pull request May 13, 2026
…(follow-up to #363) (#368)

* chore(ci): pass TF_VAR_dashboard_url into AWS Lambda deploy workflow

Follow-up to #363 (which added var.dashboard_url to the Terraform
config). Without this commit the variable stays unset in CI and the
DASHBOARD_URL env var on the deployed Lambda gets reset to "" on every
apply — symptom: invite / password-reset emails skip the send with the
"DashboardURL is not configured" error.

Adds TF_VAR_dashboard_url to both the Terraform Plan and Terraform
Apply env blocks in .github/workflows/deploy-aws-lambda.yml, sourced
from a new repo secret named DASHBOARD_URL. Matches the existing
pattern used by TF_VAR_admin_email and TF_VAR_from_email — operator
sets the secret once per repository (or per environment), CI threads
it through to every deploy.

For dev (Lambda Function URL, no custom domain), the value is the
Function URL itself: e.g.
  DASHBOARD_URL = https://<random>.lambda-url.<region>.on.aws

For deployments with frontend_domain_names already configured (custom
domain + Route53 + ACM), the secret can be left empty — the
Terraform local falls back to "https://${frontend_domain_names[0]}"
via the priority chain added in #363.

Caller action: set the GitHub repo secret DASHBOARD_URL to the
dashboard origin for each environment that uses this workflow, then
re-run the deploy. The very next apply persists the value into the
Lambda env permanently (no more manual `aws lambda
update-function-configuration` pokes that get clobbered).

* chore(ci): bind build-and-deploy to GitHub Environment (CR #368)

CR on PR #368 flagged that adding TF_VAR_dashboard_url without
binding the job to a GitHub Environment leaves DASHBOARD_URL
repo-scoped. Result: dev/staging/prod would all read the same
secret value and inject the wrong origin into customer-facing
email links for two of the three environments.

Adds environment: ${{ needs.prepare.outputs.environment }} to the
build-and-deploy job so secrets.* resolve to the named
environment's secrets when defined, falling back to repo-scoped
secrets when an env-level override isn't present. Backward-
compatible with the current repo-level DASHBOARD_URL secret —
operator can move it to env-level secrets per environment
incrementally without breaking the workflow.

Same protection now applies to TF_VAR_admin_email, TF_VAR_from_email,
TF_BACKEND_AWS, and any other secret the job reads — they pick up
environment overrides automatically once defined.
@cristim
cristim deleted the fix/terraform-dashboard-url-fallback branch June 3, 2026 21:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working effort/xs Trivial / one-liner impact/many Affects most users priority/p1 Next up; this sprint severity/high Significant harm triaged Item has been triaged type/bug Defect urgency/this-sprint Within the current sprint

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant