Files
adr-sml/docs/reference/github-actions-oidc.yml.example
T
Pouya LajevardiandClaude Opus 5 6bf1167624 fix: sweep D3 amendment through the specs; correct inverted DKIM table
The re-audit of the deploy-guard change surfaced defects well outside the
diff, including one that would have broken production mail.

docs/05-backend-spec.md had the two SES DKIM sets exactly inverted, labelling
the three records that resolve as "orphans" and the three NXDOMAIN records as
"Live. Never delete". Entry (j) corrected this in AGENTS.md §7 and the
correction never reached docs/05. Since SES has no custom MAIL FROM, DKIM is
the only thing satisfying DMARC, so acting on that table would have silently
broken intake mail authentication.

Also in this change:

- .gitea/workflows/deploy.yml gains a guard as steps[0] that fails the run,
  naming the variable, if AWS_REGION, S3_BUCKET or CLOUDFRONT_DISTRIBUTION_ID
  is empty — how a Gitea too old for the vars context manifests. Verified
  fail-closed under bash -e, sh -e and bash -euo pipefail.
- AGENTS.md Current Truth: SPF and DMARC recorded as present (Q20), the
  matching §10 High risk row retired, three duplicate Q rows removed.
- docs/reference/AWS-Hosting-Guide.md tracked and given a do-not-execute
  banner; it was an executable procedure for the architecture D1/D3 replace.
- Copy decks: "a working litigator" and "an active litigation practice"
  replaced with the register's own wording; LegalService JSON-LD replaced with
  ProfessionalService; tribunal-secretary offers removed per D14; nine stale
  question blockers swept.
- astro.config.mjs: prefetchAll disabled — it injected JS into every page
  against the zero-JS convention with no decision recorded.
- src/data/site.ts: unregistered response-time commitment nulled (Q27);
  OBA section names downgraded to [assumed] (Q28).
- s3:AbortMultipartUpload reasoning corrected to measure ./dist, not the repo.

Opens Q27, Q28, Q29. AGENTS.md entry (q) records the full resolution,
including the findings declined and why.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012XquaEq4BgWMCwUqLEyNkF
2026-08-26 11:28:42 -04:00

99 lines
3.4 KiB
Plaintext

# ---------------------------------------------------------------------------
# REFERENCE ONLY. This repository lives on self-hosted Gitea (AGENTS.md D3).
# The live pipeline is .gitea/workflows/deploy.yml.
#
# This file is kept because it is the better design: GitHub OIDC issues a
# short-lived token per run instead of a static key. If the project ever moves
# to GitHub, use this and delete the static IAM user. GitLab also federates
# to AWS by OIDC, but with entirely different CI syntax — this file is the
# design there, not the implementation.
# ---------------------------------------------------------------------------
name: Build and deploy
on:
push:
branches: [main]
workflow_dispatch:
# OIDC role assumption — a short-lived token per run, no static key.
# NOT the current posture: this repository deploys with a static IAM key.
# See docs/06-deployment.md for the live procedure and the IAM policy.
permissions:
contents: read
id-token: write
concurrency:
group: deploy-production
cancel-in-progress: false
jobs:
build-and-deploy:
runs-on: ubuntu-latest
environment: production
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version-file: .nvmrc
cache: npm
- name: Install
run: npm ci
- name: Type and template check
run: npm run check
- name: Build
run: npm run build
env:
PUBLIC_SITE_URL: https://adr.smlcompany.ca
PUBLIC_INTAKE_ENDPOINT: ${{ vars.INTAKE_ENDPOINT }}
PUBLIC_BOOKING_URL: ${{ vars.BOOKING_URL }}
# If adopting this: set AWS_DEPLOY_ROLE_ARN as a repository variable. The
# rest — AWS_REGION, S3_BUCKET, CLOUDFRONT_DISTRIBUTION_ID, INTAKE_ENDPOINT and
# BOOKING_URL — are recorded in docs/06-deployment.md.
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ vars.AWS_DEPLOY_ROLE_ARN }}
aws-region: ${{ vars.AWS_REGION }}
# Three passes: hashed immutable assets first, then images, HTML last.
# A visitor must
# never fetch a new page whose assets have not landed yet.
- name: Sync hashed assets
run: |
aws s3 sync ./dist "s3://${{ vars.S3_BUCKET }}" \
--exclude "*" \
--include "_astro/*" --include "fonts/*" \
--cache-control "public, max-age=31536000, immutable" \
--no-progress
- name: Sync images
run: |
aws s3 sync ./dist "s3://${{ vars.S3_BUCKET }}" \
--exclude "*" \
--include "*.avif" --include "*.webp" --include "*.jpg" \
--include "*.png" --include "*.svg" \
--cache-control "public, max-age=604800" \
--no-progress
- name: Sync HTML and the rest
run: |
aws s3 sync ./dist "s3://${{ vars.S3_BUCKET }}" \
--exclude "_astro/*" --exclude "fonts/*" \
--cache-control "public, max-age=0, must-revalidate" \
--delete --no-progress
- name: Invalidate CloudFront
run: |
aws cloudfront create-invalidation \
--distribution-id "${{ vars.CLOUDFRONT_DISTRIBUTION_ID }}" \
--paths "/*"
- name: Summary
run: echo "Deployed to https://adr.smlcompany.ca — commit ${GITHUB_SHA::7}" >> "$GITHUB_STEP_SUMMARY"