Skip to content

Check upstream weekly, rebuild monthly and scan the published image - #3

Open
mihow wants to merge 10 commits into
mainfrom
feat/automated-updates
Open

mihow wants to merge 10 commits into
mainfrom
feat/automated-updates

Conversation

@mihow

@mihow mihow commented Oct 2, 2026

Copy link
Copy Markdown
Collaborator

Summary

This image is only useful if it keeps up with its upstream sources and does not quietly collect known vulnerabilities. Until now, every version bump and every rebuild was a manual job that someone had to remember. This pull request automates the noticing and the preparation, and leaves the decision with a person.

Every Monday a workflow checks whether the server or client fork has published a new release, or whether the Go or Alpine base images have a newer patch. If so, it builds the image, runs the smoke test, and opens a pull request with an old/new table and links to the release notes. If nothing upstream has changed but the published image is more than 30 days old, it proposes a rebuild of the same release instead, so a rebuild happens about once a month. Every Tuesday, and after every publish, a second workflow scans the published image with Trivy and fails visibly when there are fixable critical or high findings. They also appear under the Security tab.

What stays manual: reviewing and merging the update pull request, which is still what publishes the image, updating the digest pins in the repositories that consume it, and deciding what to do about scan findings that upstream has not fixed yet.

Each build now also gets an immutable tag, <release>-r<revision>, so a rebuild of the same release never overwrites what someone has pinned.

Stacked on #1 (it reuses the smoke test added there). Please merge #1 first.

List of Changes

Change (what it does) How Notes
1. Every build gets a tag that never moves, such as RELEASE.2026-09-16T00-00-00Z-r1. The release tag and latest still move to the newest build. IMAGE_REVISION in versions.env. The build workflow pushes all three tags, skips publishing if the revision tag already exists, and prints the pin line with the revision tag and digest. README "Using the image" now recommends pinning -rN@sha256:….
2. Maintainers can see locally what an update would change. scripts/check_upstream.py, standard-library Python. It reads the GitHub and Docker Hub APIs, dereferences annotated tags, reads the go directive from both go.mod files, and chooses Go and Alpine patches. It stops with an error if a pinned release tag now points to a different commit.
3. New upstream releases and base-image patches turn into a ready-to-review pull request, tested before it is opened. Stale images get a monthly rebuild. update.yml, weekly plus manual dispatch with force_rebuild and rebuild_if_older_than_days inputs. It builds linux/amd64 and runs test/smoke.sh, then opens a PR on update/versions with peter-evans/create-pull-request. PRs opened with the default GITHUB_TOKEN do not run the normal PR build, which is why the build runs inline. An optional UPDATE_PR_TOKEN secret enables the normal checks too.
4. Known vulnerabilities in the published image fail a run and show up under the Security tab. scan.yml, weekly, on demand, and after each successful publish from main. Trivy is pinned by commit (v0.36.0). It produces a SARIF upload plus a table that fails on CRITICAL or HIGH findings that have a fix. Trivy reads the Go modules compiled into both binaries, which is the main signal for this image.
5. The README explains what runs when and what a person needs to do. New "Keeping the image up to date" section. "Bumping versions" now points at the script.

Testing

  • I ran the script locally against the current pins. It reports no change: there are no new releases since RELEASE.2026-09-16T00-00-00Z, and golang:1.27.1-alpine3.24 and alpine:3.24.2 are the newest patches. --force-rebuild proposes r2. A one-day age threshold proposes a rebuild, because the published tag is two days old. A moved tag, an unknown repository and a GitHub rate limit each exit non-zero with a clear message.
  • Both workflows ran on this branch from a temporary push trigger. That commit was removed before review, because manual dispatch only works once a workflow file is on main.
  • I could not test the scan's "after every publish" trigger from a branch, because that trigger only fires from the default branch.
  • actionlint reports no issues.

Worth discussing

The runtime stage of the Dockerfile only copies files onto the pinned RUNTIME_IMAGE. It has no package upgrade step. So a time-based rebuild with unchanged pins produces essentially the same image. The rebuilds that change anything are the ones triggered by a newer Go or Alpine patch, which the check detects independently of the image's age. If a rebuild should also pick up Alpine package fixes published between Alpine patch releases, the runtime stage needs apk upgrade. That would require QEMU emulation for the arm64 build. Alternatively, the 30-day rebuild could be dropped.

🤖 Generated with Claude Code

https://claude.ai/code/session_01FA1nFdyB4WmWTw4syt89Yz

mihow and others added 10 commits September 29, 2026 16:27
…they exist

The entrypoint starts the server, waits until it is ready, then creates each
listed bucket and applies its anonymous-access policy. The health check only
passes once that setup has finished, so compose can wait on service_healthy
instead of running a separate init container. Without the variable the server
is exec'd directly, as before.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FA1nFdyB4WmWTw4syt89Yz
scripts/check_upstream.py reads versions.env, looks up the latest server and
client releases on GitHub, the Go and Alpine base-image patches on Docker Hub,
and the age of the published image, and decides whether to bump the pins
(new release) or IMAGE_REVISION (rebuild). It can rewrite versions.env and
write GitHub Actions outputs for an update pull request.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FA1nFdyB4WmWTw4syt89Yz
versions.env gains IMAGE_REVISION. Each published build is tagged
<MINIO_TAG>-r<IMAGE_REVISION> (never overwritten), <MINIO_TAG> and latest.
A run whose revision tag already exists pushes nothing, so rebuilding the
same release needs an explicit revision bump. The run summary pins the
revision tag plus digest, and the README explains how to pin.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FA1nFdyB4WmWTw4syt89Yz
A weekly workflow runs scripts/check_upstream.py. When it proposes new pins
or a rebuild (published image older than 30 days, or newer base-image
patches), the workflow builds linux/amd64, runs the smoke test, and only
then opens a pull request on update/versions. Merging publishes as before.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FA1nFdyB4WmWTw4syt89Yz
Trivy scans insectai/minio:latest, uploads CRITICAL and HIGH findings with a
fix to code scanning, and fails the run when any exist. Trivy reads the Go
modules inside the binaries, which is the main vulnerability signal here.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FA1nFdyB4WmWTw4syt89Yz
Adds "Keeping the image up to date" (what runs when, what a person does,
forcing a rebuild, the optional UPDATE_PR_TOKEN) and points the version-bump
steps at scripts/check_upstream.py.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FA1nFdyB4WmWTw4syt89Yz
…from bot commits

A rebuild of unchanged pins produces the same image because the runtime
stage only copies files onto the pinned Alpine base, so newer Go or Alpine
patch tags are the trigger that matters and the script already detects
them. Bot-authored bump commits no longer carry the session trailer lines.
Also uses upload-sarif v4 and tightens the script's return types.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FA1nFdyB4WmWTw4syt89Yz
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant