brokerd: recover a torn line in place, real dates only, bounded ttl, EMFILE

From the independent review of task 23. A torn last line followed by an empty
later file had its recovery written into the later file, which broke the
chain for good; the line is now ended in its own file. The log-name rule
takes months 01 to 12 and days 01 to 31 only. [approvals] ttl_ms is limited
to a day, the longest loopd waits after a pending frame. Running out of file
descriptors or memory pauses the listener instead of stopping brokerd (the
errors the previous fix skipped do not occur on Linux). args.rs's doc fixed.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-22 21:48:24 -07:00
co-authored by Claude Opus 5.5
parent ba369f82ba
commit e08deb39a6
9 changed files with 157 additions and 42 deletions
+9 -3
View File
@@ -93,14 +93,20 @@ pub struct AuditRecord {
}
/// True if `name` is an audit log file: `YYYY-MM-DD.jsonl`, ASCII digits with `-` at positions 4
/// and 7. `brokerd` and `bxctl audit verify` both decide with this, so they read the same files.
/// and 7, a month from 01 to 12 and a day from 01 to 31. `brokerd` and `bxctl audit verify` both
/// decide with this, so they read the same files.
pub fn is_audit_log_name(name: &str) -> bool {
let Some(date) = name.strip_suffix(".jsonl") else {
return false;
};
date.len() == 10
let shaped = date.len() == 10
&& date.bytes().enumerate().all(|(i, b)| match i {
4 | 7 => b == b'-',
_ => b.is_ascii_digit(),
})
});
if !shaped {
return false;
}
let number = |range: std::ops::Range<usize>| date.get(range).and_then(|s| s.parse::<u8>().ok());
matches!(number(5..7), Some(1..=12)) && matches!(number(8..10), Some(1..=31))
}