rtvkiz/minimal, 137 shell-less container images rebuilt daily, and what the scans do not block
Minimal CVE Hardened container image collection
At a glance
- What is it?
- rtvkiz/minimal is a collection of 137 hardened container images built from readable melange recipes on Wolfi, shell-less where possible, signed with Cosign and rebuilt every day. It is candid about its own limits: scan results are informational, there is no support contract and no compliance accreditation.
- Who is it for?
- rtvkiz/minimal fits a team that wants a small, verifiable, non-root production image for a runtime it actually uses, and that is prepared to pin by digest and absorb the update work. It does not fit an environment that requires a support contract or a compliance accreditation, nor one whose application needs a shell in production.
- Can I use it commercially?
- Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
- Is it still maintained?
- Yes. The repository last received commits 1 day ago.
- What is it written in?
- Mainly Shell, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
137 shell-less images rebuilt every day against Wolfi
rtvkiz/minimal is a collection of 137 hardened container images, and the README states plainly what each one is: small, MIT licensed, signed and rebuilt daily. The homepage is minimalcontainers.com, where the catalog is browsable with live sizes and CVE counts, and the images are published under the ghcr.io/rtvkiz namespace.
The design premise is that a production image should not contain more than the application needs. Production images ship no /bin/sh where the application permits it, and they run as non-root by default. The images are built from source with public, readable melange recipes rather than repackaged from a base image, and both native amd64 and arm64 are produced.
The freshness claim is mechanical rather than aspirational. Images are rebuilt daily against current Wolfi packages, upstream releases and transitive CVEs open their own auto-merging pull requests, so a package security update lands as a pull request in this repository rather than waiting for a human release. There are no GitHub releases for the repository, and the last push was on 2026-10-20.
Who this is for is fairly narrow and fairly clear: teams that want a small image to run in production and would rather not maintain their own base images. What it is not is a compliance product, and the README says that in as many words: no vendor SLA, no support contract, and no FedRAMP, FIPS or STIG accreditation. The signatures, SBOMs and provenance help with verification and audits, and they do not replace those programmes.
Pulling and running an image, and the latest-dev companion
There is no account and no login step. The quick start is a single pull:
docker pull ghcr.io/rtvkiz/minimal-python:latestEvery image also has a :latest-dev companion that ships a shell and a toolchain for debugging and for multi-stage builds. That pairing is the design answer to the usual objection about distroless images, that you cannot get into a running container to find out what is wrong with it. The production image stays shell-less and the debuggable version is a separate tag.
Two run commands show the port mapping pattern, one for a web server and one for a datastore:
docker run --rm -p 8080:80 ghcr.io/rtvkiz/minimal-nginx:latest
docker run --rm -p 6379:6379 ghcr.io/rtvkiz/minimal-redis-slim:latestWhat you should see after the first pull is an image with a very small layer count and no shell, which is the point of the whole exercise. The catalog page linked from the README lists all 137 images with their live sizes and CVE counts, so the practical first step for an evaluation is to find the image you actually need and read its size before pulling it.
The images directory in the repository holds the per-image recipes, and the Makefile at the root is the build system, so the same names you see in the catalog map back to a directory you can read.
Verifying a pull with attestation, signatures and SBOM
Every published image carries a keyless Cosign signature, an SPDX SBOM and SLSA v1.0 build provenance tied to the workflow and commit that produced it. The verification command is part of the quick start, and it is short:
gh attestation verify oci://ghcr.io/rtvkiz/minimal-python:latest --owner rtvkizThe owner flag is what scopes the check to the publisher, so the command answers two questions at once: is this image signed, and was it signed by rtvkiz. The repository carries a .github directory with a SECURITY.md that holds the signature, SBOM and provenance commands for the other artefacts.
The SLSA badge in the README marks the build as L2, and the architecture badge lists amd64 and arm64. The vex/ directory at the top level of the repository is where VEX data lives, and the catalog shows raw and VEX-effective CVE counts side by side, which is the honest way to present a scanner result: some findings are accepted and documented rather than absent.
This is a differentiator in practice, because a great many container images are published with no verifiable provenance at all. The verification here is a single command, and it is documented rather than implied.
Tag semantics that decide whether your deployment drifts
The pinning guidance is short and it matters more than most of the feature lists in similar projects. The README shows two reference forms:
FROM ghcr.io/rtvkiz/minimal-python@sha256:<digest> # immutable
FROM ghcr.io/rtvkiz/minimal-python:3 # patched, no major jumpsThe rule that follows from it: the :latest tag crosses major versions, an exact version tag never moves at all, and the digest form is immutable. A tag such as 3 is a patched stream that stays within a major version without ever moving to a new one.
The reason this matters is the daily rebuild. An image that is rebuilt every day against current Wolfi packages is also an image whose latest tag can change underneath a deployment, and for a container platform that pulls on schedule, that is the mechanism by which a running service silently changes. The tags documentation page is linked from the README for the full scheme, and the catalog shows live sizes and CVE counts per image so a pin can be chosen with information rather than by default.
For a production deployment, the digest is the only form with a fixed meaning. The version tag is a compromise for teams that want security patches without a rebuild of their own manifests.
Green builds, informational scans, and what the CVE counts mean
The vulnerability reporting in this project is unusually candid, and it is the section worth reading before drawing conclusions from the catalog.
Grype scans every production image, and the results are informational: they do not block publication. A green build does not mean zero findings, and the README says that in as many words. The catalog therefore shows raw and VEX-effective counts side by side, and suppressions are reconciled against each fresh scan so that they cannot quietly go stale. A suppression that was justified against an old package is either still justified or gets dropped, which is the failure mode that makes VEX data untrustworthy in projects that skip that reconciliation.
The directory layout backs this up. There is a vex/ directory for the suppression data, a catalog.json at the repository root that the site is built from, an images/ directory holding the recipes, and scripts/ and tools/ directories for the automation around them.
The honest reading of a count on the catalog page is therefore: this is the number of raw findings, this is the number that remain after documented exceptions, and the difference is a decision someone made and then had to re justify. That is more information than most registries give you.
Building an image yourself from the melange recipes
The build system is a Makefile, and the contributions section shows the two paths that exist. The first builds an image with apko only, without compiling from source, and the second builds an image from source with melange:
make python && make test-python # apko-only image
make caddy-melange && make caddy && make test-caddy # source-built imageThe distinction is visible in the Makefile header, which states that the system uses Chainguard melange to build from source and apko to assemble the image, and that all images are shell-less or distroless for security. The two make targets are therefore not two flavours of the same thing, they are two different construction routes, and the test target in each case is what validates the result.
The Makefile also shows how versions are managed. A helper function extracts the version from a melange.yaml and treats it as the single source of truth, and most image versions are read that way, for example REDIS_VERSION, MYSQL_VERSION, KAFKA_VERSION and RUBY_VERSION, while a few are pinned directly in the Makefile, such as NGINX_VERSION 1.29.4 and HTTPD_VERSION 2.4.66. So a recipe file controls its own version and the build follows it, which is what makes the daily rebuild able to pick up upstream changes without a hand edited version bump.
Onboarding for a new image is documented in docs/onboarding.md, which the README calls the complete checklist, and the demand ranked backlog is in docs/roadmap.md. Security issues go through private vulnerability reporting rather than a public issue.
Where these images are the wrong choice
The first wrong case is a compliance requirement. The README states there is no FedRAMP, FIPS or STIG accreditation and no support contract, so if your deployment needs one of those, this collection does not satisfy it and no amount of signature verification will change that.
The second wrong case is an application that needs a shell. Production images here ship no /bin/sh where the application permits it, which is a feature for attack surface and a problem for the many build and debug scripts that assume a shell exists. The :latest-dev companion is the escape hatch, but it is a separate image, and using it in production defeats the design.
The third wrong case is a dependency on a specific base distribution. These images are built on Wolfi packages, so software that is only packaged for Debian or Alpine and not for Wolfi will not be in a recipe, and the build of that image from source is on you.
The fourth wrong case is a team that wants stability from a moving tag. The daily rebuild is a feature for patching, and a liability for reproducibility, and the only fix is pinning by digest and accepting the update work that follows.
The fifth wrong case is expecting a broad catalogue. 137 images covers the common runtimes, and a project needing an unusual stack will find that its image is not in the collection, at which point you are maintaining a recipe yourself.
Editorial conclusion
rtvkiz/minimal fits a team that wants a small, verifiable, non-root production image for a runtime it actually uses, and that is prepared to pin by digest and absorb the update work. It does not fit an environment that requires a support contract or a compliance accreditation, nor one whose application needs a shell in production. Before you adopt it, pull the image you need from ghcr.io/rtvkiz/minimal and run gh attestation verify with the owner flag to confirm the signature and provenance, then read the raw and VEX-effective counts on the catalog page rather than the badge, and decide whether the daily rebuild is a patch channel you want or a source of drift.
Frequently asked questions
How do I pull an image from the rtvkiz/minimal collection?
No account is needed. The quick start is docker pull ghcr.io/rtvkiz/minimal-python:latest, and every image also has a :latest-dev companion that includes a shell and toolchain for debugging and multi-stage builds.
How do I verify that a minimal container image was signed and built from this repository?
Every published image carries a keyless Cosign signature, an SPDX SBOM and SLSA v1.0 build provenance. The verification command is gh attestation verify oci://ghcr.io/rtvkiz/minimal-python:latest --owner rtvkiz, and the .github/SECURITY.md file holds the commands for the other artefacts.
What do the CVE counts on the catalog page mean?
Grype scans every production image and the results are informational, so they do not block publication and a green build does not mean zero findings. The catalog shows raw and VEX-effective counts side by side, with suppressions reconciled against each fresh scan.
How should I pin a minimal image so it does not change underneath my deployment?
The README shows a digest reference, FROM ghcr.io/rtvkiz/minimal-python@sha256:<digest>, as immutable, and notes that the :latest tag crosses major versions while an exact version tag never moves at all. Images are rebuilt daily, so the tag alone is not a fixed reference.
How do I build one of these images locally?
The Makefile offers two routes: make python && make test-python for an apko-only image, and make caddy-melange && make caddy && make test-caddy for a source-built image. Image versions are read from each melange.yaml, which the Makefile treats as the single source of truth.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/rtvkiz-minimal)Was this useful?