mirror of
https://github.com/wirenboard/agent-vm.git
synced 2026-07-09 16:00:54 +00:00
run: seed the pulled-digest marker on launch so the update banner can fire
Follow-up to the ghcr.io banner auth fix (v0.1.17). The banner compares the
registry against the digest recorded by our last pull (`pulled_marker`), but
that marker was written *only* by `agent-vm pull`. So anyone who got their
image via a launch's `IfMissing` auto-pull — or via an older agent-vm that
never wrote the marker (the pre-v0.1.17 401 bug) — had no baseline, landed in
`UpdateState::NotCached`, and the banner stayed silent forever until they ran
`agent-vm pull` by hand. Which is the exact "I always had to pull manually"
complaint the banner was meant to retire.
Seed the marker on the launch path, just before the probe, from what
microsandbox actually has cached (`Image::get(ref).manifest_digest()`), but
only when no marker exists yet — an existing marker is the authoritative
record of our last pull. A stale cache then trips the banner on *this* launch,
not the next.
Why `Image::get` is safe here but not in pull.rs: pull.rs uses
PullPolicy::Always, where microsandbox's cached manifest digest can lag a
re-pull under the same tag (the reason pulled_marker.rs exists). The launch
path uses IfMissing and never re-pulls, so the cached digest is accurate.
Verified live that `Image::get(...).manifest_digest()` returns the exact
per-platform digest `image_check::fetch_remote_digest` produces, so the
marker-vs-registry comparison is apples-to-apples:
seeded pulled-digest baseline from cache digest=sha256:90cfcbdc...
registry update probe digest=sha256:90cfcbdc... (UpToDate, no banner — cache current)
Fresh installs: image not cached → no seed → no banner on first run (correct,
the imminent pull lands the current image); armed from the next launch on.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
0fee58a8b9
commit
65c6d59a40
1 changed files with 41 additions and 0 deletions
|
|
@ -294,6 +294,11 @@ pub async fn launch(agent: Agent, args: Args) -> Result<i32> {
|
|||
// image available — the user runs `agent-vm pull` explicitly to
|
||||
// fetch it.
|
||||
if !args.no_update_check {
|
||||
// Give the banner a baseline to compare against on *this* launch,
|
||||
// not just future ones: if the image is already cached but we have
|
||||
// no recorded pulled-digest yet, seed the marker from the cache
|
||||
// first, then probe.
|
||||
seed_pulled_marker_if_absent(image.as_str()).await;
|
||||
notify_if_update_available(image.as_str()).await;
|
||||
}
|
||||
|
||||
|
|
@ -1947,6 +1952,42 @@ mod tests {
|
|||
}
|
||||
}
|
||||
|
||||
/// Seed the pulled-digest marker from microsandbox's cache when we have
|
||||
/// no record yet, so the update banner has a baseline to diff against on
|
||||
/// this very launch.
|
||||
///
|
||||
/// The marker (what the banner compares to the registry) was historically
|
||||
/// written *only* by `agent-vm pull`. A user who acquired the image via a
|
||||
/// launch's `IfMissing` auto-pull — or via an older agent-vm that never
|
||||
/// wrote it — had no baseline, so the banner could never fire. Here, if
|
||||
/// the image is already cached and unmarked, we record its per-platform
|
||||
/// manifest digest. Then a stale cache trips the banner on the next probe
|
||||
/// (i.e. immediately, since the call below seeds before we probe).
|
||||
///
|
||||
/// Safe on the launch path: `IfMissing` never re-pulls, so `Image::get`'s
|
||||
/// digest is accurate (the re-pull staleness that makes pull.rs avoid
|
||||
/// `Image::get` — see pulled_marker.rs — can't apply here). Verified
|
||||
/// empirically that `Image::get(...).manifest_digest()` is the same
|
||||
/// per-platform digest `image_check::fetch_remote_digest` returns, so the
|
||||
/// comparison is apples-to-apples. Only ever *seed* — never overwrite an
|
||||
/// existing marker, which is the authoritative record of our last pull.
|
||||
async fn seed_pulled_marker_if_absent(image: &str) {
|
||||
if crate::pulled_marker::read(image).is_some() {
|
||||
return;
|
||||
}
|
||||
// Not cached yet (genuine first run) → Image::get errors → nothing to
|
||||
// seed, and there's correctly nothing newer to flag: the imminent
|
||||
// IfMissing pull lands the current image.
|
||||
if let Ok(handle) = microsandbox::Image::get(image).await
|
||||
&& let Some(digest) = handle.manifest_digest()
|
||||
{
|
||||
match crate::pulled_marker::write(image, digest) {
|
||||
Ok(()) => tracing::debug!(image, digest, "seeded pulled-digest baseline from cache"),
|
||||
Err(e) => tracing::warn!(error = %e, "failed to seed pulled-digest marker"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn notify_if_update_available(image: &str) {
|
||||
use crate::image_check::{UpdateState, check_for_update};
|
||||
// The probe does up to three sequential registry round-trips for a
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue