7Sense docs

Infrastructure & deploys

The AWS stack that hosts this site, and the pipeline that publishes it.

The stack#

infra/ is an OpenTofu declaration of everything the site runs on:

ResourceWhy
S3 bucket (private, versioned)Origin for the exported bundle. No public access at all.
CloudFront + Origin Access ControlReads the bucket over SigV4, terminates TLS, compresses.
CloudFront FunctionRewrites /docs/deploy//docs/deploy/index.html at the edge.
ACM certificate (us-east-1)CloudFront viewer certificates must live in us-east-1.
Response-headers policyCSP, HSTS, X-Frame-Options: DENY, referrer policy.
Route53 ALIAS A/AAAAOptional — only when route53_zone_id is set.
IAM OIDC provider + deploy roleLets GitHub Actions publish without any long-lived key.
tofu -chdir=infra fmt -check -recursive
tofu -chdir=infra init -backend=false
tofu -chdir=infra validate

First apply#

  1. cp infra/terraform.tfvars.example infra/terraform.tfvars and fill it in.
  2. tofu -chdir=infra init && tofu -chdir=infra plan.
  3. Apply. If the hosted zone is external, take the records from the certificate_validation_records output and create them; the apply waits on validation.
  4. Read the outputs — they are exactly the repository variables the workflow needs.

Repository variables#

Set these under Settings → Secrets and variables → Actions → Variables. None is a secret — the role ARN is useless without a token from the trusted repo and ref.

VariableSource
AWS_DEPLOY_ROLE_ARNtofu output -raw deploy_role_arn
AWS_REGIONsa-east-1
S3_BUCKETtofu output -raw bucket_name
CLOUDFRONT_DISTRIBUTION_IDtofu output -raw distribution_id
SITE_URLtofu output -raw site_url

The pipeline#

ci.yml runs on every pull request: validate:content (the Markdoc schema gate — the plugin does not validate on its own), typecheck, lint, the static build, and tofu fmt/validate.

deploy.yml runs on a push to main. It assumes the deploy role via OIDC, then:

  1. Two sync passes. Fingerprinted assets under _next/static get max-age=31536000, immutable; HTML gets max-age=0, must-revalidate. One Cache-Control cannot be correct for both — with a single immutable pass, readers keep seeing the old page long after the invalidation finished.
  2. --delete on the HTML pass only, so a removed page actually disappears. 3. Invalidate and wait for the invalidation to complete. 4. Verify the edge serves it — a 200 from the home page and from a deep link. A deploy that reports success without asking the edge for the artifact has proved nothing about what readers see.

The deploy-production concurrency group is cancel-in-progress: false on purpose: cancelling a sync --delete mid-flight leaves the bucket holding half of two bundles.

Deploying by hand#

scripts/deploy.sh performs the identical sequence when CI cannot run:

S3_BUCKET=$(tofu -chdir=infra output -raw bucket_name) \
CLOUDFRONT_DISTRIBUTION_ID=$(tofu -chdir=infra output -raw distribution_id) \
SITE_URL=$(tofu -chdir=infra output -raw site_url) \
pnpm deploy