Stand the hosting up
There is nowhere to publish to. Before any workflow can copy a file there has to be a bucket with a name in front of it.
The stack owns everything except one thing: the delegation in the root account that points
toptable at this account's hosted zone. That is done by hand, once, and everything else
follows from it.
Acceptance criteria
- One CloudFormation template under
infra/creates the hosted zone, the certificate, the bucket, the distribution, the IAM roles and the alias record - The domain name comes in as a template parameter. The certificate ARN does not, because the stack now issues it rather than being handed one
- The bucket has static website hosting enabled with
index.htmlas the index document. CloudFront takes the website endpoint as a custom origin, not the REST endpoint — KB-7 has why, and getting this wrong breaks the previews rather than the live site, so it will pass a casual test - HTTP redirects to HTTPS
- A
robots.txtat the bucket root disallows/tt- - The bucket name, distribution id, role ARNs and site URL are recorded in the GitHub Actions environments the later stories read. No workflow hardcodes any of them
- Uploading a hand-built
dist/and loadinghttps://toptable.enablis.tech/serves the app
DNS and the certificate
- The hosted zone for
toptable.enablis.techis created in the development account, and its four nameservers are a stack output. The delegation is wired up from them by hand, in the root account - The hosted zone is retained when the stack is deleted. Its nameservers are what that delegation points at, and a zone deleted and recreated is given different ones. Losing them takes the site dark in a way that reads as a certificate problem
- The certificate is requested with DNS validation against that zone, in
us-east-1whatever region the bucket is in. CloudFront reads certificates from that region only - The alias record for
toptable.enablis.techpoints at the distribution - The first deploy stops at the certificate and waits. ACM validates over public DNS and nothing public knows where the zone is until the delegation exists. The nameservers are available from the zone long before the stack finishes, so the wait is workable — but it has to be written down somewhere a person will find it, or it reads as a hang
Two roles, not one
- A publish role, trusted by GitHub's OIDC provider and scoped to this repository, may write to the bucket and create invalidations on the distribution, and may do nothing else. TT-42 and TT-43 assume this one
- An infrastructure role, trusted the same way, may change the stack's own resources. Only the infrastructure workflow assumes it
- They are separate because the infrastructure role can write IAM. Giving that to the role every merge and every pull request push already holds is a privilege escalation one careless workflow edit away
Deploying the stack
- A workflow applies the template. Nothing is deployed from a laptop once the first apply has happened
- It runs only when
infra/changed. A merge that touches nothing there deploys no infrastructure - A pull request touching
infra/gets a CloudFormation changeset created and posted on it, and does not execute it. The same bargain as a preview: something a person can read before approving, rather than a diff and a hope - Merging applies the changeset. The review is the changeset on the pull request, not a second approval after it — somebody reads what will change, approves the pull request, and merging carries out the thing they read
- So the protection that matters sits on the pull request, not on the environment.
Nothing waits for an approval after a merge, so a merge to
maintouchinginfra/changes infrastructure.mainrequiring a review is what makes that a gate rather than a formality - Infrastructure still uses its own environment, separate from the previews'. They hold different role ARNs. It carries values, not a gate
- Applying a template that has not changed is a no-op and reports as one rather than failing
- A failed apply leaves the stack in a state the next run can proceed from, and says which resource failed
Agents
Two more, in .claude/agents/, on the same terms as the five TT-2 established. The
model is set explicitly on both.
| Agent | Model | Responsible for |
|---|---|---|
infra-developer |
sonnet | The CloudFormation template, the workflows and the IAM policies. Works to KB-7 |
infra-reviewer |
opus | Reads an infrastructure diff cold as an AWS engineer would. Reports on security posture, least privilege, blast radius and AWS practice |
infra-reviewerhas no Write and no Edit, for the reasonreviewerdoes not. A reviewer that can edit quietly fixes what it finds, and then you have the fix instead of the finding- It is a separate agent from
reviewerbecause the questions are different ones. Whether a policy is least privilege, whether a bucket should be public, whether a role can escalate its own permissions and whether a change can be rolled back are not things a code reviewer is looking for infra-developeris separate from the other developers because none of them should be writing IAM, and because a template is not code that tests can cover
Notes
The first apply is by hand and is the exception. The role the workflow assumes is created by this stack, so it does not exist until the stack has been applied once.
It is also the only apply that waits for a person. Once the delegation is in place the certificate validates and renews on its own, and no later deploy stops for anybody. KB-7 has the ordering.
Comments
No comments on this issue