Gehostetes Runner-Image
Workflows mit runs-on: fremforge laufen auf einer kurzlebigen VM, einer pro Commit, die aus dem gehosteten Runner-Image bereitgestellt wird. Es ist auf Gleichstand mit ubuntu-latest ausgelegt: dieselbe actions/setup-*-Bedienung wie bei GitHub Actions, dieselben eingebackenen Toolchains, dieselben Scanner und dazu natives Docker für Container-Builds.
Zweischichtige Architektur
Das Runner-Image ist die Boot-Disk der VM – beide Schichten liegen auf derselben Disk und sind ab dem Booten der VM vorhanden, ohne Download pro Job.
| Schicht | Inhalt | Größe |
|---|---|---|
| Systemschicht | Debian-13-Basis + Systemwerkzeuge in jeweils einer Version (Node 24 LTS, Build-Essentials, Scanner, IaC- und Cloud-CLIs, Browser, DB-Clients, nativer Docker-Daemon) | ~300 MB |
| hostedtoolcache-Schicht | Sprach-Runtimes in mehreren Versionen (Node, Go, Python, .NET, Java, Ruby) + Android SDK + Miniconda3 + R | ~7 GB |
setup-*-Actions lösen aus der hostedtoolcache auf, ohne Download pro Job. RUNNER_TOOL_CACHE und AGENT_TOOLSDIRECTORY zeigen bereits auf /opt/hostedtoolcache.
Die Versionsnummern in den Tabellen unten zeigen, welche Major-/Minor-Linien eingebacken sind. Die genau aufgelösten Versionen werden durch den wöchentlichen Rebuild laufend angehoben und bei jedem Rebuild automatisch veröffentlicht – den aktuell veröffentlichten Werkzeugstand findest du im Changelog.
Sprachen – System
Eine aktuelle Version im PATH. Nutze sie direkt, wenn deinem Workflow der Systemstandard genügt.
| Sprache | Version | Hinweise |
|---|---|---|
| Node.js | 24.x (LTS) | + npm, dazu pnpm + yarn über corepack. Neuere/ältere Linien über actions/setup-node – siehe unten |
| Rust | rustup stable | rustc + cargo |
| PowerShell | 7.x | pwsh |
| PHP | 8.3 | + Composer |
Sprachen – mehrere Versionen über setup-*-Actions
Nutze diese actions/setup-*-Actions genau wie auf GitHub-hosted Runnern. Die angeforderte Version wird aus der hostedtoolcache aufgelöst (kein Netzwerkabruf).
| Action | Eingebackene Versionen | Was sie einrichtet |
|---|---|---|
actions/setup-node@v4 | 26.x, 24.x, 22.x | Node.js + npm; pnpm/yarn über corepack enable aktivieren |
actions/setup-go@v5 | 1.27.x, 1.26.x | Go-Toolchain + Modul-Cache |
actions/setup-python@v5 | 3.14, 3.13, 3.12 | Python + pip |
actions/setup-dotnet@v4 | 10.0, 8.0 | .NET SDK (parallel installiert, DOTNET_ROOT gesetzt) |
actions/setup-java@v4 | Temurin 25, 21, 17 | OpenJDK von Adoptium |
ruby/setup-ruby@v1 | 4.0.x, 3.4.x, 3.3.x | Ruby (ruby-builder) |
Brauchst du eine Version, die wir nicht einbacken (z. B. Node 20.x für ein Altprojekt), können actions/setup-node, actions/setup-go, actions/setup-java und actions/setup-dotnet eine nicht eingebackene Version zur Laufzeit des Jobs herunterladen (langsamer, aber es funktioniert – sie holen generische Linux-Builds). actions/setup-python und ruby/setup-ruby können das nicht: Upstream veröffentlicht für keines von beiden ein Debian-Asset, daher scheitert eine nicht eingebackene Linie sofort, statt auf etwas zurückzufallen. Wähle eine eingebackene Linie oder nutze für einen Einzelfall uv python install <version> (uv ist eingebacken) oder einen container:-Job.
Build-Essentials
Native Node-Module, Python-Wheels mit C-Erweiterungen, Go mit cgo und Rust-Crates mit C-Abhängigkeiten bauen ohne weitere Einrichtung.
build-essential (gcc + make) · clang + lld · cmake · ninja · pkg-config · autoconf · automake · libtool · zstd · linux-headers (über die Basis)
Paketmanager und Projektwerkzeuge
| Paketmanager | Version | Hinweise |
|---|---|---|
npm | mit Node 24 gebündelt | |
pnpm | standardmäßig 12.14.0 | Über corepack, bereits aktiviert. Ein packageManager-Pin des Projekts hat Vorrang; siehe pnpm- und Yarn-Versionen |
yarn | standardmäßig 4.18.1 | Über corepack, bereits aktiviert. Für Yarn Classic yarn@1.22.22 pinnen; siehe pnpm- und Yarn-Versionen |
pipx | Debian | Installiert Python-CLI-Werkzeuge in isolierten venvs |
composer | latest | PHP |
cargo | über rustup verwaltet | Rust |
mvn (Maven) | 3.9.x | JVM |
gradle | 9.5.x | JVM |
pnpm- und Yarn-Versionen
pnpm und yarn laufen über corepack, das auf dem Runner aktiviert ist. Welche Version ein Job bekommt, hängt davon ab, ob das Projekt eine pinnt:
- Kein Pin: Ein Job bekommt pnpm 12.14.0 und Yarn 4.18.1. Beide liegen auf dem Runner, ein Download ist also nicht nötig. Bis zum 21.10.2026 bekam ein Job ohne Pin, was zur Laufzeit des Jobs npms
latestwar – bei Yarn war das Yarn Classic 1.22. - Gepinnt: Setze
packageManagerin deinerpackage.json, zum Beispiel"packageManager": "pnpm@11.28.6"oder"packageManager": "yarn@1.22.22", undcorepackführt genau diese Version aus. pnpm 12.14.0 und 11.28.6 liegen bereits auf dem Runner; jede andere Version wird beim Start des Jobs heruntergeladen.
Über packageManager triffst du die Wahl. Es hält außerdem deinen lokalen Rechner und die CI auf derselben Version. Wenn wir die Standards auf ein neueres Release anheben, kündigen wir das im Changelog an.
IaC
| Werkzeug | Hinweise |
|---|---|
tofu (OpenTofu) | MPL-2.0-Ersatz für Terraform. Das echte Terraform steht unter BUSL und ist nicht eingebacken; nutze hashicorp/setup-terraform, wenn du ausdrücklich Terraform brauchst. |
bicep | Azure |
pulumi | Cloud-übergreifend |
ansible (ansible-core) | Über pipx |
sam (AWS SAM CLI) | Serverless |
Cloud-CLIs
| Cloud | CLI | Hinweise |
|---|---|---|
| AWS | aws v2, sam | |
| Google Cloud | gcloud, gsutil, bq | |
| Azure | az | |
| T Cloud Public (OTC) | tofu + Provider opentelekomcloud | Oder pip install otc-cli pro Job |
Container und Kubernetes
| Werkzeug | Hinweise |
|---|---|
docker (CLI + nativer Daemon) | Docker läuft nativ auf der VM (kein Sidecar, kein Umweg über DOCKER_HOST) – siehe Container-Builds unten |
kaniko | Daemonloser, rootloser OCI-Image-Builder |
skopeo | Images zwischen Registrys kopieren / untersuchen |
kubectl | |
helm | |
kustomize | |
kind | Lokale k8s-Cluster – funktioniert in den meisten Fällen mit dem nativen Docker-Daemon; ergänze das Label dind-privileged, wenn du auf Operationen mit eingeschränkten Capabilities stößt (KVM-Nesting, rohes /dev für verschachtelte Gäste) |
tea | Forgejo-/Gitea-CLI |
Sicherheit und Supply Chain
Vorab eingebacken, damit Secret-, CVE-, SBOM- und SAST-Scans keine Einrichtungszeit kosten.
| Scanner | Findet |
|---|---|
gitleaks | Secrets in Commits |
trivy | CVEs in Betriebssystem und Sprachen + IaC-Fehlkonfigurationen |
osv-scanner | Schwachstellen aus der OSV-Datenbank |
cosign | Signieren und Prüfen von Container-Images |
syft | SBOM-Erzeugung (CycloneDX / SPDX) |
opengrep | SAST (Semgrep-kompatibler Fork). Vorab eingebacken mit den Sprachordnern der GitLab sast-rules unter /opt/sast-rules/: csharp, go, java, javascript, python und scala. Die Regeln stehen unter MIT, außer go, das unter Apache-2.0 steht (von gosec abgeleitet). Nur diese Ordner werden ausgeliefert. Übergib die benötigten an --config; das Wurzelverzeichnis /opt/sast-rules ist kein Regelsatz |
scorecard | OSSF-Supply-Chain-Scorecard |
checkov | IaC-Sicherheit (Terraform, CFN, k8s) |
cfn-lint | CloudFormation-Lint |
Linter
shellcheck · shfmt · yamllint · actionlint (prüft die Forgejo-Actions-Workflows, die du auf frem.sh schreibst) · hadolint (Dockerfile)
Browser und E2E
Für Headless-Browsertests:
- Chromium +
chromedriver(Debian-Paket, Versionen aufeinander abgestimmt) - Firefox ESR +
geckodriver - Selenium Server (JAR unter
/opt/selenium-server.jar)
Microsoft Edge ist nicht eingebacken – Chromium nutzt dieselbe Blink-Engine; für Tests in der CI ist Chromium gleichwertig.
Datenbank-Clients
postgresql-client · default-mysql-client · sqlite3. Die vollständigen Datenbankserver kommen über services:-Blöcke (ein Docker-Pull von Docker Hub, über den Dependency-Proxy deiner Organisation, wenn sie eine eigene Docker-Hub-Zugangsberechtigung hat; siehe Docker-Hub-Images).
Mobile und Data Science (eingebacken seit 06.06.2026)
| Werkzeug | Vorinstalliert | Pro Job ergänzen |
|---|---|---|
| Android SDK | cmdline-tools (latest) + platforms;android-34 + build-tools;34.0.0 + platform-tools unter ANDROID_HOME=/usr/local/lib/android/sdk | Weitere API-Level / NDK / Emulatoren über android-actions/setup-android@v3 (nutzt das Vorinstallierte, kein erneuter Download) |
| R (CRAN) | r-base + r-base-dev (Debian-CRAN-Repository, derzeit 4.3.x) unter /opt/hostedtoolcache/R/4.3/x64 | CRAN-Pakete über Rscript -e 'install.packages(...)' oder r-lib/actions/setup-r-dependencies@v2 |
| Miniconda3 | conda + Python 3.11 unter CONDA=/opt/hostedtoolcache/Miniconda3/latest/x64 | Umgebungen + wissenschaftlicher Stack über conda-incubator/setup-miniconda@v3 mit environment-file: |
# Android example
- uses: android-actions/setup-android@v3
- run: ./gradlew assembleDebug
# R example
- uses: r-lib/actions/setup-r@v2
- uses: r-lib/actions/setup-r-dependencies@v2
- run: Rscript -e 'testthat::test_local()'
# Miniconda example
- uses: conda-incubator/setup-miniconda@v3
with:
environment-file: env.yml
- shell: bash -el {0}
run: pytestWas weiterhin NICHT eingebacken ist
Ausgesprochene Nischen- oder schwergewichtige Werkzeuge, die die meisten Workflows nicht brauchen. Installiere sie pro Job:
| Werkzeug | Installationsweg | Hinweise |
|---|---|---|
| iOS / Xcode | Nur macOS – nicht unterstützt (fremforge-Runner laufen unter Linux) | Eigener Punkt auf der Roadmap für Runner-Stufen |
| Julia | julia-actions/setup-julia@v2 | ~150 MB Installation pro Job |
| Swift | swift-actions/setup-swift@v2 | Swift-Toolchain für Linux |
| Haskell / GHC | haskell-actions/setup@v2 | |
| Mono | apt-get install mono-complete | Nur für das alte .NET Framework – .NET 8/10 sind eingebacken |
| Browser Microsoft Edge | Nicht nötig – Chromium ist dieselbe Engine | |
| Lua / Crystal / Nim / Elixir | setup-*-Action pro Job oder apt |
Container-Builds
Natives Docker (Standard)
Auf der VM ist der Docker-Daemon installiert und läuft auf dem Host. Deine docker-CLI spricht ihn über den üblichen lokalen Socket an – kein Docker-in-Docker, kein Sidecar, kein Umweg über DOCKER_HOST. Die meisten Workflows für GitHub-hosted Runner funktionieren unverändert – docker build, docker compose, docker pull, mehrstufige Builds, BuildKit-Funktionen.
- run: docker build -t myapp:${{ github.sha }} .
- run: docker compose up -d
- run: docker pull postgres:16kaniko
Für reine Image-Builds ist kaniko daemonlos (schnellerer Kaltstart, wenn du nicht den ganzen Docker-Daemon brauchst) und verhält sich beim Layer-Caching gegenüber entfernten Registrys besser.
- run: |
/usr/local/bin/kaniko \
--context=$GITHUB_WORKSPACE \
--dockerfile=Dockerfile \
--destination=registry.example.com/$GITHUB_REPOSITORY:$GITHUB_SHAPrivilegiertes Docker (KVM-Nesting)
Braucht deine Arbeitslast zusätzliche Capabilities über das hinaus, was der Standard-Docker-Benutzer hat (z. B. kind mit KVM-Nesting, testcontainers-Funktionen, die Capabilities zum Anlegen von Namespaces brauchen, /dev-Zugriff für verschachtelte Gäste), ergänze das Label in runs-on:
jobs:
integration:
runs-on: [fremforge, dind-privileged]
steps:
- run: docker run --privileged kindest/node:v1.31.0 ...fremforge leitet diese Jobs an einen VM-Typ mit aktivierter verschachtelter Virtualisierung, mit derselben VM-Isolation pro Commit wie bei den Standard-Runnern.
Wie wir den Umfang in ~7 GB liefern, wenn GitHub-hosted ~50 GB braucht
Die GitHub-hosted Images ubuntu-latest sind groß, weil sie Folgendes einbacken:
- Mehrere Versionen pro Sprache – wir backen die 3 neuesten unterstützten Linien für Node, Python, Java und Ruby ein und 2 für Go und .NET (~3 GB insgesamt für alle 6 Sprachfamilien). Die Tabellen oben werden von Hand gepflegt und nennen die Linie, nicht den Patch-Stand. Die genauen derzeit eingebackenen Patch-Versionen – bei jeder Änderung aus den Build-Argumenten des Runner-Images erzeugt – findest du in der generierten Werkzeugliste. Weichen die beiden einmal voneinander ab, gilt die generierte Liste. Eine nicht eingebackene Linie lässt sich für Python und Ruby NICHT pro Job herunterladen (siehe Hinweis unten), wähle also aus dem eingebackenen Satz.
- Android SDK + NDK (~10 GB bei GitHub-hosted) – wir backen das Kern-SDK ein (cmdline-tools + Platform 34 + build-tools 34.0.0 + platform-tools, ~3 GB). Weitere API-Level, NDK und Emulator-System-Images werden pro Job über
setup-androidinstalliert (nutzt das Vorinstallierte). - Vorab gezogene Docker-Images für Service-Container (postgres, mysql, mongo, redis, mssql ~5 GB) – nicht eingebacken. Ein
docker pullholt sie von Docker Hub oder über den Dependency-Proxy deiner Organisation (siehe Paket-Caches). - Browser Microsoft Edge – nicht eingebacken (Chromium ist für Tests in der CI dieselbe Engine).
- Mono / Julia / Swift / Haskell / Lua / Crystal / Nim / Elixir – nicht eingebacken (Nische, pro Job installieren).
- Alte GCC-Versionen, veraltete Toolchains – wir liefern einen aktuellen Satz.
Was wir für typische Workflows gegenüber GitHub-hosted nicht verlieren:
- Jede gängige Sprache (Node, Python, Go, Java, .NET, Ruby, Rust, PHP, PowerShell)
- Mobile (Android SDK) und Data Science (Miniconda + R), eingebacken seit 06.06.2026
- Jede große Cloud-CLI (AWS, Azure, GCP)
- Jeden gängigen Scanner (Trivy, Gitleaks, OSV, Cosign, Syft, OpenGrep, Scorecard, Checkov)
- Beide großen Browser + Selenium
- Docker (nativ, privilegiert über Label)
- Alle Standard-GitHub-Actions (
actions/checkout,actions/setup-*,actions/upload-artifactusw.)
Braucht dein Team etwas, das wir nicht einbacken, wende dich an den Support – von Renovate verfolgte Werkzeuge kommen mit dem nächsten wöchentlichen Rebuild dazu.
Image-Größe, Kaltstart, Rebuild-Rhythmus
- Wöchentlicher Rebuild: jeden Montag um 06:00 UTC. Renovate schlägt laufend Versionsanhebungen vor; der Montags-Rebuild übernimmt alles, was in dieser Woche gemergt wurde.
- Trivy-Gate beim Build: CVEs der Stufen HIGH und CRITICAL lassen den Build hart scheitern. Wir liefern nie ein Image mit bekannten, ungepatchten HIGH-/CRITICAL-Befunden aus.
- Per sha256 gepinnte Downloads: Jeder Binärabruf beim Build wird gegen einen gepinnten sha256 geprüft. Renovate hebt Version und Hash im selben PR an. Weicht der Hash ab, scheitert der Build deutlich sichtbar – das ist das Sicherheitsnetz für die Supply Chain.
- VM-Kaltstart: ~25 s (ECS-Bereitstellung + Booten aus dem eingebackenen Image). VMs aus dem Warm-Pool (vorab bereitgestellt, im Leerlauf) senken die Wartezeit auf ~5 s, wenn der Pool Kapazität hat.
- Veröffentlichung des Manifests: Jeder Rebuild veröffentlicht die aufgelösten Werkzeugversionen, den Image-Digest, die Trivy-Zusammenfassung und die CycloneDX-SBOM im Changelog.
Beispiel-Workflow
Ein minimaler Workflow, der alles nutzt:
name: ci
on:
push:
branches: [main]
workflow_dispatch: {}
jobs:
build-test-scan:
runs-on: fremforge
permissions:
contents: read
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '24' # resolves from hostedtoolcache, ~1 s
- run: npm ci && npm test
- uses: actions/setup-python@v5
with:
python-version: '3.13'
- run: pip install -r requirements.txt && pytest
- name: SAST + secrets
run: |
gitleaks detect --no-banner --redact
# one --config per language folder; /opt/sast-rules itself is not a rule set
opengrep scan --config=/opt/sast-rules/python --config=/opt/sast-rules/javascript .
- name: SBOM
run: syft scan dir:. -o cyclonedx-json > sbom.json
- name: Container build
run: docker build -t myapp:${{ github.sha }} .Lizenzen und Drittanbieter-Hinweise
Das Image enthält Software von Drittanbietern unter deren eigenen Lizenzen, darunter opengrep (LGPL-2.1, mit Quellcode-Angebot), Node.js und die SAST-Regeln. Die Hinweise, die Namensnennung für Advisory-Daten und die Bezugsquelle für den Quellcode stehen unter Hinweise zu Drittanbieter-Komponenten im Runner-Image. Innerhalb eines Jobs liegen die Lizenzdateien unter /usr/share/licenses/ und /usr/share/doc/<package>/copyright.
Probleme mit dem Runner-Image melden
Fehlt ein Werkzeug, das du erwartet hast, oder stößt du auf ein Problem zur Laufzeit der VM (Ressourcengrenzen, Netzwerk, Capabilities), wende dich an support@frem.sh. Bei Regressionen der gehosteten Runner antworten wir noch am selben Werktag.