- Dockerfile 83.1%
- HCL 16.9%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
|
All checks were successful
Build / Build Builder (push) Successful in 7m39s
Reviewed-on: #10 |
||
| .github/workflows | ||
| fs/root/.ssh | ||
| .gitignore | ||
| compose.yml | ||
| docker-bake.hcl | ||
| Dockerfile | ||
| README.md | ||
Github-Actions-Runner (GHAR)
The house runner image for Forgejo Actions at git.grey.ooo. Jobs reference it through an
explicit container: key rather than relying on whatever the runner host happens to have, so
what is in this image is what CI can call.
jobs:
build:
runs-on: docker
container:
image: ghcr.io/matthewbaggett/act-runner:php8.4
Where to pull it from
| Registry | Reference |
|---|---|
| GHCR (prefer this) | ghcr.io/matthewbaggett/act-runner:php<version> |
| Docker Hub | matthewbaggett/act-runner:php<version> |
Both registries get every tag on every publish. Pull from GHCR anyway: Docker Hub rate-limits
anonymous pulls at roughly 100/6h per IP, and the Forgejo runners pull with force_pull on
every job, which has exhausted that quota and broken every job at the setup step.
Tags are php7.4, php8.1, php8.2, php8.3, php8.4, php8.5, plus latest as an alias
for the current default (PHP_VERSION_CURRENT in docker-bake.hcl, today 8.4).
main publishes linux/amd64 and linux/arm64; branch and PR builds are amd64-only to keep
them quick.
What's in it
Alpine-based, on top of matthewbaggett/php:<version>.
| Area | Tools |
|---|---|
| PHP | php (7.4–8.5 per tag) with xdebug, composer |
| Forge CLIs | tea (Gitea/Forgejo), gh (GitHub — read the caveat below) |
| Containers | docker, docker compose, docker buildx |
| Languages | go, node, npm, yarn |
| Infra | tofu (OpenTofu), aws, eksctl, aws-iam-authenticator |
| Data | psql, mysql, sqlite3, redis-cli |
| Text/JSON | jq, yq, rg (ripgrep), grep, sed, awk |
| General | git, ssh, curl, wget, rsync, make, g++, openssl, gpg, nmap, xorriso, nginx |
git.grey.ooo's host key is pre-seeded in /root/.ssh/known_hosts (port 222) so git-over-ssh
works without an interactive prompt.
gh is present, and that is not a licence to use it
gh is installed because some repos built by this image genuinely live on github.com.
It is banned outright in Grey.ooo/Someones.Computer, and in any other repo whose GitHub
side is a read-only mirror. For those, Forgejo is canonical: code, issues, PRs and CI all
live at git.grey.ooo, mirrored CI does not run on GitHub, and gh will happily report stale
or absent state without saying so. That failure is silent, which is why the rule there is "not
even read-only". Use tea instead — it is in this image for exactly that reason.
If you are unsure which kind of repo you are in, check its CLAUDE.md/contributing docs before
reaching for gh.
What is deliberately not in it
hadolint, markdownlint and actionlint are intentionally absent. Consumers run those as
pinned docker images (see bin/lint-*.sh in Someones.Computer) so that CI and a laptop
execute byte-identical versions. Installing them here would silently break that guarantee by
giving CI a different build from the one a developer runs. The same reasoning covers dive and
the Playwright image.
Adding a linter to this image is therefore a regression, not a convenience — don't.
Adding a tool
Size is a real constraint: the runners force_pull this image on every job on a shared,
serialised x86_64 worker, so every megabyte is paid repeatedly.
- Prefer a single static binary from the upstream release over a package-manager install
that drags in a dependency tree. Alpine is musl — check the binary is musl-compatible or
statically linked (Go and Rust-musl builds are fine; glibc-only builds are not, which is why
session-manager-pluginis absent). - Pin the version as an
ARGnext to theRUNblock that consumes it, so a bump is a one-line diff rather than silent drift. Current pins:TOFU_VERSION,EKSCTL_VERSION,AWS_IAM_AUTHENTICATOR_VERSION,TEA_VERSION,GH_VERSION,RIPGREP_VERSION. - Verify the checksum against the upstream checksums file. Every existing block does.
- Clean up the download. Fetch into a
mktemp -dwithtrap 'rm -rf "$WORK"' EXITand extract only the binary you need. Archives left in/tmpare shipped and re-pulled forever — this cost the image ~100 MiB before it was noticed. - Cover both arches.
mainbuilds amd64 and arm64; a block that only handles one will fail the multi-arch publish even though the PR build passed. - Run the tool once inside the block (
tea --version) so a bad download fails the build rather than the job that needs it.
Building locally
docker buildx bake # every PHP variant, amd64
docker build --target runner \
--build-arg PHP_VERSION=8.5 -t ghar . # one variant, quick
docker run --rm -i hadolint/hadolint hadolint - < Dockerfile
Publishing happens from .github/workflows/build.yml on pushes to main only. The workflow
deliberately does not run inside this image — that would make the build depend on its own
output and break the moment a tag is missing or unpullable.