Ein Chart für ConvertX (C4illin/ConvertX), eine selbstgehostete Datei-Umwandlung mit Weboberfläche. Grundlage ist die docker-compose.yml aus der Upstream-Doku.
Dieser Text ist der freigegebene Plan; ein eigener Plan-Kommentar entfällt.
Verifizierte Fakten
Gegen die Registry und den Upstream-Quelltext geprüft, nicht aus der Erinnerung:
Abbild
ghcr.io/c4illin/convertx
Tags
versioniert vorhanden: v0.19.0 ist die neueste und trägt denselben Digest wie latest (sha256:8590a21a…). Daneben wandernde Tags latest, main und pr-<n>
Größe
1468 MiB komprimiert, davon eine Schicht mit 1354 MiB — LibreOffice, ImageMagick, ffmpeg, Calibre und weitere Werkzeuge stecken darin
kein USER — das Abbild startet als root. Das Dockerfile legt convertx mit uid/gid 1000 an
Daten
/app/data — Datenbank und Dateien
Der Entrypoint ist die entscheidende Stelle. Er läuft mit set -e, sorgt dafür, dass /home/convertx existiert und dem Zielbenutzer gehört, chownt /app/data rekursiv, wenn die Eigentümerschaft abweicht, und wechselt per gosu convertx, sobald PUID gesetzt ist. Als Nicht-Root scheitert er sofort, weil chown, usermod und gosu Root verlangen.
Entschieden
Non-root, unter Umgehung des Entrypoints. Das Chart setzt command auf bun run dist/src/index.js und startet als uid/gid 1000; fsGroup erledigt die Rechte am Volume — also genau das, was der Entrypoint per chown täte, nur von Kubernetes. Damit bleibt die Härtungs-Baseline des Repos intakt.
Das Risiko gehört benannt: Legt upstream später Logik in den Entrypoint — Migrationen etwa —, übergehen wir sie stillschweigend. Bei jedem App-Update ist der Entrypoint deshalb mitzulesen. Das gehört als Kommentar an die command-Stelle, nicht nur in diesen Text.
appVersion: v0.19.0, Chart 1.0.0+upv0.19.0.
Install-Test: ja, mit erhöhtem INSTALL_TIMEOUT. Rund fünf Minuten allein für den Pull (Vergleichswert vom Runner: 96 MB in 17,5 s). Das kostet in jedem PR, der das Chart ändert, und im Rundumtest — aber ein Chart, das als root startet und dessen Startweg wir umbauen, ist genau das, bei dem ein Laufzeitnachweis am meisten wert ist.
Beide Öffnungs-Schalter als Werte, Vorgabe false:ACCOUNT_REGISTRATION und ALLOW_UNAUTHENTICATED. Upstream warnt ausdrücklich davor, sie im Internet zu aktivieren; die Warnung gehört als Kommentar in values.yaml und in NOTES.txt.
Aufbau
StatefulSet, eine Kopie, Service, PVC unter /app/data (Datenbank und umgewandelte Dateien). scaleDown, replicas, strenges values.schema.json, null-sichere Fallbacks, additiver env-Block.
Ingress nach Standard, ingress.domain und ingress.clusterIssuer erforderlich, TLS-Secret tls-<release>-convertx-ingress.
Hochlade-Grenze: ConvertX kennt keine eigene Größenbeschränkung, also ist die proxy-body-size-Annotation des Ingress die einzige Grenze. Als Wert führen, großzügig vorgeben und den Zusammenhang kommentieren — nach dem Muster von outline, wo zwei Grenzen um Faktor zehn auseinanderlagen.
Secret:JWT_SECRET als OnePasswordItem (secrets.jwtSecretRef), mit required(). Ohne den Wert erzeugt die Anwendung bei jedem Start eine zufällige UUID — alle Sitzungen wären nach jedem Neustart ungültig. Feldname in NOTES.txt benennen.
HTTP_ALLOWED als Wert, Vorgabe false: Hinter unserem TLS-terminierenden Ingress spricht der Browser https, nur die Anwendung sieht http. Der Schalter ist nur nötig, wenn ohne TLS ausgeliefert wird — mit Kommentar, wie bei outlines forceHttps.
AUTO_DELETE_EVERY_N_HOURS als Wert (Vorgabe 24, 0 schaltet ab). Das entscheidet über Datenhaltung auf dem Volume und gehört sichtbar dokumentiert.
Härtung:readOnlyRootFilesystem: true, Capabilities weg, seccompProfile: RuntimeDefault im Pod-Kontext. Schreibpfade als emptyDir — mindestens /tmp und /home/convertx (LibreOffice und fontconfig brauchen ein beschreibbares HOME). Welche Pfade tatsächlich nötig sind, ist zu messen, nicht zu raten.
Ressourcen nach Konvention: Requests als Vorgabe, Limits berechnet, kein CPU-Limit. Umwandlungen sind lastintensiv; die Vorgaben sind zu begründen.
Renovate: eigener Block. Die wandernden Tags latest, main und pr-<n> müssen außerhalb des Musters bleiben — auf dem v-Präfix verankern, wie es ytdlp-web-player vormacht.
Was gemessen werden muss, nicht angenommen
Startet die Anwendung als uid 1000 ohne den Entrypoint? Das ist die eigentliche Wette dieses Charts. Scheitert es, ist der Rückfallweg root mit PUID=1000 als dokumentierte Abweichung — dann aber mit Beleg.
Welche Pfade müssen beschreibbar sein? Aus den tatsächlichen Fehlern ableiten, nicht vorsorglich emptyDirs streuen.
Antwortet / mit 2xx oder 3xx, und taugt es als Readiness-Probe? Es gibt keinen dokumentierten Health-Endpunkt. Was hinter dem Pfad steckt, ist am laufenden Dienst zu prüfen — nicht am Pfadnamen.
Wie lange dauert der Install-Test wirklich? Der Wert gehört in die PR-Beschreibung, weil er die Erwartung für den Rundumtest aus Gitea #52 verschiebt.
Wiring
publish-convertx.yml, Eintrag in change-app-version.yml, ci/convertx/ mit test-values.yaml und settings.env, Block in renovate.json5, README-Zeile, Wiki-Seite plus Eintrag in Charts und _Sidebar.
Ein Chart für **ConvertX** (`C4illin/ConvertX`), eine selbstgehostete Datei-Umwandlung mit Weboberfläche. Grundlage ist die `docker-compose.yml` aus der Upstream-Doku.
Dieser Text ist der freigegebene Plan; ein eigener Plan-Kommentar entfällt.
## Verifizierte Fakten
Gegen die Registry und den Upstream-Quelltext geprüft, nicht aus der Erinnerung:
| | |
|---|---|
| Abbild | `ghcr.io/c4illin/convertx` |
| Tags | versioniert vorhanden: **`v0.19.0`** ist die neueste und trägt **denselben Digest wie `latest`** (`sha256:8590a21a…`). Daneben wandernde Tags `latest`, `main` und `pr-<n>` |
| Größe | **1468 MiB komprimiert**, davon eine Schicht mit 1354 MiB — LibreOffice, ImageMagick, ffmpeg, Calibre und weitere Werkzeuge stecken darin |
| Form | `WORKDIR /app`, `ExposedPorts 3000/tcp`, `ENTRYPOINT ["/entrypoint.sh"]`, `CMD ["bun","run","dist/src/index.js"]`, kein deklariertes Volume |
| Benutzer | **kein `USER`** — das Abbild startet als root. Das Dockerfile legt `convertx` mit uid/gid 1000 an |
| Daten | `/app/data` — Datenbank und Dateien |
**Der Entrypoint ist die entscheidende Stelle.** Er läuft mit `set -e`, sorgt dafür, dass `/home/convertx` existiert und dem Zielbenutzer gehört, chownt `/app/data` rekursiv, wenn die Eigentümerschaft abweicht, und wechselt per `gosu convertx`, sobald `PUID` gesetzt ist. **Als Nicht-Root scheitert er sofort**, weil `chown`, `usermod` und `gosu` Root verlangen.
## Entschieden
1. **Non-root, unter Umgehung des Entrypoints.** Das Chart setzt `command` auf `bun run dist/src/index.js` und startet als uid/gid 1000; `fsGroup` erledigt die Rechte am Volume — also genau das, was der Entrypoint per `chown` täte, nur von Kubernetes. Damit bleibt die Härtungs-Baseline des Repos intakt.
**Das Risiko gehört benannt:** Legt upstream später Logik in den Entrypoint — Migrationen etwa —, übergehen wir sie stillschweigend. Bei jedem App-Update ist der Entrypoint deshalb mitzulesen. Das gehört als Kommentar an die `command`-Stelle, nicht nur in diesen Text.
2. **`appVersion: v0.19.0`**, Chart `1.0.0+upv0.19.0`.
3. **Install-Test: ja, mit erhöhtem `INSTALL_TIMEOUT`.** Rund fünf Minuten allein für den Pull (Vergleichswert vom Runner: 96 MB in 17,5 s). Das kostet in jedem PR, der das Chart ändert, und im Rundumtest — aber ein Chart, das als root startet und dessen Startweg wir umbauen, ist genau das, bei dem ein Laufzeitnachweis am meisten wert ist.
4. **Beide Öffnungs-Schalter als Werte, Vorgabe `false`:** `ACCOUNT_REGISTRATION` und `ALLOW_UNAUTHENTICATED`. Upstream warnt ausdrücklich davor, sie im Internet zu aktivieren; die Warnung gehört als Kommentar in `values.yaml` und in `NOTES.txt`.
## Aufbau
- **StatefulSet**, eine Kopie, Service, PVC unter `/app/data` (Datenbank **und** umgewandelte Dateien). `scaleDown`, `replicas`, strenges `values.schema.json`, null-sichere Fallbacks, additiver `env`-Block.
- **Ingress** nach Standard, `ingress.domain` und `ingress.clusterIssuer` erforderlich, TLS-Secret `tls-<release>-convertx-ingress`.
- **Hochlade-Grenze:** ConvertX kennt keine eigene Größenbeschränkung, also ist die `proxy-body-size`-Annotation des Ingress die **einzige** Grenze. Als Wert führen, großzügig vorgeben und den Zusammenhang kommentieren — nach dem Muster von outline, wo zwei Grenzen um Faktor zehn auseinanderlagen.
- **Secret:** `JWT_SECRET` als `OnePasswordItem` (`secrets.jwtSecretRef`), mit `required()`. Ohne den Wert erzeugt die Anwendung bei **jedem Start** eine zufällige UUID — alle Sitzungen wären nach jedem Neustart ungültig. Feldname in `NOTES.txt` benennen.
- **`HTTP_ALLOWED`** als Wert, Vorgabe `false`: Hinter unserem TLS-terminierenden Ingress spricht der Browser https, nur die Anwendung sieht http. Der Schalter ist nur nötig, wenn ohne TLS ausgeliefert wird — mit Kommentar, wie bei outlines `forceHttps`.
- **`AUTO_DELETE_EVERY_N_HOURS`** als Wert (Vorgabe 24, `0` schaltet ab). Das entscheidet über Datenhaltung auf dem Volume und gehört sichtbar dokumentiert.
- **Härtung:** `readOnlyRootFilesystem: true`, Capabilities weg, `seccompProfile: RuntimeDefault` im Pod-Kontext. Schreibpfade als emptyDir — mindestens `/tmp` und `/home/convertx` (LibreOffice und fontconfig brauchen ein beschreibbares HOME). **Welche Pfade tatsächlich nötig sind, ist zu messen, nicht zu raten.**
- **Ressourcen** nach Konvention: Requests als Vorgabe, Limits berechnet, kein CPU-Limit. Umwandlungen sind lastintensiv; die Vorgaben sind zu begründen.
- **Renovate:** eigener Block. Die wandernden Tags `latest`, `main` und `pr-<n>` müssen **außerhalb** des Musters bleiben — auf dem `v`-Präfix verankern, wie es `ytdlp-web-player` vormacht.
## Was gemessen werden muss, nicht angenommen
1. **Startet die Anwendung als uid 1000 ohne den Entrypoint?** Das ist die eigentliche Wette dieses Charts. Scheitert es, ist der Rückfallweg root mit `PUID=1000` als dokumentierte Abweichung — dann aber mit Beleg.
2. **Welche Pfade müssen beschreibbar sein?** Aus den tatsächlichen Fehlern ableiten, nicht vorsorglich emptyDirs streuen.
3. **Antwortet `/` mit 2xx oder 3xx, und taugt es als Readiness-Probe?** Es gibt keinen dokumentierten Health-Endpunkt. Was hinter dem Pfad steckt, ist am laufenden Dienst zu prüfen — nicht am Pfadnamen.
4. **Wie lange dauert der Install-Test wirklich?** Der Wert gehört in die PR-Beschreibung, weil er die Erwartung für den Rundumtest aus Gitea #52 verschiebt.
## Wiring
`publish-convertx.yml`, Eintrag in `change-app-version.yml`, `ci/convertx/` mit `test-values.yaml` und `settings.env`, Block in `renovate.json5`, README-Zeile, Wiki-Seite plus Eintrag in `Charts` und `_Sidebar`.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Ein Chart für ConvertX (
C4illin/ConvertX), eine selbstgehostete Datei-Umwandlung mit Weboberfläche. Grundlage ist diedocker-compose.ymlaus der Upstream-Doku.Dieser Text ist der freigegebene Plan; ein eigener Plan-Kommentar entfällt.
Verifizierte Fakten
Gegen die Registry und den Upstream-Quelltext geprüft, nicht aus der Erinnerung:
ghcr.io/c4illin/convertxv0.19.0ist die neueste und trägt denselben Digest wielatest(sha256:8590a21a…). Daneben wandernde Tagslatest,mainundpr-<n>WORKDIR /app,ExposedPorts 3000/tcp,ENTRYPOINT ["/entrypoint.sh"],CMD ["bun","run","dist/src/index.js"], kein deklariertes VolumeUSER— das Abbild startet als root. Das Dockerfile legtconvertxmit uid/gid 1000 an/app/data— Datenbank und DateienDer Entrypoint ist die entscheidende Stelle. Er läuft mit
set -e, sorgt dafür, dass/home/convertxexistiert und dem Zielbenutzer gehört, chownt/app/datarekursiv, wenn die Eigentümerschaft abweicht, und wechselt pergosu convertx, sobaldPUIDgesetzt ist. Als Nicht-Root scheitert er sofort, weilchown,usermodundgosuRoot verlangen.Entschieden
Non-root, unter Umgehung des Entrypoints. Das Chart setzt
commandaufbun run dist/src/index.jsund startet als uid/gid 1000;fsGrouperledigt die Rechte am Volume — also genau das, was der Entrypoint perchowntäte, nur von Kubernetes. Damit bleibt die Härtungs-Baseline des Repos intakt.Das Risiko gehört benannt: Legt upstream später Logik in den Entrypoint — Migrationen etwa —, übergehen wir sie stillschweigend. Bei jedem App-Update ist der Entrypoint deshalb mitzulesen. Das gehört als Kommentar an die
command-Stelle, nicht nur in diesen Text.appVersion: v0.19.0, Chart1.0.0+upv0.19.0.Install-Test: ja, mit erhöhtem
INSTALL_TIMEOUT. Rund fünf Minuten allein für den Pull (Vergleichswert vom Runner: 96 MB in 17,5 s). Das kostet in jedem PR, der das Chart ändert, und im Rundumtest — aber ein Chart, das als root startet und dessen Startweg wir umbauen, ist genau das, bei dem ein Laufzeitnachweis am meisten wert ist.Beide Öffnungs-Schalter als Werte, Vorgabe
false:ACCOUNT_REGISTRATIONundALLOW_UNAUTHENTICATED. Upstream warnt ausdrücklich davor, sie im Internet zu aktivieren; die Warnung gehört als Kommentar invalues.yamlund inNOTES.txt.Aufbau
/app/data(Datenbank und umgewandelte Dateien).scaleDown,replicas, strengesvalues.schema.json, null-sichere Fallbacks, additiverenv-Block.ingress.domainundingress.clusterIssuererforderlich, TLS-Secrettls-<release>-convertx-ingress.proxy-body-size-Annotation des Ingress die einzige Grenze. Als Wert führen, großzügig vorgeben und den Zusammenhang kommentieren — nach dem Muster von outline, wo zwei Grenzen um Faktor zehn auseinanderlagen.JWT_SECRETalsOnePasswordItem(secrets.jwtSecretRef), mitrequired(). Ohne den Wert erzeugt die Anwendung bei jedem Start eine zufällige UUID — alle Sitzungen wären nach jedem Neustart ungültig. Feldname inNOTES.txtbenennen.HTTP_ALLOWEDals Wert, Vorgabefalse: Hinter unserem TLS-terminierenden Ingress spricht der Browser https, nur die Anwendung sieht http. Der Schalter ist nur nötig, wenn ohne TLS ausgeliefert wird — mit Kommentar, wie bei outlinesforceHttps.AUTO_DELETE_EVERY_N_HOURSals Wert (Vorgabe 24,0schaltet ab). Das entscheidet über Datenhaltung auf dem Volume und gehört sichtbar dokumentiert.readOnlyRootFilesystem: true, Capabilities weg,seccompProfile: RuntimeDefaultim Pod-Kontext. Schreibpfade als emptyDir — mindestens/tmpund/home/convertx(LibreOffice und fontconfig brauchen ein beschreibbares HOME). Welche Pfade tatsächlich nötig sind, ist zu messen, nicht zu raten.latest,mainundpr-<n>müssen außerhalb des Musters bleiben — auf demv-Präfix verankern, wie esytdlp-web-playervormacht.Was gemessen werden muss, nicht angenommen
PUID=1000als dokumentierte Abweichung — dann aber mit Beleg./mit 2xx oder 3xx, und taugt es als Readiness-Probe? Es gibt keinen dokumentierten Health-Endpunkt. Was hinter dem Pfad steckt, ist am laufenden Dienst zu prüfen — nicht am Pfadnamen.Wiring
publish-convertx.yml, Eintrag inchange-app-version.yml,ci/convertx/mittest-values.yamlundsettings.env, Block inrenovate.json5, README-Zeile, Wiki-Seite plus Eintrag inChartsund_Sidebar.