Closes #124. Substantive contribution from @ITJamie (#122 — 1445 additions, 12 files, 47 test cases).
Domain alias mode that actually works
The previous DNS-01 alias flow assumed the primary domain's DNS was manageable by your provider; CertMate would still try to write the _acme-challenge TXT record on the primary zone and fail with Unable to determine zone_id for <primary>. The whole point of alias mode is the case where it isn't — only the alias zone is. This release reworks the flow:
modules/core/dns_alias_hook.py— new Lexicon-backed manual DNS hook supporting cloudflare, route53, azure, google, powerdns, digitalocean, linode, gandi, ovh, namecheap, arvancloud, infomaniak, duckdns, acme-dns. Writes the TXT on the alias zone, lets the CNAME chain resolve. Unsupported providers are rejected up-front with a clear error instead of failing mid-certbot.POST /api/certificates/<domain>/check-cnames— new endpoint to verify the_acme-challengeCNAME chain exists for a domain (and all its SANs) before issuing. Surfaces missing records up-front instead of after a 60s certbot retry.- UI: alias indicator pill on dashboard cert rows, alias display in cert detail panel, SAN list in the sidebar, hint help text in the create-cert form.
- Renewal path: rebuilds the manual hook from cert metadata so renewals don't fail when the temp credentials file is gone (the alias-mode sibling of #112 — different code path, same shape of bug, fixed here for the alias case).
- Tests: 47 cases in
tests/test_domain_alias.pycovering hook regeneration on renewal, SAN+wildcard expectations, CNAME existence reporter, unsupported-provider rejection, missing-credentials handling, ACME-DNS subdomain matching, lexicon adapter mapping for all 14 supported providers.
CI workflow fix (visible to every external contributor)
docker-multiplatform.yml was constructing image tags like docker.io//certmate:pr-NN (double slash from an empty secrets.DOCKERHUB_USER on fork PRs — GitHub Actions intentionally doesn't pass secrets to fork workflows). Every dependabot PR and every external contributor PR had been red on the build job for that reason alone, hiding real test signal. Added a one-line fallback: when DOCKERHUB_USER is empty, use github.repository_owner instead. Push to Docker Hub is still disabled for PRs (gated separately).
Maintainer reconciliation during the rebase
The PR was opened before the v2.4.x cleanup landed. To bring it on top of v2.4.5:
dashboard.jscert-row template reconciled with the v2.4.2CertMate.htmlauto-escape helper (alias indicator now uses${domainAlias}interpolation;providerLabelgoes throughrowRaw()).- Bandit B310 hardening: scheme-validate the DNS-provider API URL in
_json_request,# nosec B310 - hardcoded https literalon the two static URLs (api.ipify.org for Namecheap public-IP injection; cloudflare-dns.com for the new DoH lookup).
Tests
- 209 unit tests pass (was 162 — +47 from #122)
- All e2e tests pass (build + test (3.12) green on the merged PR for the first time across all the v2.4.x triage PRs)
Full diff: v2.4.5...v2.4.6