Moving a tag retriggers docker_web, which would rebuild a published release from old source against today's base images and dependencies and push it over the existing one. On 2026-08-09 that nearly happened to v0.4.0 while the rewritten tags were force-pushed; it was averted only because the protected registry variables were unavailable in that window, so docker login failed first. The job now aborts if the target tag already exists in the registry. latest-ci stays overwritable on purpose - it names the newest state, not a version, and carries no promise. Closes axion1337.chat/ThreadNet-Web#14
327 lines
14 KiB
YAML
327 lines
14 KiB
YAML
# GitLab-CI fuer den ThreadNet-Web-Fork (Lab-GitLab: git.lab).
|
|
# Ersetzt die frueheren GitHub/Gitea-Actions-Workflows - Hintergrund: docs/axion1337-fork.md.
|
|
#
|
|
# Erkenntnisse aus den Gitea-CI-Versuchen (2026-07-30), hier eingeflossen:
|
|
# - kein scripts/layered.sh: wuerde den gepinnten matrix-js-sdk-Stand aus pnpm-lock.yaml
|
|
# mit Upstream-develop ueberschreiben (und braucht jq) -> frozen-lockfile-Install
|
|
# - webpack braucht ~4 GB Heap -> NODE_OPTIONS
|
|
# - Desktop-Build laeuft im dockerbuild-Image (rust:bullseye + node, glibc-2.31-Ziel)
|
|
|
|
# --- Wann ueberhaupt eine Pipeline entsteht ------------------------------------
|
|
# Ohne diesen Block erzeugt ein Commit, der nur docs/ anfasst, eine Pipeline mit
|
|
# NULL Jobs - und die zaehlt in GitLab als "failed". Real passiert am 2026-08-06
|
|
# (Pipelines 203 und 204): zwei Doku-Commits, zweimal rot, nichts kaputt.
|
|
#
|
|
# Der Grund liegt an der needs-Kette: web laeuft wegen changes: nicht, und
|
|
# desktop_linux/desktop_windows haengen per needs daran - damit faellt die ganze
|
|
# Pipeline in sich zusammen, auch die manuellen Jobs ohne needs.
|
|
#
|
|
# ⚠️ Warum das keine Kosmetik ist: In gitops/CLAUDE.md ist die rote Pipeline die
|
|
# ALARMANLAGE fuer die TURN-Rotation ("es gibt keinen separaten Reminder"). Rot,
|
|
# das nichts bedeutet, gewoehnt einem das Hinsehen ab.
|
|
#
|
|
# Preis: Nach einem reinen Doku-Commit entsteht keine Pipeline von selbst. Damit
|
|
# die manuellen Wartungsjobs (desktop_image, windows_provision) trotzdem
|
|
# erreichbar bleiben, laesst die Regel CI_PIPELINE_SOURCE == "web" durch - eine
|
|
# ueber "Run pipeline" in der Oberflaeche gestartete Pipeline entsteht immer.
|
|
.pfade_mit_pipeline: &pfade_mit_pipeline
|
|
- apps/**/*
|
|
- packages/**/*
|
|
- patches/**/*
|
|
- scripts/**/*
|
|
- pnpm-lock.yaml
|
|
- pnpm-workspace.yaml
|
|
- .gitlab-ci.yml
|
|
|
|
workflow:
|
|
rules:
|
|
- if: $CI_COMMIT_TAG =~ /^v/
|
|
- if: $CI_PIPELINE_SOURCE == "schedule"
|
|
- if: $CI_PIPELINE_SOURCE == "web"
|
|
- if: $CI_COMMIT_BRANCH
|
|
changes: *pfade_mit_pipeline
|
|
- when: never
|
|
|
|
stages:
|
|
- build
|
|
- package
|
|
|
|
# --- Windows-Runner-VM-Steuerung (Issue #5) ---------------------------------
|
|
# Die Windows-Build-VM (dockur/windows-Fork, siehe git.lab/axion1337.chat/vendor/windows,
|
|
# Runbook: docs/axion-runner.md dort) laeuft on-demand auf Overmind. Diese beiden Jobs
|
|
# starten/stoppen sie vom Linux-Runner aus ueber den Docker-Socket - der
|
|
# desktop_windows-Job wartet danach einfach in der Queue, bis der Runner online ist.
|
|
|
|
start_windows_vm:
|
|
stage: build
|
|
image: docker:27-cli
|
|
rules:
|
|
- if: $CI_COMMIT_TAG =~ /^v/
|
|
when: manual
|
|
allow_failure: true
|
|
- if: $CI_COMMIT_BRANCH == "main"
|
|
when: manual
|
|
allow_failure: true
|
|
script:
|
|
- docker start windows-runner
|
|
|
|
stop_windows_vm:
|
|
stage: package
|
|
image: docker:27-cli
|
|
rules:
|
|
- if: $CI_COMMIT_TAG =~ /^v/
|
|
when: manual
|
|
allow_failure: true
|
|
- if: $CI_COMMIT_BRANCH == "main"
|
|
when: manual
|
|
allow_failure: true
|
|
script:
|
|
- docker stop windows-runner
|
|
|
|
# CVE-Scan des eigenen Prod-Images (gitops#31): woechentlich per Schedule und
|
|
# manuell triggerbar. Bricht bewusst nicht hart ab (allow_failure) - Funde landen
|
|
# als Artifact + Job-Log, die Bewertung bleibt menschlich. Lab-interne Images
|
|
# (desktop-build, windows-vm) brauchen erst CA-Trust im Trivy-Container - notiert
|
|
# in gitops#31 als Ausbaustufe.
|
|
trivy_scan:
|
|
stage: build
|
|
image:
|
|
name: aquasec/trivy:0.58.2
|
|
entrypoint: [""]
|
|
rules:
|
|
- if: $CI_PIPELINE_SOURCE == "schedule"
|
|
allow_failure: true
|
|
- if: $CI_COMMIT_BRANCH == "main"
|
|
when: manual
|
|
allow_failure: true
|
|
variables:
|
|
GIT_STRATEGY: none
|
|
TRIVY_NO_PROGRESS: "true"
|
|
script:
|
|
- trivy image --severity HIGH,CRITICAL --format table --output trivy-web.txt rohana.axion1337.de/sorb/threadnet-web:latest-ci
|
|
- grep -E "Total|CRITICAL|HIGH" trivy-web.txt | head -20 || true
|
|
artifacts:
|
|
paths:
|
|
- trivy-web.txt
|
|
expire_in: 30 days
|
|
when: always
|
|
|
|
web:
|
|
stage: build
|
|
image: node:24-bullseye
|
|
rules:
|
|
# Release-Tags bauen immer (docker_web/desktop_* brauchen web als needs)
|
|
- if: $CI_COMMIT_TAG =~ /^v/
|
|
# Scheduled Pipelines gehoeren dem trivy_scan - kein wochentlicher Leerbuild
|
|
- if: $CI_PIPELINE_SOURCE == "schedule"
|
|
when: never
|
|
# Pushes nur, wenn build-relevante Pfade betroffen sind - Doku-Commits kosten nichts
|
|
- if: $CI_COMMIT_BRANCH
|
|
# derselbe Anker wie im workflow-Block oben - zwei Listen wuerden driften
|
|
changes: *pfade_mit_pipeline
|
|
variables:
|
|
NODE_OPTIONS: "--max-old-space-size=6144"
|
|
CI_PACKAGE: "true"
|
|
before_script:
|
|
- corepack enable
|
|
script:
|
|
- pnpm install --frozen-lockfile
|
|
- cp apps/web/element.io/develop/config.json apps/web/config.json
|
|
- VERSION=$(scripts/get-version-from-git.sh) pnpm --dir apps/web build
|
|
artifacts:
|
|
paths:
|
|
- apps/web/webapp
|
|
expire_in: 1 day
|
|
|
|
# Baut das kanonische Web-Image (apps/web/Dockerfile, Kontext = Monorepo-Root) und pusht
|
|
# es in die rohana-Registry, aus der Flux/k8s zieht. Deploy bleibt ein manueller Tag-Bump
|
|
# im gitops-Repo. Bewusster Doppel-Build (webpack laeuft im web-Job UND im Dockerfile) -
|
|
# kanonisch/reproduzierbar vor schnell; Optimierung als Folgearbeit in Issue #2.
|
|
docker_web:
|
|
stage: package
|
|
image: docker:27-cli
|
|
needs:
|
|
- job: web
|
|
artifacts: false
|
|
rules:
|
|
# Nur bei Release-Tags (v*) - "releasen" ist ein bewusster Akt:
|
|
# Tag pushen -> Image entsteht -> Tag-Bump im gitops-Repo deployt es
|
|
- if: $CI_COMMIT_TAG =~ /^v/
|
|
variables:
|
|
IMAGE: rohana.axion1337.de/sorb/threadnet-web
|
|
DOCKER_BUILDKIT: "1"
|
|
script:
|
|
- echo "$REGISTRY_PASSWORD" | docker login rohana.axion1337.de -u "$REGISTRY_USER" --password-stdin
|
|
# Ein veroeffentlichtes Release darf sich nicht rueckwirkend aendern.
|
|
#
|
|
# Am 2026-08-09 hat das Force-Push umgezogener Tags (History-Anonymisierung)
|
|
# drei Release-Pipelines neu gestartet - darunter v0.4.0. Ohne diese Sperre
|
|
# haette der Lauf das laengst veroeffentlichte Image aus altem Code mit
|
|
# heutigen Basis-Images und Abhaengigkeiten neu gebaut und ueberschrieben.
|
|
# Dass es damals nicht passierte, lag nur daran, dass die geschuetzten
|
|
# Registry-Variablen in dem Moment nicht verfuegbar waren - Glueck, nicht
|
|
# Absicht (ThreadNet-Web#14).
|
|
#
|
|
# Ein Tag ist hier kein Verwaltungseintrag, sondern ein Build-Ausloeser. Wer
|
|
# einen Tag verschiebt, loest einen Build aus, ob er will oder nicht. Deshalb
|
|
# Unveraenderlichkeit erzwingen statt auf Vorsicht zu hoffen.
|
|
- |
|
|
if docker manifest inspect "$IMAGE:$CI_COMMIT_TAG" >/dev/null 2>&1; then
|
|
echo "FEHLER: $IMAGE:$CI_COMMIT_TAG existiert in der Registry bereits."
|
|
echo "Ein veroeffentlichtes Release wird nicht ueberschrieben."
|
|
echo "Gewollt? Dann das Image bewusst aus der Registry entfernen oder eine"
|
|
echo "neue Version taggen - siehe ThreadNet-Web#14."
|
|
exit 1
|
|
fi
|
|
- docker build -f apps/web/Dockerfile -t "$IMAGE:$CI_COMMIT_TAG" -t "$IMAGE:latest-ci" .
|
|
- docker push "$IMAGE:$CI_COMMIT_TAG"
|
|
# latest-ci bleibt bewusst ueberschreibbar - der Tag bezeichnet "der neueste
|
|
# Stand", nicht eine Version, und traegt deshalb kein Versprechen.
|
|
- docker push "$IMAGE:latest-ci"
|
|
|
|
# Einmalig/selten: Build-Image fuer den Desktop-Build (rust:bullseye + node + tcl/sqlcipher,
|
|
# aus apps/desktop/dockerbuild). Manuell ausloesen, wenn sich .node-version oder das
|
|
# Dockerfile aendert.
|
|
desktop_image:
|
|
stage: package
|
|
image: docker:27-cli
|
|
rules:
|
|
- if: $CI_COMMIT_BRANCH == "main"
|
|
when: manual
|
|
allow_failure: true
|
|
variables:
|
|
# Lab-Registry statt rohana (OVERMIND-01): Konsument ist nur die Lab-CI selbst
|
|
IMAGE: $CI_REGISTRY_IMAGE/desktop-build
|
|
script:
|
|
- echo "$CI_JOB_TOKEN" | docker login "$CI_REGISTRY" -u gitlab-ci-token --password-stdin
|
|
- docker build -f apps/desktop/dockerbuild/Dockerfile -t "$IMAGE:bullseye" apps/desktop
|
|
- docker push "$IMAGE:bullseye"
|
|
|
|
# Electron-Linux-Build (amd64, static sqlcipher) - repliziert den am 2026-07-29 manuell
|
|
# verifizierten Build-Weg. Automatisch bei Release-Tags, auf main manuell triggerbar.
|
|
desktop_linux:
|
|
stage: package
|
|
image: registry.git.lab/axion1337.chat/threadnet-web/desktop-build:bullseye
|
|
needs:
|
|
- job: web
|
|
artifacts: true
|
|
rules:
|
|
- if: $CI_COMMIT_TAG =~ /^v/
|
|
- if: $CI_COMMIT_BRANCH == "main"
|
|
when: manual
|
|
allow_failure: true
|
|
variables:
|
|
MAX_GLIBC: "2.31"
|
|
USE_HARD_LINKS: "false"
|
|
SQLCIPHER_BUNDLED: "1"
|
|
# Eigene Build-Variante: Produktname ThreadNet statt Element. Ohne das nutzt
|
|
# electron-builder element.io/release/build.json und die Pakete heissen weiter
|
|
# "element-desktop" (real passiert 2026-08-02).
|
|
VARIANT_PATH: axion1337/build.json
|
|
script:
|
|
- pnpm install --frozen-lockfile --filter element-desktop
|
|
- cp -r apps/web/webapp apps/desktop/webapp
|
|
# Produktions-Client-Config (getrackt seit diesem Commit, vorher nur im manuellen Build)
|
|
- cp apps/desktop/axion1337/config.json apps/desktop/webapp/config.json
|
|
- cd apps/desktop
|
|
- pnpm run asar-webapp
|
|
- pnpm run build:native
|
|
# pnpm/npm setzen beim Install kein Executable-Bit auf 7za - bekannter Fix,
|
|
# gleicher Schritt wie in der Upstream-CI ("Fix permissions")
|
|
- chmod +x ../../node_modules/7zip-bin/linux/*/7za || true
|
|
- pnpm run build --publish never -l tar.gz -l deb
|
|
artifacts:
|
|
paths:
|
|
- apps/desktop/dist/*.deb
|
|
- apps/desktop/dist/*.tar.gz
|
|
expire_in: 1 week
|
|
|
|
# Windows-Desktop-Build (x64, unsigniert - Signing siehe Issue #5). Laeuft NUR auf dem
|
|
# Windows-Runner (tags), manuell: vorher start_windows_vm ausloesen. Uebersetzt aus dem
|
|
# Upstream-Workflow build_desktop_windows.yaml (x64-Pfad; arm-only-Schritte entfallen).
|
|
desktop_windows:
|
|
stage: package
|
|
tags:
|
|
- windows
|
|
needs:
|
|
- job: web
|
|
artifacts: true
|
|
rules:
|
|
- if: $CI_COMMIT_TAG =~ /^v/
|
|
when: manual
|
|
allow_failure: true
|
|
- if: $CI_COMMIT_BRANCH == "main"
|
|
when: manual
|
|
allow_failure: true
|
|
variables:
|
|
SQLCIPHER_BUNDLED: "1"
|
|
ELECTRON_CACHE: C:\electron-cache
|
|
ELECTRON_BUILDER_CACHE: C:\eb-cache
|
|
# Eigene Build-Variante (Produktname ThreadNet) - siehe desktop_linux
|
|
VARIANT_PATH: axion1337/build.json
|
|
script:
|
|
- pnpm install --frozen-lockfile --filter element-desktop
|
|
# GitHub-CDN-Downloads (Electron-Binary, winCodeSign, NSIS) reissen im Gast
|
|
# reproduzierbar ab und app-builder kann nicht fortsetzen (Jobs 415/416/424) -
|
|
# das Skript laedt alles resumefaehig in die persistenten Caches vor.
|
|
- powershell -ExecutionPolicy Bypass -File apps\desktop\axion1337\prefetch-buildcache.ps1
|
|
- Copy-Item -Recurse apps/web/webapp apps/desktop/webapp
|
|
- Copy-Item apps/desktop/axion1337/config.json apps/desktop/webapp/config.json -Force
|
|
- cd apps/desktop
|
|
- pnpm run asar-webapp
|
|
- '& "C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\Common7\Tools\Launch-VsDevShell.ps1" -Arch amd64 -SkipAutomaticLocation'
|
|
- pnpm run build:native --target x86_64-pc-windows-msvc
|
|
- pnpm run build --publish never -w nsis
|
|
artifacts:
|
|
paths:
|
|
- apps/desktop/dist/*.exe
|
|
expire_in: 1 week
|
|
|
|
# Idempotente Werkzeug-Provisionierung im Windows-Gast (laeuft als SYSTEM ueber den
|
|
# Runner selbst - kein noVNC/RDP noetig). Hintergrund: choco akzeptiert --version nicht
|
|
# bei Mehrfach-Paketen, der urspruengliche Runbook-Einzeiler hat still nichts installiert.
|
|
# Startet am Ende den Runner-Dienst verzoegert neu, damit der neue PATH fuer
|
|
# Folge-Jobs greift (der Job selbst wird davon nicht mehr unterbrochen).
|
|
windows_provision:
|
|
stage: build
|
|
tags:
|
|
- windows
|
|
rules:
|
|
- if: $CI_COMMIT_BRANCH == "main"
|
|
when: manual
|
|
allow_failure: true
|
|
variables:
|
|
# Kein Checkout - der braeuchte git, das dieser Job erst installiert (Henne-Ei)
|
|
GIT_STRATEGY: none
|
|
script:
|
|
- choco install -y git
|
|
- choco install -y nasm
|
|
- choco install -y magicsplat-tcl-tk
|
|
- choco install -y nodejs --version=24.15.0
|
|
# Fuer den seshat-hak-Build (hak/matrix-seshat/check.ts): perl+patch (Strawberry
|
|
# liefert beides, patch.exe in C:\Strawberry\c\bin), python (node-gyp), rustc.
|
|
- choco install -y strawberryperl
|
|
- choco install -y python3
|
|
# Rust maschinenweit statt Benutzerprofil: der Runner-Dienst laeuft als SYSTEM und
|
|
# sieht nur die Maschinen-Umgebung - ein Default-rustup unter %USERPROFILE% waere
|
|
# fuer Jobs unsichtbar.
|
|
- $env:RUSTUP_HOME='C:\Rust\rustup'; $env:CARGO_HOME='C:\Rust\cargo'; Invoke-WebRequest -UseBasicParsing https://win.rustup.rs/x86_64 -OutFile "$env:TEMP\rustup-init.exe"
|
|
- '& "$env:TEMP\rustup-init.exe" -y --profile minimal --default-toolchain stable --default-host x86_64-pc-windows-msvc'
|
|
- '[Environment]::SetEnvironmentVariable(''RUSTUP_HOME'',''C:\Rust\rustup'',''Machine'')'
|
|
- '[Environment]::SetEnvironmentVariable(''CARGO_HOME'',''C:\Rust\cargo'',''Machine'')'
|
|
# choco-nasm traegt sich nicht selbst in den PATH ein (Upstream macht das auch
|
|
# explizit via GITHUB_PATH) - zusammen mit cargo\bin hier maschinenweit nachziehen
|
|
- $mp=[Environment]::GetEnvironmentVariable('Path','Machine'); if ($mp -notlike '*C:\Rust\cargo\bin*') { [Environment]::SetEnvironmentVariable('Path', "$mp;C:\Rust\cargo\bin;C:\Program Files\NASM", 'Machine') }
|
|
- refreshenv; corepack enable
|
|
- '& "C:\Program Files\Git\cmd\git.exe" --version'
|
|
- '& "C:\Program Files\nodejs\node.exe" --version'
|
|
- '& C:\Rust\cargo\bin\rustc.exe --version'
|
|
# Windows-260-Zeichen-Pfadlimit: die Visual-Baseline-Pfade des Monorepos sprengen
|
|
# MAX_PATH - beide Schalter noetig (git-seitig + OS-Policy)
|
|
- '& "C:\Program Files\Git\cmd\git.exe" config --system core.longpaths true'
|
|
- Set-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem' -Name LongPathsEnabled -Value 1 -Type DWord
|
|
# Dienst-Neustart als Scheduled Task: ueberlebt das Prozessbaum-Cleanup des Runners
|
|
# beim Job-Ende (der fruehere Start-Process-Trick wurde dabei gekillt und liess den
|
|
# Dienst gestoppt zurueck - Vorfall 2026-07-31, siehe ThreadNet-Web#5).
|
|
- schtasks /create /f /tn RunnerRestart /ru SYSTEM /sc once /st ((Get-Date).AddMinutes(1).ToString('HH:mm')) /tr "powershell -Command Restart-Service gitlab-runner -Force"
|