diff --git a/README.md b/README.md index dc30873..23f8a73 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# TeamVis — Self-Hosting-Bundle (v0.59.0) +# TeamVis — Self-Hosting-Bundle (v0.59.1) Dieses Bundle enthält alles zum **Betreiben** von TeamVis auf eigener Infrastruktur — **keinen** App-Quellcode. Die App selbst kommt als fertiges @@ -36,4 +36,4 @@ Vollständige Schritt-für-Schritt-Anleitung (von der nackten VM bis live): | `supabase/migrations/` | Datenbank-Schema (DDL) | | `docs/` | Anleitungen | -Stand: TeamVis 0.59.0. +Stand: TeamVis 0.59.1. diff --git a/package.json b/package.json index 31547ad..1ef5b60 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "teamvis-selfhost", - "version": "0.59.0", + "version": "0.59.1", "private": true, "description": "Self-Hosting-Bundle für TeamVis (Installer + Migrationen, ohne App-Quellcode).", "type": "module", diff --git a/release.json b/release.json index af1be55..9c07afb 100644 --- a/release.json +++ b/release.json @@ -1,6 +1,6 @@ { - "version": "0.59.0", - "released": "2026-10-14", - "security": true, - "summary": "Neuer KI-Anbieter mit eigener Adresse (OpenAI-kompatibel), etwa für einen Hoster mit Sitz und Verarbeitung in der EU. Zwei KI-Funktionen im Portal folgen jetzt dem Modul „KI“. Eine optionale Migration (0071), keine neuen Pflicht-Variablen." + "version": "0.59.1", + "released": "2026-10-22", + "security": false, + "summary": "Schrift durchgehend Funnel Sans, auch in serverseitig erzeugten Bildern. Keine Migration, keine neuen Variablen." } diff --git a/supabase/migrations/0073_anon_rechte_minimal.sql b/supabase/migrations/0073_anon_rechte_minimal.sql new file mode 100644 index 0000000..e45a95e --- /dev/null +++ b/supabase/migrations/0073_anon_rechte_minimal.sql @@ -0,0 +1,114 @@ +-- ==================================================================== +-- 0073_anon_rechte_minimal — anon nur noch dort, wo die Karte liest +-- ==================================================================== +-- Sicherheitsplan M22 (24.10.2026). Supabase vergibt über seine +-- Default-Privileges jeder neuen Tabelle volle Rechte an anon (inkl. +-- TRUNCATE, das RLS nicht erfasst). RLS hat das bisher abgefangen; jetzt +-- werden die Rechte selbst abgebaut. Öffentlich gelesen werden nur +-- employees, persons und site_settings — dort gelten weiter die +-- Spalten-Grants aus 0014/0045 ff. (ohne Geheimnis-Spalten). +-- +-- Bewusst KEIN "revoke ... on all tables in schema public" und KEIN +-- "alter default privileges": Auf gemeinsam genutzten Datenbanken (etwa +-- supabase.stwhas.de) liegen fremde Tabellen derselben Eigentümerrolle im +-- Schema public; deren Rechte dürfen sich nicht ändern. Deshalb eine +-- ausdrückliche Liste der TeamVis-Tabellen. Neue Tabellen nehmen anon die +-- Rechte in ihrer eigenen Migration (siehe 0060, 0072 und CLAUDE.md). +-- +-- Ebenfalls entfernt: die Policies admin_write und public_read auf employees (ALL für +-- authenticated, true). Sie stammt aus keiner TeamVis-Migration — TeamVis +-- nutzt keine Supabase-Auth —, lag aber auf einer Bestandsinstanz und hätte +-- jedem Inhaber eines authenticated-JWT Schreibzugriff gegeben. + +do $$ +declare t text; +begin + foreach t in array array[ + 'admin_invites', + 'admin_users', + 'appointment_requests', + 'bookings', + 'calendar_connections', + 'card_leads', + 'card_view_log', + 'change_log', + 'compliance_role_bindings', + 'deputies', + 'external_parties', + 'job_description_blocks', + 'job_description_versions', + 'job_descriptions', + 'locations', + 'magic_link_tokens', + 'org_units', + 'organigram_versions', + 'portal_api_tokens', + 'position_assignments', + 'positions', + 'push_preferences', + 'push_subscriptions', + 'reception_kiosks', + 'reception_visit_audit', + 'service_relations', + 'teamvis_schema_migrations', + 'trusted_access_log', + 'visitor_preregistrations', + 'wallet_pass_registrations', + 'webhook_deliveries', + 'webhook_subscriptions' + ] loop + if to_regclass('public.' || t) is not null then + execute format('revoke all on table public.%I from anon', t); + end if; + end loop; +end $$; + +drop policy if exists admin_write on public.employees; + +-- authenticated: dieselben engen Rechte wie anon. TeamVis nutzt keine +-- Supabase-Auth; auf gemeinsam genutzten Datenbanken kann es aber Inhaber +-- eines authenticated-JWT geben. Übrige Tabellen: keine Rechte; die drei +-- Kartentabellen: genau die Lesespalten, die anon hat. +do $$ +declare t text; cols text; +begin + foreach t in array array[ + 'admin_invites', 'admin_users', 'appointment_requests', 'bookings', + 'calendar_connections', 'card_leads', 'card_view_log', 'change_log', + 'compliance_role_bindings', 'deputies', 'external_parties', + 'job_description_blocks', 'job_description_versions', 'job_descriptions', + 'locations', 'magic_link_tokens', 'org_units', 'organigram_versions', + 'portal_api_tokens', 'position_assignments', 'positions', + 'push_preferences', 'push_subscriptions', 'reception_kiosks', + 'reception_visit_audit', 'service_relations', 'teamvis_schema_migrations', + 'trusted_access_log', 'visitor_preregistrations', + 'wallet_pass_registrations', 'webhook_deliveries', 'webhook_subscriptions' + ] loop + if to_regclass('public.' || t) is not null then + execute format('revoke all on table public.%I from authenticated', t); + end if; + end loop; + foreach t in array array['employees', 'persons', 'site_settings'] loop + if to_regclass('public.' || t) is null then continue; end if; + select string_agg(quote_ident(column_name), ', ' order by column_name) into cols + from information_schema.column_privileges + where table_schema = 'public' and table_name = t + and grantee = 'anon' and privilege_type = 'SELECT'; + execute format('revoke all on table public.%I from authenticated', t); + if cols is not null then + execute format('grant select (%s) on public.%I to authenticated', cols, t); + end if; + end loop; +end $$; + +-- Ebenfalls nicht aus TeamVis: Policy public_read (Rolle public, aktive +-- Karten). Für anon gilt public_read_active_employees (0001/0014). +drop policy if exists public_read on public.employees; + +do $$ +begin + if to_regclass('public.teamvis_schema_migrations') is not null then + alter table public.teamvis_schema_migrations enable row level security; + revoke all on table public.teamvis_schema_migrations from anon; + end if; +end $$;