Skip to content

Promote dev: runner tooling, stateless build job, dispatch build, -lock=false plan, fresh-VPC SG bootstrap - #37

Merged
Atom-oh merged 7 commits into
mainfrom
dev
Sep 5, 2026
Merged

Atom-oh merged 7 commits into
mainfrom
dev

Conversation

@Atom-oh

@Atom-oh Atom-oh commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

Promotes #30–#36: sub-ownership docs, setup-terraform, build job derives the ECR URI without state, deploy-web dispatch build input, read-only plan with -lock=false + terraform.yml self-trigger, and the fresh-VPC CloudFront-SG bootstrap fix.

🤖 Generated with Claude Code

…#30)

The admin-removal / CLI-recreate flow changes the user's sub, so sub-keyed
ownership rows (reports, chat threads) do not follow the recreated identity;
prefer admin-disable-user on stacks holding real user data.
* docs: state rm, not disable, preserves the TF-managed admin from the planned destroy

admin-disable-user cannot stop a planned Terraform destroy — the correct
preservation mechanism is 'terraform state rm aws_cognito_user.admin' before
the first post-merge apply; disable remains the revocation tool for
manually-provisioned users.

* fix: address review feedback — -chdir on the state rm command (copy-paste-ready)
#32)

The self-hosted runner image ships no terraform binary — every job that
reaches a real terraform invocation died with 'terraform: command not found'
(exit 127); earlier green Plan runs had merely skipped on missing stack
secrets. terraform_wrapper: false keeps 'terraform output -raw' captures
clean.
The ci-build role is ECR-push-only by design and has no S3 tfstate access —
the build job's 'terraform init' for a single 'terraform output' died with a
403 on HeadObject. The web ECR repository is deterministically
"${project}-web" (ecr.tf), so the job now reads 'project' from the stack's
tfvars blob and joins it with the ECR login action's registry output; no
backend.hcl, no terraform, no state read in the build job at all (the deploy
job, under the deployer role, still reads outputs as before).
…#34)

Build was push-only, so a stack whose web-<sha> image was never built (or
was lost) could only be recovered with a dummy commit. dispatch build=true
runs the build job for the dispatched HEAD and the deploy job pins that sha;
it is mutually exclusive with image_sha (fail-closed).
…#35)

The ci-terraform-plan role is ReadOnlyAccess by design and cannot write the
S3 lock object (use_lockfile → <key>.tflock needs s3:PutObject) — the first
real branch plan failed 'Error acquiring the state lock' right after its
OIDC trust landed. A read-only plan needs no lock; apply (deployer role)
still locks. The workflow file joins the push path filter so a workflow
change self-tests with a real plan.
#36)

* terraform: fresh-VPC bootstrap for the CloudFront VPC-origin SG lookup

The singular data.aws_security_group for CloudFront-VPCOrigins-Service-SG
hard-failed every plan on a brand-new VPC ('no matching EC2 Security Group
found'): that managed SG only appears once the FIRST VPC origin in the VPC
exists — this stack's own, which needs this very ALB. The live env never hit
it because it reused a VPC that already had another stack's VPC origin.
Plural lookup (empty list instead of error) + ALB ingress that falls back to
the VPC CIDR only while the SG is absent; the next plan after the VPC origin
exists tightens the rule in place. A check block surfaces bootstrap mode as a
plan warning.

* fix: address review feedback — no CIDR fallback while the CF SG is absent

The bootstrap VPC-CIDR ingress served no CloudFront traffic (VPC-origin ENIs
match the managed SG, not CIDR) and only opened an unauthenticated in-VPC
path that nothing would auto-close. While the managed SG is absent the ALB
now has no 443 ingress at all; the second apply adds the managed-SG rule.

* fix: address review feedback — data-source comment matches the no-fallback behavior
@github-actions

github-actions Bot commented Sep 5, 2026

Copy link
Copy Markdown

🤖 AI Code Review (Claude Fable 5 chair · lens×model matrix)

_Cells (model/lens): codex/L2 codex/L3 codex/L4 codex/L5 _

Status: BLOCKED — CRITICAL/MAJOR issues must be resolved before merge

🛑 Forced FAIL due to coverage collapse: at most one vendor survived, so cross-verification across the lens x model matrix cannot happen — fail-closed regardless of the chair's judgment.

⚠️ Coverage degraded: model(s) [kiro-opus, kiro-gpt] had no response across every lens (invalid flag/missing binary/auth failure, etc.) — the review below was synthesized without them.

All verification is complete — no dangling references to the removed singular data source, the deploy job's fail-safe if already handles a skipped build, and the ECR repo derivation matches ecr.tf. Here is the synthesized review.


PR #37 — Chair Review: runner tooling, stateless build job, dispatch build, -lock=false plan, fresh-VPC SG bootstrap

Summary

This PR makes the web build job stateless (deriving the ECR repo from the tfvars project instead of reading Terraform state — a genuine least-privilege improvement for the ci-build role), adds a build dispatch input, pins setup-terraform across workflows, drops the S3 lock on the read-only plan job, and converts the CloudFront-managed-SG lookup to a plural data source so a brand-new VPC can bootstrap without a hard plan failure. All four panel reviews came back clean except one MINOR docs finding; my independent verification against base confirms the design is sound — the deploy job's if: needs.build.result == 'success' || 'skipped' (base deploy-web.yml:144-147) already tolerates the now-conditional build job, the repo name ${var.project}-web matches terraform/foundation/ecr.tf:2, and the bootstrap state fails closed (no ALB ingress rather than a CIDR fallback).

Issues per lens

L2 — code correctness

Panel: codex reported no findings. Chair verification agrees there are no CRITICAL/MAJOR issues; two chair-added MINORs:

  • MINOR (chair): The PROJECT="${PROJECT:-awsops-v2}" fallback in the build job silently masks a sed parse failure, not just a legitimately-omitted project variable. A stack whose tfvars sets a non-default project in a format the regex misses (single quotes, unusual spacing) would push its image to awsops-v2-web — the wrong stack's repo — instead of failing loudly. Risk is bounded (only the immutable web-<sha> tag is written; :web-latest is untouched; a repo-scoped push role would reject it), but a fail-closed error would match this workflow's own "no cross-branch fallback, by design" philosophy better than a silent default.
  • MINOR (chair): The build/image_sha mutual-exclusion check runs in the deploy job's pin step — after the full arm64 build has already completed, and on main after a production-environment reviewer has approved the rollout. Validating the inputs in a cheap first step (or in the build job's if) would fail the bad dispatch in seconds instead of after a build plus an approval. Not a correctness bug (the pin never happens, and the stray immutable tag is harmless).

L3 — security/AWS mutation safety

Panel: codex reported no findings. Chair concurs — no issues, and two properties worth recording as positives:

  • Removing TF_BACKEND_HCL* secrets from the build job shrinks the ci-build role's effective surface to ECR-push-only (no tfstate read), consistent with the stated design.
  • The fresh-VPC bootstrap fails closed: while CloudFront-VPCOrigins-Service-SG is absent, the ALB SG has no 443 ingress rather than a VPC-CIDR fallback — explicitly avoiding the unauthenticated in-VPC path the base comments warn about. -lock=false is confined to the ReadOnlyAccess plan role; apply still locks, and terraform apply tfplan rejects a stale plan via state-serial checks, so no lost-update window is opened. No ADR-005 surface is touched (no new mutating capability; ecs update-service in the deploy job is pre-existing CI deployment, not agent autonomy).

L4 — observability/data-integration correctness

Panel: codex reported no findings. Chair concurs — the diff touches no Steampipe queries, CIS checks, collectors, or AgentCore diagnosis logic. Nothing in scope for this lens.

L5 — docs/ADR consistency

Panel: codex flagged one MINOR. Chair verified it against base — confirmed:

  • MINOR (1/1 panel model; chair-confirmed): docs/runbooks/dev-repo-setup.md (new text in this diff) states "Only the legacy verified-email read path bridges some tables." In base, canMutateReport (web/lib/diagnosis.ts:265-271) delegates to matchesIdentity → matchesLegacyEmailOwner (web/lib/auth.ts:355-357), so while LEGACY_EMAIL_OWNER_MATCH is enabled the legacy email match also authorizes report PATCH/DELETE, not just reads. The runbook's identity caveat should say the legacy bridge covers both read and mutation of email-keyed rows, so operators reasoning about recreated users understand their effective access.
  • Positive: docs/reference/01-edge-network.md was updated in lockstep with the workload.tf singular→plural change (both the SG-lookup description and the 504-root-cause section), and the removed singular data source has no remaining references in the tree.

Suggestions

  1. Replace the silent awsops-v2 fallback with a hard error when the tfvars blob contains a project line the regex can't parse (keep the default only when the variable is genuinely absent), or at least emit a ::warning:: when the fallback is used.
  2. Move the build/image_sha mutual-exclusion check to a first-step input validation so it fails before the build and before production approval.
  3. Fix the runbook's "read path" phrasing to reflect that LEGACY_EMAIL_OWNER_MATCH also gates report mutations (canMutateReport).
  4. Consider pinning terraform_version in the setup-terraform steps (repo requires ≥1.15; unpinned latest could jump majors under CI silently).

Verdict

No CRITICAL or MAJOR findings. All four panel lenses returned clean apart from one confirmed docs MINOR; chair verification against base reproduced no gate-worthy defects — the conditional build job, stateless ECR derivation, lock-free read-only plan, and fail-closed SG bootstrap are all consistent with the repo's conventions (fail-closed stack selection, SG description immutability respected, no ADR-005 impact).


Triggered by commit 8a9a6e0e70b807da2c12c4d84e1ef0345f5d6ae3 · workflow: .github/workflows/pr-review.yml

@Atom-oh
Atom-oh merged commit ab091a2 into main Sep 5, 2026
18 of 19 checks passed
Sign up for free to 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.

1 participant