SonarQube-Analyse als geteilten Baustein aufnehmen #8

Merged
jklein merged 1 commits from feat/sonar-analysis into main 2026-10-02 01:41:29 +02:00
Member

Nimmt eine SonarQube-Analyse als geteilten Baustein auf. Der Workflow ist
für jedes Repository identisch; alles Projektspezifische —
Projektschlüssel, Quellpfade, Ausschlüsse — steht in der
sonar-project.properties des aufrufenden Repositories. Ein zweiter Abnehmer
kostet damit eine Datei mit drei Zeilen.

Erster Abnehmer wird jlab-cluster/helm-charts; cluster-config und die
suer-Projekte können den Baustein sofort mitbenutzen.

Was drin ist

Datei
.gitea/workflows/sonar-analysis.yml neu, on: workflow_call
README.md Abschnitt in der bestehenden Struktur: Zweck, Eingaben, Aufrufbeispiel, Voraussetzungen

Dazu die Langform im Wiki, sonar-analysis,
mit einer Zeile in der Tabelle auf Home — ist bereits gepusht, weil das
Wiki keinen PR-Fluss hat.

Der Baustein

Drei Schritte, in dieser Reihenfolge:

  1. Ein Wächter für die Voraussetzungen des Aufrufers. Er prüft beide
    Werte, bevor er abbricht — ein Repository, das keinen von beiden
    eingerichtet hat, erfährt das sonst in zwei Läufen statt in einem.
  2. Checkout mit fetch-depth: 0. Nicht optional: Ein flacher Klon liefert
    dem Scanner keine Historie, er schreibt dann alle Befunde dem letzten Commit
    zu, und damit wird das Meiste unbrauchbar, wofür man SonarQube aufstellt —
    Zuordnung zu Autor und Änderung, der Zeitraum „neuer Code", jedes
    datumsbasierte Maß.
  3. Die offizielle Scan-Action, SONAR_TOKEN aus dem Secret,
    SONAR_HOST_URL aus vars.

Beide Actions sind auf einen Commit gepinnt, mit der Hauptversion als
Kommentar dahinter — Hausregel dieses Repositories und die Linie von Issue #5.

runs-on: ubuntu-latest, und das ist im Workflow begründet: Die Scan-Action
deklariert runs: using: node24, ist also eine JavaScript-Action und braucht
keinen Docker-Socket. ubuntu-docker ist der einzige Runner hier, der einen
hat, und wird nicht gebraucht.

Eingaben

Eingabe Typ Pflicht Vorgabe
args string nein ""
project-base-dir string nein "."

Beide type: string, auch project-base-dir, das inhaltlich keiner Schalter
ist — die Regel gilt hier für jede Eingabe, damit sie nicht je Datei neu
entschieden wird. Grund: Boolesche workflow_call-Eingaben kommen auf dieser
Gitea-Version nicht an, bei grünem Lauf (#4). Das steht als Kommentar an der
Eingabe, damit ein späteres Aufräumen den Fehler nicht still zurückholt.

Die Vorgabe von project-base-dir ist "." und nicht leer, weil die Action
selbst . als Vorgabe hat: Ein leerer Wert würde durchgereicht und überschriebe
sie, statt sie stehen zu lassen.

Kein Quality-Gate, und das absichtlich

Die Community Build analysiert ausschließlich den Hauptzweig. Der Aufruf hängt
damit an einem Push auf main, ein Befund erscheint nach dem Merge, und
dort ist nichts mehr zu blockieren. Ein rotes Gate färbte nur main rot, ohne
etwas verhindert zu haben — und ein Dauerzustand nimmt die Glaubwürdigkeit der
übrigen Prüfungen mit.

Richtig wird ein Gate unter genau einer von zwei Bedingungen: PR-Analyse ist
verfügbar, oder ein Deployment hängt an diesem Workflow. Beides steht im README
und als Kommentar an der Stelle, an der der Schritt stünde — damit niemand ihn
als Versehen nachträgt.

Voraussetzungen im aufrufenden Repository

Name Art Zustand
SONAR_HOST_URL Variable auf der Instanz gesetzt
SONAR_TOKEN Secret offen — muss im aufrufenden Repository oder auf Organisationsebene vorliegen
sonar-project.properties Datei im Repository kommt mit dem Aufrufer

Die Adresse ist bewusst eine Variable und kein Secret: Sie ist kein
Zugangsdatum, und als Variable bleibt sie im Protokoll lesbar — erst das macht
eine falsche Adresse diagnostizierbar. Als Secret wäre sie maskiert, und genau
diese Lage hat bei publish-helm-chart einen eigenen Maskierungsschritt
erzwungen.

SONAR_TOKEN ist als required: true deklariert. Das ist auf dieser Instanz
eine echte Entscheidung: Ein fehlendes Pflicht-Secret lässt die
Job-Erzeugung scheitern, nicht den Job, der Lauf steht dann ohne Schritte
da. Hier ist es trotzdem richtig, weil jeder Aufrufer das Token braucht — ohne
Token gibt es keine Analyse, ein Lauf ohne Schritte ist also der verständliche
Fall. Der Wächter fängt entsprechend nur die anderen zwei Fälle: ein
vorhandenes, aber leeres Secret und einen vergessenen secrets: inherit.

Was nicht gemessen ist

Vollständig auf der Wiki-Seite; die vier offenen Punkte:

  1. Ist node24 im Runner-Image vorhanden? Die Action verlangt es. Fehlt es,
    scheitert sie mit einer Meldung über die Action, nicht über das Image.
  2. Kommt der Scanner-Download durch? Die Action lädt den Sonar-Scanner-CLI
    zur Laufzeit von binaries.sonarsource.com und prüft seine GPG-Signatur —
    gemessen rund 59 MiB. Das ist die wahrscheinlichste Stelle für den ersten
    Fehlschlag, und zwar mit Vorgeschichte: Im README des ersten Abnehmers steht
    gemessen, dass auf diesem Runner einmal eine 17-MB-Datei nicht durchkam, weil
    eine Docker-Brücke mit MTU 1500 gegen ein Pod-Netz mit 1450 lief. Behoben
    wurde das auf der Knoten-Seite; der Scanner-CLI ist ein Mehrfaches davon.
  3. Kommt vars.SONAR_HOST_URL in einem aus einem fremden Repository
    aufgerufenen Workflow an?
    Dokumentiert, auf dieser Forge-Fassung nicht
    gemessen — dasselbe Offene wie bei OP_CONNECT_HOST in
    publish-helm-chart. Wenn es nicht ankommt, ist es immerhin laut: Der
    Wächter greift und benennt die Variable. Der Weg wäre dann derselbe wie dort
    beim Eigentümer — die Adresse als Eingabe, im Aufrufer ausgewertet.
  4. Was der erste Lauf überhaupt meldet, insbesondere aus Helm-Templates, die
    wegen {{ }} kein gültiges YAML sind. Deshalb beginnt der erste Abnehmer
    ohne Ausschlüsse: Das bekommt man nur heraus, indem man den Analysator einmal
    darauf laufen lässt. Ausschlüsse gehören dann in die
    sonar-project.properties des Repositories, nicht in diesen Baustein.

Nach dem Merge

Der Baustein ist ab v4 verfügbar — repository-weit, wie seit v3
dokumentiert: Die Nummer bezeichnet den Zustand des Repositories und nicht die
Version einer Datei. Der Abschnitt dazu ist mitgezogen, v4 ist jetzt der
Sonar-Stand und das Beispiel für eine künftige Änderung an
docker-build-push.yml nennt v5. v4 selbst ist additiv: An den vorhandenen
Bausteinen ändert sich nichts, Aufrufer auf @v2 und @v3 bleiben unberührt.

Der Tag wird nicht in diesem PR gesetzt, sondern nach dem Merge.

Die Hülle im aufrufenden Repository (.gitea/workflows-Aufruf an @v4 mit
secrets: inherit, dazu die sonar-project.properties) kommt als eigener PR in
jlab-cluster/helm-charts — dieser PR ändert dort nichts.

Erstellt unter dem Bot-Konto.

Part of jlab-cluster/helm-charts#71

Nimmt eine **SonarQube-Analyse** als geteilten Baustein auf. Der Workflow ist für jedes Repository identisch; alles Projektspezifische — Projektschlüssel, Quellpfade, Ausschlüsse — steht in der `sonar-project.properties` des aufrufenden Repositories. Ein zweiter Abnehmer kostet damit eine Datei mit drei Zeilen. Erster Abnehmer wird `jlab-cluster/helm-charts`; `cluster-config` und die `suer`-Projekte können den Baustein sofort mitbenutzen. ## Was drin ist | Datei | | | --- | --- | | `.gitea/workflows/sonar-analysis.yml` | neu, `on: workflow_call` | | `README.md` | Abschnitt in der bestehenden Struktur: Zweck, Eingaben, Aufrufbeispiel, Voraussetzungen | Dazu die Langform im Wiki, [sonar-analysis](https://git.jk-dev.de/workflow-util/pipelines/wiki/sonar-analysis), mit einer Zeile in der Tabelle auf `Home` — **ist bereits gepusht**, weil das Wiki keinen PR-Fluss hat. ## Der Baustein Drei Schritte, in dieser Reihenfolge: 1. **Ein Wächter** für die Voraussetzungen des Aufrufers. Er prüft **beide** Werte, bevor er abbricht — ein Repository, das keinen von beiden eingerichtet hat, erfährt das sonst in zwei Läufen statt in einem. 2. **Checkout mit `fetch-depth: 0`.** Nicht optional: Ein flacher Klon liefert dem Scanner keine Historie, er schreibt dann alle Befunde dem letzten Commit zu, und damit wird das Meiste unbrauchbar, wofür man SonarQube aufstellt — Zuordnung zu Autor und Änderung, der Zeitraum „neuer Code", jedes datumsbasierte Maß. 3. **Die offizielle Scan-Action**, `SONAR_TOKEN` aus dem Secret, `SONAR_HOST_URL` aus `vars`. Beide Actions sind **auf einen Commit gepinnt**, mit der Hauptversion als Kommentar dahinter — Hausregel dieses Repositories und die Linie von Issue #5. `runs-on: ubuntu-latest`, und das ist im Workflow begründet: Die Scan-Action deklariert `runs: using: node24`, ist also eine JavaScript-Action und braucht keinen Docker-Socket. `ubuntu-docker` ist der einzige Runner hier, der einen hat, und wird nicht gebraucht. ## Eingaben | Eingabe | Typ | Pflicht | Vorgabe | | --- | --- | --- | --- | | `args` | `string` | nein | `""` | | `project-base-dir` | `string` | nein | `"."` | Beide `type: string`, auch `project-base-dir`, das inhaltlich keiner Schalter ist — die Regel gilt hier für jede Eingabe, damit sie nicht je Datei neu entschieden wird. Grund: Boolesche `workflow_call`-Eingaben kommen auf dieser Gitea-Version nicht an, bei grünem Lauf (#4). Das steht als Kommentar an der Eingabe, damit ein späteres Aufräumen den Fehler nicht still zurückholt. Die Vorgabe von `project-base-dir` ist `"."` und nicht leer, weil die Action selbst `.` als Vorgabe hat: Ein leerer Wert würde durchgereicht und überschriebe sie, statt sie stehen zu lassen. ## Kein Quality-Gate, und das absichtlich Die Community Build analysiert ausschließlich den Hauptzweig. Der Aufruf hängt damit an einem Push auf `main`, ein Befund erscheint **nach** dem Merge, und dort ist nichts mehr zu blockieren. Ein rotes Gate färbte nur `main` rot, ohne etwas verhindert zu haben — und ein Dauerzustand nimmt die Glaubwürdigkeit der übrigen Prüfungen mit. Richtig wird ein Gate unter genau einer von zwei Bedingungen: PR-Analyse ist verfügbar, oder ein Deployment hängt an diesem Workflow. Beides steht im README und als Kommentar an der Stelle, an der der Schritt stünde — damit niemand ihn als Versehen nachträgt. ## Voraussetzungen im aufrufenden Repository | Name | Art | Zustand | | --- | --- | --- | | `SONAR_HOST_URL` | Variable | auf der Instanz gesetzt | | `SONAR_TOKEN` | Secret | **offen** — muss im aufrufenden Repository oder auf Organisationsebene vorliegen | | `sonar-project.properties` | Datei im Repository | kommt mit dem Aufrufer | Die Adresse ist bewusst eine **Variable** und kein Secret: Sie ist kein Zugangsdatum, und als Variable bleibt sie im Protokoll lesbar — erst das macht eine falsche Adresse diagnostizierbar. Als Secret wäre sie maskiert, und genau diese Lage hat bei `publish-helm-chart` einen eigenen Maskierungsschritt erzwungen. `SONAR_TOKEN` ist als `required: true` deklariert. Das ist auf dieser Instanz eine echte Entscheidung: Ein fehlendes Pflicht-Secret lässt die **Job-Erzeugung** scheitern, nicht den Job, der Lauf steht dann ohne Schritte da. Hier ist es trotzdem richtig, weil jeder Aufrufer das Token braucht — ohne Token gibt es keine Analyse, ein Lauf ohne Schritte ist also der verständliche Fall. Der Wächter fängt entsprechend nur die anderen zwei Fälle: ein vorhandenes, aber leeres Secret und einen vergessenen `secrets: inherit`. ## Was nicht gemessen ist Vollständig auf der Wiki-Seite; die vier offenen Punkte: 1. **Ist `node24` im Runner-Image vorhanden?** Die Action verlangt es. Fehlt es, scheitert sie mit einer Meldung über die Action, nicht über das Image. 2. **Kommt der Scanner-Download durch?** Die Action lädt den Sonar-Scanner-CLI zur Laufzeit von `binaries.sonarsource.com` und prüft seine GPG-Signatur — gemessen rund **59 MiB**. Das ist die wahrscheinlichste Stelle für den ersten Fehlschlag, und zwar mit Vorgeschichte: Im README des ersten Abnehmers steht gemessen, dass auf diesem Runner einmal eine 17-MB-Datei nicht durchkam, weil eine Docker-Brücke mit MTU 1500 gegen ein Pod-Netz mit 1450 lief. Behoben wurde das auf der Knoten-Seite; der Scanner-CLI ist ein Mehrfaches davon. 3. **Kommt `vars.SONAR_HOST_URL` in einem aus einem fremden Repository aufgerufenen Workflow an?** Dokumentiert, auf dieser Forge-Fassung nicht gemessen — dasselbe Offene wie bei `OP_CONNECT_HOST` in `publish-helm-chart`. Wenn es nicht ankommt, ist es immerhin laut: Der Wächter greift und benennt die Variable. Der Weg wäre dann derselbe wie dort beim Eigentümer — die Adresse als Eingabe, im Aufrufer ausgewertet. 4. **Was der erste Lauf überhaupt meldet**, insbesondere aus Helm-Templates, die wegen `{{ }}` kein gültiges YAML sind. Deshalb beginnt der erste Abnehmer ohne Ausschlüsse: Das bekommt man nur heraus, indem man den Analysator einmal darauf laufen lässt. Ausschlüsse gehören dann in die `sonar-project.properties` des Repositories, nicht in diesen Baustein. ## Nach dem Merge Der Baustein ist ab **`v4`** verfügbar — repository-weit, wie seit `v3` dokumentiert: Die Nummer bezeichnet den Zustand des Repositories und nicht die Version einer Datei. Der Abschnitt dazu ist mitgezogen, `v4` ist jetzt der Sonar-Stand und das Beispiel für eine künftige Änderung an `docker-build-push.yml` nennt `v5`. `v4` selbst ist additiv: An den vorhandenen Bausteinen ändert sich nichts, Aufrufer auf `@v2` und `@v3` bleiben unberührt. Der Tag wird **nicht** in diesem PR gesetzt, sondern nach dem Merge. Die Hülle im aufrufenden Repository (`.gitea/workflows`-Aufruf an `@v4` mit `secrets: inherit`, dazu die `sonar-project.properties`) kommt als eigener PR in `jlab-cluster/helm-charts` — dieser PR ändert dort nichts. Erstellt unter dem Bot-Konto. Part of jlab-cluster/helm-charts#71
jlab-bot added 1 commit 2026-10-02 01:34:28 +02:00
Neuer Baustein sonar-analysis.yml, on: workflow_call. Ein Waechter fuer die
Voraussetzungen des Aufrufers, Checkout mit vollstaendiger Historie, dann die
offizielle Scan-Action. Beide Actions auf einen Commit gepinnt.

Projektspezifisches steht in der sonar-project.properties des aufrufenden
Repositories, nicht hier - damit ist der Workflow fuer jedes Repository
identisch und ein zweiter Abnehmer kostet eine Datei mit drei Zeilen.

Kein Quality-Gate-Schritt, und das absichtlich: Die Community Build analysiert
nur den Hauptzweig, der Ausloeser liegt damit nach dem Merge, und dort ist
nichts mehr zu blockieren. Ein rotes main ohne Wirkung nimmt die
Glaubwuerdigkeit der uebrigen Pruefungen mit. Die zwei Bedingungen, unter denen
ein Gate richtig waere, stehen im README und als Kommentar an der Stelle, an
der der Schritt stuende.

SONAR_HOST_URL ist eine Variable des Aufrufers, SONAR_TOKEN sein Secret. Die
Adresse bleibt als Variable im Protokoll lesbar - erst das macht eine falsche
Adresse diagnostizierbar. Der Waechter prueft beide, bevor er abbricht, damit
ein Repository ohne beide das in einem Lauf erfaehrt.

Beide Eingaben sind type: string, auch project-base-dir: Boolesche
workflow_call-Eingaben kommen auf dieser Gitea-Version nicht an (Issue #4), und
die Regel gilt fuer jede Eingabe hier, damit sie nicht je Datei neu entschieden
wird.

Die Langform - warum fetch-depth: 0 nicht optional ist, warum kein
Docker-Runner noetig ist, was der Scanner zur Laufzeit holt und was an diesem
Baustein noch nicht gemessen ist - steht im Wiki unter sonar-analysis.

Der Baustein ist ab v4 verfuegbar; die Tag-Nummer bezeichnet wie bisher den
Zustand des Repositories und nicht die Version einer Datei.
jklein approved these changes 2026-10-02 01:41:26 +02:00
jklein merged commit 0f7cd04c70 into main 2026-10-02 01:41:29 +02:00
jklein deleted branch feat/sonar-analysis 2026-10-02 01:41:29 +02:00
Sign in to join this conversation.
No Reviewers
No labels
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: workflow-util/pipelines#8