Adds a local acme-dns authority for the narrowly delegated acme.commoninternet.net zone and prepares NixOS security.acme to obtain ci.commoninternet.net + *.ci.commoninternet.net through its localhost-only API. The ACME service begins in Let’s Encrypt staging and persists only its restricted acme-dns account outside Git/Nix.
Traefik’s immutable Swarm secrets are now versioned from the public certificate-chain digest, and a production-only handoff service atomically installs a renewed certificate, runs the existing health-gated Traefik reconciliation, then best-effort removes obsolete secret versions.
Why
The expired wildcard certificate cannot be renewed safely with a broad Gandi credential. This design leaves Gandi authoritative for the parent zone; the server will control only the delegated subzone and one permanent ACME challenge CNAME.
Targeted Ruff format/check completed for runner/warm_reconcile.py and the new unit test.
nixpkgs-fmt, statix, and deadnix passed. The full repo lint remains red solely on pre-existing formatting in 90 unrelated files plus one unrelated Ruff finding; this PR adds none.
## What changed
Adds a local acme-dns authority for the narrowly delegated `acme.commoninternet.net` zone and prepares NixOS `security.acme` to obtain `ci.commoninternet.net` + `*.ci.commoninternet.net` through its localhost-only API. The ACME service begins in Let’s Encrypt staging and persists only its restricted acme-dns account outside Git/Nix.
Traefik’s immutable Swarm secrets are now versioned from the public certificate-chain digest, and a production-only handoff service atomically installs a renewed certificate, runs the existing health-gated Traefik reconciliation, then best-effort removes obsolete secret versions.
## Why
The expired wildcard certificate cannot be renewed safely with a broad Gandi credential. This design leaves Gandi authoritative for the parent zone; the server will control only the delegated subzone and one permanent ACME challenge CNAME.
## Evidence
- `nix eval --impure --raw path:/mnt/data/srv/cc-ci-orch/cc-ci#nixosConfigurations.cc-ci-hetzner.config.system.build.toplevel.drvPath` completed successfully.
- `pytest -q tests/unit/test_acme_dns.py` completed: 2 passed.
- Targeted Ruff format/check completed for `runner/warm_reconcile.py` and the new unit test.
- `nixpkgs-fmt`, statix, and deadnix passed. The full repo lint remains red solely on pre-existing formatting in 90 unrelated files plus one unrelated Ruff finding; this PR adds none.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
What changed
Adds a local acme-dns authority for the narrowly delegated
acme.commoninternet.netzone and prepares NixOSsecurity.acmeto obtainci.commoninternet.net+*.ci.commoninternet.netthrough its localhost-only API. The ACME service begins in Let’s Encrypt staging and persists only its restricted acme-dns account outside Git/Nix.Traefik’s immutable Swarm secrets are now versioned from the public certificate-chain digest, and a production-only handoff service atomically installs a renewed certificate, runs the existing health-gated Traefik reconciliation, then best-effort removes obsolete secret versions.
Why
The expired wildcard certificate cannot be renewed safely with a broad Gandi credential. This design leaves Gandi authoritative for the parent zone; the server will control only the delegated subzone and one permanent ACME challenge CNAME.
Evidence
nix eval --impure --raw path:/mnt/data/srv/cc-ci-orch/cc-ci#nixosConfigurations.cc-ci-hetzner.config.system.build.toplevel.drvPathcompleted successfully.pytest -q tests/unit/test_acme_dns.pycompleted: 2 passed.runner/warm_reconcile.pyand the new unit test.nixpkgs-fmt, statix, and deadnix passed. The full repo lint remains red solely on pre-existing formatting in 90 unrelated files plus one unrelated Ruff finding; this PR adds none.