diff --git a/docs/README.md b/docs/README.md
index dbfae3e..af6529c 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -15,7 +15,7 @@ Monitoring und einen Bugtracker, den Coding-Agenten selbständig bedienen.
| **[Änderungen](../public/docs/changelog.json)** | Was sich je Fassung geändert hat und was zu tun ist. Öffentlich unter `/docs/changelog.php`, maschinenlesbar über `GET /api/updateservice/v1/changelog?since=X` |
| **[Release-Anleitung für Agenten](../public/docs/release.md)** | Ein Projekt veröffentlichungsfähig machen: Vorlage kopieren, konfigurieren, ausliefern |
| **[Linux-Testumgebung](./TESTUMGEBUNG.md)** | **Die geteilte Test-VM.** Wie ein Agent dort selbständig testet: DEV-Lizenz holen, Auslieferung prüfen, Befunde melden — mit `dc-testkit` |
-| **[Testinstanz & automatisierter Testlauf](./TESTINSTANZ.md)** | **`dc-dev.mhdf.de` — die zweite Installation zum Kaputtmachen.** 129 Fälle gegen API, Rechte, Migrationen und Zugangssperre (`tests/e2e/run.py`). **`scripts/deploy.py` führt sie vor jedem Produktiv-Upload aus** und bricht bei Fehlschlägen ab (`--ohne-test` umgeht das) |
+| **[Testinstanz & automatisierter Testlauf](./TESTINSTANZ.md)** | **`dc-dev.mhdf.de` — die zweite Installation zum Kaputtmachen.** 136 Fälle gegen API, Rechte, Migrationen und Zugangssperre (`tests/e2e/run.py`). **`scripts/deploy.py` führt sie vor jedem Produktiv-Upload aus** und bricht bei Fehlschlägen ab (`--ohne-test` umgeht das) |
| **[Agenten anbinden](./AGENTEN_ANBINDEN.md)** | **Was einmalig je Projekt zu tun ist**, damit ein Agent Bugtracker, Roadmap und MCP sinnvoll benutzt: Token, Adapter, Bausteine, Roadmap-Übernahme — mit Prüffragen am Ende |
| [Agent-Prompt-Vorlage](./AGENT_PROMPT_TEMPLATE.md) | Die Textbausteine selbst. **A** Grundhaltung (immer), **B** mit MCP, **C** ohne MCP, **D** Test-VM — nicht alles einkopieren |
| [Agenten-Handbuch](../public/docs/bugtracker.md) | Vollständige Beschreibung des Bugtracker-Workflows, öffentlich unter `/docs/` |
diff --git a/public/index.php b/public/index.php
index 7b38b8b..b2e5042 100644
--- a/public/index.php
+++ b/public/index.php
@@ -959,6 +959,39 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
dc_redirect('#tab-tokens');
}
+ case 'edit_master_token': {
+ $tokenId = trim((string)($_POST['token_id'] ?? ''));
+ $scopes = $_POST['scopes'] ?? [];
+
+ try {
+ $ok = (new CoreTokenManager($pdo))->updateMasterToken($tokenId, [
+ 'name' => $_POST['name'] ?? '',
+ 'project_slug' => $_POST['project_slug'] ?? '',
+ 'license_key' => $_POST['license_key'] ?? '',
+ 'owner_type' => $_POST['owner_type'] ?? '',
+ 'owner_identity' => $_POST['owner_identity'] ?? '',
+ 'environment' => $_POST['environment'] ?? '',
+ // Das Datumsfeld liefert nur den Tag; das Token soll
+ // an diesem Tag noch gelten und erst danach ablaufen.
+ 'expires_at' => !empty($_POST['expires_at'])
+ ? $_POST['expires_at'] . ' 23:59:59' : '',
+ 'scopes' => is_array($scopes) ? $scopes : [],
+ ]);
+ } catch (\InvalidArgumentException $e) {
+ dc_flash($e->getMessage(), 'danger');
+ dc_redirect('#tab-tokens');
+ }
+
+ dc_flash(
+ $ok
+ ? 'Token-Angaben gespeichert. Der Tokenwert selbst ist unveraendert — '
+ . 'auf den Maschinen muss nichts ausgetauscht werden.'
+ : 'Master-Token nicht gefunden.',
+ $ok ? 'success' : 'danger'
+ );
+ dc_redirect('#tab-tokens');
+ }
+
case 'revoke_core_token': {
$tokenId = trim((string)($_POST['token_id'] ?? ''));
if ($tokenId !== '') {
@@ -2085,6 +2118,33 @@ function rmBadge(string $status): string
return '' . $marker . ' ' . e($label) . '';
}
+// Die auswaehlbaren Rechte - EINE Liste fuer Anlegen und Bearbeiten.
+//
+// Vorher stand sie im Anlegeformular. Genau deshalb fehlten die
+// Supervisor-Rechte monatelang: Wer eine Liste an zwei Stellen fuehrt,
+// pflegt eine davon nicht. Ein zweites Formular waere die zweite Stelle
+// gewesen.
+$scopeChoices = [
+ '*' => ['⚠️ Alle Rechte', 'Uneingeschränkt — auch Releases veröffentlichen und Tokens ausstellen. Nicht an einen Agenten geben.'],
+ 'bugtracker:manage' => ['⚙️ Bugtracker verwalten', 'Übernehmen, kommentieren, schließen — schließt Lesen und Melden ein'],
+ 'bugtracker:report' => ['🐛 Bugtracker melden', 'Nur Einträge anlegen — schließt Lesen ein'],
+ 'bugtracker:read' => ['👁️ Bugtracker lesen', 'Nur Abfragen'],
+ 'watchdog:ping' => ['🛡️ Watchdog Heartbeat', 'Statusmeldungen senden'],
+ 'watchdog:read' => ['📊 Watchdog lesen', 'Monitore und Ereignisse abfragen'],
+ // Die Supervisor-Rechte fehlten hier, obwohl TokenManager
+ // sie seit 2.6.0 kennt. Folge: Ein Werkbank-Token liess
+ // sich ueber die Oberflaeche gar nicht vollstaendig
+ // ausstellen - dc_findings und dc_metrics im MCP-Adapter
+ // liefen ins unauthorized, und der Grund war nirgends zu
+ // sehen.
+ 'supervisor:read' => ['🔎 Befunde lesen', 'Supervisor-Befunde abfragen — braucht ein Werkbank-Token für dc_findings'],
+ 'supervisor:manage' => ['🔬 Befunde einstufen', 'Befunde abhaken und bewerten — schließt Lesen ein'],
+ 'supervisor:report' => ['📡 Befunde melden', 'Nur einliefern, etwa aus einem Prüfwerkzeug — schließt Lesen ein'],
+ 'updateservice:read' => ['📦 Updates prüfen', 'Auf neue Releases prüfen'],
+ 'updateservice:publish' => ['🚀 Releases veröffentlichen', 'Neue Releases einstellen — schließt Prüfen ein'],
+ 'license:dev' => ['🧪 DEV-Lizenz abholen', 'Befristeten Testschlüssel selbst ausstellen — nur für Werkbank-Token auf Testmaschinen'],
+];
+
// Agenten-Uebersicht: wer bearbeitet gerade was
$agentWorkload = $pdo->query('
SELECT claimed_by,
@@ -5303,6 +5363,19 @@ Antwort:
+
+
+
+
+
+
+
✏️ Token bearbeiten —
+
+
+
+ Der Tokenwert und die Nummer
+ () bleiben unverändert — auf den
+ Maschinen muss nichts ausgetauscht werden.
+
+
+
+ An diesem Token hängen Sub-Tokens.
+ Sie haben ihre Rechte beim Ausstellen bekommen und behalten sie —
+ eine Einschränkung hier wirkt nicht rückwirkend auf sie.
+ Wer auch die Kinder beschneiden will, widerruft sie und stellt sie neu aus.
+
+
+
+
+
+
➕ Neuen Token erstellen
@@ -5470,26 +5650,6 @@ Antwort:
['⚠️ Alle Rechte', 'Uneingeschränkt — auch Releases veröffentlichen und Tokens ausstellen. Nicht an einen Agenten geben.'],
- 'bugtracker:manage' => ['⚙️ Bugtracker verwalten', 'Übernehmen, kommentieren, schließen — schließt Lesen und Melden ein'],
- 'bugtracker:report' => ['🐛 Bugtracker melden', 'Nur Einträge anlegen — schließt Lesen ein'],
- 'bugtracker:read' => ['👁️ Bugtracker lesen', 'Nur Abfragen'],
- 'watchdog:ping' => ['🛡️ Watchdog Heartbeat', 'Statusmeldungen senden'],
- 'watchdog:read' => ['📊 Watchdog lesen', 'Monitore und Ereignisse abfragen'],
- // Die Supervisor-Rechte fehlten hier, obwohl TokenManager
- // sie seit 2.6.0 kennt. Folge: Ein Werkbank-Token liess
- // sich ueber die Oberflaeche gar nicht vollstaendig
- // ausstellen - dc_findings und dc_metrics im MCP-Adapter
- // liefen ins unauthorized, und der Grund war nirgends zu
- // sehen.
- 'supervisor:read' => ['🔎 Befunde lesen', 'Supervisor-Befunde abfragen — braucht ein Werkbank-Token für dc_findings'],
- 'supervisor:manage' => ['🔬 Befunde einstufen', 'Befunde abhaken und bewerten — schließt Lesen ein'],
- 'supervisor:report' => ['📡 Befunde melden', 'Nur einliefern, etwa aus einem Prüfwerkzeug — schließt Lesen ein'],
- 'updateservice:read' => ['📦 Updates prüfen', 'Auf neue Releases prüfen'],
- 'updateservice:publish' => ['🚀 Releases veröffentlichen', 'Neue Releases einstellen — schließt Prüfen ein'],
- 'license:dev' => ['🧪 DEV-Lizenz abholen', 'Befristeten Testschlüssel selbst ausstellen — nur für Werkbank-Token auf Testmaschinen'],
- ];
foreach ($scopeChoices as $value => $labels): ?>