No description
  • Dockerfile 100%
Find a file
hayshin 5223c01900
All checks were successful
Build Nix runner image / Build and push nix:latest plus immutable tag (push) Successful in 8m4s
fix(nix): avoid quoted smoke commands
- invoke shell version checks without nested command strings
- keep smoke commands compatible with argument-based Docker execution
2026-07-13 22:27:26 +05:00
.forgejo fix(nix): avoid quoted smoke commands 2026-07-13 22:27:26 +05:00
go chore(docker): add metadata and standardize Dockerfiles 2026-06-06 19:07:24 +05:00
nix fix(nix): expose standard shell paths 2026-07-13 22:17:30 +05:00
pnpm chore(docker): add metadata and standardize Dockerfiles 2026-06-06 19:07:24 +05:00
python chore(docker): add metadata and standardize Dockerfiles 2026-06-06 19:07:24 +05:00
rust chore(docker): add metadata and standardize Dockerfiles 2026-06-06 19:07:24 +05:00
uv chore(docker): add metadata and standardize Dockerfiles 2026-06-06 19:07:24 +05:00
README.md feat(nix): add action lint 2026-07-12 19:48:50 +05:00

Forgejo Actions runner images

This repository builds CI-ready job container images for a self-hosted Forgejo Actions runner at:

https://git.hayshin.dev

The images are published under one package namespace:

git.hayshin.dev/infra/runner-images

Images

Expected tags include both moving convenience tags and immutable commit-pinned tags:

git.hayshin.dev/infra/runner-images/nix:latest
git.hayshin.dev/infra/runner-images/nix:latest-<git-sha>
git.hayshin.dev/infra/runner-images/rust:1
git.hayshin.dev/infra/runner-images/rust:1-<git-sha>
git.hayshin.dev/infra/runner-images/go:1
git.hayshin.dev/infra/runner-images/go:1-<git-sha>
git.hayshin.dev/infra/runner-images/python:3.14
git.hayshin.dev/infra/runner-images/python:3.14-<git-sha>
git.hayshin.dev/infra/runner-images/pnpm:22
git.hayshin.dev/infra/runner-images/pnpm:22-<git-sha>
git.hayshin.dev/infra/runner-images/uv:latest
git.hayshin.dev/infra/runner-images/uv:latest-<git-sha>

Use the immutable -<git-sha> tags for runner labels after testing. The moving tags are retained for manual convenience and discovery only.

Each image includes:

  • Node.js 22
  • git
  • bash
  • ca-certificates
  • coreutils and common POSIX tools
  • curl
  • the target toolchain

The Debian-based images install and verify Node.js 22.22.2. The nix image installs nodejs_22, devenv, actionlint, action-validator, and yamllint from the pinned nixpkgs revision and verifies the resulting Node.js version, currently v22.22.3.

The language bases are upstream images:

  • nix uses nixos/nix:2.24.11@sha256:4bfe741027f0bfbef745862cbf3b5f424ee99801c04138146c0000a28759636d
  • rust uses rust:1-bookworm
  • go uses golang:1-bookworm
  • python uses python:3.14-bookworm
  • pnpm uses node:22.22.2-bookworm@sha256:62e4daa6819762bbd3072af77cc282ab72c631c4aed30dd7980192babaf385b3
  • uv uses astral/uv:python3.14-bookworm

Runtime user

All images intentionally run as root by default. These are CI job-container images for Forgejo Actions/act, where workflows commonly need to install OS packages, populate language/tool caches, or write to workspace-mounted paths without extra permission setup.

Treat workflow code as trusted, prefer immutable -<git-sha> runner labels, and avoid using these images as general-purpose application runtime bases. If a specific job does not need elevated permissions, override the user at run time or create a derived image with a non-root user.

Why Node is included

Forgejo Actions is compatible with the GitHub Actions model and, through act, runs JavaScript actions inside the job container. A workflow step such as:

- uses: actions/checkout@v4

does not run as a shell script. It runs the bundled JavaScript action with Node, roughly equivalent to:

node dist/index.js

That means every job image intended for normal Actions workflows needs Node available in the container. Raw language images such as rust:1-bookworm, golang:1-bookworm, and python:3.14-bookworm are useful for simple run: steps, but they can fail as soon as a JavaScript action is used.

Build locally

Build all images with moving and immutable tags:

SHA=$(git rev-parse HEAD)
docker build -t git.hayshin.dev/infra/runner-images/nix:latest -t git.hayshin.dev/infra/runner-images/nix:latest-$SHA nix
docker build -t git.hayshin.dev/infra/runner-images/rust:1 -t git.hayshin.dev/infra/runner-images/rust:1-$SHA rust
docker build -t git.hayshin.dev/infra/runner-images/go:1 -t git.hayshin.dev/infra/runner-images/go:1-$SHA go
docker build -t git.hayshin.dev/infra/runner-images/python:3.14 -t git.hayshin.dev/infra/runner-images/python:3.14-$SHA python
docker build -t git.hayshin.dev/infra/runner-images/pnpm:22 -t git.hayshin.dev/infra/runner-images/pnpm:22-$SHA pnpm
docker build -t git.hayshin.dev/infra/runner-images/uv:latest -t git.hayshin.dev/infra/runner-images/uv:latest-$SHA uv

Quick checks:

docker run --rm git.hayshin.dev/infra/runner-images/nix:latest node --version
docker run --rm git.hayshin.dev/infra/runner-images/nix:latest devenv --version
docker run --rm git.hayshin.dev/infra/runner-images/rust:1 rustc --version
docker run --rm git.hayshin.dev/infra/runner-images/go:1 go version
docker run --rm git.hayshin.dev/infra/runner-images/python:3.14 python --version
docker run --rm git.hayshin.dev/infra/runner-images/pnpm:22 pnpm --version
docker run --rm git.hayshin.dev/infra/runner-images/uv:latest uv --version

Push manually

Log in to the Forgejo package registry:

docker login git.hayshin.dev

Push all tags:

SHA=$(git rev-parse HEAD)
docker push git.hayshin.dev/infra/runner-images/nix:latest
docker push git.hayshin.dev/infra/runner-images/nix:latest-$SHA
docker push git.hayshin.dev/infra/runner-images/rust:1
docker push git.hayshin.dev/infra/runner-images/rust:1-$SHA
docker push git.hayshin.dev/infra/runner-images/go:1
docker push git.hayshin.dev/infra/runner-images/go:1-$SHA
docker push git.hayshin.dev/infra/runner-images/python:3.14
docker push git.hayshin.dev/infra/runner-images/python:3.14-$SHA
docker push git.hayshin.dev/infra/runner-images/pnpm:22
docker push git.hayshin.dev/infra/runner-images/pnpm:22-$SHA
docker push git.hayshin.dev/infra/runner-images/uv:latest
docker push git.hayshin.dev/infra/runner-images/uv:latest-$SHA

Use a Forgejo user and a token with package write access if password login is disabled.

CI workflows

Each image has its own Forgejo workflow, scoped to its image folder:

.forgejo/workflows/build-nix.yml
.forgejo/workflows/build-rust.yml
.forgejo/workflows/build-go.yml
.forgejo/workflows/build-python.yml
.forgejo/workflows/build-pnpm.yml
.forgejo/workflows/build-uv.yml

On pushes to main, each workflow runs only when its Dockerfile folder or workflow file changes. Each workflow can also be started manually with workflow_dispatch.

The jobs use:

runs-on: ubuntu-latest

That runner label must resolve to an act-compatible image with Docker access and Node installed, because the workflows use actions/checkout@v4.

Create repository secrets for registry push access:

REGISTRY_USER
REGISTRY_TOKEN

REGISTRY_TOKEN should be a Forgejo token that can push packages to infra/runner-images.

Each workflow pushes both the moving tag configured in IMAGE and an immutable tag formed as ${IMAGE}-${GITHUB_SHA}.

The workflows also set OCI metadata using Forgejo/Gitea-compatible environment variables:

GITHUB_SERVER_URL
GITHUB_REPOSITORY
GITHUB_SHA
GITHUB_REF_NAME

Runner labels

After the images are published and tested, configure the Forgejo runner labels in NixOS with immutable tags like this:

[
  "nix:docker://git.hayshin.dev/infra/runner-images/nix:latest-<tested-sha>"
  "rust:docker://git.hayshin.dev/infra/runner-images/rust:1-<tested-sha>"
  "go:docker://git.hayshin.dev/infra/runner-images/go:1-<tested-sha>"
  "python-3.14:docker://git.hayshin.dev/infra/runner-images/python:3.14-<tested-sha>"
  "pnpm:docker://git.hayshin.dev/infra/runner-images/pnpm:22-<tested-sha>"
  "uv:docker://git.hayshin.dev/infra/runner-images/uv:latest-<tested-sha>"
]

Workflows can then target the labels directly:

jobs:
  test:
    runs-on: rust
    steps:
      - uses: actions/checkout@v4
      - run: rustc --version