Patch release focused on eliminating silent renewal and data-loss failures, plus two UI fixes.
Reliability (#293)
- Renew on the exact threshold boundary. A certificate sitting at exactly
renewal_threshold_days(default 30) previously skipped renewal until it dropped to threshold-1, a silent one-day delay. The check is now inclusive, matching the digest and metrics paths. - Validate and clamp
renewal_threshold_days. A 0, negative, or non-numeric value made the renewal decision permanently false (no certificate ever renewed) or raised an error in the worker. It is now rejected at the API boundary and clamped defensively on read. - Readiness probe for the renewal engine.
/healthstays 200 (liveness) so load balancers are unaffected; a new/health/readyreturns 503 when the scheduler failed to start, so orchestrators no longer see a healthy instance that quietly never renews. Boot-time scheduler failure now logs at CRITICAL. - Observable
check_renewals. Malformed entries in the domains list were skipped with no signal; every checked / renewed / failed / skipped entry is now counted, logged as a per-run summary, and returned. - External-storage failures are surfaced. A failed save to Azure Key Vault / AWS Secrets / Vault / Infisical was previously only a log line while the API returned success. The failure is now recorded in metadata (without leaking the raw exception), returned on create, and shown on
GET /api/certificates/<domain>. - SQLAlchemy is capped below 3.0.0 so a future major bump cannot break the APScheduler jobstore and silently stop renewals on an unattended upgrade.
UI (#294)
- The first-run setup wizard is now dismissible durably. Dismissal persists server-side (a dedicated
wizard_dismissedflag, kept separate fromsetup_completed) instead of only in per-browser localStorage, so the wizard no longer re-appears on another browser or after storage is cleared. It can be dismissed from any step via a header close button, Esc, or a backdrop click. - Form selectors and inputs no longer wobble on focus. The create-certificate and setup form fields used
transition-all, which animated layout on reflow; they now usetransition-colors.
Internal
- CI: self-hosted
testand CodeQL jobs are serialized host-wide to stop concurrent pull requests from cycling the shared test container (#295).