Eine Roadmap statt neun verteilter Listen
Der Stand lag ueber eine Bestandsaufnahme, drei Konzeptpapiere, vier Umsetzungsplaene und zwei Deploymentcenter-Dokumente verteilt - jedes mit eigener Reihenfolge, teils widersprueglich. Alle offenen Punkte daraus sind in docs/Roadmap.md zusammengefuehrt. Aufbau der neuen Roadmap - Statusvokabular: erledigt / beschlossen-offen / Entscheidung noetig / zurueckgestellt / Idee. Damit steht das Geparkte sichtbar drin, statt in einem Konzeptpapier zu verschwinden. - Herkunft-Spalte traegt das alte Kuerzel (S4, K2, B9, T4, F-A1, C1, DC1), damit die archivierten Papiere auffindbar bleiben, ohne sie zu lesen. - Abschnitt 1 Reihenfolge, 2 offene Entscheidungen, 3 die Vorhaben nach Bereich, 4 Ideenspeicher, 5 Chronik des Erledigten, 6 Modell-Einstufung, 7 Herkunftskarte. Was dabei sichtbar wurde - Neun Entscheidungen blockieren Arbeit, ohne dass sie Aufwand kosten - allen voran Matrix oder Rocket.Chat. Sie stehen jetzt gesammelt in Abschnitt 2 statt verstreut in den Diskussionsteilen der Konzepte. - B8 (keine Tiefenbegrenzung bei AgentComm) ist unveraendert offen. Das ist keine Theorie: A haelt sein Gate, waehrend es auf B wartet - ruft B nun A, warten beide bis zum Timeout. Der Testfall A13 dafuer fehlt bis heute. - Die vier Umsetzungsplaene vom 2026-08-05 sind alle unumgesetzt und waren in keiner Roadmap verzeichnet. Archiv Sechs Dokumente ziehen nach docs/archiv/: Bestandsaufnahme, Konzepte Backup/Finanz/Analyse, Linux-Portierung-Analyse, Lizenz-HardwareId-v2 (gegenstandslos - LicenseLabrador ist ersetzt), Deploymentcenter-Review und der 2.4-Integrationsplan. Sie bleiben als Begruendung lesbar, werden aber nicht mehr fortgeschrieben; das README ordnet jedes einzeln ein und warnt, dass ihre Quelltext-Verweise ins Leere gehen koennen. Bauplan bleibt Bauplan Taskboard, Audit, Staging, Memory, Agentenkommunikation, RocketChat und Deploymentcenter-Integration bleiben in docs/ - sie sind die Detailvorgabe fuer die Umsetzung, nicht Vorhabenlisten. Jedes bekommt oben eine Zeile, die seine Rolle und den Umsetzungsstand nennt und auf die Roadmap zeigt. Dasselbe fuer die vier Umsetzungsplaene: die Reihenfolge gilt in der Roadmap, nicht im Plan. Nebenbei repariert: Taskboard-Konzept und Teststrategie verwiesen auf AgentScheduler und ToolJobScheduler, die seit der Scanner-Konsolidierung geloescht sind. Alle Dokument-Verweise in docs/ sind geprueft. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,308 @@
|
||||
# Deploymentcenter-Anbindung — Durchsicht
|
||||
|
||||
> **Nachtrag 2026-08-08 — die Anbindung ist umgestellt, Server und SDK stehen auf 2.1.**
|
||||
> Abschnitt 4 und 5 sind abgearbeitet; wie es jetzt aussieht, steht in
|
||||
> [Deploymentcenter-Integration](../Deploymentcenter-Integration.md).
|
||||
>
|
||||
> Mit **SDK 2.1 erledigt** (waren Befunde aus Abschnitt 3 bzw. aus der Durchsicht der
|
||||
> 2.0-Anbindung):
|
||||
>
|
||||
> - `HttpClient` ohne Zeitgrenze → intern 15 s. Unsere Umgehung (eigener Client mit
|
||||
> 8 s) ist zurückgebaut.
|
||||
> - HTTP 429/5xx entzogen die Lizenz, ohne den Zwischenspeicher zu befragen → jeder
|
||||
> Nicht-Erfolg führt jetzt in denselben Offline-Zweig, `IsTransient` macht den
|
||||
> Unterschied sichtbar. Unsere Behelfsprüfung auf `unknown_error` ist entfernt.
|
||||
> - `cache_ttl_hours` wurde ignoriert, die Gnadenfrist war faktisch unbegrenzt.
|
||||
> - `app_version` fest `"1.0.0"` → kommt jetzt aus `ReleaseInfo.Version`.
|
||||
> - `BuildInfo.targets` war nicht einbindbar (CS0433/CS0103) → erzeugt die Klasse im
|
||||
> eigenen Namensraum, ist eingebunden.
|
||||
> - `UpdateClient`: API-Zweig las snake_case in ein camelCase-Modell → eigenes Modell
|
||||
> `ApiReleaseInfo`, `is_critical` von der obersten Ebene.
|
||||
> - `DeactivateAsync` schickte den Shared Key zusätzlich als `X-Watchdog-Key`.
|
||||
> - Kein `CancellationToken` in der Lizenz-API.
|
||||
>
|
||||
> **Weiterhin offen** — betrifft das Deploymentcenter, nicht ClawdDotNet:
|
||||
>
|
||||
> - **2.1 (keine Signaturprüfung)** — unverändert. `LicenseInfo.PublicKeyBase64` ist
|
||||
> gestrichen, damit nichts Totes stehenbleibt und niemand Schutz vermutet, wo keiner
|
||||
> ist. Kommt die Signatur, kommt das Feld mit ihr zurück.
|
||||
> - **2.2 (v1-Ersatzhash)** und **2.3 (Klartext-Rückfall)** — unverändert, beides im
|
||||
> SDK zu beheben.
|
||||
> - **3 (HW-ID bei jedem Aufruf neu)** — clientseitig umgangen: einmal berechnet und
|
||||
> behalten.
|
||||
> - **`parent_source` ist nur eine `source`, kein Paar** — damit schließen sich „ein
|
||||
> Monitor je Instanz" und instanzweise Alarmunterdrückung gegenseitig aus.
|
||||
|
||||
Stand: 2026-08-06. Geprüft: `J:\Softwareprojekte\Deploymentcenter` (Client, Server,
|
||||
Schema, beide Integrationsleitfäden) gegen den
|
||||
[HW-ID-v2-Vorschlag](Lizenz-HardwareId-v2-Implementierungsvorschlag.md) und die
|
||||
[Linux-Analyse](Linux-Portierung-Analyse.md).
|
||||
|
||||
**Ergebnis vorweg: Die Lizenz blockiert den Linux-Umzug nicht mehr.** Alles, was
|
||||
an Hardware-ID v2 plattformrelevant war, ist da und richtig. Was hier steht, sind
|
||||
Punkte aus derselben Durchsicht — drei davon würden beim Ausrollen wehtun.
|
||||
|
||||
---
|
||||
|
||||
## 1. Was erledigt ist
|
||||
|
||||
| Punkt aus dem Vorschlag | Umsetzung |
|
||||
|---|---|
|
||||
| Format `2:<plattform>:<hex>` | [HardwareId.cs:125](../../../Deploymentcenter/client-dotnet/Deploymentcenter.Client/HardwareId.cs) |
|
||||
| **Kein `MachineName` im Hash** | `ComputeV2Hash`, `:138` — der wichtigste Punkt, sauber umgesetzt |
|
||||
| Quellenkette Windows/Linux | `:42–107`, inklusive `dmi-uuid` |
|
||||
| `IsPlausibleMachineId` (Länge, `uninitialized`, nur Nullen) | `:161` |
|
||||
| MAC-Filter über locally-administered-Bit | `:224` |
|
||||
| `/sys/class/net/<name>/device`-Prüfung | `:228` |
|
||||
| Erweiterte Stoppwortliste | `:23` — inkl. `br-`, `virbr`, `cni`, `cali` |
|
||||
| `machine.key` mit `0600` | `:290`, `SetUnixPermissions` mit `#if NET8_0_OR_GREATER` |
|
||||
| Vorgabe per Umgebungsvariable | `LicenseConfig.HardwareIdOverride`, beide Namen |
|
||||
| XDG-Auflösungskette, nie leerer Pfad | [LicenseConfig.cs:28](../../../Deploymentcenter/client-dotnet/Deploymentcenter.Client/LicenseConfig.cs), mit `ValidateNonEmpty` |
|
||||
| Mehrfachziel `netstandard2.0;net8.0` | csproj, BouncyCastle nur im netstandard-Zweig |
|
||||
| `LLS2`-Hülle, AES-GCM, HKDF | [StateStore.cs:169](../../../Deploymentcenter/client-dotnet/Deploymentcenter.Client/StateStore.cs) — Schlüssel aus HW-ID abgeleitet, bindet den Cache also echt an die Maschine |
|
||||
| `ILicensePrompt` + Konsolenfassung | vorhanden — genau das, was der kopflose Host braucht |
|
||||
| Servermigration v1→v2 | [LicenseService.php:108](../../../Deploymentcenter/src/Modules/License/LicenseService.php), mit Prüfprotokolleintrag `hwid_migrated` |
|
||||
| Schema `hwid_version`/`hwid_source`/`platform` | `sql/migrations/v2_hardware_id.sql`, rückwärtskompatibel |
|
||||
| Verwaltungsansicht zeigt Quelle/Plattform | `public/index.php:1227` |
|
||||
|
||||
`OperatingSystemHelpers` nutzt jetzt `RuntimeInformation`. Der Client hat auf dem
|
||||
Linux-Pfad keine Windows-Laufzeitabhängigkeit — `ProtectedData` wird nur unter
|
||||
`IsWindows()` aufgerufen.
|
||||
|
||||
**Für die Portierung heißt das:** Punkt 4 aus der Entscheidungsliste der
|
||||
Linux-Analyse („Erlaubt LicenseLabrador den Wechsel der Hardware-ID?") ist
|
||||
beantwortet. Der Aufwandsblock „Lizenz" schrumpft von 3–5 PT auf **2–3 PT** —
|
||||
das ist jetzt reine Anschlussarbeit in ClawdDotNet, keine Konzeptarbeit mehr.
|
||||
|
||||
---
|
||||
|
||||
## 2. Drei Befunde, die vor dem Ausrollen geklärt sein sollten
|
||||
|
||||
### 2.1 Es wird nichts signiert — die Lizenzprüfung ist eine Vertrauensfrage an DNS
|
||||
|
||||
[LicenseClient.cs:62](../../../Deploymentcenter/client-dotnet/Deploymentcenter.Client/LicenseClient.cs):
|
||||
|
||||
```csharp
|
||||
string status = root.TryGetProperty("status", out var sProp) ? sProp.GetString() ?? "unknown" : "unknown";
|
||||
if (status.Equals("valid", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
// → gültig
|
||||
}
|
||||
```
|
||||
|
||||
Das ist die vollständige Prüfung. Es gibt im neuen Client **kein `Signature.cs`,
|
||||
keinen hinterlegten öffentlichen Schlüssel, keine Hüllenprüfung** — die Dateien
|
||||
`Signature.cs`, `LicenseResult.cs` und `LicenseState.cs` aus dem alten
|
||||
LicenseLabrador-SDK sind beim Umzug nicht mitgekommen.
|
||||
|
||||
Folge: Wer die HTTP-Anfrage umlenken kann, hat eine gültige Lizenz. Ein Eintrag
|
||||
in `/etc/hosts`, ein Proxy, ein eigener DNS — die Antwort `{"status":"valid"}`
|
||||
genügt. Auf einem Linux-Server, den der Betreiber ohnehin vollständig
|
||||
kontrolliert, ist das kein Kunststück.
|
||||
|
||||
Serverseitig sieht es passend dazu aus. `public/index.php:45`:
|
||||
|
||||
```php
|
||||
'signature' => 'ED25519_SIG_' . base64_encode(hash('sha256', $lic['license_key'] . 'DC_OFFLINE_SECRET', true))
|
||||
```
|
||||
|
||||
Das ist ein SHA-256 über den Lizenzschlüssel plus eine fest verdrahtete
|
||||
Zeichenkette — keine Signatur, sondern ein Wert, der jeder erzeugen kann, der den
|
||||
Quelltext kennt. Und `public/index.php:1993` im JavaScript:
|
||||
|
||||
```javascript
|
||||
"ED25519_SIG_" + btoa(key + hwId).substring(0, 32)
|
||||
```
|
||||
|
||||
Base64 der Eingabe, abgeschnitten. Auch kein Hash.
|
||||
|
||||
Das ist erkennbar ein Platzhalter — nur trägt er einen Namen, der nach fertigem
|
||||
Verfahren klingt, und darauf verlässt sich [LicenseGate](Services/LicenseGate.cs)
|
||||
mit seiner harten Startsperre. **Es ist keine Portierungsfrage** (unter Windows
|
||||
gilt heute dasselbe) und auch kein Grund, den Linux-Umzug aufzuhalten — aber es
|
||||
sollte eine bewusste Entscheidung sein und nicht in dem Glauben untergehen, die
|
||||
Signaturprüfung sei bereits da.
|
||||
|
||||
Wenn das Verfahren zurückkommen soll: Ed25519 über die kanonisch serialisierte
|
||||
Antwort, öffentlicher Schlüssel im Client einkompiliert, `nonce` aus der Anfrage
|
||||
in der signierten Nutzlast gegenprüfen (gegen Wiedereinspielung). Der alte
|
||||
`Signer.php` und `Signature.cs` sind im LicenseLabrador-Repo noch vorhanden und
|
||||
lassen sich als Vorlage nehmen.
|
||||
|
||||
### 2.2 Der v1-Ersatzhash trifft die alten Aktivierungen nicht
|
||||
|
||||
Der Migrationsweg ist auf beiden Seiten korrekt gebaut — er wird nur nie
|
||||
auslösen, weil der Client eine andere v1-ID berechnet als die, die in der
|
||||
Datenbank steht.
|
||||
|
||||
Alt ([LicenseLabrador/HardwareId.cs:20](../../../LicenseLabrador/client-dotnet/LicenseLabrador.Client/HardwareId.cs)):
|
||||
|
||||
```csharp
|
||||
rawBuilder.Append(machineId); // MachineGuid, sonst MAC
|
||||
rawBuilder.Append(Environment.MachineName); // direkt angehängt, kein Trenner
|
||||
→ sha256(machineGuid + machineName)
|
||||
```
|
||||
|
||||
Neu ([HardwareId.cs:149](../../../Deploymentcenter/client-dotnet/Deploymentcenter.Client/HardwareId.cs)):
|
||||
|
||||
```csharp
|
||||
string raw = $"{Environment.MachineName}:{firstMac}";
|
||||
→ sha256(machineName + ":" + mac)
|
||||
```
|
||||
|
||||
Andere Reihenfolge, anderer Trenner, und **MAC statt MachineGuid**. Auf jedem
|
||||
Windows-Rechner, auf dem `MachineGuid` lesbar war — also praktisch allen —
|
||||
stimmen die Hashes nicht überein. Der Server sucht die Altaktivierung, findet
|
||||
nichts und legt eine neue an: **genau der Platzverbrauch, den die Migration
|
||||
verhindern sollte.** Bei `max_activations = 2` ist danach ein Platz für den
|
||||
Linux-Server weniger da.
|
||||
|
||||
Auch `GetFirstPhysicalMacLegacy` (`:254`) weicht ab: keine Stoppwortfilterung,
|
||||
keine Sortierung, erste Schnittstelle in Aufzählungsreihenfolge. Die alte
|
||||
Fassung nahm die alphabetisch erste *gefilterte* MAC.
|
||||
|
||||
Zu tun: `GetLegacyHardwareId()` muss den v1-Algorithmus zeichengenau
|
||||
nachbilden — inklusive der alten Stichwortliste (`virtual`, `veth`, `docker`,
|
||||
`hyper-v`, `wsl`, `mullvad`, `wireguard`, `tap`, `tun`, `vpn`, `bluetooth`,
|
||||
`vmware`, `box`, `pseudo`, `loopback`, `npcap`, `pcap`), `OrderBy(…, Ordinal)`
|
||||
und `FirstOrDefault()`. Der Code steht im LicenseLabrador-Repo noch da und kann
|
||||
weitgehend übernommen werden.
|
||||
|
||||
Am besten mit einem Test absichern, der einen bekannten Eingabewert gegen den
|
||||
erwarteten v1-Hash prüft — sonst fällt eine Abweichung erst auf, wenn die
|
||||
Aktivierungsplätze schon verbraucht sind.
|
||||
|
||||
### 2.3 Der Klartext-Rückfall ist noch da, nur woanders
|
||||
|
||||
[StateStore.cs:79](../../../Deploymentcenter/client-dotnet/Deploymentcenter.Client/StateStore.cs) —
|
||||
„Legacy Migration Check":
|
||||
|
||||
```csharp
|
||||
string legacyJson = Encoding.UTF8.GetString(payloadBytes);
|
||||
var legacyData = JsonSerializer.Deserialize<LocalCacheData>(legacyJson);
|
||||
if (legacyData != null)
|
||||
{
|
||||
legacyData.SchemaVersion = 2;
|
||||
Save(productSlug, hardwareId, legacyData);
|
||||
return legacyData;
|
||||
}
|
||||
```
|
||||
|
||||
Der LLS2-Zweig darüber ist genau richtig — Entschlüsselung fehlgeschlagen heißt
|
||||
Cache-Fehltreffer, kein Klartext. Der Zweig darunter hebt das wieder auf: Jede
|
||||
Datei ohne `LLS2`-Kennung wird als JSON gelesen und, wenn sie sich deserialisieren
|
||||
lässt, **übernommen und anschließend verschlüsselt neu geschrieben**.
|
||||
|
||||
Durchgespielt: Eine von Hand angelegte `state.dat` mit
|
||||
|
||||
```json
|
||||
{"SchemaVersion":2,"Status":"valid","ExpiresAt":99999999999,"MaxSeenTime":0}
|
||||
```
|
||||
|
||||
wird angenommen. In `ValidateAsync` greift bei fehlender Verbindung der
|
||||
Cache-Zweig (`:110`): `Status == "valid"` ✓, `now < MaxSeenTime` ✗, `now >
|
||||
ExpiresAt` ✗ → **`IsValid = true`**. Die Bindung an die Hardware, die
|
||||
`DeriveKey(hardwareId, …)` sonst herstellt, ist auf diesem Weg umgangen; die
|
||||
Datei ist zwischen Maschinen übertragbar.
|
||||
|
||||
Der Zweig hilft dabei nicht einmal beim eigentlichen Zweck. Die alte
|
||||
`LocalCacheData` hieß `last_envelope`, `max_seen_time`, `endpoints`,
|
||||
`last_license_key`; die neue `SchemaVersion`, `Status`, `ExpiresAt`, … Kein
|
||||
gemeinsames Feld, und `JsonSerializer` ist ohne
|
||||
`PropertyNameCaseInsensitive`/`JsonPropertyName` bei den Namen streng. Eine echte
|
||||
v1-Datei ergibt also ein Objekt mit lauter Vorgabewerten (`Status = "invalid"`)
|
||||
und ist als Cache wertlos.
|
||||
|
||||
**Empfehlung: den Zweig ersatzlos streichen.** Er kostet Sicherheit und leistet
|
||||
nichts. Alte Cachedateien sollen verworfen werden — eine einmalige
|
||||
Online-Prüfung ist der ganze Preis.
|
||||
|
||||
Nebenbei: `Checksum = hwInfo.HardwareId` ([LicenseClient.cs:79](../../../Deploymentcenter/client-dotnet/Deploymentcenter.Client/LicenseClient.cs))
|
||||
ist keine Prüfsumme, sondern eine Kopie der HW-ID. Das Feld ist damit ohne
|
||||
Funktion — entweder mit einem HMAC über die übrigen Felder füllen oder entfernen,
|
||||
damit niemand später Schutz vermutet, wo keiner ist.
|
||||
|
||||
---
|
||||
|
||||
## 3. Kleinere Punkte
|
||||
|
||||
| Fundstelle | Sache |
|
||||
|---|---|
|
||||
| [LicenseClient.cs:26](../../../Deploymentcenter/client-dotnet/Deploymentcenter.Client/LicenseClient.cs) | Eigener `HttpClient` je Instanz, nie freigegeben, **ohne Zeitgrenze** (Vorgabe 100 s). Der alte `LicenseConfig.HttpTimeout` war 6 s. In `LicenseGate.RunStartupCheck` bedeutet das bis zu 100 s Standbild beim Start, wenn der Server nicht antwortet. |
|
||||
| `:107` | `catch (Exception ex)` um den gesamten Block: Auch ein Fehler beim Auswerten einer *erfolgreichen* Antwort landet im Offline-Zweig. Ein defekter Server gilt dann als „offline". |
|
||||
| `:47` | `app_version = "1.0.0"` fest verdrahtet. ClawdDotNet hat `BuildInfo.Build` — sollte Parameter sein, sonst steht in der Verwaltungsansicht bei jeder Instanz dasselbe. |
|
||||
| `:32`, `:172` | `HardwareId.GetHardwareId()` bei jedem Aufruf neu: liest unter Linux Dateien und zählt Netzwerkschnittstellen auf. Einmal berechnen und halten. |
|
||||
| `HardwareId.cs:205` | MAC-Auswahl überspringt Schnittstellen, die nicht `Up` oder `Unknown` sind. Ein Kabel, das beim Start nicht steckt, ändert damit die Hardware-ID. Für die Ausweichlösung sollte der Betriebszustand keine Rolle spielen — sonst ist sie genau in dem Moment instabil, in dem sie gebraucht wird. |
|
||||
| `HardwareId.cs:231` | `/sys/class/net/<name>/device` ist ein Symlink. `Directory.Exists`/`File.Exists` folgen ihm — funktioniert, ist aber Zufall und sollte kommentiert sein. |
|
||||
|
||||
---
|
||||
|
||||
## 4. Watchdog: die Anbindung passt noch nicht
|
||||
|
||||
Kein Linux-Thema, fällt aber in dieselbe Umbauarbeit.
|
||||
|
||||
[WatchdogClient.cs](src/ClawdDotNet.Core/Watchdog/WatchdogClient.cs) sendet an:
|
||||
|
||||
| ClawdDotNet | Deploymentcenter |
|
||||
|---|---|
|
||||
| `POST /api/heartbeat` | `POST /api/watchdog/v1/ping` (nimmt auch `/heartbeat`) |
|
||||
| `POST /api/event` | `POST /api/watchdog/v1/event` |
|
||||
| `POST /api/register` | **existiert nicht** |
|
||||
|
||||
Die Pfade sind also alle um `/watchdog/v1` zu ergänzen. Der Kopfzeilenname passt:
|
||||
`public/api/watchdog/v1/index.php:30` akzeptiert `X-Watchdog-Key`,
|
||||
`Authorization` und `X-Agent-Token`.
|
||||
|
||||
Der Selbstregistrierungsweg aus [Program.cs:334](Program.cs:334) — mit dem
|
||||
Master-Token einen eigenen Agent-Token holen und in der Instanzkonfiguration
|
||||
zwischenspeichern — hat serverseitig kein Gegenstück mehr. Zu klären: Tokens
|
||||
künftig von Hand in der Verwaltung anlegen und in die Instanzkonfiguration
|
||||
eintragen, oder `/register` im Deploymentcenter nachziehen. Für den ersten Weg
|
||||
spricht, dass er den Master-Token gar nicht erst auf die Instanzen verteilt.
|
||||
|
||||
Die Feldnamen des Ping-Rumpfs (`source`, `instance`, `type`, `status`, `message`,
|
||||
`interval`, `group`, `os`) sind gegen
|
||||
[InstanceHealthProvider](src/ClawdDotNet.Core/Watchdog/InstanceHealthProvider.cs)
|
||||
abzugleichen.
|
||||
|
||||
---
|
||||
|
||||
## 5. Was in ClawdDotNet zu tun ist
|
||||
|
||||
| Datei | Was |
|
||||
|---|---|
|
||||
| [ClawdDotNet.csproj](ClawdDotNet.csproj) | Projektverweis von `..\LicenseLabrador\client-dotnet\…` auf `..\Deploymentcenter\client-dotnet\Deploymentcenter.Client\…` umhängen. Langfristig als Submodul unter `external/` — der Kommentar dazu steht schon im csproj. |
|
||||
| [Services/LicenseGate.cs](Services/LicenseGate.cs) | Neu gegen `LicenseValidationResult` schreiben. `LicenseState` gibt es nicht mehr, `Status` ist jetzt eine Zeichenkette — `DescribeProblem` (`:125`) muss auf `revoked`/`expired`/`activation_limit`/`not_found` umgestellt werden. `MessageBox` durch `ILicensePrompt` ersetzen; die Konsolenfassung bringt der Client mit. |
|
||||
| [Services/LicenseInfo.cs](Services/LicenseInfo.cs) | `PublicKeyBase64` hat ohne Signaturprüfung keine Funktion mehr — entweder mit 2.1 zurückholen oder streichen, damit nichts Totes stehenbleibt. |
|
||||
| [Program.cs:112](Program.cs:112) | Lizenzprüfung so verlagern, dass sie ohne Fenster auskommt (kopfloser Host). |
|
||||
| Host (neu) | `--license-status`, `--license-set-key`, `--license-deactivate` — der Client bringt alles Nötige mit. |
|
||||
| [WatchdogClient.cs](src/ClawdDotNet.Core/Watchdog/WatchdogClient.cs) | Pfade auf `/api/watchdog/v1/…`; Registrierungsweg klären (Abschnitt 4). |
|
||||
| `docs/Integrationsplan-WatchDog-LicenseLabrador.md` | Abgelöst durch [Deploymentcenter-Integration](../Deploymentcenter-Integration.md). |
|
||||
|
||||
---
|
||||
|
||||
## 6. Antwort auf die Ausgangsfrage
|
||||
|
||||
**Ja — Avalonia und Linux sind damit machbar.** Die einzige Frage, die ich als
|
||||
möglicher Blocker außerhalb unserer Hand markiert hatte, ist geklärt: Der Client
|
||||
läuft auf beiden Plattformen, zielt auf `net8.0` (von net10.0 problemlos
|
||||
verwendbar), löst seinen Ablageort auch ohne `HOME` auf, und die HW-ID ist
|
||||
container- und umbenennungsfest.
|
||||
|
||||
Der Lizenzblock in der Aufwandsschätzung fällt von 3–5 PT auf **2–3 PT**. Die
|
||||
Gesamtspanne bleibt bei **50–80 PT**, weil die Lizenz nie der große Posten war —
|
||||
das sind PropertyGrid und Chat-Ansicht.
|
||||
|
||||
Zwei Dinge sollten aber vor dem Ausrollen erledigt sein, unabhängig von Linux:
|
||||
|
||||
- **2.2 (v1-Ersatzhash)** — klein, aber wenn es beim Ausrollen falsch ist, sind
|
||||
Aktivierungsplätze verbraucht und man bekommt sie nur einzeln über die
|
||||
Verwaltung zurück. Das ist der Punkt mit dem schlechtesten Verhältnis von
|
||||
Aufwand zu Schaden.
|
||||
- **2.3 (Klartext-Rückfall)** — eine Zeile weniger Code, dafür wieder das
|
||||
Verhalten, das der `LLS2`-Umbau eigentlich herstellen sollte.
|
||||
|
||||
**2.1 (keine Signaturprüfung)** ist eine eigene Entscheidung mit eigenem Umfang
|
||||
und hält den Umzug nicht auf. Sie sollte nur getroffen und nicht übersehen
|
||||
werden — der Name `ED25519_SIG_` im Serverquelltext legt sonst nahe, dass die
|
||||
Sache erledigt sei.
|
||||
Reference in New Issue
Block a user