docs: Desktop-App — Update in der App (Handbücher, CI-Secrets, CHANGELOG)
- Anwenderhandbuch: Menüeintrag "Update installieren", Ablauf per Klick unter Windows/Linux, Fehlerfall, https-Bedingung, einmaliger Wechsel für Clients bis 1.2.0 - Betriebshandbuch Kap. 10: Signierschlüssel (Secrets, Ablage, Sicherung, Verlust), Kontrollzeile /desktop/update, Manifest-Felder, zwei Fehlerbilder - Entwicklungshandbuch: lokal `tauri build --no-sign`, Hinweise zu tauri dev - ci-cd-setup.md: die zwei neuen Secrets, Bau-Schritte signieren, Fehlerbild "no private key" - CHANGELOG: eine Zeile unter Unveröffentlicht → Neu Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -192,7 +192,7 @@ Schließen Sie das Fenster über das X, legt sich Tessera lediglich in den Infob
|
||||
- **Verbunden mit …** — zeigt grau den Tessera-Server, mit dem die App verbunden ist (nicht anklickbar)
|
||||
- **Öffnen**
|
||||
- **Server-Adresse ändern…** — siehe [Server-Adresse ändern](#server-adresse-ändern)
|
||||
- **Update herunterladen** — wird aktiv, sobald eine neue Version vorliegt (auf dem Beta-Kanal: „Neuen Beta-Stand herunterladen")
|
||||
- **Update installieren** — wird aktiv, sobald eine neue Version vorliegt, und heißt dann „Auf Version X.Y.Z aktualisieren" (auf dem Beta-Kanal: „Auf Beta-Stand … aktualisieren")
|
||||
- **Mit Windows starten** (unter Linux: **Beim Anmelden starten**) — mit Häkchen
|
||||
- **Beenden**
|
||||
|
||||
@@ -212,13 +212,23 @@ Setzen oder entfernen Sie das Häkchen bei „Mit Windows starten" (bzw. „Beim
|
||||
|
||||
### Neue Version
|
||||
|
||||
Ist eine neuere Version verfügbar, meldet sich die App beim Start mit „Neue Version X.Y.Z verfügbar". Der Menüeintrag „Update herunterladen" heißt dann „Version X.Y.Z herunterladen" und öffnet mit einem Klick die Seite Einstellungen → Desktop-App im Browser — dort laden Sie die neue Version herunter und installieren sie wie oben beschrieben. Ein automatisches Aktualisieren gibt es nicht.
|
||||
Beim Start (und nach einem Wechsel der Server-Adresse) prüft die App, ob Ihr Tessera-Server eine neuere Version hat. Ist das der Fall, meldet sie sich mit „Neue Version X.Y.Z verfügbar", und der Menüeintrag im Infobereich heißt „Auf Version X.Y.Z aktualisieren" (auf dem Beta-Kanal: „Auf Beta-Stand … aktualisieren").
|
||||
|
||||
Ein Klick auf diesen Eintrag genügt: Die App lädt das Paket im Hintergrund (der Fortschritt steht im Menü, etwa „Lädt … 42 %"), prüft, dass es unverändert von Ihrem Tessera-Server stammt, und installiert es. Unter Windows erscheint kurz das Installationsfenster mit einem Fortschrittsbalken, danach startet Tessera von selbst neu; die Server-Adresse bleibt erhalten, ebenso die Fensterposition (sie kann nach einem Update einmal auf den Standard zurückfallen). Unter Linux wird die Datei `Tessera-X.Y.Z.AppImage` an ihrem Speicherort ersetzt und die App startet neu — die Datei muss dafür an einem Ort liegen, an dem Sie schreiben dürfen (zum Beispiel in Ihrem Home-Ordner).
|
||||
|
||||
Schlägt das Update fehl, meldet die App den Grund und öffnet die Seite Einstellungen → Desktop-App im Browser. Dort laden Sie die neue Version herunter und installieren sie wie oben beschrieben.
|
||||
|
||||
Voraussetzung ist eine Server-Adresse, die mit `https` beginnt. Bei einer `http`-Adresse steht im Menü „Update nur über https möglich" — der Weg über den Browser bleibt.
|
||||
|
||||
**Einmaliger Wechsel:** Wer die Desktop-App in Version 1.2.0 oder älter installiert hat, lädt die nächste Version ein letztes Mal über den Browser herunter und installiert sie von Hand. Ab dann läuft das Aktualisieren über den Menüeintrag.
|
||||
|
||||
### Wenn etwas nicht klappt
|
||||
|
||||
- **„Unter dieser Adresse antwortet kein Tessera-Server"** — prüfen Sie die eingegebene Adresse; gemeint ist die Adresse, unter der Sie Tessera im Browser öffnen, nicht eine interne API-Adresse.
|
||||
- **Der Download-Link fehlt auf der Anmeldeseite** — der Server trägt derzeit keine Desktop-Pakete. Fragen Sie in diesem Fall Ihren Administrator.
|
||||
- **Windows zeigt die SmartScreen-Warnung** — das ist normal und erwartet, siehe [Installation unter Windows](#installation-unter-windows).
|
||||
- **„Update fehlgeschlagen"** — das Netz war kurz weg, das Paket kam unvollständig an oder stammt nicht von Ihrem eigenen Server. Nehmen Sie den Weg über den Browser, wie unter [Neue Version](#neue-version) beschrieben.
|
||||
- **Linux: Das Update meldet fehlende Schreibrechte** — legen Sie die AppImage-Datei in Ihren Home-Ordner und starten Sie sie von dort.
|
||||
|
||||
## Einen Fehler melden
|
||||
|
||||
|
||||
@@ -606,7 +606,10 @@ Kanal, Version, Dateinamen, Größen und Prüfsummen.
|
||||
|
||||
`publish` kopiert die fertigen Pakete in das API-Abbild nach
|
||||
`/app/desktop-dist/`, zusammen mit einer `manifest.json` (Version, Kanal,
|
||||
Dateinamen, Größen, Prüfsummen). Auf dem Beta-Kanal tragen die Dateinamen
|
||||
Dateinamen, Größen, Prüfsummen; seit der Update-Funktion zusätzlich
|
||||
`updateVersion` – die Form, die der Client vergleicht, `X.Y.Z` auf Live und
|
||||
`X.Y.Z-beta.g{commit}` auf Beta – sowie je Plattform die `signature` des
|
||||
Pakets). Auf dem Beta-Kanal tragen die Dateinamen
|
||||
zusätzlich den Suffix `-beta.{commit}`, zum Beispiel
|
||||
`Tessera-Setup-1.1.0-beta.742fb5c.exe` und
|
||||
`Tessera-1.1.0-beta.742fb5c.AppImage`; auf Live steht dort die reine Form
|
||||
@@ -617,14 +620,23 @@ Kontrolle auf dem Server:
|
||||
```bash
|
||||
docker compose exec api ls -l /app/desktop-dist
|
||||
curl -s https://{ihre-adresse}/api-proxy/desktop/latest
|
||||
curl -si "https://{ihre-adresse}/api-proxy/desktop/update?target=windows&arch=x86_64¤t=0.0.0&base=https://{ihre-adresse}"
|
||||
```
|
||||
|
||||
`ls -l` zeigt die abgelegten Dateien samt `manifest.json`; die `curl`-Abfrage
|
||||
liefert dieselben Angaben als JSON (Version, Kanal, je Plattform Dateiname,
|
||||
Größe, Prüfsumme und relative Download-Adresse) – das ist genau die Antwort,
|
||||
die auch die Anmeldeseite und die Einstellungsseite auswerten. Antwortet die
|
||||
Abfrage mit `404`, fehlt entweder das Verzeichnis oder das Manifest; die
|
||||
Web-Oberfläche blendet den Download-Link dann automatisch aus.
|
||||
`ls -l` zeigt die abgelegten Dateien samt `manifest.json`; die erste
|
||||
`curl`-Abfrage liefert dieselben Angaben als JSON (Version, Kanal, je
|
||||
Plattform Dateiname, Größe, Prüfsumme und relative Download-Adresse) – das
|
||||
ist genau die Antwort, die auch die Anmeldeseite und die Einstellungsseite
|
||||
auswerten. Antwortet die Abfrage mit `404`, fehlt entweder das Verzeichnis
|
||||
oder das Manifest; die Web-Oberfläche blendet den Download-Link dann
|
||||
automatisch aus.
|
||||
|
||||
Die zweite Kontrollzeile stellt die Frage, die der Desktop-Client beim Start
|
||||
stellt: `200` mit `version`, `url` und `signature` bedeutet, dass sich
|
||||
installierte Clients von diesem Server aktualisieren können; `204` bedeutet,
|
||||
dass für diese Plattform kein signiertes Paket vorliegt (zum Beispiel ein Stand
|
||||
vor September 2026 oder ein Bau ohne Schlüssel). Für Linux `target=linux`
|
||||
einsetzen.
|
||||
|
||||
### Release-Dateien in Gitea
|
||||
|
||||
@@ -635,6 +647,47 @@ vorhandene Datei gleichen Namens, statt einen zweiten Anhang anzulegen. Die am
|
||||
Release hinterlegte Datei ist byteidentisch mit der im Abbild ausgelieferten;
|
||||
die Prüfsumme (`sha256`) aus `manifest.json` gilt für beide gleichermaßen.
|
||||
|
||||
### Updates in der App und der Signierschlüssel
|
||||
|
||||
Seit September 2026 aktualisiert sich die Desktop-App per Klick im Menü des
|
||||
Infobereich-Symbols. Beim Start fragt sie `GET /api-proxy/desktop/update`
|
||||
und installiert ausschließlich Pakete, deren Signatur zu dem im Client
|
||||
hinterlegten öffentlichen Schlüssel passt – ein manipuliertes oder fremdes
|
||||
Paket wird abgelehnt, bevor irgendetwas installiert wird. Das ist die
|
||||
Vertrauensbasis der Update-Funktion, nicht die Prüfsumme im Manifest.
|
||||
|
||||
Der **private Schlüssel** liegt nicht im Repository. Er existiert an zwei
|
||||
Stellen:
|
||||
|
||||
- als Gitea-Secrets `TAURI_SIGNING_PRIVATE_KEY` und
|
||||
`TAURI_SIGNING_PRIVATE_KEY_PASSWORD` (Repository → Einstellungen → Actions →
|
||||
Secrets); nur die beiden `tauri build`-Schritte des Jobs `desktop` sehen
|
||||
sie, die Skripte kennen den Schlüssel nicht;
|
||||
- als Sicherung auf dem Entwicklungsrechner unter
|
||||
`~/.tessera/desktop-updater/` (`tessera-updater.key`, `password.txt` und
|
||||
der öffentliche Teil `tessera-updater.key.pub`).
|
||||
|
||||
**Sicherung:** Legen Sie die beiden Dateien zusätzlich an einem zweiten
|
||||
sicheren Ort ab. Geht der private Schlüssel verloren, können bereits
|
||||
installierte Clients kein Update mehr annehmen: Es muss ein neues
|
||||
Schlüsselpaar erzeugt (`pnpm --filter @tessera/desktop exec tauri signer
|
||||
generate -w <pfad>`), der öffentliche Teil in
|
||||
`apps/desktop/src-tauri/tauri.conf.json` unter `plugins.updater.pubkey`
|
||||
eingetragen und jeder Client einmal von Hand neu installiert werden.
|
||||
|
||||
Ohne die Secrets bricht der CI-Bau ab („A public key has been found, but no
|
||||
private key"). `tauri build --no-sign` ist ausschließlich für lokale Proben
|
||||
gedacht und im CI nicht vorgesehen – ein so gebautes Paket trägt keine
|
||||
Signatur, und der Update-Endpunkt antwortet dafür mit `204`.
|
||||
|
||||
Windows legt bei jedem Update einen Ordner `%TEMP%\Tessera-{Version}-updater-…`
|
||||
(rund 100 MB) an und räumt ihn nicht auf. Das ist kein Fehler; die Ordner
|
||||
können jederzeit gelöscht werden.
|
||||
|
||||
Der Client erlaubt Updates in der App nur über `https`. Anwender mit einer
|
||||
`http`-Adresse sehen im Menü den Hinweis „Update nur über https möglich" und
|
||||
nutzen weiterhin den Weg über den Browser.
|
||||
|
||||
### Umgebungsvariablen
|
||||
|
||||
Für die Desktop-Auslieferung ist keine neue Pflichtvariable nötig.
|
||||
@@ -652,3 +705,5 @@ Für die Desktop-Auslieferung ist keine neue Pflichtvariable nötig.
|
||||
| Client meldet „Unter dieser Adresse antwortet kein Tessera-Server" | Anwender hat die interne API-Adresse statt der Web-Adresse eingetragen, oder `/api-proxy` ist vom Client-Rechner aus nicht erreichbar | Die im Anwenderhandbuch beschriebene Adresse verwenden (dieselbe wie im Browser); Netzwerk-/Firewall-Erreichbarkeit der Web-Adresse prüfen. |
|
||||
| Windows zeigt die SmartScreen-Warnung | Erwartet – die App ist für den internen Gebrauch nicht signiert (D-09) | Kein Fehler; Anwenderhandbuch, Abschnitt „Installation unter Windows", beschreibt den Ablauf. |
|
||||
| Beta-Paket nennt einen älteren Commit als das laufende Abbild (Dateiname `-beta.<Commit>`, Einstellungen → Desktop-App) | Erwartet: Desktop-App seit diesem Commit unverändert, Pakete aus dem Zwischenspeicher übernommen (Abschnitt „Wann gebaut wird …") | Kein Fehler. Soll dennoch neu gebaut werden, genügt eine Änderung unter `apps/desktop/` im nächsten Push. |
|
||||
| Client meldet „Update fehlgeschlagen" | Download über den Proxy abgebrochen (Größengrenze/Zeitlimit, siehe zweite Zeile dieser Tabelle), oder die Signatur passt nicht – die Pakete stammen nicht aus dem CI-Bau mit dem aktuellen Schlüssel | Kontrollzeile `/api-proxy/desktop/update` (Abschnitt „Wo die Pakete im Abbild liegen"), den Pipeline-Lauf und die Proxy-Einstellungen prüfen. Der Anwender kommt über den Browser-Weg weiter. |
|
||||
| `/api-proxy/desktop/update` antwortet dauerhaft `204`, obwohl Pakete da sind | Manifest ohne `signature`/`updateVersion`: Pakete aus einem Bau vor der Update-Funktion oder mit `--no-sign` | Eine Änderung unter `apps/desktop/` pushen bzw. den Tag neu bauen lassen; im CI prüfen, dass die Secrets `TAURI_SIGNING_PRIVATE_KEY`/`_PASSWORD` gesetzt sind (Abschnitt „Updates in der App und der Signierschlüssel"). |
|
||||
|
||||
@@ -140,15 +140,31 @@ Version setzen und Linux-Paket bauen:
|
||||
|
||||
```bash
|
||||
sh .gitea/scripts/desktop-version.sh
|
||||
pnpm --filter @tessera/desktop exec tauri build --bundles appimage
|
||||
pnpm --filter @tessera/desktop exec tauri build --bundles appimage --no-sign
|
||||
```
|
||||
|
||||
`desktop-version.sh` schreibt die Version des letzten Freigabe-Tags in
|
||||
`tauri.conf.json`/`Cargo.toml` — die im Repository eingecheckten Versionsdateien
|
||||
sind nur eine Basislinie, nicht die tatsächliche Freigabeversion. Das fertige
|
||||
Paket liegt danach unter
|
||||
`apps/desktop/src-tauri/target/release/bundle/appimage/`. Um es wie die
|
||||
API es ausliefern würde einzusammeln:
|
||||
`apps/desktop/src-tauri/target/release/bundle/appimage/`.
|
||||
|
||||
**`--no-sign` ist lokal Pflicht.** Seit der Update-Funktion in der App
|
||||
verlangt `tauri build` den Signierschlüssel (Umgebungsvariable
|
||||
`TAURI_SIGNING_PRIVATE_KEY`), weil `bundle.createUpdaterArtifacts` und der
|
||||
öffentliche Schlüssel `plugins.updater.pubkey` in `tauri.conf.json` gesetzt
|
||||
sind — ohne Schlüssel bricht der Bau mit „A public key has been found, but no
|
||||
private key" ab. Mit `--no-sign` entsteht keine `.sig`-Datei;
|
||||
`desktop-collect.sh` warnt dann nur (Kanal `dev`) und lässt das Feld
|
||||
`signature` weg, und die API antwortet auf `GET /desktop/update` mit `204`.
|
||||
Der In-App-Update-Weg lässt sich lokal also nur mit dem echten Schlüssel
|
||||
durchspielen (Betriebshandbuch, Kapitel 10). Zwei Hinweise für `tauri dev`:
|
||||
Dort läuft die App ohne AppImage — den Update-Download (`download_and_install`)
|
||||
nie auslösen, er würde die Binary in `target/` überschreiben; die
|
||||
Versionsprüfung selbst ist im Debug-Bau auch gegen `http://localhost`
|
||||
erlaubt (das Plugin warnt nur, der Release-Bau lehnt `http` ab).
|
||||
|
||||
Um das Paket so einzusammeln, wie die API es ausliefern würde:
|
||||
|
||||
```bash
|
||||
sh .gitea/scripts/desktop-collect.sh --require linux
|
||||
|
||||
+31
-4
@@ -81,17 +81,27 @@ docker ps --filter name=gitea-runner
|
||||
### Gitea Secrets (fuer die CI-Pipeline)
|
||||
|
||||
In Gitea unter **Repository > Settings > Actions > Secrets** werden die Secrets
|
||||
fuer die Pipeline konfiguriert. Benoetigt wird genau eines:
|
||||
fuer die Pipeline konfiguriert. Benoetigt werden drei:
|
||||
|
||||
| Secret | Beschreibung |
|
||||
|--------|--------------|
|
||||
| `REGISTRY_TOKEN` | Gitea-Zugangstoken (Access Token) mit Schreibrecht auf Pakete (`package: write`) und zusaetzlich auf das Repository (`repository: write`, fuer Releases). Wird im Job `publish` fuer `docker login localhost:3002 --password-stdin` verwendet und im Release-Schritt ueber `env` als `GITEA_TOKEN` an `.gitea/scripts/publish-release.sh` gereicht -- nie als Argument. |
|
||||
| `TAURI_SIGNING_PRIVATE_KEY` | Inhalt der privaten Schluesseldatei des Tauri-Updaters (eine Base64-Zeile, erzeugt mit `tauri signer generate`). Wird ausschliesslich an den zwei `tauri build`-Schritten des Jobs `desktop` als `env` gesetzt; die Tauri-CLI signiert damit das AppImage und den Windows-Installer (`.sig` neben dem Bundle). Der oeffentliche Gegenpart steht in `apps/desktop/src-tauri/tauri.conf.json` (`plugins.updater.pubkey`). |
|
||||
| `TAURI_SIGNING_PRIVATE_KEY_PASSWORD` | Passwort zu diesem Schluessel; gleiche Stelle, gleicher Umfang. |
|
||||
|
||||
Das Token erscheint nie im Log: es wird per `--password-stdin` uebergeben und
|
||||
Gitea maskiert Secret-Werte in der Job-Ausgabe. Das Veroeffentlichungs-Skript
|
||||
`.gitea/scripts/publish-images.sh` kennt das Token nicht; der Login bleibt im
|
||||
Workflow.
|
||||
|
||||
Der Signierschluessel wird ebenfalls nie ausgegeben: die Skripte kennen ihn
|
||||
nicht (`desktop-collect.sh` prueft nur, OB die Variable gesetzt ist, um die
|
||||
Signatur zur Pflicht zu machen), nur die beiden Bau-Schritte sehen ihn --
|
||||
weder `pnpm install`, `apt-get`, `cargo install cargo-xwin` noch die
|
||||
Cache-Schritte. Die Sicherung des Schluessels ausserhalb der Pipeline
|
||||
(`~/.tessera/desktop-updater/` auf dem Entwicklungsrechner) beschreibt das
|
||||
Betriebshandbuch, Kapitel 10.
|
||||
|
||||
Der Push geht ueber `localhost:3002` (Gitea laeuft auf demselben Rechner wie der
|
||||
Runner), weil der Nginx Proxy Manager vor `git.vicolab.de` grosse Image-Blobs
|
||||
blockt. Das Pullen auf den Servern laeuft ueber `git.vicolab.de`
|
||||
@@ -180,10 +190,15 @@ sh .gitea/scripts/desktop-stamp.sh stamp`.
|
||||
(`cargo check`/`cargo clippy`, D-16), Bau des Linux-AppImage
|
||||
(`tauri build --bundles appimage`), dann des Windows-Installers per
|
||||
Cross-Bau (`tauri build --runner cargo-xwin --target
|
||||
x86_64-pc-windows-msvc --bundles nsis`).
|
||||
x86_64-pc-windows-msvc --bundles nsis`). Beide Bau-Schritte tragen die
|
||||
Secrets `TAURI_SIGNING_PRIVATE_KEY`/`_PASSWORD` als `env` und signieren
|
||||
die Bundles (quick-260917-kgc): die Tauri-CLI legt `.sig`-Dateien neben
|
||||
`-setup.exe` und `.AppImage` ab -- host-unabhaengig, also auch im
|
||||
Cross-Bau. Kein `--no-sign` im CI.
|
||||
6. **Pakete einsammeln** (`desktop-collect.sh --require linux,windows`) --
|
||||
schreibt `manifest.json` und schlaegt fehl, wenn eine der beiden Dateien
|
||||
fehlt.
|
||||
schreibt `manifest.json` (mit `updateVersion` und je Plattform der
|
||||
`signature` aus der `.sig`-Datei) und schlaegt fehl, wenn eine der beiden
|
||||
Dateien fehlt oder auf `main`/Tags eine `.sig` fehlt.
|
||||
7. **Uebergabe an `publish`** per `actions/cache/save@v4` mit dem Schluessel
|
||||
`desktop-dist-${{ gitea.sha }}` (ein neuer Schluessel je Commit, damit
|
||||
`publish` garantiert die Pakete des gerade gebauten Standes bekommt, nicht
|
||||
@@ -343,6 +358,18 @@ und einen Branch-Schutz fuer `live` anlegen (T-KU1-04).
|
||||
Speicherdruck `CARGO_BUILD_JOBS` (z. B. auf `4`) als Umgebungsvariable im
|
||||
Job setzen, um die parallele Uebersetzung zu drosseln.
|
||||
|
||||
### Job `desktop`: "A public key has been found, but no private key"
|
||||
|
||||
Die Tauri-CLI bricht den Bau ab, weil `plugins.updater.pubkey` in
|
||||
`tauri.conf.json` gesetzt ist, aber `TAURI_SIGNING_PRIVATE_KEY` in der
|
||||
Umgebung fehlt. Ursache sind fast immer fehlende oder umbenannte Secrets: in
|
||||
Gitea unter **Repository > Settings > Actions > Secrets** pruefen, ob
|
||||
`TAURI_SIGNING_PRIVATE_KEY` und `TAURI_SIGNING_PRIVATE_KEY_PASSWORD` unter
|
||||
genau diesen Namen existieren, und ob beide Bau-Schritte in `ci.yml` den
|
||||
`env`-Block tragen. Niemals `--no-sign` in `ci.yml` eintragen -- damit
|
||||
entstuenden unsignierte Pakete, die kein Client als Update annimmt
|
||||
(`desktop-collect.sh` bricht auf `main`/Tags ohne `.sig` ohnehin ab).
|
||||
|
||||
### `desktop` baut, obwohl nichts geaendert wurde -- oder uebernimmt trotz Aenderung
|
||||
|
||||
**Baut trotzdem:**
|
||||
|
||||
Reference in New Issue
Block a user