Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -77,15 +77,28 @@ jobs:
- name: Docker metadata
id: docker_meta
uses: docker/metadata-action@v6
env:
DOCKER_METADATA_ANNOTATIONS_LEVELS: manifest,index
with:
images: ${{ steps.image.outputs.name }}
tags: |
type=raw,value=${{ steps.meta.outputs.version }}
labels: |
org.opencontainers.image.title=${{ steps.meta.outputs.name }}
org.opencontainers.image.description=${{ steps.meta.outputs.description }}
org.opencontainers.image.version=${{ steps.meta.outputs.version }}
org.opencontainers.image.source=https://github.com/${{ github.repository }}
org.opencontainers.image.revision=${{ github.sha }}
org.opencontainers.image.documentation=https://github.com/${{ github.repository }}/tree/${{ github.sha }}/images/${{ steps.tag.outputs.tool }}
org.opencontainers.image.licenses=${{ steps.meta.outputs.license }}
annotations: |
org.opencontainers.image.title=${{ steps.meta.outputs.name }}
org.opencontainers.image.description=${{ steps.meta.outputs.description }}
org.opencontainers.image.version=${{ steps.meta.outputs.version }}
org.opencontainers.image.source=https://github.com/${{ steps.meta.outputs.upstream }}
org.opencontainers.image.source=https://github.com/${{ github.repository }}
org.opencontainers.image.revision=${{ github.sha }}
org.opencontainers.image.documentation=https://github.com/${{ github.repository }}/tree/${{ github.sha }}/images/${{ steps.tag.outputs.tool }}
org.opencontainers.image.licenses=${{ steps.meta.outputs.license }}

- name: Build and push
id: build
Expand All @@ -97,6 +110,7 @@ jobs:
push: true
tags: ${{ steps.docker_meta.outputs.tags }}
labels: ${{ steps.docker_meta.outputs.labels }}
annotations: ${{ steps.docker_meta.outputs.annotations }}
build-args: |
VERSION=${{ steps.meta.outputs.version }}
REVISION=${{ github.sha }}
Expand Down
27 changes: 18 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
# Tiny Images
# Tiny CLI Images — Minimal Docker and OCI Images

Minimal OCI images for useful command-line tools.
Minimal, secure, multi-architecture Docker and OCI container images for useful
command-line tools. Images are published to GitHub Container Registry (GHCR)
for `linux/amd64` and `linux/arm64`. Release images run as non-root, include
SBOM and provenance attestations, and are signed with Sigstore.

## Principles

Expand All @@ -15,14 +18,17 @@ Minimal OCI images for useful command-line tools.
- Immutable version tags
- No unnecessary shell or package manager

## Images
## Container image catalog

| Image | amd64 | arm64 | Runtime |
|---|---|---|---|
| age | | | scratch |
| xh | | | scratch |
| Tool | Container image | Purpose | Platforms | Runtime |
|---|---|---|---|---|
| [age](images/age/README.md) | `ghcr.io/unitmatrix/age` | File encryption | amd64, arm64 | scratch |
| [xh](images/xh/README.md) | `ghcr.io/unitmatrix/xh` | HTTP client | amd64, arm64 | scratch |

## age
## age encryption container image

The age image packages the [age encryption tool](https://github.com/FiloSottile/age)
in a minimal, non-root container without a shell or package manager.

<!-- tiny-cli-images:version:age:start -->

Expand All @@ -35,7 +41,10 @@ docker run --rm ghcr.io/unitmatrix/age:1.3.1 --version
See [the age image documentation](images/age/README.md) for usage and release
details.

## xh
## xh HTTP client container image

The xh image packages the [xh HTTP client](https://github.com/ducaale/xh) in a
minimal, non-root container with CA certificates for HTTPS requests.

<!-- tiny-cli-images:version:xh:start -->

Expand Down
6 changes: 4 additions & 2 deletions docs/PROJECT.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,8 +108,10 @@ entrypoint. The final image uses `scratch` and runs as UID/GID `65532:65532`.
## Metadata and updates

`scripts/meta.py` reads `images/<tool>/image.toml` and exposes the name,
version, upstream repository, platform targets, and checksums to GitHub
Actions.
description, version, upstream repository, license, platform targets, and
checksums to GitHub Actions. Release builds publish this metadata as OCI labels
and as manifest and image-index annotations so multi-architecture GHCR package
pages display the image description and link back to this repository.

`scripts/update.py <tool> <version>` queries the GitHub Releases API, rejects
missing, draft, or prerelease releases, requires both expected platform
Expand Down
5 changes: 3 additions & 2 deletions images/age/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,11 @@ ARG REVISION
COPY --from=fetch /rootfs /

LABEL org.opencontainers.image.title="age"
LABEL org.opencontainers.image.description="Minimal OCI image for age"
LABEL org.opencontainers.image.description="Minimal, multi-architecture OCI container image for age file encryption"
LABEL org.opencontainers.image.version="${VERSION}"
LABEL org.opencontainers.image.revision="${REVISION}"
LABEL org.opencontainers.image.source="https://github.com/FiloSottile/age"
LABEL org.opencontainers.image.source="https://github.com/unitmatrix/tiny-cli-images"
LABEL org.opencontainers.image.documentation="https://github.com/unitmatrix/tiny-cli-images/tree/main/images/age"
LABEL org.opencontainers.image.licenses="BSD-3-Clause"

USER 65532:65532
Expand Down
8 changes: 5 additions & 3 deletions images/age/README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
# age OCI image
# age Docker and OCI container image

This image packages the upstream [FiloSottile/age](https://github.com/FiloSottile/age)
static Linux binaries in a minimal `scratch` runtime.
Minimal, non-root, multi-architecture container image for
[age](https://github.com/FiloSottile/age), a simple, modern, and secure file
encryption tool. The image packages the upstream static Linux binaries in a
`scratch` runtime and is published as `ghcr.io/unitmatrix/age`.

## Usage

Expand Down
2 changes: 1 addition & 1 deletion images/age/image.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name = "age"
description = "Simple, modern, and secure file encryption"
description = "Minimal, multi-architecture OCI container image for age file encryption"
version = "1.3.1"

upstream = "FiloSottile/age"
Expand Down
5 changes: 3 additions & 2 deletions images/xh/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,11 @@ ARG REVISION
COPY --from=fetch /rootfs /

LABEL org.opencontainers.image.title="xh"
LABEL org.opencontainers.image.description="Minimal OCI image for xh"
LABEL org.opencontainers.image.description="Minimal, multi-architecture OCI container image for xh, the friendly HTTP client"
LABEL org.opencontainers.image.version="${VERSION}"
LABEL org.opencontainers.image.revision="${REVISION}"
LABEL org.opencontainers.image.source="https://github.com/ducaale/xh"
LABEL org.opencontainers.image.source="https://github.com/unitmatrix/tiny-cli-images"
LABEL org.opencontainers.image.documentation="https://github.com/unitmatrix/tiny-cli-images/tree/main/images/xh"
LABEL org.opencontainers.image.licenses="MIT"

USER 65532:65532
Expand Down
8 changes: 5 additions & 3 deletions images/xh/README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
# xh OCI image
# xh Docker and OCI container image

This image packages the upstream [ducaale/xh](https://github.com/ducaale/xh)
Linux musl binary in a minimal `scratch` runtime.
Minimal, non-root, multi-architecture container image for
[xh](https://github.com/ducaale/xh), a friendly and fast HTTP client. The image
packages the upstream Linux musl binary in a `scratch` runtime with CA
certificates and is published as `ghcr.io/unitmatrix/xh`.

## Usage

Expand Down
2 changes: 1 addition & 1 deletion images/xh/image.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name = "xh"
description = "Friendly and fast tool for sending HTTP requests"
description = "Minimal, multi-architecture OCI container image for xh, the friendly HTTP client"
version = "0.26.2"

upstream = "ducaale/xh"
Expand Down
10 changes: 10 additions & 0 deletions scripts/meta.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ def load_config(image: str) -> dict[str, Any]:


def metadata(config: dict[str, Any]) -> dict[str, str]:
description = config.get("description")
if not isinstance(description, str) or not description or "\n" in description:
fail("manifest description must be a non-empty single-line string")

version = config.get("version")
if not isinstance(version, str):
fail("manifest version must be a string")
Expand All @@ -56,10 +60,16 @@ def metadata(config: dict[str, Any]) -> dict[str, str]:
if config.get("architectures") != list(ARCHITECTURES):
fail("manifest must declare amd64 and arm64 in that order")

license_name = config.get("license")
if not isinstance(license_name, str) or not license_name or "\n" in license_name:
fail("manifest license must be a non-empty single-line string")

values = {
"name": config["name"],
"description": description,
"version": version,
"upstream": upstream,
"license": license_name,
}

platforms = config.get("platform")
Expand Down