Repository navigation
fix(scripts): ship the Azure role module in generate-federation-iac bundles - #1467
Conversation
…d script The API's federation bundle ships the out-of-tree Azure role module (LeanerCloud#1431), but the helper that does it is unexported in internal/api, so scripts/generate-federation-iac.go cannot use it and still builds an Azure bundle that calls a module outside the zip (LeanerCloud#1442). Move the writer, the module list and the "local module sources resolve inside the zip" check into a small package both builders can import. It reads any fs.FS so the script can pass its on-disk modules directory, and skips hidden files and directories so a developer's .terraform/ or lock file never lands in a zip. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Use the shared writer for the API's federation bundles so the API and the developer script cannot drift apart again. Behaviour is unchanged: the embedded FS has no hidden files, and the module set and rewrite are the same. The bundle test keeps running every combo through the shared unresolved-module check; the guard's own self-test moved with it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…undles --format bundle --target azure zipped only iac/federation/azure-target/ terraform, whose main.tf calls ../../../../terraform/modules/iam/azure/ cudly-reservation-role, so `terraform init` on the unzipped bundle failed with "Unreadable module directory". Build the Terraform part through internal/iacbundle, as the API does since LeanerCloud#1440: the module ships at terraform/modules/cudly-reservation-role and the call points at it. Like the API's bundle it now also carries the target's terraform/tests/ directory. The new test runs every bundle the script builds through the same resolves-inside-the-zip check as the API's bundles; the Azure case fails on main. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Warning Review limit reached
This review includes 8 billable files and costs up to $2.00. Or wait 59 minutes for your next included review. View limit details
Comment |
|
Opened as a draft at c0a30ad: the script's bundle now goes through the shared internal/iacbundle writer, so its Azure bundle ships the role module. A regression test covers all 5 script bundles. Checks are listed in the PR body. |
|
Independent review (IAmJSD's agent, fresh context, given only the diff, the issue and the PR text): VERDICT: APPROVE Blocking:
Non-blocking:
Attacked:
Body-stale:
Reviewer: rE2. Bar while the maintainers are away (set by IAmJSD as acting owner): one approving independent review on the head, two for money, auth and security paths. |
|
Independent review (IAmJSD's agent, fresh context, given only the diff, the issue and the PR text): VERDICT: APPROVE Blocking:
Reviewer: rE3. Bar while the maintainers are away (set by IAmJSD as acting owner): one approving independent review on the head, two for money, auth and security paths. |
|
Local verification at |
|
Merged by IAmJSD's agent at IAmJSD's request (IAmJSD is acting owner while the maintainers are away), under the bar IAmJSD set: 2 approving independent review(s) on |
Picks up LeanerCloud#1467, which also edits scripts/generate-federation-iac.go, so the generator tests are re-run on the merged tree. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rst, read the dev Function URL from state (#1312) * chore(iac): derive the CFN issuer host, create the GCP signing key first, read the dev Function URL from state Three low findings from the 2026-09-02 audit. A13b-014: the aws-target CloudFormation template took the trust policy's condition-key host as a second parameter, OIDCIssuerHost, that the operator had to keep equal to OIDCIssuerURL minus https://. The host is now derived with !Select [1, !Split ["https://", !Ref OIDCIssuerURL]], the same value as the Terraform module's local.oidc_condition_host, and the server no longer passes the parameter in the bundle's params JSON or deploy script (CFN would reject an undeclared parameter). A13c-024: the Cloud Run module's OIDC signing key now has create_before_destroy, matching its AWS twin, so a change that forces a new key cannot destroy the live one first. destroy_scheduled_duration becomes an input whose default keeps every deployed key unchanged (the provider marks it ForceNew). prevent_destroy cannot be an input (Terraform requires a literal) and staging cleanup runs terraform destroy, so the redundant `prevent_destroy = false` line is replaced by a comment saying so. A13c-017: github-dev.tfvars no longer pins the dev Lambda Function URL host. The deploy and rollback workflows read the previous apply's lambda_function_url output (scripts/read-lambda-function-url.sh) and pass it as TF_VAR_lambda_deployed_function_url; compute.tf appends its origin to the CORS allowlist. A post-apply step warns when the apply changed the URL. Refs #324 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(iac): allowlist the mocked caller-identity account ID in the CORS tftest The combined-tree git-secrets run flagged terraform/environments/aws/tests/lambda_cors_origins.tftest.hcl:10, a bare account_id = "123456789012" in the mocked aws_caller_identity. Add an anchored whole-line .gitallowed entry for that one line (bracketed digits so the entry does not match itself), placed before the other terraform/ entries so it does not collide with #1255's entry for its own tftest. Refs #324 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Merge origin/main into fix/issue-324 Bring the branch up to date with main. Conflicted files: - .github/workflows/ci.yml: this branch appended a "Run Function URL reader self-tests" step to the aws-tfstate-platform-key job; main (#1112) added a new rollback-ecr-registry job right after that job. Kept both: the step stays at the end of aws-tfstate-platform-key and main's job follows it unchanged. rollback.yml merged cleanly: main's rewritten "Verify image exists" steps and this branch's TF_VAR_lambda_deployed_function_url export touch different steps. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Merge origin/main into fix/issue-324 Two textual conflicts, both resolved by keeping both sides: - ci.yml: main added an init-backend.sh self-test step to the same job this branch appends the Function URL reader self-tests to, plus a new tfstate-concurrency-group job after it. Both steps stay in the job, and main's job follows. - cloud-run/.terraform.lock.hcl: main's "~> 5.45" constraint with the union of both sides' h1: hashes for google 5.45.2. #1256 (merged on main) added OIDCIssuerHost to the standalone generator; the next commit drops it again to match this branch. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(scripts): drop OIDCIssuerHost from the standalone IaC generator #1256 added OIDCIssuerHost to iacData because aws-cfn-deploy.sh.tmpl passed it at the time. This branch removes the parameter from the CloudFormation template and the deploy script (the host is derived from OIDCIssuerURL), so the field is unused again and the drift test that compares iacData with federationIaCData fails until it goes. The bundle test now checks that the rendered deploy script passes OIDCIssuerURL and never OIDCIssuerHost, since CloudFormation rejects an override for an undeclared parameter. The field walker's control uses OIDCIssuerURL instead. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(iac): note the key ring order and the URL reader's failure mode Review follow-ups on #1312. create_before_destroy on the signing key also applies to the key ring it depends on, and the Function URL reader treats any terraform output failure as "no URL". Both are intended, but neither was written down where the code is. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(api): pass t to federationHandler in the CFN bundle test #1223 on main made federationHandler take *testing.T so it can register AssertExpectations on its mock. This branch's CFN bundle parameter test still called it with no arguments, so internal/api stopped compiling after the merge. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Merge origin/main into fix/issue-324 Picks up #1467, which also edits scripts/generate-federation-iac.go, so the generator tests are re-run on the merged tree. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Closes #1442
Root cause
scripts/generate-federation-iac.go --format bundlehas its own bundle builder. It zipped only the target's Terraform directory (iac/federation/azure-target/terraform), whosemain.tfcalls../../../../terraform/modules/iam/azure/cudly-reservation-role. #1440 fixed this for the API download by shipping the module inside the zip, but that helper was unexported ininternal/api, so the script never got the fix.terraform initon a script-built Azure bundle still failed with "Unreadable module directory".Fix
internal/iacbundleholds the bundle Terraform writer, the module list (ExtraModules), the source rewrite, and theUnresolvedLocalModulescheck. It reads anyfs.FSand skips hidden files and directories, so the script can pass its on-disk modules directory without picking up a local.terraform/or lock file.addDirToZipis removed.addTerraformToBundlecallsiacbundle.AddTerraformDir(os.DirFS(modulesDir), ...), so the Azure bundle ships the role module atterraform/modules/cudly-reservation-roleand the call points at it. Like the API's bundle, the script's Azure bundle now also carriesterraform/tests/identity_guards.tftest.hcl. Before, the script copied only top-level files.Three commits, each under 400 lines: add the package, switch the API to it, then switch the script and add its regression test.
Verification
scripts/generate_federation_iac_bundle_test.gobuilds every bundle the script can make (all 5 target/source combos), runs it throughiacbundle.UnresolvedLocalModules, and checks that no hidden file is shipped. On main the azure-target case fails withterraform/main.tf: ../../../../terraform/modules/iam/azure/cudly-reservation-role. It passes with the fix.internal/iacbundleunit tests: module shipped and rewritten, hidden files skipped, an uncalled module is an error, and the guard's self-test (moved frominternal/api).terraform getthere. It resolvedcudly_reservation_role in modules/cudly-reservation-role. No init or plan was run against any backend.go build ./...,go vet(plain, integration, e2e), golangci-lint v2.10.1 with and without--build-tags integration(0 issues), gocyclo -over 10 (clean),go test -race -shorton iacbundle/api/scripts/terraform,go test -race -tags integration ./internal/api/(ok), the secrets scan (clean), andscripts/test-git-secrets-allowlist.sh(183 PASS).🤖 Generated with Claude Code