ACME: a renewal that isn't due yet is rescheduled, not failed for good
ci / fork-checks (pull_request) Successful in 14s
ci / build (pull_request) Successful in 16m46s

When a valid certificate already covered a domain's names (one stored
by hand before the domain was switched to automatic, for instance), the
renewal task ended with NotDue, which the task manager treats as a
permanent failure. Nothing rescheduled it, so the certificate expired
unrenewed. The renewal now returns a new AcmeRenewal task due when the
certificate falls due, the same way a successful renewal does, and logs
it as a backoff.

The ACME integration suite checks that renewing again right after
issuance hands back one AcmeRenewal for that domain, due at the
certificate's renewal point.
This commit is contained in:
2026-09-28 12:15:05 -07:00
parent 5a73a1183a
commit beb6c33e63
2 changed files with 46 additions and 5 deletions
+19 -5
View File
@@ -1,7 +1,10 @@
/*
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
* SPDX-FileCopyrightText: 2026 Coffey Labs
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
*
* Modified by Coffey Labs in 2026 for INBUXA.
*/
use crate::{
@@ -72,11 +75,22 @@ impl Server {
.acme_certificate_renewal_due(&domains, renew_before, now())
.await?
{
return Err(AcmeError::NotDue(format!(
"Certificate for domain {} is still valid; renewal is not due until {}",
domain.name,
UTCDateTime::from_timestamp(renew_at as i64)
)));
// INBUXA: a certificate already covering these names (one stored by
// hand before the domain was switched to automatic, say) isn't a
// failure: schedule the renewal for when it falls due. Returning
// NotDue here ended the task for good, and nothing renewed the
// certificate before it expired.
trc::event!(
Acme(trc::AcmeEvent::RenewBackoff),
Domain = domain.name.clone(),
Hostname = domains.as_slice(),
Details = "A valid certificate already covers these names",
NextRetry = trc::Value::Timestamp(renew_at),
);
return Ok(vec![Task::AcmeRenewal(TaskDomainManagement {
domain_id,
status: TaskStatus::at(renew_at as i64),
})]);
}
let dns_parameters = match &domain.dns_management {