feat(host): the daily update check and the staged update (P11a step 4)
While the books are open the host looks at the release feed at most once a day (knob update_check, noted in updates/checked so a restart does not look again), and only downloads and verifies a newer release into <root>/updates/staged/ (sha256 AND minisign signature, as for update). It never swaps: the staged program is applied (a) by an opener just before it starts a host, when no host runs, so no call is cut off, after a second check against the key (a staged file that fails or does not start is dropped), and (b) by wanderbooks update, the owner's say-so, which reuses the staged copy instead of downloading again. A local release can be named in <root>/updates/feed (file:// only, with its key file, same rule as --trusted-key). The program's version is set by main since packages rewrite only the cli's. No new dependency. Tests (crates/ledger-cli/tests/update.rs): the_host_stages_a_daily_update_and_the_next_start_applies_it, a_daily_update_that_is_not_ours_is_not_staged, update_installs_the_copy_the_host_staged_without_downloading_again, a_staged_update_that_was_tampered_with_is_dropped_not_applied. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HS8WZziDnyxunC23MUxrLp
This commit is contained in:
1 parent
562b893c64
commit
6e7deb15c7
6 files changed
+454
-15
No files matched your search
@@ -33,6 +33,9 @@ pub struct Knobs {
|
||||
/// How long after books open the server first looks for a drill due
|
||||
/// (60 s), passed to the server as `--drill-first`.
|
||||
pub drill_first: Duration,
|
||||
/// How long between the host's looks for a newer release (plan
|
||||
/// P11a step 4: a day).
|
||||
pub update_check: Duration,
|
||||
}
|
||||
|
||||
impl Default for Knobs {
|
||||
@@ -47,6 +50,7 @@ impl Default for Knobs {
|
||||
open_wait: Duration::from_secs(120),
|
||||
backup_quiet: Duration::from_secs(30),
|
||||
drill_first: Duration::from_secs(60),
|
||||
update_check: Duration::from_secs(24 * 60 * 60),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -76,6 +80,7 @@ impl Knobs {
|
||||
"open_wait" => k.open_wait = d,
|
||||
"backup_quiet" => k.backup_quiet = d,
|
||||
"drill_first" => k.drill_first = d,
|
||||
"update_check" => k.update_check = d,
|
||||
other => return Err(format!("{FLAG}: there is no knob {other:?}")),
|
||||
}
|
||||
}
|
||||
@@ -97,6 +102,7 @@ impl Knobs {
|
||||
("open_wait", self.open_wait, d.open_wait),
|
||||
("backup_quiet", self.backup_quiet, d.backup_quiet),
|
||||
("drill_first", self.drill_first, d.drill_first),
|
||||
("update_check", self.update_check, d.update_check),
|
||||
] {
|
||||
if now != default {
|
||||
parts.push(format!("{name}={}", now.as_millis()));
|
||||
@@ -130,6 +136,7 @@ mod tests {
|
||||
assert_eq!(k.open_wait, Duration::from_secs(120));
|
||||
assert_eq!(k.backup_quiet, Duration::from_secs(30));
|
||||
assert_eq!(k.drill_first, Duration::from_secs(60));
|
||||
assert_eq!(k.update_check, Duration::from_secs(86_400));
|
||||
assert_eq!(k.to_arg(), None);
|
||||
assert!(k.args().is_empty());
|
||||
assert_eq!(Knobs::parse("").unwrap(), k);
|
||||
@@ -138,7 +145,7 @@ mod tests {
|
||||
#[test]
|
||||
fn knobs_pass_on_exactly() {
|
||||
let k = Knobs::parse(
|
||||
"close_after=500,backoff=20,server_delay=3000,init_wait=100,queue_wait=900,exe_poll=50,open_wait=70,backup_quiet=40,drill_first=50",
|
||||
"close_after=500,backoff=20,server_delay=3000,init_wait=100,queue_wait=900,exe_poll=50,open_wait=70,backup_quiet=40,drill_first=50,update_check=60",
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(k.close_after, Duration::from_millis(500));
|
||||
@@ -150,6 +157,7 @@ mod tests {
|
||||
assert_eq!(k.open_wait, Duration::from_millis(70));
|
||||
assert_eq!(k.backup_quiet, Duration::from_millis(40));
|
||||
assert_eq!(k.drill_first, Duration::from_millis(50));
|
||||
assert_eq!(k.update_check, Duration::from_millis(60));
|
||||
let args = k.args();
|
||||
assert_eq!(args[0], FLAG);
|
||||
assert_eq!(Knobs::parse(&args[1]).unwrap(), k);
|
||||
|
||||
Reference in new issue
Block a user