SEC: RBAC-Pruefung in ai-search, workflow-tasks, connect-setup (#369) #418

Merged
patrick merged 1 commits from fix/issue-369-rbac into main 2026-10-28 23:29:04 +01:00
Owner

Schließt #369.

Änderung

Backends (serverseitige Rechteprüfung vor jeder Verarbeitung, requirePermission-Muster wie statusapi/mailapi):

  • ai/internal/semanticsearchapi: ai.search.read (aus Migration 0018) wird nach der Service-Token-Prüfung für den Mandanten aus dem Anfragekörper (tenant_slug) gegen Core POST /authorize geprüft.
  • workflow/internal/taskapi: neu workflow.task.read (GET /tasks) und workflow.task.write (PATCH /tasks/{id}/status), geprüft nach Identitäts- und Tenant-Check. Das Paket war bisher in cmd/workflow-app gar nicht verdrahtet (nur im tasks-a11y-fixture); es ist jetzt in buildMux registriert und liegt damit hinter bearerauth.
  • connect/internal/connectorsetupapi: neu connect.setup.read (Katalog, Verbindungsliste, Mapping lesen) und connect.setup.write (Verbindung/Mapping speichern).
  • migrations/0029_task_setup_policy_rules.{up,down}.sql: vier neue Rechte je für user und tenant_admin, Muster 0018 (nächste freie Nummer nach 0028).
  • Wiring (Muster NEXARCH_DMS_APP_POLICY_*): NEXARCH_AI_APP_POLICY_URL/_POLICY_SERVICE_TOKEN, NEXARCH_WORKFLOW_APP_POLICY_URL/_POLICY_SERVICE_TOKEN, NEXARCH_CONNECT_APP_POLICY_URL/_POLICY_SERVICE_TOKEN. In connect-app wird damit auch die bereits vorhandene, bisher nie verdrahtete statusapi.WithPolicy-Prüfung (connect.status.read) scharf.
  • Frontend: MODULE_REGISTRY um ai_search_chat (3115), workflow_tasks (3116), connect_setup (3117) ergänzt, Icons in web/portal/app/moduleIcons.tsx, Rechteliste in web/portal/lib/modules.test.ts.
  • Doku: docs/BETRIEB-PORTAL.md (neuer Abschnitt), workflow/docs/ENG-11-PRUEFPROTOKOLL.md (Umgebungsvariablen).

Vorab-Prüfung (laut Auftrag)

(a) Policy-Abfrage und Identität

  • Alle drei Module nutzen common/policyclient (POST /authorize, X-Service-Token). Der Client ist fail-closed: Fehler/Nicht-200/Antwort ohne allowed → false, err; die Handler antworten dann mit 503, bei allowed=false mit 403.
  • Die Verdrahtung ist wie bei DMS/Mail/Connect-Status opt-in per Env: ohne *_POLICY_URL startet der Dienst mit Warnung im Log und ohne Prüfung (Übergang, damit Bestandsinstallationen ohne policy-api nicht ausfallen). URL ohne Token ist ein Startfehler.
  • Identität: taskapi liest X-User-Id/X-Tenant-Slug, die bearerauth in workflow-app aus den Token-Claims setzt. connectorsetupapi nutzt X-User-Id/X-Tenant-Slug ohne Token-Prüfung (bekannt, nicht Teil dieser Aufgabe). semanticsearchapi ist Modul-zu-Modul (Service-Token), der Mandant kommt aus dem Body.
  • Rolle ist in allen drei Diensten fest user (wie statusapi): bearerauth reicht Role aus den Claims nicht durch, Connect/AI haben keine Nutzerrolle. Deshalb sind die neuen Rechte für user und tenant_admin angelegt; eine Rollendifferenzierung (z. B. connect.setup.write nur für Admins) ist erst sinnvoll, wenn die Rolle ankommt — eigenes Ticket.

(b) Aufrufer

  • web/workflow-tasks (Bearer oder userId/tenant-Query), web/connect-setup (NEXT_PUBLIC_USER_ID/_TENANT_SLUG-Header), web/ai-search-chat (Service-Token + EXAMPLE_TENANT_SLUG) senden weiterhin genau das, was die Handler brauchen; die Prüfung kommt serverseitig dazu, keine Frontend-Änderung nötig.
  • Fixtures cmd/tasks-a11y-fixture, cmd/setup-a11y-fixture, cmd/searchchatapi-a11y-fixture rufen NewServer(...) ohne WithPolicy auf und laufen unverändert (keine Prüfung, wie bisher) — nichts abgeschwächt, nur nicht verdrahtet; sie sind Wegwerf-Testbinaries.
  • Bestehende Tests der drei Pakete laufen unverändert durch (policy == nil ⇒ bisheriges Verhalten).

(c) Wiring

  • Keines der drei cmd/*-app hatte einen policyclient; jetzt minimal nach dem DMS-Muster verdrahtet, Env-Variablen in docs/BETRIEB-PORTAL.md und ENG-11 genannt.

Auswirkung / Deploy

  • Reihenfolge: Migration 0029 auf der Core-DB (policy-api) vor dem Binary-Rollout, sonst antwortet Core für workflow.task.*/connect.setup.* mit allowed=false → 403 in Aufgabenboard und Connect-Setup, sobald *_POLICY_URL gesetzt ist. ai.search.read existiert seit 0018.
  • Bestands-Mandanten: policy_rules ist mandantenübergreifend (Rolle→Recht); user/tenant_admin erhalten die neuen Rechte sofort, keine Daten-Migration je Mandant. Down-Migration entfernt genau die von 0029 angelegten Zeilen (granted_by).
  • Ohne gesetzte *_POLICY_URL ändert sich das Laufzeitverhalten nicht (nur eine Warnung im Log). Mit URL: Core nicht erreichbar → 503.
  • workflow-app beantwortet neu GET /tasks und PATCH /tasks/{id}/status (bisher 404); web/workflow-tasks mit WORKFLOW_TASKS_API_URL auf 9600 funktioniert damit erstmals gegen das echte Binary.

Tests (Host 131 Scratch /root/scratch-i369, DB-Tests gegen dms_dev auf 204, beide Scratch-Verzeichnisse danach gelöscht)

  • go vet ai/workflow/connect (cmd + geänderte Pakete): sauber; gofmt -l: sauber.
  • Go ohne DB (131): ai cmd/ai-app, internal/semanticsearchapi, internal/pflichttestgate ok; workflow cmd/workflow-app, internal/taskapi, internal/pflichttestgate ok; connect internal/connectorsetupapi, internal/statusapi ok.
  • Go mit TEST_TENANT_DSN (204, dms_dev): workflow 13 PASS / 0 SKIP (inkl. TestBuildMux_AllPackagesAnswer mit neuem /tasks-Check und TestHandleList_PolicyAllows_Passes), connect 16 PASS / 0 SKIP, ai 14 PASS / 0 SKIP.
  • Neue Policy-Tests: semanticsearchapi 4, taskapi 5, connectorsetupapi 5 (403 bei Ablehnung mit Prüfung von permission/tenant im Core-Request, 200 bei Freigabe, 503 bei Ausfall, keine Policy-Abfrage ohne Identität/Service-Token, Ablehnung vor jedem Store-Zugriff).
  • Migration 0029: auf 204 in einer zurückgerollten Transaktion gegen das 0003-Schema geprüft: up → 8 policy_rules + 8 policy_rule_changes, zweites up idempotent (8), down → 0.
  • Pflichttest-Gates (Core, AI, Workflow, Mail) mit der Änderungsliste: alle bestanden.
  • Frontend (131): web/shl vitest 68/68, web/portal vitest 72/72 (inkl. Rechteliste, eindeutige Keys, Icon je Modul).
  • web/shl tsc --noEmit: 3 Fehler Cannot find name 'process' in ModuleNavShell.tsx — vorbestehend auf main (Zeilen 122/123 dort identisch, @types/node fehlt im shl-Setup), nicht Teil dieser Änderung.

Nicht geprüft / Annahmen

  • Kein next build der drei Apps und kein Ende-zu-Ende-Lauf mit laufender policy-api (Dienste auf 131/204 nicht gestartet).
  • Layout-Einbindung von ModuleNavShell in die drei Apps (wie bei mail_postfach in #368) bewusst nicht gemacht — das Issue verlangt nur den Registry-Eintrag.
  • Ports 3115–3117 für die drei Apps angenommen (nächste freie nach 3114), nicht in deploy/ports.tsv hinterlegt (dort sind Web-Apps nicht geführt).

🤖 Generated with Claude Code

Schließt #369. ## Änderung **Backends (serverseitige Rechteprüfung vor jeder Verarbeitung, `requirePermission`-Muster wie `statusapi`/`mailapi`):** - `ai/internal/semanticsearchapi`: `ai.search.read` (aus Migration 0018) wird nach der Service-Token-Prüfung für den Mandanten aus dem Anfragekörper (`tenant_slug`) gegen Core `POST /authorize` geprüft. - `workflow/internal/taskapi`: neu `workflow.task.read` (`GET /tasks`) und `workflow.task.write` (`PATCH /tasks/{id}/status`), geprüft nach Identitäts- und Tenant-Check. **Das Paket war bisher in `cmd/workflow-app` gar nicht verdrahtet** (nur im `tasks-a11y-fixture`); es ist jetzt in `buildMux` registriert und liegt damit hinter `bearerauth`. - `connect/internal/connectorsetupapi`: neu `connect.setup.read` (Katalog, Verbindungsliste, Mapping lesen) und `connect.setup.write` (Verbindung/Mapping speichern). - `migrations/0029_task_setup_policy_rules.{up,down}.sql`: vier neue Rechte je für `user` und `tenant_admin`, Muster 0018 (nächste freie Nummer nach 0028). - Wiring (Muster `NEXARCH_DMS_APP_POLICY_*`): `NEXARCH_AI_APP_POLICY_URL`/`_POLICY_SERVICE_TOKEN`, `NEXARCH_WORKFLOW_APP_POLICY_URL`/`_POLICY_SERVICE_TOKEN`, `NEXARCH_CONNECT_APP_POLICY_URL`/`_POLICY_SERVICE_TOKEN`. In `connect-app` wird damit auch die bereits vorhandene, bisher nie verdrahtete `statusapi.WithPolicy`-Prüfung (`connect.status.read`) scharf. - Frontend: `MODULE_REGISTRY` um `ai_search_chat` (3115), `workflow_tasks` (3116), `connect_setup` (3117) ergänzt, Icons in `web/portal/app/moduleIcons.tsx`, Rechteliste in `web/portal/lib/modules.test.ts`. - Doku: `docs/BETRIEB-PORTAL.md` (neuer Abschnitt), `workflow/docs/ENG-11-PRUEFPROTOKOLL.md` (Umgebungsvariablen). ## Vorab-Prüfung (laut Auftrag) **(a) Policy-Abfrage und Identität** - Alle drei Module nutzen `common/policyclient` (`POST /authorize`, `X-Service-Token`). Der Client ist fail-closed: Fehler/Nicht-200/Antwort ohne `allowed` → `false, err`; die Handler antworten dann mit 503, bei `allowed=false` mit 403. - Die Verdrahtung ist wie bei DMS/Mail/Connect-Status opt-in per Env: ohne `*_POLICY_URL` startet der Dienst mit **Warnung im Log und ohne Prüfung** (Übergang, damit Bestandsinstallationen ohne policy-api nicht ausfallen). URL ohne Token ist ein Startfehler. - Identität: `taskapi` liest `X-User-Id`/`X-Tenant-Slug`, die `bearerauth` in `workflow-app` aus den Token-Claims setzt. `connectorsetupapi` nutzt `X-User-Id`/`X-Tenant-Slug` ohne Token-Prüfung (bekannt, nicht Teil dieser Aufgabe). `semanticsearchapi` ist Modul-zu-Modul (Service-Token), der Mandant kommt aus dem Body. - **Rolle ist in allen drei Diensten fest `user`** (wie `statusapi`): `bearerauth` reicht `Role` aus den Claims nicht durch, Connect/AI haben keine Nutzerrolle. Deshalb sind die neuen Rechte für `user` **und** `tenant_admin` angelegt; eine Rollendifferenzierung (z. B. `connect.setup.write` nur für Admins) ist erst sinnvoll, wenn die Rolle ankommt — eigenes Ticket. **(b) Aufrufer** - `web/workflow-tasks` (Bearer oder `userId`/`tenant`-Query), `web/connect-setup` (`NEXT_PUBLIC_USER_ID`/`_TENANT_SLUG`-Header), `web/ai-search-chat` (Service-Token + `EXAMPLE_TENANT_SLUG`) senden weiterhin genau das, was die Handler brauchen; die Prüfung kommt serverseitig dazu, keine Frontend-Änderung nötig. - Fixtures `cmd/tasks-a11y-fixture`, `cmd/setup-a11y-fixture`, `cmd/searchchatapi-a11y-fixture` rufen `NewServer(...)` ohne `WithPolicy` auf und laufen unverändert (keine Prüfung, wie bisher) — nichts abgeschwächt, nur nicht verdrahtet; sie sind Wegwerf-Testbinaries. - Bestehende Tests der drei Pakete laufen unverändert durch (`policy == nil` ⇒ bisheriges Verhalten). **(c) Wiring** - Keines der drei `cmd/*-app` hatte einen policyclient; jetzt minimal nach dem DMS-Muster verdrahtet, Env-Variablen in `docs/BETRIEB-PORTAL.md` und `ENG-11` genannt. ## Auswirkung / Deploy - **Reihenfolge: Migration 0029 auf der Core-DB (policy-api) vor dem Binary-Rollout**, sonst antwortet Core für `workflow.task.*`/`connect.setup.*` mit `allowed=false` → 403 in Aufgabenboard und Connect-Setup, sobald `*_POLICY_URL` gesetzt ist. `ai.search.read` existiert seit 0018. - Bestands-Mandanten: `policy_rules` ist mandantenübergreifend (Rolle→Recht); `user`/`tenant_admin` erhalten die neuen Rechte sofort, keine Daten-Migration je Mandant. Down-Migration entfernt genau die von 0029 angelegten Zeilen (`granted_by`). - Ohne gesetzte `*_POLICY_URL` ändert sich das Laufzeitverhalten nicht (nur eine Warnung im Log). Mit URL: Core nicht erreichbar → 503. - `workflow-app` beantwortet neu `GET /tasks` und `PATCH /tasks/{id}/status` (bisher 404); `web/workflow-tasks` mit `WORKFLOW_TASKS_API_URL` auf 9600 funktioniert damit erstmals gegen das echte Binary. ## Tests (Host 131 Scratch `/root/scratch-i369`, DB-Tests gegen `dms_dev` auf 204, beide Scratch-Verzeichnisse danach gelöscht) - `go vet` ai/workflow/connect (cmd + geänderte Pakete): sauber; `gofmt -l`: sauber. - Go ohne DB (131): ai `cmd/ai-app`, `internal/semanticsearchapi`, `internal/pflichttestgate` ok; workflow `cmd/workflow-app`, `internal/taskapi`, `internal/pflichttestgate` ok; connect `internal/connectorsetupapi`, `internal/statusapi` ok. - Go mit `TEST_TENANT_DSN` (204, dms_dev): workflow 13 PASS / 0 SKIP (inkl. `TestBuildMux_AllPackagesAnswer` mit neuem `/tasks`-Check und `TestHandleList_PolicyAllows_Passes`), connect 16 PASS / 0 SKIP, ai 14 PASS / 0 SKIP. - Neue Policy-Tests: semanticsearchapi 4, taskapi 5, connectorsetupapi 5 (403 bei Ablehnung mit Prüfung von `permission`/`tenant` im Core-Request, 200 bei Freigabe, 503 bei Ausfall, keine Policy-Abfrage ohne Identität/Service-Token, Ablehnung vor jedem Store-Zugriff). - Migration 0029: auf 204 in einer zurückgerollten Transaktion gegen das 0003-Schema geprüft: up → 8 `policy_rules` + 8 `policy_rule_changes`, zweites up idempotent (8), down → 0. - Pflichttest-Gates (Core, AI, Workflow, Mail) mit der Änderungsliste: alle bestanden. - Frontend (131): `web/shl` vitest 68/68, `web/portal` vitest 72/72 (inkl. Rechteliste, eindeutige Keys, Icon je Modul). - `web/shl` `tsc --noEmit`: 3 Fehler `Cannot find name 'process'` in `ModuleNavShell.tsx` — **vorbestehend auf `main`** (Zeilen 122/123 dort identisch, `@types/node` fehlt im shl-Setup), nicht Teil dieser Änderung. ## Nicht geprüft / Annahmen - Kein `next build` der drei Apps und kein Ende-zu-Ende-Lauf mit laufender policy-api (Dienste auf 131/204 nicht gestartet). - Layout-Einbindung von `ModuleNavShell` in die drei Apps (wie bei `mail_postfach` in #368) bewusst nicht gemacht — das Issue verlangt nur den Registry-Eintrag. - Ports 3115–3117 für die drei Apps angenommen (nächste freie nach 3114), nicht in `deploy/ports.tsv` hinterlegt (dort sind Web-Apps nicht geführt). 🤖 Generated with [Claude Code](https://claude.com/claude-code)
patrick added 1 commit 2026-10-28 22:38:00 +01:00
SEC: RBAC-Pruefung in ai-search, workflow-tasks, connect-setup (#369)
CI / Web-Barrierefreiheitspruefung (axe, Tastatur, Reflow, Textabstaende) (push) Canceled after 0s
CI / Web-Barrierefreiheitspruefung (axe, Tastatur, Reflow, Textabstaende) (pull_request) Canceled after 0s
CI / Core-Modul (Build/Vet/Test) (push) Successful in 38s
CI / DMS Security-Test-Gate (AC5, Merge-Gate) (push) Successful in 3s
CI / Connect Security-Test-Gate (QA-01 AC4, Merge-Gate) (push) Successful in 3s
CI / DMS-Modul Supply-Chain-Scan (govulncheck) (push) Failing after 14s
CI / Web (dms-browser) (push) Failing after 53s
CI / Web (pdf-viewer) (push) Failing after 38s
CI / Web (shl) (push) Failing after 8s
Supply-Chain-Scan (Go) / govulncheck (push) Failing after 37s
AI-Pflichttest-Gate / pflichttest-gate (pull_request) Successful in 15m54s
CI / Core-Modul (Build/Vet/Test) (pull_request) Successful in 37s
CI / DMS Security-Test-Gate (AC5, Merge-Gate) (pull_request) Successful in 2s
CI / Connect Security-Test-Gate (QA-01 AC4, Merge-Gate) (pull_request) Successful in 2s
CI / DMS-Modul Supply-Chain-Scan (govulncheck) (pull_request) Failing after 13s
CI / Web (dms-browser) (pull_request) Failing after 53s
CI / Web (pdf-viewer) (pull_request) Failing after 38s
CI / Web (shl) (pull_request) Failing after 8s
Core-Schnittstellen-Vertragstests / contract-tests (pull_request) Successful in 16m2s
Supply-Chain-Scan (Go) / govulncheck (pull_request) Failing after 56s
Supply-Chain-Scan (npm) / npm-audit (pull_request) Failing after 1m13s
Core-Pflichttest-Gate / pflichttest-gate (pull_request) Successful in 16m18s
RBAC-Rollenhierarchie-Pflichtgate / rbac-policy-invariant (pull_request) Successful in 15m49s
Workflow-Pflichttest-Gate / pflichttest-gate (pull_request) Failing after 22m6s
DB-Integrationstests / db-tests (pull_request) Canceled after 0s
CI / DMS-Modul (Lint/Build/Test/Coverage/Artefakt) (pull_request) Canceled after 0s
CI / DMS-Modul (Lint/Build/Test/Coverage/Artefakt) (push) Canceled after 0s
0a4c0aaf92
- semanticsearchapi: ai.search.read per policyclient (WithPolicy), Tenant aus
  dem Anfragekoerper, nach Service-Token-Pruefung
- taskapi: workflow.task.read (GET /tasks) und workflow.task.write (PATCH
  status); Paket jetzt in cmd/workflow-app verdrahtet (lag bisher nur im
  a11y-Fixture) und damit hinter bearerauth
- connectorsetupapi: connect.setup.read/write je Route
- Migration 0029 (up/down): neue Rechte fuer user und tenant_admin
- Wiring: NEXARCH_{AI,WORKFLOW,CONNECT}_APP_POLICY_URL/_POLICY_SERVICE_TOKEN;
  ohne URL Warnung und keine Pruefung (Uebergang), URL ohne Token Startfehler;
  connect-app setzt die bestehende statusapi-Pruefung damit ebenfalls scharf
- Tests je API: 403 bei Ablehnung, 200 bei Freigabe, 503 bei Ausfall, Policy
  wird ohne Identitaet/Service-Token nicht befragt
- MODULE_REGISTRY: ai_search_chat, workflow_tasks, connect_setup (+ Icons,
  Portal-Rechteliste)
- Doku: BETRIEB-PORTAL.md, ENG-11 Umgebungsvariablen

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
patrick merged commit a2832c5b53 into main 2026-10-28 23:29:04 +01:00
Sign in to join this conversation.
No Reviewers
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: scripte/nexarch#418