Submit an issue View all issues Source
MIR-1243

Keep image-sync mirrors fresh: nothing re-runs on a schedule

In Progress public
phinze phinze Opened Jun 18, 2026 Updated Jun 24, 2026

MIR-1242 surfaced a sharp edge in how we mirror base images. A community member bumped his app's .ruby-version and Miren ignored it, partly because our Ruby buildpack wasn't reading the file (fixed in mirendev/runtime#858), but underneath that is a second problem: even if we had read it, image-sync only mirrors the exact tags someone typed into images.yaml by hand. Ruby is pinned to 3.3, 3.4, and 4.0. Ask for anything else and the tag isn't there.

Digging into mirendev/infra, the mirror-images.yml workflow runs on exactly two triggers: manual workflow_dispatch, and a push to main that edits image-sync/images.yaml. There's no schedule:. Nothing runs on its own. The mirror only moves when a human remembers to touch the file.

That leaves us with two freshness gaps. The obvious one is that new language minors (Ruby 3.5, Go 1.27, a new Node major) never appear until someone hand-adds them, so users who upgrade the normal way hit a missing tag. The subtler one is that the tags we do mirror are floating (3.4-slim), and upstream keeps pushing patch and security fixes to them. Because we only re-sync on file edits, our mirror is frozen at whatever digest it had last time someone touched the config. Apps deploying off our mirror quietly drift onto an increasingly old, unpatched base.

A scheduled re-run of the existing mirror job would close the second gap immediately, since the script re-pulls the floating tags every time it runs. Closing the first gap is a bit more work: something that diffs the available upstream tags against images.yaml and either opens a PR or pings us when a new minor shows up. We don't need to solve both at once. Even just a weekly cron on the current script would be a real improvement over "whenever someone remembers."

A third dimension: patch-level granularity.

The same community member followed up: he noticed we only accept MAJOR.MINOR, so his app landed on 4.0.2 with no way to request 4.0.4 or 4.0.5. He doesn't need it for the demo, but it's easy to imagine an app that has to match an exact patch.

This one's a deliberate starting point, not a bug. We mirror only the -MAJOR.MINOR tags to keep the combinatorial explosion of mirrored images under control. But upstream publishes every patch as its own tag (4.0.5-slim, 4.0.4-slim, ...), so the capability is there for the taking if we decide the storage and sync cost is worth it. Whatever we build for the freshness gaps above should keep this in view: an auto-sync that diffs upstream tags could pick up patch tags as easily as minor tags, and the buildpack already parses a full x.y.z out of .ruby-version (as of #858), so the version string is ready to match against a more granular tag set.

Surfaced by MIR-1242.