This document is the single source of truth for how changes flow from an
assistant-drafted edit to a verified production deployment of the
Mafrick & Company Advocates website
(mafrick-munene-advocates.com, served via GitHub Pages from
LGLenz/mafrick-munene-advocates-website).
The intent is to move governance from "Copilot/assistant remembers to run the right thing" to mandatory, codified workflows enforced by GitHub branch protection, environments, and scheduled smoke tests.
This is the same governance model used across the LGLenz/ELB Consulting
Tech first-wave repos (e.g.
bridgeaxis-consulting PR #23),
adapted to a single-page static site.
Copilot / assistant drafts change on a branch
|
v
Open Pull Request to main
|
v
┌────────────────────────────────────┐
│ PR Mandatory Checks │ ← required by branch protection
│ - install-validation │
│ - build-validation │
│ - lint │
│ - link-sanity │
│ - secrets-config │
└────────────────────────────────────┘
|
v
Reviewer approves & merges
|
v
┌────────────────────────────────────┐
│ Deploy GitHub Pages (Production) │ ← uses `production` environment
│ - build artifact │ (optional reviewers/wait timer)
│ - actions/deploy-pages │ records GitHub deployment status
│ - enforce HTTPS │
└────────────────────────────────────┘
|
v
┌────────────────────────────────────┐
│ Site Health (post-deploy) │ ← triggered by workflow_run
│ - DNS source-of-truth diff │ + scheduled every 6h
│ - HTTPS / TLS / status / title │ + manual workflow_dispatch
│ - Pages default URL + custom dom. │
└────────────────────────────────────┘
| Workflow file | Trigger | Purpose |
|---|---|---|
.github/workflows/pr-checks.yml |
pull_request, push:main, workflow_dispatch |
Mandatory PR checks (jobs listed below). |
.github/workflows/deploy-pages.yml |
push:main, workflow_dispatch |
Build + deploy Pages artifact via official actions; records deployment status against the production environment. |
.github/workflows/site-health.yml |
workflow_dispatch, schedule (6h), workflow_run (after deploy) |
DNS, TLS, HTTP, and title smoke tests of live site. |
The following job names from pr-checks.yml should be marked required
in the main branch protection rule:
Install / tooling validationBuild / artifact validationLint / static validationLink / site artifact sanityNo-secrets / config sanity
To configure (Settings → Branches → main):
- Require a pull request before merging
- Require status checks to pass before merging
- Require branches to be up to date before merging
- Add the job names above to the required-checks list.
- Require linear history (recommended).
- Require conversation resolution before merging (recommended).
The deploy workflow targets a GitHub environment named production.
Configure it under Settings → Environments → production:
- Required reviewers: add the maintainers who should approve a deploy.
- Wait timer: optional, e.g. 5 minutes to allow a final cancel.
- Deployment branches: restrict to
main.
When deploy-pages.yml runs, GitHub will:
- Record a deployment with status
in_progress. - Block on the environment's approval rules (if any).
- Run the deploy.
- Update the deployment status to
successorfailure.
This eliminates the "deployments tab is stale" problem because every
push:main and every manual dispatch produces a tracked deployment.
site-health.yml runs:
- automatically after
deploy-pages.ymlcompletes (viaworkflow_run), - on a 6-hour cron schedule,
- on demand via
workflow_dispatch.
What it checks, for each target URL:
- DNS —
digreturns at least one A/AAAA/CNAME record. - TLS —
openssl s_clientcompletes without verification errors. - HTTP —
curlreturns a 2xx/3xx status within 15s. - Title — response body contains a
<title>mentioning "Mafrick".
Targets:
| Label | URL | Required? |
|---|---|---|
| pages-default | https://lglenz.github.io/mafrick-munene-advocates-website/ | no (warn-only) |
| custom-domain | https://mafrick-munene-advocates.com | no (warn-only) |
Both targets are warn-only at the moment because:
- The custom domain
mafrick-munene-advocates.comis in the process of being provisioned. The CNAME may still be propagating and GitHub's TLS certificate issuance for the host can take 24h+ after the CNAME goes live. - The Pages default URL is a fallback that is only meaningful if Pages is configured for workflow-source builds; until that is verified, failures should not block the workflow.
When DNS / TLS / HTTPS for the custom domain is verified working, flip
the custom-domain target to required: "true" in site-health.yml
so that regressions become blocking.
When the scheduled run fails, an issue is opened with label site-health.
Expected DNS for mafrick-munene-advocates.com lives in
dns/records.yaml. The dns-check job in site-health.yml consumes
this file and diffs it against live DNS via
scripts/check_dns.py.
Expected:
mafrick-munene-advocates.comis a CNAME →lglenz.github.io.(project-Pages with a subdomain custom domain — see the GitHub Pages docs).
Note: The parent zone elbconsultingtech.com is managed under ELB
Consulting Tech outside this repository. Coordinate any changes to
the CNAME with that zone's owner.
While the custom domain is being provisioned, dns-check drift is
warn-only in site-health.yml. Switch it to a hard failure once
DNS + TLS are confirmed live.
- Copilot/assistant drafts; humans approve. The assistant opens a PR; PR checks run automatically; a human reviewer merges.
- Branch protection is the enforcer, not memory. No reliance on the assistant "remembering" to run checks — they run because GitHub requires them.
- Production deploys use environment approvals. Manual deploys via
workflow_dispatchgo through the same approval gate as automatic push-to-main deploys. - Smoke tests verify reality. A green deploy that produces a broken
site fails the post-deploy
site-healthworkflow and opens an issue. - DNS is code. Live DNS is diffed against
dns/records.yamlon every scheduled run. - No secrets in PR checks. All required PR checks are read-only and run on forks safely.
| Symptom | Likely cause | Where to look |
|---|---|---|
| Deployments tab is stale | A previous Pages workflow failed without recording a deployment. | deploy-pages.yml run log + Settings → Environments → production. |
mafrick-munene-advocates.com shows cert error |
GitHub Pages certificate for the custom host still being issued. | site-health.yml → http-check (custom-domain target, warn-only). |
dns-check job warns |
Live DNS doesn't yet match dns/records.yaml. |
Parent zone elbconsultingtech.com DNS console + scripts/check_dns.py output in job summary. |
PR check No-secrets / config sanity fails |
A secret-shaped string was committed. | Job log lists the file and pattern. |
# 1. Start from main.
git switch main && git pull
# 2. Branch.
git switch -c feat/your-change
# 3. Edit. Commit. Push.
git push -u origin feat/your-change
# 4. Open a PR. Mandatory checks run automatically.
# 5. After approval + merge, deploy-pages.yml runs.
# 6. site-health.yml runs post-deploy and on schedule.These cannot be set via committed files and need to be done in the GitHub UI by a repo admin:
- Branch protection on
main— add the fivepr-checks.ymljob names from §3 as required status checks. - Environment
production(Settings → Environments) — required reviewers and/or wait timer; restrict deployment branches tomain. - GitHub Pages source — Settings → Pages → set "Source" to
"GitHub Actions" so
deploy-pages.ymlis the source of truth (rather than the legacy branch-source build). - Custom domain DNS / TLS — once
mafrick-munene-advocates.comresolves and GitHub has issued a certificate, flip thecustom-domaintarget insite-health.ymlfromrequired: "false"torequired: "true".