feat(settings): hub auth-policy panel — T4/T5 security parity in the GUI
Some checks failed
Security / Security check (push) Failing after 1s

Settings → Security now shows the hub's effective auth policy via the
new read-only AuthStatus RPC: active token validator (static / jwt-rs256
with issuer, audience, JWKS source), anonymous-access warning, per-token
cards with scope grants, env-var presence and rate limits, plus a
localized admin-denied story for non-admin tokens. Live-reloads on
endpoint change.

Also fixes a batch of fai→chain rename leftovers this panel's
verification uncovered: hub_auth_token.dart and registry_token.dart
read/wrote ~/.fai/ while the hub reads ~/.chain/ (stored registry
tokens never reached the hub), today_story_loader + tools/today used
~/.fai/today, chain_log legacy ~/.fai/logs migration removed per the
no-legacy-recognisers decision, and UI strings still advertised the
retired .fai bundle extension.

Includes 5 widget tests for the panel, an integration-test screenshot
harness (auth_policy_shots_test.dart, guide-shots style), and DE+EN
l10n. flutter analyze clean, 58 tests green.

Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
This commit is contained in:
flemming-it 2026-07-15 03:19:33 +02:00
parent c6da5025ce
commit efaa089454
18 changed files with 1208 additions and 74 deletions

View file

@ -804,7 +804,7 @@
}
},
"registryCredentialsHeader": "REGISTRY-ZUGANGSDATEN",
"registryCredentialsBlurb": "Token zum Herunterladen von .fai-Modulen aus einer Registry mit Anmeldepflicht (Forgejo, private GitHub-Repos). Gespeichert in ~/.chain/registry-token, Modus 0600. Die Umgebungsvariable CHAIN_REGISTRY_TOKEN hat weiterhin Vorrang, wenn gesetzt.",
"registryCredentialsBlurb": "Token zum Herunterladen von .chain-Modulen aus einer Registry mit Anmeldepflicht (Forgejo, private GitHub-Repos). Gespeichert in ~/.chain/registry-token, Modus 0600. Die Umgebungsvariable CHAIN_REGISTRY_TOKEN hat weiterhin Vorrang, wenn gesetzt.",
"registryTokenStatusConfigured": "Konfiguriert ({chars} Zeichen)",
"@registryTokenStatusConfigured": {
"placeholders": {
@ -829,6 +829,29 @@
}
}
},
"authPolicyHeader": "ZUGRIFFSSCHUTZ DES HUBS",
"authPolicyBlurb": "Wie der Hub eingehende Aufrufe prüft: aktives Prüfverfahren, Tokens und ihre Rechte (Scopes). Geheimnisse bleiben in Umgebungsvariablen — hier erscheinen nur deren Namen.",
"authPolicyValidatorStatic": "Prüfverfahren: statische Token-Liste",
"authPolicyValidatorJwt": "Prüfverfahren: JWT (RS256) über eine externe Identitätsstelle",
"authPolicyAnonymous": "Keine Tokens konfiguriert — der Hub akzeptiert anonyme Aufrufe. Für lokales Arbeiten in Ordnung; für den Produktivbetrieb Tokens in ~/.chain/config.yaml einrichten.",
"authPolicyNeedsAdmin": "Diese Ansicht braucht ein Token mit admin-Recht. Hinterlegen Sie es oben unter „Hub-Authentifizierung“ und laden Sie neu.",
"authPolicyHubTooOld": "Der verbundene Hub kennt diese Ansicht noch nicht — er ist älter als Studio. Aktualisieren Sie den Hub (chain update apply) und laden Sie neu.",
"authPolicyRetry": "Erneut versuchen",
"authPolicyReload": "Tokens neu laden",
"authPolicyReloadDone": "Neu geladen — {n} Token aktiv.",
"@authPolicyReloadDone": {"placeholders": {"n": {"type": "int"}}},
"authPolicyEditHint": "Bearbeitet wird die Richtlinie in ~/.chain/config.yaml (Abschnitt auth:). Nach einer Änderung oder Token-Rotation hier neu laden — der Hub übernimmt sie ohne Neustart.",
"authPolicyEnvSet": "Umgebungsvariable {env} ist gesetzt",
"@authPolicyEnvSet": {"placeholders": {"env": {"type": "String"}}},
"authPolicyEnvMissing": "Umgebungsvariable {env} FEHLT — das Token ist nicht nutzbar",
"@authPolicyEnvMissing": {"placeholders": {"env": {"type": "String"}}},
"authPolicyRateLimit": "{n}/min",
"@authPolicyRateLimit": {"placeholders": {"n": {"type": "int"}}},
"authPolicyJwtKeySource": "Schlüsselquelle",
"authPolicyJwtAudience": "Audience (aud)",
"authPolicyJwtIssuer": "Aussteller (iss)",
"authPolicyJwtScopeClaim": "Scope-Claim",
"authPolicyNotChecked": "wird nicht geprüft",
"hubAuthTokenHeader": "HUB-AUTHENTIFIZIERUNG",
"hubAuthTokenBlurb": "Bearer-Token für die Studio-Anbindung an einen Hub mit aktivierter auth.tokens-Konfiguration (RBAC Level 2). Gespeichert in ~/.chain/hub-auth-token, Modus 0600. Studio sendet ihn als Authorization: Bearer bei jedem gRPC-Aufruf.",
"hubAuthTokenStatusConfigured": "Eingerichtet ({chars} Zeichen)",
@ -1554,16 +1577,16 @@
}
},
"addSourceTitle": "Modul-Quelle hinzufügen",
"addSourceIntro": "`{capability}` ist nicht im öffentlichen Store. Zeig dem Hub eine `.fai`-Bundle-URL oder einen lokalen Bundle-Pfad — der Hub lädt es herunter, prüft (sha256 + Signatur) und installiert.",
"addSourceIntro": "`{capability}` ist nicht im öffentlichen Store. Zeig dem Hub eine `.chain`-Bundle-URL oder einen lokalen Bundle-Pfad — der Hub lädt es herunter, prüft (sha256 + Signatur) und installiert.",
"@addSourceIntro": {
"placeholders": {
"capability": {"type": "String"}
}
},
"addSourceField": "URL oder Pfad zum .fai-Bundle",
"addSourceHint": "https://git.flemming.ai/deine-org/dein-modul/releases/download/v0.1.0/foo-0.1.0.fai",
"addSourceField": "URL oder Pfad zum .chain-Bundle",
"addSourceHint": "https://git.flemming.ai/deine-org/dein-modul/releases/download/v0.1.0/foo-0.1.0.chain",
"addSourceHowItWorksTitle": "Wie private Module funktionieren",
"addSourceHowItWorksBody": "Ein Modul ist ein Verzeichnis mit module.yaml + WASM-Artefakt. Zum Teilen: `chain pack <verzeichnis>` baut ein `.fai`-Bundle, das du beliebig hosten kannst (eigene Forgejo / GitHub / S3). Der Hub installiert per URL und prüft die Signatur gegen seinen Trust-Store.\n\nLokal entwickeln? Nimm das CLI — Studio installiert (noch) nicht aus einem unverpackten Verzeichnis:",
"addSourceHowItWorksBody": "Ein Modul ist ein Verzeichnis mit module.yaml + WASM-Artefakt. Zum Teilen: `chain pack <verzeichnis>` baut ein `.chain`-Bundle, das du beliebig hosten kannst (eigene Forgejo / GitHub / S3). Der Hub installiert per URL und prüft die Signatur gegen seinen Trust-Store.\n\nLokal entwickeln? Nimm das CLI — Studio installiert (noch) nicht aus einem unverpackten Verzeichnis:",
"addSourceCliExample": "chain install --link /pfad/zum/modul",
"addSourceInstallButton": "Installieren",
"addSourceCancel": "Abbrechen",