Fix renew_before_days not triggering on exact day boundary

expires_within_days() compared the exact expiry timestamp against
now + N days, so a cert with 3 days 23 hours remaining would report
"days_remaining=3" but not renew with renew_before_days=3.

Fix by rounding days_until_expiry() to the nearest day (using seconds
for precision) instead of truncating. This matches user expectations
and provides a half-day buffer that absorbs systemd timer
randomization delays.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Roman Kivalin
2026-04-17 21:43:59 +02:00
co-authored by Claude Opus 4.6
parent 9af56cee30
commit cf7ccb45db
3 changed files with 16 additions and 6 deletions
+2
View File
@@ -6,6 +6,8 @@
### Fixes
- Fix `renew_before_days` not triggering renewal on the exact day boundary (e.g. `renew_before_days = 3` did not renew when 3 days and 23 hours remained, even though status showed "3 days")
### Changes
## 0.8.0 (2026-04-17)
+1 -1
View File
@@ -1,6 +1,6 @@
certforge (0.9.0-1) unstable; urgency=low
* No changes
* Fix renew_before_days not triggering on exact day boundary
-- Roman Kivalin <roman@shl.dev> Thu, 17 Apr 2026 00:00:00 +0000
+13 -5
View File
@@ -52,16 +52,24 @@ impl CertInfo {
}
/// Check if the certificate expires within the given number of days.
/// Uses rounded day count so that renew_before_days = 3 triggers
/// renewal when days_until_expiry() reports 3 or less.
pub fn expires_within_days(&self, days: u32) -> bool {
let now = chrono::Utc::now();
let threshold = now + chrono::Duration::days(days as i64);
self.not_after <= threshold
self.days_until_expiry() <= days as i64
}
/// Days until expiry (negative if already expired).
/// Days until expiry, rounded to nearest day (negative if already expired).
/// Rounding provides a half-day buffer that absorbs systemd timer
/// randomization without missing the renewal window.
pub fn days_until_expiry(&self) -> i64 {
let now = chrono::Utc::now();
(self.not_after - now).num_days()
let secs = (self.not_after - now).num_seconds();
let half_day = 43200; // 12 * 60 * 60
if secs >= 0 {
(secs + half_day) / 86400
} else {
(secs - half_day) / 86400
}
}
}