No description
  • Go Template 73.5%
  • Dockerfile 26.5%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-09-18 22:30:42 +02:00
.forgejo/workflows build: run on debian-latest and prune old dated tags (#2) 2026-09-18 20:49:59 +02:00
debian-ci debian-ci: consolidate the per-stack images into one (#1) 2026-09-18 19:50:03 +02:00
docs/superpowers docs: Fix stale uv/bun references and runner-config description 2026-05-07 13:10:29 +02:00
runner runner: drop the deprecated debian-trixie-<stack> alias labels (#4) 2026-09-18 22:30:42 +02:00
README.md runner: drop the deprecated debian-trixie-<stack> alias labels (#4) 2026-09-18 22:30:42 +02:00

CI Images

One Debian-based CI runner image for cross-company use: debian-ci, a single Containerfile with every toolchain pre-installed.

The image

git.kristofferopsahl.com/kristofferopsahl/debian-ci, built FROM debian:trixie-slim.

Everything is installed from Debian trixie's apt — no upstream tarballs, no third-party repos, no version managers. Versions are whatever trixie ships:

  • Common: ca-certificates, curl, wget, git, git-lfs, openssh-client, rsync, sudo, gnupg, locales, file, procps, xz-utils, zstd, unzip, zip, jq.
  • C / C++: build-essential (gcc/g++/make), clang, cmake, ninja-build, pkg-config, autoconf, automake, libtool, libssl-dev.
  • Node: Node 20 + npm (also what JS-based actions like actions/checkout run on).
  • Go: Go 1.24.
  • Elixir: Elixir 1.18 + Erlang/OTP 27 + inotify-tools.
  • Python: Python 3.13 + venv + pip + headers. python symlinked to python3.
  • Java: Java 21 (default-jdk-headless) + Maven.
  • Rust: Rust + Cargo (~1.85) + rustfmt + clippy.
  • PHP: PHP 8.4 + Composer + common extensions (mbstring, xml, curl, mysql, pgsql, zip, intl, bcmath, gd, sqlite3).
  • Database clients: postgresql-client, default-mysql-client (MariaDB), sqlite3.

Runner labels

runs-on: Image
debian-latest debian-ci:latest
debian-13 debian-ci:latest — pins the Debian release; use it if a workflow must not move to Debian 14 when debian-latest does
debian-trixie, debian-trixie-slim upstream docker.io/library/debian:trixie[-slim] passthroughs (configured in the runner, not built here). Unused day to day; kept as the recovery path for rebuilding a broken debian-ci

Usage in downstream workflows

jobs:
  test:
    runs-on: debian-latest
    steps:
      - uses: actions/checkout@v4
      - run: mix test

Adding a tool

Add the apt package to debian-ci/Containerfile and a version check to the smoke-test RUN at the bottom. Commit and push to main. No runner change is needed — the labels already point at debian-ci:latest.

If a tool isn't in trixie's apt, it doesn't go in the image; install it in the workflow that needs it.

Provisioning a runner host

See runner/README.md — pure cloud-init bootstrap from a fresh Debian 13 cloud image, no snapshot needed.

Versioning

Versions follow Debian trixie's apt cadence. Weekly cron rebuild picks up Debian security updates.

Each build pushes two tags: :latest, which the runner labels use, and a dated :YYYY-MM-DD. The final RUN in the Containerfile is a smoke test, so a build with a broken toolchain fails before anything is pushed. If a pushed :latest still misbehaves, roll back by pointing the labels in the runner's config.yaml at the last good dated tag and restarting the runner.

The build prunes after pushing: it keeps the two newest dated tags (the current build plus one rollback target) and deletes older ones, because the Forgejo box is small and every rebuild is ~1 GB of new layers. REGISTRY_TOKEN therefore needs write:package.

Reproducibility for project code is handled by actions/cache@v4 keyed on the lockfile in downstream workflows.

Image build cycle

  • On push to main when debian-ci/Containerfile or the build workflow changes.
  • On pull request touching the same files — build and smoke test only, no push.
  • Weekly Monday 04:00 UTC.
  • Manual via Forgejo workflow dispatch.

The build job runs on debian-latest — the image builds itself. The smoke test gates the push; if a pushed image still can't run the build, point the runner's debian-latest label at the last good dated tag, or temporarily set the job's runs-on: to debian-trixie-slim, and rebuild.