- F1: test that clicking the badge/UpdateNowButton actually dispatches the update
(confirm->mutate) for standalone and stack, and not on dismiss.
- F2: Go test that a successful forced re-check repopulates the caches (a later
non-force read hits cache, no second registry HEAD).
- F3: throttle forced image-status re-checks against registry amplification —
coalesce concurrent forced re-checks of the same image via singleflight, plus a
5s per-image min-interval (== remoteDigestCache TTL) caching only successes. The
non-force path (daemon + background badges) is unchanged.
- F4: notifications are now per-container. Stack-member containers each emit their
own EventUpdated (not one aggregate stack event), Event carries the stack name
(from the com.docker.compose.project label), and the new image digest is fetched
best-effort by re-inspecting the container after the redeploy. Message:
'Environment | .. / Stack [<name>] / Update [<container>]: <old> -> <new>'.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Make the container image-status badge actionable, matching native Portainer:
- Clicking "Update available" opens the update confirm dialog and runs the
existing update flow (standalone recreate-with-pull / stack redeploy), gated
and disabled while in flight to avoid a double submit. The confirm+apply logic
is extracted from UpdateNowButton into a shared useApplyContainerImageUpdate
hook so the details button and the list badge share one implementation.
- Clicking "Up to date" re-queries the registry. Because the server caches image
status (statusCache 5m + remoteDigestCache 5s), a plain refetch was a no-op, so
the endpoint gains an optional ?force=true that bypasses BOTH caches for a
manual re-check while still repopulating them; the default (auto badges + the
auto-update daemon) keeps using the caches unchanged.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
F1: cap the image-status cache TTL at 5m (was 24h) — the cache is keyed by the
LOCAL imageID, which doesn't change when upstream pushes a new image under the
same tag, so the 24h TTL hid new images from both the badge and the auto-update
daemon; a short TTL re-resolves the remote digest within the poll window.
F2: document that the update->rollback guard map is in-memory (restart implication).
F3: skip auto-update for an unnamed container when rollback is on (the endpoint+name
keyed guard can't record it, so it would loop) — pure skipUnnamedForRollback + test.
F4: wrap the pre-update ContainerInspect in context.WithTimeout(endpointTimeout).
F5: document Reload() does not interrupt an in-flight tick.
F6: floor auto-heal CheckInterval at 1s (mirrors auto-update) + test.
F7: wontfix — migration is currently correct; namespace rework is out of scope.
F8: correct the misleading SSRF/AllowList comment (no filter is applied).
F9: front auto-heal interval floor + test; dedup STALE_TIME; fix invalidation comment.
Also refresh three stale '24h/long-lived cache' comments to match the 5m TTL.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
F1: ContainerImageStatus now reads the 24h statusCache (keyed by imageID)
before the remote registry digest lookup, so the cache is effective on the
input side for all callers instead of being write-only. This avoids the
rate-limited registry HEAD on repeat loads.
F2: add nodeName to the imageStatus query key so cached results cannot be
reused across nodes.
F3: correct the swagger annotations to reflect that engine-level issues
degrade to a 200 skipped/error status rather than 400/404.
F4: return a generic error message to the client instead of the raw
registry/engine error; the raw error is still logged server-side.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>