2
Gemessenes Verhalten
Justin Klein edited this page 2026-10-02 00:16:27 +00:00

Gemessenes Verhalten dieser Forge

Eigenheiten der Gitea-Instanz, an der diese Bausteine hängen. Alles hier ist gemessen, nicht aus einer Dokumentation übernommen, und jedes Stück hat einmal Zeit gekostet. Die Seite steht quer zu den Bausteinen, weil keine dieser Eigenheiten nur einen davon betrifft.

Gemeinsames Muster, das sie teuer macht: Keiner dieser Fehler ist rot. Der Lauf bleibt grün oder sieht harmlos aus, und erst viel später sucht jemand das Ergebnis dort, wo es hätte landen sollen.

Es stehen auch Bestätigungen hier, nicht nur Fallen. Eine Eigenheit, die sich als harmlos herausgestellt hat, kostet ungeschrieben dasselbe wie eine gefährliche: Die nächste Person misst sie erneut, oder — schlimmer — baut einen Umweg um ein Problem, das es nicht gibt. Jeder Eintrag nennt deshalb den Lauf, an dem er gemessen ist.

Boolesche workflow_call-Eingaben kommen nicht an

Gemessen an Gitea 1.27.0, Issue #4.

Eine Eingabe vom Typ boolean erreicht den aufgerufenen Workflow nicht. Weder ihre Vorgabe noch ein ausdrücklich übergebener Wert: inputs.push blieb leer. Der Baustein baute dadurch immer im Prüfmodus — bei grünem Lauf, mit einem --push, das in der Kommandozeile einfach fehlte, und einer Warnung im Protokoll, die niemand liest, solange nichts rot ist.

Zwei Läufe des ersten Abnehmers:

Lauf Aufruf Ergebnis
272 push weggelassen, Vorgabe gesetzt kein --push, nichts veröffentlicht, Lauf grün
276 push: true ausdrücklich übergeben kein --push, nichts veröffentlicht, Lauf grün

Die Eingrenzung ist das Belastbare daran: Im selben Lauf kamen alle Eingaben vom Typ string korrekt an — Plattformen, Registry, Eigentümer, Container-Name wurden alle richtig aufgelöst. push war die einzige boolesche Eingabe und die einzige, die versagte.

Konsequenz für alle Bausteine hier: Jede Eingabe ist type: string, auch eine, die inhaltlich ein Schalter ist. Werte dann als 'true' und 'false', und im Aufruf in Anführungszeichen — ein unquotiertes push: false ist im YAML ein Boolean und wird verschluckt.

Der Fehler war so langlebig, weil nirgends sichtbar war, was überhaupt ankommt. Dagegen hilft nur eines, und docker-build-push hat es seitdem: ein Diagnoseschritt, der den rohen Wert der Eingabe und den daraus abgeleiteten Modus ausgibt. Rein informativ und so abgesichert, dass er den Job unter keinen Umständen scheitern lässt.

Ein fehlendes Secret lässt die Job-Erzeugung scheitern, nicht den Job

Gemessen in jlab-cluster/helm-charts; dort festgehalten im README-Abschnitt „Where this repo lives, and what a Gitea runner does differently" und als Kommentar an der Secret-Deklaration von dessen install-test.yml.

Wiederverwendbare Workflows mit secrets: inherit funktionieren auf dieser Instanz. Die Eigenheit: Fehlt ein Secret, das der aufgerufene Workflow als required: true deklariert, scheitert nicht der Job, sondern seine Erzeugung — der Lauf steht dann ohne Schritte da. Nichts in ihm benennt die Ursache, und man debuggt mit Vorliebe das Falsche: das Workflow-YAML, den Runner, die Action.

Daraus folgt, dass required an einem Secret eine echte Entscheidung ist und keine Formalie:

  • Braucht jeder Aufrufer das Secret, ist required: true richtig — so hält es publish-helm-chart, denn ohne Connect-Token kann niemand veröffentlichen. Dass der Lauf ohne Schritte dasteht, ist dann der verständliche Fall: Es fehlt genau diese Voraussetzung.
  • Braucht nur ein Teil des Bausteins es, muss es required: false sein. Im Herkunfts-Repository hängt das Token an genau einem Zweig einer Matrix; mit required: true verlöre ein Pull Request aus einem Fork — der keine Secrets trägt — die gesamte Prüfung, jedes Chart auf einmal, ohne dass etwas die Ursache nennt. Optional deklariert scheitert nur der eine Zweig, und zwar laut an einem Wächter, der das fehlende Tresor-Feld benennt.

Dieselbe Linie wie an jeder anderen Stelle dieses Repositories: Wenn etwas fehlen kann, soll es laut und benannt fehlen, nicht still.

Wandernde Action-Verweise

Issue #5, Punkt 1.

Ein Verweis auf einen Zweig statt auf eine Hauptversion holt bei jedem Lauf den jeweils neuesten Stand. Eine Änderung dort ändert das Verhalten aller Projekte, ohne dass hier etwas angefasst wurde — und der Fehler zeigt sich bei einem Aufrufer, der nichts geändert hat.

Das ist dieselbe Mechanik, wegen der das README von Aufrufern verlangt, auf einen Tag statt auf den Hauptzweig zu zeigen: Ein beweglicher Verweis macht aus dem Übernehmen einer neuen Fassung eine unbeobachtete Nebenwirkung statt einer Entscheidung. Nach innen gilt die Regel genauso wie nach außen, sonst ist die Sorgfalt an der Aufrufgrenze wertlos.

In docker-build-push steht noch ein solcher Verweis — die Buildx-Action zeigt auf einen Zweig, während die übrigen Actions auf Hauptversionen gepinnt sind. Festgehalten als bekannte Schwachstelle unter docker-build-push, damit sie nicht erneut entdeckt werden muss.

Eine Repository-Variable erreicht einen fremd aufgerufenen Workflow

Gemessen in jlab-cluster/helm-charts, Lauf 375 (Push auf main), an sonar-analysis.

vars.<NAME> wird in einem Workflow, der per uses: aus einem anderen Repository geholt wird, im Kontext des Aufrufers aufgelöst. Dass es so dokumentiert ist, war bekannt; auf dieser Forge-Fassung gemessen war es nicht.

Der Beleg ist indirekt und trotzdem eindeutig: sonar-analysis prüft vars.SONAR_HOST_URL in einem Wächter und bricht vor dem Scan ab, wenn der Wert leer ist. In Lauf 375 ist der Wächter durchgelaufen und der Scanner gestartet — bei leerer Variable hätte es den Scan nie gegeben. Dasselbe gilt für das uses: selbst: Der Baustein liegt in diesem Repository, der Aufruf kam aus einem anderen, und er wurde aufgelöst.

Damit ist dieselbe Frage für OP_CONNECT_HOST in publish-helm-chart beantwortet. Gleiche Gitea-Fassung, gleicher Mechanismus: eine Repository-Variable, gelesen in einem aus einem fremden Repository aufgerufenen Workflow. Dort muss nichts zweites gemessen werden, und der vorgesehene Ausweg — die Adresse als Eingabe übergeben, im Aufrufer ausgewertet, wie es für das Eigentümer-Segment schon getan wurde — wird nicht gebraucht.

Was an der Publish-Strecke offen bleibt, ist etwas anderes und nur das: der Upload selbst hat nie stattgefunden. Kein Chart ist durch den geteilten Baustein veröffentlicht worden.

Der Scanner-Download kommt durch — 59 MiB in etwa drei Sekunden

Gemessen in jlab-cluster/helm-charts, Lauf 375.

SonarSource/sonarqube-scan-action lädt den Sonar-Scanner-CLI zur Laufzeit von binaries.sonarsource.com und prüft dessen GPG-Signatur. Archiv und Signatur, rund 59 MiB, waren in etwa drei Sekunden da.

Das war die erwartete Stelle für den ersten Fehlschlag, und zwar mit Vorgeschichte: Auf demselben Runner kam einmal eine 17-MB-Datei nicht durch, weil die Docker-Brücke mit MTU 1500 gegen ein Pod-Netz mit MTU 1450 lief — kleine Antworten passten in ein Paket, die große nicht, und der Fehlschlag sah nach einem kaputten Spiegel aus, nicht nach Netz. Festgehalten im README von jlab-cluster/helm-charts, Abschnitt „What a GitHub runner had been providing quietly".

Die knotenseitige Behebung hält, und sie hält beim Dreifachen der damaligen Größe. Ein Download in dieser Größenordnung ist auf diesem Runner kein Risiko mehr und braucht keinen Zwischenspeicher und keinen eigenen Spiegel.

node24 ist im Runner-Image vorhanden

Gemessen in jlab-cluster/helm-charts, Lauf 375.

SonarSource/sonarqube-scan-action deklariert runs: using: node24 und ist damit eine JavaScript-Action, keine Docker-Action. Sie lief. Zwei Folgen:

  • JavaScript-Actions mit node24 sind hier benutzbar. Fehlte die Laufzeitumgebung, scheiterte die Action mit einer Meldung über sich selbst und nicht über das Image — deshalb stand die Frage vorher aufgeschrieben.
  • runs-on: ubuntu-latest genügt für so eine Action. Das Label ubuntu-docker, das den Docker-Socket mitbringt, braucht nur, wer wirklich eine Docker-Action oder einen Build ausführt.