Skip to content

fix(api): pre-flight validation for federation IaC bundles (target/source + Azure/GCP source-identity)#67

Merged
cristim merged 1 commit into
feat/multicloud-web-frontendfrom
fix/federation-iac-failloud
Apr 25, 2026
Merged

fix(api): pre-flight validation for federation IaC bundles (target/source + Azure/GCP source-identity)#67
cristim merged 1 commit into
feat/multicloud-web-frontendfrom
fix/federation-iac-failloud

Conversation

@cristim
Copy link
Copy Markdown
Member

@cristim cristim commented Apr 25, 2026

Summary

Adds two pre-flight validation guards to the federation IaC handler so operator misconfigurations fail loudly at download time instead of silently shipping broken bundles that fail at terraform apply.

Combines fixes for two related issues that touch the same code path (internal/api/handler_federation.go::getFederationIaC and the surrounding helpers), so reviewers don't have to look at the same function twice.

Closes #41
Closes #42

Changes

#42validateFederationTargetSource (HTTP 400, fail fast)

Reject impossible target/source combinations before bundle construction. Today the only impossible-by-construction combo is target=aws-cross-account (target=aws + source=aws) from a non-AWS CUDly deployment: the rendered trust policy needs CUDly's AWS account ID in the principal ARN, which a CUDly running on Azure/GCP cannot supply. Returns NewClientError(400) naming the actual deployment cloud so the caller sees:

target=aws-cross-account requires CUDly to be deployed on AWS; this deployment is on azure

instead of a downloadable bundle that later fails with a cryptic invalid principal ARN IAM error.

#41validateSourceIdentity (HTTP 500, operator misconfig)

Extends the existing AWS-only fail-loud guard in populateSourceAccountID to cover Azure and GCP source clouds. When CUDly runs on Azure but AZURE_SUBSCRIPTION_ID or AZURE_TENANT_ID is unset (or on GCP without GCP_PROJECT_ID), the bundle previously shipped with empty identity fields. Customers ran terraform apply and got a blank client_id / missing project. Now the handler returns a 500-class error naming the missing env var so the operator knows exactly what to fix.

Test seam

Introduces mockSourceIdentity + defaultTestSourceIdentity in handler_federation_test.go so tests can pre-warm the cached sourceIdentity without going through STS / env vars. The existing TestGetFederationIaC_FailsLoudOnEmptySourceAccountID is simplified to use the new seam instead of clearing every AWS_* env var. The AWS-cross-account tests (which previously relied on the default CUDLY_SOURCE_CLOUD=gcp test fixture and the absence of the new target/source check) now correctly set CUDLY_SOURCE_CLOUD=aws.

Files changed

  • internal/api/handler_federation.go — +66 LOC (two new helpers + two new call sites in getFederationIaC)
  • internal/api/handler_federation_test.go — +258 / -19 (new test seam, 7 new test cases across 3 test functions, updates to existing AWS-cross-account tests)

Test plan

  • go build ./... clean
  • go vet ./... clean
  • go test ./... clean (full repo suite)
  • TestGetFederationIaC_FailsLoudOnEmptyAzureSourceIdentity — 3 subtests (missing-subscription-id, missing-tenant-id, all-populated positive control)
  • TestGetFederationIaC_FailsLoudOnEmptyGCPSourceIdentity — missing GCP_PROJECT_ID
  • TestGetFederationIaC_RejectsImpossibleTargetSourceCombo — 3 subtests (azure→reject, gcp→reject, aws→allow regression guard)
  • All previously-passing federation tests still pass

Notes

  • CodeRabbit auto-review may skip because the base branch (feat/multicloud-web-frontend) is not the repo's default branch — that's expected; the @coderabbitai review comment is still posted per project convention.
  • No frontend, IaC template, or deploy-time changes — Go-only PR. Existing rendered bundles remain unchanged in shape.

…urce + Azure/GCP source-identity)

Adds two pre-flight validation guards to the federation IaC handler so
operator misconfigurations fail loudly at download time instead of
silently shipping broken bundles that fail at `terraform apply`.

#42 — validateFederationTargetSource (HTTP 400, fail fast)
  Reject impossible target/source combinations early — before bundle
  construction. Today the only impossible-by-construction combo is
  target=aws-cross-account (target=aws + source=aws) from a non-AWS
  CUDly deployment: the rendered trust policy needs CUDly's AWS account
  ID in the principal ARN, which a CUDly running on Azure/GCP cannot
  supply. Returns NewClientError(400) naming the actual deployment
  cloud so the caller knows why.

#41 — validateSourceIdentity (HTTP 500, operator misconfig)
  Extends the existing AWS-only fail-loud guard in
  populateSourceAccountID to cover Azure and GCP source clouds. When
  CUDly runs on Azure but AZURE_SUBSCRIPTION_ID or AZURE_TENANT_ID is
  unset (or on GCP without GCP_PROJECT_ID), the bundle previously
  shipped with empty identity fields and customers hit a cryptic
  `terraform apply` error with a blank client_id / missing project.
  Now returns a 500-class error naming the missing env var so the
  operator knows exactly what to fix.

Test seam: introduces mockSourceIdentity + defaultTestSourceIdentity
in handler_federation_test.go so tests can pre-warm the cached
sourceIdentity without going through STS / env vars. The existing
TestGetFederationIaC_FailsLoudOnEmptySourceAccountID is simplified to
use the new seam instead of clearing every AWS_* env var. The
AWS-cross-account tests (which previously relied on the default
CUDLY_SOURCE_CLOUD=gcp test fixture and the absence of the new
target/source check) now correctly set CUDLY_SOURCE_CLOUD=aws.

New test coverage:
  - 3 Azure subtests (missing-subscription-id, missing-tenant-id,
    all-populated positive control)
  - 1 GCP test (missing-project-id)
  - 3 target/source consistency subtests (azure→reject, gcp→reject,
    aws→allow regression guard)

Closes #41
Closes #42
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 25, 2026

Warning

Rate limit exceeded

@cristim has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 50 minutes and 7 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 50 minutes and 7 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: dd1d7caf-8120-4a92-982b-05b1c534c98c

📥 Commits

Reviewing files that changed from the base of the PR and between c8f58e9 and bcf1484.

📒 Files selected for processing (2)
  • internal/api/handler_federation.go
  • internal/api/handler_federation_test.go
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/federation-iac-failloud

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.

@cristim
Copy link
Copy Markdown
Member Author

cristim commented Apr 25, 2026

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 25, 2026

✅ 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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

effort/m Days impact/many Affects most users priority/p1 Next up; this sprint severity/high Significant harm triaged Item has been triaged type/bug Defect urgency/now Drop other things

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant