feat(setup): Erstinstallation ueber den Update-Agent, Installationskonto, Downloads
Bisher gab es nur den Update-Weg: eine Anwendung musste bereits installiert und eingerichtet sein, damit sich etwas aktualisieren liess. Die Erstinstallation auf einem neuen System war Handarbeit - Paket kopieren, Konfiguration abtippen, Token besorgen. Setup-API (neu) - POST /api/setup/v1/login tauscht Benutzername und Passwort gegen ein Token mit 30 Minuten Gueltigkeit und ausschliesslich setup:install. Es wird nicht mitgeschrieben und lebt im Installer nur im Speicher. - GET /api/setup/v1/catalog zeigt nur, was zur Laufzeitkennung des anfragenden Systems passt. Ein Projekt mit ausschliesslich Windows-Paket taucht auf einem Linux-Rechner gar nicht erst auf. - POST /api/setup/v1/token stellt das Dauertoken der Anwendung aus. Welche Rechte vergeben werden, entscheidet der Server; die Anfrage kann nur einschraenken. Sonst waere der Umweg ueber ein kurzlebiges Token wirkungslos. Rollentrennung (Migration 012) - dc_users bekommt role, disabled und last_login_at. Die Rolle "installer" darf sich ueber den Setup-Weg anmelden und nicht am WebUI. Die Zugangsdaten werden auf jedem Zielsystem eingetippt; mit einem Administratorkonto verteilte man damit den Zugang zu Tokens, Lizenzen und Monitoren auf jeden Rechner, auf dem je etwas installiert wurde. - Auth::verifyCredentials() prueft sessionfrei, damit Setup- und WebUI-Login nicht zwei verschiedene Haertungsgrade haben (Drosselung, Timing-Angleichung, Rehash gelten fuer beide). - Konten mit hinterlegtem TOTP-Geheimnis werden am Setup-Weg mit 501 abgewiesen. Eine TOTP-Pruefung gibt es im Deploymentcenter noch nicht; sie stillschweigend zu uebergehen waere ein Rueckschritt. - Benutzerverwaltung im WebUI - es gab bisher gar keine, nur den einen von install_db.php angelegten Admin. Das letzte aktive Administratorkonto laesst sich weder deaktivieren noch loeschen. Installer - update-agent --action install fuehrt durch Anmeldung, Auswahl, Zielverzeichnis, Installation und Einrichtung. Die Dateien kommen ueber denselben Pfad wie ein Update - mit Pruefsumme, Signatur, Staging und Rollback. Ein zweiter Download-Weg waere ein zweiter Ort fuer dieselben Fehler. - --action configure holt die Einrichtung nachtraeglich. - setup.json im Paket beschreibt die benoetigten Werte. Bewusst im Paket und nicht zentral: so ist sie mit der Anwendung versioniert. - Gefragt wird nur, was uebrig bleibt: bereits gesetzt -> detect:... -> provision -> fragen. Platzhalter wie changeme oder <dein-wert> gelten dabei nicht als eingerichtet, sonst liefe die Anwendung mit der Vorlage los. - SetupWriter erhaelt vorhandene Inhalte. Eine appsettings.json fuehrt neben den abgefragten Werten meist Logging und anderes; sie neu zu erzeugen waere bequemer und verloere das - bei einer Neuinstallation ohne Backup. int und bool landen als JSON-Typ, nicht als Zeichenkette. Downloads - scripts/build_installer.ps1 baut selbstenthaltende Einzeldateien fuer win-x64, linux-x64 und linux-arm64 (rund 34 MB, .NET-Laufzeit inbegriffen). Ohne NativeAOT und ohne Trimming: Spectre.Console loest ueber Reflexion auf und braeche sonst erst beim Anwender. - scripts/upload_installer.py laedt sie nach /installer/. Getrennt von deploy.py, das client-dotnet bewusst ausklammert. - Bereich "Installer" auf der UpdateService-Seite mit Groessen, Pruefsummen und den wget-Befehlen; die Angaben stammen aus installer.json statt aus fest eingetragenem Text. - install.sh und install.ps1 laden, pruefen die Pruefsumme und legen ab - sie richten bewusst nichts selbst ein. Das Manifest wird BOM-frei geschrieben, sonst scheitert json_decode() daran. Enthaelt ausserdem die bislang nicht committete Arbeit an den RocketChat-Benachrichtigungen (Migrationen 010 und 011) sowie die Loesch- und Editierfunktion des UpdateService; die betroffenen Dateien liessen sich nicht getrennt stagen. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
2388b5abe1
commit
c8f3e78635
@@ -515,6 +515,154 @@ $spec = [
|
||||
],
|
||||
],
|
||||
|
||||
'/api/setup/v1/login' => [
|
||||
'post' => [
|
||||
'tags' => ['Setup'],
|
||||
'summary' => 'Anmelden und ein kurzlebiges Setup-Token holen',
|
||||
'description' =>
|
||||
"Ohne Token erreichbar - hier entsteht das Token erst.\n\n"
|
||||
. "Gedacht fuer Konten der Rolle `installer`, die sich ihrerseits **nicht** am "
|
||||
. "WebUI anmelden koennen. Die Zugangsdaten werden auf jedem Zielsystem "
|
||||
. "eingegeben; mit einem Administratorkonto verteilte man damit den Zugang zur "
|
||||
. "gesamten Verwaltung.\n\n"
|
||||
. "Das Token laeuft nach 30 Minuten ab, traegt nur `setup:install` und wird "
|
||||
. "nicht mitgeschrieben - es ist nach der Ausgabe nirgends mehr abrufbar.\n\n"
|
||||
. "Konten mit hinterlegtem TOTP-Geheimnis werden mit 501 abgewiesen: eine "
|
||||
. "TOTP-Pruefung gibt es noch nicht, und sie stillschweigend zu uebergehen "
|
||||
. "waere ein Rueckschritt.",
|
||||
'security' => [],
|
||||
'requestBody' => [
|
||||
'required' => true,
|
||||
'content' => ['application/json' => ['schema' => [
|
||||
'type' => 'object',
|
||||
'required' => ['username', 'password'],
|
||||
'properties' => [
|
||||
'username' => ['type' => 'string'],
|
||||
'password' => ['type' => 'string', 'format' => 'password'],
|
||||
'hostname' => ['type' => 'string', 'description' => 'Rechnername, erscheint im Token-Namen und im Protokoll.'],
|
||||
],
|
||||
]]],
|
||||
],
|
||||
'responses' => [
|
||||
'201' => [
|
||||
'description' => 'Angemeldet',
|
||||
'content' => ['application/json' => ['schema' => [
|
||||
'type' => 'object',
|
||||
'properties' => [
|
||||
'setup_token' => ['type' => 'string'],
|
||||
'expires_at' => ['type' => 'string', 'format' => 'date-time'],
|
||||
'expires_in' => ['type' => 'integer', 'example' => 1800],
|
||||
'scopes' => ['type' => 'array', 'items' => ['type' => 'string']],
|
||||
'role' => ['type' => 'string', 'enum' => ['admin', 'installer']],
|
||||
],
|
||||
]]],
|
||||
],
|
||||
'401' => $errorResponse,
|
||||
'429' => $errorResponse,
|
||||
'501' => $errorResponse,
|
||||
],
|
||||
],
|
||||
],
|
||||
|
||||
'/api/setup/v1/catalog' => [
|
||||
'get' => [
|
||||
'tags' => ['Setup'],
|
||||
'summary' => 'Installierbare Anwendungen fuer dieses System',
|
||||
'description' =>
|
||||
"Scope `setup:catalog`. Zeigt ausschliesslich, was zur angefragten "
|
||||
. "Laufzeitkennung passt - ein Projekt, von dem es nur ein Windows-Paket gibt, "
|
||||
. "taucht auf einem Linux-Rechner gar nicht erst auf.\n\n"
|
||||
. "Eine WebUI-Session wird hier bewusst **nicht** akzeptiert.",
|
||||
'parameters' => [
|
||||
['name' => 'platform', 'in' => 'query', 'schema' => ['type' => 'string', 'example' => 'win-x64'],
|
||||
'description' => 'Laufzeitkennung des Zielsystems. Ohne Angabe gelten nur Releases mit platform=any.'],
|
||||
],
|
||||
'responses' => [
|
||||
'200' => [
|
||||
'description' => 'Katalog',
|
||||
'content' => ['application/json' => ['schema' => [
|
||||
'type' => 'object',
|
||||
'properties' => [
|
||||
'platform' => ['type' => 'string'],
|
||||
'count' => ['type' => 'integer'],
|
||||
'projects' => [
|
||||
'type' => 'array',
|
||||
'items' => [
|
||||
'type' => 'object',
|
||||
'properties' => [
|
||||
'slug' => ['type' => 'string'],
|
||||
'name' => ['type' => 'string'],
|
||||
'notes' => ['type' => 'string', 'nullable' => true],
|
||||
'channels' => [
|
||||
'type' => 'array',
|
||||
'items' => [
|
||||
'type' => 'object',
|
||||
'properties' => [
|
||||
'channel' => ['type' => 'string'],
|
||||
'version' => ['type' => 'string'],
|
||||
'platform' => ['type' => 'string'],
|
||||
'size_bytes' => ['type' => 'integer'],
|
||||
'is_critical' => ['type' => 'boolean'],
|
||||
'signed' => ['type' => 'boolean'],
|
||||
'download_url' => ['type' => 'string'],
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
]]],
|
||||
],
|
||||
'401' => $errorResponse,
|
||||
],
|
||||
],
|
||||
],
|
||||
|
||||
'/api/setup/v1/token' => [
|
||||
'post' => [
|
||||
'tags' => ['Setup'],
|
||||
'summary' => 'Dauertoken fuer die eingerichtete Anwendung',
|
||||
'description' =>
|
||||
"Scope `setup:install`. Stellt das Token aus, mit dem die frisch installierte "
|
||||
. "Anwendung spaeter Heartbeats sendet und Fehler meldet.\n\n"
|
||||
. "**Welche Rechte vergeben werden, entscheidet der Server.** Die angefragten "
|
||||
. "`scopes` koennen nur einschraenken; erlaubt sind ausschliesslich "
|
||||
. "`watchdog:ping`, `watchdog:read`, `bugtracker:report` und "
|
||||
. "`updateservice:read`. Andernfalls waere der Umweg ueber ein kurzlebiges "
|
||||
. "Setup-Token wirkungslos - wer einmal installieren darf, stellte sich sonst "
|
||||
. "ein Token mit allen Rechten aus und behielte es.",
|
||||
'requestBody' => [
|
||||
'required' => true,
|
||||
'content' => ['application/json' => ['schema' => [
|
||||
'type' => 'object',
|
||||
'required' => ['project'],
|
||||
'properties' => [
|
||||
'project' => ['type' => 'string'],
|
||||
'scopes' => ['type' => 'array', 'items' => ['type' => 'string']],
|
||||
'hostname' => ['type' => 'string'],
|
||||
],
|
||||
]]],
|
||||
],
|
||||
'responses' => [
|
||||
'201' => [
|
||||
'description' => 'Token ausgestellt - wird nur einmal ausgeliefert',
|
||||
'content' => ['application/json' => ['schema' => [
|
||||
'type' => 'object',
|
||||
'properties' => [
|
||||
'token' => ['type' => 'string'],
|
||||
'project' => ['type' => 'string'],
|
||||
'scopes' => ['type' => 'array', 'items' => ['type' => 'string']],
|
||||
],
|
||||
]]],
|
||||
],
|
||||
'401' => $errorResponse,
|
||||
'403' => $errorResponse,
|
||||
'404' => $errorResponse,
|
||||
],
|
||||
],
|
||||
],
|
||||
|
||||
'/api/watchdog/v1/ping' => [
|
||||
'post' => [
|
||||
'tags' => ['Watchdog'],
|
||||
|
||||
Reference in New Issue
Block a user