Skip to content
unmangoPublic

About

Blessed GitHub Actions

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

actions

Blessed GitHub Actions.

CI Test Podman Actions License Nix flake Last commit Hercules CI

Composite actions and reusable workflows shared across my repos. The podman actions mirror the docker/* action interfaces so a workflow can swap between them with minimal changes.

Actions

Action Purpose Docker counterpart
podman-build-push Build and optionally push an image with podman, with multi-arch, cache, and SBOM support docker/build-push-action
podman-push Tag and push an image or manifest list already in podman's store, such as one loaded from a Nix build docker/build-push-action with push only
podman-manifest Create a manifest list from existing registry images and push it to several tags docker buildx imagetools create
podman-login Log into a container registry with podman, with ECR auto-detection docker/login-action
setup-qemu Register QEMU binfmt emulators via tonistiigi/binfmt for cross-platform builds docker/setup-qemu-action
setup-nix Install Nix and configure Cachix none
setup-podman Install or upgrade podman, crun, and skopeo from the Ubuntu archive none

Reusable workflows

Workflow Purpose
docker-build-push.yml Build and push with buildx, tagged by docker/metadata-action
podman-build-push.yml Same interface as above, built with podman
release-please.yml Open release PRs and tag releases with release-please

Each reusable workflow takes a runs-on input (default ubuntu-latest) for callers on self-hosted runners.

Usage

Releases are tagged vX.Y.Z and a floating vX tag tracks the latest release of each major version. The examples use @main for brevity; pin to @v1 for the floating major tag, or to @v1.2.3 or a full commit SHA for an exact version. setup-qemu registers binfmt_misc handlers with sudo podman run --privileged, so it needs sudo and a rootful podman. GitHub-hosted Ubuntu runners meet both requirements. podman-build-push builds from the git repository at the current commit when context is empty, so it needs no checkout; pass context: . to build the checked-out workspace instead.

Composite actions

permissions:
  contents: read
  packages: write

steps:
  - uses: actions/checkout@v4

  - uses: unmango/actions/setup-qemu@main

  - uses: unmango/actions/podman-login@main
    with:
      registry: ghcr.io
      username: ${{ github.actor }}
      password: ${{ github.token }}

  - uses: unmango/actions/podman-build-push@main
    with:
      context: .
      platforms: linux/amd64,linux/arm64
      push: 'true'
      tags: ghcr.io/${{ github.repository }}:latest

setup-nix

steps:
  - uses: actions/checkout@v4

  - uses: unmango/actions/setup-nix@main
    with:
      cachix_auth_token: ${{ secrets.CACHIX_AUTH_TOKEN }}
Input Default Purpose
install_nix true false skips the install on runners with Nix preinstalled and adds ~/.nix-profile/bin to PATH
github_access_token github.token Token for authenticated GitHub fetches by Nix
cachix_name unstoppablemango Cachix cache to pull from, and push to when a token is set; '' installs Nix without Cachix
cachix_auth_token Cachix token; without it the cache is pull-only
extra_pull_names Comma-separated read-only Cachix caches, e.g. mangopkgs,unmango
extra_nix_config Extra lines for nix.conf
use_daemon true Push through the Cachix daemon; false scans the store at job end
skip_push false Pull-only, even with cachix_auth_token set
magic_nix_cache false Run DeterminateSystems/magic-nix-cache-action between the install and Cachix

Build cache on GitHub-hosted runners

docker/build-push-action's type=gha cache has no podman equivalent. A registry cache works instead: podman pushes each built layer to a cache repository and pulls matching layers on the next build.

permissions:
  contents: read
  packages: write

steps:
  - uses: unmango/actions/podman-login@main
    with:
      registry: ghcr.io
      username: ${{ github.actor }}
      password: ${{ github.token }}

  - uses: unmango/actions/podman-build-push@main
    with:
      tags: ghcr.io/${{ github.repository }}:latest
      cache-from: ghcr.io/${{ github.repository }}/cache
      # Pull requests read the cache but do not write to it.
      cache-to: ${{ github.event_name != 'pull_request' && format('ghcr.io/{0}/cache', github.repository) || '' }}

Either input makes podman build with --layers. The cache repository is a separate GHCR package; give it the same visibility as the image.

Reusable workflow

permissions:
  contents: read
  packages: write

jobs:
  image:
    uses: unmango/actions/.github/workflows/podman-build-push.yml@main
    with:
      image: ghcr.io/${{ github.repository }}
      platforms: linux/amd64,linux/arm64
      push: ${{ github.event_name != 'pull_request' }}
      sbom: ${{ github.event_name != 'pull_request' }}
    secrets:
      dockerhub_token: ${{ secrets.DOCKERHUB_TOKEN }}

Versioning a container repo

release-please.yml runs release-please in simple mode. It opens a release PR from Conventional Commits, maintains version.txt and CHANGELOG.md, and on merge creates a vX.Y.Z tag and GitHub release. The tag push runs the build-push workflow, and docker/metadata-action derives the image tags 1.2.3, 1.2, 1, and latest from it.

The workflow needs credentials with contents, pull-requests, and issues write. With an app token or PAT, the caller can set permissions: {}; only the GITHUB_TOKEN fallback needs the caller to grant contents and pull-requests write. issues write covers the autorelease labels release-please puts on its PRs. Tags created with the default GITHUB_TOKEN do not trigger other workflows, so the image build would never run.

Pass a GitHub App through the app-client-id input and the app-private-key secret, and the workflow mints a token from them. A personal access token in the token secret is the alternative when app-client-id is empty. An app token does not act as a person and does not expire, which is the reason to prefer it over a PAT. release-please writes through the GitHub API, so its commits are signed with either token.

# .github/workflows/release-please.yml
on:
  push:
    branches: [main]

permissions: {}

jobs:
  release:
    uses: unmango/actions/.github/workflows/release-please.yml@main
    with:
      app-client-id: ${{ vars.RELEASE_APP_CLIENT_ID }}
    secrets:
      app-private-key: ${{ secrets.RELEASE_APP_PRIVATE_KEY }}
# .github/workflows/image.yml
on:
  pull_request:
  push:
    branches: [main]
    tags: ['v*']

permissions:
  contents: read
  packages: write

jobs:
  image:
    uses: unmango/actions/.github/workflows/podman-build-push.yml@main
    with:
      image: ghcr.io/${{ github.repository }}
      push: ${{ github.event_name != 'pull_request' }}
Event Image tags
Pull request pr-N
Push to main main, sha-<short>
Tag v1.2.3 1.2.3, 1.2, 1, latest, sha-<short>

Pass config-file and manifest-file to use a release-please-config.json instead of the simple defaults. The workflow exposes release_created, tag_name, version, major, minor, patch, and sha as outputs for jobs that need to run only after a release. prs_created and pr (JSON, e.g. fromJSON(needs.release.outputs.pr).headBranchName) serve jobs that push to the release PR branch, and paths_released lists released package paths in manifest mode.

Feature support matrix

✅ supported · ⚠️ accepted for interface parity but ignored · ❌ not available

podman-build-push vs docker/build-push-action

Input Podman Docker Notes
context ✅ ✅ Empty builds from <repo>.git#<sha> like buildx; pass . to build the checkout. #ref:subdir URLs are not supported by podman 5.8
file ✅ ✅
platforms ✅ ✅ Multiple platforms build a manifest list; run setup-qemu first
tags ✅ ✅
target ✅ ✅
labels ✅ ✅
annotations ✅ ✅
build-args ✅ ✅
build-contexts ✅ ✅
secrets ✅ ✅ Podman takes the id=id,src=path form only
no-cache ✅ ✅
cache-from ✅ ✅ Podman takes a single registry ref or local directory, not buildx type=... syntax, and forces --layers; see Build cache on GitHub-hosted runners
cache-to ✅ ✅ Same as cache-from
pull ✅ ✅
network ✅ ✅
add-hosts ✅ ✅
cgroup-parent ✅ ✅
shm-size ✅ ✅
ulimit ✅ ✅
push ✅ ✅
load ✅ ✅ Named docker-load, since podman load imports in the opposite direction; single-platform only
archive ✅ ❌ Writes a docker-archive tarball of all tags, for kind load image-archive; single-platform only
sbom ✅ ✅ Podman requires push and needs syft and cosign on the runner
provenance ⚠️ ✅ No native SLSA provenance generation in buildah or podman
ssh ⚠️ ✅ No buildkit SSH agent forwarding equivalent
no-cache-filters ⚠️ ✅ buildah cache invalidation is all-or-nothing
allow ⚠️ ✅ No buildkit entitlement model
attests ❌ ✅
builder ❌ ✅
call ❌ ✅
outputs ❌ ✅ archive covers type=docker,dest=<path>
secret-envs ❌ ✅
secret-files ❌ ✅ Use secrets
github-token ✅ ✅ Authenticates the git context clone
Output Podman Docker Notes
imageid ✅ ✅
digest ✅ ✅ Podman only sets it when push is true
metadata ✅ ✅ Podman emits containerimage.imageid, containerimage.digest, and image.tags, a subset of the buildx shape

Podman boolean inputs are strings ('true' and 'false') because composite actions have no typed inputs.

podman-login vs docker/login-action

Input Podman Docker Notes
registry ✅ ✅
username ✅ ✅
password ✅ ✅
ecr ✅ ✅ auto, true, or false; needs aws-actions/configure-aws-credentials first
logout ⚠️ ✅ Composite actions have no post-job hook; no warning is logged

setup-qemu vs docker/setup-qemu-action

Input Podman Docker Notes
platforms ✅ ✅
image ✅ ✅
cache-image ❌ ✅
cache-binary ❌ ✅

podman-build-push.yml vs docker-build-push.yml

Input Podman Docker Notes
image ✅ ✅
runs-on ✅ ✅ Runner label, default ubuntu-latest
platforms ✅ ✅ Podman runs setup-qemu when more than one platform is listed
push ✅ ✅
build-args ✅ ✅
file ✅ ✅
context ✅ ✅
dockerhub_token (secret) ✅ ✅
secrets-list ✅ ❌ Build secrets in id=id,src=path form
cache ✅ ❌ none, registry, or local; docker always uses the GHA cache backend
cache-image ✅ ❌ Registry ref used when cache is registry
cache-dir ✅ ❌ Directory used when cache is local, persisted with actions/cache
sbom ✅ ❌ Docker always attaches an SBOM when pushing; podman installs syft and cosign and attaches an SPDX SBOM on request
provenance ⚠️ ❌ Docker always generates provenance when pushing; podman accepts the input and ignores it

Development

Enter the dev shell with nix develop, or let direnv load it from .envrc.

make check   # nix flake check, includes actionlint
make fmt     # nix fmt

About

Blessed GitHub Actions

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages